A2A (Agent2Agent) protocol bindings (spec v1.0.1, JSON-RPC) for @aihu/agent-service.
createInMemoryTaskStorefunction createInMemoryTaskStore(): TaskStoremountA2aAdapterfunction mountA2aAdapter(service: AgentService, options?: A2aAdapterOptions): A2aAdapterA2aAdapterinterface A2aAdapter {
asMiddleware(): (req: Request) => Promise<Response | null>
}A2aAdapterOptionsinterface A2aAdapterOptions {
/** URL prefix for all routes. Default: '' */
prefix?: string
/** Agent name for the agent card. Default: 'aihu-agent-service' */
name?: string
/** Agent description for the agent card. */
description?: string
/** Agent version for the agent card. Default: '1.0.0' */
version?: string
/**
* Absolute public URL of the JSON-RPC endpoint, advertised in the agent
* card's `supportedInterfaces[0].url`. Defaults to the relative
* `{prefix}/a2a` when not provided; production cards should set it (the
* spec requires an absolute HTTPS URL).
*/
url?: string
/** Swap the task store; defaults to a per-adapter in-memory store. */
taskStore?: TaskStore
/**
* Per-request auth resolver — the same injection point `agent-service`'s own
* `asMiddleware()` uses (`AgentServiceOptions.resolveAuth`) and that
* `agent-server` forwards verbatim. The adapter calls it to build the
* `RequestContext` threaded into `handleToolCall`, so scoped/$rate-limited
* tools are decidable over the a2a transport.
*
* Thesis §4 tier 0: every transport must express WHO IS ASKING, even when
* the answer is anonymous. When this is absent — or when it throws — the
* adapter still forwards an explicit anonymous context (`{ userId: null }`)
* rather than nothing, so the gate always has something to decide against.
* Fail-closed is preserved: an anonymous context 401s on a scoped binding.
*/
resolveAuth?: (req: Request) => RequestContext | Promise<RequestContext>
}AgentCapabilitiesinterface AgentCapabilities {
streaming?: boolean
pushNotifications?: boolean
extendedAgentCard?: boolean
extensions?: unknown[]
}AgentCardinterface AgentCard {
name: string
description: string
supportedInterfaces: AgentInterface[]
version: string
capabilities: AgentCapabilities
defaultInputModes: string[]
defaultOutputModes: string[]
skills: AgentCardSkill[]
documentationUrl?: string
iconUrl?: string
}Served at `{prefix}/.well-known/agent-card.json` (spec §4.4.1, IANA §13).
AgentCardSkillinterface AgentCardSkill {
id: string
name: string
description: string
tags: string[]
examples?: string[]
inputModes?: string[]
outputModes?: string[]
}AgentInterfaceinterface AgentInterface {
url: string
/** `JSONRPC`, `GRPC`, or `HTTP+JSON`; this adapter serves `JSONRPC`. */
protocolBinding: string
/** A2A protocol version exposed at this interface, e.g. `"1.0"`. */
protocolVersion: string
tenant?: string
}Artifactinterface Artifact {
artifactId: string
name?: string
description?: string
parts: Part[]
metadata?: Record<string, unknown>
extensions?: string[]
}A task output (spec §4.1.7).
JsonRpcErrorinterface JsonRpcError {
code: number
message: string
/** Array of `@type`-tagged detail objects (spec §9.5). */
data?: unknown[]
}JsonRpcRequestinterface JsonRpcRequest {
jsonrpc: '2.0'
id?: string | number | null
method: string
params?: unknown
}JsonRpcResponseinterface JsonRpcResponse {
jsonrpc: '2.0'
id: string | number | null
result?: unknown
error?: JsonRpcError
}Messageinterface Message {
messageId: string
contextId?: string
taskId?: string
role: Role
parts: Part[]
metadata?: Record<string, unknown>
extensions?: string[]
referenceTaskIds?: string[]
}One unit of communication between client and server (spec §4.1.4).
Partinterface Part {
/** Textual content. */
text?: string
/** Raw file bytes, base64-encoded in JSON serialization. */
raw?: string
/** A URL pointing to the file's content. */
url?: string
/** Arbitrary structured data as a JSON value. */
data?: unknown
metadata?: Record<string, unknown>
filename?: string
mediaType?: string
}One section of communication content (spec §4.1.6).
StreamResponseinterface StreamResponse {
task?: Task
message?: Message
statusUpdate?: TaskStatusUpdateEvent
artifactUpdate?: TaskArtifactUpdateEvent
}Streaming payload wrapper (spec §3.2.3).
Taskinterface Task {
id: string
contextId?: string
status: TaskStatus
artifacts?: Artifact[]
history?: Message[]
metadata?: Record<string, unknown>
}The core unit of action for A2A (spec §4.1.1).
TaskArtifactUpdateEventinterface TaskArtifactUpdateEvent {
taskId: string
contextId: string
artifact: Artifact
append?: boolean
lastChunk?: boolean
metadata?: Record<string, unknown>
}TaskStatusinterface TaskStatus {
state: TaskState
message?: Message
/** ISO 8601 UTC timestamp (spec §5.6.1). */
timestamp?: string
}Task status container (spec §4.1.2).
TaskStatusUpdateEventinterface TaskStatusUpdateEvent {
taskId: string
contextId: string
status: TaskStatus
metadata?: Record<string, unknown>
}TaskStoreinterface TaskStore {
get(id: string): Task | undefined | Promise<Task | undefined>
save(task: Task): void | Promise<void>
/** All stored tasks, most recently saved last. */
list(): Task[] | Promise<Task[]>
}Persistence boundary for tasks, making `GetTask` / `ListTasks` / `CancelTask` implementable.
Roletype Role = 'ROLE_UNSPECIFIED' | 'ROLE_USER' | 'ROLE_AGENT'Message sender role (spec §4.1.5).
TaskStatetype TaskState =
| 'TASK_STATE_UNSPECIFIED'
| 'TASK_STATE_SUBMITTED'
| 'TASK_STATE_WORKING'
| 'TASK_STATE_COMPLETED'
| 'TASK_STATE_FAILED'
| 'TASK_STATE_CANCELED'
| 'TASK_STATE_INPUT_REQUIRED'
| 'TASK_STATE_REJECTED'
| 'TASK_STATE_AUTH_REQUIRED'Task lifecycle states (spec §4.1.3, ProtoJSON enum names).