跳转到内容

代理间通信 (A2A)

A2A 是一个开放协议,让一个代理把工作委托给另一个代理:调用方先读取被调用方的 Agent Card 以了解它能做什么,然后通过 JSON-RPC 发送一个任务并取回答案。SDK 支持协议版本 0.3.0,两个方向都支持。

  • a2a / a2a — 本组织自己的代理。列出它们、读取其 card,并运行其中一个直到得出最终答案。
  • A2AClient / AsyncA2AClient — 任何会说 A2A 的代理:另一个组织里的 iMBrace 代理,或者完全是第三方的代理。

一次 A2A 调用是一个阻塞回合:与 aiAgent.streamChat 不同,它只在代理完成后才返回。远端代理会跑完一整轮工具调用循环,因此请预留一分钟以上。

列出你的代理

每一项都带有对端所需的两个 URL:url(JSON-RPC 端点)和 cardUrl。

const agents = await client.a2a.listAgents()
// [{ id, name, url, cardUrl }, ...]
const card = await client.a2a.getAgentCard(agents[0].id)
console.log(card.name, card.skills?.map(s => s.name))

运行一个代理

ask() 返回答案文本。当你需要任务的 status、artifacts 或 contextId 时,用 sendMessage() / send_message() 取回原始的 A2A Task。

const answer = await client.a2a.ask(agentId, "Summarise this week's open deals")
const task = await client.a2a.sendMessage(agentId, "And the closed ones?", {
contextId: previousTask.contextId, // 延续同一个 A2A context
})
console.log(task.status.state) // "completed"

AsyncImbraceClient 上有同样的接口,配合 await 使用。

让别的代理调用你的代理

交给对方两样东西:listAgents() 返回的代理 url,以及一个限定在你组织范围内的 API key。

const { token } = await client.apiKeys.create({ expirationDays: 7 })

对方把该 key 放在 x-access-token 或 x-api-key 请求头里;你的代理 card 会在 securitySchemes 中声明这一点。这个 key 带着你组织的权限,且只显示一次 —— 请给它够用的最短有效期。

调用 iMBrace 之外的代理

给 A2AClient 一个 URL(代理的基础 URL 或其 card URL),如果该代理需要,再给一个 key。key 会同时以 x-api-key 和 Authorization: Bearer 发送,因为各家代理读取的请求头不同;若其 card 声明了别的方案,用 headers 补上。

import { A2AClient } from "@imbrace/sdk"
const reviewer = new A2AClient({
url: "https://reviewer.example.com",
apiKey: process.env.REVIEWER_KEY,
timeoutMs: 120_000, // 默认值
})
console.log((await reviewer.listSkills()).map(s => s.name))
const verdict = await reviewer.ask("Review the diff on branch feat/checkout")

异步版本请用 AsyncA2AClient。card 只取一次并缓存;传 getCard(true) / get_card(refresh=True) 可重新读取。

确认代理可达

discover() 从平台侧探测远端 card,因此它能回答一个你在自己机器上探测无法回答的问题:iMBrace 本身能否连到那个代理。在把远端代理接入你自己的代理之前,先用它确认一下。

const probe = await client.a2a.discover("https://reviewer.example.com", process.env.REVIEWER_KEY)
if (!probe.healthy) throw new Error("iMBrace cannot reach that agent")

自己解析结果

ask() 就是 sendMessage() 加上 extractA2AText(),后者先读任务 status 里的 message,再读 artifacts。当任务来自别处时,可以直接调用它。

import { extractA2AText } from "@imbrace/sdk"
const text = extractA2AText(task)

限制

  • 仅文本。 只发送和读取 text part;file part 和 data part 不作处理。
  • 不支持流式。 不支持 message/stream 和推送通知 —— 本平台公布的 card 声明 streaming: false。若要从你自己的代理逐 token 输出,请用 aiAgent.streamChat。
  • 只有一个方法。 仅 message/send。没有 tasks/get 轮询,因此先返回 submitted 任务、稍后才完成的代理无法继续跟踪。
  • 只支持 bearer 和请求头 API key。 card 要求 OAuth2 或 OIDC 的代理暂不支持。

错误

代理返回的 JSON-RPC 错误、非 2xx 的 card 请求、以及格式错误的 card,都会抛出 ImbraceError。参见错误处理。

import { ImbraceError } from "@imbrace/sdk"
try {
await reviewer.ask("...")
} catch (e) {
if (e instanceof ImbraceError) console.error(e.message)
}