"The insertion layer types whatever it's handed. So never hand it a sentence a chatbot wrote."
A Transform, Not a Conversation
Cleanup is a strict transform: raw transcript in, polished insertable text out. It must never answer the transcript, add content, or editorialize. If you dictate "remind me to call the bank," cleanup returns "Remind me to call the bank." — punctuated and capitalized — not "Sure, I'll remind you!" The provider receives a structured request (raw transcript, mode, any selected text, allowed context, dictionary, snippets, style profile, language hints, output constraints) and returns a structured result. Both ends are typed on purpose.
Why the Result Must Be Structured
The insertion layer is dumb by design: it types whatever text it's given into the live app. That's exactly why cleanup can't hand it free prose. If a cleanup brain returned "Here's your cleaned text: …" or "I'm not sure what you meant," that would be typed into the user's document verbatim. The structured result — text, action, press_enter, warnings — guarantees the insertion layer only ever receives the fields it knows how to act on. Prose is not a valid return value; a result object is.
CleanupRequest { transcript, mode, selection?, context?, dictionary,
snippets, style, language, constraints }
|
v (provider: cwkPippa full / local Ollama / deterministic)
v
CleanupResult { text, action: "insert", press_enter, warnings[] }
|
v
Insertion types ONLY result.text -- never raw model prose
Taming Weak Models
Local models are the hard case: a small Ollama model may ignore your instruction to return JSON and reply with a markdown-fenced blob, a preamble, or an emotion tag. The provider's job is to tame that — strip fences and preambles, and if all else fails, wrap the raw text in a valid result object so the contract still holds. The rule is: the insertion layer never sees the mess. Whatever a weak model does, the adapter normalizes it into the same clean result shape the strong models produce.