a2adelegation

package
v1.1.2 Latest Latest
Warning

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

Go to latest
Published: Aug 7, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package a2adelegation provides host-owned Local and Remote delegation for an adaptor Agent.

A Service owns a curated target registry, an authenticated per-run MCP sidecar, ordered DelegationEvent publication, and final result recording. Service.Option or adaptor.WithRunServices attaches that lifecycle to a leader's ordinary Run/Stream pipeline, where delegation progress appears as adaptor.SubagentUpdate on the existing Event channel.

Local targets consume adaptor.Runner directly. Remote targets use clients/a2a. Both are normalized through the same A2A event mapper. The adapter.stream.v1 spelling used by the mapper is an intentional versioned wire schema, not a temporary Go API name.

This package stays above core: it never dispatches a Driver directly, never introduces a second execution stream, and leaves network exposure, auth, tenant policy, durable storage, and target selection to the host.

Index

Constants

View Source
const (
	// ServiceKey is the runtime-service ID/name and MCP server key under
	// which the per-run delegation sidecar is published to the driver. A
	// host WithMCP declaration using the same key collides on purpose:
	// two different servers cannot share one key, and the run fails before
	// launch rather than silently picking one.
	ServiceKey = "delegate-a2a"

	// BearerTokenEnvVar names the environment variable through which the
	// sidecar's per-run bearer token reaches the driver process. The token
	// travels as ServiceRef.SecretEnv, which the SDK injects into driver
	// env only — it never enters runtime service reports, request metadata,
	// or the serialized runtime-services payload.
	BearerTokenEnvVar = "AGENT_ADAPTOR_DELEGATION_TOKEN"
)
View Source
const DelegateToolName = "delegate_to_agent"

DelegateToolName is the default MCP tool exposed by each Service sidecar.

View Source
const ProtocolA2A = "a2a"

ProtocolA2A identifies the A2A transport used by remote and local-loopback delegation results and events.

Variables

This section is empty.

Functions

func SubagentEvent

func SubagentEvent(ev DelegationEvent) adaptor.SubagentUpdate

SubagentEvent projects one DelegationEvent onto the adaptor Event vocabulary. DelegationEventKinds collapse onto the three SubagentUpdate kinds (started, delta, and finished). Data preserves the stable kind, status, remote coordinates, tool payloads, errors, artifacts, and sequence. Raw A2A payloads and StatusParts intentionally remain on the component-level EventBus and do not enter the leader's core Event stream.

func ToolSchema

func ToolSchema() map[string]any

ToolSchema returns a fresh JSON Schema for the default delegate_to_agent tool input. The schema accepts registry keys, never endpoint URLs.

Types

type A2AClient

type A2AClient interface {
	AgentCard(ctx context.Context) (clienta2a.AgentCard, error)
	Send(ctx context.Context, req clienta2a.SendRequest) (clienta2a.Task, error)
	SendStream(ctx context.Context, req clienta2a.SendRequest) (A2AStream, error)
	GetTask(ctx context.Context, req clienta2a.GetTaskRequest) (clienta2a.Task, error)
	CancelTask(ctx context.Context, req clienta2a.CancelTaskRequest) (clienta2a.Task, error)
}

A2AClient is the protocol-shaped client contract used by Delegator. The bundled clients/a2a adapter and Local in-process targets both implement it.

type A2AStream

type A2AStream interface {
	// Recv blocks until the next event. Close must unblock any in-flight Recv.
	Recv() (clienta2a.Event, error)
	Close() error
}

A2AStream is the minimal ordered event stream required by Delegator. Close must unblock an in-flight Recv. Implementations may additionally provide RecvContext(context.Context) for native cancellation.

type AfterDelegation

type AfterDelegation struct {
	DelegationID string
	AgentSpec    RemoteAgentSpec
	Request      DelegationRequest
	Result       DelegationResult
	Err          error
}

AfterDelegation is the defensive hook payload supplied after execution.

type AgentRef

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

AgentRef is one delegatable role in a Service configuration: either a local in-process Runner (Local) or a remote A2A agent (Remote / RemoteAgent). Local and remote refs mix freely in one Config.Agents table and are indistinguishable to the leader: both are reached through the same delegate_to_agent tool, the same Delegator pipeline, and the same DelegationEvent stream.

func Local

func Local(key string, runner Runner, policy Policy) AgentRef

