dsbot-session-create 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +156 -2
- package/cordis.patch.yml +4 -0
- package/index.js +1178 -0
- package/package.json +35 -4
package/README.md
CHANGED
|
@@ -1,3 +1,157 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsbot-session-create
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
给 DSH 加四个工具:**`create_session`** —— 在指定的工作区、或任意一个已存在的工作文件夹里开一个新会话,并把一段提示词直接投进去;**`session_message`** —— 给一个已经存在(在跑或已结束)的会话再追加一条消息,排队投递、落在当前这一轮之后;**`read_session_transcript`** —— 按会话 id 把它说过的话和当前状态读回来;**`list_dispatched_sessions`** —— 看这个插件派送过哪些会话、各自此刻什么状态。
|
|
4
|
+
|
|
5
|
+
它是一个 DSH 插件(dsh-plugin),宿主半边,没有界面。
|
|
6
|
+
|
|
7
|
+
## 为什么需要它
|
|
8
|
+
|
|
9
|
+
DS Bot 的 Chief 能把活派给别的 Bot(`message_bot`),但派不到「某个项目的那个会话」里去。
|
|
10
|
+
宿主本身早就有这个能力(`ctx.sessionController.create({ cwd | workspaceId })`),只是没有对外开放成工具。
|
|
11
|
+
|
|
12
|
+
这个插件就是那层薄壳:**把宿主已有的原语开成工具**。
|
|
13
|
+
参考实现是 DS Bot 自己的 `src/host/roster.js`(帮 Bot 建会话时用的同一批调用)。
|
|
14
|
+
|
|
15
|
+
## 工具
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
create_session(title, prompt, workspace? | folder?)
|
|
19
|
+
session_message(sessionId, message)
|
|
20
|
+
read_session_transcript(sessionId?, last?)
|
|
21
|
+
list_dispatched_sessions(limit?)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### `create_session`
|
|
25
|
+
|
|
26
|
+
| 参数 | 必填 | 说明 |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| `title` | 是 | 新会话的名字,显示在会话列表里 |
|
|
29
|
+
| `prompt` | 是 | 投进新会话的那段话(排队投递;它会不会立刻开跑见下面「尚未验证的边界」) |
|
|
30
|
+
| `workspace` | 二选一 | 工作区 id,或它的完整文件夹路径 |
|
|
31
|
+
| `folder` | 二选一 | 任意一个存在的文件夹的完整路径 |
|
|
32
|
+
|
|
33
|
+
`workspace` 和 `folder` **必须给且只能给一个**。
|
|
34
|
+
|
|
35
|
+
两者的区别:
|
|
36
|
+
|
|
37
|
+
- `workspace` —— 会话挂在那个 DSH 工作区下,会出现在用户的对应项目里。
|
|
38
|
+
- `folder` —— 会话按 `cwd` 创建,**不加入任何 DSH 工作区**,用户的项目列表保持原样。
|
|
39
|
+
|
|
40
|
+
两者是同一套宿主原语的两种落位方式,没有别的差别。
|
|
41
|
+
|
|
42
|
+
### 派送台账
|
|
43
|
+
|
|
44
|
+
每次 `create_session` 成功,都会往**派送台账**追加一行,记住这条会话的 id、标题、落位、提示词开头和派送时刻:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
$DSH_HOME/bot/session-create/dispatched-sessions.jsonl # 可用 DSH_SESSION_CREATE_LEDGER 覆盖
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
这是「派出去以后还能找回来」的凭据。台账写失败**不会**让整次派送算失败(会话已经建出来了),但结果里会带一个 `ledgerError`,并把「自己手动记下这个 session id」写进给用户看的文案。
|
|
51
|
+
|
|
52
|
+
落点为什么在 `bot/` 下:这份账是 **Bot ↔ 人的交接记录**,属于 DS Bot 自己的数据,所以跟在 DS Bot 的 home(`<DSH_HOME>/bot`,ds-bot 自己也是这条规则)里,不与它平级另立一处。若 ds-bot 的 home 被它自己的 profile 配置改到别处,用 `DSH_SESSION_CREATE_LEDGER` 对齐。
|
|
53
|
+
|
|
54
|
+
### `session_message`
|
|
55
|
+
|
|
56
|
+
给一个**已经存在**的会话再投一条消息,不新建会话:
|
|
57
|
+
|
|
58
|
+
| 参数 | 必填 | 说明 |
|
|
59
|
+
| --- | --- | --- |
|
|
60
|
+
| `sessionId` | 是 | 目标会话的 id(`create_session` 或 `list_dispatched_sessions` 给的) |
|
|
61
|
+
| `message` | 是 | 追加的那段话 |
|
|
62
|
+
|
|
63
|
+
走的是宿主 `controller.prompt(mode: 'queue')`,所以它是**排队投递**:落在当前正在跑的那一轮之后,不会打断它。会话已经跑完时投进去,等于让它接着再跑一轮。
|
|
64
|
+
|
|
65
|
+
### `read_session_transcript`
|
|
66
|
+
|
|
67
|
+
按 id 取回一个会话说了什么、现在什么状态(最新若干条消息 + 当前这一轮结束没有)。**不给 `sessionId` 就取台账里最近一条派送**,所以「刚派完那单跑完没」不需要手动找 id。
|
|
68
|
+
|
|
69
|
+
`last` 给取回多少条(1..200,默认 40),更早的用更大的值再读。
|
|
70
|
+
|
|
71
|
+
### `list_dispatched_sessions`
|
|
72
|
+
|
|
73
|
+
倒序列出台账里的派送,每条带**此刻**的状态:还在跑 / 上一轮已结束 / 读失败。用来挑「哪些可以收了」。
|
|
74
|
+
|
|
75
|
+
### 状态是怎么来的
|
|
76
|
+
|
|
77
|
+
会话「跑完没有」有两条来源,插件**优先问宿主**,拿不到才从会话自己的事件推:
|
|
78
|
+
|
|
79
|
+
- 宿主直给(`agent.status` 是 `running` / `idle`)→ 输出写 `the harness reports this Session as running`;
|
|
80
|
+
- 事件推断(只有 `turn/start` 没有 `turn/end`)→ 输出写 `read from the Session's own events`。
|
|
81
|
+
|
|
82
|
+
两种来源的措辞**故意不同**:推断不许冒充宿主结论。
|
|
83
|
+
|
|
84
|
+
读回走的是宿主自带的 `ctx.sessionController.page({ address, throughSeq, maxMessages }, signal)`,参数形状逐字照抄 DS Bot 自己的三处生产调用(`src/host/parts.js:1287`、`chat-index.js:58`、`usage.js:351`)——不自己造一套读事件的机制。宿主内置的 `session_event_read` / `session_search` 工具**对普通会话不可用**(返回 `No session matched "…"`),故不走。
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
## 失败时的行为(fail-closed)
|
|
88
|
+
|
|
89
|
+
位置不成立就**什么都不建**,直接报错:
|
|
90
|
+
|
|
91
|
+
| 情况 | 结果 |
|
|
92
|
+
| --- | --- |
|
|
93
|
+
| 文件夹不存在 | 报错,不建会话 |
|
|
94
|
+
| 工作区认不出 | 报错,**不回落**到默认工作区 |
|
|
95
|
+
| 两个都给 / 都不给 | 报错 |
|
|
96
|
+
| 宿主缺所需服务 | 报错,附上缺了哪几个 |
|
|
97
|
+
|
|
98
|
+
那张「宿主缺服务」的报错要能真的报出来,靠的是**服务不写进 `inject` 硬声明**:插件只 `inject: ['tools']`,`sessionController` / `sessionTitle` / `workspaceRegistry` 三个都走 `ctx.get()` 宽容路径(见 `src/core.ts` 的 `resolveServices`)。写成硬 inject 的话,宿主缺服务时整棵插件树会加载失败,`preflight` 那句可读报错根本没有机会执行——用户只会看到「工具不存在」。两个第三方先例(`dsh-better-sidebar`、`dsh-prime-memory`)都只用 `ctx.get` 取这几个服务。
|
|
99
|
+
|
|
100
|
+
这里和 DS Bot 的 `roster.js` 有一处**有意不同**:它会「工作目录没了就悄悄换到团队工作区」,本插件不这么做——悄然换位置会让人以为任务落在 A 项目,实际跑在别处。
|
|
101
|
+
|
|
102
|
+
会话建好但**提示词投递失败**时,会把这个空会话归档掉,并如实报错,不会对外说成功。归档本身也失败时,报错里会改成说「列表里可能还留着一条空会话」——不谎称已归档。
|
|
103
|
+
|
|
104
|
+
## 装
|
|
105
|
+
|
|
106
|
+
本机(DSH 0.2.1-rc.3)以链路方式装进 profile:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
# 在 profile 目录里(<DSH_HOME>/profiles/<profile>)
|
|
110
|
+
# 把 "dsbot-session-create": "link:<本插件目录的绝对路径>" 加进 package.json 的 dependencies
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
或直接把本目录复制进 `node_modules/`。装完 **必须重启 DSH**(重启只能由用户执行)。
|
|
114
|
+
|
|
115
|
+
`cordis.patch.yml` 负责把它挂上:
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
- insert:
|
|
119
|
+
- id: session-create
|
|
120
|
+
name: dsbot-session-create
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## 开发
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
bun run build # src/*.ts → index.js(@deepseek-ai/dsh-tools 保持 external)
|
|
127
|
+
bun test # 69 个测试;plugin.test.ts 测的是构建产物,跑前先 build
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
类型检查(本机没装 tsc,借用现成的):
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
node <任意本机已有的 typescript>/bin/tsc --noEmit -p .
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## 几个必须知道的事实
|
|
137
|
+
|
|
138
|
+
- **`@deepseek-ai/dsh-tools` 不在 profile 的 `node_modules` 里**(在宿主 `app.asar` 内,加载插件时注入;`node_modules/@deepseek-ai/**/package.json` 在本 profile 是 0 命中)。所以 `test/stubs/dsh-tools.ts` 是它的替身,`tsconfig.json` 的 `paths` 只为本机开发把它指过去 —— 那**不是**权威类型定义,是按 DS Bot 的实际用法反推的最小形状。
|
|
139
|
+
- 宿主 API 的形状(`create` 返回 `{ sessionId }`、`prompt` 要 `requestId` + `mode: 'queue'` + `content:[{type:'text',text}]`)是从 DS Bot 的 `src/host/roster.js`、`channel.js` **读出来**的,不是从官方文档抄的。上游没有这层文档。
|
|
140
|
+
- **已在真实宿主里加载过**:2026-10-30 00:36 重启后,四个工具在一个活会话里都出现了(描述逐字来自本插件的 `index.js`),不是只有「假 ctx + 构建产物」的验证。
|
|
141
|
+
- 作者的开发沙箱当时只允许在插件目录下写(系统临时目录与工作区的 `tmp/` 都是 EPERM),所以测试的临时目录放在 `.tmp/`。
|
|
142
|
+
|
|
143
|
+
## 尚未验证的边界
|
|
144
|
+
|
|
145
|
+
以下五条**没验过**,写在这里以免被当成已知:
|
|
146
|
+
|
|
147
|
+
1. **真宿主里读回的形状**:`ctx.sessionController.page` 在真实宿主上是否真按 `{ records, hasMore }` 返回,未验(参数形状抄的是 DS Bot 生产代码,不是官方文档)。装上 + 重启后第一件要验的就是它。
|
|
148
|
+
2. **`mode: 'queue'` 投给一个刚建出来的空会话**是否被宿主接受,未验。
|
|
149
|
+
3. **提示词会不会立刻开跑**:投递只是排队,宿主何时起跑未验;因此对外文案只说「已排队」,不说「它正在干」。
|
|
150
|
+
4. **提示词的 30 秒超时上限**:这条路径没有「真触发」用例——测试运行器 bun 1.3.13 的 `AbortSignal.timeout` 在进程没有其它待办定时器时不触发(宿主是 Node,不受影响)。
|
|
151
|
+
5. **`last` 夹到 1..200、`limit` 夹到 1..20** 是本插件自定的范围,宿主有没有更低的天花板未验。
|
|
152
|
+
|
|
153
|
+
「跑完自动把结果推给派活人」这条**已经实现**:派送时把回执地址记进台账,目标会话安静满 120 秒、且宿主复核为 idle 时,插件用 `controller.prompt(mode: 'queue')` 投一条短回执回去(`src/index.ts:282` 的 `installDispatchNotify`,源码注释见 `:280`)。**但它在真机上还没验过**——上面第 1 条的读回形状没验,这条通知就谈不上可信。现在也仍然可以一条命令取回,取回是稳的。
|
|
154
|
+
|
|
155
|
+
## 许可
|
|
156
|
+
|
|
157
|
+
MIT
|
package/cordis.patch.yml
ADDED