agent

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: May 24, 2026 License: MIT Imports: 4 Imported by: 0

README

agent/ — multi-provider agent-runner contract

This package defines the provider-agnostic types every agent provider implementation and the runner orchestrator depend on. It is the foundation block of the v0.5.0 multi-provider agent-runner subsystem.

What lives here

File Purpose
doc.go Package overview + the 9-capability matrix
types.go Enums, struct types: ProviderName, Capability, Capabilities, SandboxLevel, EffortLevel, MCPServerConfig, PermissionConfig, CodeIntelEnforcement, Spec, CostData, Result, BackstopReport, QualityReport, plus the IsSupported capability gate
provider.go Provider interface (5 methods: Name, Capabilities, Spawn, Resume, Shutdown)
handle.go Handle interface (4 methods: SessionID, Events, Inject, Stop)
event.go Event sealed-interface + 8 variant structs + MarshalEvent / UnmarshalEvent polymorphic JSON helpers
errors.go Sentinel errors: ErrUnsupported, ErrNoProvider, ErrSessionNotFound, ErrSpawnFailed, ErrProviderUnavailable

What does NOT live here

  • Provider implementations (provider/claude, provider/codex, provider/stub) — they import this package.
  • The runner orchestration loop — runner/ imports this package.
  • HTTP clients, process spawning, filesystem I/O, MCP-stdio bridging, worktree management, prompt rendering, result posting.

This package is pure types + interfaces. No business logic, no I/O, no dependencies beyond the Go standard library and log/slog.

Relationship to the legacy TypeScript surface

This package is the verbatim Go translation of the legacy TS contract at:

../agentfactory/packages/core/src/providers/types.ts

JSON tags on every struct use camelCase to match the TS wire format verbatim. Readers of QueuedWork.resolvedProfile JSON across the fleet (daemon, platform-side workflow nodes, rensei-tui) depend on this.

Public package boundary

This package is exported at the top level of the module (github.com/RenseiAI/donmai/agent). Downstream consumers including rensei-tui import it directly without depending on the rest of agentfactory-tui. F.1.1 §1 ratifies this boundary. Do not move or rename without an ADR.

The 9 capabilities

A provider declares a Capabilities struct describing which optional behaviors it supports. The runner gates on these flags via IsSupported(caps, capability) rather than try-catching unsupported operations. The 9 named capabilities (each maps 1:1 to a flag on Capabilities):

Capability constant Capabilities field Meaning
CapMessageInjection SupportsMessageInjection Handle.Inject can deliver mid-session user messages
CapSessionResume SupportsSessionResume Provider.Resume can continue a prior session
CapToolPlugins SupportsToolPlugins Provider accepts MCP stdio tool plugins (af_linear, af_code)
CapBaseInstructions NeedsBaseInstructions Provider consumes Spec.BaseInstructions
CapPermissionConfig NeedsPermissionConfig Provider consumes Spec.PermissionConfig
CapCodeIntelEnforcement SupportsCodeIntelligenceEnforcement Provider supports the Grep/Glob → af_code redirect
CapSubagentEvents EmitsSubagentEvents Provider emits Anthropic-style subagent (Task) events
CapReasoningEffort SupportsReasoningEffort Provider honors Spec.Effort (low/medium/high/xhigh)
CapToolPermissionFormatClaude ToolPermissionFormat == "claude" Provider uses Claude's Bash(prefix:glob) tool-permission grammar
v0.5.0 provider matrix (per F.1.1 §3 and locked coordinator decisions)
Provider Inject Resume ToolPlugins BaseInstr PermConfig CodeIntel Subagent Effort PermFmt
claude false true true false false false true true claude
codex false true true true true false false true codex
stub configurable per-test configurable per-test

The bolded claude flags reflect the v0.5.0 CLI shell-out approach: the Claude CLI does not expose mid-session injection in JSON-stream mode, and the runtime canUseTool callback is not yet exposed by the CLI either. Both flip to true in F.5 if/when a wrapper sidecar lands.

Sealed Event variants

The Event interface is sealed: it requires both Kind() EventKind and an unexported isAgentEvent() marker. External packages cannot satisfy the interface, which keeps the discriminated union closed to the 8 variants defined in event.go:

InitEvent → SystemEvent* → (AssistantTextEvent | ToolUseEvent | ToolResultEvent | ToolProgressEvent)* → (ResultEvent | ErrorEvent)

To decode an Event polymorphically from JSON (e.g. the events.jsonl file the runner persists per session), use:

ev, err := agent.UnmarshalEvent(jsonBytes)

UnmarshalEvent reads a "kind" discriminator field and dispatches to the matching variant struct. Use MarshalEvent to encode in the same shape; the wire format is {"kind": "<EventKind>", ...variant fields...}.

Wire-format compatibility rule

If you change a wire shape (add/remove/rename a JSON field, change a JSON tag, add an enum value), you must update the F.1.1 design doc in the same change:

../runs/2026-05-01-wave-6-fleet-iteration/F1.1-runner-contract.md

The doc is the contract source-of-truth — keeping it single-sourced prevents drift between implementations.

Testing

go test -race ./agent/...