Local registers an in-process Runner as a delegatable target. Its Event stream is projected through the intentional adapter.stream.v1 wire schema, preserving text, reasoning, tool, approval, and drop semantics without a network hop.

func LocalNamed

func LocalNamed(key, displayName string, runner Runner, policy Policy) AgentRef

LocalNamed registers an in-process Runner with a separate model-facing key and human-facing display name. The display name is carried by delegation events and is useful for UIs that need to distinguish a workflow role from its underlying provider, for example key "plan" and name "Claude Code Planner". A blank displayName falls back to key, matching Local.

func Remote

func Remote(key, cardURL string, policy Policy) AgentRef

Remote registers a remote A2A target by Agent Card URL. Discovery and task execution use clients/a2a.

func RemoteAgent

func RemoteAgent(spec RemoteAgentSpec) AgentRef

RemoteAgent registers a remote A2A agent from a full RemoteAgentSpec for hosts that need auth, tenant, transport, or accepted-output-mode control beyond what Remote(key, cardURL, policy) covers.

type BeforeDelegation

type BeforeDelegation struct {
	DelegationID string
	AgentSpec    RemoteAgentSpec
	Request      DelegationRequest
}

BeforeDelegation is the defensive hook payload supplied before remote I/O.

type ClientFactory

type ClientFactory func(RemoteAgentSpec) A2AClient

ClientFactory constructs the client for one resolved RemoteAgentSpec.

type Config

type Config struct {
	// Agents is the delegation table: Local, Remote, and RemoteAgent refs
	// mix freely. At least one entry is required.
	Agents []AgentRef

	// ToolTimeout is the default per-delegation wall clock: it becomes
	// Policy.MaxTimeout for every agent whose own policy does not set one,
	// and is surfaced on Sidecar.ToolTimeout so hosts can align the
	// driver-side MCP tool timeout. Zero means no default ceiling.
	ToolTimeout time.Duration

	// Observe, when set, receives every DelegationEvent of every run that
	// goes through the Service (subscription starts at EnsureSidecar /
	// Delegate time). Callbacks run on a Service-owned goroutine, one run
	// at a time per run ID; Close waits for them to drain.
	Observe func(Event)

	// ReplayLimit overrides the EventBus replay depth (default 256).
	ReplayLimit int

	// Tenant is passed to the per-run MCP sidecar and forwarded on
	// delegations that do not carry their own tenant.
	Tenant string

	// Hook, when set, is chained after the Service's own result-recording
	// lifecycle hook (Before runs before delegation, After runs after the
	// result is recorded).
	Hook DelegationLifecycleHook

	// NewClient overrides A2A client construction for non-local specs
	// (test seam; Local refs always use the in-process loopback).
	NewClient ClientFactory

	// StatusDecoders registers additional host-owned status DataPart
	// schema decoders on the Delegator (adapter.stream.v1 is built in).
	StatusDecoders []StatusPartDecoder

	// NewID overrides delegation-ID minting (test seam).
	NewID func() string
}

Config configures NewService. Agents is required; all other fields have conservative local defaults.

type DelegationArtifact

type DelegationArtifact struct {
	ID          string         `json:"id,omitempty"`
	Name        string         `json:"name,omitempty"`
	Description string         `json:"description,omitempty"`
	URI         string         `json:"uri,omitempty"`
	MediaType   string         `json:"mime_type,omitempty"`
	Metadata    map[string]any `json:"metadata,omitempty"`
}

DelegationArtifact is the compact artifact projection returned to the leader and emitted in DelegationArtifactCreated events.

type DelegationError

type DelegationError struct {
	Code         string         `json:"code"`
	Message      string         `json:"message"`
	Retryable    bool           `json:"retryable,omitempty"`
	RemoteStatus string         `json:"remote_status,omitempty"`
	Metadata     map[string]any `json:"metadata,omitempty"`
}

DelegationError is a stable host-facing error with optional A2A status and retry metadata.

func (*DelegationError) Error

func (e *DelegationError) Error() string

Error implements error using Message, then Code, then a stable fallback.

type DelegationEvent

type DelegationEvent struct {
	RunID            string
	ParentToolCallID string
	DelegationID     string
	AgentKey         string
	AgentName        string
	Protocol         string

	RemoteTaskID     string
	RemoteContextID  string
	RemoteMessageID  string
	RemoteArtifactID string
	RemoteToolCallID string
	Sequence         uint64

	Kind     DelegationEventKind
	Name     string
	Role     string
	Delta    string
	Text     string
	ToolName string
	Args     any
	Result   any
	Artifact *DelegationArtifact
	Status   string
	// StatusParts preserves the remote A2A status message parts for hosts that
	// consume structured status data.
	StatusParts []RemotePart
	Error       *DelegationError
	Raw         map[string]any
	Time        time.Time
}

DelegationEvent is one typed, ordered observation from a delegated task. Identity and remote coordinates are separate from the semantic payload so a host can correlate leader tool calls, delegation attempts, and A2A objects.

type DelegationEventKind

type DelegationEventKind string

DelegationEventKind classifies one event in a delegated task lifecycle.

const (
	// DelegationStarted reports that the target accepted the delegated task.
	DelegationStarted DelegationEventKind = "subagent.started"
	// DelegationStatus carries an A2A task status update.
	DelegationStatus DelegationEventKind = "subagent.status"
	// DelegationTextStart starts one delegated assistant text item.
	DelegationTextStart DelegationEventKind = "subagent.text.start"
	// DelegationTextDelta carries incremental delegated assistant text.
	DelegationTextDelta DelegationEventKind = "subagent.text.delta"
	// DelegationTextEnd closes one delegated assistant text item.
	DelegationTextEnd DelegationEventKind = "subagent.text.end"
	// DelegationReasoningStart starts one delegated reasoning item.
	DelegationReasoningStart DelegationEventKind = "subagent.reasoning.start"
	// DelegationReasoningDelta carries incremental delegated reasoning.
	DelegationReasoningDelta DelegationEventKind = "subagent.reasoning.delta"
	// DelegationReasoningEnd closes one delegated reasoning item.
	DelegationReasoningEnd DelegationEventKind = "subagent.reasoning.end"
	// DelegationToolCallStart starts one delegated tool call.
	DelegationToolCallStart DelegationEventKind = "subagent.tool_call.start"
	// DelegationToolCallArgs carries delegated tool-call arguments.
	DelegationToolCallArgs DelegationEventKind = "subagent.tool_call.args"
	// DelegationToolCallResult carries a delegated tool result.
	DelegationToolCallResult DelegationEventKind = "subagent.tool_call.result"
	// DelegationToolCallEnd closes one delegated tool call.
	DelegationToolCallEnd DelegationEventKind = "subagent.tool_call.end"
	// DelegationArtifactCreated reports an artifact from the delegated task.
	DelegationArtifactCreated DelegationEventKind = "subagent.artifact"
	// DelegationCustom carries a host-decoded custom status event.
	DelegationCustom DelegationEventKind = "subagent.custom"
	// DelegationStreamDropped summarizes delegated events lost to a sequence
	// gap, unsupported schema, or local EventBus backpressure.
	DelegationStreamDropped DelegationEventKind = "subagent.stream.dropped"
	// DelegationInputRequired reports that the remote task needs more input.
	DelegationInputRequired DelegationEventKind = "subagent.input_required"
	// DelegationFinished reports successful delegated-task completion.
	DelegationFinished DelegationEventKind = "subagent.finished"
	// DelegationFailed reports delegated-task failure.
	DelegationFailed DelegationEventKind = "subagent.failed"
	// DelegationCancelled reports delegated-task cancellation.
	DelegationCancelled DelegationEventKind = "subagent.cancelled"
)

type DelegationLifecycleHook

type DelegationLifecycleHook interface {
	BeforeDelegate(ctx context.Context, req BeforeDelegation) error
	AfterDelegate(ctx context.Context, req AfterDelegation) error
}

DelegationLifecycleHook observes one resolved delegation before remote I/O and after its terminal result. Returning an error fails that delegation.

type DelegationLifecycleHookFuncs

type DelegationLifecycleHookFuncs struct {
	BeforeFunc func(context.Context, BeforeDelegation) error
	AfterFunc  func(context.Context, AfterDelegation) error
}

DelegationLifecycleHookFuncs adapts optional functions to DelegationLifecycleHook.

func (DelegationLifecycleHookFuncs) AfterDelegate

AfterDelegate invokes AfterFunc when configured.

func (DelegationLifecycleHookFuncs) BeforeDelegate

BeforeDelegate invokes BeforeFunc when configured.

type DelegationMessage

type DelegationMessage struct {
	Role string `json:"role,omitempty"`
	Text string `json:"text,omitempty"`
}

DelegationMessage is one normalized message retained in a result.

type DelegationPolicy

type DelegationPolicy struct {
	MaxTimeout         time.Duration
	AllowInputRequired bool
	RequireStreaming   bool
	PollInterval       time.Duration
	MaxPolls           int
	MaxArtifactBytes   int64
}

DelegationPolicy bounds remote execution and controls transport behavior. Zero timeout, polling, count, and artifact values select Delegator defaults.

type DelegationRequest

type DelegationRequest struct {
	RunID                  string
	ParentToolCallID       string
	ContextID              string
	Agent                  string
	Objective              string
	Prompt                 string
	Context                string
	Message                *clienta2a.Message
	Artifacts              []InputArtifact
	IncludeRemoteArtifacts bool
	MaxArtifacts           *int
	HistoryLength          *int
	Timeout                time.Duration
	Stream                 bool
	Tenant                 string
	Metadata               map[string]any
	StageContext           DelegationStageContext
}

DelegationRequest describes one host-authorized delegation. RunID attributes events to the leader run; Agent selects a Registry key. Message, when set, takes precedence over Prompt/Objective/Context and Artifacts.

type DelegationResult

type DelegationResult struct {
	DelegationID    string                 `json:"delegation_id"`
	Agent           string                 `json:"agent"`
	RemoteProtocol  string                 `json:"remote_protocol"`
	RemoteTaskID    string                 `json:"remote_task_id,omitempty"`
	RemoteContextID string                 `json:"remote_context_id,omitempty"`
	Status          string                 `json:"status"`
	Summary         string                 `json:"summary,omitempty"`
	Artifacts       []DelegationArtifact   `json:"artifacts,omitempty"`
	RemoteArtifacts []RemoteArtifact       `json:"remote_artifacts,omitempty"`
	Messages        []DelegationMessage    `json:"messages,omitempty"`
	Error           *DelegationError       `json:"error,omitempty"`
	RawTask         map[string]any         `json:"raw_task,omitempty"`
	Metadata        map[string]interface{} `json:"metadata,omitempty"`
}

DelegationResult is the terminal, structured outcome of one delegation. Summary and Messages are the model-facing layers; RawTask and RemoteArtifacts preserve explicitly requested protocol detail.

func (DelegationResult) HasLine

func (r DelegationResult) HasLine(line string) bool

HasLine reports whether the result carries the given line — matched against the trimmed lines of Summary and of every result message — so hosts can gate a workflow on an exact sentinel without re-parsing transport payloads.

type DelegationStageContext

type DelegationStageContext struct {
	WorkflowRunID string `json:"workflow_run_id,omitempty"`
	Stage         string `json:"stage,omitempty"`
	StepID        string `json:"step_id,omitempty"`
	Attempt       int    `json:"attempt,omitempty"`
}

DelegationStageContext carries optional host workflow coordinates without making the delegation package responsible for workflow orchestration.

type Delegator

type Delegator struct {
	Registry      *Registry
	Bus           *EventBus
	NewClient     ClientFactory
	NewID         func() string
	LifecycleHook DelegationLifecycleHook
	// contains filtered or unexported fields
}

Delegator resolves curated targets, executes A2A tasks, and publishes their normalized lifecycle to an EventBus. Construct it with NewDelegator; Service owns the common production wiring.

func NewDelegator

func NewDelegator(registry *Registry, bus *EventBus, opts ...DelegatorOption) *Delegator

NewDelegator constructs a Delegator over registry and bus. Nil options are ignored; runtime configuration errors are returned by Delegate.

func (*Delegator) Delegate

func (d *Delegator) Delegate(ctx context.Context, req DelegationRequest) (out DelegationResult, err error)

Delegate executes one curated Local or Remote target, publishes ordered DelegationEvent values, and returns its structured terminal result. Failure returns both the available result and a *DelegationError.

type DelegatorOption

type DelegatorOption func(*Delegator)

DelegatorOption configures a Delegator during construction.

func WithStatusPartDecoder

func WithStatusPartDecoder(decoder StatusPartDecoder) DelegatorOption

WithStatusPartDecoder registers a host-owned Status DataPart schema decoder.

type Event

type Event = DelegationEvent

Event is the concise consumer-facing spelling of DelegationEvent.

type EventBus

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

EventBus publishes DelegationEvent values by leader RunID, retains a bounded replay window for late subscribers, and suppresses duplicate terminal events per delegation. It is safe for concurrent publishers and subscribers.

func NewEventBus

func NewEventBus(replayLimit int) *EventBus

NewEventBus constructs an EventBus. replayLimit is the maximum retained event count per run; zero disables replay and negative values become zero.

func (*EventBus) ClearRun

func (b *EventBus) ClearRun(runID string)

ClearRun closes current subscribers and removes replay and terminal state for runID. It does not remove results recorded by Service.

func (*EventBus) Publish

func (b *EventBus) Publish(ev DelegationEvent) bool

Publish accepts one event and returns whether it entered the bus. Events without RunID and duplicate terminal events are rejected. Subscriber backpressure is summarized as DelegationStreamDropped.

func (*EventBus) SubscribeRun

func (b *EventBus) SubscribeRun(ctx context.Context, runID string) <-chan DelegationEvent

SubscribeRun returns the retained replay followed by live events for runID. Canceling ctx removes the subscription and closes the channel.

type InputArtifact

type InputArtifact struct {
	Name      string `json:"name,omitempty"`
	URI       string `json:"uri,omitempty"`
	MediaType string `json:"mime_type,omitempty"`
}

InputArtifact is a model-facing reference supplied to a delegated task.

type MCPServer

type MCPServer struct {
	Delegator *Delegator
	Options   MCPServerOptions
}

MCPServer serves the default delegation tool and optional host-owned tools over Streamable HTTP MCP JSON-RPC.

func NewMCPServer

func NewMCPServer(delegator *Delegator, opts MCPServerOptions) *MCPServer

NewMCPServer constructs an MCPServer and panics on duplicate, blank, or default-tool-conflicting custom names.

func (*MCPServer) Handler

func (s *MCPServer) Handler() http.Handler

Handler returns the MCPServer as an http.Handler.

func (*MCPServer) ServeHTTP

func (s *MCPServer) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP handles authenticated MCP JSON-RPC and streamable progress. Only POST is accepted.

type MCPServerOptions

type MCPServerOptions struct {
	RunID              string
	ParentToolCallID   string
	Tenant             string
	BearerToken        string
	Tools              []ToolSpec
	DisableDefaultTool bool

	// AllowUnauthenticatedLoopbackForTest permits an otherwise unprotected
	// loopback-only server for tests and local probes. Production HTTP sidecars
	// should always use a per-run bearer token.
	AllowUnauthenticatedLoopbackForTest bool
}

MCPServerOptions configures one authenticated MCP endpoint. RunID attributes default-tool delegations; Tools add host-owned tool projections. Every request body is limited to 1 MiB.

type Policy

type Policy = DelegationPolicy

Policy is the concise consumer-facing spelling of DelegationPolicy.

type Registry

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

Registry stores host-curated remote target specifications by stable key. Registry returns defensive copies and is safe for read-only concurrent use after construction; hosts should complete registration before delegation.

func NewRegistry

func NewRegistry(specs ...RemoteAgentSpec) (*Registry, error)

NewRegistry constructs a Registry and validates each supplied target.

func (*Registry) Keys

func (r *Registry) Keys() []string

Keys returns the registered target keys. Callers that need deterministic presentation order should sort the result.

func (*Registry) Lookup

func (r *Registry) Lookup(key string) (RemoteAgentSpec, bool)

Lookup returns a defensive copy of the target registered under key.

func (*Registry) Register

func (r *Registry) Register(spec RemoteAgentSpec) error

Register validates and adds one target. Duplicate keys are rejected.

type RemoteAgentSpec

type RemoteAgentSpec struct {
	Key                 string
	DisplayName         string
	Protocol            string
	AgentCardURL        string
	AgentCard           *clienta2a.AgentCard
	Tenant              string
	Auth                clienta2a.Auth
	HTTPClient          *http.Client
	TrustedAuthOrigins  []string
	AcceptedOutputModes []string
	PreferredTransports []clienta2a.TransportProtocol
	Policy              DelegationPolicy
}

RemoteAgentSpec is one host-curated remote A2A target. It carries discovery, auth, transport, tenant, output-mode, and delegation-policy configuration; model-facing tool input names only Key and cannot replace these values.

type RemoteArtifact

