agentworkshop 0.5.9 → 0.6.0
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/.AgentWorkShop/prompts/compaction-hints.md +9 -9
- package/.AgentWorkShop/prompts/host-tools.json +42 -0
- package/.output/.AgentWorkShop/prompts/compaction-hints.md +9 -9
- package/.output/.AgentWorkShop/prompts/host-tools.json +42 -0
- package/.output/nitro.json +1 -1
- package/.output/public/_nuxt/{Dm5mD6XT.js → BD9D9pl4.js} +1 -1
- package/.output/public/_nuxt/{BdKzfJiM.js → BxD8Fg_Z.js} +1 -1
- package/.output/public/_nuxt/{dRAyjbJ6.js → C-Y5ydB6.js} +3 -3
- package/.output/public/_nuxt/{Bok1DRqh.js → C0FogB-p.js} +1 -1
- package/.output/public/_nuxt/{BUNGEK2z.js → C2QSTAWf.js} +1 -1
- package/.output/public/_nuxt/{CWDzKGtj.js → CclO6GyL.js} +1 -1
- package/.output/public/_nuxt/{B3__nfxM.js → Ck6tznoQ.js} +1 -1
- package/.output/public/_nuxt/CwS_UHeH.js +1 -0
- package/.output/public/_nuxt/{CE2ynNi9.js → CwcOEM8m.js} +1 -1
- package/.output/public/_nuxt/MhK4buEJ.js +1 -0
- package/.output/public/_nuxt/_id_.DN3U6EF9.css +1 -0
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/a0ac51ef-51c0-4ff9-8484-7c90d8dd10ba.json +1 -0
- package/.output/public/_nuxt/{entry.DjhxLu-f.css → entry.DvlXlPwx.css} +1 -1
- package/.output/public/_nuxt/settings.BG0K9_MG.css +1 -0
- package/.output/server/chunks/_/error-500.mjs.map +1 -1
- package/.output/server/chunks/_/nitro.mjs +2648 -1401
- package/.output/server/chunks/_/nitro.mjs.map +1 -1
- package/.output/server/chunks/build/{OmpTerminalPanel-CZnxR3M_.mjs → OmpTerminalPanel-B_SYhmgb.mjs} +2 -2
- package/.output/server/chunks/build/{OmpTerminalPanel-CZnxR3M_.mjs.map → OmpTerminalPanel-B_SYhmgb.mjs.map} +1 -1
- package/.output/server/chunks/build/{TownView-DYlUNRZe.mjs → TownView-D9yCQe1T.mjs} +6 -6
- package/.output/server/chunks/build/{TownView-DYlUNRZe.mjs.map → TownView-D9yCQe1T.mjs.map} +1 -1
- package/.output/server/chunks/build/{_id_-BOhG2yz8.mjs → _id_-CmKAEFHV.mjs} +4 -2
- package/.output/server/chunks/build/_id_-CmKAEFHV.mjs.map +1 -0
- package/.output/server/chunks/build/{_id_-CuyMYmhY.mjs → _id_-xR3AChMO.mjs} +74 -26
- package/.output/server/chunks/build/_id_-xR3AChMO.mjs.map +1 -0
- package/.output/server/chunks/build/{_wsId_-B5f5BdW2.mjs → _wsId_-C45nVrl-.mjs} +12 -10
- package/.output/server/chunks/build/{_wsId_-B5f5BdW2.mjs.map → _wsId_-C45nVrl-.mjs.map} +1 -1
- package/.output/server/chunks/build/{agents-BVaxN75W.mjs → agents-D4l1icvn.mjs} +5 -3
- package/.output/server/chunks/build/agents-D4l1icvn.mjs.map +1 -0
- package/.output/server/chunks/build/{channel-templates-D1K2IKrE.mjs → channel-templates-DqjtC-R0.mjs} +5 -3
- package/.output/server/chunks/build/channel-templates-DqjtC-R0.mjs.map +1 -0
- package/.output/server/chunks/build/{client-only-CFTHwakk.mjs → client-only-D5BzSQc6.mjs} +2 -2
- package/.output/server/chunks/build/client-only-D5BzSQc6.mjs.map +1 -0
- package/.output/server/chunks/build/{daq-ObtN1TQ4.mjs → daq-Boz_dlAQ.mjs} +6 -4
- package/.output/server/chunks/build/daq-Boz_dlAQ.mjs.map +1 -0
- package/.output/server/chunks/build/{dcw-fINr-He1.mjs → dcw-wTRwBAUi.mjs} +3 -1
- package/.output/server/chunks/build/dcw-wTRwBAUi.mjs.map +1 -0
- package/.output/server/chunks/build/{default-CVVO40Jj.mjs → default-Dt6xLdpd.mjs} +7 -5
- package/.output/server/chunks/build/{default-CVVO40Jj.mjs.map → default-Dt6xLdpd.mjs.map} +1 -1
- package/.output/server/chunks/build/interval-WlxgjTzO.mjs +9 -0
- package/.output/server/chunks/build/interval-WlxgjTzO.mjs.map +1 -0
- package/.output/server/chunks/build/{logs-DqNgCJAn.mjs → logs-Cdi-eXlN.mjs} +5 -3
- package/.output/server/chunks/build/logs-Cdi-eXlN.mjs.map +1 -0
- package/.output/server/chunks/build/{monitor-CTZLwbdw.mjs → monitor-yNoV98rf.mjs} +6 -4
- package/.output/server/chunks/build/{monitor-CTZLwbdw.mjs.map → monitor-yNoV98rf.mjs.map} +1 -1
- package/.output/server/chunks/build/{pages-DC52d7z7.mjs → pages-bWKy0ZsA.mjs} +6 -4
- package/.output/server/chunks/build/pages-bWKy0ZsA.mjs.map +1 -0
- package/.output/server/chunks/build/{plugins-DVQty7qG.mjs → plugins-B-ZNey0Z.mjs} +4 -2
- package/.output/server/chunks/build/plugins-B-ZNey0Z.mjs.map +1 -0
- package/.output/server/chunks/build/{settings-BeergncK.mjs → settings-C3T5hR2A.mjs} +21 -19
- package/.output/server/chunks/build/settings-C3T5hR2A.mjs.map +1 -0
- package/.output/server/chunks/build/{teams-CFeDlHDh.mjs → teams-QR3BBF7A.mjs} +5 -3
- package/.output/server/chunks/build/teams-QR3BBF7A.mjs.map +1 -0
- package/.output/server/chunks/build/{tokens-CBAUbOce.mjs → tokens-DFvr_TLj.mjs} +4 -2
- package/.output/server/chunks/build/tokens-DFvr_TLj.mjs.map +1 -0
- package/.output/server/chunks/build/town-BUqRobze.mjs +2 -0
- package/.output/server/chunks/build/town-BUqRobze.mjs.map +1 -1
- package/.output/server/chunks/build/{town-BxH-XXth.mjs → town-CKg6Qxba.mjs} +9 -7
- package/.output/server/chunks/build/town-CKg6Qxba.mjs.map +1 -0
- package/.output/server/chunks/build/{useDaqStream-CwORhsD7.mjs → useDaqStream-zHEptJQ_.mjs} +44 -1
- package/.output/server/chunks/build/useDaqStream-zHEptJQ_.mjs.map +1 -0
- package/.output/server/chunks/build/{useSiteConfig-Cc-ABesl.mjs → useSiteConfig-DJe_KMVr.mjs} +1 -1
- package/.output/server/chunks/build/{useSiteConfig-Cc-ABesl.mjs.map → useSiteConfig-DJe_KMVr.mjs.map} +1 -1
- package/.output/server/chunks/build/{useWorkshopApi-5er8_EHZ.mjs → useWorkshopApi-Bh5VUHWu.mjs} +1 -1
- package/.output/server/chunks/build/{useWorkshopApi-5er8_EHZ.mjs.map → useWorkshopApi-Bh5VUHWu.mjs.map} +1 -1
- package/.output/server/chunks/build/{useWorkshopWs-Dwr_1Q8f.mjs → useWorkshopWs-xcdeiSmJ.mjs} +2 -2
- package/.output/server/chunks/build/{useWorkshopWs-Dwr_1Q8f.mjs.map → useWorkshopWs-xcdeiSmJ.mjs.map} +1 -1
- package/.output/server/chunks/build/{user-CpVY4OAA.mjs → user-Dk-ytEUV.mjs} +1 -1
- package/.output/server/chunks/build/{user-CpVY4OAA.mjs.map → user-Dk-ytEUV.mjs.map} +1 -1
- package/.output/server/chunks/build/{users-BMs4s_6K.mjs → users-4FZ0yFUO.mjs} +4 -2
- package/.output/server/chunks/build/users-4FZ0yFUO.mjs.map +1 -0
- package/.output/server/chunks/build/{workshop-CJAyZ5zS.mjs → workshop-CLhwe5eo.mjs} +6 -4
- package/.output/server/chunks/build/workshop-CLhwe5eo.mjs.map +1 -0
- package/.output/server/chunks/build/{workspaces-Dq-1zvu9.mjs → workspaces-IfORCDJE.mjs} +2 -2
- package/.output/server/chunks/build/{workspaces-Dq-1zvu9.mjs.map → workspaces-IfORCDJE.mjs.map} +1 -1
- package/.output/server/chunks/routes/api/health.get.mjs +2 -0
- package/.output/server/chunks/routes/api/health.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/index.post.mjs +2 -0
- package/.output/server/chunks/routes/api/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/mcp/workshop.mjs +2 -0
- package/.output/server/chunks/routes/api/mcp/workshop.mjs.map +1 -1
- package/.output/server/chunks/routes/api/metrics.mjs +2 -0
- package/.output/server/chunks/routes/api/metrics.mjs.map +1 -1
- package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs +2 -0
- package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs.map +1 -1
- package/.output/server/chunks/routes/api/plugins/client/_name_.get.mjs +2 -0
- package/.output/server/chunks/routes/api/plugins/client/_name_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/plugins/manifest.get.mjs +2 -0
- package/.output/server/chunks/routes/api/plugins/manifest.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/config.get.mjs +2 -0
- package/.output/server/chunks/routes/api/system/config.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/system/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/index.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/system/index.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs +2 -0
- package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs +2 -0
- package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/monitor.get.mjs +2 -0
- package/.output/server/chunks/routes/api/system/monitor.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/settings/events.get.mjs +3 -2
- package/.output/server/chunks/routes/api/system/settings/events.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/system/settings/reset.post.mjs +2 -0
- package/.output/server/chunks/routes/api/system/settings/reset.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/users/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/_id_.get.mjs +2 -0
- package/.output/server/chunks/routes/api/users/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/_id_.put.mjs +2 -0
- package/.output/server/chunks/routes/api/users/_id_.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/users/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/index.post.mjs +2 -0
- package/.output/server/chunks/routes/api/users/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/login.post.mjs +2 -0
- package/.output/server/chunks/routes/api/users/login.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/logout.post.mjs +2 -0
- package/.output/server/chunks/routes/api/users/logout.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/me.get.mjs +2 -0
- package/.output/server/chunks/routes/api/users/me.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/register.post.mjs +2 -0
- package/.output/server/chunks/routes/api/users/register.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs +2 -0
- package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/users/tokens/_id_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/users/tokens/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/_...path_.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/_...path_.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/a2a/send.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/a2a/send.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/agents/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/_id_.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/agents/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/agents/subscribe.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/agents/subscribe.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/character/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/assets/character/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/devices/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/assets/devices/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index2.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/assets/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/audit.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/audit.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/caller.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/caller.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/from-channel.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channel-templates/from-channel.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/_memoryId_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/_memoryId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/search.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/search.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/model.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/model.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/position.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/position.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/range.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/range.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/stop.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/stop.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/events.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/events.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index2.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/index2.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index3.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/index3.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/memories/_memoryId_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/memories/_memoryId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/queue.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/queue.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/channels.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs +36 -0
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs +53 -0
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index10.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index10.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index2.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index2.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index2.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index2.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index3.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index3.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index3.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index3.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index4.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index4.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index4.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index4.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index5.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index5.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index5.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index5.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index6.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index6.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index6.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index6.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index7.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index7.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index7.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index7.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index8.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index8.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index8.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index8.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/index9.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/index9.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/mailbox/all.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/mailbox/all.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/mailbox.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/mailbox.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/memories/maintenance.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/memories/maintenance.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/plugins/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/plugins/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/runtime.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/runtime.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/scene/layouts.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/complete.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/tasks/_id/complete.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/dispatch.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/tasks/_id/dispatch.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/index.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/tasks/_id/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/report.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/tasks/_id/report.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id/retry.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/tasks/_id/retry.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/tasks.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/tasks.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/members/_agentId_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/teams/_id/members/_agentId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/teams/_id_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/teams/_id_.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id_.patch.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/teams/_id_.patch.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/users/me.get.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/users/me.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/users/register.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/users/register.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.post.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/index.delete.mjs +2 -0
- package/.output/server/chunks/routes/api/workshop/workspaces/index.delete.mjs.map +1 -1
- package/.output/server/chunks/routes/renderer.mjs +1 -1
- package/.output/server/chunks/routes/renderer.mjs.map +1 -1
- package/.output/server/chunks/virtual/entry.mjs +166 -114
- package/.output/server/chunks/virtual/entry.mjs.map +1 -1
- package/.output/server/chunks/virtual/precomputed.mjs +1 -1
- package/.output/server/index.mjs +2 -0
- package/.output/server/index.mjs.map +1 -1
- package/.output/server/package.json +1 -1
- package/app/composables/workshop/useDaqStream.ts +59 -1
- package/app/config/schema.ts +8 -0
- package/app/pages/daq/[id].vue +141 -1
- package/app/pages/settings.vue +10 -5
- package/app/plugins/runtime-config.client.ts +65 -65
- package/app/stores/runtime-config.ts +212 -212
- package/config.yml +77 -70
- package/docker-compose.yml +19 -2
- package/docs/plugins.md +271 -197
- package/i18n/dicts/_en.json +7 -2
- package/i18n/dicts/daqDetail.json +8 -2
- package/i18n/locales/en.ts +55 -29
- package/i18n/locales/zh-CN.ts +55 -29
- package/nuxt.config.ts +1 -1
- package/package.json +144 -143
- package/scripts/_dbg-collab-scenario-e2e.mjs +185 -0
- package/scripts/_dbg-daq-frame-alarm.mjs +49 -0
- package/scripts/_dbg-daq-frame-ui.mjs +62 -0
- package/scripts/_dbg-daq-frame-ws.mjs +72 -0
- package/scripts/_dbg-daq-frames-e2e.mjs +118 -0
- package/scripts/_dbg-host.mjs +16 -0
- package/scripts/_dbg-plugin-agent-read.ts +56 -0
- package/scripts/_dbg-plugin-sink-rest.mjs +70 -0
- package/scripts/_dbg-plugin-sink-ui.mjs +81 -0
- package/scripts/_dbg-prompts-hotreload-test.ts +76 -0
- package/scripts/_dbg-release-smoke.mjs +104 -0
- package/scripts/i18n-merge.mjs +69 -67
- package/scripts/test-context-governor.ts +176 -176
- package/scripts/test-daq-frames.ts +180 -0
- package/scripts/test-daq-minio.ts +77 -0
- package/scripts/test-memory-rrf-mmr.ts +114 -114
- package/scripts/test-plugin-ext.ts +173 -0
- package/server/api/system/settings/events.get.ts +27 -28
- package/server/api/system/settings/index.get.ts +14 -14
- package/server/api/system/settings/index.patch.ts +22 -22
- package/server/api/system/settings/reset.post.ts +12 -12
- package/server/api/workshop/daq/[id]/frames/content.get.ts +24 -0
- package/server/api/workshop/daq/[id]/frames.get.ts +44 -0
- package/server/data/daqs.json +89 -89
- package/server/data/dcw-rollback.json +1 -1
- package/server/data/dcw-runs.json +3136 -2492
- package/server/data/dcw-writes.json +672 -0
- package/server/data/dcws.json +4 -4
- package/server/data/line-runs.json +1 -232
- package/server/plugins/daq.ts +11 -0
- package/server/plugins/system-config.ts +38 -38
- package/server/services/system-config.ts +365 -356
- package/server/services/workshop/agents/industrial-tools.ts +91 -25
- package/server/services/workshop/agents/omp-agent.ts +1955 -1895
- package/server/services/workshop/agents/plugin-tools.ts +145 -0
- package/server/services/workshop/daq/bus/queue-port.ts +18 -0
- package/server/services/workshop/daq/daq-controller.ts +216 -14
- package/server/services/workshop/daq/daq-node.ts +257 -247
- package/server/services/workshop/daq/daq-runtime.ts +36 -4
- package/server/services/workshop/daq/daq-templates.ts +213 -157
- package/server/services/workshop/daq/drivers.ts +134 -30
- package/server/services/workshop/daq/frames.ts +227 -0
- package/server/services/workshop/daq/infra.ts +31 -17
- package/server/services/workshop/daq/objectstore/disk.adapter.ts +38 -0
- package/server/services/workshop/daq/objectstore/index.ts +88 -0
- package/server/services/workshop/daq/objectstore/minio.adapter.ts +60 -0
- package/server/services/workshop/daq/objectstore/objectstore-port.ts +27 -0
- package/server/services/workshop/daq/plugin-bridge.ts +73 -0
- package/server/services/workshop/daq/png-enc.ts +71 -0
- package/server/services/workshop/daq/storage/sqlite.adapter.ts +104 -1
- package/server/services/workshop/daq/storage/timescale.adapter.ts +95 -4
- package/server/services/workshop/daq/storage/tsdb-port.ts +46 -0
- package/server/services/workshop/plugins/host.mjs +479 -417
- package/server/services/workshop/runtime/agent-runtime.ts +744 -744
- package/shared/config/schema.json +6 -1
- package/shared/daq-protocol.ts +88 -0
- package/.output/public/_nuxt/B-PgoIPN.js +0 -1
- package/.output/public/_nuxt/DVNYfGsj.js +0 -1
- package/.output/public/_nuxt/_id_.CbiF5PrV.css +0 -1
- package/.output/public/_nuxt/builds/meta/6f7e40bf-a960-4f51-8a2e-bb1fffeaa5e8.json +0 -1
- package/.output/public/_nuxt/settings.BANibAnV.css +0 -1
- package/.output/server/chunks/build/_id_-BOhG2yz8.mjs.map +0 -1
- package/.output/server/chunks/build/_id_-CuyMYmhY.mjs.map +0 -1
- package/.output/server/chunks/build/agents-BVaxN75W.mjs.map +0 -1
- package/.output/server/chunks/build/channel-templates-D1K2IKrE.mjs.map +0 -1
- package/.output/server/chunks/build/client-only-CFTHwakk.mjs.map +0 -1
- package/.output/server/chunks/build/daq-ObtN1TQ4.mjs.map +0 -1
- package/.output/server/chunks/build/dcw-fINr-He1.mjs.map +0 -1
- package/.output/server/chunks/build/interval-Bt11uRPw.mjs +0 -9
- package/.output/server/chunks/build/interval-Bt11uRPw.mjs.map +0 -1
- package/.output/server/chunks/build/logs-DqNgCJAn.mjs.map +0 -1
- package/.output/server/chunks/build/pages-DC52d7z7.mjs.map +0 -1
- package/.output/server/chunks/build/plugins-DVQty7qG.mjs.map +0 -1
- package/.output/server/chunks/build/settings-BeergncK.mjs.map +0 -1
- package/.output/server/chunks/build/teams-CFeDlHDh.mjs.map +0 -1
- package/.output/server/chunks/build/tokens-CBAUbOce.mjs.map +0 -1
- package/.output/server/chunks/build/town-BxH-XXth.mjs.map +0 -1
- package/.output/server/chunks/build/useDaqStream-CwORhsD7.mjs.map +0 -1
- package/.output/server/chunks/build/users-BMs4s_6K.mjs.map +0 -1
- package/.output/server/chunks/build/workshop-CJAyZ5zS.mjs.map +0 -1
|
@@ -1,744 +1,744 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AgentRuntime — Agent 独立运行时对象。
|
|
3
|
-
* 状态机 idle/busy/stopped + 消费循环(自动接取/自动作业)+ run/supervise 互斥 + abort。
|
|
4
|
-
* 任务管理系统:每个运行时对自己的任务队列(待执行 FIFO / 执行中 / 已完成)有完整视图;
|
|
5
|
-
* 队列是 tasks 表的派生投影(DB 唯一事实源),状态迁移实时广播(idle/busy + 队列上下文)。
|
|
6
|
-
*/
|
|
7
|
-
import { createLogger } from '../logger'
|
|
8
|
-
import { randomUUID } from 'node:crypto'
|
|
9
|
-
import type {
|
|
10
|
-
AgentEvent,
|
|
11
|
-
AgentInfo,
|
|
12
|
-
AgentInterface,
|
|
13
|
-
AgentRunContext,
|
|
14
|
-
AgentRunRequest,
|
|
15
|
-
AgentWorkspace,
|
|
16
|
-
SupervisionDecision,
|
|
17
|
-
SupervisionSnapshot,
|
|
18
|
-
} from '../agents/agent-interface'
|
|
19
|
-
import type { A2AMessage, A2AArtifact, Part } from '../types/a2a'
|
|
20
|
-
import type { AgentContextStats, AgentStatusView, AgentTaskQueueView, TaskState, WorkspaceTask } from '../types/task'
|
|
21
|
-
import { TERMINAL_TASK_STATES } from '../types/task'
|
|
22
|
-
import type { AgentMemory } from './memory'
|
|
23
|
-
import type { Mailbox } from './mailbox'
|
|
24
|
-
|
|
25
|
-
const log = createLogger('workshop.agent-runtime')
|
|
26
|
-
|
|
27
|
-
/** ChannelBus:运行时事件总线(逐事件广播 + 任务/成员事件通知 + 调度唤醒) */
|
|
28
|
-
/** 任务变更事件携带的源头任务视图(WS 推送免 per-event 回查;WorkspaceTask 结构兼容) */
|
|
29
|
-
export interface TaskEventTask {
|
|
30
|
-
id: string
|
|
31
|
-
title?: string
|
|
32
|
-
parentId?: string
|
|
33
|
-
assigneeId?: string
|
|
34
|
-
progress?: number | null
|
|
35
|
-
routeReason?: string
|
|
36
|
-
createdAt: string
|
|
37
|
-
artifacts?: unknown[]
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface ChannelBus {
|
|
41
|
-
/** AgentEvent 流式广播:所有 harness 的统一事件出口(自定义协议流) */
|
|
42
|
-
emit(event: AgentEvent, source: A2AMessage): void
|
|
43
|
-
/** 订阅 AgentEvent 流(monitor/WS 消费);返回退订函数 */
|
|
44
|
-
onEvent(fn: (event: AgentEvent, source: A2AMessage) => void): () => void
|
|
45
|
-
/** 任务事件通知(状态迁移/进度变化;由 TaskEngine hooks 统一触发;task = 源头视图) */
|
|
46
|
-
notifyTask(e: { taskId: string, state?: TaskState, progress?: number, agentId?: string, task?: TaskEventTask }): void
|
|
47
|
-
onTaskEvent(fn: (e: { taskId: string, state?: TaskState, progress?: number, agentId?: string, task?: TaskEventTask }) => void): () => void
|
|
48
|
-
/**
|
|
49
|
-
* 成员状态通知(idle/busy/stopped + 队列上下文;AgentRuntime 转换处触发,事件驱动无轮询)。
|
|
50
|
-
* currentTaskId/currentTaskTitle/currentTaskProgress/queuedCount/completedCount
|
|
51
|
-
* 为增量字段:实时状态追踪的完整视图(lead 观察 worker 进度,防"在跑但无信号")。
|
|
52
|
-
*/
|
|
53
|
-
notifyAgent(e: {
|
|
54
|
-
agentId: string
|
|
55
|
-
state: 'idle' | 'busy' | 'stopped'
|
|
56
|
-
currentTaskId?: string | null
|
|
57
|
-
currentTaskTitle?: string | null
|
|
58
|
-
currentTaskProgress?: number | null
|
|
59
|
-
queuedCount?: number
|
|
60
|
-
completedCount?: number
|
|
61
|
-
/** harness 上下文用量(omp 有;进程内 harness 缺省) */
|
|
62
|
-
context?: AgentContextStats | null
|
|
63
|
-
}): void
|
|
64
|
-
onAgentStatus(fn: (e: {
|
|
65
|
-
agentId: string
|
|
66
|
-
state: 'idle' | 'busy' | 'stopped'
|
|
67
|
-
currentTaskId?: string | null
|
|
68
|
-
currentTaskTitle?: string | null
|
|
69
|
-
currentTaskProgress?: number | null
|
|
70
|
-
queuedCount?: number
|
|
71
|
-
completedCount?: number
|
|
72
|
-
context?: AgentContextStats | null
|
|
73
|
-
}) => void): () => void
|
|
74
|
-
/** channel 内消息投递通知(route 汇流点触发;AEP a2a.message 事件源) */
|
|
75
|
-
notifyMessage(message: A2AMessage): void
|
|
76
|
-
onMessage(fn: (message: A2AMessage) => void): () => void
|
|
77
|
-
/** 团队成员增/改/删通知(lead 自主管理或用户 REST;AEP agent.member 事件源) */
|
|
78
|
-
notifyMember(e: MemberChangeEvent): void
|
|
79
|
-
onMemberEvent(fn: (e: MemberChangeEvent) => void): () => void
|
|
80
|
-
/** 记忆写入通知(策展/主动沉淀;AEP memory.saved 事件源) */
|
|
81
|
-
notifyMemory(e: { agentId: string, scope: 'private' | 'shared', title: string, dedupKey: string }): void
|
|
82
|
-
onMemoryEvent(fn: (e: { agentId: string, scope: 'private' | 'shared', title: string, dedupKey: string }) => void): () => void
|
|
83
|
-
wakeScheduler(): void
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** 团队成员变更事件(lead 执行中自主管理成员或用户 REST 操作;AEP agent.member 载荷) */
|
|
87
|
-
export interface MemberChangeEvent {
|
|
88
|
-
op: 'added' | 'updated' | 'removed'
|
|
89
|
-
agentId: string
|
|
90
|
-
name: string
|
|
91
|
-
role: 'lead' | 'worker'
|
|
92
|
-
harness: string
|
|
93
|
-
enabled?: number
|
|
94
|
-
/** 实例 config(含 systemPromptPrefix 场景提示词;added/updated 时携带,removed 可空) */
|
|
95
|
-
config?: Record<string, unknown>
|
|
96
|
-
/** 操作发起方:'lead:<agentId>' 或 'user' */
|
|
97
|
-
by: string
|
|
98
|
-
reason?: string
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/** Parts → 纯文本(text 片段拼接;记忆召回查询与回复收集共用) */
|
|
102
|
-
function partsToText(parts: Part[]): string {
|
|
103
|
-
return parts.map(p => ('text' in p ? p.text : '')).filter(Boolean).join('\n')
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* TaskEngine 结构契约(实现方 T4 task-engine.ts,同步签名)。
|
|
108
|
-
* 以接口而非具体类声明依赖,便于测试注入 fake 与集成装配真实引擎。
|
|
109
|
-
*/
|
|
110
|
-
export interface TaskEngine {
|
|
111
|
-
create(input: {
|
|
112
|
-
channelId: string
|
|
113
|
-
creatorId: string
|
|
114
|
-
assigneeId: string
|
|
115
|
-
title: string
|
|
116
|
-
description?: string
|
|
117
|
-
parentId?: string
|
|
118
|
-
parts?: Part[]
|
|
119
|
-
}): WorkspaceTask
|
|
120
|
-
dispatch(
|
|
121
|
-
parent: WorkspaceTask,
|
|
122
|
-
input: { assigneeId: string, title: string, description?: string, parts?: Part[], routeReason?: string },
|
|
123
|
-
): WorkspaceTask
|
|
124
|
-
transition(taskId: string, state: TaskState, by: string): WorkspaceTask
|
|
125
|
-
applyEvent(taskId: string, event: AgentEvent): void
|
|
126
|
-
list(channelId: string): WorkspaceTask[]
|
|
127
|
-
get(taskId: string): WorkspaceTask | undefined
|
|
128
|
-
complete(taskId: string, artifacts?: A2AArtifact[]): WorkspaceTask
|
|
129
|
-
reassign(taskId: string, toAgentId: string): WorkspaceTask
|
|
130
|
-
/** 修改待执行任务(title/description)+ 刷新 assignee 队列投递 */
|
|
131
|
-
updateTask(taskId: string, patch: { title?: string, description?: string }, by: string): WorkspaceTask
|
|
132
|
-
cancel(taskId: string, by: string): WorkspaceTask
|
|
133
|
-
onChildCompleted(child: WorkspaceTask): void
|
|
134
|
-
/** 断线重连重投:非终态任务无 pending assign 时向 assignee 重发(restore 用) */
|
|
135
|
-
redeliverAssign(taskId: string): WorkspaceTask
|
|
136
|
-
/** 单 agent 任务队列视图(待执行 FIFO / 执行中 / 已完成) */
|
|
137
|
-
queueViewOf(channelId: string, agentId: string): AgentTaskQueueView
|
|
138
|
-
/** 批量队列视图(一次查询聚合全 channel;调度快照热路径) */
|
|
139
|
-
queueViewsOf(channelId: string): Map<string, AgentTaskQueueView>
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* AgentRuntime 的结构契约(ChannelRuntime/SchedulerLoop 消费的最小接口)。
|
|
144
|
-
*/
|
|
145
|
-
export interface AgentRuntimeLike {
|
|
146
|
-
readonly agentId: string
|
|
147
|
-
readonly role: 'lead' | 'worker'
|
|
148
|
-
readonly channelId: string
|
|
149
|
-
readonly name: string
|
|
150
|
-
enqueue(message: A2AMessage): void
|
|
151
|
-
getState(): 'idle' | 'busy' | 'stopped'
|
|
152
|
-
/** 实时状态视图(idle/busy/stopped + 当前任务 + 队列长度) */
|
|
153
|
-
getStatus(): AgentStatusView
|
|
154
|
-
/** 本 agent 的任务队列视图(待执行 FIFO / 执行中 / 已完成) */
|
|
155
|
-
getQueueView(): AgentTaskQueueView
|
|
156
|
-
abortCurrent(): void
|
|
157
|
-
wakeMailbox(): void
|
|
158
|
-
stop(): Promise<void>
|
|
159
|
-
/** 平台侧合成事件出口(如 SchedulerLoop 汇总成果);转发 ChannelBus.emit 走统一事件流 */
|
|
160
|
-
emitExternal(event: AgentEvent, fromAgentId?: string): void
|
|
161
|
-
/** 实时消息注入:busy 时通过 impl.steer 注入 omp 会话;idle 时入 mailbox 队列 */
|
|
162
|
-
injectSteer(message: A2AMessage): void
|
|
163
|
-
/** Agent 能力面(调度器执行成员管理决策用;AgentRuntime 始终提供) */
|
|
164
|
-
readonly workspace?: AgentWorkspace
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export class AgentRuntime {
|
|
168
|
-
readonly agentId: string
|
|
169
|
-
readonly role: 'lead' | 'worker'
|
|
170
|
-
readonly channelId: string
|
|
171
|
-
readonly name: string
|
|
172
|
-
private state: 'idle' | 'busy' | 'stopped' = 'idle'
|
|
173
|
-
/** 回合失败重投计数(每消息;进程内存,重启由 resetConsuming 重新给机会) */
|
|
174
|
-
private runErrorRetries = new Map<string, number>()
|
|
175
|
-
/** 正在执行的任务 id(run 期间;空闲时 null) */
|
|
176
|
-
private currentTaskId: string | null = null
|
|
177
|
-
/** poll_messages 阻塞等待数(waitPending 活动计数;>0 = 有轮询在等,实时消息留信箱由其取走) */
|
|
178
|
-
private pollWaiters = 0
|
|
179
|
-
/** run 与 supervise 互斥锁(promise 链) */
|
|
180
|
-
private execLock: Promise<void> = Promise.resolve()
|
|
181
|
-
private abortController: AbortController | null = null
|
|
182
|
-
private loopPromise: Promise<void> | null = null
|
|
183
|
-
private started = false
|
|
184
|
-
|
|
185
|
-
constructor(
|
|
186
|
-
agent: AgentInfo,
|
|
187
|
-
private impl: AgentInterface,
|
|
188
|
-
private deps: {
|
|
189
|
-
mailbox: Mailbox
|
|
190
|
-
taskEngine: TaskEngine
|
|
191
|
-
bus: ChannelBus
|
|
192
|
-
workspace: AgentWorkspace
|
|
193
|
-
memory?: AgentMemory
|
|
194
|
-
},
|
|
195
|
-
) {
|
|
196
|
-
this.agentId = agent.id
|
|
197
|
-
this.role = agent.role
|
|
198
|
-
this.channelId = agent.channelId
|
|
199
|
-
this.name = agent.name
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/** 投递消息;idle 时立即唤醒消费 */
|
|
203
|
-
enqueue(message: A2AMessage): void {
|
|
204
|
-
this.deps.mailbox.enqueue(message)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
getState(): 'idle' | 'busy' | 'stopped' {
|
|
208
|
-
return this.state
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/** 实时状态视图:idle/busy/stopped + 当前任务 + 队列 + harness 上下文用量 */
|
|
212
|
-
getStatus(): AgentStatusView {
|
|
213
|
-
const queue = this.getQueueView()
|
|
214
|
-
const current = queue.current ?? (this.currentTaskId ? this.deps.taskEngine.get(this.currentTaskId) : undefined)
|
|
215
|
-
const context = this.impl.getContextStats?.() ?? undefined
|
|
216
|
-
return {
|
|
217
|
-
agentId: this.agentId,
|
|
218
|
-
channelId: this.channelId,
|
|
219
|
-
role: this.role,
|
|
220
|
-
name: this.name,
|
|
221
|
-
state: this.state,
|
|
222
|
-
currentTaskId: current?.id ?? null,
|
|
223
|
-
// 进度/标题透出:lead 观察 worker 是否在推进(progress 空闲/未上报时为 null)
|
|
224
|
-
currentTaskTitle: current?.title ?? null,
|
|
225
|
-
currentTaskProgress: current?.progress != null ? current.progress : null,
|
|
226
|
-
queuedCount: queue.queued.length,
|
|
227
|
-
completedCount: queue.completed.length,
|
|
228
|
-
...(context ? { context } : {}),
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/** 本 agent 的任务队列视图(自己的任务管理系统:待执行 FIFO / 执行中 / 已完成) */
|
|
233
|
-
getQueueView(): AgentTaskQueueView {
|
|
234
|
-
return this.deps.taskEngine.queueViewOf(this.channelId, this.agentId)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/** 中止当前 run(任务取消/Agent 移除时);空闲时无操作 */
|
|
238
|
-
abortCurrent(): void {
|
|
239
|
-
log.warn(`[AgentRuntime:${this.agentId}] abortCurrent 调用(state=${this.state})`)
|
|
240
|
-
this.abortController?.abort()
|
|
241
|
-
// supervise 回合同样可打断(调度器 cancel 路径 → LLM 回合真中止)
|
|
242
|
-
this.superviseController?.abort()
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
emitExternal(event: AgentEvent, fromAgentId?: string): void {
|
|
246
|
-
// 合成 source(monitor 依 metadata 归属 agent);平台侧产出与 harness 事件同流
|
|
247
|
-
const source: A2AMessage = {
|
|
248
|
-
messageId: randomUUID(),
|
|
249
|
-
contextId: this.channelId,
|
|
250
|
-
role: 'ROLE_AGENT',
|
|
251
|
-
parts: [],
|
|
252
|
-
metadata: { 'x-aw-from-agent': fromAgentId ?? this.agentId },
|
|
253
|
-
}
|
|
254
|
-
this.deps.bus.emit(event, source)
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* 实时注入策略(信箱优先,与主动轮询完全兼容):
|
|
259
|
-
* - poll_messages 等待中:任何实时消息留在 pending —— 等待中的轮询经 Mailbox
|
|
260
|
-
* 到信回调毫秒级取走(读即取=已读),零打断、不与轮询竞争唯一所有权
|
|
261
|
-
* - agent 间协作消息(from-agent):同样走信箱 —— turn 结束后消费循环按 peer
|
|
262
|
-
* 回合处理(require_reply 触发语义/回执关联完整)。steer 注入 omp 会话会让
|
|
263
|
-
* 其把排队消息后的工具调用标记 "Skipped due to queued user message",
|
|
264
|
-
* 中断 poll_messages 长等待并污染执行流(实测故障源)
|
|
265
|
-
* - 仅人类紧急直发(immediate + from-label,无 from-agent)保留 steer 同轮注入:
|
|
266
|
-
* 紧急人工打断是唯一值得中断会话的场景
|
|
267
|
-
*/
|
|
268
|
-
injectSteer(message: A2AMessage): void {
|
|
269
|
-
if (this.state !== 'busy' || !this.impl.steer) return
|
|
270
|
-
// ① 轮询等待中:留 pending 给 poll_messages(毫秒级取走并标记已读)
|
|
271
|
-
if (this.pollWaiters > 0) return
|
|
272
|
-
// ② agent 间协作消息:信箱优先(turn 结束 peer 回合处理)
|
|
273
|
-
const from = message.metadata?.['x-aw-from-agent']
|
|
274
|
-
if (typeof from === 'string' && from.length > 0) return
|
|
275
|
-
// ③ 其余(人类紧急直发):原有 steer 注入路径
|
|
276
|
-
if (!this.deps.mailbox.claim(message.messageId)) return
|
|
277
|
-
const text = message.parts
|
|
278
|
-
.map((p) => {
|
|
279
|
-
if ('text' in p) return p.text
|
|
280
|
-
if ('data' in p) return JSON.stringify(p.data)
|
|
281
|
-
return ''
|
|
282
|
-
})
|
|
283
|
-
.join('\n')
|
|
284
|
-
const fromId = (message.metadata?.['x-aw-from-agent'] as string | undefined) ?? 'system'
|
|
285
|
-
const lines = [`[实时消息 from ${fromId}]: ${text}`]
|
|
286
|
-
if (message.metadata?.['x-aw-require-reply'] === 'true') {
|
|
287
|
-
lines.push(
|
|
288
|
-
`[系统触发器] 本消息要求回复(reply_to=${message.messageId})。`,
|
|
289
|
-
`请处理消息中的需求,随后用 send_message_to_agent 回复发送者 ${fromId}:`,
|
|
290
|
-
`参数 message=执行结果+对方所需内容, in_reply_to=${message.messageId},`,
|
|
291
|
-
`require_reply=仅当你还需要对方进一步响应时才设 true。`,
|
|
292
|
-
)
|
|
293
|
-
}
|
|
294
|
-
this.impl.steer(lines.join('\n'))
|
|
295
|
-
.then((mode) => {
|
|
296
|
-
if (mode === 'steer') {
|
|
297
|
-
// 确认注入流式会话 → 消费落定(at-least-once:进程崩溃由 resetConsuming 兜底)
|
|
298
|
-
this.deps.mailbox.markConsumed(message.messageId)
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
301
|
-
// deferred:释放认领回 pending,poll_messages(250ms 兜底重查)或
|
|
302
|
-
// 本回合结束后的消费循环(FIFO)接管,消息必达不丢失
|
|
303
|
-
this.releaseSteerClaim(message.messageId)
|
|
304
|
-
}
|
|
305
|
-
})
|
|
306
|
-
.catch((err) => {
|
|
307
|
-
log.error(`[AgentRuntime:${this.agentId}] steer 失败(释放认领回 pending 待循环处理):`, err)
|
|
308
|
-
this.releaseSteerClaim(message.messageId)
|
|
309
|
-
})
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/** 释放 steer 认领:consuming → pending + 唤醒 dequeue 门闩与到信等待方 */
|
|
313
|
-
private releaseSteerClaim(messageId: string): void {
|
|
314
|
-
if (this.deps.mailbox.requeue(messageId)) {
|
|
315
|
-
this.deps.mailbox.wake()
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* 长轮询未消费消息(poll_messages host 工具用):
|
|
321
|
-
* 250ms 兜底重查 + Mailbox 到信回调即时唤醒——消息到达后毫秒级返回,
|
|
322
|
-
* 不再每秒盲查。不改消息状态(peek 只读);消费语义由调用方(poll 读即取)决定。
|
|
323
|
-
* pollWaiters 计数暴露"轮询等待中"状态:injectSteer 据此把实时消息留在信箱
|
|
324
|
-
* 由本方法取走(不打断会话、与主动轮询兼容)。
|
|
325
|
-
*/
|
|
326
|
-
async waitPending(limit: number, waitMs: number): Promise<A2AMessage[]> {
|
|
327
|
-
this.pollWaiters += 1
|
|
328
|
-
try {
|
|
329
|
-
const deadline = Date.now() + Math.max(0, waitMs)
|
|
330
|
-
for (;;) {
|
|
331
|
-
const msgs = await this.deps.mailbox.peek(limit)
|
|
332
|
-
if (msgs.length > 0 || Date.now() >= deadline) return msgs
|
|
333
|
-
const { promise, resolve } = Promise.withResolvers<unknown>()
|
|
334
|
-
const off = this.deps.mailbox.onArrival(() => resolve(undefined))
|
|
335
|
-
const timer = setTimeout(() => resolve(undefined), 250)
|
|
336
|
-
await promise
|
|
337
|
-
clearTimeout(timer)
|
|
338
|
-
off()
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
finally {
|
|
342
|
-
this.pollWaiters -= 1
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/** 启动消费循环 */
|
|
347
|
-
start(): void {
|
|
348
|
-
if (this.started) return
|
|
349
|
-
this.started = true
|
|
350
|
-
this.state = 'idle'
|
|
351
|
-
this.loopPromise = this.consumeLoop()
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/** 停止:中断当前 run + 等当前事件流结束 + dispose impl(杀子进程等) */
|
|
355
|
-
async stop(): Promise<void> {
|
|
356
|
-
log.warn(`[AgentRuntime:${this.agentId}] runtime.stop() 调用(卸载/停用)`)
|
|
357
|
-
this.state = 'stopped'
|
|
358
|
-
this.abortController?.abort()
|
|
359
|
-
this.deps.mailbox.close()
|
|
360
|
-
// 状态广播:前端经 WS agent.status 实时反映 stopped
|
|
361
|
-
this.deps.bus.notifyAgent({ agentId: this.agentId, state: 'stopped', ...this.queueContext() })
|
|
362
|
-
await this.loopPromise
|
|
363
|
-
// 清理 impl 持有的资源(omp 子进程等);容错:impl.dispose 可能不存在
|
|
364
|
-
try {
|
|
365
|
-
await this.impl.dispose?.()
|
|
366
|
-
}
|
|
367
|
-
catch (err) {
|
|
368
|
-
log.error(`[AgentRuntime:${this.agentId}] dispose 失败:`, err)
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
/** 唤醒 mailbox(供 manager 在 taskEngine 直接落库投递后唤醒消费) */
|
|
373
|
-
wakeMailbox(): void {
|
|
374
|
-
this.deps.mailbox.wake()
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* 状态重广播:调度器收口(complete/cancel 等不经 processMessage 的终态迁移)
|
|
379
|
-
* 直接改动了本 agent 的队列上下文(current/completed),重新广播 agent.status,
|
|
380
|
-
* 前端实时反映 lead 判定完成后的最新状态(不刷新即可见)。
|
|
381
|
-
*/
|
|
382
|
-
refreshStatus(): void {
|
|
383
|
-
this.deps.bus.notifyAgent({ agentId: this.agentId, state: this.state, ...this.queueContext() })
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/** harness 进程资源信息(运行时资源监控;进程内 harness 无外部进程 → null) */
|
|
387
|
-
getProcessInfo(): { pid: number, alive: boolean, command: string } | null {
|
|
388
|
-
return this.impl.getProcessInfo?.() ?? null
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* 强制终止 harness 进程(不等优雅退出)。
|
|
393
|
-
* 调用方(manager terminateRuntimeProcess)终止后随即 stop 本运行时。
|
|
394
|
-
*/
|
|
395
|
-
killProcess(): void {
|
|
396
|
-
this.impl.killProcess?.()
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/** harness 进程存活校准(manager sweeper 周期性调用;休眠/强杀后校准 alive 失真;异常不抛出) */
|
|
400
|
-
reconcileProcess(): void {
|
|
401
|
-
try {
|
|
402
|
-
this.impl.reconcileProcess?.()
|
|
403
|
-
}
|
|
404
|
-
catch (err) {
|
|
405
|
-
log.error(`[AgentRuntime:${this.agentId}] 进程存活校准失败:`, err)
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/** 暴露 TaskEngine(供 SchedulerLoop 收集快照与执行调度决策) */
|
|
410
|
-
get taskEngine(): TaskEngine {
|
|
411
|
-
return this.deps.taskEngine
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/** 暴露 AgentWorkspace(供 SchedulerLoop 执行 lead 成员管理决策) */
|
|
415
|
-
get workspace(): AgentWorkspace {
|
|
416
|
-
return this.deps.workspace
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* lead 调度决策(供 SchedulerLoop 调用):转发 impl.supervise。
|
|
421
|
-
* 未实现 supervise 时返回 null(调用方回退内置规则引擎);
|
|
422
|
-
* 与 run 的互斥由调用方通过 withExecLock 保证。
|
|
423
|
-
*/
|
|
424
|
-
/** 当前 supervise 回合的控制器(abortCurrent 经此打断 LLM 调度回合) */
|
|
425
|
-
private superviseController: AbortController | null = null
|
|
426
|
-
|
|
427
|
-
async supervise(snapshot: SupervisionSnapshot): Promise<SupervisionDecision[] | null> {
|
|
428
|
-
if (!this.impl.supervise) return null
|
|
429
|
-
// lead 调度记忆:非终态/失败任务标题 + 成员名构造查询;touch:false 防 tick 通胀
|
|
430
|
-
let memoryBlock: string | undefined
|
|
431
|
-
try {
|
|
432
|
-
const query = [
|
|
433
|
-
...snapshot.tasks.filter(t => t.state === 'SUBMITTED' || t.state === 'FAILED' || t.state === 'WAITING').map(t => t.title),
|
|
434
|
-
...snapshot.members.map(m => m.name),
|
|
435
|
-
].join(' ')
|
|
436
|
-
memoryBlock = (await this.deps.memory?.recall(query, { touch: false })) ?? undefined
|
|
437
|
-
}
|
|
438
|
-
catch (err) {
|
|
439
|
-
log.error(`[AgentRuntime:${this.agentId}] supervise 记忆召回失败:`, err)
|
|
440
|
-
}
|
|
441
|
-
const controller = new AbortController()
|
|
442
|
-
this.superviseController = controller
|
|
443
|
-
const ctx: AgentRunContext = {
|
|
444
|
-
agentId: this.agentId,
|
|
445
|
-
channelId: this.channelId,
|
|
446
|
-
role: this.role,
|
|
447
|
-
workspace: this.deps.workspace,
|
|
448
|
-
signal: controller.signal,
|
|
449
|
-
memory: memoryBlock,
|
|
450
|
-
}
|
|
451
|
-
try {
|
|
452
|
-
return await this.impl.supervise(snapshot, ctx, { signal: controller.signal })
|
|
453
|
-
}
|
|
454
|
-
finally {
|
|
455
|
-
if (this.superviseController === controller) this.superviseController = null
|
|
456
|
-
// 调度回合落定:lead 的 supervise 是上下文膨胀大户,同样走 post-settle 压缩检查
|
|
457
|
-
this.maybePostSettle()
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
/**
|
|
462
|
-
* 平台侧任务记忆沉淀(调度器直接执行决策的收口路径):
|
|
463
|
-
* lead 经 supervise 决策 complete/cancel 任务时不经过 processMessage,
|
|
464
|
-
* 由 SchedulerLoop 调用此方法补齐终态 harvest(与 worker 路径同源)。
|
|
465
|
-
*/
|
|
466
|
-
async recordTaskMemory(task: WorkspaceTask): Promise<void> {
|
|
467
|
-
await this.deps.memory?.recordTaskOutcome(task)
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
/** run/supervise 互斥执行(promise 链;供消费循环与 SchedulerLoop 串行化) */
|
|
471
|
-
withExecLock<T>(fn: () => Promise<T>): Promise<T> {
|
|
472
|
-
const prev = this.execLock
|
|
473
|
-
let release!: () => void
|
|
474
|
-
this.execLock = new Promise<void>((r) => {
|
|
475
|
-
release = r
|
|
476
|
-
})
|
|
477
|
-
return (async () => {
|
|
478
|
-
await prev
|
|
479
|
-
try {
|
|
480
|
-
return await fn()
|
|
481
|
-
}
|
|
482
|
-
finally {
|
|
483
|
-
release()
|
|
484
|
-
}
|
|
485
|
-
})()
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/** 消费循环:空闲自动接取,执行中不打断 */
|
|
489
|
-
private async consumeLoop(): Promise<void> {
|
|
490
|
-
while (this.state !== 'stopped') {
|
|
491
|
-
const msg = await this.deps.mailbox.dequeue()
|
|
492
|
-
if (this.getState() === 'stopped' || msg === null) break
|
|
493
|
-
// 单条 run 抛错不阻塞下一条
|
|
494
|
-
try {
|
|
495
|
-
await this.withExecLock(() => this.processMessage(msg))
|
|
496
|
-
}
|
|
497
|
-
catch (err) {
|
|
498
|
-
log.error(`[AgentRuntime:${this.agentId}] run 失败:`, err)
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
private async processMessage(msg: A2AMessage): Promise<void> {
|
|
504
|
-
const taskId = this.taskIdOf(msg)
|
|
505
|
-
// 过期任务投递检查:任务已终态(cancel/reassign 后残留的旧 assign)→ 跳过执行,
|
|
506
|
-
// 否则 worker 会对着已取消任务的旧投递真的跑一轮 harness。
|
|
507
|
-
if (msg.metadata?.['x-aw-task-kind'] === 'assign' && taskId) {
|
|
508
|
-
const task = this.deps.taskEngine.get(taskId)
|
|
509
|
-
if (!task || TERMINAL_TASK_STATES[task.state]) {
|
|
510
|
-
this.deps.mailbox.markConsumed(msg.messageId)
|
|
511
|
-
return
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
this.state = 'busy'
|
|
515
|
-
this.currentTaskId = taskId ?? null
|
|
516
|
-
this.deps.bus.notifyAgent({ agentId: this.agentId, state: 'busy', ...this.queueContext() })
|
|
517
|
-
// 回合失败标记(须在 try 外声明,finally 依据它决定重投还是消费)
|
|
518
|
-
let sawRunError = false
|
|
519
|
-
try {
|
|
520
|
-
// 任务消息联动:assign → WORKING(自动接取;状态事件由 TaskEngine transition hooks 广播)
|
|
521
|
-
// 仅 SUBMITTED/ASSIGNED 自动接取:WAITING(已有子任务)的任务由 SchedulerLoop/子任务汇总推进,
|
|
522
|
-
// 此处不得把父任务从 WAITING 翻回 WORKING(否则父任务在子任务执行期间虚挂 WORKING,
|
|
523
|
-
// 会被 stall 检测误判为停滞而 cancel)。
|
|
524
|
-
if (msg.metadata?.['x-aw-task-kind'] === 'assign' && taskId) {
|
|
525
|
-
const task = this.deps.taskEngine.get(taskId)
|
|
526
|
-
if (task && (task.state === 'SUBMITTED' || task.state === 'ASSIGNED')) {
|
|
527
|
-
await this.deps.taskEngine.transition(taskId, 'WORKING', this.agentId)
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
// 每次 run 新建 AbortController;abort 后事件流终止
|
|
531
|
-
this.abortController = new AbortController()
|
|
532
|
-
// 记忆召回(异常不阻塞):查询=消息原文(title 首词天然显著)+ 任务关联加权
|
|
533
|
-
let memoryBlock: string | undefined
|
|
534
|
-
try {
|
|
535
|
-
memoryBlock = (await this.deps.memory?.recall(partsToText(msg.parts), {
|
|
536
|
-
relatedTaskIds: this.relatedTaskIdsOf(taskId),
|
|
537
|
-
})) ?? undefined
|
|
538
|
-
}
|
|
539
|
-
catch (err) {
|
|
540
|
-
log.error(`[AgentRuntime:${this.agentId}] 记忆召回失败:`, err)
|
|
541
|
-
}
|
|
542
|
-
const request: AgentRunRequest = this.toRequest(msg, memoryBlock)
|
|
543
|
-
const ctx: AgentRunContext = {
|
|
544
|
-
agentId: this.agentId,
|
|
545
|
-
channelId: msg.contextId,
|
|
546
|
-
role: this.role,
|
|
547
|
-
workspace: this.deps.workspace,
|
|
548
|
-
signal: this.abortController.signal,
|
|
549
|
-
}
|
|
550
|
-
// 补入产出者 agentId(monitor 据此归属事件;不改原 msg,用浅拷贝)
|
|
551
|
-
const enrichedSource = { ...msg, metadata: { ...msg.metadata, 'x-aw-producing-agent': this.agentId } }
|
|
552
|
-
// 回复文本收集(V9:omp 不产 message 事件,聚合三类源——message 事件 / status.message / 终态 artifact 'output')
|
|
553
|
-
let replyText = ''
|
|
554
|
-
const cap = (text: string): void => {
|
|
555
|
-
if (replyText.length < 400) replyText += text.slice(0, 400 - replyText.length)
|
|
556
|
-
}
|
|
557
|
-
try {
|
|
558
|
-
for await (const event of this.impl.run(request, ctx)) {
|
|
559
|
-
this.deps.bus.emit(event, enrichedSource)
|
|
560
|
-
// LLM 流式增量:只走事件流(AEP agent.delta),不进任务引擎/交付兜底管道
|
|
561
|
-
if (event.kind === 'delta') continue
|
|
562
|
-
if (event.kind === 'error') sawRunError = true
|
|
563
|
-
if (taskId) await this.deps.taskEngine.applyEvent(taskId, event)
|
|
564
|
-
if (event.kind === 'message') cap(partsToText(event.message.parts))
|
|
565
|
-
else if (event.kind === 'status' && event.status.message) cap(partsToText(event.status.message.parts))
|
|
566
|
-
else if (event.kind === 'artifact' && event.artifact.name === 'output') cap(partsToText(event.artifact.parts))
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
catch (err) {
|
|
570
|
-
// run 生成器抛错(如 omp 子进程 spawn 失败):按回合失败走重投,不外抛断循环
|
|
571
|
-
sawRunError = true
|
|
572
|
-
log.error(`[AgentRuntime:${this.agentId}] 回合异常:`, err)
|
|
573
|
-
}
|
|
574
|
-
// 交付兜底(harness 回合结束 ≠ 任务完成):
|
|
575
|
-
// - 回合产出过实质 artifact(LLM 完成了工作但跳过 complete_task 工具)→ 隐式完成,
|
|
576
|
-
// 交付物即回合规避的输出,平台代为收口(进度 100)。
|
|
577
|
-
// - 无任何产出(LLM 空转)→ FAILED 交给调度器 retry/reassign。
|
|
578
|
-
// 仅 worker 的 assign 执行消息生效:lead 由 supervise 协调;WAITING 父任务不属此列。
|
|
579
|
-
if (taskId && this.role === 'worker' && msg.metadata?.['x-aw-task-kind'] === 'assign') {
|
|
580
|
-
const after = this.deps.taskEngine.get(taskId)
|
|
581
|
-
if (after && after.assigneeId === this.agentId && after.state === 'WORKING') {
|
|
582
|
-
const deliverable = after.artifacts.find(a => a.name !== 'input' && a.parts.some(p => ('text' in p ? p.text.trim().length : 1) > 0))
|
|
583
|
-
if (deliverable) {
|
|
584
|
-
const completed = await this.deps.taskEngine.complete(taskId)
|
|
585
|
-
this.emitExternal({
|
|
586
|
-
kind: 'status',
|
|
587
|
-
status: {
|
|
588
|
-
state: 'COMPLETED',
|
|
589
|
-
message: {
|
|
590
|
-
messageId: randomUUID(),
|
|
591
|
-
contextId: this.channelId,
|
|
592
|
-
role: 'ROLE_AGENT',
|
|
593
|
-
parts: [{ text: `任务 ${taskId} 回合已产出交付物但未调用完成工具,平台隐式收口为 COMPLETED` }],
|
|
594
|
-
},
|
|
595
|
-
timestamp: new Date().toISOString(),
|
|
596
|
-
},
|
|
597
|
-
})
|
|
598
|
-
// 子任务隐式完成 → 通知父任务(lead 汇总/WAITING→WORKING 接续):
|
|
599
|
-
// 与 manager.completeTask 的显式收口同构,否则父任务 WAITING 永挂
|
|
600
|
-
// (无 child-completed 事件、父任务不翻转,lead 无感知)。
|
|
601
|
-
if (completed.parentId) {
|
|
602
|
-
this.deps.taskEngine.onChildCompleted(completed)
|
|
603
|
-
const parent = this.deps.taskEngine.get(completed.parentId)
|
|
604
|
-
if (parent) this.deps.bus.wakeScheduler()
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
else {
|
|
608
|
-
await this.deps.taskEngine.transition(taskId, 'FAILED', this.agentId)
|
|
609
|
-
this.emitExternal({
|
|
610
|
-
kind: 'status',
|
|
611
|
-
status: {
|
|
612
|
-
state: 'FAILED',
|
|
613
|
-
message: {
|
|
614
|
-
messageId: randomUUID(),
|
|
615
|
-
contextId: this.channelId,
|
|
616
|
-
role: 'ROLE_AGENT',
|
|
617
|
-
parts: [{ text: `任务 ${taskId} 执行结束但无交付(harness 回合结束未产出),标记 FAILED 待重试` }],
|
|
618
|
-
},
|
|
619
|
-
timestamp: new Date().toISOString(),
|
|
620
|
-
},
|
|
621
|
-
})
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
// 记忆沉淀:终态任务 harvest;无 taskId 的点对点消息记协作(异常不阻塞)
|
|
627
|
-
if (this.deps.memory) {
|
|
628
|
-
try {
|
|
629
|
-
const task = taskId ? this.deps.taskEngine.get(taskId) : undefined
|
|
630
|
-
if (task && TERMINAL_TASK_STATES[task.state]) {
|
|
631
|
-
await this.deps.memory.recordTaskOutcome(task)
|
|
632
|
-
}
|
|
633
|
-
else if (!taskId) {
|
|
634
|
-
const fromAgentId = (msg.metadata?.['x-aw-from-agent'] as string | undefined) ?? null
|
|
635
|
-
if (fromAgentId) await this.deps.memory.recordPeerExchange(msg, replyText)
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
catch (err) {
|
|
639
|
-
log.error(`[AgentRuntime:${this.agentId}] 记忆写入失败:`, err)
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
finally {
|
|
644
|
-
this.abortController = null
|
|
645
|
-
this.currentTaskId = null
|
|
646
|
-
if (this.state === 'busy') {
|
|
647
|
-
this.state = 'idle'
|
|
648
|
-
this.deps.bus.notifyAgent({ agentId: this.agentId, state: 'idle', ...this.queueContext() })
|
|
649
|
-
}
|
|
650
|
-
// 回合失败(harness 错误/停滞看门狗中止/子进程异常):重投消息而非静默消费,
|
|
651
|
-
// 内容不丢,重试回合(通常已是全新子进程)再处理;每消息最多重投 2 次防毒消息死循环。
|
|
652
|
-
// 任务已终态(取消/收口后 abort 让回合报错)则不再重投 —— 消息依任务终态
|
|
653
|
-
// 由调度器 reassign/新 assign 驱动,重投只会空转(启动即被终态检查消费)。
|
|
654
|
-
const taskNow = taskId ? this.deps.taskEngine.get(taskId) : undefined
|
|
655
|
-
const taskDone = !!taskNow && TERMINAL_TASK_STATES[taskNow.state]
|
|
656
|
-
if (sawRunError && !taskDone && (this.runErrorRetries.get(msg.messageId) ?? 0) < 2
|
|
657
|
-
&& this.deps.mailbox.requeue(msg.messageId)) {
|
|
658
|
-
const attempt = (this.runErrorRetries.get(msg.messageId) ?? 0) + 1
|
|
659
|
-
this.runErrorRetries.set(msg.messageId, attempt)
|
|
660
|
-
this.emitExternal({
|
|
661
|
-
kind: 'status',
|
|
662
|
-
status: {
|
|
663
|
-
state: 'WORKING',
|
|
664
|
-
message: {
|
|
665
|
-
messageId: randomUUID(),
|
|
666
|
-
contextId: this.channelId,
|
|
667
|
-
role: 'ROLE_AGENT',
|
|
668
|
-
parts: [{ text: `消息 ${msg.messageId.slice(0, 8)} 回合失败,已重投信箱待重试(第 ${attempt} 次)` }],
|
|
669
|
-
},
|
|
670
|
-
timestamp: new Date().toISOString(),
|
|
671
|
-
},
|
|
672
|
-
})
|
|
673
|
-
}
|
|
674
|
-
else {
|
|
675
|
-
this.runErrorRetries.delete(msg.messageId)
|
|
676
|
-
this.deps.mailbox.markConsumed(msg.messageId)
|
|
677
|
-
}
|
|
678
|
-
// 回合落定:信箱空 → 后台压缩检查(post-settle 路径;impl 自守卫不阻塞)
|
|
679
|
-
this.maybePostSettle()
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
/** 状态通知的队列上下文(实时:当前任务/待执行数/已完成数/harness 上下文用量) */
|
|
684
|
-
private queueContext(): Pick<AgentStatusView, 'currentTaskId' | 'currentTaskTitle' | 'currentTaskProgress' | 'queuedCount' | 'completedCount'> & { context?: AgentContextStats | null } {
|
|
685
|
-
const status = this.getStatus()
|
|
686
|
-
return {
|
|
687
|
-
currentTaskId: status.currentTaskId,
|
|
688
|
-
currentTaskTitle: status.currentTaskTitle,
|
|
689
|
-
currentTaskProgress: status.currentTaskProgress,
|
|
690
|
-
queuedCount: status.queuedCount,
|
|
691
|
-
completedCount: status.completedCount,
|
|
692
|
-
context: status.context ?? null,
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
/**
|
|
697
|
-
* 任务关联集(自身+父+兄弟,≤20):related-task boost 数据源。
|
|
698
|
-
* 同父兄弟任务的记忆(前几个子任务做了什么)在引子中必然置顶——
|
|
699
|
-
* 纯内存 id 判断,零检索开销。
|
|
700
|
-
*/
|
|
701
|
-
private relatedTaskIdsOf(taskId: string | undefined): string[] | undefined {
|
|
702
|
-
if (!taskId) return undefined
|
|
703
|
-
const task = this.deps.taskEngine.get(taskId)
|
|
704
|
-
if (!task) return undefined
|
|
705
|
-
const ids = new Set<string>([taskId])
|
|
706
|
-
if (task.parentId) {
|
|
707
|
-
ids.add(task.parentId)
|
|
708
|
-
for (const t of this.deps.taskEngine.list(this.channelId)) {
|
|
709
|
-
if (t.parentId === task.parentId) ids.add(t.id)
|
|
710
|
-
if (ids.size >= 20) break
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
return [...ids]
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
/**
|
|
717
|
-
* post-settle 压缩检查:仅信箱无排队消息时触发(排队消息的 pre-prompt gate 兜底)。
|
|
718
|
-
* impl 自守卫(回合间隙才压缩、异常不抛出);本方法自身也不阻塞消费循环。
|
|
719
|
-
*/
|
|
720
|
-
private maybePostSettle(): void {
|
|
721
|
-
if (!this.impl.onTurnSettled) return
|
|
722
|
-
void this.deps.mailbox.peek(1)
|
|
723
|
-
.then((pending) => {
|
|
724
|
-
if (pending.length > 0) return undefined
|
|
725
|
-
return this.impl.onTurnSettled?.()
|
|
726
|
-
})
|
|
727
|
-
.catch(() => {})
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
private toRequest(msg: A2AMessage, memory?: string): AgentRunRequest {
|
|
731
|
-
return {
|
|
732
|
-
message: msg,
|
|
733
|
-
taskId: msg.taskId,
|
|
734
|
-
contextId: msg.contextId,
|
|
735
|
-
fromAgentId: (msg.metadata?.['x-aw-from-agent'] as string | undefined) ?? null,
|
|
736
|
-
toAgentId: this.agentId,
|
|
737
|
-
memory,
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
private taskIdOf(msg: A2AMessage): string | undefined {
|
|
742
|
-
return msg.taskId ?? (msg.metadata?.['x-aw-task-id'] as string | undefined)
|
|
743
|
-
}
|
|
744
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* AgentRuntime — Agent 独立运行时对象。
|
|
3
|
+
* 状态机 idle/busy/stopped + 消费循环(自动接取/自动作业)+ run/supervise 互斥 + abort。
|
|
4
|
+
* 任务管理系统:每个运行时对自己的任务队列(待执行 FIFO / 执行中 / 已完成)有完整视图;
|
|
5
|
+
* 队列是 tasks 表的派生投影(DB 唯一事实源),状态迁移实时广播(idle/busy + 队列上下文)。
|
|
6
|
+
*/
|
|
7
|
+
import { createLogger } from '../logger'
|
|
8
|
+
import { randomUUID } from 'node:crypto'
|
|
9
|
+
import type {
|
|
10
|
+
AgentEvent,
|
|
11
|
+
AgentInfo,
|
|
12
|
+
AgentInterface,
|
|
13
|
+
AgentRunContext,
|
|
14
|
+
AgentRunRequest,
|
|
15
|
+
AgentWorkspace,
|
|
16
|
+
SupervisionDecision,
|
|
17
|
+
SupervisionSnapshot,
|
|
18
|
+
} from '../agents/agent-interface'
|
|
19
|
+
import type { A2AMessage, A2AArtifact, Part } from '../types/a2a'
|
|
20
|
+
import type { AgentContextStats, AgentStatusView, AgentTaskQueueView, TaskState, WorkspaceTask } from '../types/task'
|
|
21
|
+
import { TERMINAL_TASK_STATES } from '../types/task'
|
|
22
|
+
import type { AgentMemory } from './memory'
|
|
23
|
+
import type { Mailbox } from './mailbox'
|
|
24
|
+
|
|
25
|
+
const log = createLogger('workshop.agent-runtime')
|
|
26
|
+
|
|
27
|
+
/** ChannelBus:运行时事件总线(逐事件广播 + 任务/成员事件通知 + 调度唤醒) */
|
|
28
|
+
/** 任务变更事件携带的源头任务视图(WS 推送免 per-event 回查;WorkspaceTask 结构兼容) */
|
|
29
|
+
export interface TaskEventTask {
|
|
30
|
+
id: string
|
|
31
|
+
title?: string
|
|
32
|
+
parentId?: string
|
|
33
|
+
assigneeId?: string
|
|
34
|
+
progress?: number | null
|
|
35
|
+
routeReason?: string
|
|
36
|
+
createdAt: string
|
|
37
|
+
artifacts?: unknown[]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ChannelBus {
|
|
41
|
+
/** AgentEvent 流式广播:所有 harness 的统一事件出口(自定义协议流) */
|
|
42
|
+
emit(event: AgentEvent, source: A2AMessage): void
|
|
43
|
+
/** 订阅 AgentEvent 流(monitor/WS 消费);返回退订函数 */
|
|
44
|
+
onEvent(fn: (event: AgentEvent, source: A2AMessage) => void): () => void
|
|
45
|
+
/** 任务事件通知(状态迁移/进度变化;由 TaskEngine hooks 统一触发;task = 源头视图) */
|
|
46
|
+
notifyTask(e: { taskId: string, state?: TaskState, progress?: number, agentId?: string, task?: TaskEventTask }): void
|
|
47
|
+
onTaskEvent(fn: (e: { taskId: string, state?: TaskState, progress?: number, agentId?: string, task?: TaskEventTask }) => void): () => void
|
|
48
|
+
/**
|
|
49
|
+
* 成员状态通知(idle/busy/stopped + 队列上下文;AgentRuntime 转换处触发,事件驱动无轮询)。
|
|
50
|
+
* currentTaskId/currentTaskTitle/currentTaskProgress/queuedCount/completedCount
|
|
51
|
+
* 为增量字段:实时状态追踪的完整视图(lead 观察 worker 进度,防"在跑但无信号")。
|
|
52
|
+
*/
|
|
53
|
+
notifyAgent(e: {
|
|
54
|
+
agentId: string
|
|
55
|
+
state: 'idle' | 'busy' | 'stopped'
|
|
56
|
+
currentTaskId?: string | null
|
|
57
|
+
currentTaskTitle?: string | null
|
|
58
|
+
currentTaskProgress?: number | null
|
|
59
|
+
queuedCount?: number
|
|
60
|
+
completedCount?: number
|
|
61
|
+
/** harness 上下文用量(omp 有;进程内 harness 缺省) */
|
|
62
|
+
context?: AgentContextStats | null
|
|
63
|
+
}): void
|
|
64
|
+
onAgentStatus(fn: (e: {
|
|
65
|
+
agentId: string
|
|
66
|
+
state: 'idle' | 'busy' | 'stopped'
|
|
67
|
+
currentTaskId?: string | null
|
|
68
|
+
currentTaskTitle?: string | null
|
|
69
|
+
currentTaskProgress?: number | null
|
|
70
|
+
queuedCount?: number
|
|
71
|
+
completedCount?: number
|
|
72
|
+
context?: AgentContextStats | null
|
|
73
|
+
}) => void): () => void
|
|
74
|
+
/** channel 内消息投递通知(route 汇流点触发;AEP a2a.message 事件源) */
|
|
75
|
+
notifyMessage(message: A2AMessage): void
|
|
76
|
+
onMessage(fn: (message: A2AMessage) => void): () => void
|
|
77
|
+
/** 团队成员增/改/删通知(lead 自主管理或用户 REST;AEP agent.member 事件源) */
|
|
78
|
+
notifyMember(e: MemberChangeEvent): void
|
|
79
|
+
onMemberEvent(fn: (e: MemberChangeEvent) => void): () => void
|
|
80
|
+
/** 记忆写入通知(策展/主动沉淀;AEP memory.saved 事件源) */
|
|
81
|
+
notifyMemory(e: { agentId: string, scope: 'private' | 'shared', title: string, dedupKey: string }): void
|
|
82
|
+
onMemoryEvent(fn: (e: { agentId: string, scope: 'private' | 'shared', title: string, dedupKey: string }) => void): () => void
|
|
83
|
+
wakeScheduler(): void
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** 团队成员变更事件(lead 执行中自主管理成员或用户 REST 操作;AEP agent.member 载荷) */
|
|
87
|
+
export interface MemberChangeEvent {
|
|
88
|
+
op: 'added' | 'updated' | 'removed'
|
|
89
|
+
agentId: string
|
|
90
|
+
name: string
|
|
91
|
+
role: 'lead' | 'worker'
|
|
92
|
+
harness: string
|
|
93
|
+
enabled?: number
|
|
94
|
+
/** 实例 config(含 systemPromptPrefix 场景提示词;added/updated 时携带,removed 可空) */
|
|
95
|
+
config?: Record<string, unknown>
|
|
96
|
+
/** 操作发起方:'lead:<agentId>' 或 'user' */
|
|
97
|
+
by: string
|
|
98
|
+
reason?: string
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Parts → 纯文本(text 片段拼接;记忆召回查询与回复收集共用) */
|
|
102
|
+
function partsToText(parts: Part[]): string {
|
|
103
|
+
return parts.map(p => ('text' in p ? p.text : '')).filter(Boolean).join('\n')
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* TaskEngine 结构契约(实现方 T4 task-engine.ts,同步签名)。
|
|
108
|
+
* 以接口而非具体类声明依赖,便于测试注入 fake 与集成装配真实引擎。
|
|
109
|
+
*/
|
|
110
|
+
export interface TaskEngine {
|
|
111
|
+
create(input: {
|
|
112
|
+
channelId: string
|
|
113
|
+
creatorId: string
|
|
114
|
+
assigneeId: string
|
|
115
|
+
title: string
|
|
116
|
+
description?: string
|
|
117
|
+
parentId?: string
|
|
118
|
+
parts?: Part[]
|
|
119
|
+
}): WorkspaceTask
|
|
120
|
+
dispatch(
|
|
121
|
+
parent: WorkspaceTask,
|
|
122
|
+
input: { assigneeId: string, title: string, description?: string, parts?: Part[], routeReason?: string },
|
|
123
|
+
): WorkspaceTask
|
|
124
|
+
transition(taskId: string, state: TaskState, by: string): WorkspaceTask
|
|
125
|
+
applyEvent(taskId: string, event: AgentEvent): void
|
|
126
|
+
list(channelId: string): WorkspaceTask[]
|
|
127
|
+
get(taskId: string): WorkspaceTask | undefined
|
|
128
|
+
complete(taskId: string, artifacts?: A2AArtifact[]): WorkspaceTask
|
|
129
|
+
reassign(taskId: string, toAgentId: string): WorkspaceTask
|
|
130
|
+
/** 修改待执行任务(title/description)+ 刷新 assignee 队列投递 */
|
|
131
|
+
updateTask(taskId: string, patch: { title?: string, description?: string }, by: string): WorkspaceTask
|
|
132
|
+
cancel(taskId: string, by: string): WorkspaceTask
|
|
133
|
+
onChildCompleted(child: WorkspaceTask): void
|
|
134
|
+
/** 断线重连重投:非终态任务无 pending assign 时向 assignee 重发(restore 用) */
|
|
135
|
+
redeliverAssign(taskId: string): WorkspaceTask
|
|
136
|
+
/** 单 agent 任务队列视图(待执行 FIFO / 执行中 / 已完成) */
|
|
137
|
+
queueViewOf(channelId: string, agentId: string): AgentTaskQueueView
|
|
138
|
+
/** 批量队列视图(一次查询聚合全 channel;调度快照热路径) */
|
|
139
|
+
queueViewsOf(channelId: string): Map<string, AgentTaskQueueView>
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* AgentRuntime 的结构契约(ChannelRuntime/SchedulerLoop 消费的最小接口)。
|
|
144
|
+
*/
|
|
145
|
+
export interface AgentRuntimeLike {
|
|
146
|
+
readonly agentId: string
|
|
147
|
+
readonly role: 'lead' | 'worker'
|
|
148
|
+
readonly channelId: string
|
|
149
|
+
readonly name: string
|
|
150
|
+
enqueue(message: A2AMessage): void
|
|
151
|
+
getState(): 'idle' | 'busy' | 'stopped'
|
|
152
|
+
/** 实时状态视图(idle/busy/stopped + 当前任务 + 队列长度) */
|
|
153
|
+
getStatus(): AgentStatusView
|
|
154
|
+
/** 本 agent 的任务队列视图(待执行 FIFO / 执行中 / 已完成) */
|
|
155
|
+
getQueueView(): AgentTaskQueueView
|
|
156
|
+
abortCurrent(): void
|
|
157
|
+
wakeMailbox(): void
|
|
158
|
+
stop(): Promise<void>
|
|
159
|
+
/** 平台侧合成事件出口(如 SchedulerLoop 汇总成果);转发 ChannelBus.emit 走统一事件流 */
|
|
160
|
+
emitExternal(event: AgentEvent, fromAgentId?: string): void
|
|
161
|
+
/** 实时消息注入:busy 时通过 impl.steer 注入 omp 会话;idle 时入 mailbox 队列 */
|
|
162
|
+
injectSteer(message: A2AMessage): void
|
|
163
|
+
/** Agent 能力面(调度器执行成员管理决策用;AgentRuntime 始终提供) */
|
|
164
|
+
readonly workspace?: AgentWorkspace
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export class AgentRuntime {
|
|
168
|
+
readonly agentId: string
|
|
169
|
+
readonly role: 'lead' | 'worker'
|
|
170
|
+
readonly channelId: string
|
|
171
|
+
readonly name: string
|
|
172
|
+
private state: 'idle' | 'busy' | 'stopped' = 'idle'
|
|
173
|
+
/** 回合失败重投计数(每消息;进程内存,重启由 resetConsuming 重新给机会) */
|
|
174
|
+
private runErrorRetries = new Map<string, number>()
|
|
175
|
+
/** 正在执行的任务 id(run 期间;空闲时 null) */
|
|
176
|
+
private currentTaskId: string | null = null
|
|
177
|
+
/** poll_messages 阻塞等待数(waitPending 活动计数;>0 = 有轮询在等,实时消息留信箱由其取走) */
|
|
178
|
+
private pollWaiters = 0
|
|
179
|
+
/** run 与 supervise 互斥锁(promise 链) */
|
|
180
|
+
private execLock: Promise<void> = Promise.resolve()
|
|
181
|
+
private abortController: AbortController | null = null
|
|
182
|
+
private loopPromise: Promise<void> | null = null
|
|
183
|
+
private started = false
|
|
184
|
+
|
|
185
|
+
constructor(
|
|
186
|
+
agent: AgentInfo,
|
|
187
|
+
private impl: AgentInterface,
|
|
188
|
+
private deps: {
|
|
189
|
+
mailbox: Mailbox
|
|
190
|
+
taskEngine: TaskEngine
|
|
191
|
+
bus: ChannelBus
|
|
192
|
+
workspace: AgentWorkspace
|
|
193
|
+
memory?: AgentMemory
|
|
194
|
+
},
|
|
195
|
+
) {
|
|
196
|
+
this.agentId = agent.id
|
|
197
|
+
this.role = agent.role
|
|
198
|
+
this.channelId = agent.channelId
|
|
199
|
+
this.name = agent.name
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** 投递消息;idle 时立即唤醒消费 */
|
|
203
|
+
enqueue(message: A2AMessage): void {
|
|
204
|
+
this.deps.mailbox.enqueue(message)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
getState(): 'idle' | 'busy' | 'stopped' {
|
|
208
|
+
return this.state
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** 实时状态视图:idle/busy/stopped + 当前任务 + 队列 + harness 上下文用量 */
|
|
212
|
+
getStatus(): AgentStatusView {
|
|
213
|
+
const queue = this.getQueueView()
|
|
214
|
+
const current = queue.current ?? (this.currentTaskId ? this.deps.taskEngine.get(this.currentTaskId) : undefined)
|
|
215
|
+
const context = this.impl.getContextStats?.() ?? undefined
|
|
216
|
+
return {
|
|
217
|
+
agentId: this.agentId,
|
|
218
|
+
channelId: this.channelId,
|
|
219
|
+
role: this.role,
|
|
220
|
+
name: this.name,
|
|
221
|
+
state: this.state,
|
|
222
|
+
currentTaskId: current?.id ?? null,
|
|
223
|
+
// 进度/标题透出:lead 观察 worker 是否在推进(progress 空闲/未上报时为 null)
|
|
224
|
+
currentTaskTitle: current?.title ?? null,
|
|
225
|
+
currentTaskProgress: current?.progress != null ? current.progress : null,
|
|
226
|
+
queuedCount: queue.queued.length,
|
|
227
|
+
completedCount: queue.completed.length,
|
|
228
|
+
...(context ? { context } : {}),
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** 本 agent 的任务队列视图(自己的任务管理系统:待执行 FIFO / 执行中 / 已完成) */
|
|
233
|
+
getQueueView(): AgentTaskQueueView {
|
|
234
|
+
return this.deps.taskEngine.queueViewOf(this.channelId, this.agentId)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** 中止当前 run(任务取消/Agent 移除时);空闲时无操作 */
|
|
238
|
+
abortCurrent(): void {
|
|
239
|
+
log.warn(`[AgentRuntime:${this.agentId}] abortCurrent 调用(state=${this.state})`)
|
|
240
|
+
this.abortController?.abort()
|
|
241
|
+
// supervise 回合同样可打断(调度器 cancel 路径 → LLM 回合真中止)
|
|
242
|
+
this.superviseController?.abort()
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
emitExternal(event: AgentEvent, fromAgentId?: string): void {
|
|
246
|
+
// 合成 source(monitor 依 metadata 归属 agent);平台侧产出与 harness 事件同流
|
|
247
|
+
const source: A2AMessage = {
|
|
248
|
+
messageId: randomUUID(),
|
|
249
|
+
contextId: this.channelId,
|
|
250
|
+
role: 'ROLE_AGENT',
|
|
251
|
+
parts: [],
|
|
252
|
+
metadata: { 'x-aw-from-agent': fromAgentId ?? this.agentId },
|
|
253
|
+
}
|
|
254
|
+
this.deps.bus.emit(event, source)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* 实时注入策略(信箱优先,与主动轮询完全兼容):
|
|
259
|
+
* - poll_messages 等待中:任何实时消息留在 pending —— 等待中的轮询经 Mailbox
|
|
260
|
+
* 到信回调毫秒级取走(读即取=已读),零打断、不与轮询竞争唯一所有权
|
|
261
|
+
* - agent 间协作消息(from-agent):同样走信箱 —— turn 结束后消费循环按 peer
|
|
262
|
+
* 回合处理(require_reply 触发语义/回执关联完整)。steer 注入 omp 会话会让
|
|
263
|
+
* 其把排队消息后的工具调用标记 "Skipped due to queued user message",
|
|
264
|
+
* 中断 poll_messages 长等待并污染执行流(实测故障源)
|
|
265
|
+
* - 仅人类紧急直发(immediate + from-label,无 from-agent)保留 steer 同轮注入:
|
|
266
|
+
* 紧急人工打断是唯一值得中断会话的场景
|
|
267
|
+
*/
|
|
268
|
+
injectSteer(message: A2AMessage): void {
|
|
269
|
+
if (this.state !== 'busy' || !this.impl.steer) return
|
|
270
|
+
// ① 轮询等待中:留 pending 给 poll_messages(毫秒级取走并标记已读)
|
|
271
|
+
if (this.pollWaiters > 0) return
|
|
272
|
+
// ② agent 间协作消息:信箱优先(turn 结束 peer 回合处理)
|
|
273
|
+
const from = message.metadata?.['x-aw-from-agent']
|
|
274
|
+
if (typeof from === 'string' && from.length > 0) return
|
|
275
|
+
// ③ 其余(人类紧急直发):原有 steer 注入路径
|
|
276
|
+
if (!this.deps.mailbox.claim(message.messageId)) return
|
|
277
|
+
const text = message.parts
|
|
278
|
+
.map((p) => {
|
|
279
|
+
if ('text' in p) return p.text
|
|
280
|
+
if ('data' in p) return JSON.stringify(p.data)
|
|
281
|
+
return ''
|
|
282
|
+
})
|
|
283
|
+
.join('\n')
|
|
284
|
+
const fromId = (message.metadata?.['x-aw-from-agent'] as string | undefined) ?? 'system'
|
|
285
|
+
const lines = [`[实时消息 from ${fromId}]: ${text}`]
|
|
286
|
+
if (message.metadata?.['x-aw-require-reply'] === 'true') {
|
|
287
|
+
lines.push(
|
|
288
|
+
`[系统触发器] 本消息要求回复(reply_to=${message.messageId})。`,
|
|
289
|
+
`请处理消息中的需求,随后用 send_message_to_agent 回复发送者 ${fromId}:`,
|
|
290
|
+
`参数 message=执行结果+对方所需内容, in_reply_to=${message.messageId},`,
|
|
291
|
+
`require_reply=仅当你还需要对方进一步响应时才设 true。`,
|
|
292
|
+
)
|
|
293
|
+
}
|
|
294
|
+
this.impl.steer(lines.join('\n'))
|
|
295
|
+
.then((mode) => {
|
|
296
|
+
if (mode === 'steer') {
|
|
297
|
+
// 确认注入流式会话 → 消费落定(at-least-once:进程崩溃由 resetConsuming 兜底)
|
|
298
|
+
this.deps.mailbox.markConsumed(message.messageId)
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
// deferred:释放认领回 pending,poll_messages(250ms 兜底重查)或
|
|
302
|
+
// 本回合结束后的消费循环(FIFO)接管,消息必达不丢失
|
|
303
|
+
this.releaseSteerClaim(message.messageId)
|
|
304
|
+
}
|
|
305
|
+
})
|
|
306
|
+
.catch((err) => {
|
|
307
|
+
log.error(`[AgentRuntime:${this.agentId}] steer 失败(释放认领回 pending 待循环处理):`, err)
|
|
308
|
+
this.releaseSteerClaim(message.messageId)
|
|
309
|
+
})
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** 释放 steer 认领:consuming → pending + 唤醒 dequeue 门闩与到信等待方 */
|
|
313
|
+
private releaseSteerClaim(messageId: string): void {
|
|
314
|
+
if (this.deps.mailbox.requeue(messageId)) {
|
|
315
|
+
this.deps.mailbox.wake()
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* 长轮询未消费消息(poll_messages host 工具用):
|
|
321
|
+
* 250ms 兜底重查 + Mailbox 到信回调即时唤醒——消息到达后毫秒级返回,
|
|
322
|
+
* 不再每秒盲查。不改消息状态(peek 只读);消费语义由调用方(poll 读即取)决定。
|
|
323
|
+
* pollWaiters 计数暴露"轮询等待中"状态:injectSteer 据此把实时消息留在信箱
|
|
324
|
+
* 由本方法取走(不打断会话、与主动轮询兼容)。
|
|
325
|
+
*/
|
|
326
|
+
async waitPending(limit: number, waitMs: number): Promise<A2AMessage[]> {
|
|
327
|
+
this.pollWaiters += 1
|
|
328
|
+
try {
|
|
329
|
+
const deadline = Date.now() + Math.max(0, waitMs)
|
|
330
|
+
for (;;) {
|
|
331
|
+
const msgs = await this.deps.mailbox.peek(limit)
|
|
332
|
+
if (msgs.length > 0 || Date.now() >= deadline) return msgs
|
|
333
|
+
const { promise, resolve } = Promise.withResolvers<unknown>()
|
|
334
|
+
const off = this.deps.mailbox.onArrival(() => resolve(undefined))
|
|
335
|
+
const timer = setTimeout(() => resolve(undefined), 250)
|
|
336
|
+
await promise
|
|
337
|
+
clearTimeout(timer)
|
|
338
|
+
off()
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
finally {
|
|
342
|
+
this.pollWaiters -= 1
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** 启动消费循环 */
|
|
347
|
+
start(): void {
|
|
348
|
+
if (this.started) return
|
|
349
|
+
this.started = true
|
|
350
|
+
this.state = 'idle'
|
|
351
|
+
this.loopPromise = this.consumeLoop()
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/** 停止:中断当前 run + 等当前事件流结束 + dispose impl(杀子进程等) */
|
|
355
|
+
async stop(): Promise<void> {
|
|
356
|
+
log.warn(`[AgentRuntime:${this.agentId}] runtime.stop() 调用(卸载/停用)`)
|
|
357
|
+
this.state = 'stopped'
|
|
358
|
+
this.abortController?.abort()
|
|
359
|
+
this.deps.mailbox.close()
|
|
360
|
+
// 状态广播:前端经 WS agent.status 实时反映 stopped
|
|
361
|
+
this.deps.bus.notifyAgent({ agentId: this.agentId, state: 'stopped', ...this.queueContext() })
|
|
362
|
+
await this.loopPromise
|
|
363
|
+
// 清理 impl 持有的资源(omp 子进程等);容错:impl.dispose 可能不存在
|
|
364
|
+
try {
|
|
365
|
+
await this.impl.dispose?.()
|
|
366
|
+
}
|
|
367
|
+
catch (err) {
|
|
368
|
+
log.error(`[AgentRuntime:${this.agentId}] dispose 失败:`, err)
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** 唤醒 mailbox(供 manager 在 taskEngine 直接落库投递后唤醒消费) */
|
|
373
|
+
wakeMailbox(): void {
|
|
374
|
+
this.deps.mailbox.wake()
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* 状态重广播:调度器收口(complete/cancel 等不经 processMessage 的终态迁移)
|
|
379
|
+
* 直接改动了本 agent 的队列上下文(current/completed),重新广播 agent.status,
|
|
380
|
+
* 前端实时反映 lead 判定完成后的最新状态(不刷新即可见)。
|
|
381
|
+
*/
|
|
382
|
+
refreshStatus(): void {
|
|
383
|
+
this.deps.bus.notifyAgent({ agentId: this.agentId, state: this.state, ...this.queueContext() })
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/** harness 进程资源信息(运行时资源监控;进程内 harness 无外部进程 → null) */
|
|
387
|
+
getProcessInfo(): { pid: number, alive: boolean, command: string } | null {
|
|
388
|
+
return this.impl.getProcessInfo?.() ?? null
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* 强制终止 harness 进程(不等优雅退出)。
|
|
393
|
+
* 调用方(manager terminateRuntimeProcess)终止后随即 stop 本运行时。
|
|
394
|
+
*/
|
|
395
|
+
killProcess(): void {
|
|
396
|
+
this.impl.killProcess?.()
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/** harness 进程存活校准(manager sweeper 周期性调用;休眠/强杀后校准 alive 失真;异常不抛出) */
|
|
400
|
+
reconcileProcess(): void {
|
|
401
|
+
try {
|
|
402
|
+
this.impl.reconcileProcess?.()
|
|
403
|
+
}
|
|
404
|
+
catch (err) {
|
|
405
|
+
log.error(`[AgentRuntime:${this.agentId}] 进程存活校准失败:`, err)
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/** 暴露 TaskEngine(供 SchedulerLoop 收集快照与执行调度决策) */
|
|
410
|
+
get taskEngine(): TaskEngine {
|
|
411
|
+
return this.deps.taskEngine
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/** 暴露 AgentWorkspace(供 SchedulerLoop 执行 lead 成员管理决策) */
|
|
415
|
+
get workspace(): AgentWorkspace {
|
|
416
|
+
return this.deps.workspace
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* lead 调度决策(供 SchedulerLoop 调用):转发 impl.supervise。
|
|
421
|
+
* 未实现 supervise 时返回 null(调用方回退内置规则引擎);
|
|
422
|
+
* 与 run 的互斥由调用方通过 withExecLock 保证。
|
|
423
|
+
*/
|
|
424
|
+
/** 当前 supervise 回合的控制器(abortCurrent 经此打断 LLM 调度回合) */
|
|
425
|
+
private superviseController: AbortController | null = null
|
|
426
|
+
|
|
427
|
+
async supervise(snapshot: SupervisionSnapshot): Promise<SupervisionDecision[] | null> {
|
|
428
|
+
if (!this.impl.supervise) return null
|
|
429
|
+
// lead 调度记忆:非终态/失败任务标题 + 成员名构造查询;touch:false 防 tick 通胀
|
|
430
|
+
let memoryBlock: string | undefined
|
|
431
|
+
try {
|
|
432
|
+
const query = [
|
|
433
|
+
...snapshot.tasks.filter(t => t.state === 'SUBMITTED' || t.state === 'FAILED' || t.state === 'WAITING').map(t => t.title),
|
|
434
|
+
...snapshot.members.map(m => m.name),
|
|
435
|
+
].join(' ')
|
|
436
|
+
memoryBlock = (await this.deps.memory?.recall(query, { touch: false })) ?? undefined
|
|
437
|
+
}
|
|
438
|
+
catch (err) {
|
|
439
|
+
log.error(`[AgentRuntime:${this.agentId}] supervise 记忆召回失败:`, err)
|
|
440
|
+
}
|
|
441
|
+
const controller = new AbortController()
|
|
442
|
+
this.superviseController = controller
|
|
443
|
+
const ctx: AgentRunContext = {
|
|
444
|
+
agentId: this.agentId,
|
|
445
|
+
channelId: this.channelId,
|
|
446
|
+
role: this.role,
|
|
447
|
+
workspace: this.deps.workspace,
|
|
448
|
+
signal: controller.signal,
|
|
449
|
+
memory: memoryBlock,
|
|
450
|
+
}
|
|
451
|
+
try {
|
|
452
|
+
return await this.impl.supervise(snapshot, ctx, { signal: controller.signal })
|
|
453
|
+
}
|
|
454
|
+
finally {
|
|
455
|
+
if (this.superviseController === controller) this.superviseController = null
|
|
456
|
+
// 调度回合落定:lead 的 supervise 是上下文膨胀大户,同样走 post-settle 压缩检查
|
|
457
|
+
this.maybePostSettle()
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* 平台侧任务记忆沉淀(调度器直接执行决策的收口路径):
|
|
463
|
+
* lead 经 supervise 决策 complete/cancel 任务时不经过 processMessage,
|
|
464
|
+
* 由 SchedulerLoop 调用此方法补齐终态 harvest(与 worker 路径同源)。
|
|
465
|
+
*/
|
|
466
|
+
async recordTaskMemory(task: WorkspaceTask): Promise<void> {
|
|
467
|
+
await this.deps.memory?.recordTaskOutcome(task)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/** run/supervise 互斥执行(promise 链;供消费循环与 SchedulerLoop 串行化) */
|
|
471
|
+
withExecLock<T>(fn: () => Promise<T>): Promise<T> {
|
|
472
|
+
const prev = this.execLock
|
|
473
|
+
let release!: () => void
|
|
474
|
+
this.execLock = new Promise<void>((r) => {
|
|
475
|
+
release = r
|
|
476
|
+
})
|
|
477
|
+
return (async () => {
|
|
478
|
+
await prev
|
|
479
|
+
try {
|
|
480
|
+
return await fn()
|
|
481
|
+
}
|
|
482
|
+
finally {
|
|
483
|
+
release()
|
|
484
|
+
}
|
|
485
|
+
})()
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/** 消费循环:空闲自动接取,执行中不打断 */
|
|
489
|
+
private async consumeLoop(): Promise<void> {
|
|
490
|
+
while (this.state !== 'stopped') {
|
|
491
|
+
const msg = await this.deps.mailbox.dequeue()
|
|
492
|
+
if (this.getState() === 'stopped' || msg === null) break
|
|
493
|
+
// 单条 run 抛错不阻塞下一条
|
|
494
|
+
try {
|
|
495
|
+
await this.withExecLock(() => this.processMessage(msg))
|
|
496
|
+
}
|
|
497
|
+
catch (err) {
|
|
498
|
+
log.error(`[AgentRuntime:${this.agentId}] run 失败:`, err)
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
private async processMessage(msg: A2AMessage): Promise<void> {
|
|
504
|
+
const taskId = this.taskIdOf(msg)
|
|
505
|
+
// 过期任务投递检查:任务已终态(cancel/reassign 后残留的旧 assign)→ 跳过执行,
|
|
506
|
+
// 否则 worker 会对着已取消任务的旧投递真的跑一轮 harness。
|
|
507
|
+
if (msg.metadata?.['x-aw-task-kind'] === 'assign' && taskId) {
|
|
508
|
+
const task = this.deps.taskEngine.get(taskId)
|
|
509
|
+
if (!task || TERMINAL_TASK_STATES[task.state]) {
|
|
510
|
+
this.deps.mailbox.markConsumed(msg.messageId)
|
|
511
|
+
return
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
this.state = 'busy'
|
|
515
|
+
this.currentTaskId = taskId ?? null
|
|
516
|
+
this.deps.bus.notifyAgent({ agentId: this.agentId, state: 'busy', ...this.queueContext() })
|
|
517
|
+
// 回合失败标记(须在 try 外声明,finally 依据它决定重投还是消费)
|
|
518
|
+
let sawRunError = false
|
|
519
|
+
try {
|
|
520
|
+
// 任务消息联动:assign → WORKING(自动接取;状态事件由 TaskEngine transition hooks 广播)
|
|
521
|
+
// 仅 SUBMITTED/ASSIGNED 自动接取:WAITING(已有子任务)的任务由 SchedulerLoop/子任务汇总推进,
|
|
522
|
+
// 此处不得把父任务从 WAITING 翻回 WORKING(否则父任务在子任务执行期间虚挂 WORKING,
|
|
523
|
+
// 会被 stall 检测误判为停滞而 cancel)。
|
|
524
|
+
if (msg.metadata?.['x-aw-task-kind'] === 'assign' && taskId) {
|
|
525
|
+
const task = this.deps.taskEngine.get(taskId)
|
|
526
|
+
if (task && (task.state === 'SUBMITTED' || task.state === 'ASSIGNED')) {
|
|
527
|
+
await this.deps.taskEngine.transition(taskId, 'WORKING', this.agentId)
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
// 每次 run 新建 AbortController;abort 后事件流终止
|
|
531
|
+
this.abortController = new AbortController()
|
|
532
|
+
// 记忆召回(异常不阻塞):查询=消息原文(title 首词天然显著)+ 任务关联加权
|
|
533
|
+
let memoryBlock: string | undefined
|
|
534
|
+
try {
|
|
535
|
+
memoryBlock = (await this.deps.memory?.recall(partsToText(msg.parts), {
|
|
536
|
+
relatedTaskIds: this.relatedTaskIdsOf(taskId),
|
|
537
|
+
})) ?? undefined
|
|
538
|
+
}
|
|
539
|
+
catch (err) {
|
|
540
|
+
log.error(`[AgentRuntime:${this.agentId}] 记忆召回失败:`, err)
|
|
541
|
+
}
|
|
542
|
+
const request: AgentRunRequest = this.toRequest(msg, memoryBlock)
|
|
543
|
+
const ctx: AgentRunContext = {
|
|
544
|
+
agentId: this.agentId,
|
|
545
|
+
channelId: msg.contextId,
|
|
546
|
+
role: this.role,
|
|
547
|
+
workspace: this.deps.workspace,
|
|
548
|
+
signal: this.abortController.signal,
|
|
549
|
+
}
|
|
550
|
+
// 补入产出者 agentId(monitor 据此归属事件;不改原 msg,用浅拷贝)
|
|
551
|
+
const enrichedSource = { ...msg, metadata: { ...msg.metadata, 'x-aw-producing-agent': this.agentId } }
|
|
552
|
+
// 回复文本收集(V9:omp 不产 message 事件,聚合三类源——message 事件 / status.message / 终态 artifact 'output')
|
|
553
|
+
let replyText = ''
|
|
554
|
+
const cap = (text: string): void => {
|
|
555
|
+
if (replyText.length < 400) replyText += text.slice(0, 400 - replyText.length)
|
|
556
|
+
}
|
|
557
|
+
try {
|
|
558
|
+
for await (const event of this.impl.run(request, ctx)) {
|
|
559
|
+
this.deps.bus.emit(event, enrichedSource)
|
|
560
|
+
// LLM 流式增量:只走事件流(AEP agent.delta),不进任务引擎/交付兜底管道
|
|
561
|
+
if (event.kind === 'delta') continue
|
|
562
|
+
if (event.kind === 'error') sawRunError = true
|
|
563
|
+
if (taskId) await this.deps.taskEngine.applyEvent(taskId, event)
|
|
564
|
+
if (event.kind === 'message') cap(partsToText(event.message.parts))
|
|
565
|
+
else if (event.kind === 'status' && event.status.message) cap(partsToText(event.status.message.parts))
|
|
566
|
+
else if (event.kind === 'artifact' && event.artifact.name === 'output') cap(partsToText(event.artifact.parts))
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
catch (err) {
|
|
570
|
+
// run 生成器抛错(如 omp 子进程 spawn 失败):按回合失败走重投,不外抛断循环
|
|
571
|
+
sawRunError = true
|
|
572
|
+
log.error(`[AgentRuntime:${this.agentId}] 回合异常:`, err)
|
|
573
|
+
}
|
|
574
|
+
// 交付兜底(harness 回合结束 ≠ 任务完成):
|
|
575
|
+
// - 回合产出过实质 artifact(LLM 完成了工作但跳过 complete_task 工具)→ 隐式完成,
|
|
576
|
+
// 交付物即回合规避的输出,平台代为收口(进度 100)。
|
|
577
|
+
// - 无任何产出(LLM 空转)→ FAILED 交给调度器 retry/reassign。
|
|
578
|
+
// 仅 worker 的 assign 执行消息生效:lead 由 supervise 协调;WAITING 父任务不属此列。
|
|
579
|
+
if (taskId && this.role === 'worker' && msg.metadata?.['x-aw-task-kind'] === 'assign') {
|
|
580
|
+
const after = this.deps.taskEngine.get(taskId)
|
|
581
|
+
if (after && after.assigneeId === this.agentId && after.state === 'WORKING') {
|
|
582
|
+
const deliverable = after.artifacts.find(a => a.name !== 'input' && a.parts.some(p => ('text' in p ? p.text.trim().length : 1) > 0))
|
|
583
|
+
if (deliverable) {
|
|
584
|
+
const completed = await this.deps.taskEngine.complete(taskId)
|
|
585
|
+
this.emitExternal({
|
|
586
|
+
kind: 'status',
|
|
587
|
+
status: {
|
|
588
|
+
state: 'COMPLETED',
|
|
589
|
+
message: {
|
|
590
|
+
messageId: randomUUID(),
|
|
591
|
+
contextId: this.channelId,
|
|
592
|
+
role: 'ROLE_AGENT',
|
|
593
|
+
parts: [{ text: `任务 ${taskId} 回合已产出交付物但未调用完成工具,平台隐式收口为 COMPLETED` }],
|
|
594
|
+
},
|
|
595
|
+
timestamp: new Date().toISOString(),
|
|
596
|
+
},
|
|
597
|
+
})
|
|
598
|
+
// 子任务隐式完成 → 通知父任务(lead 汇总/WAITING→WORKING 接续):
|
|
599
|
+
// 与 manager.completeTask 的显式收口同构,否则父任务 WAITING 永挂
|
|
600
|
+
// (无 child-completed 事件、父任务不翻转,lead 无感知)。
|
|
601
|
+
if (completed.parentId) {
|
|
602
|
+
this.deps.taskEngine.onChildCompleted(completed)
|
|
603
|
+
const parent = this.deps.taskEngine.get(completed.parentId)
|
|
604
|
+
if (parent) this.deps.bus.wakeScheduler()
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
await this.deps.taskEngine.transition(taskId, 'FAILED', this.agentId)
|
|
609
|
+
this.emitExternal({
|
|
610
|
+
kind: 'status',
|
|
611
|
+
status: {
|
|
612
|
+
state: 'FAILED',
|
|
613
|
+
message: {
|
|
614
|
+
messageId: randomUUID(),
|
|
615
|
+
contextId: this.channelId,
|
|
616
|
+
role: 'ROLE_AGENT',
|
|
617
|
+
parts: [{ text: `任务 ${taskId} 执行结束但无交付(harness 回合结束未产出),标记 FAILED 待重试` }],
|
|
618
|
+
},
|
|
619
|
+
timestamp: new Date().toISOString(),
|
|
620
|
+
},
|
|
621
|
+
})
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// 记忆沉淀:终态任务 harvest;无 taskId 的点对点消息记协作(异常不阻塞)
|
|
627
|
+
if (this.deps.memory) {
|
|
628
|
+
try {
|
|
629
|
+
const task = taskId ? this.deps.taskEngine.get(taskId) : undefined
|
|
630
|
+
if (task && TERMINAL_TASK_STATES[task.state]) {
|
|
631
|
+
await this.deps.memory.recordTaskOutcome(task)
|
|
632
|
+
}
|
|
633
|
+
else if (!taskId) {
|
|
634
|
+
const fromAgentId = (msg.metadata?.['x-aw-from-agent'] as string | undefined) ?? null
|
|
635
|
+
if (fromAgentId) await this.deps.memory.recordPeerExchange(msg, replyText)
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
catch (err) {
|
|
639
|
+
log.error(`[AgentRuntime:${this.agentId}] 记忆写入失败:`, err)
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
finally {
|
|
644
|
+
this.abortController = null
|
|
645
|
+
this.currentTaskId = null
|
|
646
|
+
if (this.state === 'busy') {
|
|
647
|
+
this.state = 'idle'
|
|
648
|
+
this.deps.bus.notifyAgent({ agentId: this.agentId, state: 'idle', ...this.queueContext() })
|
|
649
|
+
}
|
|
650
|
+
// 回合失败(harness 错误/停滞看门狗中止/子进程异常):重投消息而非静默消费,
|
|
651
|
+
// 内容不丢,重试回合(通常已是全新子进程)再处理;每消息最多重投 2 次防毒消息死循环。
|
|
652
|
+
// 任务已终态(取消/收口后 abort 让回合报错)则不再重投 —— 消息依任务终态
|
|
653
|
+
// 由调度器 reassign/新 assign 驱动,重投只会空转(启动即被终态检查消费)。
|
|
654
|
+
const taskNow = taskId ? this.deps.taskEngine.get(taskId) : undefined
|
|
655
|
+
const taskDone = !!taskNow && TERMINAL_TASK_STATES[taskNow.state]
|
|
656
|
+
if (sawRunError && !taskDone && (this.runErrorRetries.get(msg.messageId) ?? 0) < 2
|
|
657
|
+
&& this.deps.mailbox.requeue(msg.messageId)) {
|
|
658
|
+
const attempt = (this.runErrorRetries.get(msg.messageId) ?? 0) + 1
|
|
659
|
+
this.runErrorRetries.set(msg.messageId, attempt)
|
|
660
|
+
this.emitExternal({
|
|
661
|
+
kind: 'status',
|
|
662
|
+
status: {
|
|
663
|
+
state: 'WORKING',
|
|
664
|
+
message: {
|
|
665
|
+
messageId: randomUUID(),
|
|
666
|
+
contextId: this.channelId,
|
|
667
|
+
role: 'ROLE_AGENT',
|
|
668
|
+
parts: [{ text: `消息 ${msg.messageId.slice(0, 8)} 回合失败,已重投信箱待重试(第 ${attempt} 次)` }],
|
|
669
|
+
},
|
|
670
|
+
timestamp: new Date().toISOString(),
|
|
671
|
+
},
|
|
672
|
+
})
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
this.runErrorRetries.delete(msg.messageId)
|
|
676
|
+
this.deps.mailbox.markConsumed(msg.messageId)
|
|
677
|
+
}
|
|
678
|
+
// 回合落定:信箱空 → 后台压缩检查(post-settle 路径;impl 自守卫不阻塞)
|
|
679
|
+
this.maybePostSettle()
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/** 状态通知的队列上下文(实时:当前任务/待执行数/已完成数/harness 上下文用量) */
|
|
684
|
+
private queueContext(): Pick<AgentStatusView, 'currentTaskId' | 'currentTaskTitle' | 'currentTaskProgress' | 'queuedCount' | 'completedCount'> & { context?: AgentContextStats | null } {
|
|
685
|
+
const status = this.getStatus()
|
|
686
|
+
return {
|
|
687
|
+
currentTaskId: status.currentTaskId,
|
|
688
|
+
currentTaskTitle: status.currentTaskTitle,
|
|
689
|
+
currentTaskProgress: status.currentTaskProgress,
|
|
690
|
+
queuedCount: status.queuedCount,
|
|
691
|
+
completedCount: status.completedCount,
|
|
692
|
+
context: status.context ?? null,
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* 任务关联集(自身+父+兄弟,≤20):related-task boost 数据源。
|
|
698
|
+
* 同父兄弟任务的记忆(前几个子任务做了什么)在引子中必然置顶——
|
|
699
|
+
* 纯内存 id 判断,零检索开销。
|
|
700
|
+
*/
|
|
701
|
+
private relatedTaskIdsOf(taskId: string | undefined): string[] | undefined {
|
|
702
|
+
if (!taskId) return undefined
|
|
703
|
+
const task = this.deps.taskEngine.get(taskId)
|
|
704
|
+
if (!task) return undefined
|
|
705
|
+
const ids = new Set<string>([taskId])
|
|
706
|
+
if (task.parentId) {
|
|
707
|
+
ids.add(task.parentId)
|
|
708
|
+
for (const t of this.deps.taskEngine.list(this.channelId)) {
|
|
709
|
+
if (t.parentId === task.parentId) ids.add(t.id)
|
|
710
|
+
if (ids.size >= 20) break
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
return [...ids]
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* post-settle 压缩检查:仅信箱无排队消息时触发(排队消息的 pre-prompt gate 兜底)。
|
|
718
|
+
* impl 自守卫(回合间隙才压缩、异常不抛出);本方法自身也不阻塞消费循环。
|
|
719
|
+
*/
|
|
720
|
+
private maybePostSettle(): void {
|
|
721
|
+
if (!this.impl.onTurnSettled) return
|
|
722
|
+
void this.deps.mailbox.peek(1)
|
|
723
|
+
.then((pending) => {
|
|
724
|
+
if (pending.length > 0) return undefined
|
|
725
|
+
return this.impl.onTurnSettled?.()
|
|
726
|
+
})
|
|
727
|
+
.catch(() => {})
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
private toRequest(msg: A2AMessage, memory?: string): AgentRunRequest {
|
|
731
|
+
return {
|
|
732
|
+
message: msg,
|
|
733
|
+
taskId: msg.taskId,
|
|
734
|
+
contextId: msg.contextId,
|
|
735
|
+
fromAgentId: (msg.metadata?.['x-aw-from-agent'] as string | undefined) ?? null,
|
|
736
|
+
toAgentId: this.agentId,
|
|
737
|
+
memory,
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
private taskIdOf(msg: A2AMessage): string | undefined {
|
|
742
|
+
return msg.taskId ?? (msg.metadata?.['x-aw-task-id'] as string | undefined)
|
|
743
|
+
}
|
|
744
|
+
}
|