Skip to content

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

better-write-opencode

License Stars Issues TypeScript

An OpenCode plugin that keeps write and edit usable with OpenAI-compatible local models, instead of having to turn those tools off.

Related upstream: issue #29142, PR #30224, and the earlier report #18131.


// crafted for the agentic AI community — funding keeps it maintained

GitHub Sponsors Open Collective Ko-fi Buy Me a Coffee thanks.dev


The problem

Models served through LM Studio, LiteLLM or similar (Qwen, DeepSeek, and other OpenAI-compatible endpoints) fail write/edit calls with:

Error: The write tool was called with invalid arguments:
  SchemaError(Missing key at ["content"]).
Please rewrite the input so it satisfies the expected schema.

The agent then retries the same broken shape and loops. The workaround people land on is to disable the tools outright:

permission:
  edit: deny
  write: deny

…which removes one of OpenCode's core editing paths. This plugin exists so you don't have to do that.

Two different causes, one error message

This is the part worth understanding before installing anything, because only one of the two is a plugin problem.

Cause Tool input looks like Fix
Mis-keyed arguments — model used a synonym {"fileContent": "…", "path": "…"} this plugin
Empty arguments — model emitted no args at all {} provider config, see below

If the input is {}, a plugin cannot help you

There are no keys to rename. An argument-less tool call means the model degenerated, and on the system this was developed against that was caused by context overflow. Custom providers default to limit.context = 0, and isOverflow() in session/overflow.ts bails out early on exactly that:

if (input.model.limit.context === 0) return false

Auto-compaction therefore never fires, context grows without bound, and the model eventually emits tool calls with no arguments. Measured on one session: tool calls succeeded at ~66k input tokens on average and failed from ~80k up to 167k.

The fix is to declare limits on your provider's models:

// opencode.json / opencode.jsonc
"models": {
  "your-model": {
    "limit": {
      "context": 262144,   // the model's real window
      "input":    80000,   // compaction trigger — keep well below where it degrades
      "output":   32768
    }
  }
}

limit.input is the useful knob: usable = limit.input − reserved, so you can declare the true context window while still compacting early enough to stay in the range where the model behaves.

What the plugin does

1. Alias normalization — tool.execute.before

Renames known alias keys onto their canonical names in place, before OpenCode's schema decode. In session/tools.ts the plugin.trigger("tool.execute.before", …) call runs before item.execute, and the hook receives the live args object — so a renamed key makes the call succeed outright rather than just producing a nicer error.

Covers write, edit, bash, read, grep, glob. For example fileContent/text/body → content; path/file_path/fileName → filePath; cmd/script/shell → command; old_string/search → oldString. A key the model already got right is never overwritten.

2. Field reorder — tool.definition

Re-emits the write schema with filePath declared before content. Local models generate JSON fields in declaration order, so a model that runs out of output budget partway through a large content value has already emitted the required filePath. Same idea as PR #29943, applied from userland with no rebuild.

3. Diagnostics

Appends to ~/.local/share/opencode/plugin-schema-fix.log:

  • loaded — once per start; use this to confirm the plugin is actually picked up
  • repaired tool=… alias->canonical — an alias was renamed
  • empty-args tool=… — the {} case, logged distinctly so it is never mistaken for a key mismatch

Install

# global
git clone https://github.com/VRIL-LABS/better-write-opencode
cp better-write-opencode/write-edit-schema-fix.ts ~/.config/opencode/plugins/

Or per project, into .opencode/plugins/. Discovery uses the glob {plugin,plugins}/*.{ts,js} (see packages/opencode/src/config/plugin.ts), so no config entry is needed.

Restart OpenCode and confirm it loaded:

cat ~/.local/share/opencode/plugin-schema-fix.log   # expect a "loaded" line

An empty or missing file means the plugin is not being picked up — check the directory name and that the file is .ts or .js.

Requires a build with the tool.definition and tool.execute.before hooks (developed against @opencode-ai/plugin 1.18.x).

Status

Working in real use. With the plugin installed, write succeeds — verified first-hand against a live OpenCode session backed by a local OpenAI-compatible model. The plugin logs a loaded line on every start, and the schema reorder is demonstrably in effect: the successful call emitted filePath ahead of content, which is the order this plugin installs rather than OpenCode's default.

Covered by tests against the built plugin:

  • {cmd: "hostname"} → {command: "hostname"}
  • {fileContent, path} → {content, filePath}
  • already-correct arguments left untouched
  • empty {} passed through without throwing
  • write schema reordering to [filePath, content]

One caveat worth repeating: if your tool inputs are arriving as {} rather than mis-keyed, that is the context-overflow case, and you need the config fix above as well — no plugin can rename keys that were never sent.

Relationship to PR #30224

PR #30224 improves the error message, appending expected and received keys so the model can self-correct on a subsequent turn. This plugin instead repairs the call so the first attempt succeeds, and needs no rebuild of OpenCode. They are complementary.

One note if you are comparing them: #30224 patches packages/llm/src/tool-runtime.ts, while the error text seen in the running app (The write tool was called with invalid arguments: …) is produced by InvalidArgumentsError in packages/opencode/src/tool/tool.ts — a different package. Worth confirming which path your build takes.

License

MIT — see LICENSE.

About

🩹 Resolves the "SchemaError(Missing key at ["content"])" error that some models trigger (such as Qwen) in OpenCode, which prevents file creation.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages