dsh-tree-task-flow 0.3.11 → 0.3.12
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/lib/auto-continue.js +4 -2
- package/lib/compaction.js +24 -8
- package/lib/pause.js +2 -4
- package/lib/region.js +54 -8
- package/package.json +1 -1
package/lib/auto-continue.js
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { activePath, renderContinue } from "./plan.js";
|
|
19
|
+
import { pluginSource } from "./region.js";
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* 注册续行兜底。
|
|
@@ -57,7 +58,8 @@ export function registerAutoContinue(ctx, { store, cfg }) {
|
|
|
57
58
|
// 必须按来源区分,不能按"这一步有没有消息":`agent.followup()` 推的消息同样会
|
|
58
59
|
// 从 inbox 进入下一步的 `payload.messages`,那样每一轮都会把自己刚用掉的配额
|
|
59
60
|
// 重置回去,`maxAutoRounds` 也就失去了意义。
|
|
60
|
-
// `source.kind === 'user'` 才是真人,插件推的是 `
|
|
61
|
+
// `source.kind === 'user'` 才是真人,插件推的是 `plugin:dsh-tree-task-flow`
|
|
62
|
+
// (v3 老会话里是 `{ kind: 'plugin', plugin: 'dsh-tree-task-flow' }`;两种都不是 `'user'`)。
|
|
61
63
|
//
|
|
62
64
|
// 注意这是 waterfall:必须 await next() 并把它返回,否则会截断监听器链。
|
|
63
65
|
ctx.on("agent/pre-step", async (payload, next) => {
|
|
@@ -106,7 +108,7 @@ export function registerAutoContinue(ctx, { store, cfg }) {
|
|
|
106
108
|
id: `tt-continue-${sessionId}-${Date.now().toString(36)}`,
|
|
107
109
|
role: "user",
|
|
108
110
|
content: [{ type: "text", text: renderContinue(plan) }],
|
|
109
|
-
source:
|
|
111
|
+
source: pluginSource("计划续行"),
|
|
110
112
|
});
|
|
111
113
|
ctx.logger?.info?.(
|
|
112
114
|
`dsh-tree-task-flow: 自动续行 ${used + 1}/${cfg.maxAutoRounds}(步骤 ${active.step.id})`,
|
package/lib/compaction.js
CHANGED
|
@@ -10,8 +10,15 @@
|
|
|
10
10
|
* 又明确要求"不要提及这次压缩",模型不会自己想到去查。
|
|
11
11
|
*
|
|
12
12
|
* 怎么认:压缩留下的表层节点是一条 `user/message`,它的 `source` 由
|
|
13
|
-
* `compactCheckpointSource()`
|
|
14
|
-
*
|
|
13
|
+
* `compactCheckpointSource()` 构造。**两个形状都要认**:
|
|
14
|
+
*
|
|
15
|
+
* - v4 原生:`{ kind: "compact-checkpoint", compactionId, … }`
|
|
16
|
+
* (`COMPACT_CHECKPOINT_MARKER` 就是 `{ kind: "compact-checkpoint" }`);
|
|
17
|
+
* - v3 老写法:`{ kind: "plugin", plugin: "compact" }`——它只在 v3 → v4 迁移里
|
|
18
|
+
* 被改写成前者,迁移前的会话里仍是这个样子。
|
|
19
|
+
*
|
|
20
|
+
* 只认老写法,会让**已经迁到 v4 的会话彻底收不到压缩提示**(实测:本机
|
|
21
|
+
* session-2083c383 在 v4 里连续压缩两次,一条提示都没有)。
|
|
15
22
|
*
|
|
16
23
|
* **不要认 `compaction/summary` 事件**:那是压缩自己的记录,不带 `surfaceOp`,
|
|
17
24
|
* 因此根本不在表层里;真正替代被收走那段的是紧随其后那条带
|
|
@@ -35,14 +42,21 @@
|
|
|
35
42
|
import { summaryMessage } from "./region.js";
|
|
36
43
|
|
|
37
44
|
/**
|
|
38
|
-
*
|
|
45
|
+
* 压缩检查点的插件标记——**只有** v3 老写法用到它。
|
|
39
46
|
*
|
|
40
|
-
* 与 `@deepseek-ai/dsh-compaction` 的
|
|
41
|
-
*
|
|
42
|
-
* 就把一个 DSH 内部包写进自己的依赖里。
|
|
47
|
+
* 与 `@deepseek-ai/dsh-compaction` 的 V3 侧字面量保持一致。这里按形状判断而不是
|
|
48
|
+
* import 那个包:插件不该为了认一个标记,就把一个 DSH 内部包写进自己的依赖里。
|
|
43
49
|
*/
|
|
44
50
|
const COMPACTION_PLUGIN = "compact";
|
|
45
51
|
|
|
52
|
+
/**
|
|
53
|
+
* v4 原生压缩检查点的 source kind。
|
|
54
|
+
*
|
|
55
|
+
* 与 `@deepseek-ai/dsh-compaction` 的 `COMPACT_CHECKPOINT_MARKER` 一致
|
|
56
|
+
* (`{ kind: "compact-checkpoint" }`)。
|
|
57
|
+
*/
|
|
58
|
+
const COMPACTION_KIND = "compact-checkpoint";
|
|
59
|
+
|
|
46
60
|
/**
|
|
47
61
|
* 提示正文。
|
|
48
62
|
*
|
|
@@ -64,11 +78,13 @@ function noticeId() {
|
|
|
64
78
|
return `tt-compaction-${Date.now().toString(36)}-${noticeSeq.toString(36)}`;
|
|
65
79
|
}
|
|
66
80
|
|
|
67
|
-
/**
|
|
81
|
+
/** 这条表层节点是不是压缩落下的检查点(v4 新写法与 v3 老写法都认)。 */
|
|
68
82
|
function isCompactionCheckpoint(event) {
|
|
69
83
|
if (event?.type !== "user/message") return false;
|
|
70
84
|
const source = event.data?.source;
|
|
71
|
-
|
|
85
|
+
if (source === undefined || source === null) return false;
|
|
86
|
+
if (source.kind === COMPACTION_KIND) return true;
|
|
87
|
+
return source.kind === "plugin" && source.plugin === COMPACTION_PLUGIN;
|
|
72
88
|
}
|
|
73
89
|
|
|
74
90
|
/**
|
package/lib/pause.js
CHANGED
|
@@ -39,9 +39,7 @@
|
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
41
|
import { activePath, renderContinue } from "./plan.js";
|
|
42
|
-
|
|
43
|
-
/** 本插件放下的消息都带这个身份。 */
|
|
44
|
-
const PLUGIN = "dsh-tree-task-flow";
|
|
42
|
+
import { pluginSource } from "./region.js";
|
|
45
43
|
|
|
46
44
|
/**
|
|
47
45
|
* 注册暂停闸门。
|
|
@@ -152,7 +150,7 @@ export function registerPause(ctx, { store = null, autoContinue = null } = {}) {
|
|
|
152
150
|
id: `tt-resume-${sessionId}-${Date.now().toString(36)}`,
|
|
153
151
|
role: "user",
|
|
154
152
|
content: [{ type: "text", text: renderContinue(plan) }],
|
|
155
|
-
source:
|
|
153
|
+
source: pluginSource("恢复续行"),
|
|
156
154
|
});
|
|
157
155
|
} catch (error) {
|
|
158
156
|
return {
|
package/lib/region.js
CHANGED
|
@@ -42,7 +42,55 @@
|
|
|
42
42
|
import { activePath } from "./plan.js";
|
|
43
43
|
|
|
44
44
|
/** 本插件放下的消息都带这个身份。 */
|
|
45
|
-
const PLUGIN = "dsh-tree-task-flow";
|
|
45
|
+
export const PLUGIN = "dsh-tree-task-flow";
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 本插件消息的 source kind。
|
|
49
|
+
*
|
|
50
|
+
* DSH 的会话格式 v4 要求消息来源带**生产者自有的** kind:老写法
|
|
51
|
+
* `{ kind: "plugin", plugin: "包名" }` 只在 v3 → v4 迁移那一刻被改写成
|
|
52
|
+
* `plugin:<包名>`(第三方插件一律加前缀,见 `dsh-session-format-v3-to-v4`
|
|
53
|
+
* 的转换表)。**已经是 v4 的会话不再经过迁移**,写入时直接按 v4 校验,
|
|
54
|
+
* 于是老写法被拒:
|
|
55
|
+
*
|
|
56
|
+
* format v4 message requires a producer-owned source kind
|
|
57
|
+
*
|
|
58
|
+
* 这条错误来自 DSH 自己的编码路径(`releasedV4SessionFormatCodec.encodeEvent`
|
|
59
|
+
* → `assertV4RowAdmission` → `assertV4SourceRowAdmission`),位置在会话落盘那一段,
|
|
60
|
+
* 插件自己的 try/catch 拦不住。所以从这里起**直接写迁移后的那个 kind**——
|
|
61
|
+
* 它在 v4 里合法,在 v3 里是"非空且非 plugin 的直接来源",原样保留、同样合法。
|
|
62
|
+
*/
|
|
63
|
+
export const PLUGIN_SOURCE_KIND = `plugin:${PLUGIN}`;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 本插件一条 notice 消息的 source。
|
|
67
|
+
*
|
|
68
|
+
* 字段与老写法保持一致:`form: "notice"` 让界面渲染成可展开的一行说明,
|
|
69
|
+
* `summary` 是那一行的文字。
|
|
70
|
+
*
|
|
71
|
+
* @param summary - 界面上显示的一行摘要。
|
|
72
|
+
* @returns 消息 source。
|
|
73
|
+
*/
|
|
74
|
+
export function pluginSource(summary) {
|
|
75
|
+
return { kind: PLUGIN_SOURCE_KIND, form: "notice", summary };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 这条 source 是不是本插件留下的。
|
|
80
|
+
*
|
|
81
|
+
* **两种写法都认**:v4 起写 `plugin:dsh-tree-task-flow`,而旧版留在 v3 会话里、
|
|
82
|
+
* 或压缩折叠区间里带着的老消息仍是 `{ kind: "plugin", plugin: "dsh-tree-task-flow" }`。
|
|
83
|
+
* 只认新写法会让老会话里的历史通告被当成普通过程,只认老写法会让新会话里的通告
|
|
84
|
+
* 被反复折叠。
|
|
85
|
+
*
|
|
86
|
+
* @param source - 消息的 source。
|
|
87
|
+
* @returns 是否本插件所留。
|
|
88
|
+
*/
|
|
89
|
+
export function isPluginSource(source) {
|
|
90
|
+
if (source === undefined || source === null) return false;
|
|
91
|
+
if (source.kind === PLUGIN_SOURCE_KIND) return true;
|
|
92
|
+
return source.kind === "plugin" && source.plugin === PLUGIN;
|
|
93
|
+
}
|
|
46
94
|
|
|
47
95
|
/** 三层固定的名字。只给界面用的游标同步按这个顺序走。 */
|
|
48
96
|
const LEVELS = ["goal", "task", "step"];
|
|
@@ -100,7 +148,7 @@ function isHumanMessage(event) {
|
|
|
100
148
|
|
|
101
149
|
/** 这条消息是不是本插件自己落下的折叠通告。 */
|
|
102
150
|
function isPluginNotice(event) {
|
|
103
|
-
return event?.type === "user/message" && event.data?.source
|
|
151
|
+
return event?.type === "user/message" && isPluginSource(event.data?.source);
|
|
104
152
|
}
|
|
105
153
|
|
|
106
154
|
/** 从一次工具调用的参数里取它指向的文件路径;不是文件类调用就返回 null。 */
|
|
@@ -149,18 +197,16 @@ export function touchedFiles(session, shadowed) {
|
|
|
149
197
|
* 形态是 `notice` + `summary`:界面把它渲染成一行可读的说明,展开才是正文。
|
|
150
198
|
* 刻意**不用** `snapshot`——那个形态是"运行时上下文快照"的专属标签,
|
|
151
199
|
* 借用它会让任务汇总在界面上冒充系统提示词/运行环境快照。
|
|
200
|
+
*
|
|
201
|
+
* source 走 {@link pluginSource}:**必须是生产者自有的 kind**,否则 v4 会话
|
|
202
|
+
* 会拒绝这条消息(见 `PLUGIN_SOURCE_KIND` 的说明)。
|
|
152
203
|
*/
|
|
153
204
|
export function summaryMessage(id, text, summary) {
|
|
154
205
|
return {
|
|
155
206
|
id,
|
|
156
207
|
role: "user",
|
|
157
208
|
content: [{ type: "text", text }],
|
|
158
|
-
source:
|
|
159
|
-
kind: "plugin",
|
|
160
|
-
plugin: PLUGIN,
|
|
161
|
-
form: "notice",
|
|
162
|
-
summary,
|
|
163
|
-
},
|
|
209
|
+
source: pluginSource(summary),
|
|
164
210
|
};
|
|
165
211
|
}
|
|
166
212
|
|