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,10 +5,10 @@ const options = Type.Omit(Type.Object(agentStartOptions), ["provider", "model",
|
|
|
5
5
|
const native = {
|
|
6
6
|
provider: Type.Optional(Type.String({ minLength: 1, maxLength: 128, description: "dsh 原生 provider route,默认继承父会话。" })),
|
|
7
7
|
model: Type.Optional(Type.String({ minLength: 1, maxLength: 128, description: "该 dsh provider 的模型 ID,默认继承父会话。" })),
|
|
8
|
-
thinking: Type.Optional(Type.String({ minLength: 1, maxLength: 128, description: "该 dsh
|
|
9
|
-
files: Type.Optional(Type.Array(Type.String({ minLength: 1 }), { maxItems: 32, description: "
|
|
10
|
-
tools: Type.Optional(Type.Array(Type.String({ minLength: 1 }), { minItems: 1, description: "
|
|
11
|
-
noSkills: Type.Optional(Type.Boolean({ description: "
|
|
8
|
+
thinking: Type.Optional(Type.String({ minLength: 1, maxLength: 128, description: "该 dsh 模型的 reasoning effort ID,默认继承父会话。" })),
|
|
9
|
+
files: Type.Optional(Type.Array(Type.String({ minLength: 1 }), { maxItems: 32, description: "附给专家的文件;相对原工作区根目录。图片大小与格式遵循 dsh 限制。" })),
|
|
10
|
+
tools: Type.Optional(Type.Array(Type.String({ minLength: 1 }), { minItems: 1, description: "能力工具名,不填写 run_code;省略时使用原生工具和 pbot_team_message。" })),
|
|
11
|
+
noSkills: Type.Optional(Type.Boolean({ description: "关闭该专家的技能目录和 skill 工具。" })),
|
|
12
12
|
};
|
|
13
13
|
const omitted = ["noExtensions", "noPromptTemplates", "noContextFiles", "provider", "model", "thinking", "files", "tools", "noSkills"] as const;
|
|
14
14
|
export const dshAgentParametersSchema = Type.Object({ ...Type.Omit(agentParametersSchema, omitted).properties, ...native }, { additionalProperties: false });
|
|
@@ -10,10 +10,10 @@ export const historyResultSchema = Type.Object({
|
|
|
10
10
|
total: Type.Optional(Type.Integer()), nextOffset: Type.Optional(nullableOffset),
|
|
11
11
|
node: Type.Optional(Type.Object({ ...node.properties, text: Type.String(), totalLength: Type.Integer(), nextOffset: nullableOffset,
|
|
12
12
|
parents: Type.Array(node), children: Type.Array(node), nextChildrenOffset: nullableOffset,
|
|
13
|
-
source: Type.Object({ host, sessionId: Type.String({ description: "原始宿主会话 ID
|
|
13
|
+
source: Type.Object({ host, sessionId: Type.String({ description: "原始宿主会话 ID。" }), entryIds: Type.Array(Type.String()) }), warnings: Type.Array(Type.String()) })),
|
|
14
14
|
warnings: Type.Array(Type.String()),
|
|
15
15
|
});
|
|
16
|
-
export const historyDescription = "查询当前工作区的 Pi
|
|
16
|
+
export const historyDescription = "查询当前工作区的 Pi/dsh 问答归档,host 可筛选来源。search 按不区分大小写的连续文本匹配原文和摘要;无匹配时换词,省略 query 列会话。read 按 parents/children 的 id 展开,nextOffset 续读正文,nextChildrenOffset 续读子节点。需要对话细节时读取 exchange 原文;需要工具日志时查所属宿主的原始会话。";
|
|
17
17
|
export const historyParameters = Type.Object({ action: Type.Union([Type.Literal("search"), Type.Literal("read")]),
|
|
18
18
|
host: Type.Optional(host), query: Type.Optional(Type.String()), sessionId: Type.Optional(Type.String()),
|
|
19
19
|
from: Type.Optional(Type.String({ description: "search:ISO 日期或时间,下界。" })),
|
package/src/tools/register.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
1
|
import type { ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
import { resourceRoot } from "../common/paths.js";
|
|
5
2
|
import type { AgentService } from "../services/agents/agent-service.js";
|
|
6
3
|
import type { CallAccess } from "./access.js";
|
|
7
4
|
import { agentTool } from "./agents/tool.js";
|
|
@@ -18,11 +15,8 @@ export class ToolRegistry {
|
|
|
18
15
|
readonly #registered = new Map<string, ToolDefinition>();
|
|
19
16
|
constructor(private readonly pi: ExtensionAPI) {}
|
|
20
17
|
register(tools: ToolDefinition[]) {
|
|
21
|
-
const promptGuidelines = readFileSync(join(resourceRoot, "prompts/tool-guidelines.md"), "utf8")
|
|
22
|
-
.trim().split(/\r?\n\s*\r?\n/);
|
|
23
18
|
for (const definition of tools) {
|
|
24
|
-
const tool = { ...definition, namespace: { name: "pbot", description: "
|
|
25
|
-
promptGuidelines };
|
|
19
|
+
const tool = { ...definition, namespace: { name: "pbot", description: "历史查询、专家与团队协作。" } };
|
|
26
20
|
this.#registered.set(tool.name, tool); this.pi.registerTool(tool);
|
|
27
21
|
}
|
|
28
22
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
|
|
3
|
-
export const teamDescription = "
|
|
4
|
-
export const teamMessageDescription = "
|
|
3
|
+
export const teamDescription = "组织固定成员协作。create 建立团队,run 开始一批讨论。运行时占用成员;pause 停止新安排,允许在途工作收尾,之后可私人 send;中止成员用 pbot_agent stop。close 保留成员和历史;换成员须关闭旧团队再创建。继续讨论用 run 提交新要求。成员最终答复向团队公开。";
|
|
4
|
+
export const teamMessageDescription = "读写团队公共原文。post 向全体成员发布信息,需要安排回答时由主会话调用 pbot_team run;成员只能在自己的团队工作中 post。read 用 afterSeq 翻页,长正文按 seq/offset 续读,先补完 nextOffset 非空的消息。";
|
|
5
5
|
|
|
6
6
|
import type { TSchema } from "typebox";
|
|
7
7
|
|
|
@@ -10,13 +10,13 @@ const text = Type.String({ minLength: 1, maxLength: 24000 });
|
|
|
10
10
|
const name = Type.String({ minLength: 1, maxLength: 64, pattern: "^[^\\r\\n\\x00-\\x1f]+$" });
|
|
11
11
|
const mode = Type.Union([Type.Literal("roundRobin"), Type.Literal("parallel")], { description: "run 必填:roundRobin 按成员顺序轮流发言;parallel 在并发上限内发言,全员本轮完成后才进入下一轮。" });
|
|
12
12
|
const members = Type.Array(Type.Object({ agentId: id, role: Type.String({ minLength: 1, maxLength: 4000 }) }, { additionalProperties: false }), {
|
|
13
|
-
minItems: 1, maxItems: 50, description: "仅 create
|
|
13
|
+
minItems: 1, maxItems: 50, description: "仅 create,必填:当前分支中的固定成员及职责;成员须版本兼容且未加入其他未关闭团队。",
|
|
14
14
|
});
|
|
15
15
|
const run = {
|
|
16
|
-
instruction: Type.String({ ...text, description: "仅 run
|
|
16
|
+
instruction: Type.String({ ...text, description: "仅 run,必填:本批次的任务、约束与交付要求。" }), mode,
|
|
17
17
|
rounds: Type.Optional(Type.Integer({ minimum: 1, maximum: 10, description: "仅 run:每位成员的轮数,默认 2。" })),
|
|
18
|
-
maxConcurrent: Type.Optional(Type.Integer({ minimum: 1, maximum: 50, description: "仅 run:roundRobin 默认且只允许 1;parallel 默认 min(2, 成员数)
|
|
19
|
-
timeoutSeconds: Type.Optional(Type.Integer({ minimum: 1, maximum: 86400, description: "仅 run:整批期限,默认 900
|
|
18
|
+
maxConcurrent: Type.Optional(Type.Integer({ minimum: 1, maximum: 50, description: "仅 run:roundRobin 默认且只允许 1;parallel 默认 min(2, 成员数)。不得超过成员数;待处理和执行中的发言都计入上限。" })),
|
|
19
|
+
timeoutSeconds: Type.Optional(Type.Integer({ minimum: 1, maximum: 86400, description: "仅 run:整批期限,默认 900 秒,包含所有轮次和等待。到期停止安排并尝试中止尚未人工接管的工作,之后仍须核对实际状态;pause 则允许在途工作收尾。" })),
|
|
20
20
|
};
|
|
21
21
|
const page = {
|
|
22
22
|
afterSeq: Type.Optional(Type.Integer({ minimum: 0, description: "仅 read:读取序号大于此值的消息,默认 0,不得超过 lastSeq。返回 nextAfterSeq 用于继续消息列表;单条续读使用 seq/offset,省略 afterSeq。先补完被截断的正文,再继续列表。" })),
|
|
@@ -27,7 +27,7 @@ const page = {
|
|
|
27
27
|
const object = <T extends Record<string, TSchema>>(fields: T) => Type.Object(fields, { additionalProperties: false });
|
|
28
28
|
export const teamParametersSchema = object({
|
|
29
29
|
action: Type.Union(["create", "list", "status", "read", "run", "pause", "close"].map(v => Type.Literal(v)), {
|
|
30
|
-
description: "create
|
|
30
|
+
description: "create 必填 name/brief/members;list 只接受 action;status/pause/close 必填 teamId;read 必填 teamId,可选 afterSeq/seq/offset/limit;run 必填 teamId/instruction/mode,可选 rounds/maxConcurrent/timeoutSeconds。只传对应 action 的字段。run 前须确认所有成员存活、idle、可参与团队且无待处理私人输入,团队未关闭,也无运行批次或在途工作。close 前先暂停并等待在途工作结束。",
|
|
31
31
|
}),
|
|
32
32
|
teamId: Type.Optional(id), name: Type.Optional(name), brief: Type.Optional(text), members: Type.Optional(members),
|
|
33
33
|
instruction: Type.Optional(run.instruction), mode: Type.Optional(mode), rounds: run.rounds, maxConcurrent: run.maxConcurrent, timeoutSeconds: run.timeoutSeconds, ...page,
|
|
@@ -42,7 +42,7 @@ export const teamActionSchema = Type.Union([
|
|
|
42
42
|
export const teamMessageParametersSchema = object({
|
|
43
43
|
action: Type.Union([Type.Literal("read"), Type.Literal("post")], {
|
|
44
44
|
description: "read 必填 teamId,只可选 afterSeq/seq/offset/limit,禁止 text/replyTo;post 必填 teamId/text,只可选 replyTo,禁止所有分页字段。",
|
|
45
|
-
}), teamId: id, text: Type.Optional(Type.String({ ...text, description: "仅 post
|
|
45
|
+
}), teamId: id, text: Type.Optional(Type.String({ ...text, description: "仅 post,必填:向全体成员公开的原文。" })),
|
|
46
46
|
replyTo: Type.Optional(Type.Integer({ minimum: 1, description: "仅 post:回复已有消息的 seq。" })), ...page,
|
|
47
47
|
});
|
|
48
48
|
export const teamMessageActionSchema = Type.Union([
|
|
@@ -59,10 +59,10 @@ export const teamPageSchema = object({ teamId: id, messages: Type.Array(message)
|
|
|
59
59
|
nextAfterSeq: Type.Union([Type.Integer(), Type.Null()], { description: "后续消息列表的 afterSeq;null 只表示列表已到末尾,仍须检查每条消息的 nextOffset。指定 seq 时始终为 null。" }) });
|
|
60
60
|
const ownedView = object({ teamId: id, name: Type.String(), brief: Type.String(), closed: Type.Boolean(), owned: Type.Literal(true),
|
|
61
61
|
members: Type.Array(object({ agentId: id, role: Type.String(), name: Type.String(), state: Type.String() })),
|
|
62
|
-
lastSeq: Type.Integer(), activeCount: Type.Integer({ description: "
|
|
62
|
+
lastSeq: Type.Integer(), activeCount: Type.Integer({ description: "各批次仍在途的请求数;paused 时也可能大于 0。" }),
|
|
63
63
|
unresolved: Type.Array(object({ requestId: id, agentId: id, runId: id, round: Type.Integer(), active: Type.Boolean(),
|
|
64
|
-
state: Type.String({ description: "queued
|
|
65
|
-
description: "
|
|
64
|
+
state: Type.String({ description: "queued=待处理;accepted=在途;uncertain=结果未确认;cancelled=未执行或已取消;unpublished=已完成但结果尚未公开;mixed/interactive=含人工或私人工作,不自动公开;failed/interrupted=失败或中断。" }), cycleId: Type.Optional(id) }), {
|
|
65
|
+
description: "各批次尚未确认完成且公开的请求。先核对原请求和实际结果,再决定后续操作,避免重复执行。",
|
|
66
66
|
}),
|
|
67
67
|
run: Type.Optional(object({ runId: id, instruction: Type.String(), mode, state: Type.Union([Type.Literal("running"), Type.Literal("paused"), Type.Literal("finished")]),
|
|
68
68
|
rounds: Type.Integer(), maxConcurrent: Type.Integer(), deadlineAt: Type.Number(), scheduled: Type.Integer(), published: Type.Integer(), reason: Type.Optional(Type.String()) })) });
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
# dsh 双宿主实施技术方案
|
|
2
|
-
|
|
3
|
-
状态:双宿主实现及本机 SDK、分发、Web 和桌面验证已完成;最新 Linux 全量与成功模型工作流待验收。产品边界见[双宿主方案](dsh-support-proposal.md),最新结果见[验证](validation.md)。
|
|
4
|
-
|
|
5
|
-
## 目标与完成条件
|
|
6
|
-
|
|
7
|
-
在同一个 `personal-bot` npm 包中保留 Pi 入口,增加 dsh 服务端和 Web 客户端入口。两端共用资料、业务规则和历史查询;各自管理原生会话、模型、认证、配置与执行生命周期。dsh 固定使用 `0.2.2-rc.1`,开发和完整验证使用 Linux、Node.js 24.9.0 以上。
|
|
8
|
-
|
|
9
|
-
交付必须覆盖专家、团队、通知、history、共享 Python、资源、文件确认及人工管理。接入验证和部分功能可作为实施里程碑,不能被表述为完整支持。先验证真实接口,再调整共享服务,避免以假定 API 建立大范围改动。
|
|
10
|
-
|
|
11
|
-
## 模块与依赖
|
|
12
|
-
|
|
13
|
-
| 模块 | 实施职责 |
|
|
14
|
-
| --- | --- |
|
|
15
|
-
| `src/pbot.ts` | 保留 Pi 装配及加载方式 |
|
|
16
|
-
| `src/dsh.ts` | dsh Cordis 插件入口,显式声明依赖与配置,装配服务端资源 |
|
|
17
|
-
| `src/integrations/dsh/` | 原生 Agent/Session、持久化、模型、历史、附件及事件转换 |
|
|
18
|
-
| `src/extension/dsh/` | 父会话实例、原生命令、Remote、调度、通知及资源释放 |
|
|
19
|
-
| `src/services/agents/` | 专家准入、归属、代次、请求、周期、团队占用与恢复规则 |
|
|
20
|
-
| `src/services/history/` | 来源隔离、归档查询与摘要提交协调 |
|
|
21
|
-
| `src/tools/{agents,teams,history}/` | 普通数据与 JSON Schema、输入校验、业务处理及分别注册的宿主适配 |
|
|
22
|
-
| `src/ui/dsh/` | Web 管理界面,只保存选择、草稿和订阅;不拥有执行资源 |
|
|
23
|
-
| `src/storage/` | 沿用控制记录与原子写入;原生会话位置由接入层解释 |
|
|
24
|
-
| `scripts/` 与包清单 | 服务端 ESM、客户端单 bundle、bundle patch、可选 peer 与 tarball 验证 |
|
|
25
|
-
|
|
26
|
-
服务不得导入 Cordis、Pi 或 dsh SDK。工具、命令与 Remote 使用同一业务服务。Pi 加载链不能引入 dsh 或浏览器运行时。依赖检查覆盖新增目录及双宿主边界,不新建通用宿主框架。
|
|
27
|
-
|
|
28
|
-
## 专家与异步边界
|
|
29
|
-
|
|
30
|
-
现有 `AgentHost` 的同步创建、恢复校验和报告读取需要支持 dsh 原生异步接口。保留同步的本地状态查询;异步操作在共享服务中显式等待,调用方逐层传播,不把 Promise 放入同步文件锁。
|
|
31
|
-
|
|
32
|
-
创建与恢复分为以下步骤:
|
|
33
|
-
|
|
34
|
-
1. 核对实例、工作区、父会话、兼容线与模型选项。
|
|
35
|
-
2. 在短控制锁内完成同一父会话的 50 个存活/启动中专家限额准入,保存新 generation 和启动状态。
|
|
36
|
-
3. 锁外创建或恢复原生 Agent,在 setup 中安装资源及监听器。恢复时校验原生身份、cwd 和父级,清除旧 native inbox。
|
|
37
|
-
4. 使用 `SessionStore.flush` 等公开持久化屏障确认空会话已落盘。屏障缺失或失败时不能宣布 start 成功。
|
|
38
|
-
5. 再核对 generation、stop 和实例;过期则释放原生句柄。通过后才接纳本 generation 的新要求。
|
|
39
|
-
|
|
40
|
-
Pi 继续保留原始 `session-ref.json`、路径与 leaf。dsh 使用独立的原生 Session 引用及持久位置,不给 Pi 文件字段填入 Session ID。业务层只传递引用,不解析 SDK 事件。
|
|
41
|
-
|
|
42
|
-
从 `extension/subagent-entry.ts` 提取两端实际需要的领取、周期、人工输入归因和中断规则。原生事件转换为请求消费、周期开始、结束原因及固定位置等普通数据。成功判定要求已消费请求、有效轮次结束和非空最终答复;idle 不是成功凭据。
|
|
43
|
-
|
|
44
|
-
stop 先保存停止意图,再取消和释放句柄;释放未完成时保留占用与 stopping 状态。恢复只执行新要求,不自动重放旧 generation 或旧团队批次。只读查看不恢复执行。
|
|
45
|
-
|
|
46
|
-
## 生命周期、团队与通知
|
|
47
|
-
|
|
48
|
-
服务端组件持有进程级 Python 激活;工作区持有共用历史整理器;父 Session 持有专家、团队和调度器;专家持有 AgentHandle。页面只观察这些资源。使用服务端实例信号承接已接受的工作,不能让浏览器断连信号取消已接受任务。
|
|
49
|
-
|
|
50
|
-
团队继续使用现有算法。主会话 send 遵循 `TEAM_BUSY`;专家直接人工输入归为 interactive,混合周期为 mixed,暂停团队且不自动公开混合答复。公共原文注入下一安全边界,普通 post 不开启模型轮次。
|
|
51
|
-
|
|
52
|
-
通知按 agent/cycle 或 team/run/状态去重。模型领取报告与 UI 浏览分开。异步回调核对实例和 generation;父 Session 关闭或执行组件卸载后,旧工具与 Remote 调用失效。
|
|
53
|
-
|
|
54
|
-
## History
|
|
55
|
-
|
|
56
|
-
Pi 只维护 `.pi/pbot/history/`,dsh 只维护 `.dsh/pbot/history/`,两端查询双方归档。来源由归档目录确定,关联键为 host 与 sessionId,不重写旧 Pi 节点。新 dsh 根 ID 使用 `dsh-<uuid>`。
|
|
57
|
-
|
|
58
|
-
`search` 增加可选 host 筛选;结果、导航和 read source 带来源。原有正文、关系分页和 Pi ID 语义保留。dsh 接入仅通过公开 Session query/persistence 读原生日志,不扫描另一宿主的原生记录,也不触发 Pi 旧归档导入。
|
|
59
|
-
|
|
60
|
-
摘要只在本宿主正常交互结束后安排。查询和重连不得调用模型。模型调用在短写锁外;提交前重读归档并核对原文和子节点,丢弃过期结果。dsh 使用原生 LLM 接口,复用当前模型和认证,不写入主聊天。完整工具日志由专家视图读取,不能用问答归档替代。
|
|
61
|
-
|
|
62
|
-
## Web 与安装
|
|
63
|
-
|
|
64
|
-
原生命令提供 `/pbot init`、`status`、`python setup` 及专家、团队、history 入口。Web 模块通过 dsh 原生 Remote 查询和操作同一服务,提供专家完整记录、直接对话、停止/恢复,团队操作与 history 展开。查询路径不得隐式激活 Agent。
|
|
65
|
-
|
|
66
|
-
bundle patch 基于原生 Web profile,声明默认 pbot 组合、服务端插件和客户端依赖。固定版客户端发现只接受包根 Loader 名称,因此 `personal-bot` 包根导出作为 dsh 服务端入口的别名,bundle 使用包根名称加载;`personal-bot/dsh` 独立入口仍保留,Pi 继续显式加载源码入口。客户端遵守固定版本 module loader 格式;外部复用 Cordis、React 和原生 UI。宿主包为可选 peer,开发依赖固定版本,不在发布产物打包第二份 SDK。TypeBox 是共享契约库,声明为范围为 `"*"` 的必需 peer,并在开发依赖中锁定版本。Pi 原生加载器提供 TypeBox;dsh 不提供它,由包管理器在安装时补齐,不能依靠 Pi 的安装间接供应。固定版 dsh 的输出 schema 只支持结构约束和 `oneOf`,因此协作工具保留完整生产端校验,并向宿主提供去除 TypeBox 元数据、采用互斥分支的结构 schema。
|
|
67
|
-
|
|
68
|
-
安装使用原生插件流程。`--from-default-profile` 仅用于首次创建,不作为升级命令。Pi 安装 CLI 不扩展为 dsh 配置管理器。`prepack` 生成 CLI、dsh 服务端和 Web 产物;`dist` 仍只用于测试。
|
|
69
|
-
|
|
70
|
-
## 实施里程碑
|
|
71
|
-
|
|
72
|
-
| 阶段 | 改动与验收 | 当前状态 |
|
|
73
|
-
| --- | --- | --- |
|
|
74
|
-
| A 固定版接入 | 隔离 home、真实插件加载、空 Agent flush/冷恢复、setup 清旧 inbox、只读查询、Remote/客户端加载、Bash 环境继承 | 已通过下列接入验证 |
|
|
75
|
-
| B 公共边界 | 异步 AgentHost、原生引用、运行规则与工具契约提取;Pi 完整回归、既有持久契约保留 | 已通过 Linux 回归 |
|
|
76
|
-
| C dsh 业务 | 专家、团队、通知、资源、文件确认、多会话与 Python 生命周期 | 核心接入和本地验证通过;完整工作流待验收 |
|
|
77
|
-
| D History 与 Web | 来源查询与写隔离、原生历史及摘要、完整人工管理与重连 | 进行中 |
|
|
78
|
-
| E 分发与验收 | tarball 双宿主加载、CLI 独立运行、文档更新、Linux 全量检查和真实 Web 验收 | 本机全量、双宿主 tarball 与 Web 通过;最新 Linux 和真实模型工作流未完成 |
|
|
79
|
-
|
|
80
|
-
阶段 A 在临时目录安装固定发布包,不使用个人认证或工作区配置。使用真实 SDK 和 Session API 构造本地记录,不使用 mock、stub、假模型或模拟 provider。SDK 行为验证与最终插件行为测试分开记录;仅保留能覆盖实际正确性风险的测试。
|
|
81
|
-
|
|
82
|
-
完整检查为 `npm run check`、`npm test`、`git diff --check`、`npm pack --dry-run`。真实模型调用只在已批准环境进行;缺少环境时明确记录相应验收缺口,不能以无模型测试替代。
|
|
83
|
-
|
|
84
|
-
## 接入验证记录
|
|
85
|
-
|
|
86
|
-
- 固定发布包的真实 Cordis、AgentLoop、JSONL persistence 和内存 query:空专家经 flush 后可被独立进程读取;冷恢复保留身份;恢复 setup 清除旧 inbox 后没有开启旧轮次;错误归属或缺失记录不会激活或替换会话。
|
|
87
|
-
- 使用原生 Session API 写入轮次记录,验证报告固定到持久的 `turn/end`,后续对话及 Agent 释放不改变旧报告。
|
|
88
|
-
- 原生 Bash 在 spawn 时读取进程 venv,两个工作区保留各自 cwd,禁用 user site,环境恢复通过。原生命令的两个父会话分别绑定工作区;关闭一个不影响另一个;卸载插件后旧 handler 失效。
|
|
89
|
-
- Linux Node.js 24.15.0 的初始完整检查通过:`npm ci --ignore-scripts`、`npm run check`、`npm test`,103 项测试通过。之后新增的固定报告及工作区生命周期测试已在本地通过;最终 Linux 全量检查仍须重跑。
|
|
90
|
-
- npm tarball 经原生插件命令安装到隔离 `pbot` profile;真实 Chrome 打开 Web,选择临时工作区,展开 `/pbot` 菜单、执行 status 和 init、刷新后再次查询,工作区和父会话身份保持一致,没有 pageerror。客户端需要同时声明 `remote` 与 `remote.commands` 注入。包根发现规则及 Remote 依赖问题已修正。
|
|
91
|
-
- Web 测试中的 Python 目录刻意包含无关数据,原生 setup 如实返回错误且没有覆盖该数据。该测试不证明完整 Python 依赖安装成功;真实计算环境测试由既有 Python 验证及原生 Bash 测试覆盖。
|
|
92
|
-
|
|
93
|
-
这些结果只证明接入与无模型生命周期边界。专家完整工作流、执行中页面断开/组件关闭、团队、history、文件确认与模型结果仍在后续阶段验收。
|
|
94
|
-
|
|
95
|
-
公共边界回归已完成两轮 Linux 全量检查,108 项测试全部通过。`AgentHost` 的创建、校验、报告读取和释放支持异步;启动预约计入限额,恢复校验期间停止不会更换 generation 或写入新输入,关闭等待实际释放。`AgentRun` 统一保存领取、消费、周期与人工输入归因,并封存结果未知的旧领取;Pi 原有文件引用和完成记录格式保留。专家/团队动作处理及公共原文格式化已拆离 Pi 适配。异步扫描发现的会话树事件等待问题已修正,通知恢复与故障升级的原有测试通过。
|
|
96
|
-
|
|
97
|
-
阶段 C 已接入每个父会话的专家与团队服务、原生工具、角色与技能提供方、附件保存和服务端调度。请求先保存领取,再按原生 inbox 进入轮次、`user/message` 消费及持久 `turn/end` 分别记录;原生领取本身不满足成功条件。人工输入在领取时归入对应周期,在消费后才能支持成功判定;等待未来轮次的人工输入不会把此前的答复误标为 mixed。
|
|
98
|
-
|
|
99
|
-
当前实现状态见下列阶段 D 记录。阶段 C 检查点的 `npm run check`、构建、差异检查与 19 项定向测试曾全部通过。新增真实原生工具测试验证原工作区固定、归属拒绝、空专家不启轮次、显式恢复与原模型选项保留、缺失 provider 的真实失败、团队有限批次失败暂停且不发布失败答复。真实 Agent maintenance 中运行原生 Bash,验证关闭一个父会话等待其进程退出且另一父会话继续,组件卸载等待剩余进程退出。未安装模型适配器,没有伪造模型回答。创建专家也先 flush 父会话,冷恢复测试因此使用原生 resume 恢复既有父身份。
|
|
100
|
-
|
|
101
|
-
完成通知复用共同的团队/个人选择和格式规则。dsh 以已提交的 `user/message` 或成功模型工具结果确认领取;PTC 内层 read 还须外层调用成功。原生 inbox 中的排队通知只防止重复提交,不冒充消费。没有正常交互的冷加载和只读查看不会唤醒模型;实际接纳通知或新的人工输入才重新允许自动跟进,失败准入不形成自动重试循环。主会话中断先暂停团队,后台仍核对在途工作;暂停与报告读取故障分别报告。Pi 的三项通知故障与恢复测试通过;测试临时工作目录规范化,避免 macOS 的 `/var` 符号链接造成无效工作区 fixture。
|
|
102
|
-
|
|
103
|
-
原生 `write`、`edit`、`apply_patch` 已接入文件规则。整份 patch 的源与移动目标先检查,执行前重核 cwd 和目标身份;专家工作区外直接拒绝,主会话使用原生一次批准。真实文件测试覆盖内部修改、符号链接外逃、move 和混合补丁拒绝,以及原生 `rejected`/`unavailable` 审计。真实附件服务验证二进制文件跨块保存后原字节可读、图片准入、原路径删除后附件仍可读,以及目录、取消和图片数量上限拒绝。图片总字节与数量在批量载入期间按宿主限额检查。
|
|
104
|
-
|
|
105
|
-
阶段 C 检查点仍缺最新 Linux 回归:服务器 SSH 不可达,本机没有 Docker、Colima、Lima 或 Podman,先前 C1 安装未取得成功退出证据。当时浏览器产物只到阶段 A;后续审批、资源与管理验收结果见下文。
|
|
106
|
-
|
|
107
|
-
阶段 D 的 history 服务和原生工具已接入。两个来源可共同搜索、分别维护;Pi 旧 ID、摘要、关系、分页和旧归档导入继续保留,dsh 不清理或导入 Pi 归档。公开 Session query 读取当前工作区及关联专家,按父级归属纳入不同 cwd 的专家,不把别的工作区专家因 cwd 相同而混入。普通 fork 保留为自身的原生会话;`isSeeded` 是 fork 标记,不是应排除的模板标记。人工 steering、未结束或截断答复保留为原文,工具记录仍由完整原生视图提供。
|
|
108
|
-
|
|
109
|
-
每个工作区共享一个服务端整理器,正常主交互结束后安排,其他父会话尚在交互或有待输入时不启动;新人工输入和下一原生 step 会取消整理。原生 `llm.prepareCall` 与 `stream` 复用当前模型及认证,采用宿主声明的最低 reasoning effort,单独处理纯文本且不写主聊天。摘要和扫描均在短写锁外准备,提交时重读;原文或子节点变化时放弃旧结果,已经保存的摘要优先。失败保留待整理节点并暴露警告,查询不会调用模型。
|
|
110
|
-
|
|
111
|
-
本地类型、依赖检查(121 个模块、497 条依赖)、构建、差异检查和 28 项定向组合已通过,覆盖 AgentRun、Pi 通知、全部 dsh 测试及 history。新增测试使用真实 Session、双来源归档和两个 Node 进程;FIFO 仅承载真实 SDK JSONL,用操作系统读写屏障验证慢扫描不能覆盖另一进程的新索引,没有替代来源或模型。测试还覆盖同一原生 ID 的来源区分、来源损坏隔离、旧 Pi 身份与摘要、冷读不激活、取消查询不取消后续刷新、过期摘要拒绝、实际缺失提供方的失败,以及同工作区关闭一个父会话后继续查询。随后补充未加载索引状态区分,相关 10 项 history/工作区回归及检查、构建和差异检查再次通过。
|
|
112
|
-
|
|
113
|
-
同时收紧了两项原生边界:最终答复需要持久流的 `stop` 标记,工具调用文本和 token 截断不满足成功条件;团队投递使用原生 maintenance 的空闲准入,避免把其公开的 `idle` 状态当作真正空闲。真实 Bash maintenance 验证团队要求在维护结束前没有进入 inbox。外部原生句柄占用也计入存活,恢复被拒绝且 generation 不变;当前组件不能假称已释放别的执行实例。组件卸载会撤销其挂在父会话上的 effect,释放历史缓存。
|
|
114
|
-
|
|
115
|
-
Web 管理已接入固定版公开的 `TypertRemoteService`、`Remote` 和 Typert 注册接口。四个查询描述符由 Host 与 Client 共用,Host 按组件注册,Client 通过原生 `$mount` 挂载;没有私有 HTTP 或额外类型编译框架。读取、轮询和完整原生记录使用查询方法;原生命令会追加 `command/run`/`command/done`,不能拿它反复轮询页面。原生记录按事件分页,正文与完整事件都能继续读取长内容,停止后的专家仍可冷读。人工写操作复用命令、工具的业务动作,命令不重复记录私人输入正文。
|
|
116
|
-
|
|
117
|
-
`/pbot` 的裸调用打开工作区、专家、团队和历史管理页;带参数的原生命令支持 `agent`、`chat`、`team`、`post`、`history`、`records`。页面保存自己的表单与选择,只取消查询,已经接纳的执行归服务端所有。人工对话支持服务器文件及原生输入框已准入附件,先成功暂停所属团队再进入 inbox;人工输入待进入时停止追加团队上下文。原生 registry 的根归属用于识别协调者,不只依靠可选的 origin 标签。改变 provider 或 model 时,不再把父会话的 reasoning effort 带到另一模型。
|
|
118
|
-
|
|
119
|
-
新增真实 SDK 管理测试覆盖只读查询不写主会话、不启动空专家、完整记录分页、停止后冷读、父归属、未标注 origin 的原生子 Agent、组件卸载后的失效、暂停锁失败时不接纳人工消息,以及实际缺失 provider 的失败。该测试没有模拟模型。
|
|
120
|
-
|
|
121
|
-
本机全量回归发现测试环境只隔离 XDG 路径,不符合 macOS Python 按 HOME 定位的规则,并有临时目录 `/var` 别名与 `/private/var` 不一致的问题。已停止首次全量运行;核查个人 Python 环境元数据,未发现首次全量日志创建之后修改的文件或目录条目,没有删除或回滚。此前本机测试不能作为完整 Python 环境隔离的证据。测试现在使用临时 HOME,让真实脚本以 `--check` 确定环境位置,再放入无关数据;真实 Python 仍用于解释器与计算检查。32 项定向回归通过,随后全量为 120/122,余下两项是旧 fixture 固定 Linux 路径和 `/usr/bin/python3` 的假设。修正后相关 E2E/包检查 4 项通过,随后本机完整 `npm run check`、`npm test` 和 `git diff --check` 通过,122/122 项测试成功。该结果不替代 Linux 验收。
|
|
122
|
-
|
|
123
|
-
正常 `prepack` 生成的 tarball 已通过原生插件命令装入新的隔离 Web profile,并使用真实 Chrome 验证四个 Remote 的实际传输。管理页新增本机附件选择:通用文件使用原生 `fileUpload` 的 Session 凭证,图片按原生命令的编码图片契约准入;不发送任意附件引用,也不实现私有上传路由。32 个附件的数量限制与取消由实际输入路径检查。上传期间保留新编辑的草稿,关闭视图取消尚未接纳的上传,已接纳命令继续属于服务端。
|
|
124
|
-
|
|
125
|
-
本轮浏览器验收通过:
|
|
126
|
-
|
|
127
|
-
- 创建无任务专家;轮询保留人工草稿,不发管理写命令。
|
|
128
|
-
- 上传 524,305 字节文件与 1×1 图片,原生专家记录保留相应文件长度、图像引用和完整人工文本;长 JSON 事件可分段重组。
|
|
129
|
-
- 创建两个固定成员的团队,发布 20,000 字符公共消息;翻到后续正文后轮询保留页码与草稿。
|
|
130
|
-
- 真实缺失 provider 使批次暂停,没有伪造提供方或成功模型答复。
|
|
131
|
-
- 停止后的专家可冷读,显式新任务恢复成功接纳;history 可以检索失败交互并读取原文。
|
|
132
|
-
- 页面刷新前后父身份一致,专家保持存活;全流程观察到恰好 9 次管理写命令,查询与轮询未追加写命令;`pageerror` 为空。
|
|
133
|
-
|
|
134
|
-
文件确认也通过实际原生 Web 审批:仅有的一次允许产生 `allowed-once` 并写入测试目录中的目标;等待期间改变符号链接后,即使允许也拒绝执行,两个原文件不变;真实信号取消产生 `cancelled`,目标未创建。验证命令只存在于临时 profile,使用公开 Session API 打开审计轮次并直接执行原生工具,没有生成模型响应。证据位于 `/tmp/pbot-dsh-web-D/upload/`、`/tmp/pbot-dsh-web-D/file-proof/` 和 `/tmp/pbot-dsh-browser/`,临时文件可能被清理。
|
|
135
|
-
|
|
136
|
-
固定版原生默认工作区使用操作系统 Documents 查询,macOS 上不会随测试 HOME 自动改变。测试 profile 已配置 `documentsDirectory`,并通过真实目录选择器选入临时工作区;pbot 的准备、专家、团队及 history 写入验收均在该目录内完成。
|
|
137
|
-
|
|
138
|
-
接入基线的本机检查已通过:`npm run check`、`npm test`、`git diff --check` 退出码 0,122/122 无跳过,测试耗时约 54.1 秒,覆盖附件与资源新增逻辑。依赖边界为 130 个模块、532 条依赖。专家不再显示无法调用的父 history 工具;真实 SDK 验证 noSkills、工具限制、包内技能读取及工作区技能隔离。Web 状态刷新也丢弃过期响应,避免旧查询覆盖新状态。
|
|
139
|
-
|
|
140
|
-
正常 `npm pack --dry-run` 与 prepack 打包通过。实际 tarball 在独立消费者中只安装包自身运行时依赖,没有 Pi/dsh SDK 副本;Node.js 22.19.0 下独立 CLI、Pi 四工具与技能加载、资料初始化、空专家查询通过。固定版 dsh 原生安装最终运行代码后,附件、长记录、团队、history、冷读、恢复与刷新再次通过,观察到 9 次管理写命令,轮询未增加写命令,浏览器错误为空。证据:`/tmp/pbot-dsh-docs/check-E-final.*`、`/tmp/pbot-dsh-final/`。
|
|
141
|
-
|
|
142
|
-
真实 Web 停用插件会移除命令并释放专家,重新启用后保持停止且可冷读;关闭管理页不停止专家。完整浏览器进程关闭后再打开,原父身份与两个专家的存活状态保持。资料准备可重复执行并保留文件。证据:`/tmp/pbot-dsh-web-D/unload-verified.json` 和 `/tmp/pbot-dsh-final/reconnect.json`。
|
|
143
|
-
|
|
144
|
-
本机桌面应用 0.2.2-rc.1(内置 Node.js 24.21.0)也完成实际验收:独立 Electron userData、DSH_HOME、HOME 与 Documents 目录,通过原生插件 UI 安装 tarball、启用并执行完整管理流程。附件、长记录、团队失败暂停、history、恢复与刷新通过,10 次管理写命令且页面错误为空;32 MiB 上传在关闭面板后取消,没有提交 chat 或追加 inbox。完整退出应用会停止专家,重开及插件重新启用均不自动恢复。临时登录 Shell 的 PATH 提供 Python 3.12 后,应用真实安装锁定依赖并达到 ready,pip check 和 5 项原生库测试通过。隔离实例模型选择器显示 `No models available`;原日常应用进程保持运行,测试进程已退出。详见[桌面验收记录](validation.md#macos-桌面应用实测),证据在 `/tmp/pbot-dsh-desktop-test/`。
|
|
145
|
-
|
|
146
|
-
后台模型整理成功、输入优先取消真实模型请求、成功专家/团队协作、模型实际使用资源与团队上下文,以及最新 Linux 全量仍未验收。SSH 最后重试仍超时;无模型检查和旧版 Pi 冒烟不能替代本次真实提供方工作流。
|
|
147
|
-
|
|
148
|
-
## 优先核查的风险
|
|
149
|
-
|
|
150
|
-
| 风险 | 验证与处理 |
|
|
151
|
-
| --- | --- |
|
|
152
|
-
| 空会话延迟落盘 | 真实创建、公开 flush、释放、冷读取与恢复;不插入假消息促使落盘 |
|
|
153
|
-
| 恢复自动消费旧 inbox | 在 setup 中清除旧输入,验证发布前顺序;只接受新 generation |
|
|
154
|
-
| 服务端所有权与页面生命周期耦合 | 两个父会话、断开观察、组件卸载分别验证 |
|
|
155
|
-
| 同进程专家无法强杀 | 验证协作取消及 dispose;阻塞时保持真实状态和占用 |
|
|
156
|
-
| 客户端发布格式或依赖解析不匹配 | 使用真实 tarball 在隔离 Web profile 加载,检查 Remote 与原生 UI |
|
|
157
|
-
| Pi 既有存储被异步改动破坏 | 先完成 Pi 回归,再接入 dsh;原始数据不迁移 |
|
|
158
|
-
| 固定预发布包缺少必要公开能力 | 保存可复现证据与具体影响,报告需重审的决定,不静默改版本或缩减范围 |
|