Tests cover:

  • JSON round-trip for Spec, Capabilities, Result (verifies camelCase tags + omitempty behavior).
  • Round-trip for every Event variant + MarshalEvent / UnmarshalEvent polymorphic dispatch + error paths.
  • IsSupported capability gate (table-driven over all 9 capabilities).
  • Sentinel errors are distinct (no accidental aliasing).
  • Provider and Handle interfaces are implementable from outside the package (compile-time check via a no-op type).

Documentation

Overview

Package agent declares the provider-agnostic contract for the agentfactory-tui multi-provider agent-runner subsystem.

This package is the verbatim Go translation of the legacy TypeScript type contract at:

../agentfactory/packages/core/src/providers/types.ts

It defines the types every provider implementation (claude, codex, stub, future spring-ai/a2a/gemini/ollama/opencode/jules/amp) and the runner orchestrator depend on. The package is pure types + interfaces with zero behavior, no I/O, no business logic, and no dependencies beyond the Go standard library and log/slog.

Public Package

This package is exported at the top level of the module:

github.com/RenseiAI/donmai/agent

It is importable by downstream consumers including rensei-tui without requiring an agentfactory-tui dependency cascade. F.1.1 §1 ratifies this boundary.

Wire Format Compatibility

JSON tags use camelCase to match the legacy TS shape verbatim. The JSON shape is consumed by readers of QueuedWork.resolvedProfile across the fleet. If you change a wire shape (add/remove/rename a JSON field), update the F.1.1 design doc at:

../runs/2026-05-01-wave-6-fleet-iteration/F1.1-runner-contract.md

in the same change so the contract stays single-sourced.

The Nine Capabilities

Providers declare a Capabilities struct describing which optional features they support. The runner gates behavior off these flags rather than try-catching unsupported operations. The named capability constants (CapMessageInjection, CapSessionResume, ...) align 1:1 with the Capabilities struct fields and are used with IsSupported() helper.

Sealed Event Variants

The Event interface uses the sealed-interface variant pattern: each of the 8 event variants (InitEvent, SystemEvent, AssistantTextEvent, ToolUseEvent, ToolResultEvent, ToolProgressEvent, ResultEvent, ErrorEvent) implements both Kind() EventKind and the unexported isAgentEvent() marker. New variants must be added to this package — external packages cannot satisfy the interface, which keeps the discriminated union closed. For polymorphic JSON decoding use UnmarshalEvent.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnsupported is returned when a provider is asked to perform a
	// capability it does not advertise (e.g. Handle.Inject on a
	// provider with SupportsMessageInjection=false, or Provider.Resume
	// on a provider with SupportsSessionResume=false).
	ErrUnsupported = errors.New("agent: capability not supported by provider")

	// ErrNoProvider is returned when the runner cannot resolve a
	// Provider for a requested ProviderName (e.g. an org's profile
	// names a provider not registered with the running binary).
	ErrNoProvider = errors.New("agent: no provider registered for name")

	// ErrSessionNotFound is returned by Provider.Resume when the
	// requested session id is unknown or has already terminated.
	ErrSessionNotFound = errors.New("agent: session id not found")

	// ErrSpawnFailed is returned by Provider.Spawn when the provider
	// could not start the session (CLI missing, app-server
	// unreachable, etc.). Wrap with fmt.Errorf for context.
	ErrSpawnFailed = errors.New("agent: spawn failed")

	// ErrProviderUnavailable is returned by provider constructors
	// (provider.New) when the provider's runtime dependency is missing
	// or not reachable (e.g. `claude` binary not on PATH, codex
	// app-server failed to start). It is a probe-time error distinct
	// from ErrSpawnFailed which is per-session.
	ErrProviderUnavailable = errors.New("agent: provider runtime unavailable")
)

Sentinel errors returned by Provider and Handle implementations.

Callers wrap these with fmt.Errorf("context: %w", err) and check with errors.Is. Per F.1.1 §2 these are the contract-level errors; provider-specific errors live in the provider subpackage.

Functions

func IsSupported

func IsSupported(caps Capabilities, c Capability) bool

IsSupported reports whether a Capabilities matrix has the named Capability flag set. This is the runner's preferred gate over reading individual fields, because it keeps gating expressions consistent across providers.

func MarshalEvent

func MarshalEvent(e Event) ([]byte, error)

MarshalEvent encodes an Event to JSON, embedding the discriminant "kind" field so the value can be round-tripped through UnmarshalEvent.

The wire shape is:

{"kind": "<EventKind>", ...variant fields...}

Variant fields are flattened onto the outer object. Use MarshalEvent when persisting events to JSONL / streaming over HTTP; the JSONL shape is what runner/ writes to <worktree>/.agent/events.jsonl per F.1.1 §4 step 9.

Types

type AssistantTextEvent

type AssistantTextEvent struct {
	// Text is the assistant text chunk.
	Text string `json:"text"`

	// Raw is the provider-native event payload.
	Raw any `json:"raw,omitempty"`
}

AssistantTextEvent carries an incremental assistant-text output chunk. Verbatim port of AgentAssistantTextEvent. The runner accumulates Text across multiple events to scan for the WORK_RESULT marker.

func (AssistantTextEvent) Kind

Kind reports the EventKind discriminant.

type BackstopReport

type BackstopReport struct {
	// Triggered is true when the backstop ran (i.e. the contract had
	// unfilled fields).
	Triggered bool `json:"triggered"`

	// Pushed is true when the backstop ran git push -u origin <branch>.
	Pushed bool `json:"pushed,omitempty"`

	// PRCreated is true when the backstop ran gh pr create.
	PRCreated bool `json:"prCreated,omitempty"`

	// PRURL is the URL of a PR the backstop created or detected.
	PRURL string `json:"prUrl,omitempty"`

	// UnfilledFields lists the contract fields the backstop could not
	// auto-recover (e.g. work_result, comment_posted). The platform
	// posts a diagnostic Linear comment for these.
	UnfilledFields []string `json:"unfilledFields,omitempty"`

	// Diagnostics is human-readable text describing what happened.
	Diagnostics string `json:"diagnostics,omitempty"`
}

BackstopReport captures what the post-session backstop did, if anything. Populated by runner/backstop.go (F.1.1 §5.6).

type Capabilities

type Capabilities struct {
	// SupportsMessageInjection reports whether Handle.Inject works
	// (stateful providers: legacy TS Claude SDK, A2A). v0.5.0 Claude
	// CLI provider returns false here; steering reduces to stop+resume.
	SupportsMessageInjection bool `json:"supportsMessageInjection"`

	// SupportsSessionResume reports whether Provider.Resume can
	// continue a prior session.
	SupportsSessionResume bool `json:"supportsSessionResume"`

	// SupportsToolPlugins reports whether the provider can use MCP
	// tool plugins delivered via stdio servers (af_linear_*, af_code_*).
	SupportsToolPlugins bool `json:"supportsToolPlugins,omitempty"`

	// NeedsBaseInstructions reports whether the provider requires
	// persistent base instructions via Spec.BaseInstructions
	// (Codex app-server thread/start ‘instructions' field).
	NeedsBaseInstructions bool `json:"needsBaseInstructions,omitempty"`

	// NeedsPermissionConfig reports whether the provider requires
	// structured permission config via Spec.PermissionConfig (Codex
	// approval bridge).
	NeedsPermissionConfig bool `json:"needsPermissionConfig,omitempty"`

	// SupportsCodeIntelligenceEnforcement reports whether the provider
	// supports canUseTool-style code intelligence enforcement
	// (redirect Grep/Glob to af_code_* tools). v0.5.0 Claude provider
	// ships false; flip when a CLI wrapper exposes the callback.
	SupportsCodeIntelligenceEnforcement bool `json:"supportsCodeIntelligenceEnforcement,omitempty"`

	// EmitsSubagentEvents reports whether the provider emits
	// Anthropic-style subagent events (Claude Task tool progress).
	// Drives the Topology view's subagent stream rendering.
	EmitsSubagentEvents bool `json:"emitsSubagentEvents"`

	// SupportsReasoningEffort reports whether the provider honors the
	// per-step Spec.Effort (low | medium | high | xhigh). When false,
	// the dispatch path drops the value and emits a capability-mismatch
	// hook event so observers can flag silently-ignored cost-control
	// hints. Optional for backwards compatibility — a zero value is
	// treated as not supporting reasoning effort.
	SupportsReasoningEffort bool `json:"supportsReasoningEffort,omitempty"`

	// ToolPermissionFormat names the tool-permission grammar this
	// provider uses ("claude" | "codex" | "spring-ai"). When empty
	// callers should default to "claude".
	ToolPermissionFormat string `json:"toolPermissionFormat,omitempty"`

	// AcceptsAllowedToolsList reports whether the provider honors
	// Spec.AllowedTools end-to-end at Spawn time — translating it into
	// the upstream API's allow/permission grammar. Providers that ship
	// SupportsToolPlugins=true but cannot pass through AllowedTools
	// (e.g. codex routes permissions through the approval bridge) MUST
	// declare false here so the runner knows the field is silently
	// dropped. Tracks the v2 contract's acceptsAllowedToolsList flag
	// from 002-provider-base-contract.md §"Tool-use surface — forward
	// declaration".
	AcceptsAllowedToolsList bool `json:"acceptsAllowedToolsList,omitempty"`

	// AcceptsMcpServerSpec reports whether the provider honors
	// Spec.MCPServers end-to-end at Spawn time — either passing the
	// stdio configs through to the upstream API or spawning a local
	// MCP bridge that the upstream session can call. Distinct from
	// SupportsToolPlugins which only states whether tools are usable
	// at all; this flag specifies whether the Spec field shape is
	// honored.
	AcceptsMcpServerSpec bool `json:"acceptsMcpServerSpec,omitempty"`

	// HumanLabel is a human-readable provider-family display name
	// (e.g. "Claude", "Codex"). Used in TUI/dashboard surfaces and
	// log messages where the raw name is not user-friendly.
	HumanLabel string `json:"humanLabel,omitempty"`
}

Capabilities is the typed capability matrix every provider declares.

