agentworkshop 0.7.51 → 0.7.52
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/host-tools.json +2028 -1955
- package/.output/.AgentWorkShop/prompts/host-tools.json +2028 -1955
- package/.output/nitro.json +1 -1
- package/.output/public/_nuxt/{CdIsmU5a2.js → 4wrEQ3np2.js} +1 -1
- package/.output/public/_nuxt/{asmJ99nX2.js → B8zP7kaj2.js} +1 -1
- package/.output/public/_nuxt/{D89BUtx6.js → B9cGf8mg.js} +1 -1
- package/.output/public/_nuxt/{CP0I2l-6.js → BVzw5a_0.js} +1 -1
- package/.output/public/_nuxt/{CFQSjB1h.js → B_opxrHJ.js} +1 -1
- package/.output/public/_nuxt/{BGAaKBeo2.js → BiUhxH3t2.js} +1 -1
- package/.output/public/_nuxt/{B7jlMWsz.js → C00Rd6Cg.js} +1 -1
- package/.output/public/_nuxt/{BOmDHp5L.js → CGQvF-Gg.js} +3 -3
- package/.output/public/_nuxt/CTvh8v4T.js +1 -0
- package/.output/public/_nuxt/{B9QzrmgE.js → Cbeifv55.js} +1 -1
- package/.output/public/_nuxt/{BWU1pvLL.js → CcGuXiOa.js} +1 -1
- package/.output/public/_nuxt/{zh-S_7rN2.js → CkPxL4UX2.js} +1 -1
- package/.output/public/_nuxt/{DzfVS8N72.js → D_Ce9Fon2.js} +1 -1
- package/.output/public/_nuxt/{DClNt1uS.js → Da90gveK.js} +1 -1
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/c64014ca-3595-4b7a-a5ca-055687c83ba2.json +1 -0
- package/.output/public/_nuxt/channel-templates.DkNZg-lF.css +1 -0
- package/.output/public/_nuxt/{JAM4aNC_.js → evt5VGDh.js} +1 -1
- package/.output/public/_nuxt/{DhFv8S2Z.js → mNnuUoSy.js} +1 -1
- package/.output/public/_nuxt/{CU-mhG0-.js → mgWHSRc8.js} +1 -1
- package/.output/public/_nuxt/{jRTz0hjN2.js → qPsch_ny2.js} +1 -1
- package/.output/public/_nuxt/{lWYQbIR3.js → ty5W5QwO.js} +1 -1
- package/.output/public/_nuxt/{DMYYS5sK.js → xQX5r6tW.js} +1 -1
- package/.output/server/chunks/_/character-asset.repo.mjs +1 -1
- package/.output/server/chunks/_/entity.mjs +1 -1
- package/.output/server/chunks/_/host-bindings.mjs +1 -1
- package/.output/server/chunks/_/nitro.mjs +1209 -967
- package/.output/server/chunks/_/nitro.mjs.map +1 -1
- package/.output/server/chunks/_/scene-layout.repo.mjs +1 -1
- package/.output/server/chunks/build/TownView-fP9BiALv.mjs +1 -1
- package/.output/server/chunks/build/{_wsId_-DPy2BXRd.mjs → _wsId_-C4L9fVHC.mjs} +2 -2
- package/.output/server/chunks/build/{_wsId_-DPy2BXRd.mjs.map → _wsId_-C4L9fVHC.mjs.map} +1 -1
- package/.output/server/chunks/build/{agents-CDLcboCv.mjs → agents-ydYu-Ol9.mjs} +6 -6
- package/.output/server/chunks/build/{agents-CDLcboCv.mjs.map → agents-ydYu-Ol9.mjs.map} +1 -1
- package/.output/server/chunks/build/{channel-templates-DjEsj0_v.mjs → channel-templates-DP1ndA5K.mjs} +114 -25
- package/.output/server/chunks/build/channel-templates-DP1ndA5K.mjs.map +1 -0
- package/.output/server/chunks/build/daq-N69AOtgw.mjs +1 -1
- package/.output/server/chunks/build/dcw-CN9d3Rs7.mjs +1 -1
- package/.output/server/chunks/build/{pages-rZKH72eC.mjs → pages-BzmrmLL_.mjs} +3 -3
- package/.output/server/chunks/build/{pages-rZKH72eC.mjs.map → pages-BzmrmLL_.mjs.map} +1 -1
- package/.output/server/chunks/build/{schedules-lo4bfgVt.mjs → schedules-BYR-lA1k.mjs} +2 -2
- package/.output/server/chunks/build/{schedules-lo4bfgVt.mjs.map → schedules-BYR-lA1k.mjs.map} +1 -1
- package/.output/server/chunks/build/{settings-CAJWvul5.mjs → settings-UyZ78w2e.mjs} +2 -2
- package/.output/server/chunks/build/{settings-CAJWvul5.mjs.map → settings-UyZ78w2e.mjs.map} +1 -1
- package/.output/server/chunks/build/{teams-DBBvIToa.mjs → teams-D-Y5mzU7.mjs} +8 -8
- package/.output/server/chunks/build/{teams-DBBvIToa.mjs.map → teams-D-Y5mzU7.mjs.map} +1 -1
- package/.output/server/chunks/build/types-D6J7slEa.mjs +1 -1
- package/.output/server/chunks/build/{useAgentHarnessOptions-D6SJ_uUr.mjs → useAgentHarnessOptions-CRyQYYY0.mjs} +2 -2
- package/.output/server/chunks/build/{useAgentHarnessOptions-D6SJ_uUr.mjs.map → useAgentHarnessOptions-CRyQYYY0.mjs.map} +1 -1
- package/.output/server/chunks/build/{useAgentTemplateActions-CdG4g_PF.mjs → useAgentTemplateActions-CaRsOBmB.mjs} +2 -2
- package/.output/server/chunks/build/{useAgentTemplateActions-CdG4g_PF.mjs.map → useAgentTemplateActions-CaRsOBmB.mjs.map} +1 -1
- package/.output/server/chunks/build/{useAgentTemplateForm-a5y-N5sB.mjs → useAgentTemplateForm-ChiIuPYr.mjs} +2 -2
- package/.output/server/chunks/build/{useAgentTemplateForm-a5y-N5sB.mjs.map → useAgentTemplateForm-ChiIuPYr.mjs.map} +1 -1
- package/.output/server/chunks/build/{useAgentTemplatesCatalog-pBVcUuN3.mjs → useAgentTemplatesCatalog-Bf5hk6Jf.mjs} +2 -2
- package/.output/server/chunks/build/{useAgentTemplatesCatalog-pBVcUuN3.mjs.map → useAgentTemplatesCatalog-Bf5hk6Jf.mjs.map} +1 -1
- package/.output/server/chunks/build/useDaqAddNode-kW7uTSMQ.mjs +1 -1
- package/.output/server/chunks/build/useDaqDetailNode-D_vhG0jF.mjs +1 -1
- package/.output/server/chunks/build/useDaqDetailParams-JfqHvTxr.mjs +1 -1
- package/.output/server/chunks/build/useDaqFilters-BUQtZ82a.mjs +1 -1
- package/.output/server/chunks/build/useDaqStream-wOxZcMDA.mjs +1 -1
- package/.output/server/chunks/build/useDaqTemplates-BqQRdrIm.mjs +1 -1
- package/.output/server/chunks/build/{useDashboardData-Do_Vsepa.mjs → useDashboardData-CNOY4Bi3.mjs} +2 -2
- package/.output/server/chunks/build/{useDashboardData-Do_Vsepa.mjs.map → useDashboardData-CNOY4Bi3.mjs.map} +1 -1
- package/.output/server/chunks/build/useDcwAddNode-C1HDP3yG.mjs +1 -1
- package/.output/server/chunks/build/useDcwStream-D04kCV3J.mjs +1 -1
- package/.output/server/chunks/build/{useTeamActions-C4n-taBk.mjs → useTeamActions-C51ciLb0.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamActions-C4n-taBk.mjs.map → useTeamActions-C51ciLb0.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamAddMemberDialog-Cp_z3nMa.mjs → useTeamAddMemberDialog-DthpCMP8.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamAddMemberDialog-Cp_z3nMa.mjs.map → useTeamAddMemberDialog-DthpCMP8.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamCreateDialog-C8LKUoe2.mjs → useTeamCreateDialog-Dc2KTwyg.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamCreateDialog-C8LKUoe2.mjs.map → useTeamCreateDialog-Dc2KTwyg.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamDeployDialog-wdBVsNWY.mjs → useTeamDeployDialog-CXpvPnJD.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamDeployDialog-wdBVsNWY.mjs.map → useTeamDeployDialog-CXpvPnJD.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamPluginDialog-CIk8G8nI.mjs → useTeamPluginDialog-DTs-7SSm.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamPluginDialog-CIk8G8nI.mjs.map → useTeamPluginDialog-DTs-7SSm.mjs.map} +1 -1
- package/.output/server/chunks/build/{useTeamsCatalog-D6TULzmS.mjs → useTeamsCatalog-CcpetYyW.mjs} +2 -2
- package/.output/server/chunks/build/{useTeamsCatalog-D6TULzmS.mjs.map → useTeamsCatalog-CcpetYyW.mjs.map} +1 -1
- package/.output/server/chunks/build/{useWorkshopApi-B1B9vd4m.mjs → useWorkshopApi-CO3ophqt.mjs} +5 -2
- package/.output/server/chunks/build/{useWorkshopApi-B1B9vd4m.mjs.map → useWorkshopApi-CO3ophqt.mjs.map} +1 -1
- package/.output/server/chunks/routes/api/mcp/workshop.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/grant.post.mjs +54 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/grant.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/revoke.post.mjs +51 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/revoke.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id/preview.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/entities/prune.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/env/recheck.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/env/uv.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/env/venv.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index2.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index3.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index3.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index4.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index5.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index6.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/index7.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/cancel.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/logs.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/retry.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/models/_id/predict.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/models/_id/promote.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/models/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/models/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id/train.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/aml/twin/providers.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +5 -4
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/twin-profile.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/_id/twin-profile.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels.post.mjs +4 -4
- package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/bindings.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id/write.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index3.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index4.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index5.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index5.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index6.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index6.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/index7.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/teams/_id/index2.get.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +2 -2
- package/.output/server/chunks/routes/renderer.mjs +2 -2
- package/.output/server/chunks/virtual/entry.mjs +29 -19
- package/.output/server/chunks/virtual/precomputed.mjs +1 -1
- package/.output/server/package.json +1 -1
- package/README-zh.md +2 -2
- package/README.md +2 -2
- package/app/composables/workshop/useWorkshopApi.ts +4 -2
- package/app/pages/workshop/channel-templates.vue +43 -4
- package/config.yml +1 -1
- package/docs/cli.en.md +2 -2
- package/docs/cli.md +2 -2
- package/docs/plugins.en.md +1 -1
- package/docs/plugins.md +1 -1
- package/docs/sdk.en.md +1 -1
- package/docs/sdk.md +1 -1
- package/i18n/dicts/ctpl.json +37 -32
- package/i18n/locales/en.ts +5 -0
- package/i18n/locales/zh-CN.ts +5 -0
- package/package.json +1 -1
- package/scripts/_audit/kb-team-mock-e2e.mjs +146 -0
- package/scripts/_audit/kb-team-omp-e2e.mjs +229 -0
- package/server/api/workshop/agent-tools/bindings/grant.post.ts +45 -0
- package/server/api/workshop/agent-tools/bindings/revoke.post.ts +42 -0
- package/server/api/workshop/channel-templates/[id]/instantiate.post.ts +2 -1
- package/server/services/workshop/agents/host-tool-bridge/dispatch.ts +6 -1
- package/server/services/workshop/agents/host-tool-bridge/tools/tasks.ts +15 -2
- package/server/services/workshop/agents/host-tool-bridge/tools/team-delegation.ts +104 -0
- package/server/services/workshop/agents/node-bindings.repo.ts +10 -1
- package/server/services/workshop/agents/node-delegation.ts +150 -0
- package/server/services/workshop/agents/tool-classes.ts +2 -0
- package/server/services/workshop/db/database/seed.ts +20 -0
- package/server/services/workshop/runtime/manager/channel-templates.ts +26 -2
- package/server/services/workshop/runtime/manager/types.ts +2 -0
- package/.output/public/_nuxt/8FXd9As6.js +0 -1
- package/.output/public/_nuxt/builds/meta/912eb5bb-670e-4cc8-b21d-7fc097723466.json +0 -1
- package/.output/public/_nuxt/channel-templates.DplM1pJ3.css +0 -1
- package/.output/server/chunks/build/channel-templates-DjEsj0_v.mjs.map +0 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* scripts/_audit/kb-team-omp-e2e.mjs —— 知识库集成通用闭环优化频道 × 真实 omp × 多 PLC 模拟场景。
|
|
4
|
+
*
|
|
5
|
+
* 每个 scenario:
|
|
6
|
+
* ① 模拟器建场(ensureScenarioLine) + 平台建线开跑(provisionScenarioLine,真实协议链路);
|
|
7
|
+
* ② 实例化「通用闭环优化频道(标准)」模板,enableKnowledgeBase=true(频道加载 rag-bridge);
|
|
8
|
+
* ③ lead 绑定 PV 数采节点 + 调节数控节点(auto);
|
|
9
|
+
* ④ 提交优化 goal(要求:先查知识库 → lead 委派节点权限 → 治理小步下发复测 → 判定 → 经验沉淀);
|
|
10
|
+
* ⑤ 期间轮询任务/消息/事件,全程转录落盘(transcript.md + 原始 JSON);
|
|
11
|
+
* ⑥ 验收:根任务收口 + worker 确实被授予节点(grantedBy 溯源) + 发生过治理写入
|
|
12
|
+
* + PV 回带 + 知识库经验新增(kb_agent 异步落库)。
|
|
13
|
+
*
|
|
14
|
+
* 用法:
|
|
15
|
+
* node scripts/_audit/kb-team-omp-e2e.mjs --base http://127.0.0.1:3456 --scenarios injection,wwtp
|
|
16
|
+
* 前置:目标实例为本仓库构建(内置通用模板 + rag-bridge);rag-bridge token 已配置(启 KB 鉴权时);
|
|
17
|
+
* omp CLI 在 PATH 且可用;模拟器可自举(bench/lib/sim.mjs ensureSimulator)。
|
|
18
|
+
*/
|
|
19
|
+
import { join, dirname, resolve } from 'node:path'
|
|
20
|
+
import { writeFileSync, appendFileSync } from 'node:fs'
|
|
21
|
+
import { fileURLToPath } from 'node:url'
|
|
22
|
+
import { makeApi, ensureDir, sleep } from '../../bench/lib/util.mjs'
|
|
23
|
+
import { ensureSimulator, simUp } from '../../bench/lib/sim.mjs'
|
|
24
|
+
import { SCENARIOS, ensureScenarioLine, provisionScenarioLine, readPvMean } from '../../bench/lib/scenarios.mjs'
|
|
25
|
+
|
|
26
|
+
const HERE = dirname(fileURLToPath(import.meta.url))
|
|
27
|
+
const REPO = resolve(HERE, '../..')
|
|
28
|
+
const args = process.argv.slice(2)
|
|
29
|
+
const arg = (k, d) => { const i = args.indexOf(`--${k}`); return i >= 0 ? (args[i + 1] ?? '') : d }
|
|
30
|
+
|
|
31
|
+
const BASE = arg('base', process.env.AW_BASE ?? 'http://127.0.0.1:3456')
|
|
32
|
+
const list = (arg('scenarios', 'injection') || 'injection').split(',').map(s => s.trim()).filter(id => SCENARIOS[id])
|
|
33
|
+
const TASK_TIMEOUT_MS = Number(arg('timeout-min', '32')) * 60_000
|
|
34
|
+
const KB_WAIT_MS = Number(arg('kb-wait-min', '6')) * 60_000
|
|
35
|
+
const POLL_MS = 20_000
|
|
36
|
+
const sfx = arg('sfx', `kb${new Date().toISOString().slice(5, 16).replace(/[-T:]/g, '')}`)
|
|
37
|
+
|
|
38
|
+
const rid = `kb-team-omp-${new Date().toISOString().slice(0, 19).replace(/[-T:]/g, '')}`
|
|
39
|
+
const outDir = ensureDir(join(REPO, 'bench', 'results', rid))
|
|
40
|
+
console.log(`=== kb-team × omp 闭环优化 × 多场景 ===\nbase=${BASE} scenarios=${list.join(',')} out=${outDir}\n`)
|
|
41
|
+
|
|
42
|
+
// ── 自举 ──
|
|
43
|
+
if (!(await simUp())) {
|
|
44
|
+
const r = await ensureSimulator({ log: console.log })
|
|
45
|
+
if (!r.started && !(await simUp())) { console.error(`✘ 模拟器自举失败: ${r.reason}`); process.exit(1) }
|
|
46
|
+
}
|
|
47
|
+
const api = makeApi(BASE)
|
|
48
|
+
const login = await api.login(process.env.AW_ADMIN_EMAIL ?? 'admin@awshop.local', process.env.AW_ADMIN_PASSWORD ?? 'Awshop@123!')
|
|
49
|
+
if (!login.ok) { console.error('✘ 平台登录失败'); process.exit(1) }
|
|
50
|
+
console.log(`平台就绪(${login.how},role=${login.role});模拟器就绪\n`)
|
|
51
|
+
|
|
52
|
+
const globalResult = { rid, base: BASE, scenarios: [] }
|
|
53
|
+
|
|
54
|
+
for (const id of list) {
|
|
55
|
+
const scen = SCENARIOS[id]
|
|
56
|
+
const dir = ensureDir(join(outDir, id))
|
|
57
|
+
const res = { scenario: id, zh: scen.zh, checks: {}, errors: [] }
|
|
58
|
+
globalResult.scenarios.push(res)
|
|
59
|
+
const log = (line) => { console.log(`[${id}] ${line}`); appendFileSync(join(dir, 'transcript.md'), `${line}\n`) }
|
|
60
|
+
writeFileSync(join(dir, 'transcript.md'), `# ${scen.zh}(kb-team × omp)作业转录\n\n- 开始: ${new Date().toISOString()}\n- 频道模板: chtl-generic-optimize-default(enableKnowledgeBase=true)\n\n`)
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
// ── ① 建场 + 建线 ──
|
|
64
|
+
log(`① 模拟器建场 ${scen.key} …`)
|
|
65
|
+
const ensure = await ensureScenarioLine(scen)
|
|
66
|
+
log(` 设备=${ensure.verified.devices}/${ensure.verified.expectDevices} SP=${ensure.verified.sp} PV=${ensure.verified.pv} 协议=${ensure.verified.protocols.join('/')}`)
|
|
67
|
+
const line = await provisionScenarioLine(api, scen, { sfx: `${sfx}-${id}` })
|
|
68
|
+
if (line.errors?.length || !line.ids?.lineId) throw new Error(`建线失败: ${line.errors?.join(';')}`)
|
|
69
|
+
res.line = { lineId: line.ids.lineId, recipeId: line.ids.recipeId, started: line.ids.started, reused: line.reused }
|
|
70
|
+
log(`① 平台建线 ${line.lineName} started=${line.ids.started} dcw=${Object.keys(line.dcw).length} daq=${Object.keys(line.daq).length}`)
|
|
71
|
+
|
|
72
|
+
// ── ② 实例化 KB 通用频道 ──
|
|
73
|
+
const inst = (await api.call('POST', '/api/workshop/channel-templates/chtpl-generic-optimize-default/instantiate', {
|
|
74
|
+
name: `KB闭环优化-${scen.zh}-${sfx}-${id}`,
|
|
75
|
+
enableKnowledgeBase: true,
|
|
76
|
+
}))
|
|
77
|
+
const channelId = inst.data?.channelId
|
|
78
|
+
if (!channelId) throw new Error(`频道实例化失败: ${inst.message}`)
|
|
79
|
+
const agents = (await api.call('GET', `/api/workshop/channels/${channelId}/agents`)).data ?? []
|
|
80
|
+
const lead = agents.find(a => a.role === 'lead')
|
|
81
|
+
res.channel = { channelId, leadId: lead?.id, leadHarness: lead?.harness }
|
|
82
|
+
log(`② 频道 ${channelId} 已实例化(lead=${lead?.name}/${lead?.harness},成员=${agents.length})`)
|
|
83
|
+
|
|
84
|
+
// ── ③ lead 绑定 PV 数采 + 调节数控(auto) ──
|
|
85
|
+
const pvNode = line.daq[scen.pv.sig]
|
|
86
|
+
const knobSigs = (scen.knobs ?? []).map(k => k.sig).slice(0, 2)
|
|
87
|
+
const knobNodes = knobSigs.map(s => line.dcw[s]).filter(Boolean)
|
|
88
|
+
if (!pvNode || !knobNodes.length) throw new Error(`关键节点缺失: pv=${pvNode} knobs=${knobNodes}`)
|
|
89
|
+
for (const [nodeId, kind] of [[pvNode, 'daq'], ...knobNodes.map(n => [n, 'dcw'])]) {
|
|
90
|
+
const r = await api.call('POST', '/api/workshop/agent-tools/bindings', { agentId: lead.id, nodeId, kind, mode: 'auto' })
|
|
91
|
+
if (r.status !== 200) throw new Error(`lead 绑定失败 ${kind} ${nodeId}: ${r.message}`)
|
|
92
|
+
}
|
|
93
|
+
res.leadBindings = { pvNode, knobNodes }
|
|
94
|
+
log(`③ lead 绑定:daq(${scen.pv.sig})=${pvNode} dcw=${knobNodes.join(',')}`)
|
|
95
|
+
|
|
96
|
+
// ── ④ 提交 goal ──
|
|
97
|
+
const knobText = (scen.knobs ?? []).slice(0, 2).map(k => `${k.sig}`).join('、')
|
|
98
|
+
const guardText = (scen.guards ?? []).map(g => `${g.label}≤${g.max}`).join('、') || '无'
|
|
99
|
+
const goal = [
|
|
100
|
+
`【产线闭环优化】${scen.zh}:${scen.story}`,
|
|
101
|
+
`目标:把「${scen.pv.label}(${scen.pv.sig})」稳定控制回 ${scen.pv.target}±${scen.pv.tol}${scen.pv.unit} 目标带;守卫约束:${guardText}。`,
|
|
102
|
+
`可调手段(数控节点,治理下发):${knobText}。`,
|
|
103
|
+
`作业要求:`,
|
|
104
|
+
`1. 开工先查知识库:lead 用 kb_agent(mode=sync) 检索「${scen.zh} 数据分析」「${scen.pv.label} 物理机理与设定影响」,把检索结论作为寻优方向与步长依据;`,
|
|
105
|
+
`2. lead 把自己已绑定的节点授权授予 worker(dispatch_task 带 grant_node_ids 随任务授予,或 team_grant_nodes),确保工艺工程师与数据分析师各自拿到所需节点权限,不要无权限空转;`,
|
|
106
|
+
`3. 工艺工程师单变量小步调整(每步 ≤ 量程 2%,尊重单步限幅与写入间隔),每次调整后等 ${Math.round(scen.settleMs / 1000)}s 再 daq_query 复测「${scen.pv.label}」;`,
|
|
107
|
+
`4. 进入目标带且复测稳定后 dcw_judge 落判定(keep),lead 用 kb_agent(mode=async) 把本次经验沉淀入知识库(含调整前后参数值与响应数据),随后完成收口汇报。`,
|
|
108
|
+
].join('\n')
|
|
109
|
+
const task = (await api.call('POST', `/api/workshop/channels/${channelId}/tasks`, { title: `${scen.zh}(KB 闭环)`, description: goal })).data
|
|
110
|
+
if (!task?.id) throw new Error(`根任务提交失败`)
|
|
111
|
+
res.rootTaskId = task.id
|
|
112
|
+
log(`④ 根任务 ${task.id} 已提交,开始作业(超时 ${Math.round(TASK_TIMEOUT_MS / 60000)}min)…\n`)
|
|
113
|
+
|
|
114
|
+
// ── ⑤ 轮询转录 ──
|
|
115
|
+
let seenMsg = new Set()
|
|
116
|
+
let seenTaskState = new Map()
|
|
117
|
+
let lastEventSeq = 0
|
|
118
|
+
let toolEvidence = { kbAgent: 0, grant: 0 }
|
|
119
|
+
const t0 = Date.now()
|
|
120
|
+
let terminal = null
|
|
121
|
+
const dump = async () => {
|
|
122
|
+
const msgs = (await api.call('GET', `/api/workshop/channels/${channelId}/messages?limit=200`)).data ?? []
|
|
123
|
+
for (const m of [...msgs].reverse()) {
|
|
124
|
+
const key = m.id ?? `${m.createdAt}:${m.fromAgentName}`
|
|
125
|
+
if (seenMsg.has(key)) continue
|
|
126
|
+
seenMsg.add(key)
|
|
127
|
+
const who = m.fromAgentName ?? m.from ?? '?'
|
|
128
|
+
const text = String(m.text ?? m.preview ?? '').slice(0, 600)
|
|
129
|
+
if (text.trim()) appendFileSync(join(dir, 'transcript.md'), `\n> **${who}** @ ${m.createdAt ?? ''}\n>\n${text.split('\n').map(l => `> ${l}`).join('\n')}\n`)
|
|
130
|
+
}
|
|
131
|
+
const tasks = (await api.call('GET', `/api/workshop/channels/${channelId}/tasks`)).data ?? []
|
|
132
|
+
const arr = Array.isArray(tasks) ? tasks : (tasks.tasks ?? [])
|
|
133
|
+
for (const t of arr) {
|
|
134
|
+
const st = `${t.id}:${t.state}:${t.progress ?? 0}`
|
|
135
|
+
if (seenTaskState.get(t.id) !== st) {
|
|
136
|
+
seenTaskState.set(t.id, st)
|
|
137
|
+
appendFileSync(join(dir, 'transcript.md'), `\n- [任务] ${t.id} 「${t.title}」 state=${t.state} progress=${t.progress ?? 0}% assignee=${t.assigneeId ?? '-'}`)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// 事件流:记录工具调用证据(kb_agent / team_grant_nodes / grant_node_ids)与 lead 进度报告
|
|
141
|
+
const ev = (await api.call('GET', `/api/workshop/channels/${channelId}/events?limit=200&afterSeq=${lastEventSeq}`)).data ?? {}
|
|
142
|
+
for (const item of (ev.items ?? [])) {
|
|
143
|
+
lastEventSeq = Math.max(lastEventSeq, Number(item.seq ?? 0))
|
|
144
|
+
const text = String(item.payload?.text ?? item.payload?.summary ?? '')
|
|
145
|
+
if (!text) continue
|
|
146
|
+
const kbHits = (text.match(/kb_agent/g) ?? []).length
|
|
147
|
+
const grantHits = (text.match(/team_grant_nodes|grant_node_ids/g) ?? []).length
|
|
148
|
+
toolEvidence.kbAgent += kbHits
|
|
149
|
+
toolEvidence.grant += grantHits
|
|
150
|
+
if (kbHits || grantHits) {
|
|
151
|
+
appendFileSync(join(dir, 'transcript.md'), `\n- [工具证据] @ ${(item.at ?? item.createdAt ?? '').slice(11, 19)} ${text.replace(/\n+/g, ' ').slice(0, 220)}`)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return { tasks: arr, msgs }
|
|
155
|
+
}
|
|
156
|
+
while (Date.now() - t0 < TASK_TIMEOUT_MS) {
|
|
157
|
+
await sleep(POLL_MS)
|
|
158
|
+
try {
|
|
159
|
+
const { tasks } = await dump()
|
|
160
|
+
const root = tasks.find(t => t.id === task.id)
|
|
161
|
+
if (root && ['COMPLETED', 'FAILED', 'CANCELED'].includes(root.state)) { terminal = root; break }
|
|
162
|
+
log(`… 作业中(${Math.round((Date.now() - t0) / 60000)}min)root=${root?.state ?? '?'}`)
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
log(`… 轮询抖动(忽略): ${err?.message ?? err}`)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
await dump()
|
|
169
|
+
if (!terminal) { res.errors.push(`根任务超时(${Math.round(TASK_TIMEOUT_MS / 60000)}min)未收口`) }
|
|
170
|
+
else if (terminal.state !== 'COMPLETED') { res.errors.push(`根任务终态=${terminal.state}`) }
|
|
171
|
+
res.checks.rootTaskClosed = terminal?.state === 'COMPLETED'
|
|
172
|
+
log(`\n⑤ 根任务终态=${terminal?.state ?? 'TIMEOUT'}`)
|
|
173
|
+
|
|
174
|
+
// ── ⑥ 验收 ──
|
|
175
|
+
const workers = agents.filter(a => a.role === 'worker')
|
|
176
|
+
let delegated = 0
|
|
177
|
+
for (const w of workers) {
|
|
178
|
+
const bs = (await api.call('GET', `/api/workshop/agent-tools/bindings?agentId=${w.id}`)).data
|
|
179
|
+
const flat = Array.isArray(bs) ? bs : (bs?.bindings ?? [])
|
|
180
|
+
if (flat.some(b => b.grantedByAgentId === lead.id)) delegated++
|
|
181
|
+
}
|
|
182
|
+
res.checks.workerDelegated = delegated > 0
|
|
183
|
+
log(`⑥ 委派核验:${delegated}/${workers.length} 个 worker 持有 lead 授予的节点授权`)
|
|
184
|
+
|
|
185
|
+
const dcwNow = (await api.call('GET', '/api/workshop/dcw')).data?.nodes ?? []
|
|
186
|
+
const myDcw = dcwNow.filter(n => Object.values(line.dcw).includes(n.id))
|
|
187
|
+
const wrote = myDcw.some(n => n.lastWriteAt)
|
|
188
|
+
res.checks.governedWriteHappened = wrote
|
|
189
|
+
res.dcAfter = myDcw.map(n => ({ id: n.id, name: n.name, value: n.value, lastWriteAt: n.lastWriteAt ?? null }))
|
|
190
|
+
log(`⑥ 治理写入核验:${wrote ? '发生过 dcw 治理写入' : '无 dcw 写入痕迹'}`)
|
|
191
|
+
|
|
192
|
+
const pvMean = await readPvMean(api, pvNode, 5).catch(() => null)
|
|
193
|
+
const inBand = pvMean != null && Math.abs(Number(pvMean) - scen.pv.target) <= scen.pv.tol
|
|
194
|
+
res.checks.pvInBand = inBand
|
|
195
|
+
res.pvMean = pvMean
|
|
196
|
+
log(`⑥ PV 复测:均值=${pvMean} 目标带=${scen.pv.target}±${scen.pv.tol} → ${inBand ? '达标' : '未达标'}`)
|
|
197
|
+
|
|
198
|
+
res.toolEvidence = toolEvidence
|
|
199
|
+
res.checks.kbToolUsed = toolEvidence.kbAgent > 0
|
|
200
|
+
res.checks.grantToolUsed = toolEvidence.grant > 0 || delegated > 0
|
|
201
|
+
log(`⑥ 工具证据(事件流):kb_agent×${toolEvidence.kbAgent} 委派×${toolEvidence.grant}`)
|
|
202
|
+
|
|
203
|
+
log(`⑥ 等待知识库经验沉淀可检索(≤${Math.round(KB_WAIT_MS / 60000)}min)…`)
|
|
204
|
+
const kbQuery = encodeURIComponent(`${scen.zh.slice(0, 6)} ${scen.pv.label} 经验`)
|
|
205
|
+
const kbDeadline = Date.now() + KB_WAIT_MS
|
|
206
|
+
let kbHit = false
|
|
207
|
+
while (Date.now() < kbDeadline) {
|
|
208
|
+
await sleep(45_000)
|
|
209
|
+
const sr = (await api.call('GET', `/api/plugins/rag-bridge/search?q=${kbQuery}&top_k=5`).catch(() => null))?.data
|
|
210
|
+
if ((sr?.total_results ?? 0) > 0 || (sr?.results ?? []).length > 0) { kbHit = true; break }
|
|
211
|
+
log(` … 检索暂未命中(累计等待 ${Math.round((kbDeadline - Date.now()) / 60000)}min)`)
|
|
212
|
+
}
|
|
213
|
+
res.checks.kbExperience = kbHit
|
|
214
|
+
log(`⑥ 知识库经验检索:${kbHit ? '已检出本场景经验内容' : '超时未检出(检索面后端索引漂移时以转录工具证据为准)'}`)
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
res.errors.push(String(err?.message ?? err))
|
|
218
|
+
log(`✘ 异常: ${err?.message ?? err}`)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
res.ok = res.errors.length === 0 && Object.values(res.checks).every(Boolean)
|
|
222
|
+
log(`\n════ [${id}] 结果: ${res.ok ? 'PASS' : 'FAIL'} checks=${JSON.stringify(res.checks)}${res.errors.length ? ` errors=${res.errors.join(';')}` : ''}`)
|
|
223
|
+
writeFileSync(join(dir, 'final.json'), JSON.stringify(res, null, 2))
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
writeFileSync(join(outDir, 'kb-team-omp-result.json'), JSON.stringify(globalResult, null, 2))
|
|
227
|
+
const allOk = globalResult.scenarios.every(s => s.ok)
|
|
228
|
+
console.log(`\n════ 总结果: ${allOk ? '✅ 全场景 PASS' : '❌ 存在 FAIL'}(明细: ${outDir})`)
|
|
229
|
+
process.exit(allOk ? 0 : 1)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/workshop/agent-tools/bindings/grant —— lead 把自己绑定的节点授权给同频道 worker。
|
|
3
|
+
* body: { channelId, agentId(worker 成员实例), nodeIds: string[], mode?: 'auto'|'manual' }
|
|
4
|
+
* 硬约束:nodeIds 每一个都必须在频道 lead 的绑定面内(权限不可超越授予者);全成全败。
|
|
5
|
+
* 产线权限随绑定继承(lead 绑定建立时已校验);绑定带 grantedByAgentId/grantedAt 溯源。
|
|
6
|
+
* 鉴权:channel 归属者(遗留公共 channel 需 admin)。
|
|
7
|
+
*/
|
|
8
|
+
import { readBody } from 'h3'
|
|
9
|
+
import { resolveUser } from '@/server/api/workshop/caller'
|
|
10
|
+
import { defineApiHandler } from '@/server/utils/response'
|
|
11
|
+
import { getWorkshopManager } from '@/server/plugins/workshop'
|
|
12
|
+
import { AppError, ErrorCodes } from '@/server/utils/errors'
|
|
13
|
+
import { applyDelegation, planDelegation } from '@/server/services/workshop/agents/node-delegation'
|
|
14
|
+
import type { DelegationMember } from '@/server/services/workshop/agents/node-delegation'
|
|
15
|
+
|
|
16
|
+
export default defineApiHandler(async (event) => {
|
|
17
|
+
const user = resolveUser(event)
|
|
18
|
+
const body = await readBody<{ channelId?: string, agentId?: string, nodeIds?: string[], mode?: 'auto' | 'manual' }>(event) ?? {}
|
|
19
|
+
const channelId = String(body.channelId ?? '')
|
|
20
|
+
const agentId = String(body.agentId ?? '')
|
|
21
|
+
const nodeIds = Array.isArray(body.nodeIds) ? body.nodeIds.map(x => String(x ?? '').trim()).filter(Boolean) : []
|
|
22
|
+
if (!channelId || !agentId || !nodeIds.length) {
|
|
23
|
+
throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'channelId / agentId / nodeIds 必填')
|
|
24
|
+
}
|
|
25
|
+
const manager = getWorkshopManager()
|
|
26
|
+
const channel = manager.getChannelForUser(channelId, user.id)
|
|
27
|
+
if (channel?.ownerUserId === null) {
|
|
28
|
+
const { requireAdmin } = await import('@/server/api/workshop/caller')
|
|
29
|
+
requireAdmin(event)
|
|
30
|
+
}
|
|
31
|
+
const row = (await manager.listChannels()).find(c => c.id === channelId)
|
|
32
|
+
if (!row?.leadAgentId) throw new AppError(404, ErrorCodes.NOT_FOUND, `频道不存在或没有 lead: ${channelId}`)
|
|
33
|
+
|
|
34
|
+
const members = await manager.listChannelAgents(channelId) as unknown as DelegationMember[]
|
|
35
|
+
const plan = planDelegation({
|
|
36
|
+
leaderAgentId: row.leadAgentId,
|
|
37
|
+
channelId,
|
|
38
|
+
targetAgentId: agentId,
|
|
39
|
+
nodeIds,
|
|
40
|
+
members,
|
|
41
|
+
mode: body.mode,
|
|
42
|
+
})
|
|
43
|
+
const bindings = applyDelegation(plan, row.leadAgentId)
|
|
44
|
+
return { granted: bindings }
|
|
45
|
+
})
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/workshop/agent-tools/bindings/revoke —— lead 收回授予给 worker 的节点授权。
|
|
3
|
+
* body: { channelId, agentId(worker 成员实例), nodeIds: string[] }
|
|
4
|
+
* 可收回:lead 自己授予的(grantedByAgentId=lead)或 lead 也持有的节点绑定;
|
|
5
|
+
* 其余绑定原样保留并在结果中标注 revoked=false。
|
|
6
|
+
* 鉴权:channel 归属者(遗留公共 channel 需 admin)。
|
|
7
|
+
*/
|
|
8
|
+
import { readBody } from 'h3'
|
|
9
|
+
import { resolveUser } from '@/server/api/workshop/caller'
|
|
10
|
+
import { defineApiHandler } from '@/server/utils/response'
|
|
11
|
+
import { getWorkshopManager } from '@/server/plugins/workshop'
|
|
12
|
+
import { AppError, ErrorCodes } from '@/server/utils/errors'
|
|
13
|
+
import { revokeDelegation } from '@/server/services/workshop/agents/node-delegation'
|
|
14
|
+
import type { DelegationMember } from '@/server/services/workshop/agents/node-delegation'
|
|
15
|
+
|
|
16
|
+
export default defineApiHandler(async (event) => {
|
|
17
|
+
const user = resolveUser(event)
|
|
18
|
+
const body = await readBody<{ channelId?: string, agentId?: string, nodeIds?: string[] }>(event) ?? {}
|
|
19
|
+
const channelId = String(body.channelId ?? '')
|
|
20
|
+
const agentId = String(body.agentId ?? '')
|
|
21
|
+
const nodeIds = Array.isArray(body.nodeIds) ? body.nodeIds.map(x => String(x ?? '').trim()).filter(Boolean) : []
|
|
22
|
+
if (!channelId || !agentId || !nodeIds.length) {
|
|
23
|
+
throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'channelId / agentId / nodeIds 必填')
|
|
24
|
+
}
|
|
25
|
+
const manager = getWorkshopManager()
|
|
26
|
+
const channel = manager.getChannelForUser(channelId, user.id)
|
|
27
|
+
if (channel?.ownerUserId === null) {
|
|
28
|
+
const { requireAdmin } = await import('@/server/api/workshop/caller')
|
|
29
|
+
requireAdmin(event)
|
|
30
|
+
}
|
|
31
|
+
const row = (await manager.listChannels()).find(c => c.id === channelId)
|
|
32
|
+
if (!row?.leadAgentId) throw new AppError(404, ErrorCodes.NOT_FOUND, `频道不存在或没有 lead: ${channelId}`)
|
|
33
|
+
|
|
34
|
+
const members = await manager.listChannelAgents(channelId) as unknown as DelegationMember[]
|
|
35
|
+
const results = revokeDelegation({
|
|
36
|
+
leaderAgentId: row.leadAgentId,
|
|
37
|
+
targetAgentId: agentId,
|
|
38
|
+
nodeIds,
|
|
39
|
+
members,
|
|
40
|
+
})
|
|
41
|
+
return { results }
|
|
42
|
+
})
|
|
@@ -23,6 +23,7 @@ const instantiateSchema = z.object({
|
|
|
23
23
|
scenePackId: z.string().min(1).optional(),
|
|
24
24
|
optimizationMode: z.enum(['exploration', 'aml']).optional(),
|
|
25
25
|
boundModelId: z.string().min(1).optional(),
|
|
26
|
+
enableKnowledgeBase: z.boolean().optional(),
|
|
26
27
|
})
|
|
27
28
|
|
|
28
29
|
export default defineApiHandler(async (event) => {
|
|
@@ -30,7 +31,7 @@ export default defineApiHandler(async (event) => {
|
|
|
30
31
|
const user = resolveUser(event)
|
|
31
32
|
const body = await readValidatedBody(event, zValidator(instantiateSchema))
|
|
32
33
|
const manager = getWorkshopManager()
|
|
33
|
-
const result = await manager.instantiateChannelTemplate(templateId, user, body.name, { scene: body.scene, promptVariables: body.promptVariables, objective: body.objective, toolProfile: body.toolProfile, controlPolicy: body.controlPolicy, providerId: body.providerId, providerVersion: body.providerVersion, providerHash: body.providerHash, scenePackId: body.scenePackId, optimizationMode: body.optimizationMode, boundModelId: body.boundModelId })
|
|
34
|
+
const result = await manager.instantiateChannelTemplate(templateId, user, body.name, { scene: body.scene, promptVariables: body.promptVariables, objective: body.objective, toolProfile: body.toolProfile, controlPolicy: body.controlPolicy, providerId: body.providerId, providerVersion: body.providerVersion, providerHash: body.providerHash, scenePackId: body.scenePackId, optimizationMode: body.optimizationMode, boundModelId: body.boundModelId, enableKnowledgeBase: body.enableKnowledgeBase })
|
|
34
35
|
// 模板含 lead 时直接启动调度循环(可提交任务)
|
|
35
36
|
if (result.leadAgentId) {
|
|
36
37
|
ensureLeadSchedulerLoop(manager, result.channelId)
|
|
@@ -19,6 +19,7 @@ import type { HostToolBridgeContext, HostToolCall, HostToolResult } from './type
|
|
|
19
19
|
import { INDUSTRIAL_TOOL_NAMES, dispatchIndustrialTool } from './tools/industrial'
|
|
20
20
|
import { handleCompleteTask, handleReportProgress } from './tools/progress'
|
|
21
21
|
import { handleCancelTask, handleDispatchTask, handleGetMyTaskQueue, handleGetTaskDetails, handleListChannelTasks, handleReassignTask, handleRefuseTask, handleSubmitTask, handleUpdateTask } from './tools/tasks'
|
|
22
|
+
import { handleGrantNodes, handleRevokeNodes } from './tools/team-delegation'
|
|
22
23
|
import { handleBroadcastMessage, handleListOtherTeams, handlePollMessages, handleReadChannelMail, handleSearchOtherTeamsMemory, handleSendCrossChannelMessage, handleSendMessageToAgent } from './tools/messaging'
|
|
23
24
|
import { handleSaveMemory, handleSearchMemory } from './tools/memory'
|
|
24
25
|
import { handleCreateTeamAgent, handleGetQueueOverview, handleListTeamAgents, handleRemoveTeamAgent, handleUpdateTeamAgent } from './tools/team'
|
|
@@ -121,7 +122,11 @@ export async function dispatchHostTool(ctx: HostToolBridgeContext, req: HostTool
|
|
|
121
122
|
case 'submit_task':
|
|
122
123
|
return await handleSubmitTask(args, state, ws)
|
|
123
124
|
case 'dispatch_task':
|
|
124
|
-
return await handleDispatchTask(args, ws)
|
|
125
|
+
return await handleDispatchTask(args, ws, identity)
|
|
126
|
+
case 'team_grant_nodes':
|
|
127
|
+
return await handleGrantNodes(identity, args, ws)
|
|
128
|
+
case 'team_revoke_nodes':
|
|
129
|
+
return await handleRevokeNodes(identity, args, ws)
|
|
125
130
|
case 'send_message_to_agent':
|
|
126
131
|
return await handleSendMessageToAgent(args, state, ws)
|
|
127
132
|
case 'send_cross_channel_message':
|
|
@@ -23,12 +23,25 @@ export async function handleSubmitTask(args: Record<string, unknown>, state: Hos
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export async function handleDispatchTask(args: Record<string, unknown>, ws: AgentWorkspace): Promise<HostToolResult> {
|
|
26
|
+
export async function handleDispatchTask(args: Record<string, unknown>, ws: AgentWorkspace, identity?: HostToolBridgeContext['identity']): Promise<HostToolResult> {
|
|
27
27
|
const assigneeId = args.assignee_id as string
|
|
28
28
|
const title = args.title as string
|
|
29
29
|
const description = args.description as string | undefined
|
|
30
30
|
const parentTaskId = args.parent_task_id as string | undefined
|
|
31
31
|
const routeReason = args.route_reason as string | undefined
|
|
32
|
+
// 派发时随任务授予节点权限(lead 专属;grant_node_ids ⊆ lead 自身绑定面,fail-closed):
|
|
33
|
+
// 任一节点不满足则整单拒绝,任务不创建 —— 避免 worker 拿到任务却没有节点权限的半途态。
|
|
34
|
+
let grantNote = ''
|
|
35
|
+
const rawGrant = args.grant_node_ids ?? args.grantNodeIds
|
|
36
|
+
if (rawGrant != null && identity) {
|
|
37
|
+
const { grantNodesForDispatch } = await import('./team-delegation')
|
|
38
|
+
const grantNodeIds = (Array.isArray(rawGrant) ? rawGrant : String(rawGrant).split(',')).map(x => String(x ?? '').trim()).filter(Boolean)
|
|
39
|
+
if (!grantNodeIds.length) return { text: 'grant_node_ids 为空:要么不传,要么给出至少一个节点 id。', isError: true }
|
|
40
|
+
const grantMode = args.grant_mode === 'manual' || args.grant_mode === 'auto' ? (args.grant_mode as 'auto' | 'manual') : undefined
|
|
41
|
+
const grant = await grantNodesForDispatch(identity, assigneeId, grantNodeIds, grantMode, ws)
|
|
42
|
+
if (!grant.ok) return { text: `未派发:${grant.text}\n请先用 team_grant_nodes 确认你持有这些节点,或修正 node id 后重试。`, isError: true }
|
|
43
|
+
grantNote = `\n${grant.text}`
|
|
44
|
+
}
|
|
32
45
|
// 重复派发守卫(真实场景实测:lead 模型可能对同一目标重复派发,引发协调风暴):
|
|
33
46
|
// 同父任务下已存在同标题非终态子任务 → 不再创建,直接指路既有任务
|
|
34
47
|
const dup = await ws.listTasks()
|
|
@@ -42,7 +55,7 @@ export async function handleDispatchTask(args: Record<string, unknown>, ws: Agen
|
|
|
42
55
|
}
|
|
43
56
|
}
|
|
44
57
|
const task = await ws.dispatchTask({ assigneeId, title, description, parentTaskId, routeReason })
|
|
45
|
-
return { text: `子任务 ${task.id} 已创建并指派 → ${assigneeId}(父任务 ${parentTaskId ?? '无'},标题: ${title}${routeReason ? `,路由理由: ${routeReason}` : ''})` }
|
|
58
|
+
return { text: `子任务 ${task.id} 已创建并指派 → ${assigneeId}(父任务 ${parentTaskId ?? '无'},标题: ${title}${routeReason ? `,路由理由: ${routeReason}` : ''})${grantNote}` }
|
|
46
59
|
}
|
|
47
60
|
|
|
48
61
|
export async function handleRefuseTask(args: Record<string, unknown>, ws: AgentWorkspace): Promise<HostToolResult> {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 团队节点权限委派工具(lead 专属):team_grant_nodes / team_revoke_nodes。
|
|
3
|
+
*
|
|
4
|
+
* lead 把**自己已绑定**的 DAQ/DCW 节点授权给同频道 worker(派发前、执行中均可),
|
|
5
|
+
* 授权面不可超越 lead 本人的绑定面(planDelegation fail-closed 校验)。
|
|
6
|
+
* 校验核心在 agents/node-delegation.ts;本文件只做工具面参数解析与结果文本。
|
|
7
|
+
*/
|
|
8
|
+
import { AppError } from '../../../../../utils/errors'
|
|
9
|
+
import { applyDelegation, planDelegation, revokeDelegation, type DelegationMember } from '../../node-delegation'
|
|
10
|
+
import type { HostToolBridgeContext, HostToolResult } from '../types'
|
|
11
|
+
|
|
12
|
+
/** workspace 成员视图(listAgents 与本工具面的最小接口;便于单测桩替换) */
|
|
13
|
+
interface MembersView {
|
|
14
|
+
listAgents(): Promise<Array<{ id: string, role: 'lead' | 'worker', enabled?: number }>>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function membersOf(ws: MembersView): Promise<DelegationMember[]> {
|
|
18
|
+
return ws.listAgents() as Promise<DelegationMember[]>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function summaryText(bindings: Array<{ nodeId: string, kind: string, mode: string }>): string {
|
|
22
|
+
const lines = bindings.map(b => ` - ${b.kind === 'daq' ? '数采' : '写控'} ${b.nodeId}(mode=${b.mode})`)
|
|
23
|
+
return `\n${lines.join('\n')}`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseNodeIds(args: Record<string, unknown>): string[] {
|
|
27
|
+
const raw = args.node_ids ?? args.nodeIds
|
|
28
|
+
const list = Array.isArray(raw) ? raw : String(raw ?? '').split(',')
|
|
29
|
+
return list.map(x => String(x ?? '').trim()).filter(Boolean)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** lead → worker 授予节点(自己绑定面内的节点;fail-closed 全成全败) */
|
|
33
|
+
export async function handleGrantNodes(identity: HostToolBridgeContext['identity'], args: Record<string, unknown>, ws: MembersView): Promise<HostToolResult> {
|
|
34
|
+
const targetAgentId = String(args.agent_id ?? args.assignee_id ?? '').trim()
|
|
35
|
+
const nodeIds = parseNodeIds(args)
|
|
36
|
+
const mode = args.mode === 'manual' || args.mode === 'auto' ? (args.mode as 'auto' | 'manual') : undefined
|
|
37
|
+
try {
|
|
38
|
+
const plan = planDelegation({
|
|
39
|
+
leaderAgentId: identity.agentId,
|
|
40
|
+
channelId: identity.channelId,
|
|
41
|
+
targetAgentId,
|
|
42
|
+
nodeIds,
|
|
43
|
+
members: await membersOf(ws),
|
|
44
|
+
mode,
|
|
45
|
+
})
|
|
46
|
+
const bindings = applyDelegation(plan, identity.agentId)
|
|
47
|
+
return {
|
|
48
|
+
text: `已把 ${bindings.length} 条节点授权授予 ${targetAgentId}:${summaryText(bindings)}\n来源:lead 绑定面内的节点;worker 现在可用 my_industrial_nodes 查看自己的授权。`,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
return { text: err instanceof AppError ? err.message : `节点授权失败: ${err instanceof Error ? err.message : String(err)}`, isError: true }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** lead 收回授予给 worker 的节点授权 */
|
|
57
|
+
export async function handleRevokeNodes(identity: HostToolBridgeContext['identity'], args: Record<string, unknown>, ws: MembersView): Promise<HostToolResult> {
|
|
58
|
+
const targetAgentId = String(args.agent_id ?? args.assignee_id ?? '').trim()
|
|
59
|
+
const nodeIds = parseNodeIds(args)
|
|
60
|
+
try {
|
|
61
|
+
const results = revokeDelegation({
|
|
62
|
+
leaderAgentId: identity.agentId,
|
|
63
|
+
targetAgentId,
|
|
64
|
+
nodeIds,
|
|
65
|
+
members: await membersOf(ws),
|
|
66
|
+
})
|
|
67
|
+
const okList = results.filter(r => r.revoked)
|
|
68
|
+
const missList = results.filter(r => !r.revoked)
|
|
69
|
+
const parts = [`已收回 ${okList.length} 条授权`, ...okList.map(r => ` - ${r.kind} ${r.nodeId}`)]
|
|
70
|
+
if (missList.length) parts.push(`未收回(不在其绑定面或非你授予):${missList.map(r => `${r.kind}:${r.nodeId}`).join('、')}`)
|
|
71
|
+
return { text: parts.join('\n') }
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
return { text: err instanceof AppError ? err.message : `收回授权失败: ${err instanceof Error ? err.message : String(err)}`, isError: true }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface DispatchGrantResult {
|
|
79
|
+
ok: boolean
|
|
80
|
+
text: string
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 派发时随任务授予节点(dispatch_task 的 grant_node_ids;lead 专属)。
|
|
85
|
+
* fail-closed:任一节点不在 lead 绑定面 → 整单失败,任务不创建。
|
|
86
|
+
*/
|
|
87
|
+
export async function grantNodesForDispatch(identity: HostToolBridgeContext['identity'], assigneeId: string, nodeIds: string[], mode: 'auto' | 'manual' | undefined, ws: MembersView): Promise<DispatchGrantResult> {
|
|
88
|
+
try {
|
|
89
|
+
const plan = planDelegation({
|
|
90
|
+
leaderAgentId: identity.agentId,
|
|
91
|
+
channelId: identity.channelId,
|
|
92
|
+
targetAgentId: assigneeId,
|
|
93
|
+
nodeIds,
|
|
94
|
+
members: await membersOf(ws),
|
|
95
|
+
mode,
|
|
96
|
+
})
|
|
97
|
+
const bindings = applyDelegation(plan, identity.agentId)
|
|
98
|
+
return { ok: true, text: `随任务授予 ${bindings.length} 条节点授权 → ${assigneeId}${summaryText(bindings)}` }
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
const msg = err instanceof AppError ? err.message : `随任务授予节点失败: ${err instanceof Error ? err.message : String(err)}`
|
|
102
|
+
return { ok: false, text: msg }
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -38,6 +38,10 @@ export interface AgentNodeBinding {
|
|
|
38
38
|
kind: AgentNodeBindingKind
|
|
39
39
|
mode: AgentNodeBindingMode
|
|
40
40
|
tuning?: AgentNodeBindingTuning
|
|
41
|
+
/** 委派来源:lead 经 team_grant_nodes / dispatch_task(grant_node_ids) 授予时 = lead 成员实例 id */
|
|
42
|
+
grantedByAgentId?: string
|
|
43
|
+
/** 委派时间(ISO;仅委派产生的绑定携带) */
|
|
44
|
+
grantedAt?: string
|
|
41
45
|
createdAt: string
|
|
42
46
|
}
|
|
43
47
|
|
|
@@ -83,7 +87,7 @@ export class AgentNodeBindingRepo {
|
|
|
83
87
|
return this.list.find(b => b.agentId === agentId && b.nodeId === nodeId && b.kind === kind)
|
|
84
88
|
}
|
|
85
89
|
|
|
86
|
-
bind(agentId: string, nodeId: string, kind: AgentNodeBindingKind, mode: AgentNodeBindingMode, tuning?: AgentNodeBindingTuning): AgentNodeBinding {
|
|
90
|
+
bind(agentId: string, nodeId: string, kind: AgentNodeBindingKind, mode: AgentNodeBindingMode, tuning?: AgentNodeBindingTuning, provenance?: { grantedByAgentId?: string }): AgentNodeBinding {
|
|
87
91
|
if (!agentId) throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'agentId 必填')
|
|
88
92
|
if (!nodeId) throw new AppError(400, ErrorCodes.VALIDATION_ERROR, 'nodeId 必填')
|
|
89
93
|
if (kind !== 'dcw' && kind !== 'daq') throw new AppError(400, ErrorCodes.VALIDATION_ERROR, `未知节点类型: ${kind}`)
|
|
@@ -92,6 +96,10 @@ export class AgentNodeBindingRepo {
|
|
|
92
96
|
if (prev) {
|
|
93
97
|
prev.mode = mode
|
|
94
98
|
if (tuning !== undefined) prev.tuning = normalizeTuning(tuning)
|
|
99
|
+
if (provenance?.grantedByAgentId) {
|
|
100
|
+
prev.grantedByAgentId = provenance.grantedByAgentId
|
|
101
|
+
prev.grantedAt = new Date().toISOString()
|
|
102
|
+
}
|
|
95
103
|
this.flush()
|
|
96
104
|
return prev
|
|
97
105
|
}
|
|
@@ -102,6 +110,7 @@ export class AgentNodeBindingRepo {
|
|
|
102
110
|
kind,
|
|
103
111
|
mode,
|
|
104
112
|
...(tuning ? { tuning: normalizeTuning(tuning) } : {}),
|
|
113
|
+
...(provenance?.grantedByAgentId ? { grantedByAgentId: provenance.grantedByAgentId, grantedAt: new Date().toISOString() } : {}),
|
|
105
114
|
createdAt: new Date().toISOString(),
|
|
106
115
|
}
|
|
107
116
|
this.list.push(binding)
|