personal-bot 0.2.6 → 0.2.9
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/CONTEXT.md +40 -59
- package/README.md +65 -91
- package/README.zh-CN.md +69 -89
- package/docs/README.md +21 -17
- package/docs/agent-collaboration.md +11 -13
- package/docs/architecture-guidelines.md +2 -2
- package/docs/capability-design.md +8 -10
- package/docs/dsh.en.md +339 -0
- package/docs/dsh.md +284 -48
- package/docs/file-storage.md +3 -3
- package/docs/history.md +6 -4
- package/docs/installation-design.md +55 -197
- package/docs/model-context.md +46 -0
- package/docs/model-instruction-guidelines.md +51 -0
- package/docs/release.md +10 -6
- package/docs/technical-design.md +24 -16
- package/lib/common/typebox.LICENSE +23 -0
- package/lib/common/typebox.js +4740 -0
- package/lib/dsh.js +4 -0
- package/lib/extension/dsh/agent-events.js +1 -1
- package/lib/extension/dsh/agent-runtime.js +8 -5
- package/lib/extension/dsh/command.js +1 -1
- package/lib/extension/dsh/management.js +1 -1
- package/lib/integrations/dsh/resources.d.ts +1 -1
- package/lib/integrations/dsh/resources.js +14 -14
- package/lib/integrations/dsh/session.js +1 -0
- package/lib/integrations/installation/pi-bridge.js +9 -9
- package/lib/integrations/team-context.js +7 -3
- package/lib/services/agents/agent-notices.js +2 -2
- package/lib/services/agents/team-service.js +1 -1
- package/lib/tools/agents/contract.d.ts +1 -1
- package/lib/tools/agents/contract.js +8 -8
- package/lib/tools/agents/dsh-contract.js +5 -5
- package/lib/tools/history/contract.d.ts +1 -1
- package/lib/tools/history/contract.js +3 -3
- package/lib/tools/teams/contract.d.ts +2 -2
- package/lib/tools/teams/contract.js +12 -12
- package/npm-shrinkwrap.json +33 -25
- package/package.json +124 -53
- package/python/README.md +5 -5
- package/resources/agents/coordinator.md +5 -33
- package/resources/agents/general-purpose.md +3 -15
- package/resources/prompts/history-summary.md +1 -1
- package/resources/prompts/team-member.md +7 -0
- package/resources/prompts/workspace.md +13 -24
- package/resources/references/compute-finance.md +22 -0
- package/resources/references/compute.md +11 -88
- package/resources/references/task-conductor.md +20 -15
- package/resources/skills/project-maintenance/SKILL.md +9 -11
- package/resources/skills/provider-connections/SKILL.md +7 -7
- package/scripts/README.md +16 -15
- package/src/dsh.ts +4 -0
- package/src/extension/agent-events.ts +17 -4
- package/src/extension/command.ts +1 -1
- package/src/extension/dsh/agent-events.ts +1 -1
- package/src/extension/dsh/agent-runtime.ts +7 -6
- package/src/extension/events.ts +14 -9
- package/src/extension/subagent-entry.ts +24 -16
- package/src/integrations/dsh/resources.ts +17 -14
- package/src/integrations/dsh/session.ts +2 -0
- package/src/integrations/installation/pi-bridge.ts +9 -7
- package/src/integrations/pi/agent-context.ts +1 -1
- package/src/integrations/team-context.ts +7 -3
- package/src/services/agents/agent-notices.ts +2 -2
- package/src/services/agents/team-service.ts +1 -1
- package/src/tools/agents/contract.ts +7 -7
- package/src/tools/agents/dsh-contract.ts +4 -4
- package/src/tools/history/contract.ts +2 -2
- package/src/tools/register.ts +1 -7
- package/src/tools/teams/contract.ts +11 -11
- package/docs/dsh-implementation-plan.md +0 -158
- package/docs/dsh-support-proposal.md +0 -314
- package/docs/subagent-upgrade-proposal.md +0 -357
- package/docs/validation.md +0 -132
- package/resources/prompts/tool-guidelines.md +0 -3
|
@@ -5,17 +5,17 @@ description: 维护项目结论、分析口径与可复用任务定义。用于
|
|
|
5
5
|
|
|
6
6
|
# 项目整理与维护
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
让资料呈现当前结论、适用条件、分析口径和未决问题。重要结论或决策变化时简要说明原因。
|
|
9
9
|
|
|
10
10
|
根据本次变化更新当前任务、所属正文及实际受影响的引用。整体整理按用户指定范围进行。
|
|
11
11
|
|
|
12
12
|
## 更新所属资料
|
|
13
13
|
|
|
14
|
-
从根 AGENTS.md
|
|
14
|
+
从根 AGENTS.md 和相关目录入口定位正文;入口未命中时,按主题、别名或项目名搜索。
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
按主题合并当前说明,保留继续或复用任务所需的信息。比较新旧内容的对象、时期和条件,替换过时说明,同步引用,保留未解决的冲突。
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
保留历史资料与重要决策的来源和时间,当前说明通过引用连接。用户偏好与约定按用户表达记录,不把推测写成既定约定。
|
|
19
19
|
|
|
20
20
|
从项目结论中提炼可跨任务复用的概念、方法与口径,写入 knowledge/,说明适用条件并引用来源。知识按主题命名,需要保留历史的研究和决策按日期与主题命名。
|
|
21
21
|
|
|
@@ -23,20 +23,18 @@ description: 维护项目结论、分析口径与可复用任务定义。用于
|
|
|
23
23
|
|
|
24
24
|
## 复用任务定义
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
需要跨会话继续或重复执行的任务,在所属项目或长期事务中保存目标、输入、执行方式和预期产物,随任务变化更新。
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
重复分析或报告的定义按需包含数据来源与查询方式、对象与筛选范围、期间与时区、单位、指标公式与分母、分组与比较基准、执行入口。单次报告引用所用定义。
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
按上次口径重做时,读取已有定义,检查来源、版本与关键前提是否仍适用。更新报告使用本次期间与数据;复现历史结果使用指定输入。口径变化说明对可比性的影响。
|
|
31
31
|
|
|
32
32
|
## 成果归集与清理
|
|
33
33
|
|
|
34
34
|
用户要求整理或结项时,检查本次范围内的项目目录及 scratch/ 等临时产物位置。将结论与方法并入所属正文,将交付物与可复用源码归入对应项目,更新来源引用与执行入口。
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
归集后只清理本次范围内已被正文吸收或不再需要的临时文件,不删除正式资料、历史记录或备份。
|
|
37
37
|
|
|
38
38
|
## 项目结项
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
交付条件尚未满足时,记录具体缺口及其影响。完成状态、正文与证据一致后,同步项目入口和相关导航。
|
|
40
|
+
按任务目标检查交付物和执行入口。满足本次用途即可结项;尚有缺口时说明剩余工作,额外建议另列。更新项目状态和相关导航,已知限制留在正文。
|
|
@@ -23,20 +23,20 @@ description: 接入或修复原生 CLI/MCP,核对认证与可用性,维护
|
|
|
23
23
|
|
|
24
24
|
项目配置经 Pi 项目信任规则加载,同名条目可能覆盖用户级配置。修改前核对同名项,保留无关条目与已有用户级连接;迁移另按用户指定范围处理。认证使用原生登录或环境变量引用。
|
|
25
25
|
|
|
26
|
-
外部修改配置后,请用户在当前 Pi 会话执行 `/reload`,再用 `/mcp`
|
|
26
|
+
外部修改配置后,请用户在当前 Pi 会话执行 `/reload`,再用 `/mcp` 查看配置来源和连接状态。当前工具 schema 通过原生工具搜索或 codemode 按需取得。
|
|
27
27
|
|
|
28
28
|
### dsh
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
使用当前安装版本的原生 MCP 组件、profile 设置、认证与工具发现。按其公开文档或当前 help 核对参数,不使用 Pi 的命令和 `.pi/mcp.json` 配置方式。同一 profile 的连接可能供多个工作区使用,修改时留意影响范围。
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
优先复用已有连接,保留无关条目与其他工作区配置。通过原生界面或管理能力修改配置,再从当前会话检查连接和工具;需要用户操作时说明入口。
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## 检查与手册
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
用一个简单的只读查询检查所需能力,失败时根据实际错误排障。
|
|
37
37
|
|
|
38
38
|
`providers/<id>/GUIDE.md` 面向当前使用,保留用途、原生入口、可信资料位置及适用版本。仅补充原生定义未说明、且影响正确使用的口径或限制;工具目录与参数细节从原生 help 和 schema 按需取得。
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
更新时按主题合并,替换过时说明并同步示例。手册保留当前用法和已知限制,需要详细记录时引用所属项目。
|
|
41
41
|
|
|
42
|
-
`providers/AGENTS.md`
|
|
42
|
+
`providers/AGENTS.md` 只做导航和选用约定。
|
package/scripts/README.md
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
# 维护脚本
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 构建
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
| 命令 | 作用 |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| `npm run build` | 清理 dist,编译测试模块,再构建 CLI 与 dsh 产物 |
|
|
8
|
+
| `npm run build:cli` | 清理 lib,编译独立安装器、Pi 检查桥接与启动保护 |
|
|
9
|
+
| `npm run build:dsh` | 编译 Host,将 TypeBox 与许可证纳入 lib,再构建原生 Web Loader 模块 |
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
完整构建与 prepack 先构建 CLI,再构建 dsh。宿主 SDK 保持 external;dsh 编译模块引用包内 TypeBox,原模块位置保留。Pi 扩展由宿主直接加载 src。
|
|
8
12
|
|
|
9
|
-
##
|
|
13
|
+
## 安装包检查
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
先运行 `npm pack`,再将生成的 tarball 路径传给检查脚本:
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
| 命令 | 检查内容 | 环境 |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| `node scripts/check-consumer.mjs <tarball>` | 独立 CLI、Pi 扩展、技能、工具与资料初始化 | CI 使用 Node.js 22.19.0,脚本安装锁定的 Pi SDK |
|
|
20
|
+
| `node scripts/check-dsh-consumer.mjs <tarball>` | dsh 原生插件安装、独立 CLI 与 Host 导入;检查无需单独安装 TypeBox 或宿主 SDK | Node.js 24.9+、仓库开发依赖和 PATH 中的 pnpm |
|
|
14
21
|
|
|
15
|
-
|
|
22
|
+
脚本使用隔离的用户目录、宿主配置与工作目录,完成后清理临时目录。两项检查均不调用模型;Pi 使用预置故障目录跳过 Python 依赖下载,dsh 通过原生 schema 收集导入 Host。
|
|
16
23
|
|
|
17
|
-
##
|
|
24
|
+
## Python 准备
|
|
18
25
|
|
|
19
|
-
`
|
|
20
|
-
|
|
21
|
-
## 构建清理
|
|
22
|
-
|
|
23
|
-
`clean-dist.mjs` 由 npm run build 调用,仅清理仓库内生成的 dist/,供 TypeScript 重新编译测试导入。
|
|
24
|
-
|
|
25
|
-
本包不提供工作区升级命令或历史转换脚本。插件安装和更新由对应宿主的原生包管理或用户维护的源码目录负责。
|
|
26
|
+
`setup-python.py` 按 `python/requirements.lock` 准备用户共享 venv。Personal Bot 加载时自动调用,也可运行独立脚本或 `/pbot python setup`。路径、依赖与排障见 [Python 说明](../python/README.md)。
|
package/src/dsh.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
1
2
|
import type { Context } from "@deepseek-ai/cordis";
|
|
3
|
+
import * as SkillFilesystem from "@deepseek-ai/dsh-skill-filesystem";
|
|
4
|
+
import { resourceRoot } from "./common/paths.js";
|
|
2
5
|
import { registerDshCommand } from "./extension/dsh/command.js";
|
|
3
6
|
import { registerDshManagement } from "./extension/dsh/management.js";
|
|
4
7
|
import { DshWorkspaces, dshDependencies } from "./extension/dsh/workspace.js";
|
|
@@ -10,6 +13,7 @@ export const inject = ["commands", "typert", ...dshDependencies];
|
|
|
10
13
|
export async function apply(ctx: Context) {
|
|
11
14
|
const [major, minor] = process.versions.node.split(".").map(Number);
|
|
12
15
|
requireThat(major! > 24 || (major === 24 && minor! >= 9), "dsh 接入需要 Node.js 24.9.0 或更新版本。");
|
|
16
|
+
await ctx.plugin(SkillFilesystem, { providerName: "pbot", includeDefaultRoots: false, bundledSkillDir: join(resourceRoot, "skills") });
|
|
13
17
|
const workspaces = new DshWorkspaces(ctx);
|
|
14
18
|
ctx.effect(() => () => workspaces.close());
|
|
15
19
|
const management = registerDshManagement(ctx, workspaces);
|
|
@@ -14,6 +14,7 @@ export function registerAgentEvents(pi: ExtensionAPI, lifecycle: Lifecycle, conf
|
|
|
14
14
|
let paused = false, epoch = 0, refreshEpoch = 0;
|
|
15
15
|
let refreshing: Promise<void> | undefined;
|
|
16
16
|
let controlBusySince: number | undefined;
|
|
17
|
+
let recoveredFailure: string | undefined;
|
|
17
18
|
let failure: { key: string; error: string; recovery: "retry" | "repair" | "reload" } | undefined;
|
|
18
19
|
const recordFailure = (error: unknown) => {
|
|
19
20
|
const busy = (error as NodeJS.ErrnoException).code === "PBOT_CONTROL_BUSY";
|
|
@@ -67,7 +68,19 @@ export function registerAgentEvents(pi: ExtensionAPI, lifecycle: Lifecycle, conf
|
|
|
67
68
|
if (!ctx || !lifecycle.active || paused || ctx.signal?.aborted) return;
|
|
68
69
|
const instance = lifecycle.active, revision = epoch;
|
|
69
70
|
if (!failure) {
|
|
70
|
-
try {
|
|
71
|
+
try {
|
|
72
|
+
const message = await collectNotification();
|
|
73
|
+
if (message) return message;
|
|
74
|
+
if (!ctx || revision !== epoch || instance !== lifecycle.active || paused || ctx.signal?.aborted || failure || !recoveredFailure || controlBusySince !== undefined) return;
|
|
75
|
+
const delivered = deliveredCycles(ctx), key = recoveredFailure + ":recovered";
|
|
76
|
+
if (!delivered.has(recoveredFailure) || delivered.has(key)) return;
|
|
77
|
+
const now = Date.now(), sent = submitting.get(key);
|
|
78
|
+
if (sent !== undefined && now - sent < 5000) return;
|
|
79
|
+
submitting.set(key, now);
|
|
80
|
+
return { type: "custom_message", customType: "pbot.agent-recovered", display: true,
|
|
81
|
+
content: "# 子会话自动跟进已恢复\n\n后台扫描已恢复。成员状态和报告可通过 pbot_agent status/read 查看。",
|
|
82
|
+
details: { keys: [key], failureKey: recoveredFailure } };
|
|
83
|
+
}
|
|
71
84
|
catch (error) { if (revision !== epoch || instance !== lifecycle.active) return; recordFailure(error); }
|
|
72
85
|
}
|
|
73
86
|
if (!ctx || !failure || deliveredCycles(ctx).has(failure.key)) return;
|
|
@@ -82,7 +95,7 @@ export function registerAgentEvents(pi: ExtensionAPI, lifecycle: Lifecycle, conf
|
|
|
82
95
|
return { type: "custom_message", customType: "pbot.agent-error", display: true,
|
|
83
96
|
content: ["# 子会话自动跟进故障", "", recovery,
|
|
84
97
|
...(pausePending ? ["", "团队暂停尚未确认,不能据此开始成员私人任务。"] : []), "",
|
|
85
|
-
"
|
|
98
|
+
"用 pbot_agent list/status 查询成员状态,pbot_agent read 读取可用报告。重试前先查看原请求结果,避免重复执行。", "",
|
|
86
99
|
markdownFields({ error: failure.error })].join("\n"), details: { keys: [failure.key] } };
|
|
87
100
|
};
|
|
88
101
|
const refreshWork = async () => {
|
|
@@ -103,7 +116,6 @@ export function registerAgentEvents(pi: ExtensionAPI, lifecycle: Lifecycle, conf
|
|
|
103
116
|
try { instance.agents.enqueueTeam(input, instance.agentOwner); dispatching.delete(id); }
|
|
104
117
|
catch (error) {
|
|
105
118
|
const code = (error as NodeJS.ErrnoException).code;
|
|
106
|
-
if (code === "PBOT_CONTROL_BUSY") break;
|
|
107
119
|
if (code !== "TEAM_INPUT_STALE") throw error;
|
|
108
120
|
dispatching.delete(id); instance.teams.pauseMember(input.agentId, "安排失效;未自动重发");
|
|
109
121
|
}
|
|
@@ -119,6 +131,7 @@ export function registerAgentEvents(pi: ExtensionAPI, lifecycle: Lifecycle, conf
|
|
|
119
131
|
}
|
|
120
132
|
if (ctx.mode === "tui") ctx.ui.setWidget("pbot-agents", values.some(v => ["starting", "busy", "stopping"].includes(v.state)) ? (_tui, theme) => agentBoard(values, theme) : undefined);
|
|
121
133
|
if (!pausePending) {
|
|
134
|
+
if (failure) recoveredFailure = failure.key;
|
|
122
135
|
failure = undefined; controlBusySince = undefined;
|
|
123
136
|
if (ctx.hasUI) ctx.ui.setStatus("pbot-agents-error", undefined);
|
|
124
137
|
}
|
|
@@ -150,7 +163,7 @@ export function registerAgentEvents(pi: ExtensionAPI, lifecycle: Lifecycle, conf
|
|
|
150
163
|
return;
|
|
151
164
|
};
|
|
152
165
|
pi.on("session_start", (_event, context) => {
|
|
153
|
-
epoch++; ctx = context; paused = false; pausePending = false; controlBusySince = undefined; failure = undefined; confirmations.resume(); submitting.clear(); dispatching.clear();
|
|
166
|
+
epoch++; ctx = context; paused = false; pausePending = false; controlBusySince = undefined; failure = undefined; recoveredFailure = undefined; confirmations.resume(); submitting.clear(); dispatching.clear();
|
|
154
167
|
if (timer) clearInterval(timer);
|
|
155
168
|
if (lifecycle.active) { lifecycle.active.agentOwner = agentOwner(ctx); timer = setInterval(() => { void refresh(); }, 1000); timer.unref(); }
|
|
156
169
|
return refresh();
|
package/src/extension/command.ts
CHANGED
|
@@ -26,7 +26,7 @@ export function registerCommand(pi: ExtensionAPI, lifecycle: Lifecycle, confirma
|
|
|
26
26
|
const instance = lifecycle.get();
|
|
27
27
|
if (command === "init" && !argument) {
|
|
28
28
|
await ctx.waitForIdle(); instance.check(); await prepareWorkspace(instance.root);
|
|
29
|
-
ctx.ui.notify("
|
|
29
|
+
ctx.ui.notify("资料目录已准备。新建的 AGENTS.md 在 /reload 或下次启动后由 Pi 加载。", "info"); return;
|
|
30
30
|
}
|
|
31
31
|
if (command === "status" && !argument) {
|
|
32
32
|
const python = instance.pythonEnvironment.status;
|
|
@@ -90,7 +90,7 @@ export class DshAgentEvents {
|
|
|
90
90
|
let value: { keys: string[]; content: string } | undefined;
|
|
91
91
|
if (this.#error && this.#errorKey) {
|
|
92
92
|
if (!known.has(this.#errorKey)) value = { keys: [this.#errorKey], content: "# 协作扫描故障\n\n" + this.#error +
|
|
93
|
-
"\n\n
|
|
93
|
+
"\n\n先查看控制记录和原生报告,再决定是否重试,避免重复执行。" +
|
|
94
94
|
(this.#recovery === "reload" ? "团队服务已停用;修复文件后还需重载服务端 personal-bot 插件。" :
|
|
95
95
|
this.#recovery === "retry" ? "控制锁持续占用,后台会继续重试;不会自动删除锁或重新提交任务。" : "报告或控制记录读取失败,修复后后台会重试扫描。") +
|
|
96
96
|
(this.#pausePending ? "\n\n团队暂停尚未确认,不能据此开始成员私人任务。" : "") };
|
|
@@ -25,6 +25,7 @@ export class DshAgentRuntime {
|
|
|
25
25
|
#answer = "";
|
|
26
26
|
#hasAnswer = false;
|
|
27
27
|
#activeTeam: TeamLink | undefined;
|
|
28
|
+
#teamBriefed = false;
|
|
28
29
|
#pendingPause: string | undefined;
|
|
29
30
|
#pump: Promise<void> | undefined;
|
|
30
31
|
#timer: ReturnType<typeof setInterval> | undefined;
|
|
@@ -98,12 +99,11 @@ export class DshAgentRuntime {
|
|
|
98
99
|
requireThat(link, "团队关联不可读取。");
|
|
99
100
|
const seen = this.#seen.get(link.team.teamId) ?? new Set<number>();
|
|
100
101
|
const context = createTeamContext(link, seen);
|
|
101
|
-
if (!context) return decision;
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
if (this.#teamBriefed && !context) return decision;
|
|
103
|
+
const text = [...(this.#teamBriefed ? [] : [teamBrief(link)]), ...(context ? [context.content] : [])].join("\n\n");
|
|
104
|
+
return { ...decision, messages: [...decision.messages, createUserMessage({ content: [{ type: "text", text }],
|
|
105
|
+
source: { kind: "pbot-team-context", form: "relay", teamId: link.team.teamId, seqs: context?.seqs ?? [] } })] };
|
|
104
106
|
});
|
|
105
|
-
this.ctx.systemPrompt.section({ name: "pbot:team", order: 600, interpolate: false,
|
|
106
|
-
text: () => this.#activeTeam && !this.humanPending() && this.execution.current?.source === "parent" ? teamBrief(this.#activeTeam) : "" });
|
|
107
107
|
this.execution.save({ state: "idle", activity: "空闲" });
|
|
108
108
|
this.ctx.effect(() => () => this.stop());
|
|
109
109
|
}
|
|
@@ -128,7 +128,7 @@ export class DshAgentRuntime {
|
|
|
128
128
|
private async event(event: SessionEvent) {
|
|
129
129
|
if (!this.current()) return;
|
|
130
130
|
if (event.type === "turn/start") {
|
|
131
|
-
this.#turnEvents = []; this.#answer = ""; this.#hasAnswer = false;
|
|
131
|
+
this.#turnEvents = []; this.#answer = ""; this.#hasAnswer = false; this.#teamBriefed = false;
|
|
132
132
|
this.execution.begin();
|
|
133
133
|
}
|
|
134
134
|
if (this.execution.current) this.#turnEvents.push(event);
|
|
@@ -152,6 +152,7 @@ export class DshAgentRuntime {
|
|
|
152
152
|
if (event.data.source.kind === "user") this.execution.humanInput();
|
|
153
153
|
if (event.data.source.kind === "pbot-team-context") {
|
|
154
154
|
const { teamId, seqs } = event.data.source, seen = this.#seen.get(teamId) ?? new Set<number>();
|
|
155
|
+
if (this.#activeTeam?.team.teamId === teamId) this.#teamBriefed = true;
|
|
155
156
|
for (const seq of seqs) seen.add(seq); this.#seen.set(teamId, seen);
|
|
156
157
|
}
|
|
157
158
|
}
|
package/src/extension/events.ts
CHANGED
|
@@ -25,19 +25,24 @@ export function registerEvents(pi: ExtensionAPI, lifecycle: Lifecycle, confirmat
|
|
|
25
25
|
else throw error;
|
|
26
26
|
}
|
|
27
27
|
});
|
|
28
|
-
pi.on("resources_discover", () => lifecycle.active ? { skillPaths: [join(resourceRoot, "skills")] } : {});
|
|
29
28
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
30
29
|
const instance = lifecycle.active;
|
|
31
30
|
if (!instance) return;
|
|
32
31
|
instance.cancelWork();
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
try {
|
|
33
|
+
const role = await agentText("coordinator", instance.root);
|
|
34
|
+
const workspace = await readFile(join(resourceRoot, "prompts/workspace.md"), "utf8");
|
|
35
|
+
instance.check();
|
|
36
|
+
const { state, directory } = instance.pythonEnvironment.status;
|
|
37
|
+
Object.assign(event.systemPromptOptions.sections, {
|
|
38
|
+
pbot_workspace: workspace,
|
|
39
|
+
pbot_environment: JSON.stringify({ workspaceRoot: instance.root, resourceRoot, python: { state, directory } }),
|
|
40
|
+
pbot: role,
|
|
41
|
+
});
|
|
42
|
+
} catch (error) {
|
|
43
|
+
// Pi reports hook errors but continues preparation unless the run is explicitly aborted.
|
|
44
|
+
ctx.abort(); throw error;
|
|
45
|
+
}
|
|
41
46
|
});
|
|
42
47
|
pi.on("input", () => { lifecycle.active?.cancelWork(); });
|
|
43
48
|
pi.on("agent_end", () => { lifecycle.active?.cancelWork(); });
|
|
@@ -134,7 +134,7 @@ export default function subagent(pi: ExtensionAPI) {
|
|
|
134
134
|
pi.registerTool({ ...teamMessageTool(teams, { check: ensure }, () => ({
|
|
135
135
|
kind: "member", agentId: id, generation,
|
|
136
136
|
...(activeTeam && execution.current?.source === "parent" ? { requestId: activeTeam.request.requestId } : {}),
|
|
137
|
-
})), namespace: { name: "pbot", description: "
|
|
137
|
+
})), namespace: { name: "pbot", description: "团队公共通信。" } });
|
|
138
138
|
pi.on("resources_discover", async () => {
|
|
139
139
|
if (d.options.noSkills) return {};
|
|
140
140
|
const skillPaths = [join(resourceRoot, "skills")];
|
|
@@ -189,22 +189,30 @@ export default function subagent(pi: ExtensionAPI) {
|
|
|
189
189
|
}
|
|
190
190
|
});
|
|
191
191
|
pi.on("before_agent_start", async (event, context) => {
|
|
192
|
-
ctx = context;
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
192
|
+
ctx = context;
|
|
193
|
+
try {
|
|
194
|
+
ensure(); bindSession();
|
|
195
|
+
requireThat(python, "子会话计算环境状态不可用。");
|
|
196
|
+
const workspace = await readFile(join(resourceRoot, "prompts/workspace.md"), "utf8");
|
|
197
|
+
const role = await agentText("general-purpose", d.workspace);
|
|
198
|
+
let brief: string | undefined, message;
|
|
199
|
+
if (activeTeam && !execution.interactive && execution.current?.source !== "mixed") {
|
|
200
|
+
const link = teams.links().get(activeTeam.request.requestId);
|
|
201
|
+
requireThat(link, "团队关联不可读取。");
|
|
202
|
+
brief = teamBrief(link);
|
|
203
|
+
message = teamContext(link, context, link.request.throughSeq);
|
|
204
|
+
}
|
|
205
|
+
const { state, directory } = python.status;
|
|
206
|
+
Object.assign(event.systemPromptOptions.sections, {
|
|
207
|
+
pbot_environment: JSON.stringify({ workspaceRoot: d.workspace, resourceRoot, python: { state, directory } }),
|
|
208
|
+
pbot_workspace: workspace, pbot_child: role,
|
|
209
|
+
});
|
|
210
|
+
if (brief) event.systemPromptOptions.sections.pbot_team = brief;
|
|
211
|
+
else delete event.systemPromptOptions.sections.pbot_team;
|
|
212
|
+
return message ? { message } : undefined;
|
|
213
|
+
} catch (error) {
|
|
214
|
+
context.abort(); throw error;
|
|
206
215
|
}
|
|
207
|
-
return;
|
|
208
216
|
});
|
|
209
217
|
pi.on("turn_end", (event, context) => {
|
|
210
218
|
if (!activeTeam || execution.current?.source !== "parent" || event.outcome === "aborted") return;
|
|
@@ -2,7 +2,7 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import type { Context } from "@deepseek-ai/cordis";
|
|
4
4
|
import type { Agent } from "@deepseek-ai/dsh-agent";
|
|
5
|
-
import {
|
|
5
|
+
import type {} from "@deepseek-ai/dsh-skill";
|
|
6
6
|
import type {} from "@deepseek-ai/dsh-working-directory";
|
|
7
7
|
import type {} from "@deepseek-ai/dsh-tools";
|
|
8
8
|
import { agentText } from "../agent-resources.js";
|
|
@@ -10,29 +10,32 @@ import { resourceRoot } from "../../common/paths.js";
|
|
|
10
10
|
import { requireThat } from "../../common/validation.js";
|
|
11
11
|
import type { AgentOptions } from "../../model/agent.js";
|
|
12
12
|
|
|
13
|
-
export async function dshResources(ctx: Context,
|
|
13
|
+
export async function dshResources(ctx: Context, _agent: Agent, root: string,
|
|
14
14
|
role: "coordinator" | "general-purpose", python: () => { state: string; directory?: string; error?: string }, check: () => void) {
|
|
15
|
-
|
|
16
|
-
const workspace = await
|
|
15
|
+
const read = () => Promise.all([agentText(role, root), readFile(join(resourceRoot, "prompts/workspace.md"), "utf8")]);
|
|
16
|
+
const [text, workspace] = await read();
|
|
17
17
|
check();
|
|
18
|
-
ctx.systemPrompt.section({ name: "pbot:role", order: 1, text
|
|
18
|
+
ctx.systemPrompt.section({ name: "pbot:role", order: 1, text, interpolate: false });
|
|
19
19
|
ctx.systemPrompt.section({ name: "pbot:workspace", order: 2, text: workspace, interpolate: false });
|
|
20
20
|
ctx.systemPrompt.context({ name: "pbot:environment", order: 300, required: true, interpolate: false,
|
|
21
|
-
text: () =>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
text: () => {
|
|
22
|
+
const { state, directory } = python();
|
|
23
|
+
return JSON.stringify({ workspaceRoot: root, resourceRoot, python: { state, ...(directory ? { directory } : {}) } });
|
|
24
|
+
} });
|
|
25
|
+
ctx.on("system-prompt/assemble", async (_assembly, _context, next) => {
|
|
26
|
+
check();
|
|
27
|
+
const [roleText, workspaceText] = await read();
|
|
28
|
+
check();
|
|
29
|
+
const assembly = await next();
|
|
30
|
+
return { ...assembly, sections: assembly.sections.map(section => section.name === "pbot:role" ? { ...section, text: roleText }
|
|
31
|
+
: section.name === "pbot:workspace" ? { ...section, text: workspaceText } : section) };
|
|
29
32
|
});
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
/** Map the expert's native loadout; this is not isolation from Bash, CLI, or MCP. */
|
|
33
36
|
export function dshExpertTools(ctx: Context, agent: Agent, options: AgentOptions) {
|
|
34
37
|
const names = new Set(ctx.tools.definitions(agent).map(tool => tool.name));
|
|
35
|
-
const forbidden = new Set(["pbot_agent", "pbot_team", "pbot_history", "subagent", "list_subagent_models", "list_agents", "send_message", "interrupt_agent"]);
|
|
38
|
+
const forbidden = new Set(["pbot_agent", "pbot_team", "pbot_history", "subagent", "subagent_fork", "list_subagent_models", "list_agents", "send_message", "interrupt_agent"]);
|
|
36
39
|
if (options.noSkills) forbidden.add("skill");
|
|
37
40
|
if (options.tools) {
|
|
38
41
|
for (const name of options.tools) requireThat((names.has(name) || name === "pbot_team_message") && !forbidden.has(name), "专家工具不可用:" + name);
|
|
@@ -4,6 +4,7 @@ import { SessionId } from "@deepseek-ai/dsh-session";
|
|
|
4
4
|
import { ReasoningEffortId } from "@deepseek-ai/dsh-llm";
|
|
5
5
|
import type { SessionHeader } from "@deepseek-ai/dsh-session";
|
|
6
6
|
import type {} from "@deepseek-ai/dsh-session-persistence";
|
|
7
|
+
import type {} from "@deepseek-ai/dsh-agent-preset-registry";
|
|
7
8
|
import type { AgentDescriptor } from "../../model/agent.js";
|
|
8
9
|
import { requireThat } from "../../common/validation.js";
|
|
9
10
|
|
|
@@ -37,6 +38,7 @@ export async function openDshAgent(ctx: Context, d: AgentDescriptor, parent: Age
|
|
|
37
38
|
signal.throwIfAborted();
|
|
38
39
|
const compose: AgentSetup = async (agentCtx, agent) => {
|
|
39
40
|
validateHeader(d, agent.session.header);
|
|
41
|
+
agentCtx.get("agentPresets")?.composeFrom(agentCtx, parent.ctx);
|
|
40
42
|
if (resume) agent.inbox.clear();
|
|
41
43
|
const commit = await setup(agentCtx, agent);
|
|
42
44
|
await flushDshAgent(agent);
|
|
@@ -44,20 +44,22 @@ export async function inspectPackages(root: string, workspace: string): Promise<
|
|
|
44
44
|
for (const pkg of manager.listConfiguredPackages()) {
|
|
45
45
|
const entries = (pkg.scope === "project" ? settings.getProjectSettings() : settings.getGlobalSettings()).packages ?? [];
|
|
46
46
|
const entry = entries.find(item => sourceOf(item) === pkg.source);
|
|
47
|
-
let name = npmName(pkg.source), version: string | undefined;
|
|
47
|
+
let name = npmName(pkg.source), version: string | undefined, singleFile = false;
|
|
48
48
|
if (pkg.installedPath) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (file) {
|
|
49
|
+
const info = await stat(pkg.installedPath);
|
|
50
|
+
singleFile = info.isFile(); // An existing standalone extension has no npm identity.
|
|
51
|
+
if (info.isDirectory()) {
|
|
53
52
|
try {
|
|
54
|
-
const manifest = JSON.parse(await readFile(
|
|
53
|
+
const manifest = JSON.parse(await readFile(join(pkg.installedPath, "package.json"), "utf8")) as { name?: string; version?: string };
|
|
55
54
|
if (name && manifest.name !== name) throw new Error(`安装包身份不匹配:${pkg.source}`);
|
|
56
|
-
name = typeof manifest.name === "string" ? manifest.name : name;
|
|
55
|
+
name = typeof manifest.name === "string" && manifest.name.trim() ? manifest.name : name;
|
|
57
56
|
version = typeof manifest.version === "string" ? manifest.version : undefined;
|
|
58
57
|
} catch (error) { if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error; }
|
|
59
58
|
}
|
|
60
59
|
}
|
|
60
|
+
if (!name && !singleFile) {
|
|
61
|
+
throw new Error(`无法辨认 ${pkg.scope} 来源的包身份:${pkg.source}。请先通过 Pi 原生配置恢复或修正该来源,再重新运行 setup。`);
|
|
62
|
+
}
|
|
61
63
|
result.push({ source: pkg.source, scope: pkg.scope, filtered: pkg.filtered, entry,
|
|
62
64
|
...(pkg.installedPath ? { installedPath: pkg.installedPath } : {}), ...(name ? { name } : {}), ...(version ? { version } : {}) });
|
|
63
65
|
}
|
|
@@ -6,7 +6,7 @@ export function agentOwner(ctx: ExtensionContext): AgentOwner {
|
|
|
6
6
|
export function deliveredCycles(ctx: ExtensionContext): Set<string> {
|
|
7
7
|
const keys = new Set<string>();
|
|
8
8
|
for (const entry of ctx.sessionManager.getBranch()) {
|
|
9
|
-
const data = entry.type === "custom_message" && ["pbot.agent-results", "pbot.agent-error"].includes(entry.customType) ? entry.details
|
|
9
|
+
const data = entry.type === "custom_message" && ["pbot.agent-results", "pbot.agent-error", "pbot.agent-recovered"].includes(entry.customType) ? entry.details
|
|
10
10
|
: entry.type === "custom" && entry.customType === "pbot.agent-read" ? entry.data : undefined;
|
|
11
11
|
if (entry.type === "custom" && entry.customType === "pbot.agent-read") {
|
|
12
12
|
const receipt = entry.data as { toolCallId?: string };
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
1
3
|
import type { TeamLink, TeamMessage } from "../model/team.js";
|
|
2
4
|
import { markdownBlock } from "../common/markdown.js";
|
|
5
|
+
import { resourceRoot } from "../common/paths.js";
|
|
3
6
|
|
|
4
7
|
type MessagePage = Pick<TeamMessage, "seq" | "author" | "text" | "replyTo" | "runId" | "source"> & {
|
|
5
8
|
offset: number; totalLength: number; nextOffset: number | null;
|
|
@@ -22,7 +25,7 @@ function messageMarkdown(message: MessagePage): string {
|
|
|
22
25
|
export function teamMessagesMarkdown(page: { teamId: string; messages: MessagePage[]; lastSeq: number; nextAfterSeq: number | null }): string {
|
|
23
26
|
return ["# 团队公共消息", "", "- `teamId`: `" + page.teamId + "`", "- `lastSeq`: `" + page.lastSeq + "`",
|
|
24
27
|
"- `nextAfterSeq`: `" + page.nextAfterSeq + "`", "",
|
|
25
|
-
"
|
|
28
|
+
"nextOffset 非空时先续读该条正文,再读取后续消息。", "",
|
|
26
29
|
page.messages.map(messageMarkdown).join("\n\n")].join("\n");
|
|
27
30
|
}
|
|
28
31
|
|
|
@@ -30,7 +33,8 @@ export function teamBrief(link: TeamLink): string {
|
|
|
30
33
|
return ["# 团队协作", "", "- 团队:" + link.team.name, "- `teamId`: `" + link.team.teamId + "`",
|
|
31
34
|
"- 当前成员 `agentId`: `" + link.request.agentId + "`", "- `runId`: `" + link.run.runId + "`",
|
|
32
35
|
"- 轮次:" + link.request.round + " / " + link.run.rounds, "", "## 共同目标", "", link.team.brief,
|
|
33
|
-
"", "## 成员职责", "", ...link.team.members.flatMap(member => ["### " + member.agentId, "", member.role, ""])
|
|
36
|
+
"", "## 成员职责", "", ...link.team.members.flatMap(member => ["### " + member.agentId, "", member.role, ""]),
|
|
37
|
+
readFileSync(join(resourceRoot, "prompts/team-member.md"), "utf8").trim()].join("\n");
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
export function createTeamContext(link: TeamLink, seen: ReadonlySet<number>, throughSeq = link.team.messages.length) {
|
|
@@ -54,7 +58,7 @@ export function createTeamContext(link: TeamLink, seen: ReadonlySet<number>, thr
|
|
|
54
58
|
const seqs = messages.map(m => m.seq);
|
|
55
59
|
return { content: ["# 团队公共上下文", "", "- `teamId`: `" + link.team.teamId + "`", "- `throughSeq`: `" + throughSeq + "`",
|
|
56
60
|
"- `remainingFromSeq`: `" + (pending[messages.length]?.seq ?? null) + "`", "",
|
|
57
|
-
"
|
|
61
|
+
"未包含或被截断的正文用 pbot_team_message read 读取。remainingFromSeq 非空时,用 afterSeq: remainingFromSeq - 1 读取未包含的消息。", "",
|
|
58
62
|
messages.map(messageMarkdown).join("\n\n")].join("\n"),
|
|
59
63
|
seqs };
|
|
60
64
|
}
|
|
@@ -8,7 +8,7 @@ export function teamNotice(values: ReturnType<TeamService["notifications"]>, kno
|
|
|
8
8
|
const notes = values.filter(value => !known.has(value.key)).slice(0, 8);
|
|
9
9
|
if (!notes.length) return;
|
|
10
10
|
return { kind: "teams" as const, keys: notes.map(value => value.key), content: ["# 团队批次状态", "",
|
|
11
|
-
"
|
|
11
|
+
"团队批次状态已变化,用 pbot_team status/read 查看状态和结果。暂停时可能仍有在途工作,重跑前先查看原请求结果。", "",
|
|
12
12
|
notes.map(value => ["## " + value.name, "", "- `teamId`: `" + value.teamId + "`", "- `runId`: `" + value.runId + "`",
|
|
13
13
|
"- 状态:" + value.state, "- 在途工作:" + value.activeCount, ...(value.reason ? ["", "### 原因", "", value.reason] : [])].join("\n")).join("\n\n")].join("\n") };
|
|
14
14
|
}
|
|
@@ -20,7 +20,7 @@ export function agentNotice(values: AgentCompletion[], links: ReadonlyMap<string
|
|
|
20
20
|
if (!batch.length) return;
|
|
21
21
|
return { kind: "agents" as const, keys: batch.map(value => value.agentId + ":" + value.cycle.cycleId),
|
|
22
22
|
content: "# 子会话工作结果\n\n子会话工作已结束。完整报告用 pbot_agent read 读取,指定对应 agentId 和 cycle.cycleId;nextOffset 非空时沿用该 cycleId 续读。\n\n" +
|
|
23
|
-
(batch.some(value => value.cycle.source !== "parent") ? "
|
|
23
|
+
(batch.some(value => value.cycle.source !== "parent") ? "部分结果包含人工子会话输入,来源见 cycle.source。\n\n" : "") +
|
|
24
24
|
batch.map(value => "## " + value.name + "\n\n" + markdownFields(json({ agentId: value.agentId,
|
|
25
25
|
cycle: { cycleId: value.cycle.cycleId, state: value.cycle.state, source: value.cycle.source, requestIds: value.cycle.requestIds,
|
|
26
26
|
...(value.cycle.error === undefined ? {} : { error: value.cycle.error }) },
|
|
@@ -249,7 +249,7 @@ export class TeamService {
|
|
|
249
249
|
const q = { requestId: randomUUID(), agentId: m.agentId, generation: run.generations[m.agentId]!, round: nextRound, throughSeq: team.messages.length };
|
|
250
250
|
run.issued.push(q); slots--; changed = true;
|
|
251
251
|
inputs.push({ ...q, teamId: team.teamId, runId: run.runId,
|
|
252
|
-
message: ["# 团队发言任务", "", "
|
|
252
|
+
message: ["# 团队发言任务", "", "执行本次团队发言安排。最终答复将公开给全体成员。", "",
|
|
253
253
|
"- `teamId`: `" + team.teamId + "`", "- `runId`: `" + run.runId + "`", "- 轮次:" + q.round,
|
|
254
254
|
"", "## 本批次要求", "", run.instruction].join("\n") });
|
|
255
255
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
|
|
3
|
-
export const agentDescription = "
|
|
3
|
+
export const agentDescription = "委派专家并继续对话。start 启动后即返回,完成自动通知,无需轮询;省略初始输入时待命。send 继续对话,团队占用期间不可私人 send。status 查看状态,read 读取报告;读取已结束周期即领取其通知,包括部分读取。续读固定 cycle.cycleId 并使用 nextOffset。state 表示执行状态,cycle.state 表示工作结果,queued 只表示入队。stop 保留历史,resume 携新 message 继续。每个父会话最多 50 个存活专家,空闲也计入。";
|
|
4
4
|
|
|
5
5
|
const id = Type.String({ minLength: 1, maxLength: 128 });
|
|
6
|
-
const message = Type.String({ minLength: 1, maxLength: 24000, description: "
|
|
6
|
+
const message = Type.String({ minLength: 1, maxLength: 24000, description: "本次目标、相关资料、约束和交付要求。" });
|
|
7
7
|
const name = Type.String({ minLength: 1, maxLength: 64, pattern: "^[^\\r\\n\\x00-\\x1f]+$" });
|
|
8
8
|
export const agentStartOptions = {
|
|
9
9
|
name: Type.Optional(name), message: Type.Optional(message),
|
|
10
10
|
files: Type.Optional(Type.Array(Type.String({ minLength: 1 }), { maxItems: 32, description: "随初始消息读取的文件;相对路径基于原工作区根目录。" })),
|
|
11
|
-
prompts: Type.Optional(Type.Array(message, { maxItems: 32, description: "与 message
|
|
11
|
+
prompts: Type.Optional(Type.Array(message, { maxItems: 32, description: "与 message 按顺序合并为同一初始消息。" })),
|
|
12
12
|
provider: Type.Optional(Type.String({ ...id, description: "Pi 模型提供方,默认继承主会话。" })),
|
|
13
|
-
model: Type.Optional(Type.String({ ...id, description: "
|
|
13
|
+
model: Type.Optional(Type.String({ ...id, description: "Pi 模型 ID,默认继承主会话。" })),
|
|
14
14
|
thinking: Type.Optional(Type.Union([Type.Literal("off"), Type.Literal("minimal"), Type.Literal("low"), Type.Literal("medium"), Type.Literal("high"), Type.Literal("xhigh"), Type.Literal("max")], { description: "默认继承主会话思考级别。" })),
|
|
15
15
|
cwd: Type.Optional(Type.String({ minLength: 1, description: "执行目录,相对原工作区根目录;省略时使用工作区根目录。" })),
|
|
16
|
-
tools: Type.Optional(Type.Array(id, { minItems: 1, description: "按 Pi
|
|
16
|
+
tools: Type.Optional(Type.Array(id, { minItems: 1, description: "按 Pi 规则选择工具,省略时使用默认工具;MCP 工具按当前配置提供。" })),
|
|
17
17
|
noExtensions: Type.Optional(Type.Boolean({ description: "默认 true,不发现其他扩展。" })),
|
|
18
18
|
noSkills: Type.Optional(Type.Boolean({ description: "关闭技能发现,默认 false。" })),
|
|
19
19
|
noPromptTemplates: Type.Optional(Type.Boolean({ description: "关闭提示模板发现,默认 false。" })),
|
|
@@ -42,7 +42,7 @@ export const agentActionSchema = Type.Union([
|
|
|
42
42
|
]);
|
|
43
43
|
|
|
44
44
|
const cycle = Type.Object({ cycleId: Type.String(), startedAt: Type.Number(), finishedAt: Type.Optional(Type.Number()),
|
|
45
|
-
state: Type.Union([Type.Literal("running"), Type.Literal("completed"), Type.Literal("failed"), Type.Literal("cancelled"), Type.Literal("interrupted")], { description: "
|
|
45
|
+
state: Type.Union([Type.Literal("running"), Type.Literal("completed"), Type.Literal("failed"), Type.Literal("cancelled"), Type.Literal("interrupted")], { description: "本周期的工作结果,正文用 read 读取。" }),
|
|
46
46
|
requestIds: Type.Array(Type.String()),
|
|
47
47
|
source: Type.Union([Type.Literal("parent"), Type.Literal("interactive"), Type.Literal("mixed")]), error: Type.Optional(Type.String()),
|
|
48
48
|
}, { additionalProperties: false });
|
|
@@ -52,7 +52,7 @@ export const agentViewSchema = Type.Object({ agentId: Type.String(), name: Type.
|
|
|
52
52
|
activity: Type.String(), cycle: Type.Optional(cycle), error: Type.Optional(Type.String()),
|
|
53
53
|
requestId: Type.Optional(Type.String()), messageStatus: Type.Optional(Type.Literal("queued", { description: "消息已入队,不代表模型已阅读或完成。" })),
|
|
54
54
|
cycles: Type.Optional(Type.Array(Type.Object({ cycleId: Type.String(), state: Type.String() }), { description: "仅 read 返回:可读取的周期索引。" })),
|
|
55
|
-
report: Type.Optional(Type.String({ description: "仅 read
|
|
55
|
+
report: Type.Optional(Type.String({ description: "仅 read 返回:选定周期的报告正文片段。" })),
|
|
56
56
|
totalLength: Type.Optional(Type.Integer({ description: "仅 read 返回:完整报告的 UTF-16 字符数。" })),
|
|
57
57
|
nextOffset: Type.Optional(Type.Union([Type.Integer(), Type.Null()], { description: "仅 read 返回:null 表示本报告已读完;否则以相同 agentId、cycle.cycleId 和此 offset 继续。" })),
|
|
58
58
|
}, { additionalProperties: false });
|