@robota-sdk/agent-core 3.0.0-beta.1
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/CHANGELOG.md +180 -0
- package/LICENSE +21 -0
- package/README.md +230 -0
- package/dist/abstracts/abstract-agent.d.ts +56 -0
- package/dist/abstracts/abstract-agent.d.ts.map +1 -0
- package/dist/abstracts/abstract-agent.js +55 -0
- package/dist/abstracts/abstract-agent.js.map +1 -0
- package/dist/abstracts/abstract-ai-provider.d.ts +187 -0
- package/dist/abstracts/abstract-ai-provider.d.ts.map +1 -0
- package/dist/abstracts/abstract-ai-provider.js +252 -0
- package/dist/abstracts/abstract-ai-provider.js.map +1 -0
- package/dist/abstracts/abstract-executor.d.ts +110 -0
- package/dist/abstracts/abstract-executor.d.ts.map +1 -0
- package/dist/abstracts/abstract-executor.js +156 -0
- package/dist/abstracts/abstract-executor.js.map +1 -0
- package/dist/abstracts/abstract-manager.d.ts +42 -0
- package/dist/abstracts/abstract-manager.d.ts.map +1 -0
- package/dist/abstracts/abstract-manager.js +49 -0
- package/dist/abstracts/abstract-manager.js.map +1 -0
- package/dist/abstracts/abstract-module.d.ts +365 -0
- package/dist/abstracts/abstract-module.d.ts.map +1 -0
- package/dist/abstracts/abstract-module.js +474 -0
- package/dist/abstracts/abstract-module.js.map +1 -0
- package/dist/abstracts/abstract-plugin.d.ts +369 -0
- package/dist/abstracts/abstract-plugin.d.ts.map +1 -0
- package/dist/abstracts/abstract-plugin.js +258 -0
- package/dist/abstracts/abstract-plugin.js.map +1 -0
- package/dist/abstracts/abstract-tool.d.ts +175 -0
- package/dist/abstracts/abstract-tool.d.ts.map +1 -0
- package/dist/abstracts/abstract-tool.js +140 -0
- package/dist/abstracts/abstract-tool.js.map +1 -0
- package/dist/abstracts/abstract-workflow-converter.d.ts +136 -0
- package/dist/abstracts/abstract-workflow-converter.d.ts.map +1 -0
- package/dist/abstracts/abstract-workflow-converter.js +252 -0
- package/dist/abstracts/abstract-workflow-converter.js.map +1 -0
- package/dist/abstracts/abstract-workflow-validator.d.ts +203 -0
- package/dist/abstracts/abstract-workflow-validator.d.ts.map +1 -0
- package/dist/abstracts/abstract-workflow-validator.js +447 -0
- package/dist/abstracts/abstract-workflow-validator.js.map +1 -0
- package/dist/abstracts/index.d.ts +6 -0
- package/dist/abstracts/index.d.ts.map +1 -0
- package/dist/abstracts/index.js +9 -0
- package/dist/abstracts/index.js.map +1 -0
- package/dist/agents/constants.d.ts +23 -0
- package/dist/agents/constants.d.ts.map +1 -0
- package/dist/agents/constants.js +22 -0
- package/dist/agents/constants.js.map +1 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +4 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/robota.test.d.ts +2 -0
- package/dist/agents/robota.test.d.ts.map +1 -0
- package/dist/agents/robota.test.js +416 -0
- package/dist/agents/robota.test.js.map +1 -0
- package/dist/browser/builtin-templates.json +107 -0
- package/dist/browser/index.d.ts +4237 -0
- package/dist/browser/index.js +4 -0
- package/dist/core/robota.d.ts +694 -0
- package/dist/core/robota.d.ts.map +1 -0
- package/dist/core/robota.js +1277 -0
- package/dist/core/robota.js.map +1 -0
- package/dist/executors/local-executor.d.ts +96 -0
- package/dist/executors/local-executor.d.ts.map +1 -0
- package/dist/executors/local-executor.js +197 -0
- package/dist/executors/local-executor.js.map +1 -0
- package/dist/executors/local-executor.test.d.ts +2 -0
- package/dist/executors/local-executor.test.d.ts.map +1 -0
- package/dist/executors/local-executor.test.js +192 -0
- package/dist/executors/local-executor.test.js.map +1 -0
- package/dist/index.d.ts +274 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +235 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/agent.d.ts +198 -0
- package/dist/interfaces/agent.d.ts.map +1 -0
- package/dist/interfaces/agent.js +2 -0
- package/dist/interfaces/agent.js.map +1 -0
- package/dist/interfaces/event-service.d.ts +79 -0
- package/dist/interfaces/event-service.d.ts.map +1 -0
- package/dist/interfaces/event-service.js +2 -0
- package/dist/interfaces/event-service.js.map +1 -0
- package/dist/interfaces/executor.d.ts +128 -0
- package/dist/interfaces/executor.d.ts.map +1 -0
- package/dist/interfaces/executor.js +2 -0
- package/dist/interfaces/executor.js.map +1 -0
- package/dist/interfaces/history-module.d.ts +19 -0
- package/dist/interfaces/history-module.d.ts.map +1 -0
- package/dist/interfaces/history-module.js +2 -0
- package/dist/interfaces/history-module.js.map +1 -0
- package/dist/interfaces/index.d.ts +13 -0
- package/dist/interfaces/index.d.ts.map +1 -0
- package/dist/interfaces/index.js +4 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/interfaces/manager.d.ts +142 -0
- package/dist/interfaces/manager.d.ts.map +1 -0
- package/dist/interfaces/manager.js +2 -0
- package/dist/interfaces/manager.js.map +1 -0
- package/dist/interfaces/messages.d.ts +75 -0
- package/dist/interfaces/messages.d.ts.map +1 -0
- package/dist/interfaces/messages.js +29 -0
- package/dist/interfaces/messages.js.map +1 -0
- package/dist/interfaces/progress-reporting.d.ts +86 -0
- package/dist/interfaces/progress-reporting.d.ts.map +1 -0
- package/dist/interfaces/progress-reporting.js +37 -0
- package/dist/interfaces/progress-reporting.js.map +1 -0
- package/dist/interfaces/provider.d.ts +217 -0
- package/dist/interfaces/provider.d.ts.map +1 -0
- package/dist/interfaces/provider.js +2 -0
- package/dist/interfaces/provider.js.map +1 -0
- package/dist/interfaces/service.d.ts +205 -0
- package/dist/interfaces/service.d.ts.map +1 -0
- package/dist/interfaces/service.js +6 -0
- package/dist/interfaces/service.js.map +1 -0
- package/dist/interfaces/tool.d.ts +248 -0
- package/dist/interfaces/tool.d.ts.map +1 -0
- package/dist/interfaces/tool.js +2 -0
- package/dist/interfaces/tool.js.map +1 -0
- package/dist/interfaces/types.d.ts +71 -0
- package/dist/interfaces/types.d.ts.map +1 -0
- package/dist/interfaces/types.js +33 -0
- package/dist/interfaces/types.js.map +1 -0
- package/dist/interfaces/workflow-converter.d.ts +193 -0
- package/dist/interfaces/workflow-converter.d.ts.map +1 -0
- package/dist/interfaces/workflow-converter.js +11 -0
- package/dist/interfaces/workflow-converter.js.map +1 -0
- package/dist/interfaces/workflow-validator.d.ts +209 -0
- package/dist/interfaces/workflow-validator.d.ts.map +1 -0
- package/dist/interfaces/workflow-validator.js +16 -0
- package/dist/interfaces/workflow-validator.js.map +1 -0
- package/dist/managers/agent-factory.d.ts +132 -0
- package/dist/managers/agent-factory.d.ts.map +1 -0
- package/dist/managers/agent-factory.js +284 -0
- package/dist/managers/agent-factory.js.map +1 -0
- package/dist/managers/agent-factory.test.d.ts +2 -0
- package/dist/managers/agent-factory.test.d.ts.map +1 -0
- package/dist/managers/agent-factory.test.js +249 -0
- package/dist/managers/agent-factory.test.js.map +1 -0
- package/dist/managers/agent-templates.d.ts +84 -0
- package/dist/managers/agent-templates.d.ts.map +1 -0
- package/dist/managers/agent-templates.js +159 -0
- package/dist/managers/agent-templates.js.map +1 -0
- package/dist/managers/ai-provider-manager.d.ts +80 -0
- package/dist/managers/ai-provider-manager.d.ts.map +1 -0
- package/dist/managers/ai-provider-manager.js +226 -0
- package/dist/managers/ai-provider-manager.js.map +1 -0
- package/dist/managers/conversation-history-manager.d.ts +455 -0
- package/dist/managers/conversation-history-manager.d.ts.map +1 -0
- package/dist/managers/conversation-history-manager.js +578 -0
- package/dist/managers/conversation-history-manager.js.map +1 -0
- package/dist/managers/conversation-history-manager.test.d.ts +2 -0
- package/dist/managers/conversation-history-manager.test.d.ts.map +1 -0
- package/dist/managers/conversation-history-manager.test.js +374 -0
- package/dist/managers/conversation-history-manager.test.js.map +1 -0
- package/dist/managers/index.d.ts +8 -0
- package/dist/managers/index.d.ts.map +1 -0
- package/dist/managers/index.js +8 -0
- package/dist/managers/index.js.map +1 -0
- package/dist/managers/module-registry.d.ts +161 -0
- package/dist/managers/module-registry.d.ts.map +1 -0
- package/dist/managers/module-registry.js +519 -0
- package/dist/managers/module-registry.js.map +1 -0
- package/dist/managers/module-type-registry.d.ts +113 -0
- package/dist/managers/module-type-registry.d.ts.map +1 -0
- package/dist/managers/module-type-registry.js +439 -0
- package/dist/managers/module-type-registry.js.map +1 -0
- package/dist/managers/plugins.d.ts +166 -0
- package/dist/managers/plugins.d.ts.map +1 -0
- package/dist/managers/plugins.js +339 -0
- package/dist/managers/plugins.js.map +1 -0
- package/dist/managers/tool-manager.d.ts +70 -0
- package/dist/managers/tool-manager.d.ts.map +1 -0
- package/dist/managers/tool-manager.js +138 -0
- package/dist/managers/tool-manager.js.map +1 -0
- package/dist/managers/tool-manager.test.d.ts +2 -0
- package/dist/managers/tool-manager.test.d.ts.map +1 -0
- package/dist/managers/tool-manager.test.js +186 -0
- package/dist/managers/tool-manager.test.js.map +1 -0
- package/dist/node/builtin-templates.json +107 -0
- package/dist/node/index.cjs +4 -0
- package/dist/node/index.d.cts +4237 -0
- package/dist/node/index.d.ts +4237 -0
- package/dist/node/index.js +4 -0
- package/dist/plugins/conversation-history/conversation-history-plugin.d.ts +67 -0
- package/dist/plugins/conversation-history/conversation-history-plugin.d.ts.map +1 -0
- package/dist/plugins/conversation-history/conversation-history-plugin.js +270 -0
- package/dist/plugins/conversation-history/conversation-history-plugin.js.map +1 -0
- package/dist/plugins/conversation-history/index.d.ts +3 -0
- package/dist/plugins/conversation-history/index.d.ts.map +1 -0
- package/dist/plugins/conversation-history/index.js +2 -0
- package/dist/plugins/conversation-history/index.js.map +1 -0
- package/dist/plugins/conversation-history/storages/database-storage.d.ts +19 -0
- package/dist/plugins/conversation-history/storages/database-storage.d.ts.map +1 -0
- package/dist/plugins/conversation-history/storages/database-storage.js +94 -0
- package/dist/plugins/conversation-history/storages/database-storage.js.map +1 -0
- package/dist/plugins/conversation-history/storages/file-storage.d.ts +15 -0
- package/dist/plugins/conversation-history/storages/file-storage.d.ts.map +1 -0
- package/dist/plugins/conversation-history/storages/file-storage.js +94 -0
- package/dist/plugins/conversation-history/storages/file-storage.js.map +1 -0
- package/dist/plugins/conversation-history/storages/index.d.ts +4 -0
- package/dist/plugins/conversation-history/storages/index.d.ts.map +1 -0
- package/dist/plugins/conversation-history/storages/index.js +4 -0
- package/dist/plugins/conversation-history/storages/index.js.map +1 -0
- package/dist/plugins/conversation-history/storages/memory-storage.d.ts +15 -0
- package/dist/plugins/conversation-history/storages/memory-storage.d.ts.map +1 -0
- package/dist/plugins/conversation-history/storages/memory-storage.js +33 -0
- package/dist/plugins/conversation-history/storages/memory-storage.js.map +1 -0
- package/dist/plugins/conversation-history/types.d.ts +61 -0
- package/dist/plugins/conversation-history/types.d.ts.map +1 -0
- package/dist/plugins/conversation-history/types.js +2 -0
- package/dist/plugins/conversation-history/types.js.map +1 -0
- package/dist/plugins/error-handling/context-adapter.d.ts +30 -0
- package/dist/plugins/error-handling/context-adapter.d.ts.map +1 -0
- package/dist/plugins/error-handling/context-adapter.js +41 -0
- package/dist/plugins/error-handling/context-adapter.js.map +1 -0
- package/dist/plugins/error-handling/error-handling-plugin.d.ts +49 -0
- package/dist/plugins/error-handling/error-handling-plugin.d.ts.map +1 -0
- package/dist/plugins/error-handling/error-handling-plugin.js +229 -0
- package/dist/plugins/error-handling/error-handling-plugin.js.map +1 -0
- package/dist/plugins/error-handling/index.d.ts +10 -0
- package/dist/plugins/error-handling/index.d.ts.map +1 -0
- package/dist/plugins/error-handling/index.js +10 -0
- package/dist/plugins/error-handling/index.js.map +1 -0
- package/dist/plugins/error-handling/types.d.ts +73 -0
- package/dist/plugins/error-handling/types.d.ts.map +1 -0
- package/dist/plugins/error-handling/types.js +14 -0
- package/dist/plugins/error-handling/types.js.map +1 -0
- package/dist/plugins/event-emitter/metrics.d.ts +17 -0
- package/dist/plugins/event-emitter/metrics.d.ts.map +1 -0
- package/dist/plugins/event-emitter/metrics.js +17 -0
- package/dist/plugins/event-emitter/metrics.js.map +1 -0
- package/dist/plugins/event-emitter/types.d.ts +112 -0
- package/dist/plugins/event-emitter/types.d.ts.map +1 -0
- package/dist/plugins/event-emitter/types.js +65 -0
- package/dist/plugins/event-emitter/types.js.map +1 -0
- package/dist/plugins/event-emitter-plugin.d.ts +222 -0
- package/dist/plugins/event-emitter-plugin.d.ts.map +1 -0
- package/dist/plugins/event-emitter-plugin.js +432 -0
- package/dist/plugins/event-emitter-plugin.js.map +1 -0
- package/dist/plugins/event-emitter-plugin.test.d.ts +2 -0
- package/dist/plugins/event-emitter-plugin.test.d.ts.map +1 -0
- package/dist/plugins/event-emitter-plugin.test.js +94 -0
- package/dist/plugins/event-emitter-plugin.test.js.map +1 -0
- package/dist/plugins/execution/execution-analytics-plugin.d.ts +129 -0
- package/dist/plugins/execution/execution-analytics-plugin.d.ts.map +1 -0
- package/dist/plugins/execution/execution-analytics-plugin.js +517 -0
- package/dist/plugins/execution/execution-analytics-plugin.js.map +1 -0
- package/dist/plugins/execution/index.d.ts +3 -0
- package/dist/plugins/execution/index.d.ts.map +1 -0
- package/dist/plugins/execution/index.js +2 -0
- package/dist/plugins/execution/index.js.map +1 -0
- package/dist/plugins/execution/types.d.ts +90 -0
- package/dist/plugins/execution/types.d.ts.map +1 -0
- package/dist/plugins/execution/types.js +2 -0
- package/dist/plugins/execution/types.js.map +1 -0
- package/dist/plugins/index.d.ts +10 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +11 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/limits/types.d.ts +61 -0
- package/dist/plugins/limits/types.d.ts.map +1 -0
- package/dist/plugins/limits/types.js +2 -0
- package/dist/plugins/limits/types.js.map +1 -0
- package/dist/plugins/limits-plugin.d.ts +113 -0
- package/dist/plugins/limits-plugin.d.ts.map +1 -0
- package/dist/plugins/limits-plugin.js +380 -0
- package/dist/plugins/limits-plugin.js.map +1 -0
- package/dist/plugins/logging/formatters.d.ts +14 -0
- package/dist/plugins/logging/formatters.d.ts.map +1 -0
- package/dist/plugins/logging/formatters.js +24 -0
- package/dist/plugins/logging/formatters.js.map +1 -0
- package/dist/plugins/logging/index.d.ts +3 -0
- package/dist/plugins/logging/index.d.ts.map +1 -0
- package/dist/plugins/logging/index.js +2 -0
- package/dist/plugins/logging/index.js.map +1 -0
- package/dist/plugins/logging/logging-plugin.d.ts +91 -0
- package/dist/plugins/logging/logging-plugin.d.ts.map +1 -0
- package/dist/plugins/logging/logging-plugin.js +335 -0
- package/dist/plugins/logging/logging-plugin.js.map +1 -0
- package/dist/plugins/logging/storages/console-storage.d.ts +14 -0
- package/dist/plugins/logging/storages/console-storage.d.ts.map +1 -0
- package/dist/plugins/logging/storages/console-storage.js +38 -0
- package/dist/plugins/logging/storages/console-storage.js.map +1 -0
- package/dist/plugins/logging/storages/file-storage.d.ts +14 -0
- package/dist/plugins/logging/storages/file-storage.d.ts.map +1 -0
- package/dist/plugins/logging/storages/file-storage.js +41 -0
- package/dist/plugins/logging/storages/file-storage.js.map +1 -0
- package/dist/plugins/logging/storages/index.d.ts +5 -0
- package/dist/plugins/logging/storages/index.d.ts.map +1 -0
- package/dist/plugins/logging/storages/index.js +5 -0
- package/dist/plugins/logging/storages/index.js.map +1 -0
- package/dist/plugins/logging/storages/remote-storage.d.ts +20 -0
- package/dist/plugins/logging/storages/remote-storage.d.ts.map +1 -0
- package/dist/plugins/logging/storages/remote-storage.js +61 -0
- package/dist/plugins/logging/storages/remote-storage.js.map +1 -0
- package/dist/plugins/logging/storages/silent-storage.d.ts +10 -0
- package/dist/plugins/logging/storages/silent-storage.d.ts.map +1 -0
- package/dist/plugins/logging/storages/silent-storage.js +15 -0
- package/dist/plugins/logging/storages/silent-storage.js.map +1 -0
- package/dist/plugins/logging/types.d.ts +84 -0
- package/dist/plugins/logging/types.d.ts.map +1 -0
- package/dist/plugins/logging/types.js +2 -0
- package/dist/plugins/logging/types.js.map +1 -0
- package/dist/plugins/performance/collectors/system-metrics-collector.d.ts +12 -0
- package/dist/plugins/performance/collectors/system-metrics-collector.d.ts.map +1 -0
- package/dist/plugins/performance/collectors/system-metrics-collector.js +65 -0
- package/dist/plugins/performance/collectors/system-metrics-collector.js.map +1 -0
- package/dist/plugins/performance/index.d.ts +5 -0
- package/dist/plugins/performance/index.d.ts.map +1 -0
- package/dist/plugins/performance/index.js +4 -0
- package/dist/plugins/performance/index.js.map +1 -0
- package/dist/plugins/performance/performance-plugin.d.ts +49 -0
- package/dist/plugins/performance/performance-plugin.d.ts.map +1 -0
- package/dist/plugins/performance/performance-plugin.js +293 -0
- package/dist/plugins/performance/performance-plugin.js.map +1 -0
- package/dist/plugins/performance/storages/index.d.ts +2 -0
- package/dist/plugins/performance/storages/index.d.ts.map +1 -0
- package/dist/plugins/performance/storages/index.js +4 -0
- package/dist/plugins/performance/storages/index.js.map +1 -0
- package/dist/plugins/performance/storages/memory-storage.d.ts +19 -0
- package/dist/plugins/performance/storages/memory-storage.d.ts.map +1 -0
- package/dist/plugins/performance/storages/memory-storage.js +69 -0
- package/dist/plugins/performance/storages/memory-storage.js.map +1 -0
- package/dist/plugins/performance/types.d.ts +154 -0
- package/dist/plugins/performance/types.d.ts.map +1 -0
- package/dist/plugins/performance/types.js +2 -0
- package/dist/plugins/performance/types.js.map +1 -0
- package/dist/plugins/usage/aggregate-usage-stats.d.ts +12 -0
- package/dist/plugins/usage/aggregate-usage-stats.d.ts.map +1 -0
- package/dist/plugins/usage/aggregate-usage-stats.js +115 -0
- package/dist/plugins/usage/aggregate-usage-stats.js.map +1 -0
- package/dist/plugins/usage/index.d.ts +5 -0
- package/dist/plugins/usage/index.d.ts.map +1 -0
- package/dist/plugins/usage/index.js +4 -0
- package/dist/plugins/usage/index.js.map +1 -0
- package/dist/plugins/usage/storages/file-storage.d.ts +22 -0
- package/dist/plugins/usage/storages/file-storage.d.ts.map +1 -0
- package/dist/plugins/usage/storages/file-storage.js +111 -0
- package/dist/plugins/usage/storages/file-storage.js.map +1 -0
- package/dist/plugins/usage/storages/index.d.ts +5 -0
- package/dist/plugins/usage/storages/index.d.ts.map +1 -0
- package/dist/plugins/usage/storages/index.js +5 -0
- package/dist/plugins/usage/storages/index.js.map +1 -0
- package/dist/plugins/usage/storages/memory-storage.d.ts +22 -0
- package/dist/plugins/usage/storages/memory-storage.d.ts.map +1 -0
- package/dist/plugins/usage/storages/memory-storage.js +42 -0
- package/dist/plugins/usage/storages/memory-storage.js.map +1 -0
- package/dist/plugins/usage/storages/remote-storage.d.ts +26 -0
- package/dist/plugins/usage/storages/remote-storage.d.ts.map +1 -0
- package/dist/plugins/usage/storages/remote-storage.js +115 -0
- package/dist/plugins/usage/storages/remote-storage.js.map +1 -0
- package/dist/plugins/usage/storages/silent-storage.d.ts +19 -0
- package/dist/plugins/usage/storages/silent-storage.d.ts.map +1 -0
- package/dist/plugins/usage/storages/silent-storage.js +26 -0
- package/dist/plugins/usage/storages/silent-storage.js.map +1 -0
- package/dist/plugins/usage/types.d.ts +127 -0
- package/dist/plugins/usage/types.d.ts.map +1 -0
- package/dist/plugins/usage/types.js +2 -0
- package/dist/plugins/usage/types.js.map +1 -0
- package/dist/plugins/usage/usage-plugin.d.ts +67 -0
- package/dist/plugins/usage/usage-plugin.d.ts.map +1 -0
- package/dist/plugins/usage/usage-plugin.js +309 -0
- package/dist/plugins/usage/usage-plugin.js.map +1 -0
- package/dist/plugins/webhook/http-client.d.ts +30 -0
- package/dist/plugins/webhook/http-client.d.ts.map +1 -0
- package/dist/plugins/webhook/http-client.js +110 -0
- package/dist/plugins/webhook/http-client.js.map +1 -0
- package/dist/plugins/webhook/index.d.ts +9 -0
- package/dist/plugins/webhook/index.d.ts.map +1 -0
- package/dist/plugins/webhook/index.js +9 -0
- package/dist/plugins/webhook/index.js.map +1 -0
- package/dist/plugins/webhook/transformer.d.ts +63 -0
- package/dist/plugins/webhook/transformer.d.ts.map +1 -0
- package/dist/plugins/webhook/transformer.js +157 -0
- package/dist/plugins/webhook/transformer.js.map +1 -0
- package/dist/plugins/webhook/types.d.ts +183 -0
- package/dist/plugins/webhook/types.d.ts.map +1 -0
- package/dist/plugins/webhook/types.js +2 -0
- package/dist/plugins/webhook/types.js.map +1 -0
- package/dist/plugins/webhook/webhook-plugin.d.ts +92 -0
- package/dist/plugins/webhook/webhook-plugin.d.ts.map +1 -0
- package/dist/plugins/webhook/webhook-plugin.js +328 -0
- package/dist/plugins/webhook/webhook-plugin.js.map +1 -0
- package/dist/schemas/agent-template-schema.d.ts +137 -0
- package/dist/schemas/agent-template-schema.d.ts.map +1 -0
- package/dist/schemas/agent-template-schema.js +87 -0
- package/dist/schemas/agent-template-schema.js.map +1 -0
- package/dist/services/conversation-service/index.d.ts +88 -0
- package/dist/services/conversation-service/index.d.ts.map +1 -0
- package/dist/services/conversation-service/index.js +441 -0
- package/dist/services/conversation-service/index.js.map +1 -0
- package/dist/services/conversation-service/types.d.ts +32 -0
- package/dist/services/conversation-service/types.d.ts.map +1 -0
- package/dist/services/conversation-service/types.js +8 -0
- package/dist/services/conversation-service/types.js.map +1 -0
- package/dist/services/event-service.d.ts +61 -0
- package/dist/services/event-service.d.ts.map +1 -0
- package/dist/services/event-service.js +110 -0
- package/dist/services/event-service.js.map +1 -0
- package/dist/services/event-service.test.d.ts +2 -0
- package/dist/services/event-service.test.d.ts.map +1 -0
- package/dist/services/event-service.test.js +86 -0
- package/dist/services/event-service.test.js.map +1 -0
- package/dist/services/execution-service.d.ts +151 -0
- package/dist/services/execution-service.d.ts.map +1 -0
- package/dist/services/execution-service.js +1262 -0
- package/dist/services/execution-service.js.map +1 -0
- package/dist/services/execution-service.test.d.ts +2 -0
- package/dist/services/execution-service.test.d.ts.map +1 -0
- package/dist/services/execution-service.test.js +338 -0
- package/dist/services/execution-service.test.js.map +1 -0
- package/dist/services/history-module.d.ts +15 -0
- package/dist/services/history-module.d.ts.map +1 -0
- package/dist/services/history-module.js +42 -0
- package/dist/services/history-module.js.map +1 -0
- package/dist/services/in-memory-history-store.d.ts +12 -0
- package/dist/services/in-memory-history-store.d.ts.map +1 -0
- package/dist/services/in-memory-history-store.js +41 -0
- package/dist/services/in-memory-history-store.js.map +1 -0
- package/dist/services/index.d.ts +7 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +13 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/task-events.d.ts +6 -0
- package/dist/services/task-events.d.ts.map +1 -0
- package/dist/services/task-events.js +6 -0
- package/dist/services/task-events.js.map +1 -0
- package/dist/services/tool-execution-service.d.ts +74 -0
- package/dist/services/tool-execution-service.d.ts.map +1 -0
- package/dist/services/tool-execution-service.js +189 -0
- package/dist/services/tool-execution-service.js.map +1 -0
- package/dist/services/user-events.d.ts +7 -0
- package/dist/services/user-events.d.ts.map +1 -0
- package/dist/services/user-events.js +6 -0
- package/dist/services/user-events.js.map +1 -0
- package/dist/tools/implementations/function-tool/index.d.ts +9 -0
- package/dist/tools/implementations/function-tool/index.d.ts.map +1 -0
- package/dist/tools/implementations/function-tool/index.js +13 -0
- package/dist/tools/implementations/function-tool/index.js.map +1 -0
- package/dist/tools/implementations/function-tool/schema-converter.d.ts +32 -0
- package/dist/tools/implementations/function-tool/schema-converter.d.ts.map +1 -0
- package/dist/tools/implementations/function-tool/schema-converter.js +164 -0
- package/dist/tools/implementations/function-tool/schema-converter.js.map +1 -0
- package/dist/tools/implementations/function-tool/types.d.ts +72 -0
- package/dist/tools/implementations/function-tool/types.d.ts.map +1 -0
- package/dist/tools/implementations/function-tool/types.js +14 -0
- package/dist/tools/implementations/function-tool/types.js.map +1 -0
- package/dist/tools/implementations/function-tool.d.ts +49 -0
- package/dist/tools/implementations/function-tool.d.ts.map +1 -0
- package/dist/tools/implementations/function-tool.js +223 -0
- package/dist/tools/implementations/function-tool.js.map +1 -0
- package/dist/tools/implementations/index.d.ts +4 -0
- package/dist/tools/implementations/index.d.ts.map +1 -0
- package/dist/tools/implementations/index.js +5 -0
- package/dist/tools/implementations/index.js.map +1 -0
- package/dist/tools/implementations/mcp-tool.d.ts +72 -0
- package/dist/tools/implementations/mcp-tool.d.ts.map +1 -0
- package/dist/tools/implementations/mcp-tool.js +246 -0
- package/dist/tools/implementations/mcp-tool.js.map +1 -0
- package/dist/tools/implementations/openapi-tool.d.ts +56 -0
- package/dist/tools/implementations/openapi-tool.d.ts.map +1 -0
- package/dist/tools/implementations/openapi-tool.js +324 -0
- package/dist/tools/implementations/openapi-tool.js.map +1 -0
- package/dist/tools/implementations/relay-mcp-tool.d.ts +38 -0
- package/dist/tools/implementations/relay-mcp-tool.d.ts.map +1 -0
- package/dist/tools/implementations/relay-mcp-tool.js +46 -0
- package/dist/tools/implementations/relay-mcp-tool.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/registry/index.d.ts +2 -0
- package/dist/tools/registry/index.d.ts.map +1 -0
- package/dist/tools/registry/index.js +3 -0
- package/dist/tools/registry/index.js.map +1 -0
- package/dist/tools/registry/tool-registry.d.ts +54 -0
- package/dist/tools/registry/tool-registry.d.ts.map +1 -0
- package/dist/tools/registry/tool-registry.js +146 -0
- package/dist/tools/registry/tool-registry.js.map +1 -0
- package/dist/utils/errors.d.ts +155 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +203 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/execution-proxy.d.ts +75 -0
- package/dist/utils/execution-proxy.d.ts.map +1 -0
- package/dist/utils/execution-proxy.js +230 -0
- package/dist/utils/execution-proxy.js.map +1 -0
- package/dist/utils/index.d.ts +11 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +74 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +143 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/message-converter.d.ts +68 -0
- package/dist/utils/message-converter.d.ts.map +1 -0
- package/dist/utils/message-converter.js +87 -0
- package/dist/utils/message-converter.js.map +1 -0
- package/dist/utils/periodic-task.d.ts +14 -0
- package/dist/utils/periodic-task.d.ts.map +1 -0
- package/dist/utils/periodic-task.js +26 -0
- package/dist/utils/periodic-task.js.map +1 -0
- package/dist/utils/validation.d.ts +40 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +162 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +101 -0
|
@@ -0,0 +1,1262 @@
|
|
|
1
|
+
import { ToolExecutionService, TOOL_EVENT_PREFIX } from './tool-execution-service';
|
|
2
|
+
import { createLogger } from '../utils/logger';
|
|
3
|
+
import { isDefaultEventService, bindWithOwnerPath } from './event-service';
|
|
4
|
+
/**
|
|
5
|
+
* ExecutionService owned events
|
|
6
|
+
* Local event names only (no dots). Full names are composed at emit time.
|
|
7
|
+
*/
|
|
8
|
+
export const EXECUTION_EVENTS = {
|
|
9
|
+
START: 'start',
|
|
10
|
+
COMPLETE: 'complete',
|
|
11
|
+
ERROR: 'error',
|
|
12
|
+
ASSISTANT_MESSAGE_START: 'assistant_message_start',
|
|
13
|
+
ASSISTANT_MESSAGE_COMPLETE: 'assistant_message_complete',
|
|
14
|
+
USER_MESSAGE: 'user_message',
|
|
15
|
+
TOOL_RESULTS_TO_LLM: 'tool_results_to_llm',
|
|
16
|
+
TOOL_RESULTS_READY: 'tool_results_ready'
|
|
17
|
+
};
|
|
18
|
+
export const EXECUTION_EVENT_PREFIX = 'execution';
|
|
19
|
+
// Type guard to check if error has execution properties
|
|
20
|
+
function isExecutionError(error) {
|
|
21
|
+
return 'executionId' in error || 'toolName' in error;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Service that orchestrates the entire execution pipeline
|
|
25
|
+
* Coordinates AI provider execution, tool execution service, and plugin lifecycle
|
|
26
|
+
* Uses centralized conversation history management
|
|
27
|
+
*/
|
|
28
|
+
export class ExecutionService {
|
|
29
|
+
toolExecutionService;
|
|
30
|
+
aiProviders;
|
|
31
|
+
tools;
|
|
32
|
+
conversationHistory;
|
|
33
|
+
plugins = [];
|
|
34
|
+
logger;
|
|
35
|
+
baseEventService;
|
|
36
|
+
executionContext; // 🎯 [CONTEXT-INJECTION] Parent execution context
|
|
37
|
+
ownerPathBase;
|
|
38
|
+
toolEventServices;
|
|
39
|
+
agentOwnerPathBase;
|
|
40
|
+
// Path-only: remove lastResponseExecutionId tracking
|
|
41
|
+
lastResponseExecutionId;
|
|
42
|
+
constructor(aiProviders, tools, conversationHistory, eventService, executionContext // 🎯 [CONTEXT-INJECTION] Accept parent context
|
|
43
|
+
) {
|
|
44
|
+
this.toolExecutionService = new ToolExecutionService(tools);
|
|
45
|
+
this.aiProviders = aiProviders;
|
|
46
|
+
this.tools = tools;
|
|
47
|
+
this.conversationHistory = conversationHistory;
|
|
48
|
+
this.plugins = [];
|
|
49
|
+
this.logger = createLogger('ExecutionService');
|
|
50
|
+
if (!eventService) {
|
|
51
|
+
throw new Error('[EXECUTION] EventService is required');
|
|
52
|
+
}
|
|
53
|
+
this.baseEventService = eventService;
|
|
54
|
+
this.executionContext = executionContext; // 🎯 [CONTEXT-INJECTION] Store parent context
|
|
55
|
+
this.ownerPathBase = this.buildBaseOwnerPath(executionContext);
|
|
56
|
+
this.toolEventServices = new Map();
|
|
57
|
+
this.agentOwnerPathBase = [];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Register a plugin
|
|
61
|
+
*/
|
|
62
|
+
registerPlugin(plugin) {
|
|
63
|
+
this.plugins.push(plugin);
|
|
64
|
+
this.logger.debug('Plugin registered', {
|
|
65
|
+
pluginName: plugin.name,
|
|
66
|
+
hasBeforeRun: typeof plugin.beforeRun,
|
|
67
|
+
hasAfterRun: typeof plugin.afterRun,
|
|
68
|
+
hasBeforeProviderCall: typeof plugin.beforeProviderCall,
|
|
69
|
+
hasAfterProviderCall: typeof plugin.afterProviderCall
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Remove a plugin
|
|
74
|
+
*/
|
|
75
|
+
removePlugin(pluginName) {
|
|
76
|
+
const index = this.plugins.findIndex(p => p.name === pluginName);
|
|
77
|
+
if (index !== -1) {
|
|
78
|
+
this.plugins.splice(index, 1);
|
|
79
|
+
this.logger.debug('Plugin removed', { pluginName });
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get a plugin by name
|
|
86
|
+
*/
|
|
87
|
+
getPlugin(pluginName) {
|
|
88
|
+
return this.plugins.find(p => p.name === pluginName) ?? null;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get all registered plugins
|
|
92
|
+
*/
|
|
93
|
+
getPlugins() {
|
|
94
|
+
return [...this.plugins];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Execute the full pipeline with centralized history management
|
|
98
|
+
*/
|
|
99
|
+
async execute(input, messages, config, context) {
|
|
100
|
+
// [EXECUTION-DEBUG] ExecutionService.execute entrypoint
|
|
101
|
+
// Avoid console usage; use injected logger only.
|
|
102
|
+
const executionId = this.generateExecutionId();
|
|
103
|
+
const startTime = new Date();
|
|
104
|
+
const conversationId = this.requireConversationId(context, 'execute');
|
|
105
|
+
const fullContext = {
|
|
106
|
+
messages,
|
|
107
|
+
config,
|
|
108
|
+
startTime,
|
|
109
|
+
executionId,
|
|
110
|
+
conversationId,
|
|
111
|
+
...(context?.sessionId && { sessionId: context.sessionId }),
|
|
112
|
+
...(context?.userId && { userId: context.userId }),
|
|
113
|
+
...(context?.metadata && { metadata: context.metadata })
|
|
114
|
+
};
|
|
115
|
+
this.prepareOwnerPathBases(conversationId);
|
|
116
|
+
this.logger.debug('Starting execution pipeline', {
|
|
117
|
+
executionId,
|
|
118
|
+
conversationId,
|
|
119
|
+
messageCount: messages.length,
|
|
120
|
+
hasContext: !!context
|
|
121
|
+
});
|
|
122
|
+
// Get current provider info and tools for rich data
|
|
123
|
+
const currentInfo = this.aiProviders.getCurrentProvider();
|
|
124
|
+
const provider = currentInfo ? this.aiProviders.getProvider(currentInfo.provider) : null;
|
|
125
|
+
if (!currentInfo || !currentInfo.provider || !provider) {
|
|
126
|
+
throw new Error('[EXECUTION] Provider is required');
|
|
127
|
+
}
|
|
128
|
+
const availableTools = this.tools.getTools();
|
|
129
|
+
// Emit execution start event
|
|
130
|
+
const rootId = conversationId;
|
|
131
|
+
const aiProviderInfo = {
|
|
132
|
+
providerName: currentInfo.provider,
|
|
133
|
+
model: config.defaultModel.model,
|
|
134
|
+
temperature: config.defaultModel.temperature,
|
|
135
|
+
maxTokens: config.defaultModel.maxTokens
|
|
136
|
+
};
|
|
137
|
+
const toolsInfo = availableTools.map((tool) => {
|
|
138
|
+
const paramSchema = tool.parameters;
|
|
139
|
+
const props = paramSchema?.properties;
|
|
140
|
+
if (!tool.description || tool.description.length === 0) {
|
|
141
|
+
throw new Error(`[EXECUTION] Tool "${tool.name}" is missing description`);
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
name: tool.name,
|
|
145
|
+
description: tool.description,
|
|
146
|
+
parameters: props && typeof props === 'object' ? Object.keys(props) : []
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
this.emitExecution(EXECUTION_EVENTS.START, {
|
|
150
|
+
parameters: {
|
|
151
|
+
input,
|
|
152
|
+
agentConfiguration: aiProviderInfo,
|
|
153
|
+
availableTools: toolsInfo,
|
|
154
|
+
toolCount: toolsInfo.length,
|
|
155
|
+
hasTools: toolsInfo.length > 0,
|
|
156
|
+
systemMessage: config.defaultModel.systemMessage,
|
|
157
|
+
provider: config.defaultModel.provider,
|
|
158
|
+
model: config.defaultModel.model,
|
|
159
|
+
temperature: config.defaultModel.temperature,
|
|
160
|
+
maxTokens: config.defaultModel.maxTokens
|
|
161
|
+
},
|
|
162
|
+
metadata: {
|
|
163
|
+
method: 'execute',
|
|
164
|
+
inputLength: input.length,
|
|
165
|
+
messageCount: messages.length,
|
|
166
|
+
aiProvider: aiProviderInfo.providerName,
|
|
167
|
+
model: aiProviderInfo.model,
|
|
168
|
+
toolsAvailable: toolsInfo.map((t) => t.name),
|
|
169
|
+
agentCapabilities: {
|
|
170
|
+
canUseTools: toolsInfo.length > 0,
|
|
171
|
+
supportedActions: toolsInfo.map((t) => t.name)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}, rootId, executionId);
|
|
175
|
+
try {
|
|
176
|
+
// Get conversation session for this conversation
|
|
177
|
+
const conversationSession = this.conversationHistory.getConversationSession(conversationId);
|
|
178
|
+
// Initialize conversation history with existing messages if this is first time
|
|
179
|
+
if (conversationSession.getMessageCount() === 0 && messages.length > 0) {
|
|
180
|
+
// Add all messages in the order they appear in the messages array
|
|
181
|
+
// This preserves the original order including multiple system messages
|
|
182
|
+
messages.forEach(msg => {
|
|
183
|
+
if (msg.role === 'user') {
|
|
184
|
+
conversationSession.addUserMessage(msg.content, msg.metadata);
|
|
185
|
+
}
|
|
186
|
+
else if (msg.role === 'assistant') {
|
|
187
|
+
conversationSession.addAssistantMessage(msg.content, msg.toolCalls, msg.metadata);
|
|
188
|
+
}
|
|
189
|
+
else if (msg.role === 'system') {
|
|
190
|
+
conversationSession.addSystemMessage(msg.content, msg.metadata);
|
|
191
|
+
}
|
|
192
|
+
else if (msg.role === 'tool') {
|
|
193
|
+
const toolName = msg.metadata?.['toolName'];
|
|
194
|
+
if (typeof toolName !== 'string' || toolName.length === 0) {
|
|
195
|
+
throw new Error('[EXECUTION] Tool message missing toolName metadata');
|
|
196
|
+
}
|
|
197
|
+
conversationSession.addToolMessageWithId(msg.content, msg.toolCallId, toolName, msg.metadata);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// Add system message from config if provided and not already present
|
|
202
|
+
// This allows for additional system messages during execution but prevents duplicates
|
|
203
|
+
if (config.systemMessage) {
|
|
204
|
+
const existingMessages = conversationSession.getMessages();
|
|
205
|
+
const hasConfigSystemMessage = existingMessages.some(msg => msg.role === 'system' && msg.content === config.systemMessage);
|
|
206
|
+
if (!hasConfigSystemMessage) {
|
|
207
|
+
conversationSession.addSystemMessage(config.systemMessage, { executionId });
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Only add the current input if it's not already the last message in the conversation
|
|
211
|
+
const existingMessages = conversationSession.getMessages();
|
|
212
|
+
const lastMessage = existingMessages[existingMessages.length - 1];
|
|
213
|
+
const shouldAddInput = !lastMessage ||
|
|
214
|
+
lastMessage.role !== 'user' ||
|
|
215
|
+
lastMessage.content !== input;
|
|
216
|
+
if (shouldAddInput) {
|
|
217
|
+
conversationSession.addUserMessage(input, { executionId });
|
|
218
|
+
const rootId = conversationId;
|
|
219
|
+
this.emitExecution(EXECUTION_EVENTS.USER_MESSAGE, {
|
|
220
|
+
parameters: {
|
|
221
|
+
input,
|
|
222
|
+
userPrompt: input,
|
|
223
|
+
userMessageContent: input,
|
|
224
|
+
messageLength: input.length,
|
|
225
|
+
wordCount: input.split(/\s+/).filter(word => word.length > 0).length,
|
|
226
|
+
characterCount: input.length
|
|
227
|
+
},
|
|
228
|
+
metadata: {
|
|
229
|
+
messageRole: 'user',
|
|
230
|
+
inputLength: input.length,
|
|
231
|
+
messageType: 'user_message',
|
|
232
|
+
hasQuestions: input.includes('?'),
|
|
233
|
+
containsUrgency: /urgent|asap|critical|emergency/i.test(input),
|
|
234
|
+
estimatedComplexity: input.length > 200 ? 'high' : input.length > 50 ? 'medium' : 'low'
|
|
235
|
+
}
|
|
236
|
+
}, rootId, executionId);
|
|
237
|
+
}
|
|
238
|
+
// Call beforeRun hook on all plugins
|
|
239
|
+
await this.callPluginHook('beforeRun', {
|
|
240
|
+
input,
|
|
241
|
+
...(context?.metadata ? { metadata: context.metadata } : {})
|
|
242
|
+
});
|
|
243
|
+
// Use already retrieved provider info from rich data collection above
|
|
244
|
+
if (!currentInfo) {
|
|
245
|
+
throw new Error('No AI provider configured');
|
|
246
|
+
}
|
|
247
|
+
if (!provider) {
|
|
248
|
+
throw new Error(`AI provider '${currentInfo.provider}' not found`);
|
|
249
|
+
}
|
|
250
|
+
// Provider implements IAIProvider, so chat() must exist.
|
|
251
|
+
if (typeof provider.chat !== 'function') {
|
|
252
|
+
throw new Error('Provider must have chat method to support execution');
|
|
253
|
+
}
|
|
254
|
+
// Process with conversation loop - now delegated to provider
|
|
255
|
+
let toolsExecuted = [];
|
|
256
|
+
let maxRounds = 10; // Increased limit for complex team delegation scenarios
|
|
257
|
+
let currentRound = 0;
|
|
258
|
+
while (currentRound < maxRounds) {
|
|
259
|
+
currentRound++;
|
|
260
|
+
// [ROUND-DEBUG] Round start logging
|
|
261
|
+
this.logger.info(`🔄 [ROUND-DEBUG] Starting Round ${currentRound} for agent ${fullContext.conversationId}`);
|
|
262
|
+
this.logger.debug(`🔄 [ROUND-${currentRound}] Starting execution round ${currentRound}`, {
|
|
263
|
+
executionId,
|
|
264
|
+
conversationId: fullContext.conversationId,
|
|
265
|
+
round: currentRound,
|
|
266
|
+
maxRounds: maxRounds
|
|
267
|
+
});
|
|
268
|
+
// Generate the thinking node id for this round at round start.
|
|
269
|
+
const rootId = conversationId;
|
|
270
|
+
// Path-only stable thinking id: conversation-level round (next assistant turn)
|
|
271
|
+
const historyMessages = conversationSession.getMessages();
|
|
272
|
+
if (!Array.isArray(historyMessages)) {
|
|
273
|
+
throw new Error('[EXECUTION] Conversation messages must be an array');
|
|
274
|
+
}
|
|
275
|
+
const assistantMessages = historyMessages.filter((message) => message.role === 'assistant');
|
|
276
|
+
const assistantMessageCount = assistantMessages.length;
|
|
277
|
+
const latestAssistantMessage = assistantMessages.length > 0
|
|
278
|
+
? assistantMessages[assistantMessages.length - 1]
|
|
279
|
+
: undefined;
|
|
280
|
+
const shouldChainFromPreviousToolResult = Array.isArray(latestAssistantMessage?.toolCalls) &&
|
|
281
|
+
latestAssistantMessage.toolCalls.length > 0;
|
|
282
|
+
const thinkingNodeId = `thinking_${rootId}_round${assistantMessageCount + 1}`;
|
|
283
|
+
const previousThinkingNodeId = shouldChainFromPreviousToolResult
|
|
284
|
+
? `thinking_${rootId}_round${assistantMessageCount}`
|
|
285
|
+
: undefined;
|
|
286
|
+
// Get messages from conversation history
|
|
287
|
+
const conversationMessages = historyMessages;
|
|
288
|
+
this.logger.debug('Current conversation messages', {
|
|
289
|
+
round: currentRound,
|
|
290
|
+
messageCount: conversationMessages.length,
|
|
291
|
+
fullHistory: conversationMessages.map((m, index) => ({
|
|
292
|
+
index,
|
|
293
|
+
role: m.role,
|
|
294
|
+
content: m.content?.substring(0, 100),
|
|
295
|
+
hasToolCalls: 'toolCalls' in m ? !!m.toolCalls?.length : false,
|
|
296
|
+
toolCallId: 'toolCallId' in m ? m.toolCallId : undefined,
|
|
297
|
+
toolCallsCount: 'toolCalls' in m ? m.toolCalls?.length : 0
|
|
298
|
+
}))
|
|
299
|
+
});
|
|
300
|
+
// Call beforeProviderCall hook
|
|
301
|
+
await this.callPluginHook('beforeProviderCall', {
|
|
302
|
+
messages: conversationMessages
|
|
303
|
+
});
|
|
304
|
+
this.logger.debug('Sending messages to AI provider', {
|
|
305
|
+
round: currentRound,
|
|
306
|
+
messageCount: conversationMessages.length,
|
|
307
|
+
lastFewMessages: conversationMessages.slice(-5).map(m => ({
|
|
308
|
+
role: m.role,
|
|
309
|
+
content: m.content?.substring(0, 50),
|
|
310
|
+
hasToolCalls: 'toolCalls' in m ? !!m.toolCalls?.length : false,
|
|
311
|
+
toolCallId: 'toolCallId' in m ? m.toolCallId : undefined
|
|
312
|
+
}))
|
|
313
|
+
});
|
|
314
|
+
// Validate required model configuration - use new defaultModel format
|
|
315
|
+
if (!config.defaultModel?.model) {
|
|
316
|
+
throw new Error('Model is required in defaultModel configuration. Please specify a model.');
|
|
317
|
+
}
|
|
318
|
+
if (typeof config.defaultModel.model !== 'string' || config.defaultModel.model.trim() === '') {
|
|
319
|
+
throw new Error('Model must be a non-empty string in defaultModel configuration.');
|
|
320
|
+
}
|
|
321
|
+
// Delegate entire execution to provider
|
|
322
|
+
const availableTools = this.tools.getTools();
|
|
323
|
+
const chatOptions = {
|
|
324
|
+
model: config.defaultModel.model,
|
|
325
|
+
...(config.defaultModel.maxTokens !== undefined && { maxTokens: config.defaultModel.maxTokens }),
|
|
326
|
+
...(config.defaultModel.temperature !== undefined && { temperature: config.defaultModel.temperature }),
|
|
327
|
+
...(availableTools.length > 0 && { tools: availableTools })
|
|
328
|
+
};
|
|
329
|
+
// Emit assistant message start event for each thinking phase.
|
|
330
|
+
// Absolute path-only: the path tail must be the thinking node id for this round.
|
|
331
|
+
this.emitWithContext(EXECUTION_EVENTS.ASSISTANT_MESSAGE_START, {
|
|
332
|
+
parameters: {
|
|
333
|
+
round: currentRound,
|
|
334
|
+
messageCount: conversationMessages.length
|
|
335
|
+
},
|
|
336
|
+
metadata: {
|
|
337
|
+
round: currentRound,
|
|
338
|
+
thinkingNodeId
|
|
339
|
+
}
|
|
340
|
+
}, () => this.buildThinkingOwnerContext(rootId, executionId, thinkingNodeId, previousThinkingNodeId), ctx => {
|
|
341
|
+
if (!ctx.ownerType || !ctx.ownerId) {
|
|
342
|
+
throw new Error('[EXECUTION] Missing owner context for thinking event');
|
|
343
|
+
}
|
|
344
|
+
return bindWithOwnerPath(this.baseEventService, {
|
|
345
|
+
ownerType: ctx.ownerType,
|
|
346
|
+
ownerId: ctx.ownerId,
|
|
347
|
+
ownerPath: ctx.ownerPath
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
const response = await provider.chat(conversationMessages, chatOptions);
|
|
351
|
+
const assistantToolCallsFromResponse = response.role === 'assistant'
|
|
352
|
+
? response.toolCalls
|
|
353
|
+
: undefined;
|
|
354
|
+
if (typeof response.content !== 'string') {
|
|
355
|
+
throw new Error('[EXECUTION] Provider response content is required');
|
|
356
|
+
}
|
|
357
|
+
if (assistantToolCallsFromResponse && !Array.isArray(assistantToolCallsFromResponse)) {
|
|
358
|
+
throw new Error('[EXECUTION] assistant toolCalls must be an array');
|
|
359
|
+
}
|
|
360
|
+
this.logger.debug(`🤖 [ROUND-${currentRound}] Provider response completed`, {
|
|
361
|
+
executionId,
|
|
362
|
+
conversationId: fullContext.conversationId,
|
|
363
|
+
round: currentRound,
|
|
364
|
+
responseLength: response.content.length,
|
|
365
|
+
hasToolCalls: Array.isArray(assistantToolCallsFromResponse) && assistantToolCallsFromResponse.length > 0,
|
|
366
|
+
toolCallsCount: Array.isArray(assistantToolCallsFromResponse) ? assistantToolCallsFromResponse.length : 0
|
|
367
|
+
});
|
|
368
|
+
// Call afterProviderCall hook
|
|
369
|
+
await this.callPluginHook('afterProviderCall', {
|
|
370
|
+
messages: conversationMessages,
|
|
371
|
+
responseMessage: response
|
|
372
|
+
});
|
|
373
|
+
// Add assistant response to history
|
|
374
|
+
// Response from AI provider should always be assistant message
|
|
375
|
+
if (response.role !== 'assistant') {
|
|
376
|
+
throw new Error(`Unexpected response role: ${response.role}`);
|
|
377
|
+
}
|
|
378
|
+
const assistantResponse = response;
|
|
379
|
+
if (typeof assistantResponse.content !== 'string') {
|
|
380
|
+
throw new Error('[EXECUTION] assistant response content is required');
|
|
381
|
+
}
|
|
382
|
+
const assistantToolCalls = assistantResponse.toolCalls ?? [];
|
|
383
|
+
if (!Array.isArray(assistantToolCalls)) {
|
|
384
|
+
throw new Error('[EXECUTION] assistantResponse.toolCalls must be an array');
|
|
385
|
+
}
|
|
386
|
+
conversationSession.addAssistantMessage(assistantResponse.content, assistantToolCalls, {
|
|
387
|
+
round: currentRound,
|
|
388
|
+
...(assistantResponse.metadata?.['usage'] && { usage: assistantResponse.metadata['usage'] })
|
|
389
|
+
});
|
|
390
|
+
this.logger.debug(`[RULE-9-DEBUG] Round ${currentRound} response check: toolCalls=${assistantToolCalls.length}`, {
|
|
391
|
+
round: currentRound,
|
|
392
|
+
hasToolCalls: assistantToolCalls.length > 0,
|
|
393
|
+
toolCallsLength: assistantToolCalls.length,
|
|
394
|
+
responseContent: assistantResponse.content.substring(0, 100) + '...'
|
|
395
|
+
});
|
|
396
|
+
// [ROUND2-DEBUG] Extra diagnostics for Round 2 response
|
|
397
|
+
if (currentRound === 2) {
|
|
398
|
+
this.logger.info(`🔍 [ROUND2-DEBUG] Round 2 AI Response for agent ${fullContext.conversationId}:`);
|
|
399
|
+
this.logger.info(`🔍 [ROUND2-DEBUG] - Content: ${assistantResponse.content.substring(0, 200)}...`);
|
|
400
|
+
this.logger.info(`🔍 [ROUND2-DEBUG] - Tool Calls: ${assistantToolCalls.length}`);
|
|
401
|
+
if (assistantToolCalls.length > 0) {
|
|
402
|
+
this.logger.info(`🔍 [ROUND2-DEBUG] - Tool Call Details: ${JSON.stringify(assistantToolCalls.map(tc => ({ id: tc.id, name: tc.function?.name })))}`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if (assistantToolCalls.length === 0) {
|
|
406
|
+
// No tools to execute, we're done
|
|
407
|
+
this.logger.info(`🔄 [ROUND-DEBUG] Round ${currentRound} ENDING - no tool calls for agent ${fullContext.conversationId}`);
|
|
408
|
+
this.logger.debug(`[AGENT-FLOW-CONTROL] Round ${currentRound} completed - no tool calls, execution finished for agent ${fullContext.conversationId}`);
|
|
409
|
+
// [VERIFICATION] Validate ExecutionService flow-control logic
|
|
410
|
+
this.logger.info(`🔍 [EXECUTION-VERIFICATION] Agent ${fullContext.conversationId} - Round ${currentRound} - No tool calls detected`);
|
|
411
|
+
this.logger.info(`🔍 [EXECUTION-VERIFICATION] ExecutionContext exists: ${!!this.executionContext}`);
|
|
412
|
+
if (this.executionContext) {
|
|
413
|
+
this.logger.info(`🔍 [EXECUTION-VERIFICATION] Parent ID: ${this.executionContext.parentExecutionId}`);
|
|
414
|
+
this.logger.info(`🔍 [EXECUTION-VERIFICATION] Execution Level: ${this.executionContext.executionLevel}`);
|
|
415
|
+
}
|
|
416
|
+
// [EVENT-ORTHODOXY] Emit events consistently; do not conditionally suppress emission.
|
|
417
|
+
// The handler decides whether to process the event based on context.
|
|
418
|
+
this.logger.info(`🔧 [EVENT-ORTHODOXY] Emitting assistant_message_complete for Round ${currentRound} completion (no tool calls)`);
|
|
419
|
+
if (typeof assistantResponse.content !== 'string' || assistantResponse.content.length === 0) {
|
|
420
|
+
throw new Error('[EXECUTION] assistant response content is required');
|
|
421
|
+
}
|
|
422
|
+
if (!(assistantResponse.timestamp instanceof Date)) {
|
|
423
|
+
throw new Error('[EXECUTION] assistant response timestamp is required');
|
|
424
|
+
}
|
|
425
|
+
const responseContent = assistantResponse.content;
|
|
426
|
+
const responseStartTime = assistantResponse.timestamp;
|
|
427
|
+
const responseDuration = new Date().getTime() - responseStartTime.getTime();
|
|
428
|
+
this.emitWithContext(EXECUTION_EVENTS.ASSISTANT_MESSAGE_COMPLETE, {
|
|
429
|
+
parameters: {
|
|
430
|
+
assistantMessage: responseContent,
|
|
431
|
+
responseLength: responseContent.length,
|
|
432
|
+
wordCount: responseContent.split(/\s+/).filter(word => word.length > 0).length,
|
|
433
|
+
responseTime: responseDuration,
|
|
434
|
+
contentPreview: responseContent.length > 200
|
|
435
|
+
? responseContent.substring(0, 200) + '...'
|
|
436
|
+
: responseContent
|
|
437
|
+
},
|
|
438
|
+
result: {
|
|
439
|
+
success: true,
|
|
440
|
+
data: responseContent.substring(0, 100) + '...',
|
|
441
|
+
fullResponse: responseContent,
|
|
442
|
+
responseMetrics: {
|
|
443
|
+
length: responseContent.length,
|
|
444
|
+
estimatedReadTime: Math.ceil(responseContent.split(/\s+/).length / 200),
|
|
445
|
+
hasCodeBlocks: /```/.test(responseContent),
|
|
446
|
+
hasLinks: /https?:\/\//.test(responseContent),
|
|
447
|
+
complexity: responseContent.length > 1000 ? 'high' : responseContent.length > 300 ? 'medium' : 'low'
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
metadata: {
|
|
451
|
+
executionId,
|
|
452
|
+
round: currentRound,
|
|
453
|
+
completed: true,
|
|
454
|
+
reason: 'no_tool_calls',
|
|
455
|
+
responseCharacteristics: {
|
|
456
|
+
hasQuestions: responseContent.includes('?'),
|
|
457
|
+
isError: /error|fail|wrong/i.test(responseContent),
|
|
458
|
+
isComplete: /complete|done|finish/i.test(responseContent),
|
|
459
|
+
containsNumbers: /\d/.test(responseContent)
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}, () => this.buildResponseOwnerContext(rootId, executionId, thinkingNodeId, previousThinkingNodeId), ctx => {
|
|
463
|
+
if (!ctx.ownerType || !ctx.ownerId) {
|
|
464
|
+
throw new Error('[EXECUTION] Missing owner context for response event');
|
|
465
|
+
}
|
|
466
|
+
return bindWithOwnerPath(this.baseEventService, {
|
|
467
|
+
ownerType: ctx.ownerType,
|
|
468
|
+
ownerId: ctx.ownerId,
|
|
469
|
+
ownerPath: ctx.ownerPath
|
|
470
|
+
});
|
|
471
|
+
});
|
|
472
|
+
this.logger.info(`🔍 [EXECUTION-VERIFICATION] Breaking execution loop - should prevent Round ${currentRound + 1}`);
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
// Tools are triggered in this round. Do not emit assistant_message_complete yet.
|
|
477
|
+
// Completion will be emitted when a subsequent assistant turn finishes without tool calls.
|
|
478
|
+
}
|
|
479
|
+
// [ROUND-DEBUG] Continue round: tool calls present
|
|
480
|
+
this.logger.info(`🔄 [ROUND-DEBUG] Round ${currentRound} CONTINUING - ${assistantToolCalls.length} tool calls for agent ${fullContext.conversationId}`);
|
|
481
|
+
this.logger.info(`🔄 [ROUND-DEBUG] Agent instance conversationId=${fullContext.conversationId}`);
|
|
482
|
+
this.logger.debug('Tool calls detected, executing tools', {
|
|
483
|
+
toolCallCount: assistantToolCalls.length,
|
|
484
|
+
round: currentRound,
|
|
485
|
+
toolCalls: assistantToolCalls.map((tc) => ({ id: tc.id, name: tc.function?.name }))
|
|
486
|
+
});
|
|
487
|
+
// Execute tools
|
|
488
|
+
// Ensure proper ID hierarchy for tool execution
|
|
489
|
+
const toolRootId = conversationId;
|
|
490
|
+
const rootForTools = toolRootId;
|
|
491
|
+
// Absolute path-only: tool calls must be children of the thinking node (fork point).
|
|
492
|
+
const toolOwnerPathBase = this.buildThinkingOwnerContext(rootForTools, executionId, thinkingNodeId, previousThinkingNodeId).ownerPath;
|
|
493
|
+
const expectedCountForBatch = assistantToolCalls.length;
|
|
494
|
+
const batchId = `${thinkingNodeId}`;
|
|
495
|
+
const toolRequestsBase = this.toolExecutionService.createExecutionRequestsWithContext(assistantToolCalls, {
|
|
496
|
+
ownerPathBase: toolOwnerPathBase,
|
|
497
|
+
metadataFactory: toolCall => ({
|
|
498
|
+
conversationId: toolRootId,
|
|
499
|
+
round: currentRound,
|
|
500
|
+
directParentId: thinkingNodeId,
|
|
501
|
+
batchId,
|
|
502
|
+
expectedCount: expectedCountForBatch,
|
|
503
|
+
toolCallId: toolCall.id
|
|
504
|
+
})
|
|
505
|
+
});
|
|
506
|
+
const toolRequests = toolRequestsBase.map(request => {
|
|
507
|
+
if (!request.ownerId) {
|
|
508
|
+
throw new Error('[EXECUTION] Tool request missing ownerId');
|
|
509
|
+
}
|
|
510
|
+
return {
|
|
511
|
+
...request,
|
|
512
|
+
eventService: this.ensureToolEventService(request.ownerId, request.ownerPath),
|
|
513
|
+
baseEventService: this.baseEventService
|
|
514
|
+
};
|
|
515
|
+
});
|
|
516
|
+
const toolContext = {
|
|
517
|
+
requests: toolRequests,
|
|
518
|
+
mode: 'parallel',
|
|
519
|
+
maxConcurrency: 5,
|
|
520
|
+
continueOnError: true
|
|
521
|
+
};
|
|
522
|
+
const toolSummary = await this.toolExecutionService.executeTools(toolContext);
|
|
523
|
+
toolsExecuted.push(...toolSummary.results.map(r => {
|
|
524
|
+
if (!r.toolName || r.toolName.length === 0) {
|
|
525
|
+
throw new Error('[EXECUTION] Tool result missing toolName');
|
|
526
|
+
}
|
|
527
|
+
return r.toolName;
|
|
528
|
+
}));
|
|
529
|
+
// Add tool results to history in the order they were called
|
|
530
|
+
// This ensures proper conversation flow and prevents any duplicate entries
|
|
531
|
+
for (const toolCall of assistantToolCalls) {
|
|
532
|
+
if (!toolCall.id) {
|
|
533
|
+
throw new Error(`Tool call missing ID: ${JSON.stringify(toolCall)}`);
|
|
534
|
+
}
|
|
535
|
+
const toolCallName = toolCall.function?.name;
|
|
536
|
+
if (!toolCallName || toolCallName.length === 0) {
|
|
537
|
+
throw new Error(`[EXECUTION] Tool call "${toolCall.id}" missing function name`);
|
|
538
|
+
}
|
|
539
|
+
// Find the corresponding result for this tool call
|
|
540
|
+
const result = toolSummary.results.find(r => r.executionId === toolCall.id);
|
|
541
|
+
const error = toolSummary.errors.find(e => isExecutionError(e) && e.executionId === toolCall.id);
|
|
542
|
+
let content;
|
|
543
|
+
let metadata = { round: currentRound };
|
|
544
|
+
if (result && result.success) {
|
|
545
|
+
if (typeof result.result === 'undefined') {
|
|
546
|
+
throw new Error('[EXECUTION] Tool result missing result payload');
|
|
547
|
+
}
|
|
548
|
+
content = typeof result.result === 'string'
|
|
549
|
+
? result.result
|
|
550
|
+
: JSON.stringify(result.result);
|
|
551
|
+
metadata['success'] = true;
|
|
552
|
+
if (result.toolName) {
|
|
553
|
+
metadata['toolName'] = result.toolName;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
else if (result && !result.success) {
|
|
557
|
+
// Tool execution failed (result is still present to preserve deterministic ordering)
|
|
558
|
+
if (!result.error || result.error.length === 0) {
|
|
559
|
+
throw new Error('[EXECUTION] Tool result missing error message');
|
|
560
|
+
}
|
|
561
|
+
content = `Error: ${result.error}`;
|
|
562
|
+
metadata['success'] = false;
|
|
563
|
+
metadata['error'] = result.error;
|
|
564
|
+
if (result.toolName) {
|
|
565
|
+
metadata['toolName'] = result.toolName;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
else if (error) {
|
|
569
|
+
// Tool execution failed
|
|
570
|
+
const execError = error;
|
|
571
|
+
const execMessage = (() => {
|
|
572
|
+
if (execError.error?.message)
|
|
573
|
+
return execError.error.message;
|
|
574
|
+
if (execError.message)
|
|
575
|
+
return execError.message;
|
|
576
|
+
return '';
|
|
577
|
+
})();
|
|
578
|
+
if (!execMessage || execMessage.length === 0) {
|
|
579
|
+
throw new Error('[EXECUTION] Tool execution error missing message');
|
|
580
|
+
}
|
|
581
|
+
content = `Error: ${execMessage}`;
|
|
582
|
+
metadata['success'] = false;
|
|
583
|
+
metadata['error'] = execMessage;
|
|
584
|
+
if (execError.toolName) {
|
|
585
|
+
metadata['toolName'] = execError.toolName;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
else {
|
|
589
|
+
// No result found for this tool call
|
|
590
|
+
throw new Error(`No execution result found for tool call ID: ${toolCall.id}`);
|
|
591
|
+
}
|
|
592
|
+
// Add tool result to conversation history
|
|
593
|
+
// This will throw an error if duplicate toolCallId is detected
|
|
594
|
+
this.logger.debug('Adding tool result to conversation', {
|
|
595
|
+
toolCallId: toolCall.id,
|
|
596
|
+
toolName: toolCallName,
|
|
597
|
+
content: content.substring(0, 100),
|
|
598
|
+
round: currentRound,
|
|
599
|
+
currentHistoryLength: conversationSession.getMessages().length
|
|
600
|
+
});
|
|
601
|
+
conversationSession.addToolMessageWithId(content, toolCall.id, toolCallName, metadata);
|
|
602
|
+
this.logger.debug('Tool result added to history', {
|
|
603
|
+
toolCallId: toolCall.id,
|
|
604
|
+
newHistoryLength: conversationSession.getMessages().length,
|
|
605
|
+
round: currentRound
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
// Emit tool results ready (join trigger) and then delivery to LLM
|
|
609
|
+
const toolResultsRootId = rootId;
|
|
610
|
+
const toolCallIds = assistantToolCalls.map(toolCall => {
|
|
611
|
+
if (!toolCall.id || toolCall.id.length === 0) {
|
|
612
|
+
throw new Error('[EXECUTION] Tool call missing id for tool results ready payload');
|
|
613
|
+
}
|
|
614
|
+
return toolCall.id;
|
|
615
|
+
});
|
|
616
|
+
if (toolCallIds.length === 0) {
|
|
617
|
+
throw new Error('[EXECUTION] Tool results ready requires toolCallIds');
|
|
618
|
+
}
|
|
619
|
+
this.emitWithContext(EXECUTION_EVENTS.TOOL_RESULTS_READY, {
|
|
620
|
+
parameters: {
|
|
621
|
+
toolCallIds,
|
|
622
|
+
round: currentRound
|
|
623
|
+
},
|
|
624
|
+
metadata: {
|
|
625
|
+
round: currentRound
|
|
626
|
+
}
|
|
627
|
+
}, () => this.buildThinkingOwnerContext(rootId, executionId, thinkingNodeId, previousThinkingNodeId), ctx => {
|
|
628
|
+
if (!ctx.ownerType || !ctx.ownerId) {
|
|
629
|
+
throw new Error('[EXECUTION] Missing owner context for tool results ready');
|
|
630
|
+
}
|
|
631
|
+
return bindWithOwnerPath(this.baseEventService, {
|
|
632
|
+
ownerType: ctx.ownerType,
|
|
633
|
+
ownerId: ctx.ownerId,
|
|
634
|
+
ownerPath: ctx.ownerPath
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
this.emitWithContext(EXECUTION_EVENTS.TOOL_RESULTS_TO_LLM, {
|
|
638
|
+
parameters: {
|
|
639
|
+
toolsExecuted: toolsExecuted.length,
|
|
640
|
+
round: currentRound
|
|
641
|
+
},
|
|
642
|
+
metadata: {
|
|
643
|
+
toolsExecuted: toolSummary.results.map(r => {
|
|
644
|
+
if (!r.toolName || r.toolName.length === 0) {
|
|
645
|
+
throw new Error('[EXECUTION] Tool result missing toolName');
|
|
646
|
+
}
|
|
647
|
+
return r.toolName;
|
|
648
|
+
}),
|
|
649
|
+
round: currentRound
|
|
650
|
+
}
|
|
651
|
+
}, () => this.buildThinkingOwnerContext(toolResultsRootId, executionId, thinkingNodeId, previousThinkingNodeId), ctx => {
|
|
652
|
+
if (!ctx.ownerType || !ctx.ownerId) {
|
|
653
|
+
throw new Error('[EXECUTION] Missing owner context for tool results to llm');
|
|
654
|
+
}
|
|
655
|
+
return bindWithOwnerPath(this.baseEventService, {
|
|
656
|
+
ownerType: ctx.ownerType,
|
|
657
|
+
ownerId: ctx.ownerId,
|
|
658
|
+
ownerPath: ctx.ownerPath
|
|
659
|
+
});
|
|
660
|
+
});
|
|
661
|
+
// Continue to next round - let the AI decide if more tools are needed
|
|
662
|
+
// The AI will see the tool results and can either:
|
|
663
|
+
// 1. Call more tools if needed
|
|
664
|
+
// 2. Provide a final response without tool calls
|
|
665
|
+
this.logger.info(`🔄 [ROUND-DEBUG] Round ${currentRound} COMPLETED - continuing to Round ${currentRound + 1} for agent ${fullContext.conversationId}`);
|
|
666
|
+
}
|
|
667
|
+
// Check if we hit the round limit
|
|
668
|
+
if (currentRound >= maxRounds) {
|
|
669
|
+
this.logger.warn('Maximum execution rounds reached', {
|
|
670
|
+
maxRounds,
|
|
671
|
+
conversationId
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
// Get final messages from history
|
|
675
|
+
const finalMessages = conversationSession.getMessages();
|
|
676
|
+
const lastAssistantMessage = finalMessages
|
|
677
|
+
.filter(msg => msg.role === 'assistant')
|
|
678
|
+
.pop();
|
|
679
|
+
if (!lastAssistantMessage || typeof lastAssistantMessage.content !== 'string' || lastAssistantMessage.content.length === 0) {
|
|
680
|
+
throw new Error('[EXECUTION] Final assistant message is required');
|
|
681
|
+
}
|
|
682
|
+
const duration = Date.now() - startTime.getTime();
|
|
683
|
+
const result = {
|
|
684
|
+
response: lastAssistantMessage.content,
|
|
685
|
+
messages: finalMessages.map(msg => {
|
|
686
|
+
if (typeof msg.content !== 'string') {
|
|
687
|
+
throw new Error('[EXECUTION] Message content is required');
|
|
688
|
+
}
|
|
689
|
+
return {
|
|
690
|
+
role: msg.role,
|
|
691
|
+
content: msg.content,
|
|
692
|
+
timestamp: msg.timestamp,
|
|
693
|
+
metadata: msg.metadata,
|
|
694
|
+
...(msg.role === 'assistant' && 'toolCalls' in msg ? { toolCalls: msg.toolCalls } : {}),
|
|
695
|
+
...(msg.role === 'tool' && 'toolCallId' in msg ? { toolCallId: msg.toolCallId } : {})
|
|
696
|
+
};
|
|
697
|
+
}),
|
|
698
|
+
executionId,
|
|
699
|
+
duration,
|
|
700
|
+
tokensUsed: finalMessages
|
|
701
|
+
.filter(msg => msg.metadata?.['usage'])
|
|
702
|
+
.reduce((sum, msg) => {
|
|
703
|
+
const usage = msg.metadata?.['usage'];
|
|
704
|
+
if (usage && typeof usage === 'object' && 'totalTokens' in usage) {
|
|
705
|
+
const totalTokens = Number(usage.totalTokens);
|
|
706
|
+
if (Number.isNaN(totalTokens)) {
|
|
707
|
+
throw new Error('[EXECUTION] totalTokens must be a number');
|
|
708
|
+
}
|
|
709
|
+
return sum + totalTokens;
|
|
710
|
+
}
|
|
711
|
+
return sum;
|
|
712
|
+
}, 0),
|
|
713
|
+
toolsExecuted,
|
|
714
|
+
success: true
|
|
715
|
+
};
|
|
716
|
+
// Call afterRun hook on all plugins
|
|
717
|
+
await this.callPluginHook('afterRun', { input, response: result.response, metadata: context?.metadata });
|
|
718
|
+
this.logger.debug('Execution pipeline completed successfully', {
|
|
719
|
+
executionId,
|
|
720
|
+
conversationId,
|
|
721
|
+
duration,
|
|
722
|
+
tokensUsed: result.tokensUsed,
|
|
723
|
+
toolsExecuted: result.toolsExecuted.length,
|
|
724
|
+
rounds: currentRound
|
|
725
|
+
});
|
|
726
|
+
// Emit assistant message complete event
|
|
727
|
+
// execution.assistant_message_complete emission is handled in the main execution loop.
|
|
728
|
+
// Emit execution complete event
|
|
729
|
+
const rootIdComplete = conversationId;
|
|
730
|
+
this.emitExecution(EXECUTION_EVENTS.COMPLETE, {
|
|
731
|
+
result: {
|
|
732
|
+
success: true,
|
|
733
|
+
data: result.response.substring(0, 100) + '...'
|
|
734
|
+
},
|
|
735
|
+
metadata: {
|
|
736
|
+
method: 'execute',
|
|
737
|
+
success: true,
|
|
738
|
+
duration,
|
|
739
|
+
tokensUsed: result.tokensUsed,
|
|
740
|
+
toolsExecuted: result.toolsExecuted
|
|
741
|
+
}
|
|
742
|
+
}, rootIdComplete, executionId);
|
|
743
|
+
return result;
|
|
744
|
+
}
|
|
745
|
+
catch (error) {
|
|
746
|
+
const duration = Date.now() - startTime.getTime();
|
|
747
|
+
// Call onError hook on all plugins
|
|
748
|
+
await this.callPluginHook('onError', {
|
|
749
|
+
error: error,
|
|
750
|
+
executionContext: this.convertExecutionContextToPluginFormat(fullContext)
|
|
751
|
+
});
|
|
752
|
+
this.logger.error('Execution pipeline failed', {
|
|
753
|
+
executionId,
|
|
754
|
+
conversationId,
|
|
755
|
+
duration,
|
|
756
|
+
error: error instanceof Error ? error.message : String(error)
|
|
757
|
+
});
|
|
758
|
+
// Emit execution error event
|
|
759
|
+
this.emitExecution(EXECUTION_EVENTS.ERROR, {
|
|
760
|
+
error: error instanceof Error ? error.message : String(error),
|
|
761
|
+
metadata: {
|
|
762
|
+
method: 'execute',
|
|
763
|
+
success: false,
|
|
764
|
+
duration,
|
|
765
|
+
// Identity/hierarchy fields are derived from EventContext.ownerPath.
|
|
766
|
+
}
|
|
767
|
+
}, conversationId, executionId);
|
|
768
|
+
throw error;
|
|
769
|
+
}
|
|
770
|
+
finally {
|
|
771
|
+
this.resetOwnerPathBases();
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Execute with streaming response
|
|
776
|
+
*/
|
|
777
|
+
async *executeStream(input, messages, config, context) {
|
|
778
|
+
this.logger.debug('ExecutionService.executeStream called');
|
|
779
|
+
const executionId = this.generateExecutionId();
|
|
780
|
+
const startTime = Date.now();
|
|
781
|
+
if (!context?.conversationId || context.conversationId.length === 0) {
|
|
782
|
+
throw new Error('[EXECUTION] conversationId is required for streaming');
|
|
783
|
+
}
|
|
784
|
+
const streamingConversationId = this.requireConversationId(context, 'streaming');
|
|
785
|
+
this.prepareOwnerPathBases(streamingConversationId);
|
|
786
|
+
try {
|
|
787
|
+
// Create conversation session for this execution
|
|
788
|
+
const conversationSession = this.conversationHistory.getConversationSession(context.conversationId);
|
|
789
|
+
// Add user input to conversation
|
|
790
|
+
if (input) {
|
|
791
|
+
conversationSession.addUserMessage(input, { executionId });
|
|
792
|
+
}
|
|
793
|
+
// Call beforeRun hook on all plugins
|
|
794
|
+
await this.callPluginHook('beforeRun', {
|
|
795
|
+
input,
|
|
796
|
+
...(context?.metadata ? { metadata: context.metadata } : {})
|
|
797
|
+
});
|
|
798
|
+
// Get current provider info
|
|
799
|
+
const currentInfo = this.aiProviders.getCurrentProvider();
|
|
800
|
+
if (!currentInfo) {
|
|
801
|
+
throw new Error('No AI provider configured');
|
|
802
|
+
}
|
|
803
|
+
// Get actual provider instance
|
|
804
|
+
const provider = this.aiProviders.getProvider(currentInfo.provider);
|
|
805
|
+
if (!provider) {
|
|
806
|
+
throw new Error(`AI provider '${currentInfo.provider}' not found`);
|
|
807
|
+
}
|
|
808
|
+
// Ensure provider has chatStream method (streaming is optional on IAIProvider)
|
|
809
|
+
if (typeof provider.chatStream !== 'function') {
|
|
810
|
+
throw new Error('Provider must have chatStream method to support streaming execution');
|
|
811
|
+
}
|
|
812
|
+
this.logger.debug('ExecutionService calling provider.chatStream');
|
|
813
|
+
// Get conversation messages for provider
|
|
814
|
+
const conversationMessages = conversationSession.getMessages();
|
|
815
|
+
// Create chat options
|
|
816
|
+
const configToolsLength = Array.isArray(config.tools) ? config.tools.length : undefined;
|
|
817
|
+
this.logger.debug('🔍 [EXECUTION-SERVICE] config.tools:', { length: configToolsLength });
|
|
818
|
+
const toolSchemas = this.tools.getTools();
|
|
819
|
+
const toolSchemasLength = Array.isArray(toolSchemas) ? toolSchemas.length : undefined;
|
|
820
|
+
this.logger.debug('🔍 [EXECUTION-SERVICE] this.tools.getTools():', { length: toolSchemasLength });
|
|
821
|
+
this.logger.debug('🔍 [EXECUTION-SERVICE] config.tools exists:', { exists: !!config.tools });
|
|
822
|
+
this.logger.debug('🔍 [EXECUTION-SERVICE] config.tools.length > 0:', { hasTools: config.tools && config.tools.length > 0 });
|
|
823
|
+
const chatOptions = {
|
|
824
|
+
model: config.defaultModel.model,
|
|
825
|
+
...(config.tools && config.tools.length > 0 && { tools: this.tools.getTools() })
|
|
826
|
+
};
|
|
827
|
+
this.logger.debug('🔍 [EXECUTION-SERVICE] Final chatOptions has tools:', { hasTools: !!chatOptions.tools });
|
|
828
|
+
const chatOptionsToolsLength = Array.isArray(chatOptions.tools) ? chatOptions.tools.length : undefined;
|
|
829
|
+
this.logger.debug('🔍 [EXECUTION-SERVICE] Final chatOptions.tools length:', { length: chatOptionsToolsLength });
|
|
830
|
+
const chatStream = provider.chatStream;
|
|
831
|
+
if (!chatStream) {
|
|
832
|
+
throw new Error('Provider does not support streaming');
|
|
833
|
+
}
|
|
834
|
+
const stream = chatStream.call(provider, conversationMessages, chatOptions);
|
|
835
|
+
let fullResponse = '';
|
|
836
|
+
let toolCalls = [];
|
|
837
|
+
let currentToolCallIndex = -1; // Index of the currently active tool call during streaming
|
|
838
|
+
// Collect streaming chunks and tool calls
|
|
839
|
+
for await (const chunk of stream) {
|
|
840
|
+
if (chunk.content) {
|
|
841
|
+
fullResponse += chunk.content;
|
|
842
|
+
yield { chunk: chunk.content, isComplete: false };
|
|
843
|
+
}
|
|
844
|
+
// Collect tool calls from streaming chunks (type assertion for AssistantMessage)
|
|
845
|
+
if (chunk.role === 'assistant') {
|
|
846
|
+
const assistantChunk = chunk;
|
|
847
|
+
if (Array.isArray(assistantChunk.toolCalls) && assistantChunk.toolCalls.length > 0) {
|
|
848
|
+
// Manage tool call state while streaming
|
|
849
|
+
for (const chunkToolCall of assistantChunk.toolCalls) {
|
|
850
|
+
if (chunkToolCall.id && chunkToolCall.id !== '') {
|
|
851
|
+
// ✅ Tool call id present: start a new tool call
|
|
852
|
+
if (!chunkToolCall.type || chunkToolCall.type.length === 0) {
|
|
853
|
+
throw new Error(`[EXECUTION] Tool call "${chunkToolCall.id}" missing type in stream`);
|
|
854
|
+
}
|
|
855
|
+
if (!chunkToolCall.function?.name || chunkToolCall.function.name.length === 0) {
|
|
856
|
+
throw new Error(`[EXECUTION] Tool call "${chunkToolCall.id}" missing function name in stream`);
|
|
857
|
+
}
|
|
858
|
+
if (typeof chunkToolCall.function.arguments !== 'string') {
|
|
859
|
+
throw new Error(`[EXECUTION] Tool call "${chunkToolCall.id}" missing arguments in stream`);
|
|
860
|
+
}
|
|
861
|
+
currentToolCallIndex = toolCalls.length;
|
|
862
|
+
toolCalls.push({
|
|
863
|
+
id: chunkToolCall.id,
|
|
864
|
+
type: chunkToolCall.type,
|
|
865
|
+
function: {
|
|
866
|
+
name: chunkToolCall.function.name,
|
|
867
|
+
arguments: chunkToolCall.function.arguments
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
this.logger.debug(`🆕 [TOOL-STREAM] New tool call started: ${chunkToolCall.id} (${chunkToolCall.function?.name})`);
|
|
871
|
+
}
|
|
872
|
+
else if (currentToolCallIndex >= 0) {
|
|
873
|
+
// ✅ Tool call id missing: append fragments to the current tool call
|
|
874
|
+
const hasNameFragment = typeof chunkToolCall.function?.name === 'string' && chunkToolCall.function.name.length > 0;
|
|
875
|
+
const hasArgumentsFragment = typeof chunkToolCall.function?.arguments === 'string' && chunkToolCall.function.arguments.length > 0;
|
|
876
|
+
if (!hasNameFragment && !hasArgumentsFragment) {
|
|
877
|
+
throw new Error(`[EXECUTION] Tool call fragment missing name/arguments for ${toolCalls[currentToolCallIndex].id}`);
|
|
878
|
+
}
|
|
879
|
+
if (hasNameFragment) {
|
|
880
|
+
toolCalls[currentToolCallIndex].function.name += chunkToolCall.function.name;
|
|
881
|
+
}
|
|
882
|
+
if (hasArgumentsFragment) {
|
|
883
|
+
toolCalls[currentToolCallIndex].function.arguments += chunkToolCall.function.arguments;
|
|
884
|
+
}
|
|
885
|
+
const fragmentPreview = hasArgumentsFragment
|
|
886
|
+
? chunkToolCall.function.arguments
|
|
887
|
+
: chunkToolCall.function.name;
|
|
888
|
+
this.logger.debug(`📝 [TOOL-STREAM] Adding fragment to tool ${toolCalls[currentToolCallIndex].id}: "${fragmentPreview}"`);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
this.logger.debug('🔥 [EXECUTION-SERVICE-STREAM] Stream completed, toolCalls detected:', { count: toolCalls.length });
|
|
895
|
+
if (typeof fullResponse !== 'string') {
|
|
896
|
+
throw new Error('[EXECUTION] Streaming response content is required');
|
|
897
|
+
}
|
|
898
|
+
conversationSession.addAssistantMessage(fullResponse, toolCalls, { executionId });
|
|
899
|
+
// Execute tools if detected
|
|
900
|
+
if (toolCalls.length > 0) {
|
|
901
|
+
this.logger.debug('🔥 [EXECUTION-SERVICE-STREAM] Executing tools:', { tools: toolCalls.map(tc => tc.function.name) });
|
|
902
|
+
// Execute tools with hierarchical context
|
|
903
|
+
const streamingRootId = streamingConversationId;
|
|
904
|
+
// Generate thinking node ID for streaming mode (direct provision)
|
|
905
|
+
const streamingThinkingNodeId = `thinking_${streamingRootId}_${Date.now()}_${executionId}`;
|
|
906
|
+
const streamingOwnerPathBase = [...this.buildExecutionOwnerContext(streamingRootId, executionId).ownerPath, { type: 'thinking', id: streamingThinkingNodeId }];
|
|
907
|
+
const toolRequests = this.toolExecutionService.createExecutionRequestsWithContext(toolCalls, {
|
|
908
|
+
ownerPathBase: streamingOwnerPathBase
|
|
909
|
+
});
|
|
910
|
+
const toolContext = {
|
|
911
|
+
requests: toolRequests,
|
|
912
|
+
mode: 'parallel',
|
|
913
|
+
maxConcurrency: 5,
|
|
914
|
+
continueOnError: true
|
|
915
|
+
};
|
|
916
|
+
const toolSummary = await this.toolExecutionService.executeTools(toolContext);
|
|
917
|
+
// Add tool results to conversation in the order they were called
|
|
918
|
+
for (const toolCall of toolCalls) {
|
|
919
|
+
if (!toolCall.id) {
|
|
920
|
+
throw new Error('[EXECUTION] Tool call missing id in streaming mode');
|
|
921
|
+
}
|
|
922
|
+
if (!toolCall.function?.name || toolCall.function.name.length === 0) {
|
|
923
|
+
throw new Error(`[EXECUTION] Tool call "${toolCall.id}" missing function name in streaming mode`);
|
|
924
|
+
}
|
|
925
|
+
// Find the corresponding result for this tool call
|
|
926
|
+
const result = toolSummary.results.find(r => r.executionId === toolCall.id);
|
|
927
|
+
const error = toolSummary.errors.find(e => isExecutionError(e) && e.executionId === toolCall.id);
|
|
928
|
+
let content;
|
|
929
|
+
let metadata = { executionId };
|
|
930
|
+
if (result && result.success) {
|
|
931
|
+
if (typeof result.result === 'undefined') {
|
|
932
|
+
throw new Error('[EXECUTION] Tool result missing result payload in streaming mode');
|
|
933
|
+
}
|
|
934
|
+
content = typeof result.result === 'string'
|
|
935
|
+
? result.result
|
|
936
|
+
: JSON.stringify(result.result);
|
|
937
|
+
metadata['success'] = true;
|
|
938
|
+
if (result.toolName) {
|
|
939
|
+
metadata['toolName'] = result.toolName;
|
|
940
|
+
}
|
|
941
|
+
// Yield tool result as streaming chunk
|
|
942
|
+
yield { chunk: `\n[Tool: ${toolCall.function.name} executed successfully]`, isComplete: false };
|
|
943
|
+
}
|
|
944
|
+
else if (error) {
|
|
945
|
+
// Tool execution failed
|
|
946
|
+
const execError = error;
|
|
947
|
+
const execMessage = (() => {
|
|
948
|
+
if (execError.error?.message)
|
|
949
|
+
return execError.error.message;
|
|
950
|
+
if (execError.message)
|
|
951
|
+
return execError.message;
|
|
952
|
+
return '';
|
|
953
|
+
})();
|
|
954
|
+
if (!execMessage || execMessage.length === 0) {
|
|
955
|
+
throw new Error('[EXECUTION] Tool execution error missing message in streaming mode');
|
|
956
|
+
}
|
|
957
|
+
content = `Error: ${execMessage}`;
|
|
958
|
+
metadata['success'] = false;
|
|
959
|
+
metadata['error'] = execMessage;
|
|
960
|
+
if (execError.toolName) {
|
|
961
|
+
metadata['toolName'] = execError.toolName;
|
|
962
|
+
}
|
|
963
|
+
// Yield error as streaming chunk
|
|
964
|
+
yield { chunk: `\n[Tool: ${toolCall.function.name} failed: ${execMessage}]`, isComplete: false };
|
|
965
|
+
}
|
|
966
|
+
else {
|
|
967
|
+
throw new Error(`[EXECUTION] Missing tool result for tool call "${toolCall.id}" in streaming mode`);
|
|
968
|
+
}
|
|
969
|
+
// Add tool result to conversation history
|
|
970
|
+
conversationSession.addToolMessageWithId(content, toolCall.id, toolCall.function.name, metadata);
|
|
971
|
+
}
|
|
972
|
+
// After all tool responses are emitted and recorded, trigger aggregation join
|
|
973
|
+
const streamingRoot = streamingConversationId;
|
|
974
|
+
const streamingToolCallIds = toolCalls.map(toolCall => {
|
|
975
|
+
if (!toolCall.id || toolCall.id.length === 0) {
|
|
976
|
+
throw new Error('[EXECUTION] Tool call missing id for streaming tool results ready payload');
|
|
977
|
+
}
|
|
978
|
+
return toolCall.id;
|
|
979
|
+
});
|
|
980
|
+
if (streamingToolCallIds.length === 0) {
|
|
981
|
+
throw new Error('[EXECUTION] Tool results ready requires toolCallIds in streaming mode');
|
|
982
|
+
}
|
|
983
|
+
this.emitExecution(EXECUTION_EVENTS.TOOL_RESULTS_READY, {
|
|
984
|
+
parameters: {
|
|
985
|
+
toolCallIds: streamingToolCallIds,
|
|
986
|
+
round: 1
|
|
987
|
+
},
|
|
988
|
+
metadata: {
|
|
989
|
+
toolsExecuted: toolSummary.results.map(r => {
|
|
990
|
+
if (!r.toolName || r.toolName.length === 0) {
|
|
991
|
+
throw new Error('[EXECUTION] Tool result missing toolName');
|
|
992
|
+
}
|
|
993
|
+
return r.toolName;
|
|
994
|
+
}),
|
|
995
|
+
round: 1,
|
|
996
|
+
}
|
|
997
|
+
}, streamingRoot, executionId);
|
|
998
|
+
}
|
|
999
|
+
// Call afterRun hook
|
|
1000
|
+
await this.callPluginHook('afterRun', {
|
|
1001
|
+
input,
|
|
1002
|
+
response: fullResponse,
|
|
1003
|
+
...(context?.metadata ? { metadata: context.metadata } : {})
|
|
1004
|
+
});
|
|
1005
|
+
yield { chunk: '', isComplete: true };
|
|
1006
|
+
}
|
|
1007
|
+
catch (error) {
|
|
1008
|
+
this.logger.error('ExecutionService streaming execution failed', {
|
|
1009
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1010
|
+
executionTime: Date.now() - startTime
|
|
1011
|
+
});
|
|
1012
|
+
// Call error hook
|
|
1013
|
+
await this.callPluginHook('onError', {
|
|
1014
|
+
input,
|
|
1015
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
1016
|
+
...(context?.metadata ? { metadata: context.metadata } : {})
|
|
1017
|
+
});
|
|
1018
|
+
throw error;
|
|
1019
|
+
}
|
|
1020
|
+
finally {
|
|
1021
|
+
this.resetOwnerPathBases();
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Generate a unique execution ID
|
|
1026
|
+
*/
|
|
1027
|
+
generateExecutionId() {
|
|
1028
|
+
return `exec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Get execution statistics from plugins
|
|
1032
|
+
*/
|
|
1033
|
+
async getStats() {
|
|
1034
|
+
const stats = {
|
|
1035
|
+
pluginCount: this.plugins.length,
|
|
1036
|
+
pluginNames: this.plugins.map(p => p.name),
|
|
1037
|
+
historyStats: this.conversationHistory.getStats()
|
|
1038
|
+
};
|
|
1039
|
+
// Note: Plugin-specific stats are not included here to avoid type conflicts
|
|
1040
|
+
// Plugins can implement their own getStats() method returning their specific stat types
|
|
1041
|
+
return stats;
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Clear all plugins
|
|
1045
|
+
*/
|
|
1046
|
+
clearPlugins() {
|
|
1047
|
+
this.plugins = [];
|
|
1048
|
+
this.logger.debug('All plugins cleared');
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Call a hook method on all plugins that implement it
|
|
1052
|
+
* Handles different hook signatures properly
|
|
1053
|
+
*/
|
|
1054
|
+
async callPluginHook(hookName, context) {
|
|
1055
|
+
for (const plugin of this.plugins) {
|
|
1056
|
+
try {
|
|
1057
|
+
// Use type assertion to access the hook methods
|
|
1058
|
+
const pluginWithHooks = plugin;
|
|
1059
|
+
// Call the appropriate hook method with correct parameters
|
|
1060
|
+
switch (hookName) {
|
|
1061
|
+
case 'beforeRun':
|
|
1062
|
+
if (pluginWithHooks.beforeRun && context.input) {
|
|
1063
|
+
await pluginWithHooks.beforeRun(context.input, context.metadata);
|
|
1064
|
+
}
|
|
1065
|
+
break;
|
|
1066
|
+
case 'afterRun':
|
|
1067
|
+
if (pluginWithHooks.afterRun && context.input && context.response) {
|
|
1068
|
+
await pluginWithHooks.afterRun(context.input, context.response, context.metadata);
|
|
1069
|
+
}
|
|
1070
|
+
break;
|
|
1071
|
+
case 'beforeProviderCall':
|
|
1072
|
+
if (pluginWithHooks.beforeProviderCall && context.messages) {
|
|
1073
|
+
await pluginWithHooks.beforeProviderCall(context.messages);
|
|
1074
|
+
}
|
|
1075
|
+
break;
|
|
1076
|
+
case 'afterProviderCall':
|
|
1077
|
+
if (pluginWithHooks.afterProviderCall && context.messages && context.responseMessage) {
|
|
1078
|
+
await pluginWithHooks.afterProviderCall(context.messages, context.responseMessage);
|
|
1079
|
+
}
|
|
1080
|
+
break;
|
|
1081
|
+
case 'onError':
|
|
1082
|
+
if (pluginWithHooks.onError && context.error) {
|
|
1083
|
+
const errorContext = {
|
|
1084
|
+
action: `${EXECUTION_EVENT_PREFIX}.${EXECUTION_EVENTS.ERROR}`,
|
|
1085
|
+
metadata: {}
|
|
1086
|
+
};
|
|
1087
|
+
const executionIdValue = context.executionContext?.['executionId'];
|
|
1088
|
+
if (typeof executionIdValue === 'string' && executionIdValue.length > 0) {
|
|
1089
|
+
errorContext.executionId = executionIdValue;
|
|
1090
|
+
}
|
|
1091
|
+
const sessionIdValue = context.executionContext?.['sessionId'];
|
|
1092
|
+
if (typeof sessionIdValue === 'string' && sessionIdValue.length > 0) {
|
|
1093
|
+
errorContext.sessionId = sessionIdValue;
|
|
1094
|
+
}
|
|
1095
|
+
const userIdValue = context.executionContext?.['userId'];
|
|
1096
|
+
if (typeof userIdValue === 'string' && userIdValue.length > 0) {
|
|
1097
|
+
errorContext.userId = userIdValue;
|
|
1098
|
+
}
|
|
1099
|
+
await pluginWithHooks.onError(context.error, errorContext);
|
|
1100
|
+
}
|
|
1101
|
+
break;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
catch (error) {
|
|
1105
|
+
this.logger.warn('Plugin hook failed', {
|
|
1106
|
+
pluginName: plugin.name,
|
|
1107
|
+
hookName,
|
|
1108
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
ensureToolEventService(ownerId, ownerPath) {
|
|
1114
|
+
if (isDefaultEventService(this.baseEventService)) {
|
|
1115
|
+
return this.baseEventService;
|
|
1116
|
+
}
|
|
1117
|
+
if (!ownerId) {
|
|
1118
|
+
throw new Error('[EVENT-SERVICE] Missing ownerId for tool event context');
|
|
1119
|
+
}
|
|
1120
|
+
if (!ownerPath || ownerPath.length === 0) {
|
|
1121
|
+
throw new Error('[EVENT-SERVICE] Missing ownerPath for tool event context');
|
|
1122
|
+
}
|
|
1123
|
+
if (this.toolEventServices.has(ownerId)) {
|
|
1124
|
+
return this.toolEventServices.get(ownerId);
|
|
1125
|
+
}
|
|
1126
|
+
const scoped = bindWithOwnerPath(this.baseEventService, {
|
|
1127
|
+
ownerType: TOOL_EVENT_PREFIX,
|
|
1128
|
+
ownerId,
|
|
1129
|
+
ownerPath: ownerPath.map(segment => ({ ...segment })),
|
|
1130
|
+
});
|
|
1131
|
+
this.toolEventServices.set(ownerId, scoped);
|
|
1132
|
+
return scoped;
|
|
1133
|
+
}
|
|
1134
|
+
prepareOwnerPathBases(conversationId) {
|
|
1135
|
+
this.toolEventServices.clear();
|
|
1136
|
+
const ownerPath = [...this.ownerPathBase, { type: 'agent', id: conversationId }];
|
|
1137
|
+
this.agentOwnerPathBase = ownerPath;
|
|
1138
|
+
}
|
|
1139
|
+
resetOwnerPathBases() {
|
|
1140
|
+
this.toolEventServices.clear();
|
|
1141
|
+
this.agentOwnerPathBase = [];
|
|
1142
|
+
}
|
|
1143
|
+
buildBaseOwnerPath(executionContext) {
|
|
1144
|
+
if (!executionContext?.ownerPath?.length) {
|
|
1145
|
+
return [];
|
|
1146
|
+
}
|
|
1147
|
+
return executionContext.ownerPath.map(segment => ({ ...segment }));
|
|
1148
|
+
}
|
|
1149
|
+
buildExecutionOwnerContext(rootId, executionId) {
|
|
1150
|
+
if (!rootId || rootId.length === 0) {
|
|
1151
|
+
throw new Error('[EXECUTION] Missing rootId for execution owner context');
|
|
1152
|
+
}
|
|
1153
|
+
if (!executionId || executionId.length === 0) {
|
|
1154
|
+
throw new Error('[EXECUTION] Missing executionId for execution owner context');
|
|
1155
|
+
}
|
|
1156
|
+
const basePath = this.agentOwnerPathBase.length ? this.agentOwnerPathBase : this.ownerPathBase;
|
|
1157
|
+
const path = [...basePath];
|
|
1158
|
+
if (rootId && !path.some(segment => segment.type === 'agent' && segment.id === rootId)) {
|
|
1159
|
+
path.push({ type: 'agent', id: rootId });
|
|
1160
|
+
}
|
|
1161
|
+
path.push({ type: 'execution', id: executionId });
|
|
1162
|
+
return {
|
|
1163
|
+
ownerType: EXECUTION_EVENT_PREFIX,
|
|
1164
|
+
ownerId: executionId,
|
|
1165
|
+
ownerPath: path
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
buildThinkingOwnerContext(rootId, executionId, thinkingNodeId, previousThinkingNodeId) {
|
|
1169
|
+
if (!thinkingNodeId || thinkingNodeId.length === 0) {
|
|
1170
|
+
throw new Error('[EXECUTION] Missing thinkingNodeId for thinking owner context');
|
|
1171
|
+
}
|
|
1172
|
+
const base = this.buildExecutionOwnerContext(rootId, executionId).ownerPath;
|
|
1173
|
+
const path = [...base];
|
|
1174
|
+
if (previousThinkingNodeId) {
|
|
1175
|
+
path.push({ type: 'thinking', id: previousThinkingNodeId });
|
|
1176
|
+
path.push({ type: 'tool_result', id: `tool_result_${previousThinkingNodeId}` });
|
|
1177
|
+
}
|
|
1178
|
+
path.push({ type: 'thinking', id: thinkingNodeId });
|
|
1179
|
+
return {
|
|
1180
|
+
ownerType: EXECUTION_EVENT_PREFIX,
|
|
1181
|
+
ownerId: executionId,
|
|
1182
|
+
ownerPath: path
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
buildToolOwnerContext(rootId, executionId, toolCallId) {
|
|
1186
|
+
// Tool calls are always children of a specific thinking phase (fork point).
|
|
1187
|
+
// The caller must provide an ownerPathBase that already includes `{ type: 'thinking', id }`.
|
|
1188
|
+
if (!toolCallId || toolCallId.length === 0) {
|
|
1189
|
+
throw new Error('[EXECUTION] Missing toolCallId for tool owner context');
|
|
1190
|
+
}
|
|
1191
|
+
const base = this.buildExecutionOwnerContext(rootId, executionId).ownerPath;
|
|
1192
|
+
const path = [...base, { type: 'tool', id: toolCallId }];
|
|
1193
|
+
return {
|
|
1194
|
+
ownerType: TOOL_EVENT_PREFIX,
|
|
1195
|
+
ownerId: toolCallId,
|
|
1196
|
+
ownerPath: path
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
buildResponseOwnerContext(rootId, executionId, thinkingNodeId, previousThinkingNodeId) {
|
|
1200
|
+
const thinkingPath = this.buildThinkingOwnerContext(rootId, executionId, thinkingNodeId, previousThinkingNodeId).ownerPath;
|
|
1201
|
+
const responseNodeId = `response_${thinkingNodeId}`;
|
|
1202
|
+
const path = [...thinkingPath, { type: 'response', id: responseNodeId }];
|
|
1203
|
+
return {
|
|
1204
|
+
ownerType: EXECUTION_EVENT_PREFIX,
|
|
1205
|
+
ownerId: executionId,
|
|
1206
|
+
ownerPath: path
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
emitExecution(eventType, data, rootId, executionId) {
|
|
1210
|
+
this.emitWithContext(eventType, data, () => this.buildExecutionOwnerContext(rootId, executionId), context => {
|
|
1211
|
+
if (!context.ownerType || !context.ownerId) {
|
|
1212
|
+
throw new Error('[EXECUTION] Missing owner context for execution event');
|
|
1213
|
+
}
|
|
1214
|
+
return bindWithOwnerPath(this.baseEventService, {
|
|
1215
|
+
ownerType: context.ownerType,
|
|
1216
|
+
ownerId: context.ownerId,
|
|
1217
|
+
ownerPath: context.ownerPath
|
|
1218
|
+
});
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
emitTool(eventType, data, rootId, executionId, toolCallId) {
|
|
1222
|
+
this.emitWithContext(eventType, data, () => this.buildToolOwnerContext(rootId, executionId, toolCallId), context => this.ensureToolEventService(context.ownerId, context.ownerPath));
|
|
1223
|
+
}
|
|
1224
|
+
emitWithContext(eventType, data, buildContext, resolveService) {
|
|
1225
|
+
if (isDefaultEventService(this.baseEventService)) {
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1228
|
+
const context = buildContext();
|
|
1229
|
+
const service = resolveService(context);
|
|
1230
|
+
const payload = {
|
|
1231
|
+
timestamp: new Date(),
|
|
1232
|
+
...data,
|
|
1233
|
+
};
|
|
1234
|
+
service.emit(eventType, payload, context);
|
|
1235
|
+
}
|
|
1236
|
+
requireConversationId(context, label) {
|
|
1237
|
+
if (!context?.conversationId || context.conversationId.length === 0) {
|
|
1238
|
+
throw new Error(`[EXECUTION] conversationId is required for ${label}`);
|
|
1239
|
+
}
|
|
1240
|
+
return context.conversationId;
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1243
|
+
* Convert IExecutionContext to IPluginContext compatible format
|
|
1244
|
+
*/
|
|
1245
|
+
convertExecutionContextToPluginFormat(context) {
|
|
1246
|
+
const conversationId = this.requireConversationId(context, 'plugin-context');
|
|
1247
|
+
const payload = {
|
|
1248
|
+
conversationId: conversationId,
|
|
1249
|
+
executionId: context.executionId,
|
|
1250
|
+
startTime: context.startTime.toISOString(),
|
|
1251
|
+
messageCount: context.messages.length
|
|
1252
|
+
};
|
|
1253
|
+
if (context.sessionId) {
|
|
1254
|
+
payload.sessionId = context.sessionId;
|
|
1255
|
+
}
|
|
1256
|
+
if (context.userId) {
|
|
1257
|
+
payload.userId = context.userId;
|
|
1258
|
+
}
|
|
1259
|
+
return payload;
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
//# sourceMappingURL=execution-service.js.map
|