Documentation
¶
Overview ¶
Package acp implements the Agent Communication Protocol — a small HTTP/SSE API that lets other agents (claude code, opencode, custom agents) send messages to a running overkill and receive streaming replies. Inverse of MCP.
Index ¶
- Constants
- Variables
- func GenerateToken() string
- func ReadPeerCredential(path string) (string, error)
- type AgentEvent
- type AgentEventType
- type Client
- func (c *Client) AwaitTask(ctx context.Context, id string, wait time.Duration) (Task, error)
- func (c *Client) Cancel(ctx context.Context, messageID string) error
- func (c *Client) CancelTask(ctx context.Context, id string) (Task, error)
- func (c *Client) Coordination(ctx context.Context, operation string, in CoordinationRequest) (CoordinationResponse, error)
- func (c *Client) GetInfo(ctx context.Context) (Info, error)
- func (c *Client) ListSessions(ctx context.Context) ([]json.RawMessage, error)
- func (c *Client) Ping(ctx context.Context) error
- func (c *Client) Send(ctx context.Context, content string) (<-chan Event, error)
- func (c *Client) SendTo(ctx context.Context, sessionID, content string) (<-chan Event, error)
- func (c *Client) Stream(ctx context.Context, messageID string) (<-chan Event, error)
- func (c *Client) SubmitTask(ctx context.Context, input TaskSubmitRequest) (Task, error)
- func (c *Client) TaskStatus(ctx context.Context, id string) (Task, error)
- type Config
- type CoordinationRequest
- type CoordinationResponse
- type Event
- type InboundLog
- type Info
- type RoutePattern
- type SendRequest
- type SendResponse
- type Sender
- type Server
- func (s *Server) Addr() string
- func (s *Server) Handler() http.Handler
- func (s *Server) RecentInbound() []InboundLog
- func (s *Server) Routes() []RoutePattern
- func (s *Server) Shutdown(ctx context.Context) error
- func (s *Server) Start() error
- func (s *Server) StartTasks(ctx context.Context) error
- func (s *Server) Token() string
- type Task
- type TaskStore
- func (s *TaskStore) Await(ctx context.Context, id string, wait time.Duration) (Task, error)
- func (s *TaskStore) Cancel(ctx context.Context, id string) (Task, error)
- func (s *TaskStore) Get(ctx context.Context, id string) (Task, error)
- func (s *TaskStore) Migrate(ctx context.Context) error
- func (s *TaskStore) Submit(ctx context.Context, req TaskSubmitRequest) (Task, error)
- type TaskSubmitRequest
Constants ¶
const ( TaskMaxContentBytes = 64 * 1024 TaskMaxReplyBytes = 256 * 1024 TaskMaxErrorBytes = 4096 TaskMaxProgressBytes = 4096 TaskMaxActive = 256 TaskConcurrency = 4 TaskRunTimeout = 15 * time.Minute TaskMaxAwait = 25 * time.Second )
const DefaultRequestTimeout = 30 * time.Second
DefaultRequestTimeout bounds non-streaming requests, including body reads, when the caller has not supplied a deadline. SSE follows the caller context.
Variables ¶
Functions ¶
func ReadPeerCredential ¶
ReadPeerCredential reads a trusted local private reference. All errors remain generic: credential bytes/path contents never enter model-visible errors.
Types ¶
type AgentEvent ¶
type AgentEvent struct {
Type AgentEventType
Content string
ToolName string
ToolArgs string
Error error
}
AgentEvent is the wire-friendly StreamEvent the Sender hands to the server.
type AgentEventType ¶
type AgentEventType int
AgentEventType enumerates the event categories the ACP server cares about. Defining a local enum keeps acp from importing internal/agent (which would create an import cycle: tools → acp → agent → tools).
const ( AgentEventToken AgentEventType = iota AgentEventToolStart AgentEventToolOutput AgentEventDone AgentEventError )
type Client ¶
Client speaks HTTP/SSE to a remote ACP agent. An injected HTTP client is reused unchanged, including its transport, connection pool and policies.
func (*Client) AwaitTask ¶
AwaitTask bounds only this observation; timeout/disconnect never cancels work.
func (*Client) CancelTask ¶
func (*Client) Coordination ¶
func (c *Client) Coordination(ctx context.Context, operation string, in CoordinationRequest) (CoordinationResponse, error)
Coordination uses a scoped peer credential, distinct from a global ACP token. Endpoint is explicit application configuration, never model input/discovery. Redirects are refused, including same-host redirects, before credential reuse.
func (*Client) ListSessions ¶
func (*Client) Send ¶
Send preserves the default-session API. Cancel ctx if you stop reading events.
func (*Client) SendTo ¶
SendTo addresses an existing remote session, or creates one when sessionID is empty. The POST is bounded independently of the subsequent agent stream.
func (*Client) Stream ¶
Stream delivers SSE frames until one done/error event. A malformed or dropped connection produces one terminal error instead of appearing successful. Callers MUST cancel ctx when abandoning the receiver. Cancellation releases blocked sends and closes the HTTP body. If the buffer is full during failure, its oldest pending nonterminal event is displaced to retain the terminal error.
func (*Client) SubmitTask ¶
SubmitTask persists a request and returns its handle without waiting for the agent. The caller must retain/reuse the idempotency key across uncertain POSTs.
type Config ¶
type Config struct {
Coordination *coordination.Store
Tasks *TaskStore
Addr string
Token string
AllowedOrigins []string
Agent Sender
// ResolveSender selects the actual executing session. It may create a new
// persisted session when the ID is empty; its returned identity is checked.
ResolveSender func(context.Context, string) (Sender, error)
Store session.Store
Name string
Version string
// JobStore and JobWorker are optional. When both are non-nil the server
// registers the /v1/jobs endpoints and wires job submission through the worker.
JobStore *daemon.JobStore
JobWorker *daemon.Worker
}
Config is the constructor input.
type CoordinationRequest ¶
type CoordinationRequest struct {
Execution *coordination.TransportExecution `json:"execution,omitempty"`
Send *coordination.SendInput `json:"send,omitempty"`
MessageID string `json:"message_id,omitempty"`
Payload json.RawMessage `json:"payload,omitempty"`
IdempotencyKey string `json:"idempotency_key,omitempty"`
ExpectedRevision int64 `json:"expected_revision,omitempty"`
Event string `json:"event,omitempty"`
AfterRevision int64 `json:"after_revision,omitempty"`
Limit int `json:"limit,omitempty"`
WaitMilliseconds int `json:"wait_milliseconds,omitempty"`
}
CoordinationRequest deliberately has no sender, project or credential fields. The authenticated peer token alone supplies the actor for every operation.
type CoordinationResponse ¶
type CoordinationResponse struct {
NextRevision int64 `json:"next_revision,omitempty"`
HasMore bool `json:"has_more,omitempty"`
Self *coordination.Peer `json:"self,omitempty"`
Message *coordination.Message `json:"message,omitempty"`
Messages []coordination.Message `json:"messages,omitempty"`
Peers []coordination.Peer `json:"peers,omitempty"`
Events []coordination.Event `json:"events,omitempty"`
TimedOut bool `json:"timed_out,omitempty"`
}
type Event ¶
type Event struct {
Type string `json:"type"` // text_delta | tool_call | done | error
Content string `json:"content,omitempty"`
ToolName string `json:"tool_name,omitempty"`
ToolArgs string `json:"tool_args,omitempty"`
Error string `json:"error,omitempty"`
Timestamp time.Time `json:"timestamp"`
Extra map[string]any `json:"extra,omitempty"`
}
Event is a single SSE frame on /v1/messages/{id}/events.
type InboundLog ¶
type InboundLog struct {
From string `json:"from"`
MessageID string `json:"messageID"`
Snippet string `json:"snippet"`
At time.Time `json:"at"`
}
InboundLog records that a peer sent us a message; the /acp dialog displays the last few entries.
type Info ¶
type Info struct {
Name string `json:"name"`
Version string `json:"version"`
Model string `json:"model"`
Capabilities []string `json:"capabilities"`
}
Info is the response body of GET /v1/info.
type RoutePattern ¶
type RoutePattern struct {
Path string // e.g. "/v1/info", "/v1/messages/{id}/events"
Methods []string // expected methods; empty = test all standard methods
}
RoutePattern is one registered route with its HTTP method expectation.
type SendRequest ¶
type SendRequest struct {
From string `json:"from"`
Content string `json:"content"`
SessionID string `json:"sessionID,omitempty"`
Options map[string]any `json:"options,omitempty"`
}
SendRequest is the body of POST /v1/messages.
type SendResponse ¶
type SendResponse struct {
MessageID string `json:"messageID"`
SessionID string `json:"sessionID"`
}
SendResponse is returned from POST /v1/messages.
type Sender ¶
type Sender interface {
StreamACP(ctx context.Context, userInput string) (<-chan AgentEvent, error)
Model() string
SessionID() string
}
Sender is the slice of agent.Agent that the ACP server actually needs. Defining it locally keeps the package free of circular imports.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server exposes the ACP HTTP+SSE surface.
func (*Server) Handler ¶
Handler returns the http.Handler so callers can mount it under their own mux (and so tests can drive it without a TCP listener). Also populates s.routes so the auth guard test can auto-discover all routes. Safe for concurrent use.
func (*Server) RecentInbound ¶
func (s *Server) RecentInbound() []InboundLog
RecentInbound is a snapshot of the inbound ring buffer.
func (*Server) Routes ¶
func (s *Server) Routes() []RoutePattern
Routes returns every registered route pattern. The auth guard test (§8.7.5) uses this to auto-discover all routes and assert 401 on each, so a new route added without auth fails the test automatically.
func (*Server) Start ¶
Start binds the server and runs http.Serve in a goroutine. Use Shutdown to stop it.
func (*Server) StartTasks ¶
StartTasks starts this server's bounded durable task workers. Mounted Handler users call it explicitly; Handler itself never starts background work.
type Task ¶
type Task struct {
WorkerError string `json:"workerError,omitempty"`
TaskID string `json:"taskID"`
MessageID string `json:"messageID"`
SessionID string `json:"sessionID"`
Status string `json:"status"`
Reply string `json:"reply,omitempty"`
Error string `json:"error,omitempty"`
Progress string `json:"progress,omitempty"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}