@tekmidian/pai 0.37.0 → 0.39.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/dist/{auto-route-DM7GhJ8y.mjs → auto-route-BlWOWT4z.mjs} +2 -2
- package/dist/{auto-route-DM7GhJ8y.mjs.map → auto-route-BlWOWT4z.mjs.map} +1 -1
- package/dist/{providers-sXcK5bDZ.mjs → chain-CTtHligI.mjs} +1040 -782
- package/dist/chain-CTtHligI.mjs.map +1 -0
- package/dist/cli/index.mjs +4 -3
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/program.mjs +4 -3
- package/dist/{clusters-Do4tEGyc.mjs → clusters-wlK0w41E.mjs} +1 -1
- package/dist/{clusters-Do4tEGyc.mjs.map → clusters-wlK0w41E.mjs.map} +1 -1
- package/dist/daemon/index.mjs +7 -7
- package/dist/{daemon-CGg1VCbA.mjs → daemon-CTkN_Vn8.mjs} +25 -25
- package/dist/{daemon-CGg1VCbA.mjs.map → daemon-CTkN_Vn8.mjs.map} +1 -1
- package/dist/{daemon-DsGGiIJM.mjs → daemon-CmHHmKpg.mjs} +7 -7
- package/dist/daemon-mcp/index.mjs +207 -34
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/{detector-CMap-9vw.mjs → detector-Bwk_4Pk4.mjs} +1 -1
- package/dist/{detector-CMap-9vw.mjs.map → detector-Bwk_4Pk4.mjs.map} +1 -1
- package/dist/detector-DO730Zq0.mjs +5 -0
- package/dist/{factory-DD2T33C9.mjs → factory-A9x-T2Kg.mjs} +5 -5
- package/dist/{factory-DD2T33C9.mjs.map → factory-A9x-T2Kg.mjs.map} +1 -1
- package/dist/factory-BD-np0Vd.mjs +3 -0
- package/dist/hooks/route-agents-to-worker.mjs +112 -20
- package/dist/hooks/route-agents-to-worker.mjs.map +2 -2
- package/dist/hooks/worker-proxy.mjs +110 -18
- package/dist/hooks/worker-proxy.mjs.map +2 -2
- package/dist/hooks/worker-status-line.mjs +176 -23
- package/dist/hooks/worker-status-line.mjs.map +4 -4
- package/dist/{indexer-backend-Cox9BCo-.mjs → indexer-backend-TG64CCQC.mjs} +1 -1
- package/dist/{indexer-backend-Cox9BCo-.mjs.map → indexer-backend-TG64CCQC.mjs.map} +1 -1
- package/dist/{latent-ideas-BC1oINZ-.mjs → latent-ideas-B7wq75Pt.mjs} +2 -2
- package/dist/{latent-ideas-BC1oINZ-.mjs.map → latent-ideas-B7wq75Pt.mjs.map} +1 -1
- package/dist/{link-boost-QFLrJwD6.mjs → link-boost-HkG7JWZR.mjs} +1 -1
- package/dist/{link-boost-QFLrJwD6.mjs.map → link-boost-HkG7JWZR.mjs.map} +1 -1
- package/dist/{neighborhood-D9MJ1c8f.mjs → neighborhood-lThN-MaQ.mjs} +1 -1
- package/dist/{neighborhood-D9MJ1c8f.mjs.map → neighborhood-lThN-MaQ.mjs.map} +1 -1
- package/dist/{note-context-d1wT_-GA.mjs → note-context-b6k0mAKi.mjs} +1 -1
- package/dist/{note-context-d1wT_-GA.mjs.map → note-context-b6k0mAKi.mjs.map} +1 -1
- package/dist/planner-BDI7bE9B.mjs +243 -0
- package/dist/planner-BDI7bE9B.mjs.map +1 -0
- package/dist/{postgres--BjPtLa0.mjs → postgres-mW1n7Vi1.mjs} +1 -1
- package/dist/{postgres--BjPtLa0.mjs.map → postgres-mW1n7Vi1.mjs.map} +1 -1
- package/dist/{program-CEIHn_Ma.mjs → program-DXBwJV7h.mjs} +274 -65
- package/dist/program-DXBwJV7h.mjs.map +1 -0
- package/dist/providers-FYkZjn_C.mjs +1405 -0
- package/dist/providers-FYkZjn_C.mjs.map +1 -0
- package/dist/{query-feedback-BUJxgw5B.mjs → query-feedback-BV4CcxqS.mjs} +1 -1
- package/dist/{query-feedback-BUJxgw5B.mjs.map → query-feedback-BV4CcxqS.mjs.map} +1 -1
- package/dist/query-feedback-DSVyHtrG.mjs +3 -0
- package/dist/router-Bk77E7hj.mjs +3 -0
- package/dist/{router-DK_sLsUL.mjs → router-DcHKnEPa.mjs} +1 -1
- package/dist/{router-DK_sLsUL.mjs.map → router-DcHKnEPa.mjs.map} +1 -1
- package/dist/skills/Worker/SKILL.md +34 -12
- package/dist/{sources-Bi7--33T.mjs → sources-kLnQsNrW.mjs} +1 -1
- package/dist/{sources-Bi7--33T.mjs.map → sources-kLnQsNrW.mjs.map} +1 -1
- package/dist/{sqlite-DtaL1glm.mjs → sqlite-BenGr3UP.mjs} +1 -1
- package/dist/{sqlite-DtaL1glm.mjs.map → sqlite-BenGr3UP.mjs.map} +1 -1
- package/dist/{state-BY2L6-vX.mjs → state-CAeyOdfq.mjs} +1 -1
- package/dist/{state-BY2L6-vX.mjs.map → state-CAeyOdfq.mjs.map} +1 -1
- package/dist/{state-8Hm9E4tW.mjs → state-Ca9F_sZc.mjs} +1 -1
- package/dist/{themes-BN0a2duq.mjs → themes-BI4GMRP9.mjs} +1 -1
- package/dist/{themes-BN0a2duq.mjs.map → themes-BI4GMRP9.mjs.map} +1 -1
- package/dist/{tools-CGPqpU3A.mjs → tools-Bp7hj6OW.mjs} +1 -1
- package/dist/{tools-y2bJpKom.mjs → tools-DGcB3o_S.mjs} +13 -13
- package/dist/{tools-y2bJpKom.mjs.map → tools-DGcB3o_S.mjs.map} +1 -1
- package/dist/{trace-h23JCcFD.mjs → trace-bobARFEX.mjs} +1 -1
- package/dist/{trace-h23JCcFD.mjs.map → trace-bobARFEX.mjs.map} +1 -1
- package/dist/{vault-indexer-DgsPjMgs.mjs → vault-indexer-C3OfXTNF.mjs} +1 -1
- package/dist/{vault-indexer-DgsPjMgs.mjs.map → vault-indexer-C3OfXTNF.mjs.map} +1 -1
- package/dist/{work-queue-worker-gsKd2LJa.mjs → work-queue-worker-DW8lz-Oo.mjs} +3 -3
- package/dist/{work-queue-worker-Dva_v_pI.mjs → work-queue-worker-R7UGIag_.mjs} +3 -3
- package/dist/{work-queue-worker-Dva_v_pI.mjs.map → work-queue-worker-R7UGIag_.mjs.map} +1 -1
- package/dist/{zettelkasten-vo7psPdT.mjs → zettelkasten-m5QPtb-L.mjs} +3 -3
- package/dist/{zettelkasten-vo7psPdT.mjs.map → zettelkasten-m5QPtb-L.mjs.map} +1 -1
- package/docs/commands/README.md +12 -7
- package/docs/commands/worker.md +110 -17
- package/docs/worker.md +244 -25
- package/package.json +1 -1
- package/src/hooks/ts/pre-tool-use/route-agents-to-worker.ts +2 -2
- package/dist/detector-DtLExmHN.mjs +0 -5
- package/dist/factory-BXzqRYVZ.mjs +0 -3
- package/dist/program-CEIHn_Ma.mjs.map +0 -1
- package/dist/providers-sXcK5bDZ.mjs.map +0 -1
- package/dist/query-feedback-DhyLOe5S.mjs +0 -3
- package/dist/router-1zi8jiNF.mjs +0 -3
- /package/dist/{main-resolver-IhZo4pI0.mjs → main-resolver-D6IImXvF.mjs} +0 -0
package/docs/commands/worker.md
CHANGED
|
@@ -24,6 +24,10 @@ pai worker <subcommand> [options]
|
|
|
24
24
|
| [`pai worker pane [id]`](#pai-worker-pane-id) | Open the follow pane for a worker (or one shared pane for this session) |
|
|
25
25
|
| [`pai worker log [what]`](#pai-worker-log-what) | all = ledger, tail = last ledger lines, <id> = raw event stream, none = list |
|
|
26
26
|
| [`pai worker say <id> <text>`](#pai-worker-say-id-text) | Send one message to a running worker (forwarded to its open stdin) |
|
|
27
|
+
| [`pai worker handoff <json>`](#pai-worker-handoff-json) | From inside a worker: append a handoff to the parent's inbox and (when it runs) say it to the parent. |
|
|
28
|
+
| [`pai worker merge <id>`](#pai-worker-merge-id) | Merge a worker's worktree branch (worker/<id>) into the original checkout, then remove the worktree |
|
|
29
|
+
| [`pai worker discard <id>`](#pai-worker-discard-id) | Drop a worker's worktree and branch, keeping nothing |
|
|
30
|
+
| [`pai worker controls <id> <who>`](#pai-worker-controls-id-who) | Hand the desktop controls (clickr) to a worker or take them back. |
|
|
27
31
|
| [`pai worker resume <id> <text>`](#pai-worker-resume-id-text) | Continue a finished worker on the same provider: claude --resume <session> |
|
|
28
32
|
| [`pai worker proxy [stop]`](#pai-worker-proxy-stop) | The local Anthropic↔OpenAI proxy (loopback only); started on demand by `run`, |
|
|
29
33
|
| [`pai worker mcp [list]`](#pai-worker-mcp-list) | MCP servers workers may load via --mcp / roles, and the configured sets |
|
|
@@ -32,7 +36,7 @@ pai worker <subcommand> [options]
|
|
|
32
36
|
| [`pai worker off`](#pai-worker-off) | Stop routing: Agent tool runs on Anthropic again |
|
|
33
37
|
| [`pai worker install`](#pai-worker-install) | Migrate: Agent hook in settings.json, ~/.local/bin glm* shims, old script cleanup |
|
|
34
38
|
| [`pai worker providers`](#pai-worker-providers) | Providers: list (default), add, remove, use, enable, disable, test |
|
|
35
|
-
| [`pai worker
|
|
39
|
+
| [`pai worker classes`](#pai-worker-classes) | Classes: which provider serves draft / implement / review / … |
|
|
36
40
|
|
|
37
41
|
### pai worker run [args...]
|
|
38
42
|
|
|
@@ -40,6 +44,8 @@ Run one claude-code worker through the configured provider.
|
|
|
40
44
|
|
|
41
45
|
Unknown options are passed to claude verbatim (e.g. -p, --allowedTools);
|
|
42
46
|
--output-format/--verbose are handled here.
|
|
47
|
+
--chain draft,implement[,review] runs a spec-first pipeline;
|
|
48
|
+
--agent <name> runs an agent definition from ~/.claude/agents.
|
|
43
49
|
|
|
44
50
|
**Arguments**
|
|
45
51
|
|
|
@@ -52,11 +58,16 @@ Unknown options are passed to claude verbatim (e.g. -p, --allowedTools);
|
|
|
52
58
|
| Option | Description | Default |
|
|
53
59
|
|--------|-------------|---------|
|
|
54
60
|
| `--provider <name>` | Provider to run on (default: active, else routing order) | |
|
|
55
|
-
| `--
|
|
61
|
+
| `--class <name>` | Use the provider of this class (draft, implement, review, research, spotcheck, simple, complex, image) | |
|
|
62
|
+
| `--role <name>` | Alias of --class (roles were renamed to classes) | |
|
|
63
|
+
| `--chain <stages>` | Comma-separated stage classes, e.g. draft,implement or draft,implement,review | |
|
|
64
|
+
| `--agent <name>` | Run the agent definition ~/.claude/agents/<name>.md on a worker | |
|
|
56
65
|
| `--model <model>` | Override the provider's model for this run | |
|
|
57
66
|
| `--label <text>` | Short task label shown in ps / follow / status line | |
|
|
58
67
|
| `--mcp <names>` | MCP servers/sets this worker may use (comma-separated; see `pai worker mcp`) | |
|
|
59
68
|
| `--no-pane` | Do not open a follow pane for this worker | |
|
|
69
|
+
| `--worktree` | Run in a git worktree on branch worker/<id> (default for implement/complex/plan in a git repo) | |
|
|
70
|
+
| `--no-worktree` | Run in place, no worktree | |
|
|
60
71
|
|
|
61
72
|
|
|
62
73
|
### pai worker ps
|
|
@@ -124,7 +135,7 @@ Open the follow pane for a worker (or one shared pane for this session)
|
|
|
124
135
|
|
|
125
136
|
| Option | Description | Default |
|
|
126
137
|
|--------|-------------|---------|
|
|
127
|
-
| `--check` | Only report whether the pane is open, plus the profile file's path and
|
|
138
|
+
| `--check` | Only report whether the pane is open, plus the profile file's path, font, and the hosting window's bounds | |
|
|
128
139
|
|
|
129
140
|
|
|
130
141
|
### pai worker log [what]
|
|
@@ -150,6 +161,56 @@ Send one message to a running worker (forwarded to its open stdin)
|
|
|
150
161
|
| `<text>` | required |
|
|
151
162
|
|
|
152
163
|
|
|
164
|
+
### pai worker handoff <json>
|
|
165
|
+
|
|
166
|
+
From inside a worker: append a handoff to the parent's inbox and (when it runs) say it to the parent.
|
|
167
|
+
|
|
168
|
+
Payload: {"kind":"proposal|question|blocker","text":"…","data":{…}} — from/to come from the environment.
|
|
169
|
+
|
|
170
|
+
**Arguments**
|
|
171
|
+
|
|
172
|
+
| Argument | Kind |
|
|
173
|
+
|----------|------|
|
|
174
|
+
| `<json>` | required |
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
### pai worker merge <id>
|
|
178
|
+
|
|
179
|
+
Merge a worker's worktree branch (worker/<id>) into the original checkout, then remove the worktree
|
|
180
|
+
|
|
181
|
+
**Arguments**
|
|
182
|
+
|
|
183
|
+
| Argument | Kind |
|
|
184
|
+
|----------|------|
|
|
185
|
+
| `<id>` | required |
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
### pai worker discard <id>
|
|
189
|
+
|
|
190
|
+
Drop a worker's worktree and branch, keeping nothing
|
|
191
|
+
|
|
192
|
+
**Arguments**
|
|
193
|
+
|
|
194
|
+
| Argument | Kind |
|
|
195
|
+
|----------|------|
|
|
196
|
+
| `<id>` | required |
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
### pai worker controls <id> <who>
|
|
200
|
+
|
|
201
|
+
Hand the desktop controls (clickr) to a worker or take them back.
|
|
202
|
+
|
|
203
|
+
<who> is `you` (the worker may actuate) or `me` (the operator keeps them);
|
|
204
|
+
inside a worker's pane, typing "your controls" does the same.
|
|
205
|
+
|
|
206
|
+
**Arguments**
|
|
207
|
+
|
|
208
|
+
| Argument | Kind |
|
|
209
|
+
|----------|------|
|
|
210
|
+
| `<id>` | required |
|
|
211
|
+
| `<who>` | required |
|
|
212
|
+
|
|
213
|
+
|
|
153
214
|
### pai worker resume <id> <text>
|
|
154
215
|
|
|
155
216
|
Continue a finished worker on the same provider: claude --resume <session>
|
|
@@ -235,7 +296,7 @@ Providers: list (default), add, remove, use, enable, disable, test
|
|
|
235
296
|
|
|
236
297
|
### pai worker providers add <name>
|
|
237
298
|
|
|
238
|
-
Add a provider; the first one also turns workers on and seeds
|
|
299
|
+
Add a provider; the first one also turns workers on and seeds classes.
|
|
239
300
|
|
|
240
301
|
Example: pai worker providers add glm --base-url https://…/anthropic \
|
|
241
302
|
--key-file ~/.config/zai/api_key --model glm-5.3 --fast-model glm-5.3-flash
|
|
@@ -263,11 +324,31 @@ Codex (ChatGPT plan): --engine codex — runs through the Codex CLI.
|
|
|
263
324
|
| `--engine <engine>` | claude (default) or codex — codex runs `codex exec --json` | |
|
|
264
325
|
| `--context-window <tokens>` | Context window for the meter (default 200000; init event overrides) | |
|
|
265
326
|
| `--quota-probe <url>` | URL whose JSON first number is the quota percent (0-100) | |
|
|
327
|
+
| `--cost-tier <1-5>` | Cost tier 1 (cheapest) … 5 (most expensive; default 3) | |
|
|
328
|
+
| `--tags <tags>` | Capability tags, comma-separated (from: code, vision, image-gen, long-context, fast, reasoning) | `` |
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
### pai worker providers update <name>
|
|
332
|
+
|
|
333
|
+
Change cost tier and tags of a provider (routing constraints use these)
|
|
334
|
+
|
|
335
|
+
**Arguments**
|
|
336
|
+
|
|
337
|
+
| Argument | Kind |
|
|
338
|
+
|----------|------|
|
|
339
|
+
| `<name>` | required |
|
|
340
|
+
|
|
341
|
+
**Options**
|
|
342
|
+
|
|
343
|
+
| Option | Description | Default |
|
|
344
|
+
|--------|-------------|---------|
|
|
345
|
+
| `--cost-tier <1-5>` | Cost tier 1 (cheapest) … 5 (most expensive) | |
|
|
346
|
+
| `--tags <tags>` | Capability tags, comma-separated (from: code, vision, image-gen, long-context, fast, reasoning); --tags '' clears | `` |
|
|
266
347
|
|
|
267
348
|
|
|
268
349
|
### pai worker providers remove <name>
|
|
269
350
|
|
|
270
|
-
Remove a provider and any
|
|
351
|
+
Remove a provider and any classes pointing at it
|
|
271
352
|
|
|
272
353
|
**Arguments**
|
|
273
354
|
|
|
@@ -278,7 +359,7 @@ Remove a provider and any roles pointing at it
|
|
|
278
359
|
|
|
279
360
|
### pai worker providers use <name>
|
|
280
361
|
|
|
281
|
-
Make this provider the active one for runs without --provider/--
|
|
362
|
+
Make this provider the active one for runs without --provider/--class
|
|
282
363
|
|
|
283
364
|
**Arguments**
|
|
284
365
|
|
|
@@ -320,37 +401,49 @@ One-word pong probe through a provider (default: the active one)
|
|
|
320
401
|
| `[name]` | optional |
|
|
321
402
|
|
|
322
403
|
|
|
323
|
-
### pai worker
|
|
404
|
+
### pai worker classes
|
|
405
|
+
|
|
406
|
+
Classes: which provider serves draft / implement / review / …
|
|
324
407
|
|
|
325
|
-
Roles: which provider serves implement / research / spotcheck
|
|
326
408
|
|
|
409
|
+
### pai worker classes list
|
|
327
410
|
|
|
328
|
-
|
|
411
|
+
List classes and their targets (default action)
|
|
329
412
|
|
|
330
|
-
List roles and their providers (default action)
|
|
331
413
|
|
|
414
|
+
### pai worker classes set <class> [target]
|
|
332
415
|
|
|
333
|
-
|
|
416
|
+
Point a class at a provider (or provider/fast), or give only constraints:
|
|
334
417
|
|
|
335
|
-
|
|
418
|
+
classes set research --max-cost-tier 2 --require-tags long-context,reasoning
|
|
336
419
|
|
|
337
420
|
**Arguments**
|
|
338
421
|
|
|
339
422
|
| Argument | Kind |
|
|
340
423
|
|----------|------|
|
|
341
|
-
| `<
|
|
342
|
-
|
|
|
424
|
+
| `<class>` | required |
|
|
425
|
+
| `[target]` | optional |
|
|
426
|
+
|
|
427
|
+
**Options**
|
|
428
|
+
|
|
429
|
+
| Option | Description | Default |
|
|
430
|
+
|--------|-------------|---------|
|
|
431
|
+
| `--provider <name>` | Pin the class to this provider (object form) | |
|
|
432
|
+
| `--mcp <names>` | MCP servers/sets for runs of this class (comma-separated) | |
|
|
433
|
+
| `--max-cost-tier <1-5>` | Auto-routing considers only providers up to this cost tier | |
|
|
434
|
+
| `--require-tags <tags>` | Auto-routing needs these tags (comma-separated) | |
|
|
435
|
+
| `--order <providers>` | Per-class routing order overriding workers.routing.order (comma-separated) | |
|
|
343
436
|
|
|
344
437
|
|
|
345
|
-
### pai worker
|
|
438
|
+
### pai worker classes unset <class>
|
|
346
439
|
|
|
347
|
-
Remove a
|
|
440
|
+
Remove a class (runs then use the active provider)
|
|
348
441
|
|
|
349
442
|
**Arguments**
|
|
350
443
|
|
|
351
444
|
| Argument | Kind |
|
|
352
445
|
|----------|------|
|
|
353
|
-
| `<
|
|
446
|
+
| `<class>` | required |
|
|
354
447
|
|
|
355
448
|
|
|
356
449
|
## See also
|
package/docs/worker.md
CHANGED
|
@@ -32,22 +32,26 @@ main session (Anthropic) workers (configured provider)
|
|
|
32
32
|
"keyFile": "~/.config/zai/api_key",
|
|
33
33
|
"models": { "default": "glm-5.3", "fast": "glm-5.3-flash" },
|
|
34
34
|
"env": { "API_TIMEOUT_MS": "3000000" },
|
|
35
|
-
"contextWindow": 200000
|
|
35
|
+
"contextWindow": 200000,
|
|
36
|
+
"costTier": 2,
|
|
37
|
+
"tags": ["code", "long-context"]
|
|
36
38
|
},
|
|
37
39
|
"oai": {
|
|
38
40
|
"protocol": "openai",
|
|
39
41
|
"upstreamUrl": "https://api.openai.com/v1",
|
|
40
42
|
"keyFile": "~/.config/pai/keys/oai",
|
|
41
|
-
"models": { "default": "gpt-5.2", "fast": "gpt-5.2-mini" }
|
|
43
|
+
"models": { "default": "gpt-5.2", "fast": "gpt-5.2-mini" },
|
|
44
|
+
"costTier": 4,
|
|
45
|
+
"tags": ["reasoning", "vision"]
|
|
42
46
|
},
|
|
43
47
|
"codexprov": {
|
|
44
48
|
"engine": "codex",
|
|
45
49
|
"models": { "default": "gpt-5.2-codex" }
|
|
46
50
|
}
|
|
47
51
|
},
|
|
48
|
-
"
|
|
52
|
+
"classes": {
|
|
49
53
|
"implement": "glm",
|
|
50
|
-
"research": "
|
|
54
|
+
"research": { "maxCostTier": 2, "requireTags": ["long-context"] },
|
|
51
55
|
"spotcheck": "glm/fast",
|
|
52
56
|
"docs": { "provider": "glm", "mcp": ["office"] }
|
|
53
57
|
},
|
|
@@ -70,8 +74,12 @@ main session (Anthropic) workers (configured provider)
|
|
|
70
74
|
Code (see below).
|
|
71
75
|
- `contextWindow` overrides the context-meter window when the endpoint's
|
|
72
76
|
init event does not announce one (default 200 000).
|
|
73
|
-
-
|
|
74
|
-
`
|
|
77
|
+
- `costTier` (1 cheapest … 5 most expensive, default 3) and `tags` (from:
|
|
78
|
+
`code`, `vision`, `image-gen`, `long-context`, `fast`, `reasoning`) describe
|
|
79
|
+
a provider; classes use them to constrain routing (next section).
|
|
80
|
+
- A class target is `"provider[/model]"` or an object with `provider` and a
|
|
81
|
+
`mcp` allowlist applied on top of `--mcp`, or an object with only routing
|
|
82
|
+
constraints (`maxCostTier`, `requireTags`, `order`).
|
|
75
83
|
|
|
76
84
|
Or add one from the CLI:
|
|
77
85
|
|
|
@@ -80,19 +88,64 @@ pai worker providers add glm \
|
|
|
80
88
|
--base-url https://api.z.ai/api/anthropic \
|
|
81
89
|
--key-file ~/.config/zai/api_key \
|
|
82
90
|
--model glm-5.3 --fast-model glm-5.3-flash \
|
|
83
|
-
--env API_TIMEOUT_MS=3000000
|
|
91
|
+
--env API_TIMEOUT_MS=3000000 \
|
|
92
|
+
--cost-tier 2 --tags code,long-context
|
|
84
93
|
pai worker providers add oai \
|
|
85
94
|
--upstream-url https://api.openai.com/v1 \
|
|
86
95
|
--key-file ~/.config/pai/keys/oai --model gpt-5.2
|
|
96
|
+
pai worker providers update glm --cost-tier 1 # tiers/tags change later
|
|
87
97
|
```
|
|
88
98
|
|
|
89
99
|
The first provider also sets `enabled: true`, makes itself active and seeds
|
|
90
|
-
the
|
|
100
|
+
the nine classes. Then:
|
|
91
101
|
|
|
92
102
|
```
|
|
93
103
|
pai worker install # Agent hook in settings.json + glm* shims + cleanup
|
|
94
104
|
```
|
|
95
105
|
|
|
106
|
+
## Task classes
|
|
107
|
+
|
|
108
|
+
Roles were renamed to **classes** — task classes pick the provider for a kind
|
|
109
|
+
of work. The nine standard classes: `draft`, `plan`, `implement`, `review`,
|
|
110
|
+
`research`, `spotcheck`, `simple`, `complex`, `image` (any other name can be
|
|
111
|
+
defined too). Configs with the old `roles` key keep parsing; the key migrates
|
|
112
|
+
to `classes` on the first write.
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
pai worker classes # list
|
|
116
|
+
pai worker classes set implement glm # pin a provider
|
|
117
|
+
pai worker classes set spotcheck glm/fast # …its fast model
|
|
118
|
+
pai worker classes set research --max-cost-tier 2 --require-tags long-context
|
|
119
|
+
pai worker classes unset research
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Every provider carries a **cost tier** (1 cheapest … 5 most expensive,
|
|
123
|
+
default 3) and **tags** (`code`, `vision`, `image-gen`, `long-context`,
|
|
124
|
+
`fast`, `reasoning`). A class resolves its provider as:
|
|
125
|
+
|
|
126
|
+
1. `--provider` (explicit flag) wins;
|
|
127
|
+
2. else the class mapping when it pins a provider;
|
|
128
|
+
3. else auto-routing (see below) restricted to providers within the class's
|
|
129
|
+
`maxCostTier` and carrying all its `requireTags`;
|
|
130
|
+
4. nothing qualifies → the run fails with a message listing why every
|
|
131
|
+
provider was excluded.
|
|
132
|
+
|
|
133
|
+
`classes.<name>.order` overrides `routing.order` for that class. Cooldown and
|
|
134
|
+
quota logic is unchanged.
|
|
135
|
+
|
|
136
|
+
### Preferences from chat
|
|
137
|
+
|
|
138
|
+
The Worker skill maps phrases onto the MCP tools — the answer is one or two
|
|
139
|
+
lines, and the user is never told to edit a file:
|
|
140
|
+
|
|
141
|
+
- "use X for image generation" / "route research to kimi" →
|
|
142
|
+
`worker_classes set <class>=<provider>`
|
|
143
|
+
- "prefer the flash model for simple tasks" / "cheap only for drafts" →
|
|
144
|
+
`worker_classes set simple|draft=<provider>/fast` (or `max_cost_tier`)
|
|
145
|
+
- "reviews should use a reasoning model" → `worker_classes set review` with
|
|
146
|
+
`require_tags: ["reasoning"]`
|
|
147
|
+
- "what handles reviews" / "show the routing table" → `worker_classes list`
|
|
148
|
+
|
|
96
149
|
## The proxy (OpenAI-protocol providers)
|
|
97
150
|
|
|
98
151
|
A provider with `protocol: "openai"` cannot be talked to by Claude Code
|
|
@@ -135,6 +188,8 @@ so it is unavailable for codex workers (their thread id is kept, but
|
|
|
135
188
|
pai worker run --label "fix black buttons" -p '<task spec>' \
|
|
136
189
|
--allowedTools 'Read,Edit,Write,Bash,Grep,Glob' --output-format json \
|
|
137
190
|
--mcp office
|
|
191
|
+
pai worker run --chain draft,implement -p '<brief>' # spec-first (below)
|
|
192
|
+
pai worker run --agent engineer -p '<task>' # agent library (below)
|
|
138
193
|
pai worker ps # this session's workers
|
|
139
194
|
pai worker follow [id] # live transcript (type to talk to it)
|
|
140
195
|
pai worker replay <id> # transcript of one worker
|
|
@@ -145,10 +200,46 @@ pai worker proxy [--port N|stop] # the translating proxy, by hand
|
|
|
145
200
|
pai worker log [all|tail|<id>] # raw streams + routing ledger
|
|
146
201
|
```
|
|
147
202
|
|
|
148
|
-
|
|
149
|
-
`--no-pane` suppresses the iTerm follow
|
|
150
|
-
|
|
151
|
-
contract below is added alongside it, not
|
|
203
|
+
Classes pick the provider for a task class: `--class implement|research|spotcheck|…`
|
|
204
|
+
(`--role` still works as its alias). `--no-pane` suppresses the iTerm follow
|
|
205
|
+
pane; `--provider <name>` bypasses classes entirely. If you bring your own
|
|
206
|
+
`--append-system-prompt`, the worker contract below is added alongside it, not
|
|
207
|
+
instead.
|
|
208
|
+
|
|
209
|
+
## Chains (draft → implement → review)
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
pai worker run --chain draft,implement -p '<brief>'
|
|
213
|
+
pai worker run --chain draft,implement,review -p '<brief>' # + review pass
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
- The **draft** class turns the brief into a full spec file under
|
|
217
|
+
`<logDir>/specs/<chain id>.md` — goal, constraints, files likely touched,
|
|
218
|
+
acceptance checks, verification commands. It reads the repository first and
|
|
219
|
+
implements nothing.
|
|
220
|
+
- **implement** (or any other stage class) runs with that spec as its prompt
|
|
221
|
+
and the original brief attached.
|
|
222
|
+
- **review** reads the spec and the working-tree diff and produces the
|
|
223
|
+
structured report.
|
|
224
|
+
- Each stage is its own worker: own id, own pane, `parent` set to the chain
|
|
225
|
+
id — `ps` shows the chain as a tree.
|
|
226
|
+
- A stage that fails stops the chain (the exit code is the first failing
|
|
227
|
+
stage's); a draft that produces no spec stops it with a message telling the
|
|
228
|
+
caller to write the spec and re-run without the draft stage.
|
|
229
|
+
- `--class` alongside `--chain` overrides the class of every stage; `--label`
|
|
230
|
+
names the chain (stages render as `<label> · <stage>`).
|
|
231
|
+
|
|
232
|
+
## Agent definitions as workers
|
|
233
|
+
|
|
234
|
+
`pai worker run --agent <name>` loads `~/.claude/agents/<name>.md` and runs it
|
|
235
|
+
on a worker: the front matter's `model` maps to a class (haiku→simple,
|
|
236
|
+
sonnet→implement, opus→complex — `--class` overrides), `tools` becomes
|
|
237
|
+
`--allowedTools`, and the body is passed via `--append-system-prompt` (your
|
|
238
|
+
own flags on the command line still win). The label defaults to
|
|
239
|
+
`<agent>: <first 50 chars of prompt>`.
|
|
240
|
+
|
|
241
|
+
The agent library therefore runs on workers, not on the orchestrator's
|
|
242
|
+
Anthropic account — same hooks, same classes, same `ps`/`follow`/`replay`.
|
|
152
243
|
|
|
153
244
|
The old habits keep working: `glm`, `glm-run`, `glm-ps`, `glm-log` are shims
|
|
154
245
|
to the pai commands (`pai worker install` moves any previous versions to
|
|
@@ -156,13 +247,19 @@ to the pai commands (`pai worker install` moves any previous versions to
|
|
|
156
247
|
|
|
157
248
|
## Routing
|
|
158
249
|
|
|
159
|
-
A run resolves its provider as: `--provider` > `--
|
|
250
|
+
A run resolves its provider as: `--provider` > `--class` > `active`.
|
|
160
251
|
|
|
161
|
-
With `active: "auto"`, providers are tried in `routing.order
|
|
252
|
+
With `active: "auto"`, providers are tried in `routing.order` (or the class's
|
|
253
|
+
own `order`), skipping:
|
|
162
254
|
|
|
163
255
|
- disabled providers,
|
|
164
256
|
- providers in a cooldown (set for `cooldownMinutes` after a quota failure),
|
|
165
|
-
- providers whose `quotaProbe` URL reports ≥ `quotaSkipAt` (default 95)
|
|
257
|
+
- providers whose `quotaProbe` URL reports ≥ `quotaSkipAt` (default 95),
|
|
258
|
+
- providers above the class's `maxCostTier` or missing one of its
|
|
259
|
+
`requireTags`.
|
|
260
|
+
|
|
261
|
+
Nothing qualifying fails the run with the exclusion reason of every provider
|
|
262
|
+
in the order.
|
|
166
263
|
|
|
167
264
|
A quota failure before the first tool call is re-run on the next provider and
|
|
168
265
|
logged as `WORKER-REROUTE`. `pai worker providers enable <name>` clears a
|
|
@@ -213,9 +310,116 @@ stdin closes two seconds later unless another message arrives — after that
|
|
|
213
310
|
|
|
214
311
|
`pai worker resume <id> "<text>"` continues the same Claude session (the id
|
|
215
312
|
recorded from the init event) on the same provider, labelled `↩ <original>`,
|
|
216
|
-
and prints a fresh worker id with `--print-id`.
|
|
217
|
-
|
|
218
|
-
|
|
313
|
+
and prints a fresh worker id with `--print-id`.
|
|
314
|
+
|
|
315
|
+
A `follow <id>` pane on a TTY is a chat, not a tail: the transcript lives in
|
|
316
|
+
a scroll region that ends two rows above the pane's bottom, the last two rows
|
|
317
|
+
are fixed — the prompt row (`› `, full readline editing: arrows, backspace,
|
|
318
|
+
Ctrl-A/E, Ctrl-U) and the ticker row — and every transcript line is inserted
|
|
319
|
+
above them with a save-cursor / restore-cursor write, so the cursor never
|
|
320
|
+
leaves the prompt. Enter sends the line: said to the worker while it runs,
|
|
321
|
+
`resume`d into the same session once it has finished (the pane follows the
|
|
322
|
+
fresh run id and keeps the chat). The sent line is echoed into the transcript
|
|
323
|
+
as a `»` row with its time gutter, exactly once — the mirrored `operator`
|
|
324
|
+
event is swallowed. `/help` lists the commands:
|
|
325
|
+
|
|
326
|
+
| key | action |
|
|
327
|
+
| --- | --- |
|
|
328
|
+
| `/quit` | close the pane |
|
|
329
|
+
| `/resume <text>` | resume the finished worker with `<text>` |
|
|
330
|
+
| `/status` | one-line worker status |
|
|
331
|
+
| anything else | a message — said, or resumed |
|
|
332
|
+
|
|
333
|
+
Ctrl-C on an empty prompt leaves the pane, on a draft it clears the prompt;
|
|
334
|
+
Ctrl-D leaves. The auto-exit countdown never fires while the prompt holds
|
|
335
|
+
unsent text. Without a TTY (piped output) the pane keeps the plain scrolling
|
|
336
|
+
behaviour — no prompt row, no ticker, stdin still the operator channel.
|
|
337
|
+
|
|
338
|
+
### Sub-workers and handoffs
|
|
339
|
+
|
|
340
|
+
Any worker may start its own workers: the runner exports `PAI_WORKER_ID` in
|
|
341
|
+
every worker's environment, and a `pai worker run` launched from inside one
|
|
342
|
+
records `parent` in its status — so the forest is visible in `ps` (children
|
|
343
|
+
indented under their parent, `├`/`└` connectors), the status line (`↳` under
|
|
344
|
+
the parent) and each child gets its own follow pane. Handoffs travel **up
|
|
345
|
+
only**, from a child to its parent:
|
|
346
|
+
|
|
347
|
+
```
|
|
348
|
+
pai worker handoff '{"kind":"proposal","text":"run this on a cheap provider","data":{…}}'
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
(or the MCP tool `worker_handoff`; kinds `proposal`, `question`, `blocker` —
|
|
352
|
+
`result` is sent automatically when a child finishes). The handoff is appended
|
|
353
|
+
to `<logDir>/<parent>.inbox.jsonl` (durable, ordered) and, when the parent is
|
|
354
|
+
running, also delivered as an operator message `[handoff from <child id>]`. The
|
|
355
|
+
parent sees it in its pane (`◆ from <id> · kind: text`, magenta), `ps` and the
|
|
356
|
+
status line show `◆N` for an inbox with N handoffs, and `replay`/`follow`
|
|
357
|
+
merge them into the transcript by timestamp. There is no sideways channel:
|
|
358
|
+
siblings never see each other, everything goes up.
|
|
359
|
+
|
|
360
|
+
Two caps keep the tree bounded (`workers.tree`):
|
|
361
|
+
|
|
362
|
+
- `maxDepth` (default 2) — how deep sub-workers may nest; a launch one level
|
|
363
|
+
past the cap fails with a message that suggests a handoff instead,
|
|
364
|
+
- `maxChildren` (default 4) — how many children of one parent may run at the
|
|
365
|
+
same time (finished children do not count).
|
|
366
|
+
|
|
367
|
+
Chain stages and planner sub-tasks carry a parent too, but a parent without a
|
|
368
|
+
status file (a chain id) is not a worker and is never capped by depth.
|
|
369
|
+
|
|
370
|
+
### Worktrees and merge
|
|
371
|
+
|
|
372
|
+
A run whose class writes files (`implement`, `complex`, `plan`) in a git repo,
|
|
373
|
+
with a prompt that is not read-only, gets **its own git worktree** by default:
|
|
374
|
+
`<logDir>/worktrees/<id>` on branch `worker/<id>` from the current HEAD. The
|
|
375
|
+
worker commits its work on that branch (the no-commit rule applies to the main
|
|
376
|
+
branch only — the appended system prompt says so); when git refuses (no
|
|
377
|
+
commits yet, detached setup) the run degrades to in place with a note on
|
|
378
|
+
stderr and in the ledger.
|
|
379
|
+
|
|
380
|
+
```
|
|
381
|
+
pai worker merge <id> # git merge --no-ff worker/<id> + remove the worktree
|
|
382
|
+
pai worker discard <id> # remove worktree and branch, keep nothing
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
`ps` marks a worker with an unmerged branch `⎇<commits>` (yellow); the status
|
|
386
|
+
file records `branch`, `commits` and `worktreeDir`. Chains give a worktree to
|
|
387
|
+
the implement stage only; `--worktree` forces one on, `--no-worktree` opts
|
|
388
|
+
out.
|
|
389
|
+
|
|
390
|
+
### The planner class
|
|
391
|
+
|
|
392
|
+
`--class plan` runs a small orchestration, not one worker:
|
|
393
|
+
|
|
394
|
+
1. a planner worker reads the repository and writes
|
|
395
|
+
`<logDir>/plans/<planner id>.json` — sub-tasks (`title`, `brief`, `class`,
|
|
396
|
+
`files`, `acceptance`), 5–50 of them, fewer only when the goal names a
|
|
397
|
+
smaller count;
|
|
398
|
+
2. the runner validates the plan and spawns the sub-tasks as children of the
|
|
399
|
+
planner, at most `workers.tree.maxChildren` at a time;
|
|
400
|
+
3. each child's structured report arrives in the planner's inbox as a
|
|
401
|
+
`kind: "result"` handoff;
|
|
402
|
+
4. the run finishes with a summary report (`n/m sub-tasks ok`) and the
|
|
403
|
+
`pai worker merge` lines for any unmerged branches.
|
|
404
|
+
|
|
405
|
+
The planner's prompt carries the prompt rules that make plans executable:
|
|
406
|
+
domain-specific instructions only (real files, real commands), constraints
|
|
407
|
+
over step lists, explicit quantity ranges, no checkbox style.
|
|
408
|
+
|
|
409
|
+
### Clickr controls (desktop set)
|
|
410
|
+
|
|
411
|
+
The default `mcpSets` ship one set: `desktop = ["clickr"]`. A worker launched
|
|
412
|
+
`--mcp desktop` receives the clickr MCP server — screen control for GUI work
|
|
413
|
+
— and follows the same control handover as a session:
|
|
414
|
+
|
|
415
|
+
```
|
|
416
|
+
pai worker controls <id> you # hand control of the desktop to the worker
|
|
417
|
+
pai worker controls <id> me # take it back
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
`controls` runs the `clickr controls you|me` CLI and the worker's screenshot
|
|
421
|
+
and input tools honour it. Control starts with the operator: a worker cannot
|
|
422
|
+
drive the desktop until it is handed over.
|
|
219
423
|
|
|
220
424
|
### Context meter
|
|
221
425
|
|
|
@@ -239,7 +443,7 @@ pai worker run --mcp office … # a set, or names: --mcp memory,github
|
|
|
239
443
|
`--mcp` takes server names and/or `mcpSets` names (comma-separated,
|
|
240
444
|
repeatable); the filtered config is written from `~/.claude.json`'s
|
|
241
445
|
`mcpServers` to `<logDir>/<id>.mcp.json` and passed with
|
|
242
|
-
`--strict-mcp-config --mcp-config`.
|
|
446
|
+
`--strict-mcp-config --mcp-config`. Class targets may add `"mcp": ["office"]`
|
|
243
447
|
on top. An unknown name fails fast, listing what exists;
|
|
244
448
|
`pai worker mcp list` shows servers and sets. A caller-provided
|
|
245
449
|
`--mcp-config` always wins; MCP is chosen at launch, not mid-run.
|
|
@@ -263,6 +467,17 @@ separator when the day changes) and, on a TTY, a liveness line
|
|
|
263
467
|
erased before the next event. `replay` shows a finished transcript with the
|
|
264
468
|
same gutter.
|
|
265
469
|
|
|
470
|
+
The pane wraps rows itself at the terminal width (re-read on resize, so a
|
|
471
|
+
narrower pane re-wraps what arrives after the resize): breaks on whitespace
|
|
472
|
+
where it can, hard-wraps a long token otherwise, never splits an ANSI escape
|
|
473
|
+
(it measures printable columns, not string length), and carries diff colours
|
|
474
|
+
onto every continuation row. Each continuation row carries a blank-time
|
|
475
|
+
gutter with the `│` bar kept — the bar runs unbroken down the pane and no
|
|
476
|
+
content ever lands left of it. In the chat layout the transcript scrolls
|
|
477
|
+
inside an ANSI scroll region (`ESC[1;rows-2r`, reset on exit and re-set on
|
|
478
|
+
resize) so the prompt and ticker rows stay fixed; piped output keeps the
|
|
479
|
+
terminal's own wrapping instead.
|
|
480
|
+
|
|
266
481
|
The pane command is `exec pai worker follow …` so the pane holds exactly one
|
|
267
482
|
process — signals reach the follow directly, and when the worker finishes
|
|
268
483
|
the pane counts down its `auto-exit` (default 60 s, `pane.autoExitSecs`).
|
|
@@ -288,12 +503,16 @@ background instead. Decisions are ledgered (`DENIED-ANTHROPIC-AGENT`,
|
|
|
288
503
|
|
|
289
504
|
## MCP tools
|
|
290
505
|
|
|
291
|
-
`worker_status`, `worker_providers`
|
|
292
|
-
|
|
293
|
-
`
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
506
|
+
`worker_status`, `worker_providers`
|
|
507
|
+
(list/add/update/remove/use/enable/disable/test — `update` changes
|
|
508
|
+
`cost_tier`/`tags`), `worker_classes` (list/set/unset), `worker_run` (start a
|
|
509
|
+
worker or chain from chat, returns the id immediately), `worker_toggle`,
|
|
510
|
+
`worker_ps`, `worker_replay`, `worker_say` (message a running worker),
|
|
511
|
+
`worker_resume` (continue a finished one), `worker_handoff` (from inside a
|
|
512
|
+
worker: send a proposal/question/blocker up to its parent) — the same library
|
|
513
|
+
the CLI calls.
|
|
514
|
+
`worker_providers add` accepts a raw `key`, parks it in
|
|
515
|
+
`~/.config/pai/keys/<name>` (mode 0600) and stores only the path.
|
|
297
516
|
|
|
298
517
|
## Status line
|
|
299
518
|
|
package/package.json
CHANGED
|
@@ -112,10 +112,10 @@ async function main(): Promise<void> {
|
|
|
112
112
|
deny(
|
|
113
113
|
"Agent tool is disabled: subagents run on the configured worker provider, not Anthropic. " +
|
|
114
114
|
"Delegate with Bash instead, in the background:\n\n" +
|
|
115
|
-
`pai worker run --label "${label || "task"}" --
|
|
115
|
+
`pai worker run --label "${label || "task"}" --class research -p '<full, self-contained task spec>' ` +
|
|
116
116
|
"--allowedTools 'Read,Edit,Write,Bash,Grep,Glob' --output-format json\n\n" +
|
|
117
117
|
"- Run it with run_in_background: true and always with a timeout.\n" +
|
|
118
|
-
"- Use --
|
|
118
|
+
"- Use --class spotcheck (or implement) as the task demands.\n" +
|
|
119
119
|
"- Web research: add WebSearch,WebFetch to --allowedTools.\n" +
|
|
120
120
|
"- The answer is in the `result` field of the JSON it prints. Review the diff yourself.\n" +
|
|
121
121
|
"- pai worker ps lists running workers; pai worker follow <id> shows one live.\n" +
|