opencode

package
v0.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 1, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Overview

Package opencode implements the built-in OpenCode agent runtime behind the public CandaceOS harness seam.

What OpenCode is

OpenCode is a separate server process (pinned to PinnedServerVersion) that owns the agent loop: the model, the tool calls, and the transcript. This package never runs a model or a tool. It speaks to that server over HTTP with the official generated SDK, attaches to exactly one OpenCode session scoped to one workspace directory, and projects that session's provider transcript into the normalized Liquid Proto HarnessEvent stream that CandaceOS Core consumes.

What the runtime owns

The runtime owns only what the provider does not:

  • Run correlation. Core submits a prompt carrying a run ID. The runtime remembers which provider message a run ID belongs to and fences every projected event to the run of the turn that is currently active, so a late or historical provider message can never be attributed to a newer run.
  • Admission. Follow-up guidance is admitted through a bounded FIFO queue whose capacity comes from configuration; an overflow is rejected with ErrQueueFull rather than dropped.
  • Delivery semantics. See "Steering" below.
  • Publication retry. Host.Publish is allowed to fail. A projected event is recorded as delivered only after the host accepts it, so a failed publication is retried on the next reconciliation instead of being lost, and an idle transition is never published ahead of the terminal event it concludes.

The runtime owns none of Core's authority: approvals, fleet truth, reconciliation, durable run state, and UI projection stay in Core. Session state here is in memory only; a restart re-attaches and re-hydrates rather than replaying history.

Steering

A prompt carries a delivery mode. HARNESS_DELIVERY_ENQUEUE appends to the bounded queue and is drained in FIFO order as each turn completes, with no idle event published between queued turns. HARNESS_DELIVERY_IMMEDIATE steers the active turn: when the session is busy the runtime aborts the in-flight provider turn, marks that abort as operator-intentional so the resulting provider "aborted" error is suppressed rather than surfaced as a failure, and submits the replacement prompt in its place. This is the capability the factory advertises as HARNESS_CAPABILITY_ACTIVE_TURN_STEERING.

Abort clears queued guidance, keeps the aborting run's fence so the idle event that concludes it carries the right run ID, and leaves the session ready for new work.

Concurrency model

Every mutation of session state happens on one command goroutine reached through an unbuffered mailbox, so no session field needs a lock and no operation observes a torn state. Start, Activate, Send, Abort, and Close are safe to call concurrently; each blocks until the command goroutine has run it. Provider HTTP calls that must be ordered against session state (prompt submission, abort, reconciliation) deliberately run on that goroutine under the configured request timeout, which is what makes "publish the terminal event before accepting newer guidance" observable rather than racy.

Two background goroutines are started by Activate and stopped by Close: a poller that reconciles the transcript on the configured interval, and an event-stream watcher that collapses provider server-sent events into reconciliation wakeups. Close cancels both, waits for them, and is idempotent.

Index

Constants

View Source
const PinnedServerVersion = "1.18.21"

PinnedServerVersion is the single OpenCode server version this package is contracted against. Start refuses to attach to any other version rather than projecting a transcript whose shape it cannot vouch for, so the sidecar image and this constant are upgraded together.

Variables

View Source
var (
	// ErrConfigRequired reports a nil OpenCodeConfig supplied to NewFactory.
	ErrConfigRequired = errors.New("opencode: configuration is required")
	// ErrHostRequired reports a nil harness.IHost supplied to Factory.New.
	ErrHostRequired = errors.New("opencode: host is required")
	// ErrProviderRequired reports a runtime constructed with no provider.
	ErrProviderRequired = errors.New("opencode: provider is required")
	// ErrModel reports a configured model outside the providerID/modelID
	// grammar. Only the first separator splits, so "openrouter/openai/gpt" is
	// provider "openrouter" and model "openai/gpt".
	ErrModel = errors.New("opencode: model must be providerID/modelID")

	// ErrClosed reports an operation that arrived after Close began. It is
	// terminal: the runtime never becomes usable again.
	ErrClosed = errors.New("opencode: runtime is closed")
	// ErrAlreadyStarted reports a second Start on one runtime.
	ErrAlreadyStarted = errors.New("opencode: runtime is already started")
	// ErrAlreadyActivated reports a second Activate on one runtime.
	ErrAlreadyActivated = errors.New("opencode: runtime is already activated")
	// ErrSessionUnavailable reports an operation with no attached, activated,
	// live session: before Start, before Activate, or after the session
	// lifecycle was canceled. Core may retry after a fresh Start.
	ErrSessionUnavailable = errors.New("opencode: session is unavailable")

	// ErrQueueFull reports a follow-up prompt rejected because the bounded FIFO
	// queue is at its configured capacity. The caller may retry once a turn
	// completes; nothing was submitted to the provider.
	ErrQueueFull = errors.New("opencode: prompt queue is full")

	// ErrUnhealthy reports that the OpenCode server answered its health probe
	// without reporting itself healthy.
	ErrUnhealthy = errors.New("opencode: server reported unhealthy")
	// ErrVersionMismatch reports a server outside the pinned version contract.
	// The wrapped message names both the reported and the pinned version.
	ErrVersionMismatch = errors.New("opencode: server version does not match the pinned contract")
	// ErrEmptySession reports a session response with no usable identity.
	ErrEmptySession = errors.New("opencode: server returned an empty session")
	// ErrWorkspaceMismatch reports a session bound to a directory other than
	// the workspace Core supplied. The runtime refuses to attach to it.
	ErrWorkspaceMismatch = errors.New("opencode: session belongs to another workspace")
	// ErrIncoherentSession reports that the session's status kept changing
	// while the runtime tried to read one coherent transcript snapshot.
	ErrIncoherentSession = errors.New("opencode: session kept changing while hydrating")
	// ErrAbortRejected reports an abort the server accepted but did not
	// acknowledge as applied.
	ErrAbortRejected = errors.New("opencode: server did not acknowledge the abort")
)

Sentinel errors returned by this package. Every error a caller can act on is reachable with errors.Is; nothing in this package expects a caller to match on error text. Errors that carry detail wrap the sentinel with fmt.Errorf("%w: ...") and keep the "opencode: " prefix supplied by the sentinel.

Functions

This section is empty.

Types

type Factory

type Factory struct {
	// contains filtered or unexported fields
}

Factory constructs OpenCode runtimes from one immutable, validated transport policy. One Factory may be reused for many runtimes; every runtime it produces is an independent session that shares nothing but the snapshot. Factory is safe for concurrent use.

func NewFactory

func NewFactory(config *candaceosv1.OpenCodeConfig) (*Factory, error)

NewFactory validates config and snapshots it, so a later mutation by the caller cannot change how sessions are opened. It reports ErrConfigRequired for a nil config, the Liquid Proto validation error for a config outside its declared bounds, and ErrModel for a model outside the providerID/modelID grammar.

func (*Factory) New

func (factory *Factory) New(
	harnessContext *candaceosv1.HarnessContext,
	host harness.IHost,
) (*harness.Instance, error)

New implements harness.IFactory. It validates harnessContext, then returns a runtime bound to that context's workspace and the supplied host. The returned runtime has already started its command goroutine, so the caller owns it and must Close it even if Start is never called or later fails. host must remain usable until that Close returns.

The advertised identity is fixed: this backend has workspace-write and active-turn steering capabilities, and reports the configured model.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL