opencode

package
v0.15.4 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2026 License: AGPL-3.0 Imports: 21 Imported by: 0

Documentation

Index

Constants

View Source
const (
	V2DeliveryQueue = agent.V2DeliveryQueue
	V2DeliverySteer = agent.V2DeliverySteer
)

Re-export V2 delivery constants.

Variables

View Source
var (
	ErrV2PromptConflict  = agent.ErrV2PromptConflict
	ErrV2SessionNotFound = agent.ErrV2SessionNotFound
)

V2 prompt/interrupt error sentinels. These are distinct from the V1 V2 prompt/interrupt error sentinels re-exported from pkg/agent (the canonical location). Callers branch on these to decide retry vs. surface-to-user.

View Source
var ErrNoRunningPod = agent.ErrNoRunningPod

ErrNoRunningPod is re-exported from pkg/agent (the canonical location). Callers should use agent.ErrNoRunningPod; this alias exists for backward compatibility with code that still imports this package.

Functions

func FormatOpenCodeConfig

func FormatOpenCodeConfig(providers []secrets.LLMProviderData) ([]byte, error)

FormatOpenCodeConfig renders a slice of validated LLMProviderData into the JSON shape opencode accepts.

**Schema** (evidence-driven; established by live cluster probe in worklog 0128. Do NOT change without re-validating against a running opencode):

{
  "$schema": "https://opencode.ai/config.json",
  "provider": {                          <-- SINGULAR (not "providers")
    "<id>": {
      "options": {                       <-- direct, NO aisdk wrapper
        "apiKey":  "...",                <-- the credential
        "baseURL": "..."                 <-- in options, NOT in a
      },                                     separate `endpoint` object
      "models": { "<id>": { "name": "..." } }
    }
  },
  "model": "<id>/<modelID>"
}

