dsh-agent-board 1.0.0 → 1.0.2
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/index.mjs +36 -9
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -34,7 +34,22 @@ export function apply(ctx) {
|
|
|
34
34
|
|
|
35
35
|
// ===== 工具函数 =====
|
|
36
36
|
function getActorId() { const a = ctx.agents; if (a) { const i = a.currentInitiator(); if (i) return String(i.id) } return 'unknown' }
|
|
37
|
-
|
|
37
|
+
// resolveRoot 是同步热点(每个工具守卫/RPC/prompt 组装都调),agent 注册表可能有几百个子代理,
|
|
38
|
+
// 每次调用 roots()+list()+全表 isOwnedBy 扫描会反复卡宿主事件循环 → memoize 10s TTL。
|
|
39
|
+
// 父子归属在一个 agent 存活期内不变,10s 过期窗口足够安全。
|
|
40
|
+
var _rootCache = {}
|
|
41
|
+
function resolveRootUncached(sid) { const agentsSvc = ctx.agents; if (!agentsSvc) return sid; var cur = sid; var roots = agentsSvc.roots(); var rids = []; for (var i = 0; i < roots.length; i++) rids.push(String(roots[i].id)); if (rids.indexOf(cur) >= 0) return cur; var all = agentsSvc.list(); var visited = {}; while (!visited[cur]) { visited[cur] = true; var o = null; for (var j = 0; j < all.length; j++) { if (agentsSvc.isOwnedBy(cur, all[j])) { o = all[j]; break } }; if (!o) break; cur = String(o.id); if (rids.indexOf(cur) >= 0) return cur }; return cur }
|
|
42
|
+
function resolveRoot(sid) {
|
|
43
|
+
var now = Date.now()
|
|
44
|
+
var c = _rootCache[sid]
|
|
45
|
+
if (c && now - c.at < 10000) return c.root
|
|
46
|
+
var r = resolveRootUncached(sid)
|
|
47
|
+
// 缓存上限:超 512 个 key 时清掉过期项,防长进程累积
|
|
48
|
+
var keys = Object.keys(_rootCache)
|
|
49
|
+
if (keys.length > 512) { for (var i = 0; i < keys.length; i++) { if (now - _rootCache[keys[i]].at >= 10000) delete _rootCache[keys[i]] } }
|
|
50
|
+
_rootCache[sid] = { root: r, at: now }
|
|
51
|
+
return r
|
|
52
|
+
}
|
|
38
53
|
function toolSessionId() { var sid = resolveRoot(getActorId()); touchSession(sid); return sid }
|
|
39
54
|
function rpcSessionId(args) { var sid = (args && typeof args.sessionId === 'string' && args.sessionId.length > 0) ? args.sessionId : resolveRoot(getActorId()); touchSession(sid); return sid }
|
|
40
55
|
// 已知会话集合:心跳驱动这些会话的 poolCycle(摆脱对客户端轮询的依赖)
|
|
@@ -212,8 +227,19 @@ export function apply(ctx) {
|
|
|
212
227
|
// 批量聚合:任务多时每任务一条 followup 会把主窗口 turn 队列打满(用户输入排队等回执处理完才刷新),
|
|
213
228
|
// 改为 45s 窗口(或满 5 条)聚合为一条摘要;发送前等主窗口空闲,不打断对话。
|
|
214
229
|
var receiptBuf = {}
|
|
230
|
+
// 回执幂等去重表:key = 任务id + 类别 + 完成事件指纹(deliverable/verification/resolvedAt/末条history 时间戳)。
|
|
231
|
+
// 同一完成事件被任何路径(工具直报/run 结算/未来回归)重复通知时指纹一致 → 吞掉;
|
|
232
|
+
// 驳回后重做完成 → 时间戳全换新 → 指纹不同 → 正常回执。
|
|
233
|
+
var receiptedKeys = {}
|
|
215
234
|
function notifyTaskDone(sid, t, kind) {
|
|
216
235
|
if (!t || !isDispatched(sid, t.claimedBy)) return
|
|
236
|
+
var lastHist = (t.history && t.history.length) ? String(t.history[t.history.length - 1].timestamp || '') : ''
|
|
237
|
+
var stamp = [kind, (t.deliverable && t.deliverable.at) || '', (t.verification && t.verification.at) || '', t.resolvedAt || '', lastHist].join('|')
|
|
238
|
+
var key = t.id + ':' + stamp
|
|
239
|
+
if (receiptedKeys[key]) return
|
|
240
|
+
var rkeys = Object.keys(receiptedKeys)
|
|
241
|
+
if (rkeys.length > 512) { var rnow = Date.now(); for (var ri = 0; ri < rkeys.length; ri++) { if (rnow - receiptedKeys[rkeys[ri]] > 3600000) delete receiptedKeys[rkeys[ri]] } }
|
|
242
|
+
receiptedKeys[key] = Date.now()
|
|
217
243
|
var buf = receiptBuf[sid] || (receiptBuf[sid] = { items: [], timer: null })
|
|
218
244
|
var lastNote = (t.history && t.history.length) ? String(t.history[t.history.length - 1].note || '') : ''
|
|
219
245
|
buf.items.push({ kind: kind, title: t.title, id: t.id, summary: (t.deliverable && t.deliverable.summary) || '', note: lastNote })
|
|
@@ -313,14 +339,12 @@ export function apply(ctx) {
|
|
|
313
339
|
text: function (assembleCtx) {
|
|
314
340
|
var agent = assembleCtx && assembleCtx.agent
|
|
315
341
|
if (!agent) return ''
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
//
|
|
319
|
-
//
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (!teamModeCache[sid]) return ''
|
|
323
|
-
return '【任务看板 Team 模式已开启】\n本会话的任务看板处于 Team 模式。请遵循以下工作方式:\n1. 涉及代码改动、文件创建、命令执行等实质性工作时,优先用 task_create 提交为看板任务(由一次性 Worker/Verifier 子代理执行与验收),不要自己直接动手实现。\n2. 你仍保有全部工具能力——调研、读代码、讨论方案、回答问题时直接进行,无需提交任务。\n3. 创建任务时,务必在 description 里写清子代理需要的上下文:涉及哪些文件(路径)、相关代码的约束/约定、前置条件等。子代理是全新会话、无你的会话记忆,如果上下文不够,子代理需要从零开始自行调研,效率会大打折扣甚至跑偏方向。\n4. Worker 上报歧义时会通过 task_arbitrate 等待你裁决,请及时响应。驳回重派时同样:新 Worker 没有上一轮的记忆,驳回原因会在 prompt 里,但额外上下文需你在 description 里补上。\n5. 任务尽量一次写清 description/dependsOn/acceptance;需要分步建设的用 task_create draft:true 先建草稿,补全后 publish。'
|
|
342
|
+
// O(1) 快路径:root agent 的 id 就是其会话 id(Agent.id === SessionId),
|
|
343
|
+
// teamModeCache 按会话 id 键——Worker/Verifier 自己的会话 id 不在缓存里,天然不会误注入。
|
|
344
|
+
// 不能走 resolveRoot:该函数在每个 agent 每次 prompt 组装时同步执行,
|
|
345
|
+
// resolveRoot 全表扫 agent 注册表会把宿主事件循环卡死(曾导致全局界面卡顿、用户消息延迟渲染)。
|
|
346
|
+
if (!teamModeCache[String(agent.id)]) return ''
|
|
347
|
+
return '【任务看板 Team 模式已开启】\n本会话的任务看板处于 Team 模式。请遵循以下工作方式:\n1. 涉及代码改动、文件创建、命令执行等实质性工作时,优先用 task_create 提交为看板任务(由一次性 Worker/Verifier 子代理执行与验收),不要自己直接动手实现。\n2. 你仍保有全部工具能力——调研、读代码、讨论方案、回答问题时直接进行,无需提交任务。\n3. 创建任务时,务必在 description 里写清子代理需要的上下文:涉及哪些文件(路径)、相关代码的约束/约定、前置条件等。子代理是全新会话、无你的会话记忆,如果上下文不够,子代理需要从零开始自行调研,效率会大打折扣甚至跑偏方向。\n4. Worker 上报歧义时会通过 task_arbitrate 等待你裁决,请及时响应。驳回重派时同样:新 Worker 没有上一轮的记忆,驳回原因会在 prompt 里,但额外上下文需你在 description 里补上。\n5. 创建多个相互关联的任务时,必须「先草稿后发布」:所有任务先用 task_create draft:true 建为草稿(草稿不会被派发领取),等全部任务创建完成、dependsOn 依赖关系都写好后,再逐个 task_update publish=true 统一发布。严禁直接创建 pending 任务再后补依赖——依赖还没写入,后向任务就会被 Worker 提前领走。'
|
|
324
348
|
},
|
|
325
349
|
})
|
|
326
350
|
ctx.effect(function () { return disposeSection })
|
|
@@ -514,6 +538,9 @@ export function apply(ctx) {
|
|
|
514
538
|
} else if (args.op === 'set-priority') {
|
|
515
539
|
if (['low', 'medium', 'high', 'critical'].indexOf(args.value) < 0) { skipped.push(id); return }
|
|
516
540
|
t.priority = args.value; ah(t, t.status, t.status, actor, '批量设优先级: ' + args.value); done++
|
|
541
|
+
} else if (args.op === 'publish') {
|
|
542
|
+
if (t.status !== 'draft') { skipped.push(id); return }
|
|
543
|
+
t.status = 'pending'; ah(t, 'draft', 'pending', actor, 'batch publish'); done++
|
|
517
544
|
} else { skipped.push(id) }
|
|
518
545
|
})
|
|
519
546
|
return { ok: true, done: done, skipped: skipped }
|
package/package.json
CHANGED