Documentation
¶
Overview ¶
Package acpagent provides a Google ADK agent implementation backed by an Agent Client Protocol (ACP) coding agent.
The package starts an ACP-compatible coding-agent subprocess, talks to it as an ACP client over stdio, and maps each ADK session to a remote ACP session. By default, ACP session creation uses Config.WorkingDir as the ACP session cwd.
Per-session overrides via ADK state ¶
Callers can override ACP session creation per ADK session by setting CWDStateKey before the first invocation in that ADK session:
map[string]any{
CWDStateKey: "/absolute/path", // optional
}
ACP-specific session/new metadata may be provided under SessionStateKey:
map[string]any{
acpagent.SessionStateKey: map[string]any{
"meta": map[string]any{ // optional; forwarded to ACP session/new _meta
"codex": map[string]any{"approvalMode": "manual"},
},
},
}
Behavior:
- If `state[CWDStateKey]` is set, it overrides Config.WorkingDir for ACP session creation.
- The adapter persists the canonical ACP session ID under `state[SessionStateKey].session_id` and uses that value for ACP session/resume when the ACP agent advertises resume capability. ACP session configuration values are persisted under `state[SessionStateKey].config_values`.
- As soon as the adapter binds a remote ACP session, it stores the canonical ACP session ID in the live ADK session state under `state[SessionStateKey]`.
- If `state[SessionStateKey].session_id` is absent, the package creates a new ACP session.
- For newly created ACP sessions, resolved startup instructions are passed through two channels: `session/new._meta.codex` receives `baseInstructions` and `developerInstructions` when those keys are not already set, and the first real user `session/prompt` is prepended with the combined instructions. The adapter does not send a separate instruction-only prompt.
- The adapter does not use ACP `session/load`; ACP v1 load replays prior history, and this adapter does not yet map that replay into ADK-visible history.
- If `state[SessionStateKey].meta` is set, it is passed through to ACP session/new._meta and session/resume._meta.
- If `state[SessionStateKey].config_values` is set, it overrides matching Config.SessionConfig defaults for that ADK session.
- Overrides are read when the ACP session is first created for the ADK session. Subsequent changes do not rebind that existing ACP session.
Invalid override values (for example, non-string `state[CWDStateKey]`, non-object `state[SessionStateKey]`, non-object `state[SessionStateKey].meta`, non-string `state[SessionStateKey].session_id`, invalid `state[SessionStateKey].config_values`, or a cwd that is not a valid existing directory) cause invocation failure before ACP session creation.
ACP plan updates ¶
ACP `session/update.plan` notifications are projected into ADK event state under PlanStateKey. Each event carries the full replacement snapshot at `event.Actions.StateDelta[PlanStateKey]` with an `entries` field containing the current ACP plan entries. Plan updates do not appear as content parts.
Index ¶
- Constants
- Variables
- type Agent
- type Client
- func (c *Client) Authenticate(ctx context.Context, methodID string) error
- func (c *Client) Close() error
- func (c *Client) CreateSession(ctx context.Context, cwd string, configValues []SessionConfigValue, ...) (acp.NewSessionResponse, error)
- func (c *Client) CreateSessionWithMeta(ctx context.Context, cwd string, configValues []SessionConfigValue, ...) (acp.NewSessionResponse, error)
- func (c *Client) CreateTerminal(_ context.Context, _ acp.CreateTerminalRequest) (acp.CreateTerminalResponse, error)
- func (c *Client) Initialize(ctx context.Context) (acp.InitializeResponse, error)
- func (c *Client) KillTerminal(_ context.Context, _ acp.KillTerminalRequest) (acp.KillTerminalResponse, error)
- func (c *Client) LoadSession(ctx context.Context, sessionID, cwd string, mcpServers []acp.McpServer) (acp.LoadSessionResponse, error)
- func (c *Client) LoadSessionWithMeta(ctx context.Context, sessionID, cwd string, mcpServers []acp.McpServer, ...) (acp.LoadSessionResponse, error)
- func (c *Client) NewSession(ctx context.Context, cwd string, mcpServers []acp.McpServer) (acp.NewSessionResponse, error)
- func (c *Client) NewSessionWithMeta(ctx context.Context, cwd string, mcpServers []acp.McpServer, ...) (acp.NewSessionResponse, error)
- func (c *Client) Prompt(ctx context.Context, sessionID, prompt string) (<-chan ExtendedSessionNotification, <-chan PromptResult, error)
- func (c *Client) PromptWithContent(ctx context.Context, sessionID string, prompt []acp.ContentBlock) (<-chan ExtendedSessionNotification, <-chan PromptResult, error)
- func (c *Client) ReadTextFile(_ context.Context, _ acp.ReadTextFileRequest) (acp.ReadTextFileResponse, error)
- func (c *Client) ReleaseTerminal(_ context.Context, _ acp.ReleaseTerminalRequest) (acp.ReleaseTerminalResponse, error)
- func (c *Client) RequestPermission(ctx context.Context, params acp.RequestPermissionRequest) (acp.RequestPermissionResponse, error)
- func (c *Client) ResumeSession(ctx context.Context, sessionID, cwd string, mcpServers []acp.McpServer) (acp.ResumeSessionResponse, error)
- func (c *Client) ResumeSessionWithMeta(ctx context.Context, sessionID, cwd string, mcpServers []acp.McpServer, ...) (acp.ResumeSessionResponse, error)
- func (c *Client) SessionUpdate(ctx context.Context, params acp.SessionNotification) error
- func (c *Client) SetSessionConfigOption(ctx context.Context, req acp.SetSessionConfigOptionRequest) (acp.SetSessionConfigOptionResponse, error)
- func (c *Client) SetSessionMode(ctx context.Context, sessionID, mode string) error
- func (c *Client) SupportsSessionLoad() bool
- func (c *Client) SupportsSessionResume() bool
- func (c *Client) TerminalOutput(_ context.Context, _ acp.TerminalOutputRequest) (acp.TerminalOutputResponse, error)
- func (c *Client) WaitForTerminalExit(_ context.Context, _ acp.WaitForTerminalExitRequest) (acp.WaitForTerminalExitResponse, error)
- func (c *Client) WriteTextFile(_ context.Context, _ acp.WriteTextFileRequest) (acp.WriteTextFileResponse, error)
- type ClientConfig
- type Config
- type ExtendedSessionNotification
- type InstructionProvider
- type MCPServerConfig
- type MCPServerType
- type PermissionHandler
- type PromptResult
- type SessionConfigValue
Examples ¶
Constants ¶
const ( // SessionStateKey is the reserved ADK session-state key for ACP-specific // per-session settings. // // The value at this key must be an object with optional fields: // - "meta" (object): forwarded to ACP session/new._meta // - "session_id" (string): canonical ACP session id returned by the ACP // agent and used for ACP session/resume // // This state is the source of truth for ACP session identity. If the ADK // session is deleted, this state is deleted with it and no in-memory ACP // session binding is reused. SessionStateKey = "acp_session" // PlanStateKey is the ADK session-state key used for ACP plan snapshots. // // Each ACP session/update.plan notification is projected into // event.Actions.StateDelta[PlanStateKey] as the authoritative full plan // replacement snapshot. PlanStateKey = "acp_plan" // CWDStateKey is the ADK session-state key used to override the ACP // session working directory for a single ADK session. CWDStateKey = "cwd" )
Variables ¶
var ( // ErrPromptAlreadyActive is returned when a prompt is already in progress for // the same ACP session ID. ErrPromptAlreadyActive = errors.New("acp prompt already active") )
Functions ¶
This section is empty.
Types ¶
type Agent ¶
Agent is an ADK agent implementation backed by an Agent Client Protocol (ACP) coding-agent subprocess. It manages the subprocess lifecycle and maps ACP sessions to ADK sessions.
func New ¶
New creates an ADK agent backed by an ACP client process.
It starts the ACP process, performs ACP initialization, and creates ACP sessions lazily per ADK session.
Per ADK session, callers may provide state overrides:
- CWDStateKey (string): override ACP session/new cwd
- SessionStateKey.meta (object): forwarded to ACP session/new._meta and session/resume._meta
ACP session IDs are agent-owned. The adapter persists the canonical ACP session id under SessionStateKey.session_id and uses that value for session/resume when the ACP agent advertises resume capability.
ACP session/load is not used by this adapter. Per ACP v1, load replays prior history; until that replay is intentionally mapped into ADK-visible history, the adapter restores only through session/resume or creates a new ACP session.
If no override is provided, Config.WorkingDir is used as ACP session cwd. The first ACP session created for an ADK session is reused for subsequent invocations in that same ADK session. For newly created ACP sessions, resolved instructions are sent in session/new._meta.codex and prepended to the first real user prompt. The adapter does not send a separate instruction-only prompt.
The caller is responsible for calling Close() to shut down the subprocess.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client manages a single Agent Client Protocol (ACP) subprocess and its communication over standard input/output. It implements the acp.Client interface to handle protocol-level callbacks and manages multiple concurrent prompt sessions.
func NewClient ¶
func NewClient(ctx context.Context, cfg ClientConfig) (*Client, error)
NewClient starts an ACP subprocess and returns a protocol client over stdio.
Example ¶
previous := os.Getenv("GO_WANT_ACP_HELPER")
_ = os.Setenv("GO_WANT_ACP_HELPER", "1")
defer func() {
if previous == "" {
_ = os.Unsetenv("GO_WANT_ACP_HELPER")
return
}
_ = os.Setenv("GO_WANT_ACP_HELPER", previous)
}()
workingDir, err := os.MkdirTemp("", "runtime-acpagent-example-*")
if err != nil {
fmt.Println(err)
return
}
defer func() { _ = os.RemoveAll(workingDir) }()
client, err := NewClient(context.Background(), ClientConfig{
Command: []string{os.Args[0], "-test.run=TestACPHelperProcess", "--"},
})
if err != nil {
fmt.Println(err)
return
}
defer func() { _ = client.Close() }()
if _, err := client.Initialize(context.Background()); err != nil {
fmt.Println(err)
return
}
sessionResp, err := client.NewSession(context.Background(), workingDir, nil)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(sessionResp.SessionId) != "")
Output: true
func (*Client) Authenticate ¶
Authenticate requests ACP authentication for a specific method.
func (*Client) CreateSession ¶
func (c *Client) CreateSession(ctx context.Context, cwd string, configValues []SessionConfigValue, mcpServers []acp.McpServer) (acp.NewSessionResponse, error)
CreateSession creates a new ACP session and applies configured session config values when requested.
func (*Client) CreateSessionWithMeta ¶
func (c *Client) CreateSessionWithMeta( ctx context.Context, cwd string, configValues []SessionConfigValue, mcpServers []acp.McpServer, meta map[string]any, ) (acp.NewSessionResponse, error)
CreateSessionWithMeta creates a new ACP session with optional session/new _meta and applies configured session config values when requested.
This helper is equivalent to:
- NewSessionWithMeta(ctx, cwd, mcpServers, meta)
- optionally SetSessionConfigOption(...) for ACP session config values
The ACP protocol requires cwd to be an absolute path.
func (*Client) CreateTerminal ¶
func (c *Client) CreateTerminal(_ context.Context, _ acp.CreateTerminalRequest) (acp.CreateTerminalResponse, error)
CreateTerminal reports unsupported terminal creation for this ACP client.
func (*Client) Initialize ¶
Initialize performs ACP protocol initialization and validates protocol compatibility.
func (*Client) KillTerminal ¶
func (c *Client) KillTerminal(_ context.Context, _ acp.KillTerminalRequest) (acp.KillTerminalResponse, error)
KillTerminal reports unsupported terminal command control for this ACP client.
func (*Client) LoadSession ¶
func (c *Client) LoadSession(ctx context.Context, sessionID, cwd string, mcpServers []acp.McpServer) (acp.LoadSessionResponse, error)
LoadSession loads an existing ACP session in the provided working directory.
The ACP protocol requires cwd to be an absolute path.
func (*Client) LoadSessionWithMeta ¶
func (c *Client) LoadSessionWithMeta( ctx context.Context, sessionID, cwd string, mcpServers []acp.McpServer, meta map[string]any, ) (acp.LoadSessionResponse, error)
LoadSessionWithMeta loads an existing ACP session in the provided working directory and sends optional _meta extensions with the load request.
The ACP protocol requires cwd to be an absolute path.
func (*Client) NewSession ¶
func (c *Client) NewSession(ctx context.Context, cwd string, mcpServers []acp.McpServer) (acp.NewSessionResponse, error)
NewSession creates a new ACP session in the provided working directory.
The ACP protocol requires cwd to be an absolute path.
func (*Client) NewSessionWithMeta ¶
func (c *Client) NewSessionWithMeta( ctx context.Context, cwd string, mcpServers []acp.McpServer, meta map[string]any, ) (acp.NewSessionResponse, error)
NewSessionWithMeta creates a new ACP session in the provided working directory and sends optional _meta extensions with the session request.
The ACP protocol requires cwd to be an absolute path.
func (*Client) Prompt ¶
func (c *Client) Prompt(ctx context.Context, sessionID, prompt string) (<-chan ExtendedSessionNotification, <-chan PromptResult, error)
Prompt sends a prompt to an ACP session and streams session updates.
func (*Client) PromptWithContent ¶
func (c *Client) PromptWithContent(ctx context.Context, sessionID string, prompt []acp.ContentBlock) (<-chan ExtendedSessionNotification, <-chan PromptResult, error)
PromptWithContent sends a prompt composed of ACP content blocks and streams session updates.
func (*Client) ReadTextFile ¶
func (c *Client) ReadTextFile(_ context.Context, _ acp.ReadTextFileRequest) (acp.ReadTextFileResponse, error)
ReadTextFile reports unsupported file read for this ACP client.
func (*Client) ReleaseTerminal ¶
func (c *Client) ReleaseTerminal(_ context.Context, _ acp.ReleaseTerminalRequest) (acp.ReleaseTerminalResponse, error)
ReleaseTerminal reports unsupported terminal release for this ACP client.
func (*Client) RequestPermission ¶
func (c *Client) RequestPermission(ctx context.Context, params acp.RequestPermissionRequest) (acp.RequestPermissionResponse, error)
RequestPermission handles ACP permission callbacks.
func (*Client) ResumeSession ¶
func (c *Client) ResumeSession(ctx context.Context, sessionID, cwd string, mcpServers []acp.McpServer) (acp.ResumeSessionResponse, error)
ResumeSession resumes an existing ACP session in the provided working directory.
The ACP protocol requires cwd to be an absolute path.
func (*Client) ResumeSessionWithMeta ¶
func (c *Client) ResumeSessionWithMeta( ctx context.Context, sessionID, cwd string, mcpServers []acp.McpServer, meta map[string]any, ) (acp.ResumeSessionResponse, error)
ResumeSessionWithMeta resumes an existing ACP session in the provided working directory and sends optional _meta extensions with the resume request.
The ACP protocol requires cwd to be an absolute path.
func (*Client) SessionUpdate ¶
SessionUpdate is part of the ACP client callback contract.
func (*Client) SetSessionConfigOption ¶ added in v0.1.4
func (c *Client) SetSessionConfigOption( ctx context.Context, req acp.SetSessionConfigOptionRequest, ) (acp.SetSessionConfigOptionResponse, error)
SetSessionConfigOption sets an ACP session configuration option.
func (*Client) SetSessionMode ¶
SetSessionMode selects the active mode for an ACP session.
func (*Client) SupportsSessionLoad ¶
SupportsSessionLoad reports whether the initialized ACP server advertises session/load support.
func (*Client) SupportsSessionResume ¶
SupportsSessionResume reports whether the initialized ACP server advertises session/resume support.
func (*Client) TerminalOutput ¶
func (c *Client) TerminalOutput(_ context.Context, _ acp.TerminalOutputRequest) (acp.TerminalOutputResponse, error)
TerminalOutput reports unsupported terminal output streaming for this ACP client.
func (*Client) WaitForTerminalExit ¶
func (c *Client) WaitForTerminalExit(_ context.Context, _ acp.WaitForTerminalExitRequest) (acp.WaitForTerminalExitResponse, error)
WaitForTerminalExit reports unsupported terminal wait operations for this ACP client.
func (*Client) WriteTextFile ¶
func (c *Client) WriteTextFile(_ context.Context, _ acp.WriteTextFileRequest) (acp.WriteTextFileResponse, error)
WriteTextFile reports unsupported file write for this ACP client.
type ClientConfig ¶
type ClientConfig struct {
// Command is the argv array used to start the ACP subprocess.
Command []string
// WorkingDir is the directory where the ACP subprocess is executed
// (cmd.Dir). It is independent from ACP session/new.cwd, which is provided
// per session creation call.
WorkingDir string
// ClientName is the name reported to the ACP server. Defaults to "runtime-acpagent".
ClientName string
// ClientVersion is the version reported to the ACP server. Defaults to "dev".
ClientVersion string
// Stderr is an optional writer for the ACP subprocess's standard error.
Stderr io.Writer
// PermissionHandler decides how to respond to ACP permission requests.
PermissionHandler PermissionHandler
// Logger is the slog logger to use for this client.
Logger *slog.Logger
}
ClientConfig configures an ACP subprocess client.
type Config ¶
type Config struct {
// Context is the base context for the agent's lifecycle.
Context context.Context
// Name is the display name of the agent. Defaults to "ACPAgent".
Name string
// Description describes the agent's purpose.
Description string
// BeforeAgentCallbacks are standard ADK lifecycle callbacks invoked before
// the ACP-backed run starts.
BeforeAgentCallbacks []adkagent.BeforeAgentCallback
// AfterAgentCallbacks are standard ADK lifecycle callbacks invoked after
// the ACP-backed run completes.
AfterAgentCallbacks []adkagent.AfterAgentCallback
// SessionConfig contains ACP session configuration values applied after
// session/new or session/resume.
SessionConfig []SessionConfigValue
// Instruction is the optional instruction applied to each invocation.
Instruction string
// GlobalInstruction is the optional global instruction applied before
// Instruction.
GlobalInstruction string
// ReasoningEffort selects the provider reasoning effort when supported.
ReasoningEffort string
// InstructionProvider dynamically provides [Config.Instruction] content.
// When set, this takes precedence over [Config.Instruction].
InstructionProvider InstructionProvider
// GlobalInstructionProvider dynamically provides
// [Config.GlobalInstruction] content. When set, this takes precedence over
// [Config.GlobalInstruction].
GlobalInstructionProvider InstructionProvider
// SystemInstructions is deprecated and kept for backward compatibility.
// Use Instruction instead.
SystemInstructions string
// ClientName is the name reported to the ACP server during initialization.
ClientName string
// ClientVersion is the version reported to the ACP server during initialization.
ClientVersion string
// Command is the argv array used to start the ACP subprocess.
Command []string
// WorkingDir is the default directory for ACP execution:
// - the ACP subprocess is started with this directory as cmd.Dir.
// - ACP session/new uses this as cwd unless overridden per ADK session
// via session state key [CWDStateKey].
//
// When session state override is present, the override takes precedence for
// ACP session cwd selection.
WorkingDir string
// Stderr is an optional writer for the ACP subprocess's standard error.
Stderr io.Writer
// PermissionHandler decides how to respond to ACP permission requests.
PermissionHandler PermissionHandler
// Logger is the slog logger to use for this agent.
Logger *slog.Logger
// MCPServers is the map of MCP server configurations.
MCPServers map[string]MCPServerConfig
// SessionService is ignored. ACP session bindings are recorded through the
// ADK session state exposed by the invocation context.
SessionService session.Service
// OutputKey stores the final visible model output in session state delta for this invocation.
// When set, the final non-partial turn-complete event includes
// event.Actions.StateDelta[OutputKey] = final visible output text.
OutputKey string
}
Config configures an ACP-backed ADK agent.
type ExtendedSessionNotification ¶
type ExtendedSessionNotification struct {
acp.SessionNotification
Raw json.RawMessage
Method string
}
ExtendedSessionNotification wraps an ACP notification with its raw JSON representation to allow access to fields not yet supported by the SDK.
type InstructionProvider ¶
type InstructionProvider func(ctx adkagent.ReadonlyContext) (string, error)
InstructionProvider allows ACP instructions to be created dynamically using invocation context, mirroring llmagent semantics.
type MCPServerConfig ¶
type MCPServerConfig struct {
// Type selects the MCP transport implementation.
Type MCPServerType
// Cmd is the stdio server executable path or argv prefix.
Cmd []string
// Args appends additional stdio server arguments after Cmd.
Args []string
// Env defines environment variables for stdio server execution.
Env map[string]string
// WorkingDir sets the stdio server process working directory.
WorkingDir string
// URL is the base endpoint for HTTP and SSE MCP transports.
URL string
// Headers provides additional request headers for HTTP and SSE transports.
Headers map[string]string
}
MCPServerConfig describes how to connect to an MCP server.
type MCPServerType ¶
type MCPServerType string
MCPServerType represents the transport type for an MCP server.
const ( // MCPServerTypeStdio is the stdio transport type. MCPServerTypeStdio MCPServerType = "stdio" // MCPServerTypeHTTP is the HTTP transport type. MCPServerTypeHTTP MCPServerType = "http" // MCPServerTypeSSE is the SSE (Server-Sent Events) transport type. MCPServerTypeSSE MCPServerType = "sse" )
type PermissionHandler ¶
type PermissionHandler func(context.Context, acp.RequestPermissionRequest) (acp.RequestPermissionResponse, error)
PermissionHandler decides how ACP permission requests should be handled. It returns a response with the selected outcome or an error if the request could not be processed.
type PromptResult ¶
type PromptResult struct {
Response acp.PromptResponse
Usage *acp.Usage
Raw json.RawMessage
Err error
}
PromptResult contains the terminal Prompt RPC response, usage metadata, or an error.
type SessionConfigValue ¶ added in v0.1.4
type SessionConfigValue struct {
// ID is the ACP session config option ID.
ID string `json:"id"`
// Value is the ACP session config value ID.
Value string `json:"value"`
}
SessionConfigValue is an ACP session configuration value to apply to each bound ACP session.