What pre-fix code generated, and why opencode rejected it:

  • top-level key was `providers` (plural) → ConfigInvalidError
  • apiKey lived at options.aisdk.provider.apiKey → ConfigInvalidError
  • baseURL lived at endpoint.url → silently ignored (chat requests went to api.openai.com instead of the operator's endpoint)

The function is pure — no side effects, no filesystem access.

Returns an error if providers is empty (callers MUST check for this — opencode treats an empty config differently and a "no-op write of an empty config" is a bug).

func ParseHistoryStream added in v0.14.4

func ParseHistoryStream(r io.Reader, workspaceID string) (msgs []session.Message, changedFilesPerMsg [][]string, downgraded int, err error)

ParseHistoryStream decodes + translates an opencode history array from an io.Reader using a streaming json.Decoder. It does NOT buffer the whole body — peak memory is O(largest single message), not O(total history size). This removes the silent-truncation failure mode that affected sessions larger than the previous fixed readBody cap (issue #737).

Resilience is identical to ParseHistoryWire (issue #730): a message that fails to decode is downgraded to a session.MessageSystem notice and counted in `downgraded`; the rest translate normally.

func ParseHistoryWire added in v0.14.0

func ParseHistoryWire(body []byte, workspaceID string) (msgs []session.Message, changedFilesPerMsg [][]string, downgraded int, err error)

ParseHistoryWire is the testable boundary: bytes in, contract out. Used by Adapter.GetHistory after the HTTP round-trip. Returns the translated messages AND a parallel slice of changed-file path lists (one entry per message; nil for messages with no patch part). The caller uses the changed-files to produce FileChange parts via filediff.Producer.

Exported for the package's own test consumers (translate_test.go, adapter_test.go).

Resilience (issues #730, #737): delegates to ParseHistoryStream which uses a streaming json.Decoder — no body-size cap, no buffering of the full array. Each message is decoded independently; a message that fails to decode (e.g. a future opencode wire-shape change in one part) is downgraded to a session.MessageSystem notice rather than failing the entire history. If the body is truncated mid-stream, the messages decoded so far are returned with no error (graceful partial result).

The returned `downgraded` count is the number of messages that were degraded to system notices. Callers (Adapter.GetHistory) log it so operators have a signal when wire-shape drift is happening (Rule 3: no swallowed errors).

func ParseSessionListWire added in v0.14.0

func ParseSessionListWire(body []byte, workspaceID string) ([]session.Session, error)

ParseSessionListWire is the testable boundary for GET /session.

opencode 1.18.10 returns a bare array; some earlier versions wrap in {data: [...]}. We try the wrapped format first (parse succeeds → use it, including when Data is empty); fall back to the bare array only when the wrapped parse fails (body was not an object).

func ParseSessionWire added in v0.14.0

func ParseSessionWire(body []byte, workspaceID string) (*session.Session, error)

ParseSessionWire is the testable boundary for GET /session/:id.

func Register

func Register()

Types

type Adapter added in v0.14.0

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

Adapter implements agent.Adapter for the opencode runtime.

Construction: NewAdapter(pw, ip, logger, opts...) resolves each call to the workspace's pod IP + password via the supplied resolvers, then delegates to the low-level *Client. The shared HTTP client pools connections across all workspaces.

Translation: every method translates opencode's wire shapes to the platform contract via the pure functions in translate.go. The translator never sees an HTTP response — it gets bytes — so it is independently testable.

Design 0049 §4.6: 16 methods. AgentConfigWriter is intentionally NOT implemented here — see the agent.Adapter doc comment for why (the two seams run in different processes with different filesystem capabilities).

Credential methods (FormatProviderConfig, ValidateCredentials) delegate to the existing OpenCodeAgent (agent.AgentRuntime) to avoid behavior divergence. R3 from PR #714 review: duplication between Adapter and OpenCodeAgent was a maintenance hazard; delegation keeps one source of truth.

func NewAdapter added in v0.14.0

func NewAdapter(pw PasswordResolver, ip PodIPResolver, logger *zap.Logger, opts ...AdapterOption) *Adapter

NewAdapter constructs an opencode Adapter that resolves workspace → podIP + password on each call. The httpCli is shared across all calls for connection pooling; port defaults to agentd.AgentPort.

func (*Adapter) Abort added in v0.14.0

func (a *Adapter) Abort(ctx context.Context, userID, workspaceID, sessionID string) error

func (*Adapter) Capabilities added in v0.14.0

func (a *Adapter) Capabilities() []session.Capability

func (*Adapter) CreateSession added in v0.14.0

func (a *Adapter) CreateSession(ctx context.Context, userID, workspaceID, title string) (*session.Session, error)

func (*Adapter) DeleteSession added in v0.14.0

func (a *Adapter) DeleteSession(ctx context.Context, userID, workspaceID, sessionID string) error

func (*Adapter) FormatProviderConfig added in v0.14.0

func (a *Adapter) FormatProviderConfig(providers []agent.LLMProviderData) ([]byte, error)

func (*Adapter) GetHistory added in v0.14.0

func (a *Adapter) GetHistory(ctx context.Context, userID, workspaceID, sessionID string) ([]session.Message, error)

func (*Adapter) GetSession added in v0.14.0

func (a *Adapter) GetSession(ctx context.Context, userID, workspaceID, sessionID string) (*session.Session, error)

func (*Adapter) ListAvailableModels added in v0.14.0

func (a *Adapter) ListAvailableModels(ctx context.Context, userID, workspaceID string) ([]session.ModelInfo, error)

func (*Adapter) ListPending added in v0.14.0

func (a *Adapter) ListPending(ctx context.Context, userID, workspaceID, sessionID string) ([]session.InputRequest, error)

func (*Adapter) ListSessions added in v0.14.0

func (a *Adapter) ListSessions(ctx context.Context, userID, workspaceID string) ([]session.Session, error)

func (*Adapter) RenameSession added in v0.14.0

func (a *Adapter) RenameSession(ctx context.Context, userID, workspaceID, sessionID, title string) error

func (*Adapter) Resolve added in v0.14.0

func (a *Adapter) Resolve(ctx context.Context, userID, workspaceID, requestID, reply string) error

func (*Adapter) Send added in v0.14.0

func (a *Adapter) Send(ctx context.Context, userID, workspaceID, sessionID, text string, opts session.SendOpts) (*session.Message, error)

func (*Adapter) SendAsync added in v0.14.0

func (a *Adapter) SendAsync(ctx context.Context, userID, workspaceID, sessionID, text string, opts session.SendOpts) (string, error)

func (*Adapter) SetModel added in v0.14.0

func (a *Adapter) SetModel(ctx context.Context, userID, workspaceID, sessionID string, model session.ModelRef) error

func (*Adapter) Stream added in v0.14.0

func (a *Adapter) Stream(ctx context.Context, userID, workspaceID, sessionID string) (<-chan session.Event, error)

Stream subscribes to the workspace's /event SSE endpoint, translates each event to session.Event, and sends on the returned channel. The channel closes when the context is canceled or the upstream closes the connection. Unknown event types are dropped (not sent on the channel). Scanner errors (connection breakage) are emitted as session.EventError events before the channel closes.

Thread-safety: each Stream call opens its own HTTP connection. Safe for concurrent use across workspaces.

func (*Adapter) ValidateCredentials added in v0.14.0

func (a *Adapter) ValidateCredentials(rawConfig []byte) (*agent.CredentialCheckResult, error)

type AdapterOption added in v0.14.0

type AdapterOption func(*Adapter)

AdapterOption configures an Adapter at construction.

func WithAdapterHTTPClient added in v0.14.0

func WithAdapterHTTPClient(hc *http.Client) AdapterOption

WithAdapterHTTPClient injects a shared *http.Client so connections are pooled across all workspace calls. When unset, a tuned default is used (mirrors WorkspaceClient.newTunedHTTPClient).

func WithAdapterPort added in v0.14.0

func WithAdapterPort(port int) AdapterOption

WithAdapterPort overrides the agent port the Adapter connects to. Defaults to agentd.AgentPort (4096). Used by tests that bind a fake server to a random port; production callers never override.

func WithFileDiffProducer added in v0.14.0

func WithFileDiffProducer(p *filediff.Producer) AdapterOption

WithFileDiffProducer wires a filediff.Producer so FileChange parts are produced from `git diff` on the workspace PVC. Required for GetHistory and Stream to emit FileChange parts; without it, patch parts are silently dropped (their file paths are still collected but no Patch text is produced). Used by the agentd-side construction; the API-side Adapter has no filesystem access to the PVC and skips this.

type AgentClient

type AgentClient interface {
	ListModels(ctx context.Context, userID, workspaceID string) ([]byte, error)
	PatchConfig(ctx context.Context, userID, workspaceID string, config map[string]any) error
	DisposeInstance(ctx context.Context, userID, workspaceID string) error
	GetSessionStatuses(ctx context.Context, userID, workspaceID string) (map[string]string, error)
	StageCredentials(ctx context.Context, userID, workspaceID string, providers []secrets.LLMProviderData) error
}

AgentClient abstracts all direct opencode HTTP communication at the workspace level (US-29.1). Each method resolves podIP and password internally from the injected resolvers, keeping callers clean of auth concerns. The interface is caller-shaped — consumers ask for what they need, not for a raw HTTP client.

userID is required for workspace ownership verification (the PodIPResolver enforces that the caller owns the workspace before returning the IP).

type Client

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

Client communicates with a running opencode instance's HTTP API. It implements credential injection via PUT /auth/:providerID (Control API) and instance disposal via POST /instance/dispose.

Every opencode endpoint — including /auth/* and /instance/* — is gated by HTTP Basic auth with username `agentd.AuthUsername` and the per-pod password mounted at /sandbox-cfg/password (= OPENCODE_SERVER_PASSWORD env var). Calling these endpoints without auth produces 401 + WWW-Authenticate: Basic realm="Secure Area", which is what broke the live credential flow in worklog 0125.

func NewClient

func NewClient(baseURL, password string, logger *zap.Logger, opts ...Option) *Client

NewClient creates a Client targeting the given opencode base URL.

password is the value mounted at /sandbox-cfg/password inside the sandbox pod and exported to opencode as OPENCODE_SERVER_PASSWORD. It is the SAME secret used by every other agentd → opencode call (see cmd/workspace-agentd/main.go OpenCodeClient). Passing the empty string is allowed (so unit tests that don't need auth-gated paths still work) but will fail against a real opencode server with 401.

func (*Client) Abort added in v0.15.1

func (c *Client) Abort(ctx context.Context, sessionID string) error

Abort calls POST /session/:id/abort on opencode. This is the V1 abort path, which is the only interrupt endpoint that exists on opencode 1.18.10+. The V2 endpoint (POST /api/session/:id/interrupt) was removed in 1.18.10 — the v2/ route group was deleted entirely from packages/opencode/src/server/routes/instance/httpapi/groups/v2/. On 1.18.10 the V2 path returns 204 from a catch-all stub but does nothing (verified live: a long V1 turn keeps running after V2 interrupt). The V1 /abort path returns 200 and actually stops the in-flight turn (verified live: session transitions to idle).

func (*Client) DisposeInstance

func (c *Client) DisposeInstance(ctx context.Context) error

DisposeInstance triggers POST /instance/dispose, which invalidates all InstanceState caches for the current instance. The opencode process stays alive; the next request triggers a fresh instance load with updated auth.

In-flight LLM calls are aborted. Sessions persist in SQLite.

func (*Client) GetSessionStatuses

func (c *Client) GetSessionStatuses(ctx context.Context) (map[string]string, error)

GetSessionStatuses calls GET /session/status on opencode and returns the current status of all known sessions. The map key is the session ID; the value is the status type string: "idle", "busy", or "retry".

func (*Client) InterruptV2 added in v0.12.2

func (c *Client) InterruptV2(ctx context.Context, sessionID string) error

InterruptV2 sends a non-destructive interrupt to an opencode V2 session. It POSTs to /api/session/:sid/interrupt with Basic auth.

The spike confirmed: returns HTTP 204 (No Content) both when a turn is in-flight AND when the session is idle (no-op success). Interrupt is non-destructive (F8): admitted-but-unpromoted queue entries survive and run on the next execution.wake. This replaces the V1 destructive abort that cleared the Redis queue.

func (*Client) ListModels

func (c *Client) ListModels(ctx context.Context) ([]byte, error)

ListModels calls GET /provider on opencode and returns the raw JSON body. The caller is responsible for parsing the response shape (it varies by opencode version). The body is size-limited to providerCatalogReadLimit.

func (*Client) PatchConfig

func (c *Client) PatchConfig(ctx context.Context, config map[string]any) error

PatchConfig calls PATCH /global/config on opencode with the given config map. Used by SetModel to change the active model.

func (*Client) PromptV2 added in v0.12.2

func (c *Client) PromptV2(ctx context.Context, sessionID, text string, delivery V2Delivery) (*V2PromptResponse, error)

PromptV2 sends a prompt to an opencode V2 session endpoint with the given delivery mode. It POSTs to /api/session/:sid/prompt using the same Basic auth (opencode + password) as every other opencode call.

The response is admit-and-schedule (non-streaming): opencode queues the prompt internally and returns immediately. The body is read+discarded on non-2xx; on 2xx the data payload is decoded and returned.

F17: the caller MUST NOT supply a message id — this method omits it unconditionally. F18: the prompt body is {text:"..."} (plain string), not the parts-based contract shape; see the v2PromptRequest doc comment.

func (*Client) PushCredentials

func (c *Client) PushCredentials(ctx context.Context, providers []secrets.LLMProviderData) error

PushCredentials writes each provider's API key to opencode's auth store via PUT /auth/:providerID. This writes to auth.json but does NOT trigger provider state refresh — call DisposeInstance or (future) RefreshProviders afterward to pick up the new credentials.

Returns nil if providers is empty (no-op). Returns the first error encountered; subsequent providers are not attempted.

func (*Client) StageCredentials

func (c *Client) StageCredentials(ctx context.Context, providers []secrets.LLMProviderData) error

StageCredentials writes provider credentials to opencode's auth.json (via PUT /auth/:providerID) but does NOT trigger provider-state refresh. The credentials are "staged" — they exist on disk but opencode's in-memory provider state is unchanged until DisposeInstance is called separately by the caller (typically via POST /api/v1/workspaces/:id/agent/reload).

Returns nil if providers is empty (no-op).

type ConfigWriter added in v0.12.0

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

ConfigWriter is the single writer of agent-config.json within the agentd process. All config changes (provider credentials, model selection, relay injection, MCP servers) go through SetProviders / SetModel / SetRelay / SetMCPServers followed by Rebuild.

Thread-safe: all mutating methods acquire mu. Rebuild serializes the read-merge-write cycle so concurrent reloads and relay injection cannot interleave.

func NewConfigWriter added in v0.12.0

func NewConfigWriter(path string, opts ...ConfigWriterOption) *ConfigWriter

NewConfigWriter creates the writer and initializes its sources from the existing agent-config.json file (written by the materialize subcommand at boot), the admin-prompt file, and the allowed-dirs file. Options set the paths; absent options mean the corresponding source is skipped. If agent-config.json is absent or corrupt, sources start empty and the first Rebuild creates a fresh file.

func (*ConfigWriter) Apply added in v0.14.0

func (w *ConfigWriter) Apply(in agent.AgentConfigInput) (bool, error)

Apply implements agent.AgentConfigWriter. It is the seam platform code uses after construction; it never calls the SetX methods directly.

Each non-nil field on in updates one source on the writer. A nil field leaves the writer's existing state for that source unchanged. A non-nil pointer to a zero-value struct clears the source (where meaningful).

After merging the input, Apply calls rebuildLocked to render and write the full config atomically. Returns (true, nil) on success — opencode does not hot-reload its config file, so every successful Apply requires the process to be restarted for the change to take effect. A future agent that hot-reloads returns false from its Apply; platform code branches on the bool and skips the restart.

Thread-safety: Apply holds w.mu across the entire merge + write cycle so concurrent Apply / Rebuild / SetX calls serialize. Two concurrent Apply calls cannot interleave such that one caller's update is lost (Rule 11 F1: atomicity is part of the Apply contract, not just the write step).

The opencode-specific rendering (deep-merge semantics, $schema URL, disabled_providers, the opencode-relay provider block, the agent.build prompt merge, the mode.permissions.external_directory merge, the mcp section) is owned by this method and rebuildLocked — none of it leaks through the agent.AgentConfigInput type. Platform code calls Apply and reacts to restartRequired; it does not know WHY a restart is needed.

func (*ConfigWriter) HasRelay added in v0.12.0

func (w *ConfigWriter) HasRelay() bool

HasRelay returns true if the relay injector has successfully injected relay config. Used by the readyz handler for the RelayInjected signal.

func (*ConfigWriter) Rebuild added in v0.12.0

func (w *ConfigWriter) Rebuild() error

Rebuild merges all sources (providers, model, relay, MCP, admin prompt, allowed dirs) and writes the complete agent-config.json atomically via temp-file + os.Rename.

Merge semantics:

  • $schema is always set to "https://opencode.ai/config.json"
  • provider map = existing providers (from SetProviders or loadExisting)
  • opencode-relay (if relay is set). No existing provider is removed.
  • model = the model source (from SetModel or loadExisting)
  • disabled_providers = ["opencode"] (only if relay is set)
  • agent.build.prompt = admin prompt (deep-merged into existing build agent)
  • mode.permissions.external_directory = allowed-dirs glob allow-rules
  • mcp = staged MCP servers + pre-marshal hook additions

The temp-file + rename pattern ensures readers never see a partially written file. os.Rename is atomic on POSIX filesystems (same mount).

Thread-safety: Rebuild acquires w.mu for the whole read-merge-write cycle so concurrent Rebuild/SetX calls cannot interleave.

func (*ConfigWriter) SetMCPServers added in v0.12.0

func (w *ConfigWriter) SetMCPServers(servers []MCPServerEntry)

SetMCPServers replaces the MCP server source. Called after materialize stages MCP server entries from secrets.json. Each server renders as one entry in the opencode "mcp" top-level config section.

func (*ConfigWriter) SetModel added in v0.12.0

func (w *ConfigWriter) SetModel(model string)

SetModel updates the model source. Called by applyWorkspaceConfig at boot (via the materialize subcommand) to set the default model from workspace-config.json.

func (*ConfigWriter) SetProviders added in v0.12.0

func (w *ConfigWriter) SetProviders(formattedConfig []byte) error

SetProviders updates the provider source from a FormatOpenCodeConfig result. The formatted bytes contain the complete opencode config shape ({ $schema, provider: {...} }); this method extracts just the provider map. The model from the formatter is NOT captured — the model source is owned by SetModel (set at boot via loadExisting) and must survive credential reloads.

func (*ConfigWriter) SetRelay added in v0.12.0

func (w *ConfigWriter) SetRelay(url string, models []RelayModel)

SetRelay updates the relay source after the relay injector successfully discovers the free model list. The writer stores the URL and models; Rebuild merges them into the provider map.

type ConfigWriterOption added in v0.12.0

type ConfigWriterOption func(*ConfigWriter)

ConfigWriterOption configures a ConfigWriter at construction.

func WithAdminPromptPath added in v0.12.0

func WithAdminPromptPath(p string) ConfigWriterOption

WithAdminPromptPath sets the path to the admin-configured system prompt file (written by the agentd bootstrap subcommand). The writer reads it once at construction. Empty (the default) means no admin-prompt source.

func WithAllowedDirsPath added in v0.12.0

func WithAllowedDirsPath(p string) ConfigWriterOption

WithAllowedDirsPath sets the path to the instance's allowedExternalDirectories JSON array (written by the bootstrap subcommand). The writer reads it once at construction. Empty (the default) means no external-directory allow-rules are injected.

func WithPreMarshalHook added in v0.12.0

func WithPreMarshalHook(fn func(map[string]json.RawMessage)) ConfigWriterOption

WithPreMarshalHook registers a function invoked on the rendered config map immediately before final marshal. agentd uses this to inject its built-in admin MCP server (the "llmsafespaces" entry pointing at agentd's own admin port) without this package needing to know that port. nil (the default) means no hook.

type Dialect

type Dialect struct{}

Dialect implements agent.Dialect for the opencode agent runtime.

func (*Dialect) EventStreamPath

func (d *Dialect) EventStreamPath() string

func (*Dialect) IsPermissionAsked

func (d *Dialect) IsPermissionAsked(eventType string) bool

func (*Dialect) IsPermissionResolved

func (d *Dialect) IsPermissionResolved(eventType string) bool

func (*Dialect) IsQuestionAsked

func (d *Dialect) IsQuestionAsked(eventType string) bool

func (*Dialect) IsQuestionResolved

func (d *Dialect) IsQuestionResolved(eventType string) bool

func (*Dialect) IsSessionBusy

func (d *Dialect) IsSessionBusy(eventType string, properties json.RawMessage) bool

func (*Dialect) IsSessionIdle

func (d *Dialect) IsSessionIdle(eventType string, properties json.RawMessage) bool

func (*Dialect) ParsePermissionRequest

func (d *Dialect) ParsePermissionRequest(eventType string, properties json.RawMessage) (*agent.PermissionRequest, error)

func (*Dialect) ParseQuestionRequest

func (d *Dialect) ParseQuestionRequest(eventType string, properties json.RawMessage) (*agent.QuestionRequest, error)

func (*Dialect) ParseSessionStatus

func (d *Dialect) ParseSessionStatus(properties json.RawMessage) (string, string, error)

func (*Dialect) PermissionListPath

func (d *Dialect) PermissionListPath() string

func (*Dialect) PermissionReplyPath

func (d *Dialect) PermissionReplyPath(requestID string) string

func (*Dialect) QuestionListPath

func (d *Dialect) QuestionListPath() string

func (*Dialect) QuestionRejectPath

func (d *Dialect) QuestionRejectPath(requestID string) string

func (*Dialect) QuestionReplyPath

func (d *Dialect) QuestionReplyPath(requestID string) string

func (*Dialect) SessionAbortPath

func (d *Dialect) SessionAbortPath(sessionID string) string

func (*Dialect) SessionCreatePath

func (d *Dialect) SessionCreatePath() string

func (*Dialect) SessionGetPath

func (d *Dialect) SessionGetPath(sessionID string) string

func (*Dialect) SessionListPath

func (d *Dialect) SessionListPath() string

func (*Dialect) SessionMessagePath

func (d *Dialect) SessionMessagePath(sessionID string) string

func (*Dialect) SessionPromptAsyncPath

func (d *Dialect) SessionPromptAsyncPath(sessionID string) string

type MCPServerEntry added in v0.12.0

type MCPServerEntry struct {
	Name      string
	Transport string // http, sse, or stdio
	URL       string
	Command   string
	Args      []string
	TimeoutMs int
	Env       map[string]string
	Headers   map[string]string
}

MCPServerEntry is one staged MCP server, carrying the fields needed to render its opencode config entry (local or remote shape per the contract).

type OpenCodeAgent

type OpenCodeAgent struct{}

func (*OpenCodeAgent) FormatProviderConfig

func (a *OpenCodeAgent) FormatProviderConfig(providers []agent.LLMProviderData) ([]byte, error)

func (*OpenCodeAgent) Type

func (a *OpenCodeAgent) Type() agent.AgentType

func (*OpenCodeAgent) ValidateCredentials

func (a *OpenCodeAgent) ValidateCredentials(rawConfig []byte) (*agent.CredentialCheckResult, error)

type Option

type Option func(*Client)

Option configures a Client at construction.

func WithHTTPClient

func WithHTTPClient(hc *http.Client) Option

WithHTTPClient injects a pre-configured *http.Client (e.g. one shared across many workspaces for connection pooling — M11-a). When unset, NewClient allocates a default client with a 10s timeout.

type PasswordResolver

type PasswordResolver func(ctx context.Context, workspaceID string) (string, error)

PasswordResolver resolves the opencode Basic-auth password for a workspace. The API-side implementation reads from the K8s Secret cache (pwCache); agentd-side reads from /sandbox-cfg/password.

type PodIPResolver

type PodIPResolver interface {
	GetWorkspacePodIP(ctx context.Context, userID, workspaceID string) (string, error)
}

PodIPResolver resolves the pod IP for a workspace.

type RelayModel added in v0.12.0

type RelayModel struct {
	ID           string
	Name         string
	ContextLimit int
	OutputLimit  int
}

RelayModel is one free-tier model discovered from opencode's /provider endpoint by the relay injector. The writer renders it into the opencode-relay provider block's "models" map.

type V2Delivery added in v0.12.2

type V2Delivery = agent.V2Delivery

V2Delivery is re-exported from pkg/agent (the canonical location). Callers should use agent.V2Delivery; this alias exists for backward compatibility.

type V2PromptResponse added in v0.12.2

type V2PromptResponse = agent.V2PromptResponse

V2PromptResponse is re-exported from pkg/agent.

type WorkspaceClient

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

WorkspaceClient implements AgentClient by resolving each call to a specific pod IP + password, then delegating to the low-level Client. It is constructed once and shared across handlers; each call resolves the workspace's current podIP + password fresh, so pod migrations and password rotations are transparent to callers.

The shared httpClient enables connection pooling across all workspace calls (M11-a). The agentPort field replaces the former package-level var so tests are parallel-safe (M1-a).

func NewWorkspaceClient

func NewWorkspaceClient(pw PasswordResolver, ip PodIPResolver, logger *zap.Logger, opts ...WorkspaceClientOption) *WorkspaceClient

NewWorkspaceClient creates an AgentClient that resolves workspace → podIP + password on each call. The httpClient is shared across all calls for connection pooling; agentPort defaults to agentd.AgentPort.

func (*WorkspaceClient) DisposeInstance

func (w *WorkspaceClient) DisposeInstance(ctx context.Context, userID, workspaceID string) error

func (*WorkspaceClient) GetSessionStatuses

func (w *WorkspaceClient) GetSessionStatuses(ctx context.Context, userID, workspaceID string) (map[string]string, error)

func (*WorkspaceClient) ListModels

func (w *WorkspaceClient) ListModels(ctx context.Context, userID, workspaceID string) ([]byte, error)

func (*WorkspaceClient) PatchConfig

func (w *WorkspaceClient) PatchConfig(ctx context.Context, userID, workspaceID string, config map[string]any) error

func (*WorkspaceClient) StageCredentials

func (w *WorkspaceClient) StageCredentials(ctx context.Context, userID, workspaceID string, providers []secrets.LLMProviderData) error

type WorkspaceClientOption

type WorkspaceClientOption func(*WorkspaceClient)

WorkspaceClientOption configures a WorkspaceClient at construction.

func WithWorkspaceHTTPClient

func WithWorkspaceHTTPClient(hc *http.Client) WorkspaceClientOption

WithWorkspaceHTTPClient injects a shared *http.Client so connections are pooled across all workspace calls (M11-a). When unset, a tuned default is used (see newTunedHTTPClient). The client must not set a per-request Timeout that would interfere with caller context deadlines.

Directories

Path Synopsis
Package filediff produces unified-diff text for files changed by an agent turn, using `git diff` against the workspace PVC's HEAD commit.
Package filediff produces unified-diff text for files changed by an agent turn, using `git diff` against the workspace PVC's HEAD commit.

Jump to

Keyboard shortcuts

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