Skip to content

OpenCode as the default agent: providers, web search, plan mode - #95

Merged
deymosh merged 9 commits into
masterfrom
feat/opencode-full-support
Oct 8, 2026
Merged

deymosh merged 9 commits into
masterfrom
feat/opencode-full-support

Conversation

@deymosh

@deymosh deymosh commented Oct 8, 2026

Copy link
Copy Markdown
Owner

Summary

Work toward full OpenCode support, since it becomes the default agent.

Provider profiles

  • The providers page refreshes as soon as a profile is saved or deleted (the profile list reached the store but never signalled the views).
  • An agent's model list is asked for on every screen open instead of being held for five minutes, so a newly saved provider's models show at once.
  • A model read from an endpoint keeps the provider a gateway routes it to and its context window (ProviderModel.provider, contextWindow, with a corpus fixture). Phones group it as "profile · provider"; OpenCode lists it the same way and gets limit.context, so it can compact in time.
  • OpenCode providers take the profile's name: "CCR" is ccr, no codedeck- prefix. A name one of OpenCode's own providers has (built in, configured or signed in to), or an older profile, is refused: set-providers now answers providers-set {refused}, a save waits on it and is undone with the agent's reason, and a profile left out later carries the reason as error in provider-profiles.
  • While OpenCode restarts for a profile change, a model list waits for the new server instead of coming back empty (and no second server can start).
  • The providers page lists each provider's models, grouped by upstream provider, with the default and context size, in expandable rows like the MCP page.

OpenCode sessions

  • Web search for every model: the server is started with OPENCODE_ENABLE_EXA (checked on 1.18.32: a custom provider's model gets websearch with it and not without).
  • A Plan mode that runs OpenCode's own plan agent; other modes name no agent, so OpenCode's default applies.
  • Permission cards offer OpenCode's "always" when it has one, labelled "Always allow in this project" (OpenCode keeps it for the project until its server restarts).
  • apply_patch and lsp get their tool kinds.

Test plan

  • cargo clippy (workspace, all targets) and cargo test for every crate
  • agent host typecheck + test + build; driver-protocol spawn test and bridge end-to-end test
  • driver-protocol TS types and UniFFI Kotlin bindings regenerated
  • Android unit tests, Paparazzi (changed and new providers snapshots reviewed), lint
  • Live on OpenCode 1.18.32: websearch offered to a custom provider's model only with OPENCODE_ENABLE_EXA

🤖 Generated with Claude Code

deymosh and others added 9 commits October 8, 2026 19:04
A provider-profiles answer updated the machines store without the persist
that tells the views the slice changed, so a saved or deleted profile only
appeared once something else touched the machine. The profiles are still
never written: the machines slice strips them when it serializes.

Co-Authored-By: Claude Code <noreply@anthropic.com>
A model list was held for five minutes, so a provider profile saved a
moment ago, which adds models to its agent, did not show in the picker
until the hold ran out or the app restarted. Model lists are not pushed by
the bridge, so they are now asked for on every screen open; only a request
still in flight is not repeated. Provider profiles, which the bridge pushes
on every change, are still held for the connection.

Co-Authored-By: Claude Code <noreply@anthropic.com>
A profile's models were stored as an id and a label, so a gateway's
"OpenCode Go/deepseek-v4.1-flash" showed under the profile's name alone
and the upstream provider was lost. A model read from an endpoint now
keeps the provider before the first slash and the context window, when
the endpoint says. Phones group such a model under "profile · provider"
and name it without the provider the group already shows; OpenCode's own
list groups its profile models the same way, and OpenCode is given the
context window so it can compact before a model overflows.

Co-Authored-By: Claude Code <noreply@anthropic.com>
While the server was restarted for a changed profile list, the driver
had no client until the old server had closed: a model list asked for in
that window came back empty, and a session started in it could start a
second server. The replacement is now the pending client from the start,
closing the old server as its first step.

Co-Authored-By: Claude Code <noreply@anthropic.com>
A profile reached OpenCode as the provider "codedeck-<profile id>". Its
provider id is now the profile's name in lower case ("CCR" is "ccr"),
shown as the user wrote it. A name one of OpenCode's own providers has
(built in, in the operator's config, or signed in to) is never shadowed,
and of two profiles with the same name the older one keeps it.

The agent host answers set-providers with the profiles it left out and
why. A save now waits on that answer: a profile left out is not saved,
the earlier version stands, and the ack carries the reason. A stored
profile the agent leaves out later carries the reason in the profile list,
and the providers page shows it.

Co-Authored-By: Claude Code <noreply@anthropic.com>
OpenCode offers its web search only to models of its own providers, so a
session on a provider profile, or on any provider the operator added, had
no way to search unless an MCP server gave it one. The server the bridge
starts now sets OPENCODE_ENABLE_EXA, which offers the same search (Exa's
keyless endpoint, still asked for under OpenCode's websearch permission)
to every model. Checked on 1.18.32: a custom provider's model gets
websearch with it and not without.

Co-Authored-By: Claude Code <noreply@anthropic.com>
A provider showed only how many models it had, so seeing what a gateway
offers meant opening a new session's model picker. Each provider is now a
row like an MCP server's: its name, endpoint and one chip for what matters
most (not offered by its agent, no token, or its model count). Opened, it
says why its agent leaves it out, where its models came from, and lists
them under the provider a gateway routes each to, with the default marked
and the context window when the endpoint gave it.

Co-Authored-By: Claude Code <noreply@anthropic.com>
OpenCode edits files with its apply_patch tool and queries its language
servers with lsp, but only the older "patch" spelling had a kind: the
phone showed both as unknown tools. apply_patch is an edit and lsp a read.

Co-Authored-By: Claude Code <noreply@anthropic.com>
OpenCode sessions had two modes, Ask and YOLO, and never used OpenCode's
own plan agent, which explores and proposes without editing. A Plan mode
now names that agent on every prompt and command; leaving it names none
again, so OpenCode goes back to its default agent (build, or the
operator's).

A permission card offered only Allow and Deny, though OpenCode offers to
allow such calls from then on. When it does, the card now has "Always
allow in this project": OpenCode keeps that rule for every session of the
project until its server restarts, and does not save it.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@deymosh
deymosh merged commit aa1f8a1 into master Oct 8, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant