AI tools
A local LLM running on your device, or bring your own API key: your choice.
The AI tool runs a fixed set of one-tap writing actions (rewrite, summarize, translate, and more) against whatever text is in the field you’re typing in. Where those actions actually run is up to you: a cloud provider with your own API key, a self-hosted Ollama or LM Studio server on your network, or a model that downloads once and answers entirely on the device.
Using it
Section titled “Using it”Open AI from the toolbar or the toolbox. It isn’t pinned by default, so the first time you’ll likely reach it through the toolbox, by typing its ai keyword on the suggestion strip, or, on a hardware keyboard, through the leader key: double-tap Ctrl, then press A.
The panel opens on a row of action chips. Eight ship with the keyboard, and the list is yours to change: rename them, rewrite their prompts, turn off the ones you never use, reorder them, or add your own. See Your own actions below.
- Rewrite, Summarize, Translate, Improve, Fix grammar, Explain, Continue: each needs text to work on and is greyed out on an empty field.
- Custom — the one chip that stays live on an empty field. Tapping it opens an instruction box on the keyboard itself; whatever you type is the prompt for that run, so it can write brand-new text from nothing rather than transform existing text.
If nothing is configured yet, the panel shows a short explanation instead of the chip row: an Open settings shortcut if no provider is set up (the default on a fresh install), or a Download a model shortcut if On-device is selected but nothing has been downloaded yet. If a model is downloading right now, that empty state shows the download’s progress instead — and once you’re past it, a one-line progress strip sits above the chips so a download you started in Settings stays visible while you carry on typing.
What gets sent: selected text wins if you’ve selected any; otherwise the whole field. Continue is the exception: it always uses the text before the cursor (up to 4,000 characters), since continuing needs to know what came before, not what comes after. Tapping a chip on a truly empty field (and no selection) shows “Nothing to work on — type some text first” instead of sending a request.
While a request is running, the panel reports which step it’s on (Preparing, Connecting, Waiting for the model, and Reasoning for a model that thinks before answering) rather than a bare spinner, since a request can spend most of its time waiting on a slow connection or a long field. Waiting for the model is the one you’ll see most: it starts the moment your text is on its way and lasts until the first words come back, which for a cloud provider is nearly the whole run.
Once a result streams in, two buttons commit it: Replace swaps the field’s text for the result, and Insert drops it in at the cursor instead. Continue is the one exception to Replace: since deleting the text you just asked it to continue would defeat the point, Replace appends there rather than overwriting. A strip markdown checkbox (checked by default when the result contains any) removes headings, bullets, quotes, code fences/inline code, links, and bold/italic syntax from what gets committed; unchecking it keeps the raw markdown. Reasoning output between <think> tags is filtered out of both Replace and Insert either way; only the answer itself lands in your field.
If a model stops mid-answer because it hit the length ceiling, the panel says so and points at the setting to raise. That’s worth knowing about: a truncated answer otherwise looks exactly like a finished one, and you’d only find out by reading your own half-rewritten text.
Seeing what changed
Section titled “Seeing what changed”A finished result gets a Result / Changes pair of chips. Changes compares the answer against the text the action ran on and marks what the model added and what it took out, the way git diff does. It’s the one thing the plain result can’t show you: after a Fix grammar run, the spelling it corrected is simply gone from the screen.
Deleted text is struck through, added text is underlined and slightly bolder. That’s deliberate rather than colour alone, so it stays readable on a photo-background theme, in a high-contrast theme, and if you’re colour-blind. A changed space or paragraph break is drawn with a visible mark, since an empty highlight tells you nothing. Under the text sits a count of how many parts changed — “parts”, because they’re words in prose and single characters in a language that doesn’t put spaces between words.
Two cases can’t be compared and don’t offer the chips: Continue, which only ever read the text before your cursor, and any run that wrote from an empty field, where there’s no original to compare against. Very long pairs of texts aren’t compared either; the panel shows the plain result and says why. The comparison also waits until the answer has finished streaming, since half an answer reads as “everything after this was deleted”.
The chips are on by default. Open a result on the changes (off by default) makes the panel start there instead.
Reporting a result
Section titled “Reporting a result”Every finished result also carries a Report button, at the bottom right of the panel next to the strip-markdown checkbox. Tap it if a model produced something offensive, dangerous, or plainly wrong, and it opens a pre-filled email to the developer with a blank line at the top for what went wrong.
Nothing is uploaded when you tap it. The report is a draft in your own mail app, and you can read every line, edit it, or throw it away before sending. What it fills in for you:
- Your complaint, once you type it in the space at the top.
- Which action ran, which provider and model answered, and (for Custom) the instruction you gave.
- The app version, Android version, and device model.
- The text that went in and the text that came out, each trimmed to the first 4,000 characters.
That last one is the part worth a second look before you hit send, since it quotes whatever was in the field. The button only appears once a result has finished streaming; half an answer isn’t the thing you’d be reporting anyway.
For bugs in the keyboard itself rather than something a model wrote, use the Feedback rows in About instead.
Choosing where it runs
Section titled “Choosing where it runs”A row of provider chips sits at the top of the tool’s settings: Claude, OpenAI, Gemini, Grok, DeepSeek, Ollama, LM Studio, Other service, and On-device. You’re not limited to picking one forever; switching providers is just another tap.
Cloud providers
Section titled “Cloud providers”Claude (Anthropic), OpenAI, Gemini, Grok, and DeepSeek are bring-your-own-key only; WM Keyboard ships no built-in or proxied key for any of them, unlike some of the other network tools. Paste your own key into the provider’s field:
- Claude — from
console.anthropic.com→ API keys - OpenAI — from
platform.openai.com→ API keys - Gemini — has a free tier at
aistudio.google.com - Grok — from
console.x.ai→ API keys - DeepSeek — from
platform.deepseek.com→ API keys
Each provider also has a Model field; leave it blank to fall back to the app’s built-in default (claude-sonnet-5 for Claude, gpt-5.6-luna for OpenAI, gemini-3.5-flash for Gemini, grok-4.5 for Grok, deepseek-v4-flash for DeepSeek), shown right in the field’s hint, so fill in a model name here if you want something else.
DeepSeek’s reasoning models stream their thinking on a separate field, which the app folds into the same <think> handling everything else uses, so Show model reasoning and the reasoning progress readout work there exactly as they do elsewhere.
Any other OpenAI-compatible service
Section titled “Any other OpenAI-compatible service”Other service is the escape hatch, and it covers far more than the named chips do: anything that speaks OpenAI’s chat-completions shape works, including OpenRouter, Groq, Together, Mistral, Cerebras, and self-hosted vLLM. Three fields:
- Service address — the address up to and including the version segment, for example
https://openrouter.ai/api/v1. The app adds/chat/completionsitself. That split exists because services genuinely disagree about the prefix (/v1,/openai/v1,/api/v1), so guessing it would break half of them. - Model — required here, unlike the named providers. There’s no sensible default to guess for a service the app knows nothing about.
- API key — optional. A gateway on your own network often wants none.
Self-hosted servers
Section titled “Self-hosted servers”Ollama and LM Studio point at a server on your own network instead of a cloud API: no key needed, just an address like http://192.168.0.10:11434 (Ollama) or http://192.168.0.10:1234 (LM Studio). Ollama needs OLLAMA_HOST=0.0.0.0 set so it listens beyond localhost; LM Studio needs its local-server option turned on. Both fields are blank by default. Ollama defaults its model field to qwen3 when left blank. LM Studio has no default model to fall back to. It uses whatever model the server currently has loaded.
Local models
Section titled “Local models”The On-device provider runs a model entirely on the phone, no network involved. It’s the only provider option that needs a download first, and it’s the one provider chip that doesn’t appear at all in a Lite build.

