pi-web-ui 0.95.0 → 0.96.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/CHANGELOG.md +63 -1
- package/bin/pi-web-ui.mjs +159 -31
- package/dist/server/agent-service.js +880 -240
- package/dist/server/approval-rules.js +56 -10
- package/dist/server/attachment-store.js +21 -4
- package/dist/server/attachments.js +30 -3
- package/dist/server/bg-servers.js +45 -7
- package/dist/server/claim-files-tool.js +4 -8
- package/dist/server/claim-store.js +4 -2
- package/dist/server/client-state.js +63 -14
- package/dist/server/compact-context-tool.js +6 -5
- package/dist/server/composer-drafts.js +9 -0
- package/dist/server/control-socket.js +57 -28
- package/dist/server/conversation-read-tool.js +7 -17
- package/dist/server/dangling-tools.js +72 -5
- package/dist/server/delegate-task.js +25 -28
- package/dist/server/dsh/dsh-agent-service.js +19 -6
- package/dist/server/edit-soft-tool.js +14 -11
- package/dist/server/eval-tool.js +67 -14
- package/dist/server/file-archives.js +16 -5
- package/dist/server/files-service.js +30 -11
- package/dist/server/goal-service.js +141 -19
- package/dist/server/hashline-engine.js +59 -21
- package/dist/server/host-guard.js +94 -0
- package/dist/server/i18n.js +3 -3
- package/dist/server/index.js +331 -78
- package/dist/server/lsp-tool.js +752 -60
- package/dist/server/mcp-bridge.js +47 -3
- package/dist/server/model-admin.js +94 -34
- package/dist/server/office-parse.js +96 -30
- package/dist/server/patch-tool.js +9 -15
- package/dist/server/permission-preset.js +25 -0
- package/dist/server/plan-manager.js +11 -1
- package/dist/server/plugin-catalog-sync.js +36 -19
- package/dist/server/plugin-catalog.js +11 -4
- package/dist/server/plugin-facilities.js +92 -21
- package/dist/server/plugin-installer.js +30 -0
- package/dist/server/plugin-llm.js +71 -65
- package/dist/server/plugin-project.js +70 -2
- package/dist/server/plugin-updater.js +115 -12
- package/dist/server/plugins.js +205 -44
- package/dist/server/present-files-tool.js +9 -12
- package/dist/server/process-utils.js +4 -0
- package/dist/server/prompt-composer.js +9 -0
- package/dist/server/protocol-version.js +1 -1
- package/dist/server/read-tool.js +69 -30
- package/dist/server/resolve-global-sdk.js +30 -16
- package/dist/server/schedule-agent-tool.js +12 -15
- package/dist/server/sdk-origin.js +18 -2
- package/dist/server/serialize.js +108 -21
- package/dist/server/settings-service.js +4 -2
- package/dist/server/skill-tool.js +5 -7
- package/dist/server/subagent-templates.js +51 -0
- package/dist/server/subagents.js +48 -72
- package/dist/server/terminals.js +181 -69
- package/dist/server/tool-manager.js +24 -7
- package/dist/server/tool-overrides.js +59 -0
- package/dist/server/update-check.js +28 -1
- package/dist/server/uploads.js +17 -2
- package/dist/server/wait-subscription-scan.js +18 -21
- package/dist/server/ws-client-id.js +29 -0
- package/dist/server/ws-pending-queue.js +60 -0
- package/extensions/webui.ts +60 -2
- package/package.json +4 -2
- package/plugins/catalog.json +20 -0
- package/themes/aetheris.css +457 -0
- package/themes/zhupi-dark.css +718 -0
- package/themes/zhupi.css +771 -0
- package/web/dist/assets/{TerminalPanel-DlGBF2MD.js → TerminalPanel-O3GyFIGG.js} +1 -1
- package/web/dist/assets/index-B7Zp23Vc.css +1 -0
- package/web/dist/assets/index-ByfoaDwp.js +366 -0
- package/web/dist/assets/{markdown-eUQn_o9D.js → markdown-DXwnfD9T.js} +1 -1
- package/web/dist/index.html +3 -3
- package/web/dist/assets/index-BXnCQL9p.js +0 -364
- package/web/dist/assets/index-RpIGFyi_.css +0 -1
package/dist/server/subagents.js
CHANGED
|
@@ -23,21 +23,21 @@
|
|
|
23
23
|
// 它的 conversation 体系)、以及注册给每个会话的 subagent_* 工具。真正创建
|
|
24
24
|
// conversation / 跑 prompt 全部在 agent-service.ts 的 spawnSubagent 里完成。
|
|
25
25
|
//
|
|
26
|
-
//
|
|
27
|
-
// (英文在前);per-call 返回文本按 lang 取 pick(lang, zh, en)。
|
|
26
|
+
// 返回文本按 lang 取 pick(lang, zh, en)。
|
|
28
27
|
// ---------------------------------------------------------------------------
|
|
29
28
|
import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
30
29
|
import { Type } from "typebox";
|
|
31
|
-
import {
|
|
30
|
+
import { pick } from "./i18n.js";
|
|
32
31
|
/**
|
|
33
32
|
* subagent_wait_all 的最长阻塞时间:必须短暂低于工具看门狗(默认 20 分钟,
|
|
34
33
|
* PI_WEB_TOOL_TIMEOUT_MS 可调),否则看门狗会先中止整个会话而不是让 wait
|
|
35
|
-
*
|
|
34
|
+
* 干净地超时返回。取 0.8×看门狗并以 60s 封顶、5s 兜底:看门狗调小(如 <75s)
|
|
35
|
+
* 时 60s 下限会反超看门狗造成本末倒置,此时随看门狗缩短,但不低于 5s。
|
|
36
36
|
*/
|
|
37
37
|
const WAIT_CAP_MS = (() => {
|
|
38
38
|
const v = Number(process.env.PI_WEB_TOOL_TIMEOUT_MS);
|
|
39
39
|
const watchdog = Number.isFinite(v) && v > 0 ? v : 20 * 60_000;
|
|
40
|
-
return Math.max(60_000, Math.floor(watchdog * 0.8));
|
|
40
|
+
return Math.max(Math.min(60_000, Math.floor(watchdog * 0.8)), 5_000);
|
|
41
41
|
})();
|
|
42
42
|
/** 子代理是否已到终态(运行结束、被中止或出错)。wait 工具据此判断
|
|
43
43
|
* 是否可以取结果;streaming=false 即可(error/canceled 都在快照里带标记)。 */
|
|
@@ -86,50 +86,33 @@ export function makeSubagentTools(host, lang, selfConvId) {
|
|
|
86
86
|
defineTool({
|
|
87
87
|
name: "subagent_spawn",
|
|
88
88
|
label: "Spawn subagent",
|
|
89
|
-
description:
|
|
90
|
-
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
"subagent_get_result for results, subagent_steer to redirect mid-run, subagent_stop to stop. " +
|
|
94
|
-
"Good for: long-running exploration, parallel research, delegating independent subtasks. Optional template " +
|
|
95
|
-
"param: use a subagent template configured in the settings panel " +
|
|
96
|
-
"(role system prompt + skills/extensions whitelist + optional model + optional thinking level); optional model " +
|
|
97
|
-
"param: explicitly set " +
|
|
98
|
-
'the subagent model (provider/id, e.g. "anthropic/claude-opus-4-5"), which overrides the template and panel ' +
|
|
99
|
-
"default; omit both = follow the main conversation's model and thinking level.", "在后台启动一个独立的子代理对话,用一个明确的指令去完成一项可独立交付的工作(调研/实现/审查等)。" +
|
|
100
|
-
"子代理会出现在左栏「运行的对话」列表(带子代理标识),用户可点开查看、补充、中止。主 agent 可并行派发多个:" +
|
|
101
|
-
"用 subagent_wait_all 一次性等全部完成(不用轮询)、subagent_list 查看运行态、subagent_get_result 取结果、" +
|
|
102
|
-
"subagent_steer 中途改向、subagent_stop 停止。" +
|
|
103
|
-
"适合:长耗时探索、并行调研、独立子任务委派。可选 template 参数:使用设置面板配置的子代理模板" +
|
|
104
|
-
"(角色系统提示词 + 技能/扩展白名单 + 可选模型 + 可选思考强度);可选 model 参数:显式指定子代理模型(provider/id 格式," +
|
|
105
|
-
'如 "anthropic/claude-opus-4-5"),优先级高于模板与设置面板的默认模型;都不传 = 跟随主对话当前模型与思考强度。'),
|
|
89
|
+
description: "Spawn an independent background subagent conversation for a self-contained deliverable task (research/implement/review). " +
|
|
90
|
+
"Subagents appear in the running-conversations list; the user can open, supplement, or stop them. Several may run in parallel — " +
|
|
91
|
+
"subagent_wait_all waits for all (no polling), subagent_get_result fetches a result, subagent_list shows status, subagent_steer redirects, subagent_stop stops. " +
|
|
92
|
+
"Good for long-running exploration, parallel research, and independent subtasks.",
|
|
106
93
|
promptSnippet: "spawn an independent background subagent for a deliverable task (parallel work)",
|
|
107
94
|
parameters: Type.Object({
|
|
108
95
|
prompt: Type.String({
|
|
109
|
-
description:
|
|
96
|
+
description: "Full instructions for the subagent (goal + constraints + expected output).",
|
|
110
97
|
}),
|
|
111
98
|
type: Type.Optional(Type.String({
|
|
112
|
-
description:
|
|
99
|
+
description: "Subagent type/role name (e.g. explore/implement/review), for display. Default general.",
|
|
113
100
|
})),
|
|
114
101
|
template: Type.Optional(Type.String({
|
|
115
|
-
description:
|
|
116
|
-
"
|
|
117
|
-
"
|
|
118
|
-
"模板 = 角色系统提示词 + 技能/扩展白名单 + 可选模型 + 可选思考强度;不传 = 不使用模板,按主会话默认配置运行。"),
|
|
102
|
+
description: "Subagent template name (preset from Settings → Subagent Templates; see subagent_templates): " +
|
|
103
|
+
"role system prompt + skills/extensions whitelist + optional model/thinking level. " +
|
|
104
|
+
"Omit to run with the main session defaults.",
|
|
119
105
|
})),
|
|
120
106
|
model: Type.Optional(Type.String({
|
|
121
|
-
description:
|
|
122
|
-
"template model
|
|
123
|
-
"main conversation model.", '可选:子代理模型 "provider/id"(如 "anthropic/claude-opus-4-5"),显式指定本次子代理的模型,' +
|
|
124
|
-
"优先级高于模板自带模型与设置面板默认模型;不传 = 模板模型 → 设置面板默认模型 → 跟随主对话当前模型。"),
|
|
107
|
+
description: 'Subagent model "provider/id" (e.g. "anthropic/claude-opus-4-5") for this run; ' +
|
|
108
|
+
"overrides template model then panel default. Omit = template model → panel default → main conversation model.",
|
|
125
109
|
})),
|
|
126
110
|
cwd: Type.Optional(Type.String({
|
|
127
|
-
description:
|
|
111
|
+
description: "Subagent working directory (relative/absolute). Defaults to the main session's cwd.",
|
|
128
112
|
})),
|
|
129
113
|
persist: Type.Optional(Type.Boolean({
|
|
130
|
-
description:
|
|
131
|
-
"Default false (lightweight in-memory subagent)
|
|
132
|
-
"默认 false(轻量内存子代理)。需要长期留存或后续人工跟进的任务建议设为 true。"),
|
|
114
|
+
description: "Persist this conversation to disk as a regular session (saved in history, resumable). " +
|
|
115
|
+
"Default false (lightweight in-memory subagent); use true for tasks needing long-term retention or human follow-up.",
|
|
133
116
|
})),
|
|
134
117
|
}),
|
|
135
118
|
execute: async (_id, p, _signal, _onUpdate, ctx) => {
|
|
@@ -177,12 +160,13 @@ export function makeSubagentTools(host, lang, selfConvId) {
|
|
|
177
160
|
defineTool({
|
|
178
161
|
name: "subagent_get_result",
|
|
179
162
|
label: "Get subagent result",
|
|
180
|
-
description:
|
|
181
|
-
"
|
|
163
|
+
description: "Fetch a subagent's result or current progress. " +
|
|
164
|
+
"If not finished yet, returns the current status and partial output; " +
|
|
165
|
+
"runtime errors (e.g. provider 400) are surfaced here as explicit errors.",
|
|
182
166
|
promptSnippet: "fetch a subagent's result / current progress",
|
|
183
167
|
parameters: Type.Object({
|
|
184
168
|
runId: Type.String({
|
|
185
|
-
description:
|
|
169
|
+
description: "ConvId returned by subagent_spawn. Clicking the same conversation in the left panel opens it directly.",
|
|
186
170
|
}),
|
|
187
171
|
}),
|
|
188
172
|
execute: async (_id, p) => {
|
|
@@ -205,14 +189,14 @@ export function makeSubagentTools(host, lang, selfConvId) {
|
|
|
205
189
|
defineTool({
|
|
206
190
|
name: "subagent_steer",
|
|
207
191
|
label: "Steer subagent",
|
|
208
|
-
description:
|
|
192
|
+
description: "Inject a message into a subagent to redirect or supplement its work (same as the user sending a message in its conversation).",
|
|
209
193
|
promptSnippet: "inject a message into a running subagent to redirect its work",
|
|
210
194
|
parameters: Type.Object({
|
|
211
195
|
runId: Type.String({
|
|
212
|
-
description:
|
|
196
|
+
description: "Target subagent convId.",
|
|
213
197
|
}),
|
|
214
198
|
message: Type.String({
|
|
215
|
-
description:
|
|
199
|
+
description: "Redirect / supplementary info to inject.",
|
|
216
200
|
}),
|
|
217
201
|
}),
|
|
218
202
|
execute: async (_id, p) => {
|
|
@@ -228,12 +212,14 @@ export function makeSubagentTools(host, lang, selfConvId) {
|
|
|
228
212
|
defineTool({
|
|
229
213
|
name: "subagent_list",
|
|
230
214
|
label: "List subagents",
|
|
231
|
-
description:
|
|
215
|
+
description: "List all subagents and managed conversations with their live status: " +
|
|
216
|
+
"convId, type, state, title, message count (errors/aborts are marked in the state).",
|
|
232
217
|
promptSnippet: "list all subagents and their live status",
|
|
233
218
|
parameters: Type.Object({
|
|
234
219
|
kind: Type.Optional(Type.String({
|
|
235
220
|
enum: ["all", "subagent", "persistent"],
|
|
236
|
-
description:
|
|
221
|
+
description: "Filter: all (default) = all managed tasks; " +
|
|
222
|
+
"subagent = only ephemeral in-memory subagents; persistent = only persistent conversations.",
|
|
237
223
|
})),
|
|
238
224
|
}),
|
|
239
225
|
execute: async (_id, p) => {
|
|
@@ -252,11 +238,12 @@ export function makeSubagentTools(host, lang, selfConvId) {
|
|
|
252
238
|
defineTool({
|
|
253
239
|
name: "subagent_stop",
|
|
254
240
|
label: "Stop subagent",
|
|
255
|
-
description:
|
|
241
|
+
description: "Stop a running subagent (same as the user aborting it in its conversation). " +
|
|
242
|
+
"Already-finished ones are unaffected.",
|
|
256
243
|
promptSnippet: "stop a running subagent",
|
|
257
244
|
parameters: Type.Object({
|
|
258
245
|
runId: Type.String({
|
|
259
|
-
description:
|
|
246
|
+
description: "Target subagent convId.",
|
|
260
247
|
}),
|
|
261
248
|
}),
|
|
262
249
|
execute: async (_id, p) => {
|
|
@@ -272,26 +259,18 @@ export function makeSubagentTools(host, lang, selfConvId) {
|
|
|
272
259
|
defineTool({
|
|
273
260
|
name: "subagent_wait_all",
|
|
274
261
|
label: "Wait for subagents",
|
|
275
|
-
description:
|
|
276
|
-
"
|
|
277
|
-
"
|
|
278
|
-
"
|
|
279
|
-
"(a subagent calling this without runIds won't deadlock on itself or its parent). " +
|
|
280
|
-
"Descendants spawned during the wait are picked up automatically. " +
|
|
281
|
-
"On timeout or abort of this round, returns the remaining unfinished list; call again to continue waiting. " +
|
|
282
|
-
"Good for: collecting parallel subagents.", "一次性等待多个子代理全部完成(阻塞本回合直到它们都到达终态或超时),然后汇总返回每个的结果/错误——" +
|
|
283
|
-
"不用反复调 subagent_get_result 轮询。传 runIds 指定要等的子代理(subagent_spawn 返回的 convId);" +
|
|
284
|
-
"不传 = 子代理调用时只等自己的后代,主对话调用时等当前全部运行中的子代理。调用者自身与祖先永不计入等待" +
|
|
285
|
-
"(子代理不传 runIds 时不会等自己或父级,避免父子互等到超时)。等待期间新派生的后代会自动纳入。" +
|
|
286
|
-
"超时或本轮被中止时返回剩余未完成名单,可再次调用继续等。" +
|
|
287
|
-
"适合:并行派发多个子代理后收口。"),
|
|
262
|
+
description: "Wait for multiple subagents to finish (blocks until all reach a terminal state or time out), then summarizes each result/error — no polling. " +
|
|
263
|
+
"Pass runIds for specific subagents; omit = own descendant subagents when called from a subagent, else all currently running. " +
|
|
264
|
+
"The calling session and its ancestors are never waited on (no self-deadlock); descendants spawned during the wait are picked up automatically. " +
|
|
265
|
+
"On timeout returns the remaining unfinished list — call again to keep waiting.",
|
|
288
266
|
promptSnippet: "wait for multiple subagents to finish (no polling) and get all results",
|
|
289
267
|
parameters: Type.Object({
|
|
290
268
|
runIds: Type.Optional(Type.Array(Type.String({
|
|
291
|
-
description:
|
|
269
|
+
description: "ConvId of a subagent to wait for (returned by subagent_spawn). " +
|
|
270
|
+
"Omit = wait for all currently running.",
|
|
292
271
|
}))),
|
|
293
272
|
timeoutSeconds: Type.Optional(Type.Integer({
|
|
294
|
-
description:
|
|
273
|
+
description: `Max wait in seconds (default 600, cap ~${Math.floor(WAIT_CAP_MS / 1000)} — stays below the tool watchdog; on timeout returns the unfinished list so you can call again).`,
|
|
295
274
|
minimum: 1,
|
|
296
275
|
maximum: Math.floor(WAIT_CAP_MS / 1000),
|
|
297
276
|
})),
|
|
@@ -391,7 +370,8 @@ export function makeSubagentTools(host, lang, selfConvId) {
|
|
|
391
370
|
return text(pick(emptyLang, "没有需要等待的子代理(调用者自身与祖先不计入等待;子代理无参时只等自己的后代)。", "No subagents to wait for (the calling session itself and its ancestors are never waited on; a subagent without runIds only waits for its own descendants).", "subagents.wait.empty"));
|
|
392
371
|
}
|
|
393
372
|
const currentWatchdogMs = host.getWatchdogTimeoutMs?.() ?? WAIT_CAP_MS;
|
|
394
|
-
|
|
373
|
+
// 同 WAIT_CAP_MS:0.8×看门狗、60s 封顶、5s 兜底,wait 必须先于看门狗干净超时。
|
|
374
|
+
const currentWaitCapMs = currentWatchdogMs > 0 ? Math.max(Math.min(60_000, Math.floor(currentWatchdogMs * 0.8)), 5_000) : 3600_000;
|
|
395
375
|
const timeoutMs = Math.min(Math.max(p.timeoutSeconds ?? 600, 1), Math.floor(currentWaitCapMs / 1000)) * 1000;
|
|
396
376
|
const waitStart = Date.now();
|
|
397
377
|
const deadline = waitStart + timeoutMs;
|
|
@@ -455,10 +435,8 @@ export function makeSubagentTools(host, lang, selfConvId) {
|
|
|
455
435
|
defineTool({
|
|
456
436
|
name: "subagent_templates",
|
|
457
437
|
label: "List subagent templates",
|
|
458
|
-
description:
|
|
459
|
-
"
|
|
460
|
-
"Empty list = no templates configured; subagents run with defaults.", "列出设置面板「子代理模板」配置的可用模板(角色系统提示词 + 技能/扩展白名单 + 可选模型与思考强度 的组合预设)," +
|
|
461
|
-
"供 subagent_spawn 的 template 参数选用。已停用的模板不会出现在这里。list 为空 = 未配置模板,子代理按默认配置运行。"),
|
|
438
|
+
description: "List the configurable subagent templates (role system prompt + skills/extensions whitelist + optional model/thinking level) usable via the subagent_spawn template param. " +
|
|
439
|
+
"Disabled templates never appear; empty list = subagents run with defaults.",
|
|
462
440
|
promptSnippet: "list configurable subagent templates (role prompt + skills/extensions whitelist presets)",
|
|
463
441
|
parameters: Type.Object({}),
|
|
464
442
|
execute: async () => {
|
|
@@ -495,19 +473,17 @@ export function makeSubagentTools(host, lang, selfConvId) {
|
|
|
495
473
|
defineTool({
|
|
496
474
|
name: "subagent_handoff",
|
|
497
475
|
label: "Hand off to peer subagent",
|
|
498
|
-
description:
|
|
499
|
-
"without routing through the parent conversation. Enables direct multi-agent pipeline collaboration.", "将任务产物、上下文或分析结果直接交接给另一个同行子代理(对等消息路由)," +
|
|
500
|
-
"无需通过主会话中转,实现多智能体同行流水线协作。"),
|
|
476
|
+
description: "Hand off artifacts, context, or results directly to a peer subagent (peer-to-peer, bypassing the parent conversation).",
|
|
501
477
|
promptSnippet: "hand off task artifacts or results directly to another peer subagent",
|
|
502
478
|
parameters: Type.Object({
|
|
503
479
|
toRunId: Type.String({
|
|
504
|
-
description:
|
|
480
|
+
description: "Target peer subagent convId (from subagent_list).",
|
|
505
481
|
}),
|
|
506
482
|
payload: Type.String({
|
|
507
|
-
description:
|
|
483
|
+
description: "The artifact, analysis result, or instruction to hand off to the peer subagent.",
|
|
508
484
|
}),
|
|
509
485
|
fromRunId: Type.Optional(Type.String({
|
|
510
|
-
description:
|
|
486
|
+
description: "Source subagent convId. Optional: defaults to the current calling subagent.",
|
|
511
487
|
})),
|
|
512
488
|
}),
|
|
513
489
|
execute: async (_id, p) => {
|