Verbatim port of AgentProviderCapabilities. Flat struct (no nested objects) per the rensei-architecture base-contract validator constraint (002-provider-base-contract.md §Capabilities).

Per F.1.1 §3.1 and the locked coordinator decision, the v0.5.0 claude provider ships SupportsMessageInjection=false (no mid-session injection in CLI JSON-stream mode); flip when a wrapper sidecar lands in F.5.

Source: ../agentfactory/packages/core/src/providers/types.ts (AgentProviderCapabilities).

type Capability

type Capability string

Capability names a single optional behavior a provider may support.

The 9 named capabilities mirror the AgentProviderCapabilities fields from the legacy TS interface verbatim. Use IsSupported(caps, cap) to gate runner behavior rather than try-catching unsupported provider operations.

Source: ../agentfactory/packages/core/src/providers/types.ts (AgentProviderCapabilities).

const (
	CapMessageInjection           Capability = "message_injection"
	CapSessionResume              Capability = "session_resume"
	CapToolPlugins                Capability = "tool_plugins"
	CapBaseInstructions           Capability = "base_instructions"
	CapPermissionConfig           Capability = "permission_config"
	CapCodeIntelEnforcement       Capability = "code_intel_enforcement"
	CapSubagentEvents             Capability = "subagent_events"
	CapReasoningEffort            Capability = "reasoning_effort"
	CapToolPermissionFormatClaude Capability = "tool_perm_format_claude"
	// CapAcceptsAllowedToolsList reports whether the provider honors
	// Spec.AllowedTools end-to-end (translation into upstream API).
	// Tracks the v2 contract's `acceptsAllowedToolsList` flag from
	// 002-provider-base-contract.md §"Tool-use surface — forward declaration".
	CapAcceptsAllowedToolsList Capability = "accepts_allowed_tools_list"
	// CapAcceptsMcpServerSpec reports whether the provider honors
	// Spec.MCPServers end-to-end (translation into upstream API or a
	// session-local MCP bridge). Tracks the v2 contract's
	// `acceptsMcpServerSpec` flag.
	CapAcceptsMcpServerSpec Capability = "accepts_mcp_server_spec"
)

Named capability constants. Each maps 1:1 to a field on Capabilities.

type CodeIntelEnforcement

type CodeIntelEnforcement struct {
	// EnforceUsage requires the agent to call at least one af_code_*
	// tool before native Grep/Glob is allowed.
	EnforceUsage bool `json:"enforceUsage"`

	// FallbackAfterAttempt allows native Grep/Glob after a single
	// af_code_* attempt, regardless of result.
	FallbackAfterAttempt bool `json:"fallbackAfterAttempt"`
}

CodeIntelEnforcement is the Grep/Glob redirect-to-af_code_* config. When set, the provider's tool callback redirects native Grep/Glob calls to af_code_* tools until the agent has attempted code intelligence at least once.

type CostData

type CostData struct {
	InputTokens       int64   `json:"inputTokens,omitempty"`
	OutputTokens      int64   `json:"outputTokens,omitempty"`
	CachedInputTokens int64   `json:"cachedInputTokens,omitempty"`
	TotalCostUsd      float64 `json:"totalCostUsd,omitempty"`
	NumTurns          int     `json:"numTurns,omitempty"`
}

CostData mirrors AgentCostData from the legacy TS providers/types.ts.

All fields are optional; providers populate what they have available.

type EffortLevel

type EffortLevel string

EffortLevel mirrors EffortLevel from ../agentfactory/packages/core/src/providers/index.ts. Providers map this to their native reasoning-effort knob:

  • Claude : --effort flag
  • Codex : reasoningEffort / model_reasoning_effort
  • Gemini : thinkingBudget
const (
	EffortLow    EffortLevel = "low"
	EffortMedium EffortLevel = "medium"
	EffortHigh   EffortLevel = "high"
	EffortXHigh  EffortLevel = "xhigh"
)

EffortLevel constants. The xhigh tier matches Anthropic's reasoning-effort scale.

type ErrorEvent

type ErrorEvent struct {
	// Message is the human-readable error message.
	Message string `json:"message"`

	// Code is an optional provider-defined error code (e.g.
	// "spawn_no_result", "rate_limited").
	Code string `json:"code,omitempty"`

	// Raw is the provider-native event payload.
	Raw any `json:"raw,omitempty"`
}

ErrorEvent is a non-recoverable provider error fired before any terminal ResultEvent. The provider closes the events channel after emitting an ErrorEvent. Verbatim port of AgentErrorEvent.

func (ErrorEvent) Kind

func (ErrorEvent) Kind() EventKind

Kind reports the EventKind discriminant.

type Event

type Event interface {
	// Kind returns the discriminant for this variant.
	Kind() EventKind
	// contains filtered or unexported methods
}

Event is the sealed-interface base type for all agent event variants.

Implementations: InitEvent, SystemEvent, AssistantTextEvent, ToolUseEvent, ToolResultEvent, ToolProgressEvent, ResultEvent, ErrorEvent. The unexported isAgentEvent marker prevents external packages from satisfying the interface, keeping the discriminated union closed.