type RemoteArtifact struct {
	ID          string         `json:"id,omitempty"`
	Name        string         `json:"name,omitempty"`
	Description string         `json:"description,omitempty"`
	Parts       []RemotePart   `json:"parts,omitempty"`
	Extensions  []string       `json:"extensions,omitempty"`
	Metadata    map[string]any `json:"metadata,omitempty"`
	Raw         map[string]any `json:"raw,omitempty"`
}

RemoteArtifact preserves an opt-in full remote A2A artifact projection.

type RemotePart

type RemotePart struct {
	Kind      clienta2a.PartKind `json:"kind,omitempty"`
	Text      string             `json:"text,omitempty"`
	Raw       []byte             `json:"raw,omitempty"`
	Data      any                `json:"data,omitempty"`
	URL       string             `json:"url,omitempty"`
	MediaType string             `json:"mime_type,omitempty"`
	Filename  string             `json:"filename,omitempty"`
	Metadata  map[string]any     `json:"metadata,omitempty"`
}

RemotePart preserves one part of an opt-in RemoteArtifact.

type Runner

type Runner = adaptor.Runner

Runner is adaptor.Runner. Agent, Thread, and host decorators can all be Local delegation targets and execute in-process without an A2A server or HTTP hop.

type Service

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

Service is the consolidated delegation runtime. Construct with NewService; Close releases every sidecar and observer. All methods are safe for concurrent use.

func NewService

func NewService(cfg Config) (*Service, error)

NewService validates the agent table, registers every ref (local refs get a synthetic in-process AgentCard and a Runner-backed loopback client), and wires Registry + EventBus + Delegator with the Service's result-recording lifecycle hook.

func (*Service) AttachRun

func (s *Service) AttachRun(_ context.Context, runID string) (adaptor.RunAttachment, error)

AttachRun starts (or reuses) this run's MCP sidecar and publishes it as a runtime service carrying a typed MCP declaration, plus the delegation event source for the run. It is the RunServiceProvider half of Option().

A failure here is a pre-launch failure: the leader driver never starts, which is the correct outcome — a leader whose delegate_to_agent endpoint does not exist would silently run as a solo agent.

func (*Service) Bus

func (s *Service) Bus() *EventBus

Bus exposes the shared EventBus for component-level subscribers. Ordinary Agent integration should use Option or adaptor.WithRunServices, which folds these events into the leader's existing Event stream.

func (*Service) Close

func (s *Service) Close() error

Close shuts down every sidecar, stops every observer, clears bus state, and waits for observer callbacks to drain. Idempotent; safe to defer immediately after NewService. Recorded results remain readable.

func (*Service) Delegate

Delegate runs one delegation directly (the programmatic path; the MCP sidecar is the driver path). Events publish to the shared bus and the result is recorded like any sidecar-initiated delegation.

func (*Service) Delegations

func (s *Service) Delegations(runID string) []DelegationResult

Delegations returns every delegation accepted for runID in the exact order its DelegationStarted event was accepted by the Service's EventBus. Unlike Results, it preserves repeated delegations to the same agent. An in-flight entry has Status "running" until its final result is recorded. The returned slice and every result in it are defensive copies and remain available after ReleaseRun and Close, matching the existing result-recording lifecycle.

func (*Service) Delegator

func (s *Service) Delegator() *Delegator

Delegator exposes the underlying Delegator for hosts that need the component-level API; its lifecycle hook and client factory are owned by the Service and must not be replaced.

func (*Service) DetachRun

func (s *Service) DetachRun(_ context.Context, runID string) error

DetachRun shuts the run's sidecar down, stops its observer, and clears the run's bus state — ReleaseRun, reached through the SDK's teardown instead of a host-written defer. Recorded results survive, so team.Result(runID, key) still answers after the run ends.

func (*Service) EnsureSidecar

func (s *Service) EnsureSidecar(runID string) (Sidecar, error)

EnsureSidecar returns the per-run MCP endpoint for runID, starting it on first use. Idempotent per run: repeated calls return the same URL and token. The endpoint serves the delegate_to_agent tool authenticated by Sidecar.BearerToken. Agent integrations should prefer Option or adaptor.WithRunServices, which publishes the typed MCP declaration safely.

func (*Service) Option

func (s *Service) Option() adaptor.SharedOption

Option returns the adaptor option that binds this Service to every run of the agent it is passed to. It is a dual-scope option: in adaptor.New it is the agent's team for every run, in Run/Stream it equips a single invocation. Passing the same Service's option in both places attaches it once, not twice.

The Service must outlive the runs it equips; Close it when the host is done (recorded results stay readable afterwards).

func (*Service) Registry

func (s *Service) Registry() *Registry

Registry exposes the delegation registry (read-only usage expected).

func (*Service) ReleaseRun

func (s *Service) ReleaseRun(runID string) error

ReleaseRun shuts down the run's sidecar and observer and clears the run's bus state. Recorded results are kept so hosts can read them after the run ends; they are released with the Service.

func (*Service) Result

func (s *Service) Result(runID, key string) (DelegationResult, bool)

Result returns the recorded final DelegationResult of the given run and agent key. The result is recorded by the Service's lifecycle hook before the terminal delegation event reaches the bus, so a consumer that just saw a terminal event can read the result without further synchronization. When the same agent was delegated to multiple times in one run, the latest result wins.

func (*Service) Results

func (s *Service) Results(runID string) map[string]DelegationResult

Results returns all recorded results of one run, keyed by agent key.

type Sidecar

type Sidecar struct {
	// RunID is the leader run this sidecar attributes delegations to.
	RunID string
	// URL is the Streamable-HTTP MCP endpoint (http://127.0.0.1:PORT/mcp).
	URL string
	// BearerToken authenticates requests (Authorization: Bearer <token>).
	BearerToken string
	// ToolTimeout is the effective per-delegation wall clock configured on
	// the Service, surfaced so hosts can align driver-side tool timeouts.
	ToolTimeout time.Duration
}

Sidecar describes one live per-run MCP endpoint: the loopback URL the leader's driver should be pointed at (mcp_servers entry) and the bearer token that authenticates it.

type StatusPartDecoder

type StatusPartDecoder interface {
	Profile() string
	DecodeStatusPart(data any) (events []DelegationEvent, matched bool, err error)
}

StatusPartDecoder converts one host-owned A2A Status DataPart schema into DelegationEvent values. Implementations fill semantic fields only; the mapper supplies delegation identity, A2A coordinates, profile, and time. matched=false allows the next registered decoder to inspect the value.

type ToolConstraints

type ToolConstraints struct {
	TimeoutSeconds    int  `json:"timeout_seconds,omitempty"`
	TimeoutSecondsSet bool `json:"-"`
	Stream            bool `json:"stream,omitempty"`
	MaxArtifacts      int  `json:"max_artifacts,omitempty"`
	MaxArtifactsSet   bool `json:"-"`
	HistoryLength     int  `json:"history_length,omitempty"`
	HistoryLengthSet  bool `json:"-"`
}

ToolConstraints carries model-requested bounds. The Set fields distinguish an omitted value from an explicit JSON zero during validation.

type ToolContext

type ToolContext struct {
	RunID            string
	ParentToolCallID string
	Tenant           string
}

ToolContext carries host-owned invocation context for one MCP tool call.

type ToolInput

type ToolInput struct {
	Agent       string          `json:"agent"`
	Objective   string          `json:"objective"`
	Input       ToolInputBody   `json:"input,omitempty"`
	Constraints ToolConstraints `json:"constraints,omitempty"`
}

ToolInput is the strictly decoded model-facing input of DelegateToolName.

func ParseToolInput

func ParseToolInput(raw []byte) (ToolInput, error)

ParseToolInput strictly decodes and validates default tool input. Unknown fields, endpoint_url, missing required fields, and invalid bounds fail with *DelegationError.

type ToolInputBody

type ToolInputBody struct {
	Prompt    string          `json:"prompt,omitempty"`
	Context   string          `json:"context,omitempty"`
	Artifacts []InputArtifact `json:"artifacts,omitempty"`
}

ToolInputBody carries optional prompt context and artifact references.

type ToolSpec

type ToolSpec struct {
	Name        string
	Description string
	InputSchema map[string]any

	BuildRequest func(ctx context.Context, raw json.RawMessage, env ToolContext) (DelegationRequest, error)
	BuildResult  func(ctx context.Context, out DelegationResult) (any, error)
}

ToolSpec describes one stage-oriented MCP tool built on top of Delegator.

BuildRequest should parse tool arguments and produce a DelegationRequest. Fields left empty (`RunID`, `ParentToolCallID`, `Tenant`) are backfilled from ToolContext by the MCP server.

BuildResult optionally projects the final DelegationResult into a typed tool payload. When nil, the raw DelegationResult is returned.

Jump to

Keyboard shortcuts

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