dsh-retrace 0.4.7 → 0.4.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/lib/dynamic-host.js +30 -9
- package/lib/host-core.js +30 -9
- package/package.json +1 -1
package/lib/dynamic-host.js
CHANGED
|
@@ -187,13 +187,34 @@ return {
|
|
|
187
187
|
return session
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
190
|
+
/**
|
|
191
|
+
* 确保 agent 空闲(2026-08-30 事故闭环,用户方案落地):agent 正在响应时,
|
|
192
|
+
* **不拒绝**——自动请求停止(`agent.cancel`)并等待其干净收尾(`whenIdle`)。
|
|
193
|
+
*
|
|
194
|
+
* 为什么必须等停止:编辑/重发发生在 agent 还开着 step 时,DSH 的 resend 机制
|
|
195
|
+
* 会把旧 step 的 assistant/chunk 全部引用进新 assistant/message 的
|
|
196
|
+
* `sourceEventSeqs`(526f1835 seq 936047:引用跨 turn 54 的 step 7/8/9),
|
|
197
|
+
* token-meter 对跨 step 引用抛 `belongs to another step`(dsh-token-meter
|
|
198
|
+
* lib/index.js:645)→ 同样刷屏压垮 host。先停止 → step 干净关闭 → 编辑在
|
|
199
|
+
* 轮次边界执行,不再触发跨 step 引用。
|
|
200
|
+
*
|
|
201
|
+
* agent 无 cancel/whenIdle(headless/测试桩)时回退为抛 agent-busy(原行为)。
|
|
202
|
+
*/
|
|
203
|
+
async function ensureIdle(agent) {
|
|
204
|
+
if (!agent || typeof agent.status !== 'string' || agent.status !== 'running') return
|
|
205
|
+
if (typeof agent.cancel === 'function' && typeof agent.whenIdle === 'function') {
|
|
206
|
+
try {
|
|
207
|
+
agent.cancel({ kind: 'plugin-retrace-edit' })
|
|
208
|
+
await agent.whenIdle()
|
|
209
|
+
return
|
|
210
|
+
} catch (error) {
|
|
211
|
+
throw editorError('agent-stop-failed', `Failed to stop the running reply before editing: ${String(error)}`)
|
|
212
|
+
}
|
|
196
213
|
}
|
|
214
|
+
throw editorError(
|
|
215
|
+
'agent-busy',
|
|
216
|
+
'The agent is still responding. Stop the current reply before recalling or editing.',
|
|
217
|
+
)
|
|
197
218
|
}
|
|
198
219
|
|
|
199
220
|
/** Locate the durable seq of a user/assistant message by its stable message id. */
|
|
@@ -328,7 +349,7 @@ return {
|
|
|
328
349
|
const sessionId = String(args?.sessionId ?? '')
|
|
329
350
|
const messageId = String(args?.messageId ?? '')
|
|
330
351
|
const session = requireSession(sessionId)
|
|
331
|
-
|
|
352
|
+
await ensureIdle(agents.get(sessionId))
|
|
332
353
|
const seq = findMessageSeq(session, messageId)
|
|
333
354
|
if (seq === -1) throw editorError('message-not-found', 'Message not found in this session.')
|
|
334
355
|
const span = roundSpanFrom(session, seq)
|
|
@@ -358,7 +379,7 @@ return {
|
|
|
358
379
|
const fromScratch = args?.fromScratch === true
|
|
359
380
|
const session = requireSession(sessionId)
|
|
360
381
|
const agent = agents.get(sessionId)
|
|
361
|
-
|
|
382
|
+
await ensureIdle(agent)
|
|
362
383
|
const seq = findMessageSeq(session, messageId)
|
|
363
384
|
if (seq === -1) throw editorError('message-not-found', 'Message not found in this session.')
|
|
364
385
|
const event = session.events[seq]
|
|
@@ -399,7 +420,7 @@ return {
|
|
|
399
420
|
const messageId = String(args?.messageId ?? '')
|
|
400
421
|
const session = requireSession(sessionId)
|
|
401
422
|
const agent = agents.get(sessionId)
|
|
402
|
-
|
|
423
|
+
await ensureIdle(agent)
|
|
403
424
|
const seq = findMessageSeq(session, messageId)
|
|
404
425
|
if (seq === -1) throw editorError('message-not-found', 'Message not found in this session.')
|
|
405
426
|
const event = session.events[seq]
|
package/lib/host-core.js
CHANGED
|
@@ -178,13 +178,34 @@ export function createEditorApi(ctx, sessions, agents, log = () => {}, hooks = {
|
|
|
178
178
|
return session
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
181
|
+
/**
|
|
182
|
+
* 确保 agent 空闲(2026-08-30 事故闭环,用户方案落地):agent 正在响应时,
|
|
183
|
+
* **不拒绝**——自动请求停止(`agent.cancel`)并等待其干净收尾(`whenIdle`)。
|
|
184
|
+
*
|
|
185
|
+
* 为什么必须等停止:编辑/重发发生在 agent 还开着 step 时,DSH 的 resend 机制
|
|
186
|
+
* 会把旧 step 的 assistant/chunk 全部引用进新 assistant/message 的
|
|
187
|
+
* `sourceEventSeqs`(526f1835 seq 936047:引用跨 turn 54 的 step 7/8/9),
|
|
188
|
+
* token-meter 对跨 step 引用抛 `belongs to another step`(dsh-token-meter
|
|
189
|
+
* lib/index.js:645)→ 同样刷屏压垮 host。先停止 → step 干净关闭 → 编辑在
|
|
190
|
+
* 轮次边界执行,不再触发跨 step 引用。
|
|
191
|
+
*
|
|
192
|
+
* agent 无 cancel/whenIdle(headless/测试桩)时回退为抛 agent-busy(原行为)。
|
|
193
|
+
*/
|
|
194
|
+
async function ensureIdle(agent) {
|
|
195
|
+
if (!agent || typeof agent.status !== 'string' || agent.status !== 'running') return
|
|
196
|
+
if (typeof agent.cancel === 'function' && typeof agent.whenIdle === 'function') {
|
|
197
|
+
try {
|
|
198
|
+
agent.cancel({ kind: 'plugin-retrace-edit' })
|
|
199
|
+
await agent.whenIdle()
|
|
200
|
+
return
|
|
201
|
+
} catch (error) {
|
|
202
|
+
throw editorError('agent-stop-failed', `Failed to stop the running reply before editing: ${String(error)}`)
|
|
203
|
+
}
|
|
187
204
|
}
|
|
205
|
+
throw editorError(
|
|
206
|
+
'agent-busy',
|
|
207
|
+
'The agent is still responding. Stop the current reply before recalling or editing.',
|
|
208
|
+
)
|
|
188
209
|
}
|
|
189
210
|
|
|
190
211
|
/** Locate the durable seq of a user/assistant message by its stable message id. */
|
|
@@ -319,7 +340,7 @@ export function createEditorApi(ctx, sessions, agents, log = () => {}, hooks = {
|
|
|
319
340
|
const sessionId = String(args?.sessionId ?? '')
|
|
320
341
|
const messageId = String(args?.messageId ?? '')
|
|
321
342
|
const session = requireSession(sessionId)
|
|
322
|
-
|
|
343
|
+
await ensureIdle(agents.get(sessionId))
|
|
323
344
|
const seq = findMessageSeq(session, messageId)
|
|
324
345
|
if (seq === -1) throw editorError('message-not-found', 'Message not found in this session.')
|
|
325
346
|
const span = roundSpanFrom(session, seq)
|
|
@@ -349,7 +370,7 @@ export function createEditorApi(ctx, sessions, agents, log = () => {}, hooks = {
|
|
|
349
370
|
const fromScratch = args?.fromScratch === true
|
|
350
371
|
const session = requireSession(sessionId)
|
|
351
372
|
const agent = agents.get(sessionId)
|
|
352
|
-
|
|
373
|
+
await ensureIdle(agent)
|
|
353
374
|
const seq = findMessageSeq(session, messageId)
|
|
354
375
|
if (seq === -1) throw editorError('message-not-found', 'Message not found in this session.')
|
|
355
376
|
const event = session.events[seq]
|
|
@@ -390,7 +411,7 @@ export function createEditorApi(ctx, sessions, agents, log = () => {}, hooks = {
|
|
|
390
411
|
const messageId = String(args?.messageId ?? '')
|
|
391
412
|
const session = requireSession(sessionId)
|
|
392
413
|
const agent = agents.get(sessionId)
|
|
393
|
-
|
|
414
|
+
await ensureIdle(agent)
|
|
394
415
|
const seq = findMessageSeq(session, messageId)
|
|
395
416
|
if (seq === -1) throw editorError('message-not-found', 'Message not found in this session.')
|
|
396
417
|
const event = session.events[seq]
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-retrace",
|
|
3
3
|
"description": "Retrace · 回溯 — Recall, edit-and-resend, regenerate, and conversation/artifact versioning (timeline, rollback, fork map) for DeepSeek Harness — Web and Desktop",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.8",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|