To decode an Event polymorphically from JSON use UnmarshalEvent.

func UnmarshalEvent

func UnmarshalEvent(data []byte) (Event, error)

UnmarshalEvent decodes an Event from JSON written by MarshalEvent. It reads the "kind" discriminator and dispatches to the matching variant struct. Unknown kinds return a wrapped error.

This is the polymorphic decode entry point per F.1.1 §2; runner/ uses it to read <worktree>/.agent/events.jsonl back during recovery.

type EventKind

type EventKind string

EventKind is the discriminant for Event variants.

Verbatim port of the legacy TS AgentEvent.type literal union. Each variant is a dedicated struct; the discriminated-union pattern uses a Go interface with a private marker method.

const (
	EventInit          EventKind = "init"
	EventSystem        EventKind = "system"
	EventAssistantText EventKind = "assistant_text"
	EventToolUse       EventKind = "tool_use"
	EventToolResult    EventKind = "tool_result"
	EventToolProgress  EventKind = "tool_progress"
	EventResult        EventKind = "result"
	EventError         EventKind = "error"
)

EventKind constants. The wire values match the legacy TS literal union (e.g. "init", "assistant_text", "tool_use") so providers can dispatch off the JSON type field.

type Handle

type Handle interface {
	// SessionID returns the provider-native session identifier
	// (Claude session UUID, Codex thread id). Empty until the
	// InitEvent fires; callers should consume events first.
	SessionID() string

	// Events returns the read-only event channel. The provider
	// closes this channel after emitting a terminal ResultEvent or
	// an unrecoverable ErrorEvent.
	Events() <-chan Event

	// Inject sends a follow-up user message into the session.
	// Returns ErrUnsupported when
	// !Provider.Capabilities().SupportsMessageInjection. Implementations
	// that support it should be safe to call concurrently with Events
	// consumption.
	Inject(ctx context.Context, text string) error

	// Stop aborts the session. Idempotent; safe to call after the
	// event channel has closed (returns nil). Implementations should
	// honor ctx cancellation for stop deadlines (typical: 5s grace
	// then SIGKILL for child-process providers).
	Stop(ctx context.Context) error
}

Handle is the live interface to one running session.

Verbatim port of the legacy TS AgentHandle interface from ../agentfactory/packages/core/src/providers/types.ts.

Returned by Provider.Spawn / Provider.Resume. The provider closes the channel returned by Events() after emitting a terminal ResultEvent or an unrecoverable ErrorEvent, signalling that the session is done and no more events will arrive.

type InitEvent

type InitEvent struct {
	// SessionID is the provider-native session/thread id (Claude UUID,
	// Codex thread id). Captured by the runner for resume.
	SessionID string `json:"sessionId"`

	// Raw is the provider-native event payload, opaque to callers.
	Raw any `json:"raw,omitempty"`
}

InitEvent fires when the agent has initialized; it captures the provider-native session identifier. Verbatim port of AgentInitEvent.

func (InitEvent) Kind

func (InitEvent) Kind() EventKind

Kind reports the EventKind discriminant.

type MCPServerConfig

type MCPServerConfig struct {
	Name string `json:"name"`
	// Type is the transport shape. Either "stdio" (default) or "http".
	Type    string            `json:"type,omitempty"`
	Command string            `json:"command,omitempty"`
	Args    []string          `json:"args,omitempty"`
	Env     map[string]string `json:"env,omitempty"`
	// URL is the HTTP MCP endpoint when Type == "http".
	URL string `json:"url,omitempty"`
	// Headers are HTTP headers to send on every MCP request. Typically
	// holds the Authorization bearer for the platform's MCP route.
	Headers map[string]string `json:"headers,omitempty"`
}

MCPServerConfig is one MCP server the provider should configure on session start. Providers that support MCP tool plugins inject these on session init (Claude: via --mcp-config; Codex: via config/batchWrite mcpStdioServers).

