personal-bot 0.2.6 → 0.2.8
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 +47 -13
- package/README.zh-CN.md +46 -12
- package/docs/README.md +4 -2
- package/docs/agent-collaboration.md +4 -4
- package/docs/capability-design.md +12 -6
- package/docs/dsh-implementation-plan.md +9 -7
- package/docs/dsh-support-proposal.md +6 -22
- package/docs/dsh.en.md +333 -0
- package/docs/dsh.md +346 -48
- package/docs/file-storage.md +1 -1
- package/docs/history.md +2 -0
- package/docs/installation-design.md +7 -4
- package/docs/model-context.md +60 -0
- package/docs/model-instruction-guidelines.md +51 -0
- package/docs/release.md +10 -6
- package/docs/subagent-upgrade-proposal.md +1 -1
- package/docs/technical-design.md +21 -15
- package/docs/validation.md +64 -7
- 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/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 +7 -7
- package/lib/tools/agents/dsh-contract.js +4 -4
- package/lib/tools/history/contract.d.ts +1 -1
- package/lib/tools/history/contract.js +2 -2
- package/lib/tools/teams/contract.d.ts +2 -2
- package/lib/tools/teams/contract.js +11 -11
- package/npm-shrinkwrap.json +30 -25
- package/package.json +28 -25
- package/python/README.md +1 -1
- 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 +1 -1
- 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/resources/prompts/tool-guidelines.md +0 -3
|
@@ -1,97 +1,20 @@
|
|
|
1
1
|
# Python 计算
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
环境上下文的 `python.state` 是当前共享环境状态。ready 时通过 Bash 使用 `python` 或 `python3`,直接导入第三方库。项目构建和测试使用项目声明的环境。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 环境异常
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
未就绪或依赖异常时可自主诊断,只暂停依赖该环境的计算,不退回系统 Python,不删除或重建共享环境。完整准备错误可在 `/pbot status` 查看,修复后用 `/pbot python setup` 重试;需要用户执行会话操作时说明入口,专家向主会话交回所需条件。
|
|
8
8
|
|
|
9
|
-
所有 pbot
|
|
9
|
+
所有 pbot 工作区共用该环境。更改依赖会影响其他工作区,停止相关计算后再更新。安装与许可信息见 [Python 说明](../../python/README.md)。
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## 按项目运行
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
| --- | --- | --- |
|
|
15
|
-
| NumPy | `import numpy as np` | 数组与数值运算 |
|
|
16
|
-
| pandas | `import pandas as pd` | 行情表、时间序列和文件读写 |
|
|
17
|
-
| TA-Lib | `import talib` | 技术指标与形态函数 |
|
|
18
|
-
| backtesting | `from backtesting import Backtest, Strategy` | 策略回测 |
|
|
19
|
-
| SciPy | `from scipy import stats, optimize, signal` | 统计检验、优化、信号处理 |
|
|
20
|
-
| statsmodels | `import statsmodels.api as sm` | 回归、时间序列、统计诊断 |
|
|
21
|
-
| scikit-learn | `import sklearn` | 预处理、预测模型、聚类与评估;导入名为 sklearn |
|
|
22
|
-
| Matplotlib | `import matplotlib.pyplot as plt` | 保存静态图表 |
|
|
23
|
-
| seaborn | `import seaborn as sns` | 基于 Matplotlib 的统计图表 |
|
|
24
|
-
| openpyxl | `import openpyxl` | Excel `.xlsx` 读写;也可用 pandas 的 openpyxl 引擎 |
|
|
25
|
-
| PyArrow | `import pyarrow as pa` | Arrow、Parquet、Feather;也可用 pandas 的 pyarrow 引擎 |
|
|
26
|
-
| Bokeh | `from bokeh.plotting import figure` | 交互式 HTML 图表,backtesting 绘图也使用它 |
|
|
13
|
+
沿用项目的工作目录、脚本或模块入口、输入参数与输出位置。包内相对导入通常使用项目根目录下的 `python -m 包.模块`,不为绕过导入错误随意改 `sys.path`。相对数据路径取决于 cwd 或脚本自身的处理;交付时提供实际产物路径,并检查结果。
|
|
27
14
|
|
|
28
|
-
|
|
15
|
+
预装库包括 NumPy、pandas、SciPy、statsmodels、scikit-learn(导入名 sklearn)、Matplotlib、seaborn、Bokeh、openpyxl、PyArrow、TA-Lib 和 backtesting。按任务查阅当前版本的原生 API。
|
|
29
16
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
cd "/项目根目录" && python scripts/analyze.py --window 20
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
环境中只有 python3 命令时,将示例中的 python 换成 python3。包内相对导入通常使用模块入口,例如在项目根目录执行 `python -m analysis.main --window 20`。普通脚本导入同目录模块与 `-m` 的包导入遵循 Python 原生规则;不要为绕过错误随意改 sys.path。相对数据路径取决于工作目录或脚本自己的路径处理,应先核对约定。临时计算也可使用 `python -c` 或标准输入。
|
|
39
|
-
|
|
40
|
-
按脚本或项目约定提供输入、参数和结果位置,使用实际 Bash 工具的超时与取消能力。
|
|
41
|
-
|
|
42
|
-
Python 具有宿主文件和网络权限,不是沙箱;不得超出本次任务授权执行业务变更或改写历史记录。取消不回滚已发生的副作用。
|
|
43
|
-
|
|
44
|
-
## 绘图与文件
|
|
45
|
-
|
|
46
|
-
在无交互式图形界面的执行环境中使用 Matplotlib/seaborn 时,在导入 pyplot 或 seaborn 前选择 Agg 后端,保存图像并关闭 figure,不调用 `plt.show()`:
|
|
47
|
-
|
|
48
|
-
```python
|
|
49
|
-
import matplotlib
|
|
50
|
-
matplotlib.use("Agg")
|
|
51
|
-
import matplotlib.pyplot as plt
|
|
52
|
-
|
|
53
|
-
fig, ax = plt.subplots()
|
|
54
|
-
ax.plot([1, 2, 3], [10, 12, 11]) # 示例数据,不是行情证据
|
|
55
|
-
fig.savefig("chart.png", dpi=150, bbox_inches="tight")
|
|
56
|
-
plt.close(fig)
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
文件按项目约定保存并交回实际产物路径;相对输出路径基于所选工作目录。Excel 可用 `pd.read_excel(path, engine="openpyxl")` 与 `df.to_excel(path, index=False, engine="openpyxl")`;Parquet 可用 `pd.read_parquet(path, engine="pyarrow")` 与 `df.to_parquet(path, index=False, engine="pyarrow")`。Feather 使用 `pd.read_feather` / `df.to_feather`。检查读写后的字段类型、时间单位与时区;Excel 不直接保存带时区的 datetime,转换前明确目标时区,不默默丢弃时区含义。
|
|
60
|
-
|
|
61
|
-
## TA-Lib 技术指标
|
|
62
|
-
|
|
63
|
-
常用原生函数包括 `SMA`、`EMA`、`MACD`、`RSI`、`BBANDS`、`ATR`、`ADX`、`STOCH`、`OBV` 和 `CDL*` 形态函数。用 `talib.get_function_groups()` 或 `talib.get_functions()` 查找能力,用 `help(talib.函数名)` 核对参数与返回值,不凭名称猜测。
|
|
64
|
-
|
|
65
|
-
以下脚本从第一个命令行参数指定的 JSON 文件读取 close 数组,计算均线并输出严格 JSON:
|
|
66
|
-
|
|
67
|
-
```python
|
|
68
|
-
import json
|
|
69
|
-
import sys
|
|
70
|
-
import numpy as np
|
|
71
|
-
import talib
|
|
72
|
-
|
|
73
|
-
with open(sys.argv[1]) as file:
|
|
74
|
-
data = json.load(file)
|
|
75
|
-
close = np.asarray(data["close"], dtype=np.float64)
|
|
76
|
-
sma = talib.SMA(close, timeperiod=20)
|
|
77
|
-
print(json.dumps({"sma20": [float(x) if np.isfinite(x) else None for x in sma]}, allow_nan=False))
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
使用前核对时间顺序、复权口径、缺失数据、单位和样本长度。多输入函数要求 OHLCV 数组按同一时间轴对齐。backtesting 策略可通过 `self.I(talib.SMA, self.data.Close, 20)` 注册指标。
|
|
81
|
-
|
|
82
|
-
- `talib.MACD` 返回 `(macd, signal, hist)`,`hist = macd - signal`,不乘 2。
|
|
83
|
-
- `talib.BBANDS` 返回 `(upper, middle, lower)`,默认使用 SMA 中轨和两倍总体标准差。
|
|
84
|
-
- 暖机期输出 NaN;例如 SMA(20) 前 19 根、RSI(14) 前 14 根不可用。EMA、RSI 等按 TA-Lib 的种子与平滑规则计算,不等同于直接 pandas ewm。
|
|
85
|
-
- NaN 输入可能影响后续输出,不擅自填零或把暖机值当成信号。持平序列的 RSI 在暖机后为 0,不是 50。
|
|
86
|
-
- 指标可计算不证明策略有效。记录参数、TA-Lib 版本与数据依据;生成严格 JSON 时把非有限值转为 null。
|
|
87
|
-
|
|
88
|
-
## backtesting 原生回测
|
|
89
|
-
|
|
90
|
-
直接使用 `from backtesting import Backtest, Strategy`。继承 Strategy 定义 `init()` 和 `next()`,通过 `Backtest(data, 策略类, ...).run()` 运行。数据使用按时间升序的 OHLC DataFrame,可带 Volume,建议使用 DatetimeIndex;以当前安装版本的 API 为准。
|
|
91
|
-
|
|
92
|
-
- 显式确定资金、手续费、价差、成交时点与仓位假设,不把库默认值当作投资规则。
|
|
93
|
-
- 原生 Backtest 不自动提供 A 股 T+1、整手买入、涨跌停或交易日历约束。研究需要这些规则时,必须明确建模并验证;无法表达时说明限制,不能直接声称结果适用于该市场。
|
|
94
|
-
- 按研究问题决定是否划分样本内/样本外及如何暖机,不默认套用固定回测流程。避免未来数据泄漏。
|
|
95
|
-
- 按交付需要提取统计或交易记录,并说明参数与库版本。导出时处理原生结果中的 Series、DataFrame、时间和非有限值。
|
|
96
|
-
|
|
97
|
-
环境与许可信息见 [Python 说明](../../python/README.md)。
|
|
17
|
+
- 无图形界面的绘图:在导入 pyplot/seaborn 前选择 Matplotlib 的 Agg 后端,保存文件并关闭 figure。
|
|
18
|
+
- Excel、Parquet、Feather:按格式选择 openpyxl 或 pyarrow;核对读写后的字段类型、时间单位与时区。Excel 不直接保存带时区的 datetime,转换前明确目标时区。
|
|
19
|
+
- 统计或建模:记录数据与假设。时间序列按时间切分,预处理只在训练数据拟合,避免未来数据泄漏。
|
|
20
|
+
- 技术指标或回测:再读 [指标与回测](compute-finance.md),按本次问题确定数据口径和交易假设。
|
|
@@ -4,30 +4,35 @@
|
|
|
4
4
|
|
|
5
5
|
## 准备能力
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
通过当前宿主的原生工具发现查找 Task Conductor,读取 `using-task-conductor` 技能,再按实际 MCP schema 操作。工具未直接显示时,先按技能检查连接;技能缺失时检查插件安装和资源启用状态。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
| 宿主 | 插件与技能入口 |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| Pi | `pi list` 查看来源与资源;从工作区根目录用 `pi install --local npm:task-conductor-plugin` 安装已发布接入,或用 `pi install --local /absolute/path/to/task-conductor/plugin` 加载未发布源码。当前会话执行 `/reload`,技能入口为 `/skill:using-task-conductor` |
|
|
12
|
+
| dsh | 用 `dsh plugin --profile pbot list task-conductor-plugin --depth 0` 查看所选 profile;本地 tarball 使用 `dsh plugin --profile pbot add /absolute/path/to/task-conductor-plugin-<version>.tgz` 安装。重启对应宿主后,通过原生 skill 工具读取 `using-task-conductor`,或在聊天框调用 `/using-task-conductor`。桌面应用使用自己的原生插件页 |
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
pi install --local npm:task-conductor-plugin
|
|
13
|
-
```
|
|
14
|
+
将 `pbot` 和示例路径替换为实际 profile 和产物。dsh 接入包含于尚未发布的 Task Conductor `0.1.6` 候选版本;发布前使用该版本的本地插件及配套服务,构建方法见 [dsh 指南](../../docs/dsh.md#task-conductor)或[上游接入说明](https://github.com/realqiyan/task-conductor/blob/master/docs/host-integrations.md)。宿主聊天命令在相应会话中执行,不能通过 Bash 代执行;已发现技能时直接读取其正文继续。
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
dsh 插件随包提供共享技能,并为根主会话创建原生 MCP 连接,工作目录取该会话 cwd。通过实际名称调用工具,如 `mcp__task-conductor__executor_list`、`mcp__task-conductor__task_list`;保留名称中的连字符。复用插件连接,已有手工连接按上游方法调整来源,避免重复注册。dsh 接入不需要 Pi 交互 CLI;服务的协调模型单独配置。
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
服务安装、setup、连接与排障按上游技能处理。dsh 中用 `/task-conductor status` 查看连接状态;服务设置完成或故障修复后用 `/task-conductor connect` 重连。能力不可用时说明具体阻碍,继续不受影响的工作。
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
## 使用 dsh 执行节点
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
通过 Task Conductor 管理员 CLI 或 Web 注册自定义执行端 `dsh-acp`,使用 dsh 的规范绝对可执行路径和 `["--profile", "acp"]` 参数;`dsh` 不是内置执行端 ID。注册与查询步骤见上游技能的 `references/custom-acp.md`。在任务节点的 `executorId` 中选择已就绪的 `dsh-acp`。
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
执行端使用 Task Conductor 后台的运行环境及 dsh 的 `acp` profile,单独准备模型认证、工具、技能和 Python;当前主会话的配置不自动传给节点。
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
## 定义任务
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
提交前写明输入、工作目录、所需工具与模型、输出。周期任务还需明确频率、时区、执行范围及每轮数据来源、期间与时点。
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
准备节点所需的工具、技能、Python 环境和认证。需要人工交互的步骤应留在交互会话中完成。节点直接完成分配的任务,不再递归委派。
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
## 状态与结果
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
任务定义、执行和节点分别用 taskId、runId 和节点 ID 标识。提交响应不明时先按已有 ID 查询;未取得 ID 时,按请求关联、任务列表、提交时间或任务特征查找,避免重复创建。实时状态查询 Task Conductor,项目资料保存任务定义、标识和结果位置。
|
|
35
|
+
|
|
36
|
+
通知回到提交任务的原生持久会话;dsh 恢复原 Session 后可以继续接收待处理事件。同项目的新会话不会代收,仍可通过 MCP 查询任务。
|
|
37
|
+
|
|
38
|
+
取消当前执行与停止未来周期分别操作,并查询确认。pbot_agent stop 或当前宿主关闭不停止 Task Conductor。报告时区分调度已创建和本轮已完成,并给出对应状态与产物位置。
|
|
@@ -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
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
## dsh 构建
|
|
14
14
|
|
|
15
|
-
`npm run build:dsh` 调用 `build-dsh.mjs`,由 tsconfig.dsh.json 编译 Host 与浏览器入口,再用 esbuild 将 Web
|
|
15
|
+
`npm run build:dsh` 调用 `build-dsh.mjs`,由 tsconfig.dsh.json 编译 Host 与浏览器入口,再用 esbuild 将 Web 代码包装为当前开发基线的原生包根 Loader 模块。宿主 SDK 保持 external;完整 build 和 prepack 先构建 CLI、再构建 dsh,统一输出到 lib。
|
|
16
16
|
|
|
17
17
|
## 发布包消费者检查
|
|
18
18
|
|
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 };
|