agent-work-layer 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +54 -12
- package/SPEC.md +44 -5
- package/dist/cli.js +44 -20
- package/dist/generated.d.ts +6 -0
- package/dist/generated.js +453 -0
- package/dist/types.d.ts +25 -5
- package/dist/types.js +7 -3
- package/dist/validate.d.ts +2 -2
- package/dist/validate.js +4 -5
- package/dist/validator.d.ts +7 -0
- package/dist/validator.js +7 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -3
- package/package.json +12 -15
- package/schemas/work-order.schema.json +32 -3
- package/schemas/work-report.schema.json +35 -4
- package/dist/mcp.d.ts +0 -13
- package/dist/mcp.js +0 -116
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0 — 2026-10-09
|
|
4
|
+
|
|
5
|
+
### Breaking
|
|
6
|
+
|
|
7
|
+
- The MCP server moved to a new package, `agent-work-layer-mcp`, so installing `agent-work-layer` no longer downloads the MCP SDK and zod (7 packages instead of 97).
|
|
8
|
+
- `npx -y agent-work-layer desk` → `npx -y agent-work-layer-mcp` (same flags and environment variables).
|
|
9
|
+
- `import { createDeskServer } from "agent-work-layer/mcp"` → `from "agent-work-layer-mcp"`.
|
|
10
|
+
- `awl desk` now exits with code 2 and prints the new command.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Spec v0.2: optional `handoff` on Work Orders and Work Reports: decisions made, approaches tried, open questions and next step, so a job can move to another worker without starting over (SPEC.md §4.4). The MCP tools accept it too.
|
|
15
|
+
- `agent-work-layer/validate`: types, schemas and every check, with no Node built-ins. Runs in browsers, Deno and Bun.
|
|
16
|
+
- `ORDER_SPECS` and `REPORT_SPECS`: every spec version this package reads.
|
|
17
|
+
- `awl new order` and `awl new report` print starter documents that validate together as printed (#7, thanks @brunnojob).
|
|
18
|
+
- SPEC.md §13, Related work: Agent Contracts, A2A tasks, the IETF WIMSE cross-org delegation draft and KYA-OS / MCP-I.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- The repository is now an npm workspace: the core is in `packages/core`, the MCP server in `packages/mcp`. Published package contents are unchanged by this.
|
|
23
|
+
|
|
24
|
+
- The desk writes `awl/work-order@0.2` and `awl/work-report@0.2`. Documents marked `@0.1` are still accepted, so stored orders keep working.
|
|
25
|
+
- Schemas and the version number are built into the code (`packages/core/src/generated.ts`) instead of read from disk at startup.
|
|
26
|
+
|
|
3
27
|
## 0.1.1 — 2026-10-09
|
|
4
28
|
|
|
5
29
|
- Package metadata now links to the GitHub repository, homepage and issue tracker.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# agent-work-layer
|
|
2
2
|
|
|
3
|
-
**Work Orders and Work Reports for AI agents.** A typed SDK, validator
|
|
3
|
+
**Work Orders and Work Reports for AI agents.** A typed SDK, validator and lifecycle engine for handing work from one agent to another, with checkable results. The MCP server is a separate package, [`agent-work-layer-mcp`](packages/mcp/).
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/agent-work-layer)
|
|
6
6
|
[](LICENSE)
|
|
@@ -25,9 +25,13 @@ More diagrams: [message sequence](docs/sequence.svg) · [lifecycle](docs/lifecyc
|
|
|
25
25
|
|
|
26
26
|
## Install
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
Install only the part you use:
|
|
29
|
+
|
|
30
|
+
| You want to… | Install | Packages |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| Validate orders and reports, or run a desk in your code | `npm install agent-work-layer` | 7 |
|
|
33
|
+
| Validate in a browser, Deno or Bun | `npm install agent-work-layer`, then import `agent-work-layer/validate` | 7 |
|
|
34
|
+
| Connect agent sessions (e.g. Claude Code) through MCP | `npx -y agent-work-layer-mcp` ([setup](#run-as-an-mcp-server)) | ~100 |
|
|
31
35
|
|
|
32
36
|
Node.js 20.11 or later. ESM only. Types included.
|
|
33
37
|
|
|
@@ -84,6 +88,28 @@ The desk enforces the spec as you go:
|
|
|
84
88
|
- Cost within budget and finishing before the deadline. Going over either expires the order.
|
|
85
89
|
- Sub-orders can only narrow their parent's authority.
|
|
86
90
|
|
|
91
|
+
### Hand off unfinished work
|
|
92
|
+
|
|
93
|
+
When a worker fails, gets blocked or is cancelled, it can say what the next worker should know. The manager passes that along in the next order:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
await desk.submitReport(order.id, {
|
|
97
|
+
status: "failed",
|
|
98
|
+
error: "Export runs out of memory on files over 2 GB",
|
|
99
|
+
handoff: {
|
|
100
|
+
decisions: [{ text: "Stream rows instead of buffering", why: "Memory limit" }],
|
|
101
|
+
tried: [{ text: "xlsx library", result: "Too slow on large files" }],
|
|
102
|
+
next_step: "Add tests for null cells",
|
|
103
|
+
},
|
|
104
|
+
/* result, evidence, cost, tools_used */
|
|
105
|
+
}, "agent:researcher");
|
|
106
|
+
|
|
107
|
+
const { handoff } = (await desk.get(order.id)).reports.at(-1)!;
|
|
108
|
+
await desk.create({ ...nextJob, to: "agent:other-worker", handoff }, "agent:manager");
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`context` lists what to read; `handoff` says what was decided and already tried. See [SPEC.md §4.4](SPEC.md#44-handoff).
|
|
112
|
+
|
|
87
113
|
## Validate documents
|
|
88
114
|
|
|
89
115
|
```ts
|
|
@@ -98,23 +124,27 @@ Every finding carries the rule id from [SPEC.md §7](SPEC.md#7-checks). `invalid
|
|
|
98
124
|
|
|
99
125
|
The JSON Schemas are exported too: `workOrderSchema`, `workReportSchema`, or `agent-work-layer/schemas/work-order.schema.json`.
|
|
100
126
|
|
|
127
|
+
`agent-work-layer/validate` has the same checks, types and schemas without the desk. It imports nothing from Node, so it runs in browsers, Deno and Bun. (Cloudflare Workers are not supported: the validator compiles schemas to code at runtime, which Workers block.)
|
|
128
|
+
|
|
101
129
|
## Run as an MCP server
|
|
102
130
|
|
|
131
|
+
The server lives in its own package, [`agent-work-layer-mcp`](packages/mcp/), so people who only validate documents don't download the MCP SDK.
|
|
132
|
+
|
|
103
133
|
Each agent session runs its own desk process. Sessions share one folder, and each is locked to one identity, so a worker cannot approve its own work.
|
|
104
134
|
|
|
105
135
|
```sh
|
|
106
136
|
# Claude Code: a manager session and a worker session, each added in its own project folder
|
|
107
|
-
claude mcp add awl -e AWL_STORE="$HOME/.awl" -e AWL_ACTOR=agent:manager -- npx -y agent-work-layer
|
|
108
|
-
claude mcp add awl -e AWL_STORE="$HOME/.awl" -e AWL_ACTOR=agent:worker -- npx -y agent-work-layer
|
|
137
|
+
claude mcp add awl -e AWL_STORE="$HOME/.awl" -e AWL_ACTOR=agent:manager -- npx -y agent-work-layer-mcp
|
|
138
|
+
claude mcp add awl -e AWL_STORE="$HOME/.awl" -e AWL_ACTOR=agent:worker -- npx -y agent-work-layer-mcp
|
|
109
139
|
```
|
|
110
140
|
|
|
111
141
|
Tools: `create_work_order`, `list_work_orders`, `get_work_order`, `accept_work_order`, `decline_work_order`, `start_work_order`, `submit_work_report`, `answer_question`, `review_work_report`, `cancel_work_order`, `wait_for_update`.
|
|
112
142
|
|
|
113
|
-
To embed the server in your own process or transport:
|
|
143
|
+
To embed the server in your own process or transport (`npm install agent-work-layer agent-work-layer-mcp`):
|
|
114
144
|
|
|
115
145
|
```ts
|
|
116
146
|
import { WorkDesk, FileStore } from "agent-work-layer";
|
|
117
|
-
import { createDeskServer } from "agent-work-layer
|
|
147
|
+
import { createDeskServer } from "agent-work-layer-mcp";
|
|
118
148
|
|
|
119
149
|
const server = createDeskServer({ desk: new WorkDesk({ store: new FileStore("./.awl") }), actor: "agent:manager" });
|
|
120
150
|
await server.connect(transport);
|
|
@@ -123,13 +153,21 @@ await server.connect(transport);
|
|
|
123
153
|
## CLI
|
|
124
154
|
|
|
125
155
|
```sh
|
|
156
|
+
npx agent-work-layer new order > order.json
|
|
157
|
+
npx agent-work-layer new report > report.json
|
|
126
158
|
npx agent-work-layer validate order.json report.json # exit 1 on invalid, prints rule ids
|
|
127
159
|
npx agent-work-layer validate child.json --parent order.json
|
|
128
160
|
npx agent-work-layer validate order.json report.json --json
|
|
129
161
|
npx agent-work-layer schema order
|
|
130
|
-
npx agent-work-layer
|
|
162
|
+
npx -y agent-work-layer-mcp --store ./.awl --actor agent:worker # the MCP desk (was "awl desk" before 0.2)
|
|
131
163
|
```
|
|
132
164
|
|
|
165
|
+
`new order` starts with one criterion, a USD 1 budget, no allowed tools and a
|
|
166
|
+
deadline one hour after creation. `new report` starts as `blocked`, with a question
|
|
167
|
+
and no evidence of completed work. Both templates validate together as printed.
|
|
168
|
+
Replace the placeholder goal, identities, criterion and report contents before
|
|
169
|
+
using them; keep the report's `order_id` equal to the order's `id`.
|
|
170
|
+
|
|
133
171
|
## Lifecycle
|
|
134
172
|
|
|
135
173
|
```
|
|
@@ -160,7 +198,8 @@ Any active state ──cancel──▶ cancelled · deadline or budget excee
|
|
|
160
198
|
| `toolAllowed`, `patternCovered` | Tool pattern matching |
|
|
161
199
|
| `nextState`, `allowedActions`, `STATES`, `ROLE_FOR`, `isTerminal` | The state machine |
|
|
162
200
|
| `AwlError`, `isAwlError` | Typed errors with `code` and `findings` |
|
|
163
|
-
| `
|
|
201
|
+
| `ORDER_SPEC`, `REPORT_SPEC`, `ORDER_SPECS`, `REPORT_SPECS` | The spec version written, and every version read |
|
|
202
|
+
| `createDeskServer` (from `agent-work-layer-mcp`) | MCP server for a desk |
|
|
164
203
|
|
|
165
204
|
`WorkDesk` options: `store`, `clock` (for tests), `newId`, `onEvent(event, record)` (webhooks, logging, metrics).
|
|
166
205
|
|
|
@@ -187,13 +226,16 @@ The desk trusts the `actor` it is given. In production, derive the actor from au
|
|
|
187
226
|
|
|
188
227
|
## Development
|
|
189
228
|
|
|
229
|
+
The repo is an npm workspace with two packages: the core in [`packages/core`](packages/core/) and the MCP server in [`packages/mcp`](packages/mcp/). The spec, schemas and examples stay at the root; the core copies them in when it is packed.
|
|
230
|
+
|
|
190
231
|
```sh
|
|
191
232
|
npm install
|
|
192
|
-
npm test #
|
|
233
|
+
npm test # core and MCP tests (builds the core first)
|
|
193
234
|
npm run test:coverage
|
|
194
235
|
npm run typecheck
|
|
195
|
-
npm run test:package #
|
|
236
|
+
npm run test:package # packs both packages, installs them in clean projects and uses them
|
|
196
237
|
npm run check # all of the above; runs automatically before npm publish
|
|
238
|
+
npm run generate # after editing schemas/*.json: refreshes packages/core/src/generated.ts
|
|
197
239
|
```
|
|
198
240
|
|
|
199
241
|
## Contributing
|
package/SPEC.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Agent Work Layer (AWL) — Specification v0.
|
|
1
|
+
# Agent Work Layer (AWL) — Specification v0.2 (draft)
|
|
2
2
|
|
|
3
|
-
Status: draft · Date: 2026-10-09
|
|
3
|
+
Status: draft · Date: 2026-10-09 · Changes from v0.1: the optional `handoff` field (§4.4); readers accept both versions (§11); related work (§13).
|
|
4
4
|
|
|
5
5
|
## 1. Purpose
|
|
6
6
|
|
|
@@ -39,7 +39,7 @@ The key words MUST, SHOULD and MAY are used as in RFC 2119.
|
|
|
39
39
|
|
|
40
40
|
| Field | Req | Type | Meaning |
|
|
41
41
|
|----------------|-----|---------------------|---------|
|
|
42
|
-
| `spec` | yes | `"awl/work-order@0.
|
|
42
|
+
| `spec` | yes | `"awl/work-order@0.2"` | Format and version. Readers also accept `@0.1` (§11). |
|
|
43
43
|
| `id` | yes | string | Unique job id, set by the desk or manager. |
|
|
44
44
|
| `created_at` | yes | timestamp | When the order was issued. |
|
|
45
45
|
| `from` | yes | agent ref | The manager. |
|
|
@@ -52,6 +52,7 @@ The key words MUST, SHOULD and MAY are used as in RFC 2119.
|
|
|
52
52
|
| `escalate_to` | no | agent ref | Who to ask when blocked. Default: `from`. |
|
|
53
53
|
| `inputs` | no | object | Structured inputs for the job. |
|
|
54
54
|
| `context` | no | array of `{uri, note?}` | Pointers to material the worker should read. |
|
|
55
|
+
| `handoff` | no | Handoff (§4.4) | What earlier work on this job established. |
|
|
55
56
|
| `output_schema`| no | JSON Schema | Shape that `result.output` MUST match when done. |
|
|
56
57
|
| `parent_id` | no | string | Set when this order was split from a larger one (§8). |
|
|
57
58
|
| `metadata` | no | object | Free-form; ignored by checks. |
|
|
@@ -77,11 +78,35 @@ A Budget is an object with at least one of these units. Cost (in the report) use
|
|
|
77
78
|
A tool is named `<server>/<tool>`, where `<server>` is the MCP server name as the worker knows it.
|
|
78
79
|
Patterns: `server/tool` (exactly one tool), `server/*` (every tool on that server), `*` (any tool).
|
|
79
80
|
|
|
81
|
+
### 4.4 Handoff
|
|
82
|
+
|
|
83
|
+
When a job moves from one worker to another (after a failure, a cancellation or a block), the next worker should not start from nothing. `context` says what to read; `handoff` says what was decided, what was already tried, and where things stand.
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
"handoff": {
|
|
87
|
+
"summary": "Parser done; export fails on files over 2 GB",
|
|
88
|
+
"decisions": [{ "text": "Stream rows instead of buffering", "why": "Memory limit" }],
|
|
89
|
+
"tried": [{ "text": "xlsx library", "result": "Too slow on large files" }],
|
|
90
|
+
"open_questions": ["Quote style for commas?"],
|
|
91
|
+
"next_step": "Add tests for null cells"
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
| Field | Type | Meaning |
|
|
96
|
+
|------------------|-------------------------------|---------|
|
|
97
|
+
| `summary` | string | Where the work stands. |
|
|
98
|
+
| `decisions` | array of `{text, why?}` | Choices already made, and why. The next worker SHOULD keep them unless it has a reason not to. |
|
|
99
|
+
| `tried` | array of `{text, result?}` | Approaches already attempted and what happened, so they are not repeated. |
|
|
100
|
+
| `open_questions` | array of string | Questions still unanswered. |
|
|
101
|
+
| `next_step` | string | The most useful thing to do next. |
|
|
102
|
+
|
|
103
|
+
Every field is optional, but a handoff MUST NOT be empty. A Work Report MAY carry a handoff (§5); a worker SHOULD include one when it reports `failed` or `blocked`. A manager reissuing the job MAY copy it, edited or not, into the new order. Handoff content is the previous worker's account, not verified fact; it is not checked against evidence.
|
|
104
|
+
|
|
80
105
|
## 5. Work Report
|
|
81
106
|
|
|
82
107
|
| Field | Req | Type | Meaning |
|
|
83
108
|
|---------------|-----|-------------------------|---------|
|
|
84
|
-
| `spec` | yes | `"awl/work-report@0.
|
|
109
|
+
| `spec` | yes | `"awl/work-report@0.2"` | Format and version. Readers also accept `@0.1` (§11). |
|
|
85
110
|
| `order_id` | yes | string | The order this answers. |
|
|
86
111
|
| `from` | yes | agent ref | The worker. |
|
|
87
112
|
| `status` | yes | `done` \| `blocked` \| `failed` | Outcome of this attempt. |
|
|
@@ -94,6 +119,7 @@ Patterns: `server/tool` (exactly one tool), `server/*` (every tool on that serve
|
|
|
94
119
|
| `attempt` | no | integer ≥ 1 | 1 for the first report, +1 after each rework. |
|
|
95
120
|
| `questions` | no | array of string | Open questions. Required when `blocked`. |
|
|
96
121
|
| `error` | no | string | What went wrong. Required when `failed`. |
|
|
122
|
+
| `handoff` | no | Handoff (§4.4) | What whoever continues this job should know. |
|
|
97
123
|
| `metadata` | no | object | Free-form. |
|
|
98
124
|
|
|
99
125
|
### 5.1 Evidence
|
|
@@ -184,7 +210,7 @@ A desk MUST reject a child order that breaks C1–C3. The parent's reported cost
|
|
|
184
210
|
How AWL documents travel. A desk MAY support several.
|
|
185
211
|
|
|
186
212
|
- **Files**: `<id>.order.json` and `<id>.report.json` side by side. Good for tests and audit archives.
|
|
187
|
-
- **MCP**: a desk exposed as an MCP server with tools such as `create_work_order`, `submit_work_report` and `review_work_report`. The reference implementation
|
|
213
|
+
- **MCP**: a desk exposed as an MCP server with tools such as `create_work_order`, `submit_work_report` and `review_work_report`. The reference implementation is the `agent-work-layer-mcp` package in this repo.
|
|
188
214
|
- **A2A**: the document travels as a data part of an A2A message with the AWL media type. The A2A task id SHOULD be stored in `metadata.a2a_task_id`.
|
|
189
215
|
|
|
190
216
|
## 10. Security
|
|
@@ -197,8 +223,21 @@ How AWL documents travel. A desk MAY support several.
|
|
|
197
223
|
|
|
198
224
|
`spec` carries the version. Minor versions (0.x) may add optional fields only. Readers MUST reject a major version they do not know.
|
|
199
225
|
|
|
226
|
+
A v0.2 reader MUST accept documents marked `@0.1` and `@0.2`, and MUST reject any other version. A v0.2 writer marks new documents `@0.2`. Every v0.1 document is a valid v0.2 document once its version is accepted.
|
|
227
|
+
|
|
200
228
|
## 12. Planned for later versions
|
|
201
229
|
|
|
202
230
|
- Delegation Pass: a signed, standalone grant of budget, tools and time.
|
|
203
231
|
- Track record: an aggregate of approved reports per worker.
|
|
204
232
|
- Streaming progress events while `working`.
|
|
233
|
+
|
|
234
|
+
## 13. Related work
|
|
235
|
+
|
|
236
|
+
AWL overlaps with these efforts and is meant to work alongside them.
|
|
237
|
+
|
|
238
|
+
| Work | What it covers | How AWL relates |
|
|
239
|
+
|------|----------------|-----------------|
|
|
240
|
+
| Agent Contracts (Ye and Tan, 2026, [arXiv:2601.08815](https://arxiv.org/abs/2601.08815)) | A formal model of resource-bounded agents: budgets, deadlines, weighted success criteria, and sub-contracts whose budgets may not exceed the parent's. | Close in intent. AWL is a wire format (JSON documents, JSON Schemas, numbered checks) with evidence per criterion, separate manager and worker roles, and review. Its sub-order rules (§8) are the same conservation idea. |
|
|
241
|
+
| A2A tasks ([a2a-protocol.org](https://a2a-protocol.org)) | Task lifecycle and message transport between agents. | AWL describes the job and its proof; the A2A binding (§9) carries AWL documents inside A2A messages. |
|
|
242
|
+
| IETF [draft-reece-wimse-cross-org-delegation](https://datatracker.ietf.org/doc/draft-reece-wimse-cross-org-delegation/) | Requirements for authority that can only narrow at each delegation hop, verifiable across organizations. | Same principle as §8. Input for the planned Delegation Pass (§12). |
|
|
243
|
+
| KYA-OS / MCP-I ([@kya-os/mcp](https://www.npmjs.com/package/@kya-os/mcp)) | Agent identity, delegation credentials and verifiable audit for MCP servers. | Identifies the actor, not the job. A desk can use such credentials to meet §10's requirement to authenticate `actor`. |
|
package/dist/cli.js
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { parseArgs } from "node:util";
|
|
4
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
-
import { WorkDesk } from "./desk.js";
|
|
6
|
-
import { createDeskServer } from "./mcp.js";
|
|
7
|
-
import { FileStore } from "./store.js";
|
|
8
4
|
import { hasInvalid, validateChildOrder, validateOrder, validateReport, workOrderSchema, workReportSchema } from "./validate.js";
|
|
5
|
+
import { ORDER_SPEC, REPORT_SPEC } from "./types.js";
|
|
9
6
|
import { VERSION } from "./version.js";
|
|
10
7
|
const HELP = `awl ${VERSION} — Agent Work Layer
|
|
11
8
|
|
|
12
9
|
Usage:
|
|
13
10
|
awl validate <order.json> [report.json] [--parent <parent-order.json>] [--json]
|
|
14
|
-
awl desk [--store <dir>] [--actor <agent-ref>] Run the desk as an MCP server on stdio
|
|
15
11
|
awl schema <order|report> Print a JSON Schema
|
|
12
|
+
awl new <order|report> Print a starter document
|
|
16
13
|
awl --version | --help
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
The MCP desk server is a separate package: npx -y agent-work-layer-mcp
|
|
19
16
|
Exit codes: 0 ok, 1 invalid document, 2 usage or file error.`;
|
|
20
17
|
function readJson(path) {
|
|
21
18
|
try {
|
|
@@ -27,6 +24,38 @@ function readJson(path) {
|
|
|
27
24
|
}
|
|
28
25
|
class UsageError extends Error {
|
|
29
26
|
}
|
|
27
|
+
function newDocument(args) {
|
|
28
|
+
const [which] = args;
|
|
29
|
+
if (args.length !== 1 || (which !== "order" && which !== "report")) {
|
|
30
|
+
throw new UsageError('new needs "order" or "report"');
|
|
31
|
+
}
|
|
32
|
+
const now = new Date();
|
|
33
|
+
const document = which === "order" ? {
|
|
34
|
+
spec: ORDER_SPEC,
|
|
35
|
+
id: "wo_example",
|
|
36
|
+
created_at: now.toISOString(),
|
|
37
|
+
from: "agent:manager",
|
|
38
|
+
to: "agent:worker",
|
|
39
|
+
goal: "Replace with the work to be done",
|
|
40
|
+
criteria: [{ id: "c1", text: "Replace with a checkable acceptance criterion" }],
|
|
41
|
+
budget: { usd: 1 },
|
|
42
|
+
deadline: new Date(now.getTime() + 3_600_000).toISOString(),
|
|
43
|
+
tools: [],
|
|
44
|
+
} : {
|
|
45
|
+
spec: REPORT_SPEC,
|
|
46
|
+
order_id: "wo_example",
|
|
47
|
+
from: "agent:worker",
|
|
48
|
+
status: "blocked",
|
|
49
|
+
result: { summary: "Replace with the work performed so far" },
|
|
50
|
+
evidence: [],
|
|
51
|
+
cost: { usd: 0 },
|
|
52
|
+
finished_at: now.toISOString(),
|
|
53
|
+
tools_used: [],
|
|
54
|
+
questions: ["What work should be completed for criterion c1?"],
|
|
55
|
+
};
|
|
56
|
+
console.log(JSON.stringify(document, null, 2));
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
30
59
|
function validate(args) {
|
|
31
60
|
const { values, positionals } = parseArgs({ args, allowPositionals: true, options: { parent: { type: "string" }, json: { type: "boolean" } } });
|
|
32
61
|
const [orderPath, reportPath] = positionals;
|
|
@@ -58,20 +87,15 @@ function validate(args) {
|
|
|
58
87
|
}
|
|
59
88
|
return failed ? 1 : 0;
|
|
60
89
|
}
|
|
61
|
-
|
|
62
|
-
const { values } = parseArgs({ args, options: { store: { type: "string" }, actor: { type: "string" } } });
|
|
63
|
-
const store = new FileStore(values.store ?? process.env.AWL_STORE ?? ".awl");
|
|
64
|
-
const server = createDeskServer({ desk: new WorkDesk({ store }), actor: values.actor ?? process.env.AWL_ACTOR });
|
|
65
|
-
await server.connect(new StdioServerTransport());
|
|
66
|
-
}
|
|
67
|
-
async function main(argv) {
|
|
90
|
+
function main(argv) {
|
|
68
91
|
const [command, ...rest] = argv;
|
|
69
92
|
switch (command) {
|
|
93
|
+
case "new":
|
|
94
|
+
return newDocument(rest);
|
|
70
95
|
case "validate":
|
|
71
96
|
return validate(rest);
|
|
72
97
|
case "desk":
|
|
73
|
-
|
|
74
|
-
return undefined; // keep running
|
|
98
|
+
throw new UsageError('"awl desk" moved to its own package in 0.2.0. Run: npx -y agent-work-layer-mcp --store <dir> --actor <agent-ref>');
|
|
75
99
|
case "schema": {
|
|
76
100
|
const which = rest[0];
|
|
77
101
|
if (which !== "order" && which !== "report")
|
|
@@ -92,10 +116,10 @@ async function main(argv) {
|
|
|
92
116
|
throw new UsageError(`unknown command "${command}"`);
|
|
93
117
|
}
|
|
94
118
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
119
|
+
try {
|
|
120
|
+
process.exitCode = main(process.argv.slice(2));
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
99
123
|
console.error(e instanceof UsageError ? `awl: ${e.message}\n\n${HELP}` : e);
|
|
100
124
|
process.exitCode = 2;
|
|
101
|
-
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** This package's version. */
|
|
2
|
+
export declare const VERSION: string;
|
|
3
|
+
/** The Work Order JSON Schema (schemas/work-order.schema.json). */
|
|
4
|
+
export declare const workOrderSchema: Record<string, unknown>;
|
|
5
|
+
/** The Work Report JSON Schema (schemas/work-report.schema.json). */
|
|
6
|
+
export declare const workReportSchema: Record<string, unknown>;
|
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
// Generated by scripts/generate.ts from package.json and schemas/*.json. Do not edit.
|
|
2
|
+
/** This package's version. */
|
|
3
|
+
export const VERSION = "0.2.0";
|
|
4
|
+
/** The Work Order JSON Schema (schemas/work-order.schema.json). */
|
|
5
|
+
export const workOrderSchema = {
|
|
6
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
7
|
+
"$id": "https://awl.dev/schemas/work-order-0.2.json",
|
|
8
|
+
"title": "AWL Work Order v0.2",
|
|
9
|
+
"type": "object",
|
|
10
|
+
"required": [
|
|
11
|
+
"spec",
|
|
12
|
+
"id",
|
|
13
|
+
"created_at",
|
|
14
|
+
"from",
|
|
15
|
+
"to",
|
|
16
|
+
"goal",
|
|
17
|
+
"criteria",
|
|
18
|
+
"budget",
|
|
19
|
+
"deadline",
|
|
20
|
+
"tools"
|
|
21
|
+
],
|
|
22
|
+
"properties": {
|
|
23
|
+
"spec": {
|
|
24
|
+
"enum": [
|
|
25
|
+
"awl/work-order@0.1",
|
|
26
|
+
"awl/work-order@0.2"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"id": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"minLength": 1,
|
|
32
|
+
"maxLength": 128
|
|
33
|
+
},
|
|
34
|
+
"created_at": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"format": "date-time"
|
|
37
|
+
},
|
|
38
|
+
"from": {
|
|
39
|
+
"$ref": "#/$defs/agentRef"
|
|
40
|
+
},
|
|
41
|
+
"to": {
|
|
42
|
+
"$ref": "#/$defs/agentRef"
|
|
43
|
+
},
|
|
44
|
+
"goal": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"minLength": 1
|
|
47
|
+
},
|
|
48
|
+
"criteria": {
|
|
49
|
+
"type": "array",
|
|
50
|
+
"minItems": 1,
|
|
51
|
+
"items": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"required": [
|
|
54
|
+
"id",
|
|
55
|
+
"text"
|
|
56
|
+
],
|
|
57
|
+
"properties": {
|
|
58
|
+
"id": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"minLength": 1,
|
|
61
|
+
"maxLength": 64
|
|
62
|
+
},
|
|
63
|
+
"text": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"minLength": 1
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"additionalProperties": false
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"budget": {
|
|
72
|
+
"$ref": "#/$defs/amounts",
|
|
73
|
+
"minProperties": 1
|
|
74
|
+
},
|
|
75
|
+
"deadline": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"format": "date-time"
|
|
78
|
+
},
|
|
79
|
+
"tools": {
|
|
80
|
+
"type": "array",
|
|
81
|
+
"items": {
|
|
82
|
+
"$ref": "#/$defs/toolPattern"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"escalate_to": {
|
|
86
|
+
"$ref": "#/$defs/agentRef"
|
|
87
|
+
},
|
|
88
|
+
"inputs": {
|
|
89
|
+
"type": "object"
|
|
90
|
+
},
|
|
91
|
+
"context": {
|
|
92
|
+
"type": "array",
|
|
93
|
+
"items": {
|
|
94
|
+
"type": "object",
|
|
95
|
+
"required": [
|
|
96
|
+
"uri"
|
|
97
|
+
],
|
|
98
|
+
"properties": {
|
|
99
|
+
"uri": {
|
|
100
|
+
"type": "string",
|
|
101
|
+
"minLength": 1
|
|
102
|
+
},
|
|
103
|
+
"note": {
|
|
104
|
+
"type": "string"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"additionalProperties": false
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"handoff": {
|
|
111
|
+
"$ref": "#/$defs/handoff"
|
|
112
|
+
},
|
|
113
|
+
"output_schema": {
|
|
114
|
+
"type": "object"
|
|
115
|
+
},
|
|
116
|
+
"parent_id": {
|
|
117
|
+
"type": "string",
|
|
118
|
+
"minLength": 1
|
|
119
|
+
},
|
|
120
|
+
"metadata": {
|
|
121
|
+
"type": "object"
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"patternProperties": {
|
|
125
|
+
"^x-": {}
|
|
126
|
+
},
|
|
127
|
+
"additionalProperties": false,
|
|
128
|
+
"$defs": {
|
|
129
|
+
"agentRef": {
|
|
130
|
+
"type": "string",
|
|
131
|
+
"minLength": 1,
|
|
132
|
+
"maxLength": 512
|
|
133
|
+
},
|
|
134
|
+
"toolPattern": {
|
|
135
|
+
"type": "string",
|
|
136
|
+
"pattern": "^(\\*|[A-Za-z0-9_.-]+/(\\*|[A-Za-z0-9_.-]+))$"
|
|
137
|
+
},
|
|
138
|
+
"amounts": {
|
|
139
|
+
"type": "object",
|
|
140
|
+
"properties": {
|
|
141
|
+
"usd": {
|
|
142
|
+
"type": "number",
|
|
143
|
+
"minimum": 0
|
|
144
|
+
},
|
|
145
|
+
"tokens": {
|
|
146
|
+
"type": "integer",
|
|
147
|
+
"minimum": 0
|
|
148
|
+
},
|
|
149
|
+
"tool_calls": {
|
|
150
|
+
"type": "integer",
|
|
151
|
+
"minimum": 0
|
|
152
|
+
},
|
|
153
|
+
"seconds": {
|
|
154
|
+
"type": "number",
|
|
155
|
+
"minimum": 0
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"additionalProperties": false
|
|
159
|
+
},
|
|
160
|
+
"handoff": {
|
|
161
|
+
"type": "object",
|
|
162
|
+
"minProperties": 1,
|
|
163
|
+
"properties": {
|
|
164
|
+
"summary": {
|
|
165
|
+
"type": "string",
|
|
166
|
+
"minLength": 1
|
|
167
|
+
},
|
|
168
|
+
"decisions": {
|
|
169
|
+
"type": "array",
|
|
170
|
+
"items": {
|
|
171
|
+
"type": "object",
|
|
172
|
+
"required": [
|
|
173
|
+
"text"
|
|
174
|
+
],
|
|
175
|
+
"properties": {
|
|
176
|
+
"text": {
|
|
177
|
+
"type": "string",
|
|
178
|
+
"minLength": 1
|
|
179
|
+
},
|
|
180
|
+
"why": {
|
|
181
|
+
"type": "string"
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
"additionalProperties": false
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
"tried": {
|
|
188
|
+
"type": "array",
|
|
189
|
+
"items": {
|
|
190
|
+
"type": "object",
|
|
191
|
+
"required": [
|
|
192
|
+
"text"
|
|
193
|
+
],
|
|
194
|
+
"properties": {
|
|
195
|
+
"text": {
|
|
196
|
+
"type": "string",
|
|
197
|
+
"minLength": 1
|
|
198
|
+
},
|
|
199
|
+
"result": {
|
|
200
|
+
"type": "string"
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
"additionalProperties": false
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"open_questions": {
|
|
207
|
+
"type": "array",
|
|
208
|
+
"items": {
|
|
209
|
+
"type": "string",
|
|
210
|
+
"minLength": 1
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
"next_step": {
|
|
214
|
+
"type": "string",
|
|
215
|
+
"minLength": 1
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
"additionalProperties": false
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
/** The Work Report JSON Schema (schemas/work-report.schema.json). */
|
|
223
|
+
export const workReportSchema = {
|
|
224
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
225
|
+
"$id": "https://awl.dev/schemas/work-report-0.2.json",
|
|
226
|
+
"title": "AWL Work Report v0.2",
|
|
227
|
+
"type": "object",
|
|
228
|
+
"required": [
|
|
229
|
+
"spec",
|
|
230
|
+
"order_id",
|
|
231
|
+
"from",
|
|
232
|
+
"status",
|
|
233
|
+
"result",
|
|
234
|
+
"evidence",
|
|
235
|
+
"cost",
|
|
236
|
+
"finished_at",
|
|
237
|
+
"tools_used"
|
|
238
|
+
],
|
|
239
|
+
"properties": {
|
|
240
|
+
"spec": {
|
|
241
|
+
"enum": [
|
|
242
|
+
"awl/work-report@0.1",
|
|
243
|
+
"awl/work-report@0.2"
|
|
244
|
+
]
|
|
245
|
+
},
|
|
246
|
+
"order_id": {
|
|
247
|
+
"type": "string",
|
|
248
|
+
"minLength": 1
|
|
249
|
+
},
|
|
250
|
+
"from": {
|
|
251
|
+
"type": "string",
|
|
252
|
+
"minLength": 1,
|
|
253
|
+
"maxLength": 512
|
|
254
|
+
},
|
|
255
|
+
"status": {
|
|
256
|
+
"enum": [
|
|
257
|
+
"done",
|
|
258
|
+
"blocked",
|
|
259
|
+
"failed"
|
|
260
|
+
]
|
|
261
|
+
},
|
|
262
|
+
"result": {
|
|
263
|
+
"type": "object",
|
|
264
|
+
"required": [
|
|
265
|
+
"summary"
|
|
266
|
+
],
|
|
267
|
+
"properties": {
|
|
268
|
+
"summary": {
|
|
269
|
+
"type": "string"
|
|
270
|
+
},
|
|
271
|
+
"output": {},
|
|
272
|
+
"artifacts": {
|
|
273
|
+
"type": "array",
|
|
274
|
+
"items": {
|
|
275
|
+
"type": "object",
|
|
276
|
+
"required": [
|
|
277
|
+
"uri"
|
|
278
|
+
],
|
|
279
|
+
"properties": {
|
|
280
|
+
"uri": {
|
|
281
|
+
"type": "string",
|
|
282
|
+
"minLength": 1
|
|
283
|
+
},
|
|
284
|
+
"media_type": {
|
|
285
|
+
"type": "string"
|
|
286
|
+
},
|
|
287
|
+
"note": {
|
|
288
|
+
"type": "string"
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
"additionalProperties": false
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
"additionalProperties": false
|
|
296
|
+
},
|
|
297
|
+
"evidence": {
|
|
298
|
+
"type": "array",
|
|
299
|
+
"items": {
|
|
300
|
+
"type": "object",
|
|
301
|
+
"required": [
|
|
302
|
+
"criterion",
|
|
303
|
+
"type"
|
|
304
|
+
],
|
|
305
|
+
"properties": {
|
|
306
|
+
"criterion": {
|
|
307
|
+
"type": "string",
|
|
308
|
+
"minLength": 1
|
|
309
|
+
},
|
|
310
|
+
"type": {
|
|
311
|
+
"enum": [
|
|
312
|
+
"tool_call",
|
|
313
|
+
"artifact",
|
|
314
|
+
"citation",
|
|
315
|
+
"note"
|
|
316
|
+
]
|
|
317
|
+
},
|
|
318
|
+
"ref": {
|
|
319
|
+
"type": "string"
|
|
320
|
+
},
|
|
321
|
+
"note": {
|
|
322
|
+
"type": "string"
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
"additionalProperties": false
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
"cost": {
|
|
329
|
+
"type": "object",
|
|
330
|
+
"properties": {
|
|
331
|
+
"usd": {
|
|
332
|
+
"type": "number",
|
|
333
|
+
"minimum": 0
|
|
334
|
+
},
|
|
335
|
+
"tokens": {
|
|
336
|
+
"type": "integer",
|
|
337
|
+
"minimum": 0
|
|
338
|
+
},
|
|
339
|
+
"tool_calls": {
|
|
340
|
+
"type": "integer",
|
|
341
|
+
"minimum": 0
|
|
342
|
+
},
|
|
343
|
+
"seconds": {
|
|
344
|
+
"type": "number",
|
|
345
|
+
"minimum": 0
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
"additionalProperties": false
|
|
349
|
+
},
|
|
350
|
+
"started_at": {
|
|
351
|
+
"type": "string",
|
|
352
|
+
"format": "date-time"
|
|
353
|
+
},
|
|
354
|
+
"finished_at": {
|
|
355
|
+
"type": "string",
|
|
356
|
+
"format": "date-time"
|
|
357
|
+
},
|
|
358
|
+
"tools_used": {
|
|
359
|
+
"type": "array",
|
|
360
|
+
"items": {
|
|
361
|
+
"type": "string",
|
|
362
|
+
"pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$"
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
"attempt": {
|
|
366
|
+
"type": "integer",
|
|
367
|
+
"minimum": 1
|
|
368
|
+
},
|
|
369
|
+
"questions": {
|
|
370
|
+
"type": "array",
|
|
371
|
+
"items": {
|
|
372
|
+
"type": "string",
|
|
373
|
+
"minLength": 1
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
"error": {
|
|
377
|
+
"type": "string",
|
|
378
|
+
"minLength": 1
|
|
379
|
+
},
|
|
380
|
+
"handoff": {
|
|
381
|
+
"$ref": "#/$defs/handoff"
|
|
382
|
+
},
|
|
383
|
+
"metadata": {
|
|
384
|
+
"type": "object"
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
"patternProperties": {
|
|
388
|
+
"^x-": {}
|
|
389
|
+
},
|
|
390
|
+
"additionalProperties": false,
|
|
391
|
+
"$defs": {
|
|
392
|
+
"handoff": {
|
|
393
|
+
"type": "object",
|
|
394
|
+
"minProperties": 1,
|
|
395
|
+
"properties": {
|
|
396
|
+
"summary": {
|
|
397
|
+
"type": "string",
|
|
398
|
+
"minLength": 1
|
|
399
|
+
},
|
|
400
|
+
"decisions": {
|
|
401
|
+
"type": "array",
|
|
402
|
+
"items": {
|
|
403
|
+
"type": "object",
|
|
404
|
+
"required": [
|
|
405
|
+
"text"
|
|
406
|
+
],
|
|
407
|
+
"properties": {
|
|
408
|
+
"text": {
|
|
409
|
+
"type": "string",
|
|
410
|
+
"minLength": 1
|
|
411
|
+
},
|
|
412
|
+
"why": {
|
|
413
|
+
"type": "string"
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
"additionalProperties": false
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
"tried": {
|
|
420
|
+
"type": "array",
|
|
421
|
+
"items": {
|
|
422
|
+
"type": "object",
|
|
423
|
+
"required": [
|
|
424
|
+
"text"
|
|
425
|
+
],
|
|
426
|
+
"properties": {
|
|
427
|
+
"text": {
|
|
428
|
+
"type": "string",
|
|
429
|
+
"minLength": 1
|
|
430
|
+
},
|
|
431
|
+
"result": {
|
|
432
|
+
"type": "string"
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
"additionalProperties": false
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
"open_questions": {
|
|
439
|
+
"type": "array",
|
|
440
|
+
"items": {
|
|
441
|
+
"type": "string",
|
|
442
|
+
"minLength": 1
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
"next_step": {
|
|
446
|
+
"type": "string",
|
|
447
|
+
"minLength": 1
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
"additionalProperties": false
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
/** Document types for AWL v0.
|
|
2
|
-
|
|
3
|
-
export declare const
|
|
1
|
+
/** Document types for AWL v0.2. Field meanings are defined in SPEC.md §4 and §5. */
|
|
2
|
+
/** The spec version this package writes. */
|
|
3
|
+
export declare const ORDER_SPEC = "awl/work-order@0.2";
|
|
4
|
+
export declare const REPORT_SPEC = "awl/work-report@0.2";
|
|
5
|
+
/** Every spec version this package reads (SPEC.md §11). */
|
|
6
|
+
export declare const ORDER_SPECS: readonly ["awl/work-order@0.1", "awl/work-order@0.2"];
|
|
7
|
+
export declare const REPORT_SPECS: readonly ["awl/work-report@0.1", "awl/work-report@0.2"];
|
|
4
8
|
/** An Agent Card URL, an agent name, or `human:<id>`. */
|
|
5
9
|
export type AgentRef = string;
|
|
6
10
|
/** Budget and cost units (SPEC.md §4.2). */
|
|
@@ -15,8 +19,22 @@ export interface ContextRef {
|
|
|
15
19
|
uri: string;
|
|
16
20
|
note?: string;
|
|
17
21
|
}
|
|
22
|
+
/** What the next worker should know: decisions, dead ends and where work stands (SPEC.md §4.4). */
|
|
23
|
+
export interface Handoff {
|
|
24
|
+
summary?: string;
|
|
25
|
+
decisions?: {
|
|
26
|
+
text: string;
|
|
27
|
+
why?: string;
|
|
28
|
+
}[];
|
|
29
|
+
tried?: {
|
|
30
|
+
text: string;
|
|
31
|
+
result?: string;
|
|
32
|
+
}[];
|
|
33
|
+
open_questions?: string[];
|
|
34
|
+
next_step?: string;
|
|
35
|
+
}
|
|
18
36
|
export interface WorkOrder {
|
|
19
|
-
spec: typeof
|
|
37
|
+
spec: (typeof ORDER_SPECS)[number];
|
|
20
38
|
id: string;
|
|
21
39
|
created_at: string;
|
|
22
40
|
from: AgentRef;
|
|
@@ -30,6 +48,7 @@ export interface WorkOrder {
|
|
|
30
48
|
escalate_to?: AgentRef;
|
|
31
49
|
inputs?: Record<string, unknown>;
|
|
32
50
|
context?: ContextRef[];
|
|
51
|
+
handoff?: Handoff;
|
|
33
52
|
output_schema?: Record<string, unknown>;
|
|
34
53
|
parent_id?: string;
|
|
35
54
|
metadata?: Record<string, unknown>;
|
|
@@ -54,7 +73,7 @@ export interface WorkResult {
|
|
|
54
73
|
artifacts?: Artifact[];
|
|
55
74
|
}
|
|
56
75
|
export interface WorkReport {
|
|
57
|
-
spec: typeof
|
|
76
|
+
spec: (typeof REPORT_SPECS)[number];
|
|
58
77
|
order_id: string;
|
|
59
78
|
from: AgentRef;
|
|
60
79
|
status: ReportStatus;
|
|
@@ -68,6 +87,7 @@ export interface WorkReport {
|
|
|
68
87
|
attempt?: number;
|
|
69
88
|
questions?: string[];
|
|
70
89
|
error?: string;
|
|
90
|
+
handoff?: Handoff;
|
|
71
91
|
metadata?: Record<string, unknown>;
|
|
72
92
|
[extension: `x-${string}`]: unknown;
|
|
73
93
|
}
|
package/dist/types.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
/** Document types for AWL v0.
|
|
2
|
-
|
|
3
|
-
export const
|
|
1
|
+
/** Document types for AWL v0.2. Field meanings are defined in SPEC.md §4 and §5. */
|
|
2
|
+
/** The spec version this package writes. */
|
|
3
|
+
export const ORDER_SPEC = "awl/work-order@0.2";
|
|
4
|
+
export const REPORT_SPEC = "awl/work-report@0.2";
|
|
5
|
+
/** Every spec version this package reads (SPEC.md §11). */
|
|
6
|
+
export const ORDER_SPECS = ["awl/work-order@0.1", ORDER_SPEC];
|
|
7
|
+
export const REPORT_SPECS = ["awl/work-report@0.1", REPORT_SPEC];
|
|
4
8
|
/** Budget and cost units (SPEC.md §4.2). */
|
|
5
9
|
export const UNITS = ["usd", "tokens", "tool_calls", "seconds"];
|
package/dist/validate.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { workOrderSchema, workReportSchema } from "./generated.ts";
|
|
1
2
|
import type { Finding, WorkOrder, WorkReport } from "./types.ts";
|
|
2
3
|
/** The JSON Schemas shipped with this package. */
|
|
3
|
-
export
|
|
4
|
-
export declare const workReportSchema: Record<string, unknown>;
|
|
4
|
+
export { workOrderSchema, workReportSchema };
|
|
5
5
|
/** Does a concrete tool name (`server/tool`) match one of the allowed patterns? */
|
|
6
6
|
export declare function toolAllowed(tool: string, patterns: readonly string[]): boolean;
|
|
7
7
|
/** Is everything a child pattern allows also allowed by the parent's patterns? */
|
package/dist/validate.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
// Checks from SPEC.md §7 (orders and reports) and §8 (sub-orders).
|
|
2
|
-
|
|
1
|
+
// Checks from SPEC.md §7 (orders and reports) and §8 (sub-orders). No Node built-ins here:
|
|
2
|
+
// the validator also runs in browsers, Deno and Bun (see src/validator.ts).
|
|
3
3
|
import Ajv2020Module from "ajv/dist/2020.js";
|
|
4
4
|
import addFormatsModule from "ajv-formats";
|
|
5
|
+
import { workOrderSchema, workReportSchema } from "./generated.js";
|
|
5
6
|
import { UNITS } from "./types.js";
|
|
6
7
|
// ajv and ajv-formats are CommonJS; their classes live on `.default` under NodeNext.
|
|
7
8
|
const Ajv2020 = Ajv2020Module.default;
|
|
@@ -11,10 +12,8 @@ function newAjv() {
|
|
|
11
12
|
addFormats(ajv);
|
|
12
13
|
return ajv;
|
|
13
14
|
}
|
|
14
|
-
const loadSchema = (file) => JSON.parse(readFileSync(new URL(`../schemas/${file}`, import.meta.url), "utf8"));
|
|
15
15
|
/** The JSON Schemas shipped with this package. */
|
|
16
|
-
export
|
|
17
|
-
export const workReportSchema = loadSchema("work-report.schema.json");
|
|
16
|
+
export { workOrderSchema, workReportSchema };
|
|
18
17
|
const ajv = newAjv();
|
|
19
18
|
const orderShape = ajv.compile(workOrderSchema);
|
|
20
19
|
const reportShape = ajv.compile(workReportSchema);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation only: document types, JSON Schemas and every check in SPEC.md §7–§8.
|
|
3
|
+
* Imports no Node built-ins, so it runs in browsers, Deno and Bun.
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
export * from "./types.ts";
|
|
7
|
+
export { validateOrder, validateReport, validateChildOrder, hasInvalid, isWorkOrder, isWorkReport, toolAllowed, patternCovered, workOrderSchema, workReportSchema, } from "./validate.ts";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation only: document types, JSON Schemas and every check in SPEC.md §7–§8.
|
|
3
|
+
* Imports no Node built-ins, so it runs in browsers, Deno and Bun.
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
export * from "./types.js";
|
|
7
|
+
export { validateOrder, validateReport, validateChildOrder, hasInvalid, isWorkOrder, isWorkReport, toolAllowed, patternCovered, workOrderSchema, workReportSchema, } from "./validate.js";
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/** This package's version,
|
|
2
|
-
export
|
|
1
|
+
/** This package's version, from package.json (written into src/generated.ts at build time). */
|
|
2
|
+
export { VERSION } from "./generated.ts";
|
package/dist/version.js
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export const VERSION = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version;
|
|
1
|
+
/** This package's version, from package.json (written into src/generated.ts at build time). */
|
|
2
|
+
export { VERSION } from "./generated.js";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-work-layer",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Work Orders and Work Reports for AI agents: a typed SDK, validator
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Work Orders and Work Reports for AI agents: a typed SDK, validator and lifecycle desk. The MCP server is in agent-work-layer-mcp.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
7
7
|
"agents",
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"types": "./dist/index.d.ts",
|
|
27
27
|
"import": "./dist/index.js"
|
|
28
28
|
},
|
|
29
|
-
"./
|
|
30
|
-
"types": "./dist/
|
|
31
|
-
"import": "./dist/
|
|
29
|
+
"./validate": {
|
|
30
|
+
"types": "./dist/validator.d.ts",
|
|
31
|
+
"import": "./dist/validator.js"
|
|
32
32
|
},
|
|
33
33
|
"./schemas/work-order.schema.json": "./schemas/work-order.schema.json",
|
|
34
34
|
"./schemas/work-report.schema.json": "./schemas/work-report.schema.json",
|
|
@@ -40,28 +40,25 @@
|
|
|
40
40
|
"files": [
|
|
41
41
|
"dist",
|
|
42
42
|
"schemas",
|
|
43
|
+
"README.md",
|
|
44
|
+
"LICENSE",
|
|
43
45
|
"SPEC.md",
|
|
44
46
|
"CHANGELOG.md"
|
|
45
47
|
],
|
|
46
48
|
"sideEffects": false,
|
|
47
49
|
"scripts": {
|
|
50
|
+
"generate": "node scripts/generate.ts",
|
|
48
51
|
"build": "rm -rf dist && tsc -p tsconfig.build.json && chmod +x dist/cli.js",
|
|
49
52
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
50
53
|
"test": "node --test \"test/**/*.test.ts\"",
|
|
51
54
|
"test:coverage": "node --test --experimental-test-coverage --test-coverage-include=\"src/**\" \"test/**/*.test.ts\"",
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"prepublishOnly": "npm run
|
|
55
|
+
"version": "node scripts/generate.ts",
|
|
56
|
+
"prepack": "cp ../../README.md ../../LICENSE ../../SPEC.md ../../CHANGELOG.md . && rm -rf schemas && cp -R ../../schemas schemas",
|
|
57
|
+
"prepublishOnly": "npm run build"
|
|
55
58
|
},
|
|
56
59
|
"dependencies": {
|
|
57
|
-
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
58
60
|
"ajv": "^8.20.0",
|
|
59
|
-
"ajv-formats": "^3.0.1"
|
|
60
|
-
"zod": "^3.25.76"
|
|
61
|
-
},
|
|
62
|
-
"devDependencies": {
|
|
63
|
-
"@types/node": "^22.20.5",
|
|
64
|
-
"typescript": "^7.0.2"
|
|
61
|
+
"ajv-formats": "^3.0.1"
|
|
65
62
|
},
|
|
66
63
|
"publishConfig": {
|
|
67
64
|
"access": "public"
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://awl.dev/schemas/work-order-0.
|
|
4
|
-
"title": "AWL Work Order v0.
|
|
3
|
+
"$id": "https://awl.dev/schemas/work-order-0.2.json",
|
|
4
|
+
"title": "AWL Work Order v0.2",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"required": ["spec", "id", "created_at", "from", "to", "goal", "criteria", "budget", "deadline", "tools"],
|
|
7
7
|
"properties": {
|
|
8
|
-
"spec": { "
|
|
8
|
+
"spec": { "enum": ["awl/work-order@0.1", "awl/work-order@0.2"] },
|
|
9
9
|
"id": { "type": "string", "minLength": 1, "maxLength": 128 },
|
|
10
10
|
"created_at": { "type": "string", "format": "date-time" },
|
|
11
11
|
"from": { "$ref": "#/$defs/agentRef" },
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"additionalProperties": false
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
|
+
"handoff": { "$ref": "#/$defs/handoff" },
|
|
41
42
|
"output_schema": { "type": "object" },
|
|
42
43
|
"parent_id": { "type": "string", "minLength": 1 },
|
|
43
44
|
"metadata": { "type": "object" }
|
|
@@ -56,6 +57,34 @@
|
|
|
56
57
|
"seconds": { "type": "number", "minimum": 0 }
|
|
57
58
|
},
|
|
58
59
|
"additionalProperties": false
|
|
60
|
+
},
|
|
61
|
+
"handoff": {
|
|
62
|
+
"type": "object",
|
|
63
|
+
"minProperties": 1,
|
|
64
|
+
"properties": {
|
|
65
|
+
"summary": { "type": "string", "minLength": 1 },
|
|
66
|
+
"decisions": {
|
|
67
|
+
"type": "array",
|
|
68
|
+
"items": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"required": ["text"],
|
|
71
|
+
"properties": { "text": { "type": "string", "minLength": 1 }, "why": { "type": "string" } },
|
|
72
|
+
"additionalProperties": false
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"tried": {
|
|
76
|
+
"type": "array",
|
|
77
|
+
"items": {
|
|
78
|
+
"type": "object",
|
|
79
|
+
"required": ["text"],
|
|
80
|
+
"properties": { "text": { "type": "string", "minLength": 1 }, "result": { "type": "string" } },
|
|
81
|
+
"additionalProperties": false
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"open_questions": { "type": "array", "items": { "type": "string", "minLength": 1 } },
|
|
85
|
+
"next_step": { "type": "string", "minLength": 1 }
|
|
86
|
+
},
|
|
87
|
+
"additionalProperties": false
|
|
59
88
|
}
|
|
60
89
|
}
|
|
61
90
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://awl.dev/schemas/work-report-0.
|
|
4
|
-
"title": "AWL Work Report v0.
|
|
3
|
+
"$id": "https://awl.dev/schemas/work-report-0.2.json",
|
|
4
|
+
"title": "AWL Work Report v0.2",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"required": ["spec", "order_id", "from", "status", "result", "evidence", "cost", "finished_at", "tools_used"],
|
|
7
7
|
"properties": {
|
|
8
|
-
"spec": { "
|
|
8
|
+
"spec": { "enum": ["awl/work-report@0.1", "awl/work-report@0.2"] },
|
|
9
9
|
"order_id": { "type": "string", "minLength": 1 },
|
|
10
10
|
"from": { "type": "string", "minLength": 1, "maxLength": 512 },
|
|
11
11
|
"status": { "enum": ["done", "blocked", "failed"] },
|
|
@@ -61,8 +61,39 @@
|
|
|
61
61
|
"attempt": { "type": "integer", "minimum": 1 },
|
|
62
62
|
"questions": { "type": "array", "items": { "type": "string", "minLength": 1 } },
|
|
63
63
|
"error": { "type": "string", "minLength": 1 },
|
|
64
|
+
"handoff": { "$ref": "#/$defs/handoff" },
|
|
64
65
|
"metadata": { "type": "object" }
|
|
65
66
|
},
|
|
66
67
|
"patternProperties": { "^x-": {} },
|
|
67
|
-
"additionalProperties": false
|
|
68
|
+
"additionalProperties": false,
|
|
69
|
+
"$defs": {
|
|
70
|
+
"handoff": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"minProperties": 1,
|
|
73
|
+
"properties": {
|
|
74
|
+
"summary": { "type": "string", "minLength": 1 },
|
|
75
|
+
"decisions": {
|
|
76
|
+
"type": "array",
|
|
77
|
+
"items": {
|
|
78
|
+
"type": "object",
|
|
79
|
+
"required": ["text"],
|
|
80
|
+
"properties": { "text": { "type": "string", "minLength": 1 }, "why": { "type": "string" } },
|
|
81
|
+
"additionalProperties": false
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"tried": {
|
|
85
|
+
"type": "array",
|
|
86
|
+
"items": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"required": ["text"],
|
|
89
|
+
"properties": { "text": { "type": "string", "minLength": 1 }, "result": { "type": "string" } },
|
|
90
|
+
"additionalProperties": false
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"open_questions": { "type": "array", "items": { "type": "string", "minLength": 1 } },
|
|
94
|
+
"next_step": { "type": "string", "minLength": 1 }
|
|
95
|
+
},
|
|
96
|
+
"additionalProperties": false
|
|
97
|
+
}
|
|
98
|
+
}
|
|
68
99
|
}
|
package/dist/mcp.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import type { WorkDesk } from "./desk.ts";
|
|
3
|
-
export interface DeskServerOptions {
|
|
4
|
-
desk: WorkDesk;
|
|
5
|
-
/**
|
|
6
|
-
* Fixes who this server acts as. When set, tools act as this identity and refuse any
|
|
7
|
-
* other `actor` argument, so a worker session cannot approve its own work.
|
|
8
|
-
*/
|
|
9
|
-
actor?: string;
|
|
10
|
-
name?: string;
|
|
11
|
-
}
|
|
12
|
-
/** Builds an MCP server exposing the desk's operations as tools. Connect it to any transport. */
|
|
13
|
-
export declare function createDeskServer({ desk, actor: sessionActor, name }: DeskServerOptions): McpServer;
|
package/dist/mcp.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
// The desk as an MCP server (SPEC.md §9, MCP binding).
|
|
2
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
-
import { z } from "zod";
|
|
4
|
-
import { AwlError } from "./errors.js";
|
|
5
|
-
import { STATES } from "./lifecycle.js";
|
|
6
|
-
import { summarize } from "./desk.js";
|
|
7
|
-
import { VERSION } from "./version.js";
|
|
8
|
-
const amounts = z
|
|
9
|
-
.object({
|
|
10
|
-
usd: z.number().min(0).optional(),
|
|
11
|
-
tokens: z.number().int().min(0).optional(),
|
|
12
|
-
tool_calls: z.number().int().min(0).optional(),
|
|
13
|
-
seconds: z.number().min(0).optional(),
|
|
14
|
-
})
|
|
15
|
-
.strict();
|
|
16
|
-
const actorArg = z.string().optional().describe("Who is acting. Omit to use this session's identity.");
|
|
17
|
-
const idArg = z.string().describe("Work order id");
|
|
18
|
-
const view = (r) => ({ ...summarize(r), order: r.order, latest_report: r.reports.at(-1) ?? null, findings: r.findings, events: r.events });
|
|
19
|
-
/** Drops keys whose value is undefined so they don't reach JSON Schema validation. */
|
|
20
|
-
const defined = (o) => JSON.parse(JSON.stringify(o));
|
|
21
|
-
async function respond(fn) {
|
|
22
|
-
try {
|
|
23
|
-
const value = await fn();
|
|
24
|
-
return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }] };
|
|
25
|
-
}
|
|
26
|
-
catch (e) {
|
|
27
|
-
const body = e instanceof AwlError ? e.toJSON() : { code: "INTERNAL", message: String(e) };
|
|
28
|
-
return { isError: true, content: [{ type: "text", text: JSON.stringify(body, null, 2) }] };
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/** Builds an MCP server exposing the desk's operations as tools. Connect it to any transport. */
|
|
32
|
-
export function createDeskServer({ desk, actor: sessionActor, name = "awl-work-desk" }) {
|
|
33
|
-
const server = new McpServer({ name, version: VERSION });
|
|
34
|
-
const who = (arg) => {
|
|
35
|
-
if (sessionActor && arg && arg !== sessionActor)
|
|
36
|
-
throw new AwlError("FORBIDDEN", `this session acts as "${sessionActor}", not "${arg}"`);
|
|
37
|
-
const actor = arg ?? sessionActor;
|
|
38
|
-
if (!actor)
|
|
39
|
-
throw new AwlError("BAD_REQUEST", 'no actor: pass "actor" or start the desk with an identity');
|
|
40
|
-
return actor;
|
|
41
|
-
};
|
|
42
|
-
server.registerTool("create_work_order", {
|
|
43
|
-
description: "Issue a Work Order to a worker agent. Every criterion must be provable with evidence. " +
|
|
44
|
-
"Set parent_id to split your own order into a sub-order; it may only narrow budget, tools and deadline.",
|
|
45
|
-
inputSchema: {
|
|
46
|
-
actor: actorArg,
|
|
47
|
-
to: z.string().describe("Worker agent reference (Agent Card URL or name)"),
|
|
48
|
-
goal: z.string().describe("What to achieve, in plain language"),
|
|
49
|
-
criteria: z.array(z.object({ id: z.string(), text: z.string() })).min(1).describe("How done will be judged"),
|
|
50
|
-
budget: amounts.describe("Upper limits; set at least one unit"),
|
|
51
|
-
deadline: z.string().describe("RFC 3339 timestamp"),
|
|
52
|
-
tools: z.array(z.string()).describe('Allowed tools: "server/tool", "server/*" or "*"'),
|
|
53
|
-
escalate_to: z.string().optional(),
|
|
54
|
-
inputs: z.record(z.any()).optional(),
|
|
55
|
-
context: z.array(z.object({ uri: z.string(), note: z.string().optional() })).optional(),
|
|
56
|
-
output_schema: z.record(z.any()).optional().describe("JSON Schema that result.output must match"),
|
|
57
|
-
parent_id: z.string().optional(),
|
|
58
|
-
id: z.string().optional().describe("Optional explicit id"),
|
|
59
|
-
metadata: z.record(z.any()).optional(),
|
|
60
|
-
},
|
|
61
|
-
}, async ({ actor, ...input }) => respond(async () => view(await desk.create(defined(input), who(actor)))));
|
|
62
|
-
server.registerTool("list_work_orders", {
|
|
63
|
-
description: "List work orders. Workers: filter by to=<yourself> and state=offered to find new jobs.",
|
|
64
|
-
inputSchema: {
|
|
65
|
-
to: z.string().optional(),
|
|
66
|
-
from: z.string().optional(),
|
|
67
|
-
state: z.enum(STATES).optional(),
|
|
68
|
-
parent_id: z.string().optional(),
|
|
69
|
-
},
|
|
70
|
-
}, async (filter) => respond(() => desk.list(defined(filter))));
|
|
71
|
-
server.registerTool("get_work_order", { description: "Full order, current state, latest report, check findings and event log.", inputSchema: { id: idArg } }, async ({ id }) => respond(async () => view(await desk.get(id))));
|
|
72
|
-
server.registerTool("accept_work_order", { description: "Worker accepts an offered order.", inputSchema: { id: idArg, actor: actorArg } }, async ({ id, actor }) => respond(async () => view(await desk.accept(id, who(actor)))));
|
|
73
|
-
server.registerTool("decline_work_order", { description: "Worker declines an offered order.", inputSchema: { id: idArg, actor: actorArg, reason: z.string().optional() } }, async ({ id, actor, reason }) => respond(async () => view(await desk.decline(id, who(actor), reason))));
|
|
74
|
-
server.registerTool("start_work_order", { description: "Worker starts an accepted order.", inputSchema: { id: idArg, actor: actorArg } }, async ({ id, actor }) => respond(async () => view(await desk.start(id, who(actor)))));
|
|
75
|
-
server.registerTool("submit_work_report", {
|
|
76
|
-
description: "Worker reports on an order. done needs evidence for every criterion; blocked needs questions; failed needs error. " +
|
|
77
|
-
"A rejected report returns the failed checks so you can fix it and resubmit.",
|
|
78
|
-
inputSchema: {
|
|
79
|
-
id: idArg,
|
|
80
|
-
actor: actorArg,
|
|
81
|
-
status: z.enum(["done", "blocked", "failed"]),
|
|
82
|
-
result: z.object({
|
|
83
|
-
summary: z.string(),
|
|
84
|
-
output: z.any().optional(),
|
|
85
|
-
artifacts: z.array(z.object({ uri: z.string(), media_type: z.string().optional(), note: z.string().optional() })).optional(),
|
|
86
|
-
}),
|
|
87
|
-
evidence: z.array(z.object({
|
|
88
|
-
criterion: z.string(),
|
|
89
|
-
type: z.enum(["tool_call", "artifact", "citation", "note"]),
|
|
90
|
-
ref: z.string().optional(),
|
|
91
|
-
note: z.string().optional(),
|
|
92
|
-
})),
|
|
93
|
-
cost: amounts,
|
|
94
|
-
tools_used: z.array(z.string()).describe('Exact tool names called, as "server/tool"'),
|
|
95
|
-
started_at: z.string().optional(),
|
|
96
|
-
finished_at: z.string().optional(),
|
|
97
|
-
questions: z.array(z.string()).optional(),
|
|
98
|
-
error: z.string().optional(),
|
|
99
|
-
metadata: z.record(z.any()).optional(),
|
|
100
|
-
},
|
|
101
|
-
}, async ({ id, actor, ...input }) => respond(async () => {
|
|
102
|
-
const { record, findings } = await desk.submitReport(id, defined(input), who(actor));
|
|
103
|
-
return { ...summarize(record), findings };
|
|
104
|
-
}));
|
|
105
|
-
server.registerTool("answer_question", { description: "Manager or escalation contact answers a blocked worker; the order returns to working.", inputSchema: { id: idArg, actor: actorArg, answer: z.string() } }, async ({ id, actor, answer }) => respond(async () => view(await desk.answer(id, who(actor), answer))));
|
|
106
|
-
server.registerTool("review_work_report", {
|
|
107
|
-
description: "Manager approves a submitted report, or sends it back for rework with a reason.",
|
|
108
|
-
inputSchema: { id: idArg, actor: actorArg, decision: z.enum(["approve", "rework"]), reason: z.string().optional() },
|
|
109
|
-
}, async ({ id, actor, decision, reason }) => respond(async () => view(await desk.review(id, who(actor), decision, reason))));
|
|
110
|
-
server.registerTool("cancel_work_order", { description: "Manager cancels an order that is not finished.", inputSchema: { id: idArg, actor: actorArg, reason: z.string().optional() } }, async ({ id, actor, reason }) => respond(async () => view(await desk.cancel(id, who(actor), reason))));
|
|
111
|
-
server.registerTool("wait_for_update", {
|
|
112
|
-
description: "Wait until the order changes after since_seq (up to timeout_s seconds). Use it to follow a job live.",
|
|
113
|
-
inputSchema: { id: idArg, since_seq: z.number().int().min(0), timeout_s: z.number().min(1).max(55).optional() },
|
|
114
|
-
}, async ({ id, since_seq, timeout_s }, extra) => respond(async () => view(await desk.waitForChange(id, since_seq, { timeoutMs: (timeout_s ?? 25) * 1000, signal: extra.signal }))));
|
|
115
|
-
return server;
|
|
116
|
-
}
|