Two transports are supported:

  • stdio — Command + Args + Env (the original / legacy shape)
  • http — URL + Headers (Streamable HTTP, used by the platform's per-session MCP endpoint at /api/mcp/<sessionId> — see the A2A per-session MCP ADR)

Type is the discriminator. When empty it defaults to "stdio" so existing callers that only set Command/Args/Env keep working unchanged.

type PermissionConfig

type PermissionConfig struct {
	// AllowPatterns is the list of tool-call patterns auto-approved
	// without prompting (e.g. "Bash(pnpm:*)").
	AllowPatterns []string `json:"allowPatterns,omitempty"`

	// DisallowPatterns is the list of tool-call patterns auto-denied.
	DisallowPatterns []string `json:"disallowPatterns,omitempty"`

	// DefaultDecision is the fallback when no pattern matches.
	// Valid values: "allow" | "deny" | "prompt". Empty defaults to
	// "prompt" (provider-specific).
	DefaultDecision string `json:"defaultDecision,omitempty"`
}

PermissionConfig is the runtime permission policy for the codex approval bridge. Verbatim port of CodexPermissionConfig from ../agentfactory/packages/core/src/templates/adapters.ts.

Providers without NeedsPermissionConfig=true ignore this field.

type Provider

type Provider interface {
	// Name returns this provider's identifier. Stable for the lifetime
	// of the Provider instance.
	Name() ProviderName

	// Capabilities returns this provider's capability flags. Stable
	// for the lifetime of the Provider instance.
	Capabilities() Capabilities

	// Spawn starts a new agent session. The returned Handle's Events
	// channel emits exactly one InitEvent, then zero or more
	// assistant/tool events, then exactly one terminal ResultEvent,
	// then closes. ctx cancellation aborts the session.
	Spawn(ctx context.Context, spec Spec) (Handle, error)

	// Resume continues a previously interrupted session. sessionID is
	// the value captured from a prior InitEvent. Behavior is
	// capability-gated by SupportsSessionResume; providers that do
	// not support resume return ErrUnsupported.
	Resume(ctx context.Context, sessionID string, spec Spec) (Handle, error)

	// Shutdown releases provider-level resources (long-lived child
	// processes such as the codex app-server). Providers with
	// per-session children may no-op and return nil. Called by the
	// runner on fleet shutdown.
	Shutdown(ctx context.Context) error
}

Provider is the contract every agent runtime implements.

Verbatim port of the legacy TS AgentProvider interface from ../agentfactory/packages/core/src/providers/types.ts.

Implementations live in github.com/RenseiAI/donmai/provider/ subpackages (claude, codex, stub for v0.5.0). Each implementation is independent and only depends on this package + its provider-native CLI/SDK + the standard library.

Lifecycle expectations (F.1.1 §3):

  • Provider construction (provider.New) does fail-fast probing such as `which claude`. Callers see provider unavailability before any worktree work.
  • Spawn returns a Handle whose Events channel emits exactly one InitEvent, then zero or more assistant/tool events, then exactly one terminal ResultEvent (or ErrorEvent followed by close), then closes.
  • Resume continues a previously interrupted session, gated by Capabilities().SupportsSessionResume; providers that do not support resume return ErrUnsupported.
  • Shutdown releases provider-level resources such as the long-lived codex app-server child. Providers with per-session children (Claude CLI) may no-op. Called once on daemon drain.

type ProviderName

type ProviderName string

ProviderName is the stable identifier for an agent provider family.

It mirrors AgentProviderName from the legacy TS port. v0.5.0 ships claude, codex, and stub. Future families (spring-ai, a2a, gemini, ollama, opencode, jules, amp) extend this enum without breaking the contract.

Source: ../agentfactory/packages/core/src/providers/types.ts (AgentProviderName).

const (
	ProviderClaude   ProviderName = "claude"
	ProviderCodex    ProviderName = "codex"
	ProviderStub     ProviderName = "stub" // test-only; deterministic
	ProviderSpringAI ProviderName = "spring-ai"
	ProviderA2A      ProviderName = "a2a"
	ProviderAmp      ProviderName = "amp"
	ProviderGemini   ProviderName = "gemini"
	ProviderOllama   ProviderName = "ollama"
	ProviderOpenCode ProviderName = "opencode"
	ProviderJules    ProviderName = "jules"
)

ProviderName constants. v0.5.0 ships ProviderClaude, ProviderCodex, and ProviderStub. The remaining identifiers are reserved for v0.6.0+ providers per F.1.1 §1; declaring them now keeps the wire enum stable across waves so platform-side dispatch routing does not regress.

type QualityReport

type QualityReport struct {
	// BaselineCaptured is true when the session-start baseline was
	// successfully recorded; false when the gate was unavailable
	// (e.g. testCommand missing).
	BaselineCaptured bool `json:"baselineCaptured"`

	// TestDelta is the change in failing test count vs baseline.
	// Negative means improvement, positive means regression.
	TestDelta int `json:"testDelta"`

	// TypeDelta is the change in typecheck error count vs baseline.
	TypeDelta int `json:"typeDelta"`

	// LintDelta is the change in lint error count vs baseline.
	LintDelta int `json:"lintDelta"`

	// BlockedPromotion is true when a regression triggered a
	// status-promotion block on the platform side.
	BlockedPromotion bool `json:"blockedPromotion"`
}

QualityReport captures the test/typecheck/lint deltas vs the session-start baseline. Populated by runner/quality.go (F.1.1 §5.5).

type Result

type Result struct {
	// Status is the terminal session status. Drives platform-side
	// agent_session.status mutations downstream of /completion.
	// Valid values: "completed" | "failed" | "stopped".
	Status string `json:"status"`

	// ProviderName identifies which provider produced this result.
	ProviderName ProviderName `json:"providerName"`

	// ProviderSessionID is the provider-native session id (Claude UUID,
	// Codex thread id) captured from InitEvent.
	ProviderSessionID string `json:"providerSessionId,omitempty"`

	// WorktreePath is the absolute path of the worktree the session
	// ran in. Useful for debugging and for the
	// PreserveWorktreeOnFailure path.
	WorktreePath string `json:"worktreePath,omitempty"`

	// PullRequestURL is the URL of the PR opened (by the agent or the
	// backstop). Empty when no PR exists.
	PullRequestURL string `json:"pullRequestUrl,omitempty"`

	// CommitSHA is the head commit sha of the work branch when known.
	CommitSHA string `json:"commitSha,omitempty"`

	// Summary is a short human-readable summary of the work done.
	Summary string `json:"summary,omitempty"`

	// WorkResult is the QA/acceptance verdict. Valid values:
	// "passed" | "failed" | "unknown". Drives the acceptance gate on
	// the platform side.
	WorkResult string `json:"workResult,omitempty"`

	// Cost rolls up token usage and dollars across the session.
	Cost *CostData `json:"cost,omitempty"`

	// FailureMode classifies why a non-completed session failed.
	// Enum values are owned by runner/failure.go.
	FailureMode string `json:"failureMode,omitempty"`

	// BackstopReport captures what the post-session backstop did,
	// if it ran.
	BackstopReport *BackstopReport `json:"backstopReport,omitempty"`

	// QualityReport captures the test/typecheck/lint deltas vs the
	// session-start baseline.
	QualityReport *QualityReport `json:"qualityReport,omitempty"`

	// Error is the human-readable error message when Status is
	// "failed".
	Error string `json:"error,omitempty"`
}

Result is the runner's final session-result shape, distinct from the per-provider terminal ResultEvent.

The runner builds this from the terminal Event plus side-channel data (worktree path, backstop report, quality report, WORK_RESULT marker) and posts it to the platform via POST /api/sessions/<id>/completion (see F.1.1 §6).

type ResultEvent

type ResultEvent struct {
	// Success reports whether the session ended successfully.
	Success bool `json:"success"`

	// Message is the completion message (typically only set on success).
	Message string `json:"message,omitempty"`

	// Errors is the list of error messages (typically only set on
	// failure).
	Errors []string `json:"errors,omitempty"`

	// ErrorSubtype is the provider-defined error subtype (e.g.
	// "error_during_execution", "error_max_turns").
	ErrorSubtype string `json:"errorSubtype,omitempty"`

	// Cost is the rolled-up cost/usage for the session.
	Cost *CostData `json:"cost,omitempty"`

	// Raw is the provider-native event payload.
	Raw any `json:"raw,omitempty"`
}

ResultEvent is the terminal session-outcome event from the provider. Distinct from agent.Result which is the runner's higher-level session-result struct (see types.go). Verbatim port of AgentResultEvent.

func (ResultEvent) Kind

func (ResultEvent) Kind() EventKind

Kind reports the EventKind discriminant.

type SandboxLevel

type SandboxLevel string

SandboxLevel mirrors AgentSpawnConfig.sandboxLevel from the legacy TS.

Source: ../agentfactory/packages/core/src/providers/types.ts.

const (
	SandboxReadOnly       SandboxLevel = "read-only"
	SandboxWorkspaceWrite SandboxLevel = "workspace-write"
	SandboxFullAccess     SandboxLevel = "full-access"
)

SandboxLevel constants align with Codex sandbox policies (readOnly / workspaceWrite / dangerFullAccess) and the cross-provider sandbox taxonomy in F.1.1 §3.2.

type Spec

type Spec struct {
	// Prompt is the task-specific directive.
	Prompt string `json:"prompt"`

	// Cwd is the working directory the agent session runs in.
	// Typically the runner's worktree path.
	Cwd string `json:"cwd"`

	// Env is the environment variable map merged onto the process
	// environment (after AGENT_ENV_BLOCKLIST filtering).
	Env map[string]string `json:"env"`

	// Autonomous indicates the session has no interactive user;
	// providers should disable user-input tools when true.
	Autonomous bool `json:"autonomous"`

	// SandboxEnabled enables the provider's default filesystem/network
	// sandbox.
	SandboxEnabled bool `json:"sandboxEnabled"`

	// SandboxLevel overrides the sandbox tier when SandboxEnabled is
	// true. Maps to provider-native policies.
	SandboxLevel SandboxLevel `json:"sandboxLevel,omitempty"`

	// AllowedTools is the list of tool-call patterns auto-allowed
	// without prompting (Claude permission-pattern format
	// "Bash(prefix:glob)").
	AllowedTools []string `json:"allowedTools,omitempty"`

	// DisallowedTools is the list of tool-call patterns the provider
	// must reject.
	DisallowedTools []string `json:"disallowedTools,omitempty"`

	// MCPServers is the list of stdio MCP servers the provider should
	// configure on session start.
	MCPServers []MCPServerConfig `json:"mcpStdioServers,omitempty"`

	// MCPToolNames is the list of fully-qualified MCP tool names
	// (e.g. "mcp__af-code-intelligence__af_code_get_repo_map") that
	// should be added to AllowedTools so autonomous agents can call
	// them.
	MCPToolNames []string `json:"mcpToolNames,omitempty"`

	// MaxTurns caps agentic turns (API round-trips) before the
	// provider stops. nil falls back to the provider default.
	MaxTurns *int `json:"maxTurns,omitempty"`

	// Model is the model identifier (e.g. "claude-sonnet-4-5"). Empty
	// falls back to provider/env default.
	Model string `json:"model,omitempty"`

	// Effort is the normalized reasoning-effort tier. Honored only
	// when Capabilities.SupportsReasoningEffort is true.
	Effort EffortLevel `json:"effort,omitempty"`

	// BaseInstructions are persistent system instructions
	// (Codex thread/start ‘instructions'). Honored only when
	// Capabilities.NeedsBaseInstructions is true.
	BaseInstructions string `json:"baseInstructions,omitempty"`

	// SystemPromptAppend is appended to the system prompt after
	// standard instruction sections (sourced from
	// RepositoryConfig.systemPrompt).
	SystemPromptAppend string `json:"systemPromptAppend,omitempty"`

	// PermissionConfig is the structured permission policy for
	// providers that consume one (Codex approval bridge).
	PermissionConfig *PermissionConfig `json:"permissionConfig,omitempty"`

	// CodeIntelEnforcement enables the af_code_* redirect for
	// providers that support it.
	CodeIntelEnforcement *CodeIntelEnforcement `json:"codeIntelligenceEnforcement,omitempty"`

	// ProviderConfig is provider-specific settings from the matched
	// model profile (e.g. {"serviceTier":"fast"} for OpenAI,
	// {"speed":"fast"} for Anthropic).
	ProviderConfig map[string]any `json:"providerConfig,omitempty"`

	// SubAgentProvider names the provider for spawned sub-agents when
	// different from the parent. Used by coordination templates.
	SubAgentProvider ProviderName `json:"subAgentProvider,omitempty"`

	// OnProcessSpawned is an optional callback that fires once the
	// provider has spawned its underlying process; used by the runner
	// to capture PIDs for metrics. Not serialized.
	OnProcessSpawned func(pid int) `json:"-"`
}

Spec is the input contract for Provider.Spawn.

Verbatim port of the AgentSpawnConfig from the legacy TS providers/types.ts. Capability-gated: providers consume the fields they support; unsupported fields are silently ignored. The runner is responsible for not setting incompatible fields (gate on Capabilities before invoking Spawn).

Source: ../agentfactory/packages/core/src/providers/types.ts (AgentSpawnConfig).

type SystemEvent

type SystemEvent struct {
	// Subtype is the provider-defined event subtype (e.g. "compaction",
	// "rate_limited").
	Subtype string `json:"subtype"`

	// Message is an optional human-readable message.
	Message string `json:"message,omitempty"`

	// Raw is the provider-native event payload.
	Raw any `json:"raw,omitempty"`
}

SystemEvent is a provider-emitted lifecycle/status event (compaction, rate-limit notice, etc.). Verbatim port of AgentSystemEvent.

func (SystemEvent) Kind

func (SystemEvent) Kind() EventKind

Kind reports the EventKind discriminant.

type ToolProgressEvent

type ToolProgressEvent struct {
	// ToolName is the tool identifier.
	ToolName string `json:"toolName"`

	// ElapsedSeconds is how long the tool has been running.
	ElapsedSeconds float64 `json:"elapsedSeconds"`

	// Raw is the provider-native event payload.
	Raw any `json:"raw,omitempty"`
}

ToolProgressEvent is a long-running tool's progress tick. Verbatim port of AgentToolProgressEvent.

func (ToolProgressEvent) Kind

Kind reports the EventKind discriminant.

type ToolResultEvent

type ToolResultEvent struct {
	// ToolName is the tool identifier; may be empty when the provider
	// only reports the tool-use id.
	ToolName string `json:"toolName,omitempty"`

	// ToolUseID pairs with ToolUseEvent.ToolUseID.
	ToolUseID string `json:"toolUseId,omitempty"`

	// Content is the tool's output text or stringified result.
	Content string `json:"content"`

	// IsError is true when the tool reported failure.
	IsError bool `json:"isError"`

	// Raw is the provider-native event payload.
	Raw any `json:"raw,omitempty"`
}

ToolResultEvent carries a tool-execution result (success or error). Verbatim port of AgentToolResultEvent.

func (ToolResultEvent) Kind

func (ToolResultEvent) Kind() EventKind

Kind reports the EventKind discriminant.

type ToolUseEvent

type ToolUseEvent struct {
	// ToolName is the tool identifier (e.g. "Bash", "Edit",
	// "mcp__af_linear__af_linear_get_issue").
	ToolName string `json:"toolName"`

	// ToolUseID is the provider-native tool-call identifier; pairs
	// with ToolResultEvent.ToolUseID.
	ToolUseID string `json:"toolUseId,omitempty"`

	// Input is the tool-call input map.
	Input map[string]any `json:"input"`

	// ToolCategory is the runner's categorization
	// ("filesystem"|"shell"|"network"|"linear"|"code-intel"). Empty
	// when the runner has not yet categorized the call.
	ToolCategory string `json:"toolCategory,omitempty"`

	// Raw is the provider-native event payload.
	Raw any `json:"raw,omitempty"`
}

ToolUseEvent fires when the agent invokes a tool. Verbatim port of AgentToolUseEvent.

func (ToolUseEvent) Kind

func (ToolUseEvent) Kind() EventKind

Kind reports the EventKind discriminant.

Jump to

Keyboard shortcuts

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