所需权限:
workspace_agent:a2aBase URL
POST {baseUrl}/message:send 或 GET {baseUrl}/tasks/{taskId}。
协议版本
MemoryLake 并行暴露两套 A2A 路由,分别对应一个协议版本;每个版本都可以通过两种传输方式调用:REST 与 JSON-RPC 2.0。
走 JSON-RPC 时,两个协议版本都 POST 到不带后缀的
{baseUrl},由 method 指定具体操作:v1.0 使用 SendMessage、SendStreamingMessage、GetTask、CancelTask、SubscribeToTask;v0.3 使用 message/send、message/stream、tasks/get、tasks/cancel、tasks/resubscribe。协议版本由方法名协商得出;v1.0 客户端还应额外发送 A2A-Version: 1.0。
四组路由都接受同一个 configuration 对象,以及下文描述的同一套 MemoryLake 扩展。两个协议版本对「是否等待任务完成」的开关叫法不同:
不支持推送通知。 Agent Card 声明
pushNotifications: false,传 pushNotificationConfig(v0.3)或 taskPushNotificationConfig(v1.0)都不会收到回调。要跟踪任务进度,请使用流式响应,或订阅这个任务。MemoryLake 扩展
MemoryLake 通过metadata.memorylake 命名空间扩展了标准 A2A 协议。在 message:send 或 message:stream 请求的 metadata 里传入此对象:REST 请求体放在顶层 metadata,JSON-RPC 放在 params.metadata。Agent 不会从 message.metadata 里读取这些字段。
这是与普通 A2A 服务器的核心区别 —— 这些字段将 Agent 连接到 MemoryLake 中的工作空间、项目和 Actor。对象里的字段分两类:
- 记忆与身份:
actorId、readWriteProjectId、readOnlyProjectIds、skipMemory,决定 Agent 使用谁的记忆、读写哪些项目。 - 运行配置:
overrides、runtimeOptions,调整 Agent 处理这条消息的方式。
metadata 下除 memorylake 以外的键,Agent 都不会读取。
metadata.memorylake 必须传。 不传时请求返回 400 INVALID_ARGUMENT。传空对象 {} 即使用默认设置:Agent 使用您自己的 Actor,记忆处于开启状态。记忆与身份
string
发出这条消息的终端用户,填 MemoryLake 的 Actor ID(
actor- 加 32 位十六进制字符)。Agent 会检索这个 Actor 的记忆,会话中用户一方的发言也记在这个 Actor 名下,从而实现按用户记忆。- 默认值: 当前认证用户在该工作空间里的 Actor。该用户在这里没有 Actor 时,请求返回
400 STATE_NOT_READY。 - 必须是已绑定到该工作空间的 Actor。其他 ID 返回
400,已删除的 Actor 返回400 ACTOR_INACTIVE。 - 权限: 需要对该 Actor 有
workspace_actor:fact_add和workspace_actor:fact_search。会话开始时校验一次;之后某条消息带来会话里还没有过的 Actor 时,会再校验。
string
Agent 工作所在的项目(
proj- 加 32 位十六进制字符)。Agent 会检索这个项目的文档和记忆,会话也记在这个项目下,从会话中提取的记忆就保存在这里。会话历史本身存储在工作空间层级。- 一个会话只绑定一个项目。 会话(
contextId)的第一条消息绑定项目,之后的消息可以不传,沿用该项目。传入不同的项目,或者给一个开始时没有项目的会话补上项目,都会返回400。 - 只能是同一工作空间的项目。 其他工作空间的项目返回
404。 - 权限: 需要对该项目有
project:mem_add、project:doc_add、project:mem_search和project:doc_search,在会话开始时校验。 - 带文件时必填。 消息里的文件(
drive://引用或 inline 字节)会作为文档导入这个项目。带文件的消息必须自己写明项目,不能靠从会话继承,否则请求返回400。
string[]
Agent 可以检索(文档和记忆)但不会写入的其他项目。用于让 Agent 访问共享知识库。
- 只对这一条消息生效。 它不会存到会话里,所以每条需要看到这些项目的消息都要带上。
- 权限: 需要对每个项目有
project:mem_search和project:doc_search,缺任何一项都返回403。 - 找不到对应项目的 ID 会被跳过,不报错。
boolean
default:"false"
为
true 时,这条消息不使用记忆:Agent 不检索记忆和项目文档,这条消息的内容也不会写入记忆。会话照常创建,对 Actor 和项目的权限照常校验。运行配置
object
只对这一条消息修改 Agent 的配置。没有传的项沿用 Agent 自身的配置。
object
这条消息的运行选项。
按消息开启能力
overrides.capabilitiesOverride 用来给单条消息额外开启能力。它是一个对象:键是能力名,值是该能力的配置。能力名及其字段一律用蛇形命名(snake_case),与周围的驼峰字段不同(也接受 webSearch、openDatasets 这样的驼峰写法)。
使用时请注意:
- 只对这一条消息生效。 同一会话的下一条消息不带这个覆盖,就不会开启。
- Agent 默认没有这些能力。 不传覆盖时,只有 Agent 自身配置了联网搜索或读取网页,它才会使用(见创建 Agent 的
capabilities)。pii、vega和dataset只能在这里开启。 - 传入的配置会替换 Agent 自身的配置。 请给出该能力完整的配置,不要指望从 Agent 那里继承字段。例如 Agent 的
web_search配置了open_datasets,而这次只传"web_search": {},这条消息就不会检索任何 Open Data 数据集。 - 只能开启,不能关闭。 不传某个能力,即沿用 Agent 自身的配置;传
null也关不掉 Agent 已有的能力。{"enabled": false}更要避免:并没有enabled这个字段,它会被当成{},反而以默认配置开启该能力,即使 Agent 原本没有。需要不带某个能力运行时,请使用没有配置该能力的 Agent。
示例
发送一条消息涉及三个彼此独立的选择 —— 协议版本(v1.0 / v0.3)×方法(send / stream)×传输方式(REST / JSON-RPC),因此共有 8 种有效组合。以下把 8 种全部列出。 下表的路径均相对于上文的 base URL;JSON-RPC 一律 POST 到不带后缀的 base URL,由method 指定操作。
上表 header 列中,SSE 表示
Accept: text/event-stream,v1.0 表示 A2A-Version: 1.0。8 种组合都使用相同的 configuration 字段(v1.0 默认等待并使用 returnImmediately,v0.3 使用 blocking)和同一套 metadata.memorylake 扩展。其中 4 个 streaming 变体以 text/event-stream 返回;4 个 send 变体返回单个 JSON 响应体。
请注意版本与传输方式之间的三处结构差异:v1.0 使用
parts,role 为 "ROLE_USER";v0.3 REST 使用 content,role 为 "ROLE_USER";v0.3 JSON-RPC 使用 parts 且每个 part 都带 kind 判别符,role 为小写的 "user"。REST 传输
JSON-RPC 传输
两个协议版本共用同一个路径 —— 不带任何后缀的POST {baseUrl}。协议版本由方法名决定;v1.0 客户端还应额外发送 A2A-Version: 1.0。
响应
所有组合返回的都是同一套任务模型,只有外层结构和少数拼写随协议版本和传输方式变化,见 v0.3 的差异。本节示例使用 v1.0 REST。非流式发送
message:send 总是返回一个任务,不会只返回一条消息。默认会等任务执行完再返回:
string
任务 ID。
string
任务所属的会话。下一条消息把它作为
message.contextId 传入即可继续这个会话。请求里没有传时,会生成一个新的。object
array
您发出的消息,之后按顺序是 Agent 的消息:执行过程中写的文字、思考内容,以及工具调用。连续的文字会合并成一条消息。
configuration.historyLength 只保留最后 N 条,传 0 时不返回 history。returnImmediately: true(v1.0)或 blocking: false(v0.3)时,任务一创建就返回:状态为 TASK_STATE_SUBMITTED(也可能已经是 TASK_STATE_WORKING),history 里只有您发出的消息,没有 artifact。任务会在后台继续执行;要拿到回答,请订阅这个任务。
流式发送
message:stream 以 text/event-stream 返回,每行 data: 是一个 JSON 事件,顺序如下:
task:刚创建的任务,history里是您发出的消息。statusUpdate,状态TASK_STATE_WORKING:Agent 开始执行。statusUpdate,状态TASK_STATE_WORKING:每一步进展一个,status.message里只有一个 part,可能是:- 一段回答文字。文字是增量下发的,需要依次拼接;每段都有自己的
messageId; - 一段思考内容,带
metadata.adk_thought: true; - 一次工具调用或工具结果;
- Agent 生成的文件,形如
{"url": "...", "mediaType": "...", "filename": "..."}。
- 一段回答文字。文字是增量下发的,需要依次拼接;每段都有自己的
artifactUpdate:回答,见回答内容。statusUpdate:最终状态,TASK_STATE_COMPLETED、TASK_STATE_FAILED(status.message里是错误说明)或TASK_STATE_CANCELED。之后流结束。
: 开头的行是保活注释,忽略即可。
… 做了缩写,重复字段也已省略。
回答内容
名为result 的 artifact 以一组 part 承载回答:
artifact 和流里还可能出现其他
data part。遇到不认识的 kind,或者没有 kind 的 data part,跳过即可。data part 里的数字会以浮点数返回,例如 2 会变成 2.0。
工具调用
Agent 的工具调用以data part 的形式出现,用 metadata.adk_type 标记,这是 Google Agent Development Kit 的约定。流和 history 里都会出现。
工具调用上可能还带有
metadata.adk_thought_signature,这是一个不透明的值,忽略即可。
跟踪任务
GET {baseUrl}/tasks/{taskId}(v0.3:{baseUrl}/v1/tasks/{taskId})只返回任务的 id、contextId 和 status(含 state 与 timestamp):不包含回答和历史,失败的任务也不带错误说明。
要拿到一个没有等待的任务的回答,请订阅它:GET {baseUrl}/tasks/{taskId}:subscribe(v0.3:{baseUrl}/v1/tasks/{taskId}:subscribe),并带上 Accept: text/event-stream。它会从头重放该任务的事件,格式与 message:stream 相同,只是开头没有 task 事件;之后实时跟随,直到任务结束。已经失败或被取消的任务无法订阅。
错误
任务失败。 请求仍然返回 HTTP 200,任务以TASK_STATE_FAILED 结束,status.message.parts[0].text 是错误说明。例如 overrides.model 填了不存在的模型时,任务失败,错误为 LLM model config not found: <model>。
请求被拒绝。 REST 路由返回 HTTP 错误状态码和标准的错误响应体(success、message、error_code),例如:
JSON-RPC 下,MemoryLake 在 Agent 运行之前发现的错误(例如配额或权限错误)同样使用上面的 HTTP 状态码和错误响应体;Agent 报告的错误则以 JSON-RPC
error 对象返回,HTTP 状态码为 200,其中 v0.3 方法一律使用错误码 -32603。
v0.3 的差异
- JSON-RPC。 result 直接就是任务,带
"kind": "task"。流事件带"kind": "status-update"或"artifact-update",最后一个状态更新带"final": true。状态用小写,例如completed、failed、canceled、submitted、working;角色为user和agent。每个 part 都带kind:{"kind": "text", "text": ...}、{"kind": "data", "data": {...}}或{"kind": "file", "file": {...}}。 - REST。 状态拼写与 v1.0 相同,只有已取消拼作
TASK_STATE_CANCELLED。消息的 part 放在content下而不是parts,data part 的形式是{"data": {"data": {...}}}。GET返回的任务不带timestamp。 - REST 的默认值。 不传
blocking时,message:send会立即返回而不是等待;不传historyLength时不返回history。请显式设置这两个字段。