@tekmidian/pai 0.37.0 → 0.38.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/cli/index.mjs +2 -2
- package/dist/cli/program.mjs +2 -2
- package/dist/daemon-mcp/index.mjs +153 -32
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/hooks/route-agents-to-worker.mjs +76 -14
- package/dist/hooks/route-agents-to-worker.mjs.map +2 -2
- package/dist/hooks/worker-proxy.mjs +76 -14
- package/dist/hooks/worker-proxy.mjs.map +2 -2
- package/dist/hooks/worker-status-line.mjs +76 -14
- package/dist/hooks/worker-status-line.mjs.map +2 -2
- package/dist/{program-CEIHn_Ma.mjs → program-Y0hAiVy8.mjs} +207 -49
- package/dist/program-Y0hAiVy8.mjs.map +1 -0
- package/dist/{providers-sXcK5bDZ.mjs → providers-DUshcB-d.mjs} +1171 -207
- package/dist/providers-DUshcB-d.mjs.map +1 -0
- package/dist/skills/Worker/SKILL.md +34 -12
- package/docs/commands/README.md +8 -7
- package/docs/commands/worker.md +54 -17
- package/docs/worker.md +156 -25
- package/package.json +1 -1
- package/dist/program-CEIHn_Ma.mjs.map +0 -1
- package/dist/providers-sXcK5bDZ.mjs.map +0 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -7,13 +7,13 @@ import "../helpers-IjZkXBhj.mjs";
|
|
|
7
7
|
import "../sync-BWbe8JTg.mjs";
|
|
8
8
|
import "../embeddings-DOLZnT1X.mjs";
|
|
9
9
|
import "../search-Rpk1cSBC.mjs";
|
|
10
|
-
import { n as drainStdio, t as buildProgram } from "../program-
|
|
10
|
+
import { n as drainStdio, t as buildProgram } from "../program-Y0hAiVy8.mjs";
|
|
11
11
|
import "../context-handover-cache-BpUojjsi.mjs";
|
|
12
12
|
import "../indexer-D7MvSQPY.mjs";
|
|
13
13
|
import "../ipc-client-BmypMNYk.mjs";
|
|
14
14
|
import "../config-B64vFg14.mjs";
|
|
15
15
|
import "../factory-DD2T33C9.mjs";
|
|
16
|
-
import "../providers-
|
|
16
|
+
import "../providers-DUshcB-d.mjs";
|
|
17
17
|
import "../main-resolver-DlaLOFBA.mjs";
|
|
18
18
|
import { CommanderError } from "commander";
|
|
19
19
|
|
package/dist/cli/program.mjs
CHANGED
|
@@ -6,13 +6,13 @@ import "../helpers-IjZkXBhj.mjs";
|
|
|
6
6
|
import "../sync-BWbe8JTg.mjs";
|
|
7
7
|
import "../embeddings-DOLZnT1X.mjs";
|
|
8
8
|
import "../search-Rpk1cSBC.mjs";
|
|
9
|
-
import { t as buildProgram } from "../program-
|
|
9
|
+
import { t as buildProgram } from "../program-Y0hAiVy8.mjs";
|
|
10
10
|
import "../context-handover-cache-BpUojjsi.mjs";
|
|
11
11
|
import "../indexer-D7MvSQPY.mjs";
|
|
12
12
|
import "../ipc-client-BmypMNYk.mjs";
|
|
13
13
|
import "../config-B64vFg14.mjs";
|
|
14
14
|
import "../factory-DD2T33C9.mjs";
|
|
15
|
-
import "../providers-
|
|
15
|
+
import "../providers-DUshcB-d.mjs";
|
|
16
16
|
import "../main-resolver-DlaLOFBA.mjs";
|
|
17
17
|
|
|
18
18
|
export { buildProgram };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as PaiClient } from "../ipc-client-BmypMNYk.mjs";
|
|
3
3
|
import { o as loadConfig } from "../config-B64vFg14.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { A as ledgerPath, D as ledgerSummary, E as loadStatus, P as readWorkersSection, _ as testProvider, a as setClass, c as unsetClass, f as psOutput, g as runWorker, h as runChain, i as removeProvider, j as workersLogDir, l as updateProvider, n as classTargetText, o as setProviderEnabled, p as replayOutput, r as describeProviders, s as setWorkersEnabled, t as addProvider, u as useProvider, x as sayToWorker } from "../providers-DUshcB-d.mjs";
|
|
5
5
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
7
|
|
|
@@ -4524,40 +4524,62 @@ const worker = {
|
|
|
4524
4524
|
description: "Run, watch and route subagent workers on configured providers",
|
|
4525
4525
|
content: `## Worker Skill
|
|
4526
4526
|
|
|
4527
|
-
USE WHEN delegating subagent work, checking on running workers, or managing worker providers.
|
|
4527
|
+
USE WHEN delegating subagent work, checking on running workers, or managing worker providers/classes from chat.
|
|
4528
4528
|
|
|
4529
4529
|
### Delegating
|
|
4530
4530
|
|
|
4531
4531
|
The Agent tool is denied when workers are on — delegate with Bash instead:
|
|
4532
4532
|
|
|
4533
4533
|
\`\`\`
|
|
4534
|
-
pai worker run --label "short task label" --
|
|
4534
|
+
pai worker run --label "short task label" --class research \\
|
|
4535
4535
|
-p '<full, self-contained task spec>' \\
|
|
4536
4536
|
--allowedTools 'Read,Edit,Write,Bash,Grep,Glob' --output-format json
|
|
4537
4537
|
\`\`\`
|
|
4538
4538
|
|
|
4539
4539
|
- Always run in background (run_in_background: true) and with a timeout.
|
|
4540
|
-
-
|
|
4540
|
+
- Classes: draft (spec writing), plan, implement (default quality), review,
|
|
4541
|
+
research (web: add WebSearch,WebFetch), spotcheck (cheap/fast model), simple,
|
|
4542
|
+
complex, image. \`--role\` still works as an alias of \`--class\`.
|
|
4543
|
+
- Anything larger than a one-file change goes through a chain:
|
|
4544
|
+
\`pai worker run --chain draft,implement …\` — the draft stage turns the brief
|
|
4545
|
+
into a spec file, implement runs with it, \`--chain draft,implement,review\`
|
|
4546
|
+
adds a review pass. \`--class spotcheck\` for verification runs.
|
|
4541
4547
|
- The answer is in the \`result\` field of the JSON it prints. Review the diff yourself.
|
|
4542
4548
|
- \`--no-pane\` suppresses the iTerm follow pane; panes open automatically otherwise.
|
|
4543
|
-
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4549
|
+
- \`--agent <name>\` runs a definition from ~/.claude/agents/<name>.md (the agent
|
|
4550
|
+
library runs on workers: body becomes the system prompt, tools the allowlist,
|
|
4551
|
+
model the class).
|
|
4546
4552
|
|
|
4547
4553
|
### Watching
|
|
4548
4554
|
|
|
4549
|
-
- \`worker_ps\` — running + last finished workers.
|
|
4555
|
+
- \`worker_ps\` — running + last finished workers (chains show as trees).
|
|
4550
4556
|
- \`worker_replay\` with id — the transcript of one worker.
|
|
4551
4557
|
- CLI equivalents: \`pai worker ps\`, \`pai worker follow <id>\`.
|
|
4552
4558
|
|
|
4553
4559
|
### Routing
|
|
4554
4560
|
|
|
4555
4561
|
- \`worker_status\` — on/off, active provider, providers, run tally.
|
|
4556
|
-
- \`worker_providers\` — list/add/remove/use/enable/disable/test. Adding
|
|
4557
|
-
name, base_url, model and a key (key file path, or a raw key which is
|
|
4558
|
-
parked in ~/.config/pai/keys/<name>, mode 0600).
|
|
4559
|
-
|
|
4560
|
-
-
|
|
4562
|
+
- \`worker_providers\` — list/add/update/remove/use/enable/disable/test. Adding
|
|
4563
|
+
needs name, base_url, model and a key (key file path, or a raw key which is
|
|
4564
|
+
parked in ~/.config/pai/keys/<name>, mode 0600). update changes cost_tier
|
|
4565
|
+
(1 cheapest … 5 most expensive) and tags (code, vision, image-gen,
|
|
4566
|
+
long-context, fast, reasoning).
|
|
4567
|
+
- \`worker_classes\` — list/set/unset class → provider[/fast], or constraints
|
|
4568
|
+
only (max_cost_tier, require_tags) so auto-routing picks a qualifying provider.
|
|
4569
|
+
- \`worker_run\` — start a worker or chain from chat; returns the id immediately.
|
|
4570
|
+
- \`worker_toggle\` — off makes Agent subagents run on Anthropic again.
|
|
4571
|
+
|
|
4572
|
+
### Preferences from chat (map the phrase, use the tool, never mention files)
|
|
4573
|
+
|
|
4574
|
+
- "use <provider> for image generation" / "route research to <provider>" →
|
|
4575
|
+
worker_classes set <class>=<provider>. One line back.
|
|
4576
|
+
- "prefer the flash model for simple tasks" / "cheap only for drafts" →
|
|
4577
|
+
worker_classes set simple|draft=<provider>/fast (or a max_cost_tier). One line.
|
|
4578
|
+
- "reviews should use a reasoning model" → worker_classes set review with
|
|
4579
|
+
require_tags ["reasoning"] (drop the pin if one exists). One line.
|
|
4580
|
+
- "what handles reviews" / "show the routing table" → worker_classes list
|
|
4581
|
+
(plus worker_status for providers). One or two lines.
|
|
4582
|
+
- Never tell the user to edit a config file — the tools do it.`
|
|
4561
4583
|
};
|
|
4562
4584
|
|
|
4563
4585
|
//#endregion
|
|
@@ -5738,20 +5760,22 @@ async function startShim() {
|
|
|
5738
5760
|
}
|
|
5739
5761
|
});
|
|
5740
5762
|
server.tool("worker_providers", [
|
|
5741
|
-
"Manage worker providers (list, add, remove, use, enable, disable, test).",
|
|
5763
|
+
"Manage worker providers (list, add, update, remove, use, enable, disable, test).",
|
|
5742
5764
|
"",
|
|
5743
|
-
"action=list (default) shows providers,
|
|
5765
|
+
"action=list (default) shows providers (with cost tier and tags), classes and routing.",
|
|
5744
5766
|
"action=add needs name, model — and either key_file or key, plus:",
|
|
5745
5767
|
" base_url (anthropic protocol) or upstream_url (protocol=openai, runs",
|
|
5746
5768
|
" through the local PAI proxy). A raw key is written to",
|
|
5747
5769
|
" ~/.config/pai/keys/<name> (mode 0600); only the path lands in the config.",
|
|
5748
5770
|
" engine=codex runs the Codex CLI instead of Claude Code.",
|
|
5771
|
+
"action=update changes cost_tier / tags of an existing provider.",
|
|
5749
5772
|
"action=test runs a one-word pong probe through the provider",
|
|
5750
5773
|
" (reports 'codex not installed' when that engine's CLI is missing)."
|
|
5751
5774
|
].join("\n"), {
|
|
5752
5775
|
action: _enum([
|
|
5753
5776
|
"list",
|
|
5754
5777
|
"add",
|
|
5778
|
+
"update",
|
|
5755
5779
|
"remove",
|
|
5756
5780
|
"use",
|
|
5757
5781
|
"enable",
|
|
@@ -5770,12 +5794,29 @@ async function startShim() {
|
|
|
5770
5794
|
fast_model: string().optional().describe("Cheaper model for spotchecks (add, optional)."),
|
|
5771
5795
|
env: record(string(), string()).optional().describe("Extra env for runs (add, optional)."),
|
|
5772
5796
|
note: string().optional().describe("Human note shown in listings (add, optional)."),
|
|
5773
|
-
quota_probe: string().optional().describe("URL whose JSON first number is the quota percent (add, optional).")
|
|
5797
|
+
quota_probe: string().optional().describe("URL whose JSON first number is the quota percent (add, optional)."),
|
|
5798
|
+
cost_tier: number().int().min(1).max(5).optional().describe("Cost tier 1 (cheapest) … 5 (most expensive). Default 3. (add, update)"),
|
|
5799
|
+
tags: array(_enum([
|
|
5800
|
+
"code",
|
|
5801
|
+
"vision",
|
|
5802
|
+
"image-gen",
|
|
5803
|
+
"long-context",
|
|
5804
|
+
"fast",
|
|
5805
|
+
"reasoning"
|
|
5806
|
+
])).optional().describe("Capability tags (add, update).")
|
|
5774
5807
|
}, async (args) => {
|
|
5775
5808
|
try {
|
|
5776
5809
|
const action = args.action ?? "list";
|
|
5777
5810
|
if (action === "list") return workerText(describeProviders(readWorkersSection().workers).join("\n"));
|
|
5778
5811
|
if (!args.name) return workerError(/* @__PURE__ */ new Error("name is required for this action"));
|
|
5812
|
+
if (action === "update") {
|
|
5813
|
+
if (args.cost_tier === void 0 && args.tags === void 0) return workerError(/* @__PURE__ */ new Error("update needs cost_tier and/or tags"));
|
|
5814
|
+
updateProvider(args.name, {
|
|
5815
|
+
...args.cost_tier !== void 0 ? { costTier: args.cost_tier } : {},
|
|
5816
|
+
...args.tags !== void 0 ? { tags: args.tags } : {}
|
|
5817
|
+
});
|
|
5818
|
+
return workerText([`provider ${args.name} updated`, ...describeProviders(readWorkersSection().workers)].join("\n"));
|
|
5819
|
+
}
|
|
5779
5820
|
if (action === "add") {
|
|
5780
5821
|
if (!args.model) return workerError(/* @__PURE__ */ new Error("add needs model"));
|
|
5781
5822
|
if (args.protocol !== "openai" && !args.base_url) return workerError(/* @__PURE__ */ new Error("add needs base_url (only protocol=openai goes without it)"));
|
|
@@ -5792,7 +5833,9 @@ async function startShim() {
|
|
|
5792
5833
|
...args.upstream_url ? { upstreamUrl: args.upstream_url } : {},
|
|
5793
5834
|
...args.engine ? { engine: args.engine } : {},
|
|
5794
5835
|
...args.context_window ? { contextWindow: args.context_window } : {},
|
|
5795
|
-
...args.quota_probe ? { quotaProbe: args.quota_probe } : {}
|
|
5836
|
+
...args.quota_probe ? { quotaProbe: args.quota_probe } : {},
|
|
5837
|
+
...args.cost_tier !== void 0 ? { costTier: args.cost_tier } : {},
|
|
5838
|
+
...args.tags?.length ? { tags: args.tags } : {}
|
|
5796
5839
|
});
|
|
5797
5840
|
return workerText([`provider ${args.name} added; active: ${workers.active ?? "(none)"}; workers ${workers.enabled ? "on" : "off"}`, ...describeProviders(workers)].join("\n"));
|
|
5798
5841
|
}
|
|
@@ -5818,37 +5861,115 @@ async function startShim() {
|
|
|
5818
5861
|
return workerError(e);
|
|
5819
5862
|
}
|
|
5820
5863
|
});
|
|
5821
|
-
server.tool("
|
|
5822
|
-
"Manage worker
|
|
5864
|
+
server.tool("worker_classes", [
|
|
5865
|
+
"Manage worker classes (list, set, unset).",
|
|
5823
5866
|
"",
|
|
5824
|
-
"A
|
|
5867
|
+
"A class maps a task class to a provider, optionally its fast model:",
|
|
5825
5868
|
"implement=glm, research=glm, spotcheck=glm/fast.",
|
|
5826
|
-
"
|
|
5869
|
+
"set can instead give routing constraints only (max_cost_tier,",
|
|
5870
|
+
"require_tags) — auto-routing then picks a qualifying provider.",
|
|
5871
|
+
"Runs pick the provider via --class first, then the active provider."
|
|
5827
5872
|
].join("\n"), {
|
|
5828
5873
|
action: _enum([
|
|
5829
5874
|
"list",
|
|
5830
5875
|
"set",
|
|
5831
5876
|
"unset"
|
|
5832
5877
|
]).optional().describe("Default: list."),
|
|
5833
|
-
|
|
5834
|
-
target: string().optional().describe("Provider or provider/fast (set).")
|
|
5878
|
+
class: string().optional().describe("Class name (set/unset), e.g. implement, spotcheck."),
|
|
5879
|
+
target: string().optional().describe("Provider or provider/fast (set)."),
|
|
5880
|
+
max_cost_tier: number().int().min(1).max(5).optional().describe("Auto-routing considers only providers up to this cost tier (set)."),
|
|
5881
|
+
require_tags: array(_enum([
|
|
5882
|
+
"code",
|
|
5883
|
+
"vision",
|
|
5884
|
+
"image-gen",
|
|
5885
|
+
"long-context",
|
|
5886
|
+
"fast",
|
|
5887
|
+
"reasoning"
|
|
5888
|
+
])).optional().describe("Auto-routing needs these tags (set).")
|
|
5835
5889
|
}, async (args) => {
|
|
5836
5890
|
try {
|
|
5837
5891
|
const action = args.action ?? "list";
|
|
5838
5892
|
if (action === "list") {
|
|
5839
5893
|
const { workers } = readWorkersSection();
|
|
5840
|
-
const entries = Object.entries(workers.
|
|
5841
|
-
|
|
5842
|
-
return workerText(entries.length ? entries.map(([r, t]) => `${r}: ${text(t)}`).join("\n") : "no roles set");
|
|
5894
|
+
const entries = Object.entries(workers.classes);
|
|
5895
|
+
return workerText(entries.length ? entries.map(([cls, t]) => `${cls}: ${classTargetText(t)}`).join("\n") : "no classes set");
|
|
5843
5896
|
}
|
|
5844
|
-
if (!args.
|
|
5897
|
+
if (!args.class) return workerError(/* @__PURE__ */ new Error("class is required for this action"));
|
|
5845
5898
|
if (action === "set") {
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5899
|
+
const hasConstraints = args.max_cost_tier !== void 0 || args.require_tags !== void 0;
|
|
5900
|
+
if (!args.target && !hasConstraints) return workerError(/* @__PURE__ */ new Error("set needs target provider[/fast] and/or max_cost_tier/require_tags"));
|
|
5901
|
+
const target = args.target !== void 0 && !hasConstraints ? args.target : {
|
|
5902
|
+
...args.target ? { provider: args.target.split("/")[0] } : {},
|
|
5903
|
+
...args.max_cost_tier !== void 0 ? { maxCostTier: args.max_cost_tier } : {},
|
|
5904
|
+
...args.require_tags !== void 0 ? { requireTags: args.require_tags } : {}
|
|
5905
|
+
};
|
|
5906
|
+
setClass(args.class, target);
|
|
5907
|
+
return workerText(`class ${args.class} → ${classTargetText(target)}`);
|
|
5849
5908
|
}
|
|
5850
|
-
|
|
5851
|
-
return workerText(`
|
|
5909
|
+
unsetClass(args.class);
|
|
5910
|
+
return workerText(`class ${args.class} removed`);
|
|
5911
|
+
} catch (e) {
|
|
5912
|
+
return workerError(e);
|
|
5913
|
+
}
|
|
5914
|
+
});
|
|
5915
|
+
server.tool("worker_run", [
|
|
5916
|
+
"Start a worker (or a chain) and return its id immediately.",
|
|
5917
|
+
"",
|
|
5918
|
+
"This is the chat-side face of `pai worker run`: prompt is required,",
|
|
5919
|
+
"chain (e.g. \"draft,implement\") runs spec-first stages, class picks the",
|
|
5920
|
+
"provider (default: active). Check on it with worker_ps / worker_replay,",
|
|
5921
|
+
"talk to it with worker_say."
|
|
5922
|
+
].join("\n"), {
|
|
5923
|
+
prompt: string().min(1).describe("The task (the -p value)."),
|
|
5924
|
+
chain: string().optional().describe("Comma-separated stages, e.g. draft,implement or draft,implement,review."),
|
|
5925
|
+
class: string().optional().describe("Task class (draft, implement, review, research, spotcheck, simple, complex, image)."),
|
|
5926
|
+
label: string().optional().describe("Short task label shown in worker_ps."),
|
|
5927
|
+
cwd: string().optional().describe("Working directory (default: here)."),
|
|
5928
|
+
allowed_tools: string().optional().describe("Comma-separated tool allowlist passed to the worker."),
|
|
5929
|
+
mcp: string().optional().describe("MCP servers/sets the worker may use (comma-separated).")
|
|
5930
|
+
}, async (args) => {
|
|
5931
|
+
try {
|
|
5932
|
+
const claudeArgs = [
|
|
5933
|
+
"-p",
|
|
5934
|
+
args.prompt,
|
|
5935
|
+
...args.allowed_tools ? ["--allowedTools", args.allowed_tools] : []
|
|
5936
|
+
];
|
|
5937
|
+
let startedIdResolve;
|
|
5938
|
+
let startupFailure = null;
|
|
5939
|
+
const idArrived = new Promise((resolve) => {
|
|
5940
|
+
startedIdResolve = resolve;
|
|
5941
|
+
});
|
|
5942
|
+
const background = async () => {
|
|
5943
|
+
if (args.chain) return runChain({
|
|
5944
|
+
stages: args.chain.split(","),
|
|
5945
|
+
className: args.class,
|
|
5946
|
+
label: args.label,
|
|
5947
|
+
noPane: false,
|
|
5948
|
+
mcpFlag: args.mcp,
|
|
5949
|
+
brief: args.prompt,
|
|
5950
|
+
claudeArgs,
|
|
5951
|
+
...args.cwd ? { cwd: args.cwd } : {},
|
|
5952
|
+
onChainStart: (id) => startedIdResolve(id),
|
|
5953
|
+
quiet: true
|
|
5954
|
+
});
|
|
5955
|
+
return runWorker({
|
|
5956
|
+
className: args.class,
|
|
5957
|
+
label: args.label,
|
|
5958
|
+
noPane: false,
|
|
5959
|
+
mcpFlag: args.mcp,
|
|
5960
|
+
claudeArgs,
|
|
5961
|
+
...args.cwd ? { cwd: args.cwd } : {},
|
|
5962
|
+
onWorkerStart: (wid) => startedIdResolve(wid),
|
|
5963
|
+
quiet: true
|
|
5964
|
+
});
|
|
5965
|
+
};
|
|
5966
|
+
background().catch((e) => {
|
|
5967
|
+
startupFailure = e;
|
|
5968
|
+
startedIdResolve("");
|
|
5969
|
+
});
|
|
5970
|
+
const id = await Promise.race([idArrived, new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("worker did not start within 15s")), 15e3))]);
|
|
5971
|
+
if (!id) return workerError(startupFailure ?? /* @__PURE__ */ new Error("worker failed to start"));
|
|
5972
|
+
return workerText(`${id} started${args.chain ? ` (chain: ${args.chain})` : ""} — check on it with worker_ps, worker_replay, worker_say`);
|
|
5852
5973
|
} catch (e) {
|
|
5853
5974
|
return workerError(e);
|
|
5854
5975
|
}
|