The catalog is eight models, ordered best-first rather than smallest-first:
| Model | Params | Size | Tier | Gated |
|---|---|---|---|---|
| Gemma 4 E2B | 2B | 2.59 GB | Recommended | |
| Gemma 4 E4B | 4B | 3.66 GB | Recommended | |
| Gemma 3 1B | 1B | 584 MB | Untested | Yes |
| Qwen 2.5 1.5B | 1.5B | 1.6 GB | Standard | |
| Qwen 3 0.6B | 0.6B | 347 MB | Experimental | |
| Qwen 2.5 0.5B | 0.5B | 546 MB | Experimental | |
| Gemma 3 270M | 270M | 304 MB | Untested | Yes |
| SmolLM2 135M | 135M | 143 MB | Experimental |
“Gated” models (2 of the 8) need a Hugging Face account: paste a token into the Access token field under Hugging Face account above the catalog, then accept the model’s license on its Hugging Face page once. Every model also carries an advisory minimum-RAM figure behind the scenes: the app appends “May be too large for this device” to a model’s subtitle when your phone’s total RAM falls under it, but it never blocks the download outright and never shows the raw RAM number. That comparison is the only per-device signal the catalog gives you up front: there’s no published speed benchmark, since how fast a model actually responds depends on the phone as much as the model, and a progress readout with elapsed seconds is what you get once a request is running rather than an estimate beforehand.
Tapping Download starts a resumable download: cancel it, lose signal, or background the app, and resuming picks the transfer back up from where it left off rather than restarting. Only one download runs at a time. A model 500 MB or larger asks for confirmation first if you’re on a metered connection.
Don’t need the catalog? Import your own takes any .litertlm or .task file (the two container formats the on-device engine actually loads), for instance one you converted yourself or downloaded elsewhere in a browser. There’s no GGUF support; a file with any other extension is rejected on import.
A Compute row picks CPU or GPU for inference; CPU is the default. GPU is best-effort: if it fails to initialize, or crashes partway through an answer, the engine falls back to CPU on its own and remembers not to retry GPU for that model file again this session.
A Context size row sets how much text the model is loaded with, prompt and answer together, in tokens. It defaults to the model’s own value. This is the only length lever on-device: unlike a cloud API there’s no per-response ceiling to set, so the window is what bounds an answer. A larger window costs memory, and changing it reloads the model.
Your own actions
Section titled “Your own actions”The eight chips on the panel are a list you own. The screen lists them in panel order, with a checkbox to turn one off, an edit button, and a New action row at the bottom. Drag the handles in Order of the actions to rearrange them; the panel follows that order exactly.
An action that ships with the keyboard is never deleted, only changed. Editing one saves your version under the same identity, so Reset in its editor drops your version and the original comes straight back. Turning one off leaves it on this screen, greyed on the panel and one checkbox away from returning. Only actions you wrote yourself get a Delete.
The editor holds a name, the prompt, and a handful of behaviour switches:
- Type the prompt at every run — the keyboard asks you for the prompt instead of using a saved one. This is what makes Custom work the way it does.
- Start from the saved prompt — only shown under the switch above, and it brings the prompt field back. The instruction box then opens with that text already in it, so you adjust a template rather than retype it. Useful for something you run often with a small variation each time: “reply to this politely, and mention that…”. The saved text wins every time the box opens, not just the first, since a template you only see once isn’t a template. Leave it off and the box reopens on whatever you typed last instead.
- Works with an empty field — with nothing in the field, the action writes new text instead of changing text.
- Read the text before the cursor — the action reads only what’s in front of the cursor rather than the whole field. A selection always wins over this.
- Add the result to the end — Replace appends rather than overwriting. Together with the previous switch, this is what Continue is; separating them means “append but read the whole field” is now something you can build.
- Answer with the text only — on for everything except Explain, whose answer is prose about your text rather than a replacement for it.
About the prompt field
Section titled “About the prompt field”You write the task, not the whole prompt. The app wraps what you write in a fixed frame: who the model is, the rule that your field’s text is material to work on and never instructions to obey, and (unless you turn it off) the rule to answer with the result and nothing else.
That’s on purpose. The middle part is what stops a model treating text in your field — an email you’re replying to, a message someone sent you — as commands aimed at it, and it isn’t something a text box should be able to delete by accident. The prompt that the app sends below the editor shows you the assembled result, so it’s visible without being editable.
Write {target} anywhere in a prompt and it becomes the translate target language, which is how the shipped Translate action works. Because the token is stored rather than the language, changing the target language updates every prompt that mentions it.
Write the whole prompt is the deliberate way out for anyone who wants to write the safety wording themselves; the app then sends your text exactly as you typed it.
Chatting instead of transforming
Section titled “Chatting instead of transforming”The panel’s actions all do the same shape of thing: take the text in a field, hand it back changed. When you want an actual conversation instead, Chat opens one in the settings app, against any model you’ve already set up here. It’s a separate screen with its own saved conversations, its own model picker, and a launcher shortcut of its own. See AI chat.
History
Section titled “History”Off by default. Turned on, the keyboard keeps a record of each run: what you sent, what came back, which action and model, how long it took, how much of that was reasoning, and whether you actually used the answer. The screen searches across the input, the answer and the model name, filters by action, and expands a row to copy either side or delete it.
Failed runs are recorded too, with the error the panel showed, since “it keeps failing” is the most likely reason to open the screen at all.
Four things have to be true before anything is written down, and any one of them being false is the end of it:
- You turned the history on.
- The device has been unlocked at least once since it restarted.
- The field isn’t a password box.
- Incognito isn’t in force, from either the setting or a field that asked for it, like a private browser tab.
API keys are never part of a record; it carries the model’s name and nothing about the connection.
Number of records to keep defaults to 100 and tops out at 500; the oldest falls off when it’s full, and each side of a record is capped at 4,000 characters. Delete all history clears it, and so does turning the setting off — an off switch that quietly leaves the log on disk isn’t an off switch.
Options
Section titled “Options”Like every tool, AI has an Enabled toggle (on by default) and, if colorful tool icons are on, a per-tool icon color override. Below that:
- Keyword: the word that offers this tool on the suggestion strip when you type it alone. Defaults to
ai. - Provider: which of the nine providers above is active. Defaults to Claude, though with no key entered yet a fresh install lands on the empty-state screen until you add one.
- Max response length: a token ceiling, roughly ¾ of a word each, picked from steps rather than a slider: 1k through 128k, plus Provider maximum. Default 8,192. A model the app guesses is a reasoning model (by a substring match against its model ID, e.g. containing “thinking”, “qwen3”, “grok-4” or “deepseek-v4”) automatically gets 4× this ceiling, capped at 131,072, since reasoning tokens are spent from the same budget before the answer even starts. Replaced by Context size for the On-device provider.
- Translate action’s target language: free text, defaults to English.
- Show model reasoning: off by default. Turning it on streams a reasoning model’s raw
<think>passages instead of the step-by-step progress readout. - Model picker on the panel: on by default. Adds a horizontally-scrolling row to the panel itself for switching between every configured provider and downloaded local model in one tap. It’s hidden automatically whenever there are fewer than two to choose from.
- Show a changes view: on by default, see Seeing what changed. Open a result on the changes below it is off.
- Chat with the model: opens the conversation screen, see AI chat.
- Actions on the panel: the whole action list, see Your own actions.
- History: off by default, see History.
What the On-device provider adds
Section titled “What the On-device provider adds”Picking On-device draws the whole model manager onto the same screen, under the provider row. Local models covers the catalog, Compute and Context size. Three more things sit on that screen and nowhere else:
- Hugging Face account, holding an Access token field. Blank by default, stored the same way an API key is, and only the gated models need it. Under the field, Get a token opens
huggingface.co/settings/tokensin your browser. - Import your own, an Import model file button that opens the system file picker. It takes
.litertlmand.taskfiles only, and anything else is rejected with a message under the button. - Free up, labelled with a size (like “Free up 584 MB”). It only appears when there are orphaned files, meaning model directories left behind by an app update that dropped a model from the catalog. No row can reach those files any more, so the button is the only way to delete them. They’re reported rather than deleted for you, on the grounds that it’s a multi-gigabyte download you already paid for.
Above that sits a line reporting how much storage your models take in total, partial downloads included. That figure is usually bigger than the one beside Your models, which only sums the finished ones you can see.
About “Provider maximum”
Section titled “About “Provider maximum””This one is worth understanding, because the old default was the reason a long Improve used to come back with only the first part rewritten. Provider maximum leaves the ceiling out of the request entirely and lets the service apply its own, which for a modern model is far more than any number you’d pick by hand. It’s the right choice for long text.
Anthropic is the one exception: its API requires the field, so the app asks for a large number there instead. If the model you picked allows less, Anthropic rejects the request and names its real limit in the error, and the app retries once at that number — nothing has streamed at that point, so you just see the answer.
Ollama had never been sent a limit at all before this; it now gets one, and Provider maximum there means what it always did.
What leaves your phone
Section titled “What leaves your phone”The panel itself sends nothing until you actually tap an action chip: opening the tool, or typing in the field behind it, sends nothing anywhere on its own.
- On-device: the text you run an action on never leaves the phone. Response length is bounded by the local model’s own context window instead of a server-side limit.
- Any other provider (cloud or self-hosted): the text you run an action on is sent to that provider, only at the moment you tap the action. API keys and server addresses are stored on the device, not in any WM Keyboard service. See Privacy at a glance for how this fits the keyboard’s broader per-tool approach to anything that leaves the device.
- Report: builds a draft in your mail app and hands it over. The app has no reporting server and sends nothing itself, so a report only exists if you send the mail. API keys are never part of it.
- History: goes nowhere. It’s a file in the app’s private storage, off unless you turn it on, never written from a password field or in incognito, and deleted when you turn it off. It’s deliberately left out of settings backups too, so it can’t ride along in a file you export and mail to yourself — the same reasoning that keeps the learned dictionary out. See Your data.
- The changes view: is computed on your phone. Comparing two pieces of text is arithmetic, not a request; nothing is sent to build it.
Details & edge cases
Section titled “Details & edge cases”- Not every row here can be reset. The four switches (Show model reasoning, Model picker on the panel, Show a changes view, Open a result on the changes) and the Translate target-language field each grow a restore button once you move them off the default listed above; see Putting one setting back. The provider row, Max response length and Context size are drawn as chip rows rather than settings rows, so none of them has one, and the shipped value of an API key or address field is an empty box you clear yourself.
- AI isn’t pinned to the toolbar or the onboarding wizard’s starter set by default. You add it yourself from the toolbox once you want it, the same as most non-essential tools.
- Not available on the lock screen. AI needs credentials the direct-boot-safe mirror of your data deliberately doesn’t carry, so it’s one of the tools that only works after you’ve unlocked the device once since restart.
- The Writing keyboard mode pins AI first on its toolbar for apps it recognizes as writing-heavy (see Keyboard modes). The pin shows in both editions, same as the tool itself; only the On-device provider is Full-only.
- A reasoning model’s guess is just a substring match against the model ID (things like “thinking”, “-r1”, “qwen3”, “gpt-5”, “grok-4”, “deepseek-v4”), so it can be wrong in either direction: a false positive only costs a larger token ceiling, a false negative risks a response that gets cut off mid-thought.
- Custom has no stored default prompt. Every other action’s prompt can be edited but always has a built-in fallback; Custom’s instruction only ever exists for the run you type it for.
- On-device answers never claim to have been cut off. The local engine reports no stop reason, so there’s nothing to read, and the app says nothing rather than guessing. Every other provider does report it.
- The changes view can’t spot moved text. A paragraph the model relocated reads as a deletion where it was and an insertion where it went. Detecting moves properly needs a second pass that git only does on request, and the actions that move text (Summarize, Rewrite) reword it at the same time, so it would fire rarely and mislead when it did.
- Comparisons drop to whole characters for scripts without spaces (Chinese, Japanese, Thai, and others). Word-sized pieces would make an entire sentence a single highlight there. Mixed text uses characters throughout, which is noisier but never wrong.
- Local models are advisory about RAM, never a hard gate. A phone under a model’s stated minimum can still download and run it; you just get a warning in the catalog first.
- No shared or built-in key for any cloud provider. Every one of Claude, OpenAI, Gemini, Grok, and DeepSeek requires your own API key; there’s no free built-in quota the way some of the other network tools offer.
- A model download dies with the app’s process. It resumes rather than restarting, but it isn’t a foreground service, so backgrounding the app for long enough can stop it. That hasn’t changed; the panel just shows you it’s happening now.
