attachadapter

package
v2.8.0-dev.3 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package attachadapter bridges a *agent.Agent onto the attach-mode HTTP/SSE surface (pkg/attach). It is phase 4 of the pkg/agent decomposition (docs/agent-package-split-design.md): the 22 Attach* capability methods and the WithAttach* provider options that used to live on the core Agent now live here, so the frozen agent surface stays narrow and hosts that never serve attach-mode never carry the wiring.

Usage:

a := agent.New(llm, ...)                 // core options only
ad := attachadapter.New(a,
    attachadapter.WithMemoryProvider(f), // formerly agent.WithAttachMemoryProvider
    attachadapter.WithPromptBroker(b),
)
reg.Register(ad)                          // ad satisfies attach.Registrant

The adapter satisfies attach.Registrant plus every optional attach capability interface (ToolsProvider, UsageProvider, PermsController, ...); registering it with a *attach.SessionRegistry makes the agent reachable over HTTP/SSE via attach.NewServer.

Index

Constants

This section is empty.

Variables

View Source
var ErrSubagentSpawnerUnavailable = errors.New("agent: subagent spawner unavailable (no BackgroundAgentManager wired)")

ErrSubagentSpawnerUnavailable is returned by AttachSpawnSubagent when the agent wasn't constructed with agent.WithBackgroundManager. The attach handler maps this to HTTP 501 so the operator sees "subagent spawn not registered" instead of a 500.

The message string is load-bearing: pkg/attach matches it literally (it can't import this package's sentinel without knowing about the agent side), so it must not change. Formerly agent.ErrSubagentSpawnerUnavailable.

Functions

This section is empty.

Types

type Adapter

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

Adapter wraps a *agent.Agent with the attach-facing capability surface. Construct with New; the zero value is not useful.

The capability methods (Attach*) are safe on a nil receiver — they degrade to the same "capability not registered" responses an unwired closure produces, matching the nil-safety convention of the agent package. The plain Registrant forwards (AppName, Inject, ...) assume a real wrapped agent, same as registering a bare *agent.Agent did before the split.

func New

func New(a *agent.Agent, opts ...Option) *Adapter

