pi-ptc-subagents 6.0.0 → 6.0.1
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/README.md +6 -3
- package/dist/index.js +24 -37
- package/docs/routes/create-a-task.md +15 -0
- package/docs/routes/manage-a-task.md +9 -0
- package/docs/routes/reach-the-web.md +15 -0
- package/docs/routes/report-what-you-did.md +9 -0
- package/docs/routes/run-a-phased-workflow.md +12 -0
- package/docs/routes/run-one-program.md +11 -0
- package/docs/routes/use-the-built-in-tools.md +7 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -70,9 +70,12 @@ Which one you get depends on whether `codemode` is loaded and callable. Nothing
|
|
|
70
70
|
|
|
71
71
|
## PTC mode
|
|
72
72
|
|
|
73
|
-
On a `full_ptc` session, PTC mode
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
On a `full_ptc` session, PTC mode adds a routing lead to the system prompt: batch your
|
|
74
|
+
tool calls into one program. `/ptc mode off` drops the lead.
|
|
75
|
+
|
|
76
|
+
It does not hide the built-in tools from the model. pi keeps a tool callable from a
|
|
77
|
+
program only while it is active, so narrowing the loadout would take `tools.read` away
|
|
78
|
+
from the program too — the two cannot both hold on pi 1.4.0.
|
|
76
79
|
|
|
77
80
|
## Configuration
|
|
78
81
|
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
@@ -4890,7 +4890,8 @@ function createPtcRunCodeTool(options) {
|
|
|
4890
4890
|
description: TOOLS$1.ptc_run_code.description(options.surface ?? "full_ptc"),
|
|
4891
4891
|
parameters: RUN_CODE_PARAMETERS,
|
|
4892
4892
|
renderResult: renderPtcResult("run_code"),
|
|
4893
|
-
execute: async (_id, args) => {
|
|
4893
|
+
execute: async (_id, args, _signal, _onUpdate, ctx) => {
|
|
4894
|
+
options.onToolContext?.(ctx);
|
|
4894
4895
|
const outcome = await runPtcProgram({
|
|
4895
4896
|
code: args.code,
|
|
4896
4897
|
surface: "run_code",
|
|
@@ -4936,7 +4937,8 @@ function createPtcWorkflowTool(options) {
|
|
|
4936
4937
|
description: TOOLS$1.ptc_workflow.description(options.surface ?? "full_ptc"),
|
|
4937
4938
|
parameters: WORKFLOW_PARAMETERS,
|
|
4938
4939
|
renderResult: renderPtcResult("workflow"),
|
|
4939
|
-
execute: async (_id, params) => {
|
|
4940
|
+
execute: async (_id, params, _signal, _onUpdate, ctx) => {
|
|
4941
|
+
options.onToolContext?.(ctx);
|
|
4940
4942
|
try {
|
|
4941
4943
|
validateWorkflowArgs(params.args);
|
|
4942
4944
|
} catch (error) {
|
|
@@ -5116,11 +5118,11 @@ const ROUTE_INDEX_LEAD = {
|
|
|
5116
5118
|
full_ptc: "批量调工具默认先写程序(ptc_run_code);单次调用或要逐步判断、审批敏感的才直连。",
|
|
5117
5119
|
codemode_ptc: "编排写 codemode 脚本;批量派活经脚本内的 pi_task_codemode;要查/停任务用任务面三工具。"
|
|
5118
5120
|
};
|
|
5119
|
-
function renderRouteIndex(surface) {
|
|
5120
|
-
const lines = ROUTES.map((route) => `- ${route.name} — ${route.when}。这面怎么走:${route.how[surface]}。细节:${route.detail}`);
|
|
5121
|
+
function renderRouteIndex(surface, detailBase, nudge = true) {
|
|
5122
|
+
const lines = ROUTES.map((route) => `- ${route.name} — ${route.when}。这面怎么走:${route.how[surface]}。细节:${detailBase ? join(detailBase, route.detail.split("/").pop()) : route.detail}`);
|
|
5121
5123
|
let index = [
|
|
5122
5124
|
`<ptc>`,
|
|
5123
|
-
ROUTE_INDEX_LEAD[surface],
|
|
5125
|
+
...nudge ? [ROUTE_INDEX_LEAD[surface]] : [],
|
|
5124
5126
|
"路由表(一条一行,详情按需 read):",
|
|
5125
5127
|
...lines,
|
|
5126
5128
|
`</ptc>`
|
|
@@ -5221,6 +5223,9 @@ const textResult = (value) => ({
|
|
|
5221
5223
|
}],
|
|
5222
5224
|
details: void 0
|
|
5223
5225
|
});
|
|
5226
|
+
const packageRoot = fileURLToPath(new URL("..", import.meta.url));
|
|
5227
|
+
const publishedDetailDir = join(packageRoot, "docs", "routes");
|
|
5228
|
+
const detailDir = existsSync(publishedDetailDir) ? publishedDetailDir : join(packageRoot, "..", "routes", "docs", "routes");
|
|
5224
5229
|
function piPtcEntry(pi) {
|
|
5225
5230
|
pi.on("session_start", (_event, ctx) => {
|
|
5226
5231
|
if (Number(process.env.PI_PTC_DEPTH ?? 0) > 0) {
|
|
@@ -5230,37 +5235,15 @@ function piPtcEntry(pi) {
|
|
|
5230
5235
|
const surface = pi.getActiveTools().includes("codemode") ? "codemode_ptc" : FALLBACK_SURFACE_MODE;
|
|
5231
5236
|
let modeEnabled = readDefaultModeConfig(getAgentDir());
|
|
5232
5237
|
let modeActive = false;
|
|
5233
|
-
let baseLoadout = null;
|
|
5234
5238
|
const applyMode = () => {
|
|
5235
|
-
|
|
5236
|
-
const shouldEnter = surface === "full_ptc" && modeEnabled && active.includes("ptc_run_code");
|
|
5237
|
-
if (shouldEnter && !modeActive) {
|
|
5238
|
-
baseLoadout ??= [...active];
|
|
5239
|
-
pi.setActiveTools(active.filter((name) => !KNOWN_BINDING_NAMES.includes(name)));
|
|
5240
|
-
modeActive = true;
|
|
5241
|
-
} else if (!shouldEnter && modeActive && baseLoadout) {
|
|
5242
|
-
pi.setActiveTools(baseLoadout);
|
|
5243
|
-
baseLoadout = null;
|
|
5244
|
-
modeActive = false;
|
|
5245
|
-
}
|
|
5239
|
+
modeActive = surface === "full_ptc" && modeEnabled;
|
|
5246
5240
|
};
|
|
5247
5241
|
applyMode();
|
|
5248
5242
|
pi.on("before_agent_start", (event) => {
|
|
5249
5243
|
applyMode();
|
|
5250
5244
|
applyTaskFaceVisibility(pi, session);
|
|
5251
5245
|
const sections = event.systemPromptOptions?.sections;
|
|
5252
|
-
if (sections) sections["ptc"] = renderRouteIndex(surface);
|
|
5253
|
-
if (!modeActive) return;
|
|
5254
|
-
const active = pi.getActiveTools();
|
|
5255
|
-
if (active.includes("read") || active.includes("bash")) return;
|
|
5256
|
-
const loaded = loadSkills({
|
|
5257
|
-
cwd: process.cwd(),
|
|
5258
|
-
agentDir: getAgentDir(),
|
|
5259
|
-
skillPaths: [],
|
|
5260
|
-
includeDefaults: true
|
|
5261
|
-
});
|
|
5262
|
-
if (loaded.skills.length === 0) return;
|
|
5263
|
-
if (sections) sections["available_skills"] = formatSkillsForPrompt(loaded.skills, "indirect");
|
|
5246
|
+
if (sections) sections["ptc"] = renderRouteIndex(surface, detailDir, modeActive);
|
|
5264
5247
|
});
|
|
5265
5248
|
const pool = new WorkerPool(spawnPtcWorker);
|
|
5266
5249
|
const notifications = new NotificationCenter();
|
|
@@ -5305,7 +5288,7 @@ function piPtcEntry(pi) {
|
|
|
5305
5288
|
]
|
|
5306
5289
|
});
|
|
5307
5290
|
pi.registerCommand("ptc", {
|
|
5308
|
-
description: "/ptc off|on:派发开关 · /ptc why on|off:理由开关 · /ptc mode on|off:PTC
|
|
5291
|
+
description: "/ptc off|on:派发开关 · /ptc why on|off:理由开关 · /ptc mode on|off:PTC 模式(程序优先的引导层)",
|
|
5309
5292
|
handler: async (args, cmdCtx) => {
|
|
5310
5293
|
const [sub, rest] = args.trim().split(/\s+/);
|
|
5311
5294
|
if (sub === "off") {
|
|
@@ -5358,12 +5341,16 @@ function piPtcEntry(pi) {
|
|
|
5358
5341
|
};
|
|
5359
5342
|
registerTaskFace(registerTracked, session, surface);
|
|
5360
5343
|
applyTaskFaceVisibility(pi, session);
|
|
5361
|
-
|
|
5344
|
+
let toolContext;
|
|
5345
|
+
const bindings = createBindingTable(pi, session, () => toolContext);
|
|
5362
5346
|
registerPtcTools(registerTracked, {
|
|
5363
5347
|
getBindings: () => bindings,
|
|
5364
5348
|
cwd: process.cwd(),
|
|
5365
5349
|
surface,
|
|
5366
|
-
getPool: () => pool
|
|
5350
|
+
getPool: () => pool,
|
|
5351
|
+
onToolContext: (ctx) => {
|
|
5352
|
+
toolContext = ctx;
|
|
5353
|
+
}
|
|
5367
5354
|
}, surface);
|
|
5368
5355
|
if (surface === "codemode_ptc") registerTaskDoor(registerTracked, session, surface);
|
|
5369
5356
|
pi.on("turn_end", () => pool.drain());
|
|
@@ -5463,12 +5450,12 @@ function registerChildToolsOnly(pi) {
|
|
|
5463
5450
|
})
|
|
5464
5451
|
});
|
|
5465
5452
|
}
|
|
5466
|
-
function createBindingTable(pi,
|
|
5467
|
-
const executeTool = ctx.executeTool;
|
|
5453
|
+
function createBindingTable(pi, session, getToolContext) {
|
|
5468
5454
|
const names = resolveBindingNames(pi.getActiveTools());
|
|
5469
5455
|
const table = Object.fromEntries(names.map((name) => [name, async (args, callCtx) => {
|
|
5470
|
-
|
|
5471
|
-
|
|
5456
|
+
const ctx = getToolContext();
|
|
5457
|
+
if (!ctx?.executeTool) throw new Error(`此 pi 版本不支持程序内工具调用(executeTool 不可用,binding: ${name})`);
|
|
5458
|
+
const outcome = await ctx.executeTool(name, args, { signal: callCtx.signal });
|
|
5472
5459
|
for (const block of outcome.result.content) if (block.type === "image") callCtx.emitImage(block);
|
|
5473
5460
|
if (outcome.isError) {
|
|
5474
5461
|
const text = outcome.result.content.map((block) => block.type === "text" ? block.text : `[${block.type}]`).join("\n");
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# 派一个子代理
|
|
2
|
+
|
|
3
|
+
入口两扇门面(ADR-0006),同参同形(名字随所在平面),只是所在平面不同:
|
|
4
|
+
|
|
5
|
+
- `pi_task_ptc`:PTC 程序内的 binding,程序里 `tools.pi_task_ptc({...})`
|
|
6
|
+
- `pi_task_codemode`:注册的工具(exposure: codemode,模型不可见),codemode 脚本里 `tools.pi_task_codemode({...})`
|
|
7
|
+
|
|
8
|
+
参数:`task`(必填,孩子要干的活)、`label`、`wait`、`why`、`agent`、`agentScope`、`model`、`thinkingLevel`、`readOnly` 均已生效(`cwd` 待接);
|
|
9
|
+
agent 定义里的 `tools / model / thinkingLevel / childReport` 由 frontmatter 钉住。
|
|
10
|
+
|
|
11
|
+
返回 handle:`{ taskId, label?, status: "queued" }`。默认不等;撞闸(随闸门落地)返回
|
|
12
|
+
`{ status: "rejected", errorMessage }`,不抛异常。
|
|
13
|
+
|
|
14
|
+
任务建成后在任务记录里排队(满员排队不拒绝,ADR-0010),经
|
|
15
|
+
`ptc_task_list / ptc_task_output / ptc_task_stop` 查/停。
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# 管一个任务
|
|
2
|
+
|
|
3
|
+
三个工具,有任务记录才出现在模型面前(ADR-0007:可见性 = 有无记录,不是独立开关):
|
|
4
|
+
|
|
5
|
+
- `ptc_task_list()`:在飞的全部 + 最近完成的(默认 10 条)
|
|
6
|
+
- `ptc_task_output({ task_id })`:读一条记录(状态/产出/报告)
|
|
7
|
+
- `ptc_task_stop({ task_id, reason? })`:排队中的抽掉(canceled);在跑的转 stopping
|
|
8
|
+
|
|
9
|
+
任务记录是派发的唯一痕迹:每次建任务都建记录,前台任务也一样。
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# 上网查资料(web_ds_search,ADR-0001–0049)
|
|
2
|
+
|
|
3
|
+
搜索能力**只活在被派出的子代理里**(父会话不注册这个工具)——「这条来源靠不靠谱」的判断力在干活的子代理侧。
|
|
4
|
+
|
|
5
|
+
三动作:
|
|
6
|
+
|
|
7
|
+
- `search({ query, count? })`:概览(title/url/snippet,默认 10 条)。snippet 是 DeepSeek 自算的短摘要——便宜且不丢事实;长 summary 不经概览给
|
|
8
|
+
- `open({ url })`:抓整页(记忆命中最近结果则免费)
|
|
9
|
+
- `find({ url, pattern })`:页内按正则匹配行(先查记忆)
|
|
10
|
+
|
|
11
|
+
预算与配额:
|
|
12
|
+
|
|
13
|
+
- 模型可见文本预算 12,000 字符;超了按排名**整条丢弃** + 告知丢了哪些(要哪个用 open 补抓)——不按字符截断
|
|
14
|
+
- 配额每进程计(`searchMaxCalls`,默认 30 次/进程,0 = 不限;只计成功调用)
|
|
15
|
+
- 开关 `webDsSearch`(`~/.pi/agent/ptc.json`)是布尔,**默认关**:开关关 = 工具不存在;开关开但缺凭据 = 注册但调用返回可读错误
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# 交报告(child report,旧 ADR-0032)
|
|
2
|
+
|
|
3
|
+
子代理收工前交一份结构化报告,四样:`summary`(一句话结论)、`findings`(每条 what +
|
|
4
|
+
独立 evidence)、`files_touched`、`usage`(input/output/cost/turns)。散文保留不替换。
|
|
5
|
+
|
|
6
|
+
- 契约写在孩子的追加 system prompt(唯一处),形式:最终消息**末尾的 fenced JSON 块**
|
|
7
|
+
- 宿主自动解析;`reportChannel` 四值:`tool` = 经 `ptc_child_report` 工具交的(首选通道,已落地)、`prompt-json` = 末尾 fenced JSON 解析到了、`none` = 没交(散文照交但不标可信)、`opted-out` = agent 定义 `childReport:false` 声明免交
|
|
8
|
+
- 报告落 TaskRecord,经 `ptc_task_output` 读得到;没交报告的孩子永远明说,不静默
|
|
9
|
+
- 工具通道(`ptc_child_report`)在子代理进程注册,已是首选;prompt 通道兜底
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# 分阶段 workflow(ptc_workflow)
|
|
2
|
+
|
|
3
|
+
`ptc_workflow({ meta: { name, description, phases? }, script, args?, timeoutMs? })`。
|
|
4
|
+
|
|
5
|
+
script 内额外可用(仅 workflow 面注入):
|
|
6
|
+
|
|
7
|
+
- `workflow.log(...)`:阶段内日志
|
|
8
|
+
- `workflow.phase(name)`:阶段标记
|
|
9
|
+
- `workflow.parallel([fn, ...])`:并行执行
|
|
10
|
+
- `workflow.pipeline(items, step)`:顺序流水线
|
|
11
|
+
|
|
12
|
+
args 必须是可 JSON 序列化的值(进 worker 前校验)。
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# 批量调工具的一段程序(ptc_run_code)
|
|
2
|
+
|
|
3
|
+
`ptc_run_code({ code, description, timeoutMs? })`:code 是 TypeScript 程序体,
|
|
4
|
+
支持顶层 await 与 return。程序内 `tools.<name>(args)` 调工具:
|
|
5
|
+
|
|
6
|
+
- 绑定表 = 内置名单 ∩ 会话活跃工具(`--tools` 收窄的会话不会拿到被滤掉的绑定)
|
|
7
|
+
- `bash` 不在默认表里,需 opt-in 授权(旧 ADR-0040)
|
|
8
|
+
- 程序返回值是归约后的结果;undefined 返回标记为「无完成值」
|
|
9
|
+
|
|
10
|
+
默认 2 分钟超时(可经 timeoutMs 下调,上限 10 分钟)。输出超 50 KB 按 pi 截断契约切尾,
|
|
11
|
+
全文写在临时文件、路径进尾注。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-ptc-subagents",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"description": "Programmable tool calling (PTC) and subagent fan-out for pi",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
22
|
"dist/**/*.js",
|
|
23
|
+
"docs/routes/**/*.md",
|
|
23
24
|
"README.md",
|
|
24
25
|
"LICENSE"
|
|
25
26
|
],
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
},
|
|
31
32
|
"scripts": {
|
|
32
33
|
"build": "pnpm -r run build",
|
|
33
|
-
"prepack": "pnpm run build && rm -rf dist && cp -R packages/entry/dist dist",
|
|
34
|
+
"prepack": "pnpm run build && rm -rf dist docs/routes && cp -R packages/entry/dist dist && cp -R packages/routes/docs/routes docs/routes",
|
|
34
35
|
"check": "pnpm -r run check",
|
|
35
36
|
"lint": "oxlint",
|
|
36
37
|
"fmt": "oxfmt",
|