Documentation
¶
Index ¶
- Variables
- func IsSessionNotFound(err error) bool
- func Register(agentType AgentType, a AgentRuntime)
- func Unregister(agentType AgentType)
- type Adapter
- type AdminPromptChange
- type AgentConfigInput
- type AgentConfigWriter
- type AgentProvidersChange
- type AgentRuntime
- type AgentType
- type AllowedDirsChange
- type CredentialCheckResult
- type CredentialState
- type Dialect
- type InputResolution
- type LLMModelConfig
- type LLMProviderData
- type MCPServerChange
- type MCPServerEntry
- type ModelSelection
- type PermissionRequest
- type QuestionInfo
- type QuestionOption
- type QuestionRequest
- type RelayModel
- type RelayState
- type ToolRef
- type V2ClientFactory
- type V2Delivery
- type V2PromptResponse
- type V2SessionClient
Constants ¶
This section is empty.
Variables ¶
var ( ErrV2PromptConflict = stderrors.New("agent V2: prompt conflict (id collision)") ErrV2SessionNotFound = stderrors.New("agent V2: session not found") )
V2 error sentinels. Re-exported from pkg/agent/opencode; canonical location is here so callers don't import the opencode package.
var ErrNoRunningPod = &pkgerrors.StatusError{ Status: http.StatusNotFound, Code: "no_running_pod", Message: "workspace pod not running", }
ErrNoRunningPod is the canonical sentinel for "workspace pod is not running (empty podIP)". The opencode adapter wraps this via fmt.Errorf("workspace %s: %w", workspaceID, ErrNoRunningPod) so callers use errors.Is(err, agent.ErrNoRunningPod) without importing the opencode package. Previously defined in pkg/agent/opencode/agent_client.go — moved here (US-65.6-followup) to break the import cycle that forced handlers to import the opencode package for the sentinel.
Functions ¶
func IsSessionNotFound ¶ added in v0.14.2
IsSessionNotFound returns true if err is or wraps ErrV2SessionNotFound. Convenience for handlers that need to map to HTTP 404.
func Register ¶
func Register(agentType AgentType, a AgentRuntime)
func Unregister ¶
func Unregister(agentType AgentType)
Types ¶
type Adapter ¶ added in v0.14.0
type Adapter interface {
// CreateSession creates a new session in the agent and returns the
// platform view. The adapter generates or translates the ID.
CreateSession(ctx context.Context, userID, workspaceID, title string) (*session.Session, error)
// GetSession returns the current state of one session.
GetSession(ctx context.Context, userID, workspaceID, sessionID string) (*session.Session, error)
// ListSessions returns the platform view of all sessions on the
// workspace, ordered by recency.
ListSessions(ctx context.Context, userID, workspaceID string) ([]session.Session, error)
// RenameSession updates a session's title.
RenameSession(ctx context.Context, userID, workspaceID, sessionID, title string) error
// DeleteSession removes a session from the agent. Subsequent Get
// calls return a not-found error.
DeleteSession(ctx context.Context, userID, workspaceID, sessionID string) error
// Send delivers a user message synchronously and returns the
// assistant's completed response. Streaming callers use Stream
// instead; Send is for request-response callers (MCP, SDK).
Send(ctx context.Context, userID, workspaceID, sessionID, text string, opts session.SendOpts) (*session.Message, error)
// SendAsync delivers a user message without waiting for the
// assistant response. The returned message ID lets the caller
// correlate via Stream or GetHistory. Use this for long-running
// tasks where the caller will poll.
SendAsync(ctx context.Context, userID, workspaceID, sessionID, text string, opts session.SendOpts) (messageID string, err error)
// Abort stops any in-flight work on the session. The abort is
// non-destructive: queued user input survives and runs on the
// next wake (design 0049 §3 — loss of revoke is accepted).
Abort(ctx context.Context, userID, workspaceID, sessionID string) error
// GetHistory returns the session transcript in platform shape.
// The adapter drops agent-specific parts (e.g. opencode's patch
// part) and produces FileChange parts from git diff where the
// agent reported file changes.
GetHistory(ctx context.Context, userID, workspaceID, sessionID string) ([]session.Message, error)
// Stream subscribes to the session's event stream, translating
// agent-specific events to session.Event values. The channel
// closes when the context is canceled or the agent ends the
// stream. Unknown/malformed events are dropped silently.
// Connection-level errors (scanner failure) are emitted as
// session.EventError events before the channel closes.
Stream(ctx context.Context, userID, workspaceID, sessionID string) (<-chan session.Event, error)
// ListPending returns the currently-blocking InputRequests on a
// session (questions or permissions). The adapter unifies the
// agent's question/permission shapes into session.InputRequest.
//
// Contract: a non-nil error means the pending set is UNKNOWN
// (agent unreachable, endpoint error) — never treat it as an
// authoritative empty. A 404-not-implemented endpoint yields an
// authoritative empty with a nil error. Callers that broadcast
// snapshots (the SSE input snapshot) must mark failed fetches as
// non-authoritative so they cannot wipe live pending prompts.
ListPending(ctx context.Context, userID, workspaceID, sessionID string) ([]session.InputRequest, error)
// Resolve settles a pending InputRequest with the user's reply.
// For questions, reply carries the selected option(s) or custom
// text. For permissions, reply carries "allow" / "deny" (the
// adapter translates to the agent's accept/reject endpoints).
Resolve(ctx context.Context, userID, workspaceID, requestID, reply string) error
// ListAvailableModels returns the catalog of models the agent can
// select, including context/output limits for "context: X% used"
// display. The adapter converts agent-side cost/relay/provider
// data into the platform ModelInfo shape.
ListAvailableModels(ctx context.Context, userID, workspaceID string) ([]session.ModelInfo, error)
// SetModel changes the session's active model. Subsequent Send
// calls use the new model.
SetModel(ctx context.Context, userID, workspaceID, sessionID string, model session.ModelRef) error
// Capabilities reports the optional agent behaviors the client
// may render affordances for (steer, queue, rewind, fork, stash,
// diff, reasoning). The set is per-adapter, not per-session.
Capabilities() []session.Capability
// FormatProviderConfig renders the supplied providers in the
// agent's native config format. Returns nil if the agent has no
// provider config concept for these credentials.
FormatProviderConfig(providers []LLMProviderData) ([]byte, error)
// ValidateCredentials checks whether the supplied raw config
// (already agent-formatted) is structurally valid. Returns nil
// on success, an error describing the validation failure
// otherwise. Used at bind time to reject malformed credentials
// before they reach the workspace.
ValidateCredentials(rawConfig []byte) (*CredentialCheckResult, error)
}
Adapter is the single seam between platform code (proxy handlers, MCP server, services) and one agent runtime. It folds the existing AgentRuntime + Dialect + AgentClient interface shapes into one surface and adds the session/messaging methods the proxy migrates to under US-65.4.
Per design 0049 §4.6, the full Adapter has ~18 methods. This file defines the interface shape; the opencode implementation lives in pkg/agent/opencode/adapter.go. Platform code holds an Adapter (interface) and never imports an implementation.
AgentConfigWriter is NOT embedded here. The two seams run in different processes: AgentConfigWriter is held by agentd (the in-pod supervisor that writes agent-config.json); Adapter is held by the API server (proxy handlers that translate HTTP calls). The API pod has no filesystem access to the workspace PVC and cannot write agent config. Composing the two into one interface would force every Adapter implementation to provide panic-stubs for Apply/HasRelay — code that lies about its capabilities. design 0049 §4.6's "folds AgentConfigWriter" described the long-term intent (one unified seam per agent); the as-built architecture has two seams because the two processes have different capabilities.
Rule 12 (containment before abstraction): pass-through operations (Rewind, Fork) are NOT included until a second adapter validates their shape or a forcing UX need lands one.
type AdminPromptChange ¶ added in v0.15.7
type AdminPromptChange struct {
Text string
}
AdminPromptChange is the admin-prompt-source update payload. See AgentConfigInput.AdminPrompt for semantics.
type AgentConfigInput ¶ added in v0.14.0
type AgentConfigInput struct {
// Providers updates the LLM provider map. Formatted is the
// agent-rendered provider JSON — the agent's formatter is the
// only thing that knows the shape (e.g. opencode's
// {"provider": {...}} struct). The writer passes the bytes
// through verbatim.
//
// A non-nil pointer with nil/empty Formatted bytes clears the
// provider source.
Providers *AgentProvidersChange
// Model updates the default model selection. Empty string
// (ModelSelection("")) clears the model source.
Model *ModelSelection
// Relay updates the relay state. A non-nil pointer with empty URL
// clears the relay source (distinct from nil = leave unchanged).
Relay *RelayState
// MCPServers updates the MCP server list. A non-nil pointer with
// an empty Servers slice clears the MCP source.
MCPServers *MCPServerChange
// AdminPrompt updates the platform-level system prompt rendered into
// the agent's build prompt (replace semantics: the new Text fully
// supersedes the prior source, side-car-loaded or rendered). A
// non-nil pointer with empty Text clears the prompt source
// (distinct from nil = leave unchanged).
//
// At bootstrap the writer loads this source from the side-car file
// (WithAdminPromptPath — the materialize staging contract); this
// field is the runtime update path so a caller can revise the
// prompt without recreating the writer. It does NOT watch files.
AdminPrompt *AdminPromptChange
// AllowedDirs updates the glob patterns auto-approved as the
// agent's external-directory allow rules. A non-nil pointer with an
// empty Dirs slice clears the source. Same bootstrap/runtime split
// as AdminPrompt: construction may load from the side-car file
// (WithAllowedDirsPath); this field updates thereafter.
AllowedDirs *AllowedDirsChange
}
AgentConfigInput is the partial-update payload for Apply. Each pointer field is one source; nil means "leave the writer's existing state for this source unchanged". A non-nil pointer to a zero-value struct means "this source is now empty/disabled" — e.g. `Relay: &RelayState{}` clears the relay source.
Fields are pointers (not values + a "set" bool) because:
- Pointer-omission composes cleanly with JSON encoding semantics callers already understand.
- The zero value of the input struct is a valid no-op Apply.
type AgentConfigWriter ¶ added in v0.14.0
type AgentConfigWriter interface {
Apply(in AgentConfigInput) (restartRequired bool, err error)
HasRelay() bool
}
AgentConfigWriter is the seam between platform code and the agent-specific config writer. The interface is the ONLY surface platform code holds after construction; it does not import or reference the concrete type.
Methods:
Apply merges the supplied input onto the writer's existing state and writes the result atomically. Returns restartRequired=true when the running agent process must be restarted to pick up the change (the opencode implementation always returns true — opencode does not hot-reload its config file). A future agent that hot-reloads returns false and the platform's restart machinery no-ops.
HasRelay reports whether the writer's current state includes a relay block. Used by the readyz handler and the relay injector short-circuit. Read-only — does not write.
Thread-safety: implementations must be safe for concurrent use. The opencode implementation guards Apply with a mutex.
type AgentProvidersChange ¶ added in v0.14.0
type AgentProvidersChange struct {
// Formatted is the agent-rendered provider JSON. For opencode,
// this is the output of FormatOpenCodeConfig — a struct
// {"provider": {...}} containing the agent's exact provider map.
Formatted []byte
}
AgentProvidersChange is the provider-source update payload. See AgentConfigInput.Providers for semantics.
type AgentRuntime ¶
type AgentRuntime interface {
Type() AgentType
ValidateCredentials(rawConfig []byte) (*CredentialCheckResult, error)
FormatProviderConfig(providers []LLMProviderData) ([]byte, error)
}
func Get ¶
func Get(agentType AgentType) (AgentRuntime, error)
type AllowedDirsChange ¶ added in v0.15.7
type AllowedDirsChange struct {
Dirs []string
}
AllowedDirsChange is the allowed-dirs-source update payload. See AgentConfigInput.AllowedDirs for semantics.
type CredentialCheckResult ¶
type CredentialCheckResult struct {
State CredentialState `json:"state"`
Agent AgentType `json:"agent"`
Message string `json:"message,omitempty"`
}
type CredentialState ¶
type CredentialState string
const ( CredentialStatePresent CredentialState = "Present" CredentialStateMissing CredentialState = "Missing" CredentialStateInvalid CredentialState = "Invalid" )
type Dialect ¶
type Dialect interface {
// --- Session route paths (pod-internal, relative) ---
SessionCreatePath() string
SessionListPath() string
SessionMessagePath(sessionID string) string
SessionPromptAsyncPath(sessionID string) string
SessionAbortPath(sessionID string) string
SessionGetPath(sessionID string) string
EventStreamPath() string
// --- Input request route paths ---
QuestionListPath() string
QuestionReplyPath(requestID string) string
QuestionRejectPath(requestID string) string
PermissionListPath() string
PermissionReplyPath(requestID string) string
// --- SSE event classification ---
IsQuestionAsked(eventType string) bool
IsQuestionResolved(eventType string) bool
IsPermissionAsked(eventType string) bool
IsPermissionResolved(eventType string) bool
IsSessionIdle(eventType string, properties json.RawMessage) bool
IsSessionBusy(eventType string, properties json.RawMessage) bool
// --- Event parsing (returns nil+error if event doesn't match) ---
ParseQuestionRequest(eventType string, properties json.RawMessage) (*QuestionRequest, error)
ParsePermissionRequest(eventType string, properties json.RawMessage) (*PermissionRequest, error)
ParseSessionStatus(properties json.RawMessage) (sessionID string, status string, err error)
}
Dialect encodes the HTTP API contract of the agent running inside a workspace pod. Implement this interface for each supported agent runtime.
type InputResolution ¶
type InputResolution struct {
RequestID string `json:"request_id"`
SessionID string `json:"session_id"`
Reply string `json:"reply,omitempty"`
}
InputResolution contains the resolution data for a question or permission.
type LLMModelConfig ¶
type LLMModelConfig struct {
ID string `json:"id"`
Label string `json:"label,omitempty"`
ContextLimit int `json:"contextLimit,omitempty"`
OutputLimit int `json:"outputLimit,omitempty"`
}
LLMModelConfig specifies a model identifier, optional display label, and optional context/output token limits.
ContextLimit and OutputLimit MUST be set together (both > 0) to be emitted into opencode's agent-config.json — opencode's published JSON Schema (https://opencode.ai/config.json) requires both `context` and `output` when the `limit` object is present. See pkg/secrets/types.go LLMModelConfig for the authoritative documentation.
type LLMProviderData ¶
type LLMProviderData struct {
Kind string `json:"kind"`
Slug string `json:"slug"`
APIKey string `json:"apiKey"`
BaseURL string `json:"baseURL,omitempty"`
Models []LLMModelConfig `json:"models,omitempty"`
Default string `json:"default,omitempty"`
SmallModel string `json:"smallModel,omitempty"`
}
LLMProviderData is re-exported from pkg/secrets for use in the interface. This avoids a circular import between pkg/agent and pkg/secrets.
Epic 55: see pkg/secrets/types.go for the authoritative documentation. Briefly — Kind is the SDK-class enum; Slug is the per-owner unique identity that becomes the literal key in agent-config.json's provider map (opencode persists it as `providerID` on session records).
type MCPServerChange ¶ added in v0.14.0
type MCPServerChange struct {
Servers []MCPServerEntry
}
MCPServerChange is the MCP-source update payload. See AgentConfigInput.MCPServers for semantics.
type MCPServerEntry ¶ added in v0.14.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 MCP server to render into the agent's config. Agent-neutral: the opencode adapter converts to opencode's remote/local shape via pkg/agentd/secrets.RenderOpencodeMCPServerEntry.
type ModelSelection ¶ added in v0.14.0
type ModelSelection string
ModelSelection is the fully-qualified "providerID/modelID" string the agent expects in its config. Platform code resolves the providerID before calling Apply; the writer does not look it up.
Empty string = clear the model source.
type PermissionRequest ¶
type PermissionRequest struct {
ID string `json:"id"`
SessionID string `json:"session_id"`
RootSessionID string `json:"root_session_id,omitempty"`
Permission string `json:"permission"`
Patterns []string `json:"patterns"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
Always []string `json:"always,omitempty"`
Tool *ToolRef `json:"tool,omitempty"`
}
PermissionRequest is the normalized, agent-agnostic representation of a pending permission.
RootSessionID — see QuestionRequest for semantics.
type QuestionInfo ¶
type QuestionInfo struct {
Question string `json:"question"`
Header string `json:"header"`
Options []QuestionOption `json:"options"`
Multiple bool `json:"multiple"`
Custom bool `json:"custom"`
}
QuestionInfo is a single question with its options.
type QuestionOption ¶
QuestionOption is a single selectable choice within a question.
type QuestionRequest ¶
type QuestionRequest struct {
ID string `json:"id"`
SessionID string `json:"session_id"`
RootSessionID string `json:"root_session_id,omitempty"`
Questions []QuestionInfo `json:"questions"`
Tool *ToolRef `json:"tool,omitempty"`
}
QuestionRequest is the normalized, agent-agnostic representation of a pending question.
RootSessionID is the top-level session in the parent chain. For top-level sessions it equals SessionID. For subtask/subagent sessions (e.g. opencode's `task` tool spawning child sessions) it is the ancestor session that the user is actually viewing in the chat UI. The frontend uses this to bubble subtask prompts up to the user — without it, prompts would be silently dropped because the subtask's SessionID does not match the URL session.
type RelayModel ¶ added in v0.14.0
RelayModel is one free-tier model discovered by the relay injector. Mirrors opencode.RelayModel (and the controller's freemodels.Model wire format) — the type is agent-neutral at this layer; the opencode adapter converts.
type RelayState ¶ added in v0.14.0
type RelayState struct {
URL string
Models []RelayModel
}
RelayState describes what the relay injector discovered. A pointer-to-zero-value means "relay disabled" (empty URL); nil means "leave the existing relay source unchanged". The two are distinct and load-bearing — see AgentConfigInput.Relay.
type V2ClientFactory ¶ added in v0.14.2
type V2ClientFactory func(ctx context.Context, workspaceID string) (V2SessionClient, error)
V2ClientFactory builds a V2SessionClient for the given workspace.
type V2Delivery ¶ added in v0.14.2
type V2Delivery string
V2Delivery selects how the agent's V2 session runner admits a prompt. Generic equivalent of opencode.V2Delivery; allows proxy_v2.go to use V2 types without importing the opencode package.
const ( V2DeliveryQueue V2Delivery = "queue" V2DeliverySteer V2Delivery = "steer" )
type V2PromptResponse ¶ added in v0.14.2
type V2PromptResponse struct {
AdmittedSeq int `json:"admittedSeq"`
ID string `json:"id"`
SessionID string `json:"sessionID"`
}
V2PromptResponse is the response from a V2 prompt admission.
type V2SessionClient ¶ added in v0.14.2
type V2SessionClient interface {
PromptV2(ctx context.Context, sessionID, text string, delivery V2Delivery) (*V2PromptResponse, error)
InterruptV2(ctx context.Context, sessionID string) error
}
V2SessionClient is the subset of agent client methods the proxy's V2 session-queue paths use. Defined in pkg/agent so proxy_v2.go doesn't need to import pkg/agent/opencode.
Directories
¶
| Path | Synopsis |
|---|---|
|
filediff
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. |