New wraps a with the attach capability surface. a may be nil (the adapter's methods all no-op / zero-value), though in practice the caller constructs the agent first and wraps it immediately.

func (*Adapter) Agent

func (ad *Adapter) Agent() *agent.Agent

Agent returns the wrapped *agent.Agent. Hosts that thread the adapter through construction seams (session factories, TUI deps) use this to recover the agent for Run/Inject/etc without carrying both values.

func (*Adapter) AppName

func (ad *Adapter) AppName() string

AppName implements attach.Registrant.

func (*Adapter) AttachAddAllow

func (ad *Adapter) AttachAddAllow(patterns []string) error

AttachAddAllow implements attach.PermsController. Delegates to permissions.Gate.AddAllowPatterns. Returns nil if no gate was wired (no-op rather than error — operators shouldn't see an error for an absent gate). Surfaces validation errors from the gate so the operator sees malformed-pattern feedback.

func (*Adapter) AttachAddDeny

func (ad *Adapter) AttachAddDeny(patterns []string) error

AttachAddDeny implements attach.PermsController. Delegates to permissions.Gate.AddDenyPatterns.

func (*Adapter) AttachAgents

func (ad *Adapter) AttachAgents() []attach.AgentInfo

AttachAgents implements attach.AgentsProvider. Returns the live background subagents from the agent's SubagentManager, or an empty slice when no manager was wired.

func (*Adapter) AttachAskSideQuestion

func (ad *Adapter) AttachAskSideQuestion(ctx context.Context, question string) (string, error)

AttachAskSideQuestion implements attach.SideQueryProvider. Wraps agent.AskSideQuestion (the /btw side-channel that doesn't persist to the event log).

func (*Adapter) AttachCheckpoint

func (ad *Adapter) AttachCheckpoint(ctx context.Context, note string) (attach.CheckpointResponse, error)

AttachCheckpoint implements attach.CheckpointSlashProvider. Wraps agent.Checkpoint.

func (*Adapter) AttachCompact

func (ad *Adapter) AttachCompact(ctx context.Context, focus string) (attach.CompactResponse, error)

AttachCompact implements attach.CompactSlashProvider. Wraps agent.Compact and projects the result into the JSON wire format. Errors propagate; the attach handler turns them into 500s.

func (*Adapter) AttachContext

func (ad *Adapter) AttachContext() attach.ContextInfo

AttachContext implements attach.ContextProvider. Projects the agent's ContextStats (compaction / checkpoint / subtask shape) into the attach wire format. Same cost as ContextStats (one session.Service.Get() + O(events) scan) — operator-driven, infrequent.

func (*Adapter) AttachInterrupt

func (ad *Adapter) AttachInterrupt() bool

AttachInterrupt implements attach.InterruptProvider so the attach-mode POST /sessions/<sid>/interrupt handler can dispatch cancel intents from a remote operator. Forwards to agent.Interrupt.

func (*Adapter) AttachMCP

func (ad *Adapter) AttachMCP() attach.MCPInfo

AttachMCP implements attach.MCPProvider.

func (*Adapter) AttachMemory

func (ad *Adapter) AttachMemory() []attach.MemorySource

AttachMemory implements attach.MemoryProvider. Returns nil when no provider was wired — the handler emits 200 with an empty `{"sources": []}`.

func (*Adapter) AttachPerms

func (ad *Adapter) AttachPerms() attach.PermsInfo

AttachPerms implements attach.PermsProvider. Returns the gate's current Snapshot (mode + allow + deny pattern lists) projected into the attach wire format, plus the per-session approval log so the remote TUI's /permissions slash can render what was approved this session. Returns zero PermsInfo if no gate was wired via agent.WithGate.

func (*Adapter) AttachPricing

func (ad *Adapter) AttachPricing() attach.PricingInfo

AttachPricing implements attach.PricingProvider.

func (*Adapter) AttachPromptBroker

func (ad *Adapter) AttachPromptBroker() *attach.PromptBroker

AttachPromptBroker implements attach.PromptBrokerProvider.

func (*Adapter) AttachRefreshPricing

func (ad *Adapter) AttachRefreshPricing(ctx context.Context) (attach.PricingRefreshResponse, error)

AttachRefreshPricing implements attach.PricingController. Returns attach.ErrCapabilityNotRegistered when no func was wired — the handler maps that to HTTP 501.

func (*Adapter) AttachReload

func (ad *Adapter) AttachReload(ctx context.Context) attach.ReloadResponse

AttachReload implements attach.Reloader. Returns a response with Errors populated by ErrCapabilityNotRegistered when no func was wired so the handler emits the same 501 the other unwired controllers do.

func (*Adapter) AttachReplan

func (ad *Adapter) AttachReplan(ctx context.Context, req attach.ReplanRequest) (attach.ReplanResponse, error)

AttachReplan implements attach.ReplanProvider. Routes to the closure wired by WithReplanner; returns ErrCapabilityNotRegistered when no func was wired.

func (*Adapter) AttachSetManualPricing

func (ad *Adapter) AttachSetManualPricing(req attach.PricingSetRequest) error

AttachSetManualPricing implements attach.PricingController.

func (*Adapter) AttachSkills

func (ad *Adapter) AttachSkills() []attach.SkillInfo

AttachSkills implements attach.SkillsProvider.

func (*Adapter) AttachSpawnSubagent

func (ad *Adapter) AttachSpawnSubagent(ctx context.Context, spec attach.SubagentSpec) (attach.SubagentSpawnResponse, error)

AttachSpawnSubagent implements attach.SubagentSpawner. Delegates to the agent's wired SubagentManager. Returns ErrSubagentSpawnerUnavailable when no manager is attached.

func (*Adapter) AttachStatus

func (ad *Adapter) AttachStatus() attach.StatusInfo

AttachStatus implements attach.StatusProvider. V1 returns the agent's model name + a coarse "idle" state — finer-grained state (running / deferred / paused) would require run-loop instrumentation that hasn't been wired yet; the design doc captures pause/resume + state mutation as v3 work.

func (*Adapter) AttachTools

func (ad *Adapter) AttachTools() []attach.ToolInfo

AttachTools implements attach.ToolsProvider. Returns the agent's full tool catalog as ToolInfo entries with source classification (builtin vs other) and the gate's pre-flight state per tool when a gate was wired via agent.WithGate. MCP / skill attribution is "other" in v1 — distinguishing them at the slice level needs an upstream metadata pass we haven't done yet.

func (*Adapter) AttachUsage

func (ad *Adapter) AttachUsage() attach.UsageInfo

AttachUsage implements attach.UsageProvider. Returns the agent's usage tracker totals plus a per-model breakdown when more than one model has been used in this session (typical pattern: parent on a frontier model, subtasks on a cheap flash-tier model via --agentic-small-model), plus a per-turn array so operators can answer per-turn cost/cache questions without hand-scraping the eventlog (issue #222). Returns a zero UsageInfo if no usage tracker was wired (agent.WithUsageTracker).

cost_usd_uncached_reference is computed per-turn using the resolved pricing for that turn's model — sessions that mix models (parent + subtask on a flash-tier via --agentic-small-model) get accurate reference numbers instead of averaging one model's rates over the other. Rolled up into Overall / PerModel by summing per-turn contributions.

func (*Adapter) Description

func (ad *Adapter) Description() string

Description implements attach.DescriptionProvider — the /.well-known/agent-card.json handler falls back to this when no explicit AgentCardConfig.Description override is supplied.

func (*Adapter) EventLog

func (ad *Adapter) EventLog() *eventlog.Handle

EventLog implements attach.Registrant.

func (*Adapter) Inject

func (ad *Adapter) Inject(message string) error

Inject implements attach.Registrant.

func (*Adapter) InjectAs

func (ad *Adapter) InjectAs(message string, caller auth.Caller) error

InjectAs implements attach.Registrant.

func (*Adapter) RequestWake

func (ad *Adapter) RequestWake()

RequestWake implements attach.Registrant.

func (*Adapter) SessionID

func (ad *Adapter) SessionID() string

SessionID implements attach.Registrant.

func (*Adapter) SetAttachEmitter

func (ad *Adapter) SetAttachEmitter(f func(eventType string, payload any))

SetAttachEmitter implements attach.EmitTarget. The attach broadcaster calls this on first SSE subscriber (wiring its Emit method) and again with nil when the last subscriber disconnects. Forwards to the agent, which owns the emit machinery — the core run loop is the thing that emits status/turn/usage events.

func (*Adapter) UserID

func (ad *Adapter) UserID() string

UserID implements attach.Registrant.

type Option

type Option func(*Adapter)

Option configures an Adapter under construction.

func WithMCPProvider

func WithMCPProvider(fn func() attach.MCPInfo) Option

WithMCPProvider wires a snapshot func for /sessions/<sid>/mcp (backs /mcp). Formerly agent.WithAttachMCPProvider.

func WithMemoryProvider

func WithMemoryProvider(fn func() []attach.MemorySource) Option

WithMemoryProvider wires a snapshot func that returns the agent's loaded instruction sources for the remote-attach /sessions/<sid>/memory endpoint (backs the remote TUI's /memory slash). The caller usually projects an `instruction.Loaded`'s Sources list into []attach.MemorySource; nil = endpoint returns empty. Formerly agent.WithAttachMemoryProvider.

func WithPricingProvider

func WithPricingProvider(fn func() attach.PricingInfo) Option

WithPricingProvider wires a snapshot func for /sessions/<sid>/pricing (backs the remote TUI's /pricing read). Formerly agent.WithAttachPricingProvider.

func WithPricingSetter

func WithPricingSetter(fn func(req attach.PricingSetRequest) error) Option

WithPricingSetter wires a func that runs on POST /sessions/<sid>/pricing/set — writes a manual per-model rate and rebuilds the catalog. Formerly agent.WithAttachPricingSetter.

func WithPromptBroker

func WithPromptBroker(b *attach.PromptBroker) Option

WithPromptBroker wires the broker that bridges the agent's permissions.Gate prompts to remote operators over GET /sessions/<sid>/perms/stream and POST /perms/respond. The caller is also responsible for wiring this broker into the gate (typically via Gate.SetPrompter(broker)) so prompts the gate generates actually flow through it. Without this option the /perms/stream + /perms/respond routes return 501. Formerly agent.WithAttachPromptBroker.

func WithRefreshPricer

func WithRefreshPricer(fn func(ctx context.Context) (attach.PricingRefreshResponse, error)) Option

WithRefreshPricer wires a func that runs on POST /sessions/<sid>/pricing/refresh — typically calls into `internal/pricing.Refresh` and rebuilds the catalog. Returns the outcome the operator sees. Formerly agent.WithAttachRefreshPricer.

func WithReloader

func WithReloader(fn func(ctx context.Context) attach.ReloadResponse) Option

WithReloader wires a func that runs on POST /sessions/<sid>/reload. The closure is expected to re-walk project deps (instruction sources, skills bundles, MCP config) and return per-surface success in the response so the operator sees which parts succeeded and which failed. The adapter doesn't inspect the response shape; what "reload" means is the host's concern. Without this option the operator sees 501 / capability not registered. Formerly agent.WithAttachReloader.

func WithReplanner

func WithReplanner(fn func(ctx context.Context, req attach.ReplanRequest) (attach.ReplanResponse, error)) Option

WithReplanner wires a func that runs on POST /sessions/<sid>/slash/replan and on the in-process TUI's /replan slash dispatch. The closure is expected to clear the gate's planRecorded flag and archive the latest plan artifact (typically `tools.RevokeLatestPlan(gate, agentsDir)`). Without this option the slash returns 501 / "capability not registered".

Wire only when plan-first gating is active (config permissions.require_plan_artifact: true). Wiring it under other configs is a no-op but harmless. Formerly agent.WithAttachReplanner.

func WithSkillsProvider

func WithSkillsProvider(fn func() []attach.SkillInfo) Option

WithSkillsProvider wires a snapshot func for /sessions/<sid>/skills (backs /skills). Formerly agent.WithAttachSkillsProvider.

Jump to

Keyboard shortcuts

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