Documentation
¶
Overview ¶
Package opencode implements an llm.LLMProvider for the OpenCode CLI driven over the Agent Client Protocol (ACP). A ready OpenCode contributes a live model catalog discovered from the local CLI through the same catalog, discovery, context-window, and cost interfaces the other providers use, so its backend models participate in routing, provider-grouped model lists, and as a co-equal default selection. A failed refresh can use a previously discovered cache with a warning; no accessible backend is invented. Models are always expressed in OpenCode's native "provider/model" form: the "opencode:" routing prefix and Agentico's "[<window>]" context-window suffix are both stripped before a model string is handed to the CLI.
Index ¶
- Constants
- Variables
- func BackendModel(model string) string
- type AgentCapabilities
- type AgentInfo
- type AuthMethod
- type ClientCapabilities
- type ClientInfo
- type ContentBlock
- type ErrorResponse
- type FSCapability
- type FSResultResponse
- type InitializeParams
- type InitializeResult
- type Notification
- type PermissionOption
- type PermissionOutcome
- type PermissionOutcomeResult
- type PermissionResponse
- type PermissionToolCall
- type PromptParams
- type PromptResult
- type PromptUsage
- type Protocol
- func (p *Protocol) ACPSessionID() string
- func (p *Protocol) AdditionalSessionCost(ctx context.Context) (llm.SessionCostAdjustment, error)
- func (p *Protocol) BackendModelForTest() string
- func (p *Protocol) Close() error
- func (p *Protocol) Handshake(ctx context.Context) error
- func (p *Protocol) InitialPromptForTest() string
- func (p *Protocol) Interrupt() error
- func (p *Protocol) NegotiatedVersion() int
- func (p *Protocol) ParseLine(line []byte) ([]llm.SDKMessage, error)
- func (p *Protocol) RespondToAskUser(requestID string, questions json.RawMessage, answers map[string]string, ...) error
- func (p *Protocol) RespondToControl(requestID string, allow bool, _ json.RawMessage, _ string) error
- func (p *Protocol) RespondToHook(string) error
- func (p *Protocol) SendUserMessage(text string) error
- func (p *Protocol) SessionID() string
- func (p *Protocol) SetLogFunc(f func(string, ...interface{}))
- func (p *Protocol) SetRequestIDsForTest(initID, sessionNewID, sessionLoadID, promptID int)
- func (p *Protocol) SetStdin(w io.Writer)
- func (p *Protocol) TranscriptPath() string
- func (p *Protocol) WorkDirForTest() string
- type Provider
- func (p *Provider) AskingQuestionsClause() string
- func (p *Provider) AvailableModels() []string
- func (p *Provider) BuildCommand(opts llm.CommandBuildOpts) ([]string, []string, error)
- func (p *Provider) CheckReadiness(ctx context.Context) llm.ProviderReadiness
- func (p *Provider) ComputeCost(model string, inputTokens, outputTokens int64) float64
- func (p *Provider) ContextWindowForModel(model string) int
- func (p *Provider) DetectCLI() bool
- func (p *Provider) DiscoverModelCatalog(ctx context.Context) ([]llm.ModelInfo, error)
- func (p *Provider) DiscoverModelCatalogWithProgress(ctx context.Context, report llm.ModelDiscoveryReporter) ([]llm.ModelInfo, error)
- func (p *Provider) EnablesPendingToolWatchdog() bool
- func (p *Provider) EnforcesMinVersion() bool
- func (p *Provider) EnvVarsToExclude() []string
- func (p *Provider) InstallHint() string
- func (p *Provider) MatchesModel(model string) bool
- func (p *Provider) MinVersion() [3]int
- func (p *Provider) ModelCatalog() []llm.ModelInfo
- func (p *Provider) Name() string
- func (p *Provider) NewProtocol(opts llm.ProtocolOpts) llm.Protocol
- func (p *Provider) RefreshCatalogOnStartup() bool
- func (p *Provider) ReviewPreferenceBand(model llm.ModelInfo) (int, bool)
- func (p *Provider) SetModelCatalog(models []llm.ModelInfo)
- func (p *Provider) SupportsNativeToollessReview() bool
- func (p *Provider) SupportsSessionResume() bool
- func (p *Provider) UsesBoundedHelperSandbox() bool
- func (p *Provider) VersionInfo() (string, error)
- type RPCError
- type ReadTextFileParams
- type ReadTextFileResult
- type Request
- type RequestPermissionParams
- type SessionCancelParams
- type SessionLoadParams
- type SessionNewParams
- type SessionNewResult
- type SessionUpdate
- type SessionUpdateParams
- type ToolCallLocation
- type UpdateContent
- type UsageCost
- type WriteTextFileParams
Constants ¶
const ( StopReasonEndTurn = "end_turn" StopReasonMaxTokens = "max_tokens" StopReasonMaxTurnRequests = "max_turn_requests" StopReasonRefusal = "refusal" StopReasonCancelled = "cancelled" )
ACP stop reasons returned by session/prompt.
const ( UpdateAgentMessageChunk = "agent_message_chunk" UpdateAgentThoughtChunk = "agent_thought_chunk" UpdateToolCall = "tool_call" UpdateToolCallUpdate = "tool_call_update" UpdateUsage = "usage_update" UpdateAvailableCommands = "available_commands_update" )
session/update discriminator values handled by the tracer.
const ( ToolKindExecute = "execute" ToolKindEdit = "edit" ToolKindFetch = "fetch" ToolKindSearch = "search" ToolKindRead = "read" ToolKindThink = "think" // OpenCode's kind for the task (subagent-spawn) tool ToolKindOther = "other" ToolKindQuestion = "question" )
ACP tool-call kinds the tracer recognizes. Unknown kinds still surface as a permission prompt (the user decides) rather than failing closed; only the "question" kind diverts to the AskUserQuestion flow.
const ( OptionKindAllowOnce = "allow_once" OptionKindAllowAlways = "allow_always" OptionKindRejectOnce = "reject_once" OptionKindRejectAlways = "reject_always" )
ACP permission option kinds. The allow_* kinds approve the action; the reject_* kinds decline it.
const ( OutcomeSelected = "selected" OutcomeCancelled = "cancelled" )
ACP permission outcome discriminators.
const RoutingPrefix = providerName + ":"
RoutingPrefix is the Agentico-only model prefix that explicitly selects the OpenCode provider, e.g. "opencode:anthropic/claude-sonnet-4-5". It is purely a routing artifact: the prefix is stripped before the backend model string is handed to OpenCode.
Variables ¶
var Module = fx.Module("llm-opencode", fx.Provide(func(cfg *config.Config) *Provider { return NewWithBinary(cfg.ProviderCLI(providerName, defaultBinary)) }), fx.Invoke(func(r *llm.Registry, p *Provider) { r.Register(p) }), )
Module registers the OpenCode provider in the LLM registry. It is included only when OpenCode is explicitly requested (`--providers opencode`) or auto-registered because the config already selects an `opencode:` model; OpenCode is not part of the unconditional default provider set. Once registered and ready it discovers and contributes a model catalog like the other providers.
Functions ¶
func BackendModel ¶
BackendModel returns the OpenCode-native "provider/model" string for a model selection. It strips the two Agentico-only routing artifacts so OpenCode never sees them: the "opencode:" routing prefix (removed exactly once) and the trailing "[<window>]" context-window suffix (selection metadata, never part of a backend model name). The remaining slash-form id — including any colon-form tag such as an ollama "model:tag" — is preserved verbatim.
Types ¶
type AgentCapabilities ¶
type AgentCapabilities struct {
LoadSession bool `json:"loadSession"`
}
AgentCapabilities is the subset of the ACP initialize result that gates which optional protocol surfaces Agentico may use for this OpenCode session. Only the fields the tracer acts on are decoded; unknown capability fields are ignored. loadSession reports whether the agent supports session/load, the ACP-standard mechanism Agentico uses to resume a prior session identity.
type AuthMethod ¶
type AuthMethod struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
}
AuthMethod describes an authentication method OpenCode offers.
type ClientCapabilities ¶
type ClientCapabilities struct {
FS FSCapability `json:"fs"`
// Terminal is intentionally false — Agentico does not host an ACP terminal
// for OpenCode.
Terminal bool `json:"terminal"`
}
ClientCapabilities declares which client-side capabilities Agentico supports. Agentico hosts the client filesystem surface (fs/read_text_file, fs/write_text_file) because OpenCode delegates I/O for paths outside its session workspace to the client; without it, an out-of-workspace artifact write (knowledge-base graph, feature-state artifact) would fail closed. The terminal surface stays unhosted, so terminal/* requests still fail closed.
type ClientInfo ¶
ClientInfo identifies the Agentico client to OpenCode.
type ContentBlock ¶
ContentBlock is an ACP content block. Agentico sends only text blocks.
type ErrorResponse ¶
type ErrorResponse struct {
JSONRPC string `json:"jsonrpc"`
ID json.RawMessage `json:"id"`
Error RPCError `json:"error"`
}
ErrorResponse is an outbound JSON-RPC 2.0 error response to a server-initiated (agent-to-client) request. Agentico fails closed with this response whenever OpenCode asks for a client capability that is not implemented.
type FSCapability ¶
type FSCapability struct {
ReadTextFile bool `json:"readTextFile"`
WriteTextFile bool `json:"writeTextFile"`
}
FSCapability declares client filesystem capabilities. Both true: Agentico hosts fs/read_text_file and fs/write_text_file (see clientfs.go).
type FSResultResponse ¶
type FSResultResponse struct {
JSONRPC string `json:"jsonrpc"`
ID json.RawMessage `json:"id"`
Result any `json:"result"`
}
FSResultResponse is an outbound JSON-RPC result for a hosted fs/* request: Result is null for a successful write and a ReadTextFileResult for a read.
type InitializeParams ¶
type InitializeParams struct {
ProtocolVersion int `json:"protocolVersion"`
ClientCapabilities ClientCapabilities `json:"clientCapabilities"`
ClientInfo *ClientInfo `json:"clientInfo,omitempty"`
}
InitializeParams are the parameters for the ACP initialize request.
type InitializeResult ¶
type InitializeResult struct {
ProtocolVersion int `json:"protocolVersion"`
AgentInfo *AgentInfo `json:"agentInfo,omitempty"`
AuthMethods []AuthMethod `json:"authMethods,omitempty"`
AgentCapabilities AgentCapabilities `json:"agentCapabilities"`
}
InitializeResult is OpenCode's response to initialize.
type Notification ¶
type Notification struct {
JSONRPC string `json:"jsonrpc"`
Method string `json:"method"`
Params interface{} `json:"params,omitempty"`
}
Notification is an outbound JSON-RPC 2.0 notification (no id, no response).
type PermissionOption ¶
type PermissionOption struct {
OptionID string `json:"optionId"`
Name string `json:"name"`
Kind string `json:"kind,omitempty"`
Description string `json:"description,omitempty"`
Recommended bool `json:"recommended,omitempty"`
Confidence *float64 `json:"confidence,omitempty"`
}
PermissionOption is one selectable response to a session/request_permission request. For a tool permission, Kind is one of the allow_*/reject_* values and Name is the human label ("Allow", "Reject"). For a question (Kind=="question" on the tool call), each option is an answer choice: Name is the answer label, and the optional Description/Recommended/Confidence enrich the surfaced AskUserQuestion when OpenCode provides them.
type PermissionOutcome ¶
type PermissionOutcome struct {
Outcome string `json:"outcome"`
OptionID string `json:"optionId,omitempty"`
}
PermissionOutcome is the user's decision. Outcome is "selected" with the chosen OptionID, or "cancelled" when no option applies (e.g. a denial with no reject option, or a free-form answer that matched no listed choice).
type PermissionOutcomeResult ¶
type PermissionOutcomeResult struct {
Outcome PermissionOutcome `json:"outcome"`
}
PermissionOutcomeResult wraps the outcome in the ACP result envelope.
type PermissionResponse ¶
type PermissionResponse struct {
JSONRPC string `json:"jsonrpc"`
ID int `json:"id"`
Result PermissionOutcomeResult `json:"result"`
}
PermissionResponse is the outbound JSON-RPC result for a session/request_permission request. It carries the user's outcome so OpenCode either runs the gated action / records the answer or skips it.
type PermissionToolCall ¶
type PermissionToolCall struct {
ToolCallID string `json:"toolCallId,omitempty"`
Title string `json:"title,omitempty"`
Kind string `json:"kind,omitempty"`
RawInput json.RawMessage `json:"rawInput,omitempty"`
}
PermissionToolCall describes the action OpenCode wants permission for, or the question it wants answered. Kind classifies the surface (execute, edit, fetch, search, read, question); RawInput carries the tool's native input so the permission prompt and cache can show and match concrete detail; Title is a human summary used as the question stem and as a detail fallback.
type PromptParams ¶
type PromptParams struct {
SessionID string `json:"sessionId"`
Prompt []ContentBlock `json:"prompt"`
}
PromptParams are the parameters for session/prompt.
type PromptResult ¶
type PromptResult struct {
StopReason string `json:"stopReason"`
Usage *PromptUsage `json:"usage,omitempty"`
}
PromptResult is OpenCode's response to session/prompt. The end-turn token accounting rides in Usage (the ACP end-turn-token-usage shape OpenCode builds via UsageService.buildUsage); StopReason classifies the outcome. When present, Usage folds into the terminal result's normalized usage.
type PromptUsage ¶
type PromptUsage struct {
TotalTokens int `json:"totalTokens"`
InputTokens int `json:"inputTokens"`
OutputTokens int `json:"outputTokens"`
ThoughtTokens int `json:"thoughtTokens"`
CachedReadTokens int `json:"cachedReadTokens"`
CachedWriteTokens int `json:"cachedWriteTokens"`
}
PromptUsage is OpenCode's end-turn token accounting attached to the session/prompt result, matching the real ACP wire shape (camelCase, verified against packages/opencode/src/acp/usage.ts and the ACP end-turn-token-usage RFD). thoughtTokens/cachedReadTokens/cachedWriteTokens are omitted when zero.
This is the ONLY carrier of the input/output/cache token split — the streamed usage_update notification reports context and cost but no per-token breakdown. Each result's tokens are summed once into the protocol's cumulative totals, so a multi-turn session (e.g. a question/answer follow-up) accumulates without double-counting. When OpenCode emits nothing, usage stays zero (no context %).
type Protocol ¶
type Protocol struct {
// contains filtered or unexported fields
}
Protocol implements llm.Protocol for the OpenCode ACP (Agent Client Protocol) JSON-RPC stdio transport. One instance is created per session.
func NewProtocol ¶
func NewProtocol(opts llm.ProtocolOpts) *Protocol
NewProtocol creates a new OpenCode ACP protocol handler.
func (*Protocol) ACPSessionID ¶
ACPSessionID returns the internal ACP session id created during the handshake.
func (*Protocol) AdditionalSessionCost ¶ added in v0.147.0
AdditionalSessionCost returns costs for OpenCode-managed child sessions, such as Task subagents. OpenCode reports the parent ACP session cost separately from those rows, so Agentico has to add descendants explicitly.
func (*Protocol) BackendModelForTest ¶
BackendModelForTest returns the backend "provider/model" the protocol selected.
func (*Protocol) Handshake ¶
Handshake performs the ACP bootstrap:
- initialize — negotiate the protocol version and read agent capabilities.
- session/new (or session/load when resuming) — establish the session, rooted at the resolved work directory, the prompt is delivered to.
- session/prompt — deliver the rendered Agentico phase prompt as the first user turn. The prompt response arrives asynchronously and is surfaced as a terminal result by ParseLine.
func (*Protocol) InitialPromptForTest ¶
InitialPromptForTest returns the rendered phase prompt the protocol will send as the first user turn.
func (*Protocol) Interrupt ¶
Interrupt cancels the in-flight turn using the ACP session/cancel notification, which OpenCode answers by completing the pending session/prompt with stopReason "cancelled" (mapped to a terminal non-success result). It returns llm.ErrNotSupported only before a session exists (no stdin or no session id yet), so the session layer's process-group SIGINT fallback still applies in that window.
func (*Protocol) NegotiatedVersion ¶
NegotiatedVersion returns the ACP protocol version OpenCode negotiated.
func (*Protocol) ParseLine ¶
func (p *Protocol) ParseLine(line []byte) ([]llm.SDKMessage, error)
ParseLine translates one JSON-RPC line from OpenCode's stdout into SDKMessages. Returns a nil slice for lines that produce no Agentico message (handshake responses, ignored notifications, blank framing lines). OpenCode's stdout is contractually clean newline-delimited JSON-RPC — its logs go to stderr — so a line that is not a valid JSON-RPC envelope is genuine protocol corruption and fails the tracer closed with a terminal non-success result rather than being silently dropped.
func (*Protocol) RespondToAskUser ¶
func (p *Protocol) RespondToAskUser(requestID string, questions json.RawMessage, answers map[string]string, _ map[string]llm.AskUserAnnotation) error
RespondToAskUser delivers the user's answer to an OpenCode question. A structured question with a native pending request is answered through that request's ACP outcome (selecting the option whose label the user chose); a synthetic question parsed from plain text — and a structured answer that matched no listed option — is delivered as a framed follow-up turn so the agent still receives the user's intent. annotations are accepted for interface parity; OpenCode carries no per-question note side-channel.
func (*Protocol) RespondToControl ¶
func (p *Protocol) RespondToControl(requestID string, allow bool, _ json.RawMessage, _ string) error
RespondToControl answers a permission request as an ACP outcome: approval selects an allow-kind option and denial selects a reject-kind option. A denial with no reject option (or an unknown request) is answered "cancelled" so the action does not run and OpenCode still unblocks. originalInput and reason are accepted for interface parity; OpenCode's outcome carries neither.
func (*Protocol) RespondToHook ¶
RespondToHook is a no-op — OpenCode ACP has no PreToolUse hook callbacks.
func (*Protocol) SendUserMessage ¶
SendUserMessage delivers a follow-up user turn as a new session/prompt.
func (*Protocol) SessionID ¶
SessionID returns the captured ACP session id so Agentico can scope session views, PID-file identity, and the permission cache to this OpenCode session, and so a later run can request a resume of it. It is empty until the handshake establishes (or resumes) a session.
func (*Protocol) SetLogFunc ¶
SetLogFunc sets a logging function for debug output.
func (*Protocol) SetRequestIDsForTest ¶
SetRequestIDsForTest pins the handshake request ids (including session/load) so other packages can drive a real protocol through session establishment and prompt responses without running the full ACP handshake. Test-only.
func (*Protocol) TranscriptPath ¶
TranscriptPath returns a concrete OpenCode transcript path only when the provider has proven one over ACP. OpenCode exposes no transcript path through the ACP surface Agentico uses, so this is empty (best-effort) rather than a fabricated path; it never panics.
func (*Protocol) WorkDirForTest ¶
WorkDirForTest returns the resolved work directory used for session/new.
type Provider ¶
type Provider struct {
// contains filtered or unexported fields
}
Provider implements llm.LLMProvider for the OpenCode CLI (ACP stdio mode).
runner is injectable so version/readiness/discovery probes can be exercised in tests without a real OpenCode binary; production code falls back to clirun helpers. catalog holds the model catalog discovered at startup (empty until discovery runs); rates holds the per-model pricing parsed alongside it. Both are guarded by mu because discovery, startup enrichment, and routing lookups touch them from different goroutines.
func New ¶
func New() *Provider
New returns a Provider with the default (production) command runner and the default CLI binary name.
func NewWithBinary ¶ added in v0.149.0
NewWithBinary returns a Provider that invokes the supplied CLI binary name (or the default when empty). It is the constructor used by the FX module to honor the providers.opencode.cli config override.
func NewWithRunner ¶
func NewWithRunner(runner clirun.CommandRunner) *Provider
NewWithRunner returns a Provider that uses the supplied command runner for its version, readiness, and model-discovery probes instead of shelling out to the real OpenCode binary. It is a dependency-injection seam for tests that drive the provider through the shared startup discovery and cache path; production code uses New.
func (*Provider) AskingQuestionsClause ¶
AskingQuestionsClause provides the provider-specific asking-questions prompt section. OpenCode questions surface through Agentico's shared AskUserQuestion flow: the protocol parses the agent's numbered text alternatives into a formal AskUserQuestion that pauses the session for the user, so the clause directs the agent to express any question in exactly that numbered, confidence-qualified format (the structure the plain-text parser reads). A question phrased this way becomes a help-waiting pause, not a phase completion.
func (*Provider) AvailableModels ¶
AvailableModels returns only discovered or cached model IDs.
func (*Provider) BuildCommand ¶
BuildCommand returns the args and environment needed to launch OpenCode in ACP stdio mode with a deterministic, Agentico-owned managed session configuration.
The backend model is validated as a data value before any command is constructed: empty selections, CLI-flag-shaped values, and values carrying shell/interpolation metacharacters fail closed so a malformed or hostile selection can never reach a launchable command (and an empty selection never silently falls back to OpenCode's default model). Valid slash-form "provider/model" ids pass through unchanged.
The command itself is the bare `opencode acp`: it speaks newline-delimited JSON-RPC on stdout while sending its own logs to stderr, so stdout stays valid for the protocol reader. Managed configuration is generated under the provider-managed state directory and delivered through the OPENCODE_CONFIG file plus the highest-precedence OPENCODE_CONFIG_CONTENT inline channel, while inherited compatibility/config sources are scrubbed through environment flags — none of which mutates the user's global OpenCode configuration. Any build failure aborts before a launchable command exists. See buildManagedSession.
func (*Provider) CheckReadiness ¶
func (p *Provider) CheckReadiness(ctx context.Context) llm.ProviderReadiness
CheckReadiness probes whether OpenCode is configured with usable provider access, beyond mere binary presence. It runs the non-interactive `opencode models`, which lists the models reachable from configured providers, and distinguishes ready / installed-but-unconfigured / command-failed / timed-out states with actionable remedies.
func (*Provider) ComputeCost ¶
ComputeCost computes token cost from the pricing parsed during catalog discovery. When pricing was exposed for the model in a stable numeric shape it is applied (per million tokens); otherwise — unknown model, no pricing, or a a catalog without advertised pricing — it returns 0 so the session falls back to the cost OpenCode reports over ACP without corrupting usage summaries.
func (*Provider) ContextWindowForModel ¶
ContextWindowForModel returns the context window for a model from the discovered or cached catalog, matching by canonical id or alias (so suffixed IDs, unsuffixed aliases, and the canonicalized form of an explicit "opencode:" selection all resolve). It returns 0 only when no catalog metadata exists for the model, which callers treat as "unknown" without corrupting behavior.
func (*Provider) DetectCLI ¶
DetectCLI reports whether the OpenCode CLI binary is available in PATH.
func (*Provider) DiscoverModelCatalog ¶
DiscoverModelCatalog refreshes OpenCode's model catalog from the local CLI.
func (*Provider) DiscoverModelCatalogWithProgress ¶
func (p *Provider) DiscoverModelCatalogWithProgress(ctx context.Context, report llm.ModelDiscoveryReporter) ([]llm.ModelInfo, error)
DiscoverModelCatalogWithProgress refreshes OpenCode's model catalog and, on success, reports each parsed model in catalog order before returning. Pricing parsed alongside the catalog is stored on the provider for ComputeCost. The returned error is sanitized so a failed discovery cannot leak credential-like or terminal-control content into a startup warning, log, or cache diagnostic.
func (*Provider) EnablesPendingToolWatchdog ¶
EnablesPendingToolWatchdog opts this adapter into the generic session watchdog for providers that can report tool lifecycle updates without necessarily completing the enclosing turn or surfacing a permission request. The historical capability name is retained for compatibility; it enables both the running-tool and post-tool turn-completion safety rails.
func (*Provider) EnforcesMinVersion ¶
EnforcesMinVersion reports that OpenCode must meet MinVersion() to be ready at startup. Because its ACP wire behavior is only verified at or above 1.17.9, a too-old CLI is filtered out of the ready provider set — and thus out of routing, catalog discovery, and model lists — rather than left selectable with only a warning.
func (*Provider) EnvVarsToExclude ¶
EnvVarsToExclude returns nil — OpenCode needs no env stripping.
func (*Provider) InstallHint ¶
InstallHint returns the supported OpenCode install command.
func (*Provider) MatchesModel ¶
MatchesModel reports whether this provider handles the given model string.
An explicit "opencode:" routing prefix always matches when a backend model follows it (the bare prefix "opencode:" with no backend is not a valid selection). A bare model string matches only when it names an entry in the effective catalog — a discovered or cached catalog — by canonical id or alias. Catalog IDs are slash-form "provider/model" values, so a ready OpenCode never captures a bare name (e.g. "sonnet", "gpt-5.4") meant for another provider.
func (*Provider) MinVersion ¶
MinVersion returns the minimum OpenCode CLI version required. 1.17.9 is the earliest version against which the OpenCode ACP behavior (initialize with protocolVersion 1, session/new, session/prompt, session/update streaming) and the `opencode models` discovery surface have been verified.
func (*Provider) ModelCatalog ¶
ModelCatalog returns an isolated snapshot of discovered or cached metadata. No models or capabilities are fabricated when discovery is unavailable.
func (*Provider) NewProtocol ¶
func (p *Provider) NewProtocol(opts llm.ProtocolOpts) llm.Protocol
NewProtocol creates a per-session ACP protocol handler.
func (*Provider) RefreshCatalogOnStartup ¶ added in v0.156.0
RefreshCatalogOnStartup prevents a CLI-version cache from hiding changes to user-defined provider models or variants. A failed refresh can use a stale cache with the startup warning, but no model catalog is fabricated.
func (*Provider) ReviewPreferenceBand ¶ added in v0.149.0
ReviewPreferenceBand admits discovered text models for native toolless review without guessing quality or cost from family names.
func (*Provider) SetModelCatalog ¶
SetModelCatalog installs an isolated metadata snapshot and restores its advertised pricing, including when the catalog was loaded from cache.
func (*Provider) SupportsNativeToollessReview ¶ added in v0.149.0
SupportsNativeToollessReview attests that the provider's isolated managed configuration and ACP protocol implement Agentico's complete hidden-review contract. BuildCommand activates that boundary only when all three native isolation options are requested; ordinary OpenCode sessions are unchanged.
func (*Provider) SupportsSessionResume ¶ added in v0.149.0
SupportsSessionResume reports that a prior ACP session can be resumed via ProtocolOpts.ResumeSessionID (session/load). Agents that do not advertise the loadSession capability fail the resume handshake with a clear error, which callers treat as "resume unavailable" and fall back.
func (*Provider) UsesBoundedHelperSandbox ¶
UsesBoundedHelperSandbox opts bounded helper sessions into OS-level worktree sandboxing so helper shell probes fail as process errors rather than provider permission denials.
func (*Provider) VersionInfo ¶
VersionInfo runs `opencode --version` (through the injectable runner) and returns the parsed semver string (e.g. "1.17.9"), matching the Claude and Codex providers. Parsing — rather than returning the raw command output — guarantees the value the startup discovery path uses as the catalog cache key, cache filename, and persisted cache metadata is a clean version token that cannot carry trailing credential-like or terminal-control content from a malformed or hostile `opencode --version` line. On unparseable output it returns a generic error that does not echo the raw output, so no untrusted content reaches the startup version diagnostic either. It shares the same runner seam as discovery.
type ReadTextFileParams ¶
type ReadTextFileParams struct {
SessionID string `json:"sessionId"`
Path string `json:"path"`
Line *int `json:"line,omitempty"`
Limit *int `json:"limit,omitempty"`
}
ReadTextFileParams is the params of an fs/read_text_file request. Line is an optional 1-based start line and Limit an optional maximum number of lines.
type ReadTextFileResult ¶
type ReadTextFileResult struct {
Content string `json:"content"`
}
ReadTextFileResult is the result of a hosted fs/read_text_file request.
type Request ¶
type Request struct {
JSONRPC string `json:"jsonrpc"`
ID int `json:"id"`
Method string `json:"method"`
Params interface{} `json:"params,omitempty"`
}
Request is an outbound JSON-RPC 2.0 request (has id, expects a response).
type RequestPermissionParams ¶
type RequestPermissionParams struct {
SessionID string `json:"sessionId"`
ToolCall PermissionToolCall `json:"toolCall"`
Options []PermissionOption `json:"options"`
}
RequestPermissionParams is the params object of a session/request_permission request. OpenCode describes the gated action in ToolCall and offers the selectable Options the user picks among.
type SessionCancelParams ¶
type SessionCancelParams struct {
SessionID string `json:"sessionId"`
}
SessionCancelParams are the parameters for the session/cancel notification.
type SessionLoadParams ¶
type SessionLoadParams struct {
SessionID string `json:"sessionId"`
Cwd string `json:"cwd"`
MCPServers []interface{} `json:"mcpServers"`
}
SessionLoadParams are the parameters for session/load. The sessionId names the prior session to resume; cwd and mcpServers mirror session/new so the resumed session is rooted at the same work directory.
type SessionNewParams ¶
type SessionNewParams struct {
Cwd string `json:"cwd"`
MCPServers []interface{} `json:"mcpServers"`
}
SessionNewParams are the parameters for session/new.
type SessionNewResult ¶
type SessionNewResult struct {
SessionID string `json:"sessionId"`
}
SessionNewResult is OpenCode's response to session/new.
type SessionUpdate ¶
type SessionUpdate struct {
SessionUpdate string `json:"sessionUpdate"`
// agent_message_chunk / agent_thought_chunk carry an object content block;
// tool_call_update may carry an array of output content blocks. Keep it raw
// so the polymorphic shape cannot make the whole session/update fail to
// decode.
MessageID string `json:"messageId,omitempty"`
Content json.RawMessage `json:"content,omitempty"`
// tool_call / tool_call_update
ToolCallID string `json:"toolCallId,omitempty"`
Title string `json:"title,omitempty"`
Kind string `json:"kind,omitempty"`
Status string `json:"status,omitempty"`
Locations []ToolCallLocation `json:"locations,omitempty"`
RawInput json.RawMessage `json:"rawInput,omitempty"`
RawOutput json.RawMessage `json:"rawOutput,omitempty"`
// usage_update: Used is the tokens currently in context (input + cache read),
// Size is the model's total context window, and Cost is the cumulative
// session cost. These drive context-% reporting and cost; they carry no
// per-token (input/output/cache) split — that lives only on the prompt result.
Used int `json:"used,omitempty"`
Size int `json:"size,omitempty"`
Cost *UsageCost `json:"cost,omitempty"`
}
SessionUpdate is the polymorphic body of a session/update; SessionUpdate (the discriminator) selects which fields are populated.
type SessionUpdateParams ¶
type SessionUpdateParams struct {
SessionID string `json:"sessionId"`
Update SessionUpdate `json:"update"`
}
SessionUpdateParams is the params object of a session/update notification.
type ToolCallLocation ¶
type ToolCallLocation struct {
Path string `json:"path,omitempty"`
Line int `json:"line,omitempty"`
}
ToolCallLocation is an ACP source/file location attached to a tool call. OpenCode uses it for edit targets and, for some shell commands, the directory context where the command ran.
type UpdateContent ¶
UpdateContent is the content block carried by message-chunk updates.
type UsageCost ¶
UsageCost is the cumulative session cost carried on a usage_update. Amount is the running total in Currency (ISO-4217). OpenCode omits it (or sends zero) when the backend has no pricing, in which case Agentico keeps its zero-cost fallback rather than inventing a figure.
type WriteTextFileParams ¶
type WriteTextFileParams struct {
SessionID string `json:"sessionId"`
Path string `json:"path"`
Content string `json:"content"`
}
WriteTextFileParams is the params of an fs/write_text_file request: OpenCode asks the client to write Content to Path. ACP fs paths are absolute; a relative path is resolved against the session working directory.