agent-work-layer
人工智能代理的工作指令和工作报告。 类型化SDK、验证器和生命周期引擎,用于将工作从一个代理处理到另一个代理,并具有可检查的结果。MCP服务器是一个单独的包, agent-work-layer-mcp.
- 工作订单 (经理→工人):目标,如何判断“完成”,预算,截止日期,允许使用的工具。
- 工作报告 (工人→管理者):结果,每个标准的依据,实际成本,使用的工具。
探员卡上写着探员是谁。A2A在代理之间传递信息。MCP连接座席和工具。锥子描述 工作本身,因此,任何经理都可以把工作交给任何工人,并检查工作结果。格式定义为 SPEC.md.
它是如何工作的
- 经理发出 工作订单目标、标准、预算、截止日期、允许使用的工具。
- 工人接受它,用它的工具工作。
- 工作程序返回 工作报告 每一项标准都有证据以及它的花费。
- 服务台根据订单核对报告。经理批准它或将其发回。
更多的图: 消息序列 · 生命周期 · 代表团 · 切换 · 上演了工具 · 经过身份验证的演员 · 代表团通过 · JWS vs JWT
安装
只安装您使用的部分:
| 你想… | 安装 | 包 |
|---|---|---|
| 验证订单和报告,或者在代码中运行桌面 | npm install agent-work-layer | 7 |
| 在浏览器、Deno或Bun中进行验证 | npm install agent-work-layer,然后导入 agent-work-layer/validate | 7 |
| 在Python中验证订单和报告 | pip install agent-work-layer (python /) | 11 |
| 通过MCP连接代理会话(例如Claude Code) | npx -y agent-work-layer-mcp (设置) | ~ 100 |
| 签署或验证委托通行证 | npm install agent-work-layer (如何) | 7 |
Node.js 20.11或更高版本。ESM。类型包括在内。Python包需要Python 3.9或更高版本。
快速启动
import { WorkDesk } from "agent-work-layer";
const desk = new WorkDesk(); // in-memory; use FileStore, SqliteStore or your own DeskStore to persist
// Manager issues a job
const { order } = await desk.create(
{
to: "agent:researcher",
goal: "Summarize the main risk factors in the latest annual report",
criteria: [
{ id: "c1", text: "Lists three risk factors, each quoted from the filing" },
{ id: "c2", text: "States total debt and its fiscal year" },
],
budget: { usd: 2, tool_calls: 20 },
deadline: new Date(Date.now() + 3_600_000).toISOString(),
tools: ["filings/*"],
},
"agent:manager",
);
// Worker accepts, does the work, reports with evidence
await desk.accept(order.id, "agent:researcher");
const { record } = await desk.submitReport(
order.id,
{
status: "done",
result: { summary: "Refinancing, customer concentration and FX risk. Debt 1.2B USD (FY2025)." },
evidence: [
{ criterion: "c1", type: "tool_call", ref: "filings/get_section#3" },
{ criterion: "c2", type: "citation", ref: "filings/get_section#5" },
],
cost: { usd: 0.84, tool_calls: 7 },
tools_used: ["filings/search", "filings/get_section"],
},
"agent:researcher",
);
// Manager approves, or sends it back with a reason
await desk.review(order.id, "agent:manager", "approve");
对于可运行的版本,克隆repo,运行 npm install,然后跑 node examples/two-agents.ts (节点22.18 +)。 例子/ two-agents.ts 通过拒绝的报告、返工请求和批准来遍历一个作业,并在发生时打印每个事件。
桌面在您进行时强制执行该规范:
- 谁可以做什么:只有工人报告,只有经理批准。
- 哪些州的变化是合法的。
- 每个标准的证据。
- 只允许使用工具。
- 成本在预算范围内,并在截止日期前完成。超过任何一个都将使订单失效。
- 子命令只能缩小父命令的权限。它们的预算来自于父订单,所以整个子订单树的支出永远不会超过其根订单。
- 重新发布的订单只能延续已完成的订单,因此一个作业永远不会有两个有效的订单。
可选地,它还将工作者的权限签名到 代表团通过 网关和其他系统可以在没有桌面的情况下进行检查。
移交未完成的工作
当一个worker失败、被阻塞或被取消时,它可以告诉下一个worker应该知道什么。经理在下一个订单中传递它:
await desk.submitReport(order.id, {
status: "failed",
error: "Export runs out of memory on files over 2 GB",
handoff: {
decisions: [{ text: "Stream rows instead of buffering", why: "Memory limit" }],
tried: [{ text: "xlsx library", result: "Too slow on large files" }],
next_step: "Add tests for null cells",
},
/* result, evidence, cost, tools_used */
}, "agent:researcher");
const { handoff } = (await desk.get(order.id)).reports.at(-1)!;
await desk.cancel(order.id, "agent:manager", "reissuing"); // a continued order must be finished
await desk.create({ ...nextJob, to: "agent:other-worker", handoff, continues: order.id }, "agent:manager");
await desk.list({ continues: order.id }); // the orders that pick up from this one
context 列出要读的书; handoff 说的是已经决定的和已经尝试过的; continues 将新订单链接到它所取代的订单,因此订单链是作业的完整历史记录。不像 parent_id它不会缩小任何东西:新秩序可以有不同的工人、预算和工具。看到 SPEC.md§4.4 和 §4.5.
Hold写直到报告被批准
拒绝报告不会取消发送电子邮件。对于您想要首先检查其效果的工具,请将其列出 staged:
await desk.create({ ...job, tools: ["filings/*", "gmail/*"], staged: ["gmail/send"] }, "agent:manager");
工人的 MCP网关 然后阻止呼叫 gmail/send:它计数并记录每一个,并返回一个占位符(pending:gmail/send#4). 工人在报告中列出了它们 effects,经理与报告的其余部分一起审查。批准让大门控制他们;返工会丢失它们,因为它们从未运行过,所以没有什么可以撤销的。读取仍然正常运行。子顺序不能允许工具拥有父阶段(C5)。
分阶段调用可以使用先前调用的结果:pass { "$ref": "github/create_issue#3", "pointer": "/structuredContent/number" } 作为参数,并且网关在运行效果时填充它。经理也只能批准一些效果:
await desk.review(order.id, "agent:manager", "approve", "Send the CFO copy only", { effects: ["gmail/send#4"] });
看到 SPEC.md§4.6.
跟踪进度和跟踪记录
await desk.progress(order.id, "agent:researcher", "Risk section read; checking the debt note", 60);
await desk.trackRecord("agent:researcher");
// { orders: 12, approved: 9, approved_first_time: 7, reworks: 3, expired: 1, ..., spent: { usd: 8.4 }, budget: { usd: 24 } }
进度说明如下 progress 事件:它们不改变状态,但是 waitForChange 和 wait_for_update 唤醒他们。跟踪记录记录的是一个工作台为一个工人保存的订单发生了什么。看到 SPEC.md§6.2 和 §6.3.
验证文档
import { validateOrder, validateReport, hasInvalid } from "agent-work-layer";
const findings = validateReport(report, order);
// [{ rule: "R4", kind: "invalid", path: "/evidence", message: 'no evidence for criterion "c2"' }, ...]
if (hasInvalid(findings)) reject(findings);
每个发现都带有来自的规则id SPEC.md§7. invalid 调查结果拒绝文档。 limit 记录发现(超出预算、超过截止日期)并使订单过期。
用另一种语言编写验证器?对JSON测试向量运行它 一致性/:包含每个规则必须报告的结果的文档。
JSON模式也被导出: workOrderSchema, workReportSchema,或者 agent-work-layer/schemas/work-order.schema.json.
agent-work-layer/validate 在没有桌面的情况下具有相同的检查、类型和模式。它没有从Node中导入任何东西,因此它可以在浏览器、Deno和Bun中运行。(不支持Cloudflare Workers:验证器在运行时将模式编译为代码,而Workers会阻止。)
以MCP服务器身份运行
服务器位于自己的包中, agent-work-layer-mcp,所以只验证文档的人不会下载MCP SDK。
对于开发,在工作室。 每个代理会话运行自己的桌面进程。会话共享一个文件夹,每个会话都被锁定到它开始时的身份。
# Claude Code: a manager session and a worker session, each added in its own project folder
claude mcp add awl -e AWL_STORE="$HOME/.awl" -e AWL_ACTOR=agent:manager -- npx -y agent-work-layer-mcp
claude mcp add awl -e AWL_STORE="$HOME/.awl" -e AWL_ACTOR=agent:worker -- npx -y agent-work-layer-mcp
通过HTTP共享使用。 一个桌面为每个代理服务,每个请求的凭据决定它作为谁,因此工作人员不能批准自己的工作(细节):
npx -y agent-work-layer-mcp serve --keys keys.json # { "keys": { "<key>": "agent:manager", ... } }
claude mcp add --transport http awl http://127.0.0.1:8787/mcp --header "Authorization: Bearer $AWL_KEY"
工具: create_work_order, list_work_orders, get_work_order, accept_work_order, decline_work_order, start_work_order, report_progress, submit_work_report, answer_question, review_work_report, allow_effect_retry, cancel_work_order, wait_for_update, get_track_record, renew_work_pass 当桌子发出信号时 代表团传递.
在工人工作时执行命令,并保持命令不变 上演了 写,直到你批准,连接工人到它的真实的MCP服务器通过网关: npx -y agent-work-layer-mcp gateway --order <id> --config upstream.json。批准后, --commit 运行已批准的写操作。看到 网关文档.
要将服务器嵌入到您自己的进程或传输中(npm install agent-work-layer agent-work-layer-mcp):
import { WorkDesk, FileStore } from "agent-work-layer";
import { createDeskServer } from "agent-work-layer-mcp";
const server = createDeskServer({ desk: new WorkDesk({ store: new FileStore("./.awl") }), actor: "agent:manager" });
await server.connect(transport);
命令行界面
npx agent-work-layer new order > order.json
npx agent-work-layer new report > report.json
npx agent-work-layer validate order.json report.json # exit 1 on invalid, prints rule ids
npx agent-work-layer validate child.json --parent order.json
npx agent-work-layer validate order.json report.json --json
npx agent-work-layer schema order
npx -y agent-work-layer-mcp --store ./.awl --actor agent:worker # the MCP desk on stdio (was "awl desk" before 0.2)
npx -y agent-work-layer-mcp serve --keys keys.json # one shared desk over HTTP; add --pass-key/--issuer to sign passes
npx -y agent-work-layer-mcp gateway --order <id> --config <file> # enforce an order at every tool call; add --pass-keys to use passes
new order 从一个标准开始,1美元的预算,不允许使用工具和一个
截止日期为创建后一小时。 new report 开始时 blocked,带着一个问题
也没有完成工作的证据。两个模板在打印时一起验证。
替换之前的占位符目标、身份、标准和报告内容
使用它们;保留这份报告。 order_id 等于阶数 id.
生命周期
offered ──accept──▶ accepted ──start──▶ working ──report done/failed──▶ submitted ──approve──▶ approved
│ │ ▲ │
decline blocked │ │ answer │ rework (with reason)
▼ ▼ │ ▼
declined blocked working
Any active state ──cancel──▶ cancelled · deadline or budget exceeded ──▶ expired
而 working,工人可以张贴进度记录。它们被记录为事件,但不改变状态(SPEC.md§6.2)。
| 行动 | 谁 |
|---|---|
| 接受,拒绝,启动,提交报告,发布进度 | 工人(order.to) |
| 经批准后,记录或处理效果结果 | 工人 |
| 批准、返工、取消、允许效果重试 | 经理(order.from) |
| 回答一个被封锁的工人 | 经理或 order.escalate_to |
| 到期 | 桌子上 |
API
| 出口 | 目的 |
|---|---|
WorkDesk | 运行生命周期: create, accept, decline, start, progress, submitReport, answer, review, cancel, get, list, subOrders, held, trackRecord, waitForChange, issuePass 当它发出时就过去了。批准后: recordCommit, settle (工人)和 allowRetry (经理) |
MemoryStore, FileStore, SqliteStore, DeskStore | 存储。实现 DeskStore (4)使用数据库的方法 |
validateOrder, validateReport, validateChildOrder, validateChildBudgets, validateOwnCost, hasInvalid | 规格检查,退货 Finding[] |
heldBySubOrders | 一个订单的子订单所拥有的预算,它自己可能不会花掉 |
isWorkOrder, isWorkReport | 类型警卫 |
toolAllowed, patternCovered | 刀具图案匹配 |
effectReferences | 对早期效果的引用导致了效果的参数 |
approvedEffects, effectOutcomes | 批准允许运行的效果,以及从订单中知道的每个效果 commit 和 settle 事件 |
nextState, allowedActions, STATES, ROLE_FOR, isTerminal | 状态机 |
AwlError, isAwlError | 输入错误 code 和 findings |
signPass, verifyPass, decodePass, PassError | 代表团传递:签名,验证(包括缩小对父母),阅读 |
orderSpecFor, reportSpecFor | 包含文档在桌面写入时使用的每个字段的最低版本 |
ORDER_SPEC, REPORT_SPEC, ORDER_SPECS, REPORT_SPECS | 最新的规范版本,和每一个版本阅读 |
createDeskServer (从 agent-work-layer-mcp) | 桌面用MCP服务器 |
createDeskHttpHandler, apiKeyAuth, bearerAuth, AuthError (从 agent-work-layer-mcp) | 桌面通过HTTP,通过actor获取每个请求的凭据 |
createGateway (从 agent-work-layer-mcp) | MCP网关在每次工具调用时强制执行命令或委托通行证 |
WorkDesk 选项: store, clock (测试), newId, onEvent(event, record) (webhook, logging, metrics), passes: { key, issuer, ttlSeconds? } (签署Delegation Passes)。
错误代码
NOT_FOUND, ALREADY_EXISTS, FORBIDDEN, INVALID_TRANSITION, VALIDATION_FAILED (与 findings), CONFLICT (并发写入器先到达;重读并重试), BAD_REQUEST.
PassError 代码: MALFORMED, UNSUPPORTED, BAD_SIGNATURE, EXPIRED, NOT_YET_VALID, WRONG_ISSUER, WRONG_WORKER, WRONG_ORDER, WRONG_PARENT, WIDER_THAN_PARENT (与 findings 从C1-C3和C5)。
自定义存储
MemoryStore 在内存中保存记录, FileStore 为每个订单写入一个JSON文件,并且 SqliteStore 将它们保存在使用Node内置的SQLite数据库中 node:sqlite (节点22.13+,无额外依赖):
import { WorkDesk, SqliteStore } from "agent-work-layer";
const desk = new WorkDesk({ store: new SqliteStore("./awl.db") }); // or ":memory:"
要使用其他数据库,请实现 DeskStore:
import type { DeskStore, OrderRecord } from "agent-work-layer";
class PostgresStore implements DeskStore {
async read(id: string): Promise<OrderRecord | null> { /* SELECT */ }
async insert(record: OrderRecord) { /* INSERT, throw AwlError("ALREADY_EXISTS") on conflict */ }
async update(record: OrderRecord, expectedSeq: number) { /* UPDATE ... WHERE last_seq = expectedSeq, else AwlError("CONFLICT") */ }
async list() { /* SELECT */ }
}
生产笔记
工作室的桌子信任 actor 它开始于。在生产环境中,通过HTTP运行一个桌面,从每个请求的凭据中获取参与者: npx -y agent-work-layer-mcp serve --keys keys.json,或者 createDeskHttpHandler 用你自己的 authenticate (OAuth 2.1承载令牌,API密钥,mTLS)。看到 MCP包README. 要进行实时执行,请运行MCP网关(npx -y agent-work-layer-mcp gateway),它检查 tools 和 budget 在每个工具调用时,而不仅仅是在报告到达时。当网关或其他团队的系统无法读取桌面时,给出它 代表团传递 代替。看到 SPEC.md§9.1 和 §10.
经过身份验证的演员
使用studio,每个代理运行自己的桌面并声明自己的桌面 actor因此,工人可以作为经理开办一家公司。在HTTP上,每个代理都连接到一个工作台,该工作台通过可插入的方式从请求的凭据中获取参与者 authenticate(request) 钩。团队插入他们已经使用的东西:OAuth 2.1承载令牌,API密钥或mTLS。一个 actor 指定其他任何人的论点被拒绝(# 16, SPEC.md§10.1)。
代表团通过
当一个工人开始工作时,工作台会签署一张短期通行证(JWS),上面有订单的工具、预算和截止日期。工作人员在每次工具调用时呈现它,网关或另一个团队的系统自行验证它,而不需要调用桌面。子订单获得命名其父订单的窄通道,因此可以脱机检查委托规则(C1-C3, C5) (# 17, SPEC.md§10.2)。
- 默认情况下,通过时间为15分钟,永远不会超过截止日期。每次订单进入时,柜台都会发出一个新的订单
working,工人在它工作的时候更新它。 - 它包含订单的全部预算;该门户跟踪已花费的资金。
- 取消订单或订单到期将停止新的通行证。没有其他的撤销,这就是为什么通行证很短。
- 传递是一个JWS,它的有效负载是声明集,这也使它成为一个JWT。 这个图 显示通行证的三个部分以及验证它们的顺序。
import { WorkDesk, verifyPass } from "agent-work-layer";
const desk = new WorkDesk({ passes: { key: privateJwk, issuer: "https://desk.example.com" } });
// ...create, accept...
const { pass } = await desk.start(id, "agent:worker"); // renew with desk.issuePass(id, "agent:worker")
// Anywhere else, with only the desk's public key:
const verified = await verifyPass(pass, publicJwk, { issuer: "https://desk.example.com", worker: "agent:worker", order: id });
verified.allows("filings/search"); // true
const child = await verifyPass(childPass, publicJwk, { parent: verified }); // throws WIDER_THAN_PARENT if it breaks C1–C3 or C5
密钥是您提供的P-256或Ed25519 JWKs(或WebCrypto密钥);SDK没有密钥管理。 signPass 和 verifyPass 只使用WebCrypto,所以他们也在 agent-work-layer/validate 浏览器为Deno和Bun。在Node中创建密钥对:
const { privateKey, publicKey } = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"]);
console.log(JSON.stringify(await crypto.subtle.exportKey("jwk", privateKey)), JSON.stringify(await crypto.subtle.exportKey("jwk", publicKey)));
在MCP, awl-desk serve --pass-key priv.json --issuer <url> 问题通过,并且 awl-desk gateway --pass-keys pub.json 执行;看到 MCP包README.
开发
repo是一个npm工作空间,包含两个包:核心包 packages/core 和MCP服务器 packages/mcp. 规范、模式和示例留在根;磁芯在包装时将它们复制进去。
npm install
npm test # core and MCP tests (builds the core first)
npm run test:coverage
npm run typecheck
npm run test:package # packs both packages, installs them in clean projects and uses them
npm run check # all of the above; runs automatically before npm publish
npm run generate # after editing schemas/*.json: refreshes packages/core/src/generated.ts
中的Python包 python/ 与NPM工作区分开:
cd python
python -m venv .venv && .venv/bin/pip install -e ".[test]"
.venv/bin/pytest
贡献
欢迎问题,想法和拉请求。看到 CONTRIBUTING.md 和 路线图. 规范变更开始于 规范的建议 问题。
许可证
apache - 2.0. 您可以使用、修改和发布它,包括商业使用。该许可包括专利授权。