agentworkshop 0.7.33 → 0.7.34

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.
@@ -688,14 +688,11 @@ async function doReload(host) {
688
688
  }
689
689
  }
690
690
  const prevNames = [...host.plugins.keys()]
691
- // 卸载即注销其注册的全部 agent 工具(否则停用插件后工具仍残留在注册表、可被继续调用)
691
+ // 工具注销延后:先装载新集、后清「本轮未再装载」的旧插件工具。
692
+ // 原先在装载前就全部注销 → 重载窗口内(秒级~数十秒)所有插件工具"未知工具",
693
+ // 期间到达的 Agent 工具调用(daq:sample 自动诊断/kb_store 等)被误拒
694
+ // (实测生产闭环 Stage D 撞窗失败)。同名工具装载时按"后注册者胜"覆盖,无残留。
692
695
  const ompTools = await import('@/server/services/workshop/agents/plugin-tools').catch(() => null)
693
- for (const prev of prevNames) {
694
- try {
695
- ompTools?.unregisterPluginTools(prev)
696
- }
697
- catch { /* 注销失败不阻断重载 */ }
698
- }
699
696
  host.plugins.clear()
700
697
  host.routes = createRouteTable()
701
698
  host.failures = []
@@ -197,6 +197,11 @@ export class AgentRuntime {
197
197
  this.role = agent.role
198
198
  this.channelId = agent.channelId
199
199
  this.name = agent.name
200
+ // 工作区即时可用:impl 的 workspace 原本在首个 run() 才注入,此前 REST 直调
201
+ // host 工具(agent-tools/invoke)会拿到 null →「workspace 未就绪」。
202
+ // 装配期即绑定(与 run() 注入的是同一对象,语义等价)。
203
+ const attach = (this.impl as { attachWorkspace?: (ws: AgentWorkspace) => void }).attachWorkspace
204
+ if (typeof attach === 'function') attach.call(this.impl, deps.workspace)
200
205
  }
201
206
 
202
207
  /** 投递消息;idle 时立即唤醒消费 */
@@ -582,6 +587,13 @@ export class AgentRuntime {
582
587
  // LLM 流式增量:只走事件流(AEP agent.delta),不进任务引擎/交付兜底管道
583
588
  if (event.kind === 'delta') continue
584
589
  if (event.kind === 'error') sawRunError = true
590
+ // 无原生工具面的 harness(codex/dsh 等)以 shell/文本方式作业:回合 error 收束
591
+ // 但已有实质输出时,不落入 FAILED(交由回合结束后的交付兜底按最终输出隐式收口)——
592
+ // 否则「工作已做完、流断在收尾」的任务全部 FAILED→重试→CANCELED(实测 dsh)。
593
+ if (event.kind === 'error' && taskId && replyText.trim().length >= 40) {
594
+ const cur = this.deps.taskEngine.get(taskId)
595
+ if (cur && cur.state === 'WORKING') continue
596
+ }
585
597
  if (taskId) await this.deps.taskEngine.applyEvent(taskId, event)
586
598
  if (event.kind === 'message') cap(partsToText(event.message.parts))
587
599
  else if (event.kind === 'status' && event.status.message) cap(partsToText(event.status.message.parts))
@@ -618,13 +630,30 @@ export class AgentRuntime {
618
630
  // 交付兜底(harness 回合结束 ≠ 任务完成):
619
631
  // - 回合产出过实质 artifact(LLM 完成了工作但跳过 complete_task 工具)→ 隐式完成,
620
632
  // 交付物即回合规避的输出,平台代为收口(进度 100)。
621
- // - 无任何产出(LLM 空转)→ FAILED 交给调度器 retry/reassign。
633
+ // - 无 artifact 但回合有最终文本输出(部分 harness 不支持回合内调工具,只能把
634
+ // 结果写在答复里,如 codex/dsh 的 MCP 桥未就绪/未被模型使用)→ 同样隐式完成,
635
+ // 最终文本作为交付物;否则这类引擎的所有任务都会「工作做完了却停滞被回收」。
636
+ // - 两者皆无(LLM 空转)→ FAILED 交给调度器 retry/reassign。
622
637
  // 仅 worker 的 assign 执行消息生效:lead 由 supervise 协调;WAITING 父任务不属此列。
623
638
  if (taskId && this.role === 'worker' && msg.metadata?.['x-aw-task-kind'] === 'assign') {
624
639
  const after = this.deps.taskEngine.get(taskId)
625
640
  if (after && after.assigneeId === this.agentId && after.state === 'WORKING') {
626
641
  const deliverable = after.artifacts.find(a => a.name !== 'input' && a.parts.some(p => ('text' in p ? p.text.trim().length : 1) > 0))
627
- if (deliverable) {
642
+ const fallbackText = deliverable ? '' : replyText.trim()
643
+ if (deliverable || fallbackText) {
644
+ if (!deliverable) {
645
+ // 回合最终文本 → 平台代录交付物(与 complete_task 的 deliverable 同构)
646
+ await this.deps.taskEngine.applyEvent(taskId, {
647
+ kind: 'artifact',
648
+ artifact: {
649
+ artifactId: randomUUID(),
650
+ name: 'deliverable',
651
+ parts: [{ text: fallbackText.slice(0, 20_000) }],
652
+ },
653
+ lastChunk: true,
654
+ totalChunks: 1,
655
+ })
656
+ }
628
657
  const completed = await this.deps.taskEngine.complete(taskId)
629
658
  this.emitExternal({
630
659
  kind: 'status',
@@ -634,7 +663,7 @@ export class AgentRuntime {
634
663
  messageId: randomUUID(),
635
664
  contextId: this.channelId,
636
665
  role: 'ROLE_AGENT',
637
- parts: [{ text: `任务 ${taskId} 回合已产出交付物但未调用完成工具,平台隐式收口为 COMPLETED` }],
666
+ parts: [{ text: `任务 ${taskId} 回合已产出交付物但未调用完成工具,平台隐式收口为 COMPLETED${deliverable ? '' : '(交付物取自回合最终输出)'}` }],
638
667
  },
639
668
  timestamp: new Date().toISOString(),
640
669
  },
@@ -1 +0,0 @@
1
- {"id":"291ef3e6-fa6a-4dee-8f46-05da1aeab815","timestamp":1789115705165,"prerendered":[]}