@robota-sdk/agent-core 3.0.0-beta.2 → 3.0.0-beta.21
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/README.md +64 -184
- package/dist/abstracts/abstract-agent.d.ts.map +1 -1
- package/dist/abstracts/abstract-agent.js.map +1 -1
- package/dist/abstracts/abstract-ai-provider.d.ts +8 -7
- package/dist/abstracts/abstract-ai-provider.d.ts.map +1 -1
- package/dist/abstracts/abstract-ai-provider.js +21 -15
- package/dist/abstracts/abstract-ai-provider.js.map +1 -1
- package/dist/abstracts/abstract-executor.d.ts.map +1 -1
- package/dist/abstracts/abstract-executor.js +20 -12
- package/dist/abstracts/abstract-executor.js.map +1 -1
- package/dist/abstracts/abstract-manager.d.ts.map +1 -1
- package/dist/abstracts/abstract-manager.js.map +1 -1
- package/dist/abstracts/abstract-module-events.d.ts +77 -0
- package/dist/abstracts/abstract-module-events.d.ts.map +1 -0
- package/dist/abstracts/abstract-module-events.js +8 -0
- package/dist/abstracts/abstract-module-events.js.map +1 -0
- package/dist/abstracts/abstract-module-types.d.ts +110 -0
- package/dist/abstracts/abstract-module-types.d.ts.map +1 -0
- package/dist/abstracts/abstract-module-types.js +20 -0
- package/dist/abstracts/abstract-module-types.js.map +1 -0
- package/dist/abstracts/abstract-module.d.ts +13 -312
- package/dist/abstracts/abstract-module.d.ts.map +1 -1
- package/dist/abstracts/abstract-module.js +137 -302
- package/dist/abstracts/abstract-module.js.map +1 -1
- package/dist/abstracts/abstract-module.test.d.ts +2 -0
- package/dist/abstracts/abstract-module.test.d.ts.map +1 -0
- package/dist/abstracts/abstract-module.test.js +150 -0
- package/dist/abstracts/abstract-module.test.js.map +1 -0
- package/dist/abstracts/abstract-plugin-types.d.ts +152 -0
- package/dist/abstracts/abstract-plugin-types.d.ts.map +1 -0
- package/dist/abstracts/abstract-plugin-types.js +29 -0
- package/dist/abstracts/abstract-plugin-types.js.map +1 -0
- package/dist/abstracts/abstract-plugin.d.ts +15 -304
- package/dist/abstracts/abstract-plugin.d.ts.map +1 -1
- package/dist/abstracts/abstract-plugin.js +28 -144
- package/dist/abstracts/abstract-plugin.js.map +1 -1
- package/dist/abstracts/abstract-tool.d.ts +1 -1
- package/dist/abstracts/abstract-tool.d.ts.map +1 -1
- package/dist/abstracts/abstract-tool.js +2 -2
- package/dist/abstracts/abstract-tool.js.map +1 -1
- package/dist/abstracts/abstract-workflow-converter.d.ts.map +1 -1
- package/dist/abstracts/abstract-workflow-converter.js +29 -20
- package/dist/abstracts/abstract-workflow-converter.js.map +1 -1
- package/dist/abstracts/abstract-workflow-converter.test.d.ts +2 -0
- package/dist/abstracts/abstract-workflow-converter.test.d.ts.map +1 -0
- package/dist/abstracts/abstract-workflow-converter.test.js +144 -0
- package/dist/abstracts/abstract-workflow-converter.test.js.map +1 -0
- package/dist/abstracts/abstract-workflow-validator-helpers.d.ts +37 -0
- package/dist/abstracts/abstract-workflow-validator-helpers.d.ts.map +1 -0
- package/dist/abstracts/abstract-workflow-validator-helpers.js +147 -0
- package/dist/abstracts/abstract-workflow-validator-helpers.js.map +1 -0
- package/dist/abstracts/abstract-workflow-validator-helpers.test.d.ts +2 -0
- package/dist/abstracts/abstract-workflow-validator-helpers.test.d.ts.map +1 -0
- package/dist/abstracts/abstract-workflow-validator-helpers.test.js +157 -0
- package/dist/abstracts/abstract-workflow-validator-helpers.test.js.map +1 -0
- package/dist/abstracts/abstract-workflow-validator.d.ts +18 -130
- package/dist/abstracts/abstract-workflow-validator.d.ts.map +1 -1
- package/dist/abstracts/abstract-workflow-validator.js +58 -326
- package/dist/abstracts/abstract-workflow-validator.js.map +1 -1
- package/dist/abstracts/abstract-workflow-validator.test.d.ts +2 -0
- package/dist/abstracts/abstract-workflow-validator.test.d.ts.map +1 -0
- package/dist/abstracts/abstract-workflow-validator.test.js +142 -0
- package/dist/abstracts/abstract-workflow-validator.test.js.map +1 -0
- package/dist/abstracts/index.d.ts +1 -0
- package/dist/abstracts/index.d.ts.map +1 -1
- package/dist/abstracts/index.js +3 -2
- package/dist/abstracts/index.js.map +1 -1
- package/dist/agents/constants.d.ts +1 -1
- package/dist/agents/constants.d.ts.map +1 -1
- package/dist/agents/constants.js +1 -1
- package/dist/agents/constants.js.map +1 -1
- package/dist/agents/index.js +1 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/robota.test.js +36 -36
- package/dist/agents/robota.test.js.map +1 -1
- package/dist/browser/index.d.ts +32 -2
- package/dist/browser/index.js +6 -4
- package/dist/context/index.d.ts +4 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +2 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/models.d.ts +27 -0
- package/dist/context/models.d.ts.map +1 -0
- package/dist/context/models.js +76 -0
- package/dist/context/models.js.map +1 -0
- package/dist/context/models.test.d.ts +2 -0
- package/dist/context/models.test.d.ts.map +1 -0
- package/dist/context/models.test.js +51 -0
- package/dist/context/models.test.js.map +1 -0
- package/dist/context/types.d.ts +25 -0
- package/dist/context/types.d.ts.map +1 -0
- package/dist/context/types.js +8 -0
- package/dist/context/types.js.map +1 -0
- package/dist/core/robota-config-manager.d.ts +78 -0
- package/dist/core/robota-config-manager.d.ts.map +1 -0
- package/dist/core/robota-config-manager.js +216 -0
- package/dist/core/robota-config-manager.js.map +1 -0
- package/dist/core/robota-execution.d.ts +23 -0
- package/dist/core/robota-execution.d.ts.map +1 -0
- package/dist/core/robota-execution.js +81 -0
- package/dist/core/robota-execution.js.map +1 -0
- package/dist/core/robota-initializer.d.ts +37 -0
- package/dist/core/robota-initializer.d.ts.map +1 -0
- package/dist/core/robota-initializer.js +77 -0
- package/dist/core/robota-initializer.js.map +1 -0
- package/dist/core/robota-lifecycle.d.ts +53 -0
- package/dist/core/robota-lifecycle.d.ts.map +1 -0
- package/dist/core/robota-lifecycle.js +73 -0
- package/dist/core/robota-lifecycle.js.map +1 -0
- package/dist/core/robota-module-manager.d.ts +78 -0
- package/dist/core/robota-module-manager.d.ts.map +1 -0
- package/dist/core/robota-module-manager.js +114 -0
- package/dist/core/robota-module-manager.js.map +1 -0
- package/dist/core/robota-plugin-manager.d.ts +40 -0
- package/dist/core/robota-plugin-manager.d.ts.map +1 -0
- package/dist/core/robota-plugin-manager.js +71 -0
- package/dist/core/robota-plugin-manager.js.map +1 -0
- package/dist/core/robota.d.ts +56 -606
- package/dist/core/robota.d.ts.map +1 -1
- package/dist/core/robota.js +210 -1152
- package/dist/core/robota.js.map +1 -1
- package/dist/core/robota.test.d.ts +2 -0
- package/dist/core/robota.test.d.ts.map +1 -0
- package/dist/core/robota.test.js +353 -0
- package/dist/core/robota.test.js.map +1 -0
- package/dist/event-service/event-service.d.ts +61 -0
- package/dist/event-service/event-service.d.ts.map +1 -0
- package/dist/event-service/event-service.js +120 -0
- package/dist/event-service/event-service.js.map +1 -0
- package/dist/event-service/index.d.ts +6 -0
- package/dist/event-service/index.d.ts.map +1 -0
- package/dist/event-service/index.js +4 -0
- package/dist/event-service/index.js.map +1 -0
- package/dist/event-service/interfaces.d.ts +98 -0
- package/dist/event-service/interfaces.d.ts.map +1 -0
- package/dist/event-service/interfaces.js +8 -0
- package/dist/event-service/interfaces.js.map +1 -0
- package/dist/event-service/task-events.d.ts +6 -0
- package/dist/event-service/task-events.d.ts.map +1 -0
- package/dist/event-service/task-events.js +6 -0
- package/dist/event-service/task-events.js.map +1 -0
- package/dist/event-service/user-events.d.ts +7 -0
- package/dist/event-service/user-events.d.ts.map +1 -0
- package/dist/event-service/user-events.js +6 -0
- package/dist/event-service/user-events.js.map +1 -0
- package/dist/executors/local-executor.d.ts +2 -2
- package/dist/executors/local-executor.d.ts.map +1 -1
- package/dist/executors/local-executor.js +7 -7
- package/dist/executors/local-executor.js.map +1 -1
- package/dist/executors/local-executor.test.js +16 -16
- package/dist/executors/local-executor.test.js.map +1 -1
- package/dist/hooks/hook-runner.d.ts +20 -0
- package/dist/hooks/hook-runner.d.ts.map +1 -0
- package/dist/hooks/hook-runner.js +95 -0
- package/dist/hooks/hook-runner.js.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/types.d.ts +40 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +5 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/index.d.ts +49 -75
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -71
- package/dist/index.js.map +1 -1
- package/dist/interfaces/agent.d.ts +3 -2
- package/dist/interfaces/agent.d.ts.map +1 -1
- package/dist/interfaces/cache.d.ts +64 -0
- package/dist/interfaces/cache.d.ts.map +1 -0
- package/dist/interfaces/cache.js +2 -0
- package/dist/interfaces/cache.js.map +1 -0
- package/dist/interfaces/event-service.d.ts +4 -75
- package/dist/interfaces/event-service.d.ts.map +1 -1
- package/dist/interfaces/executor.d.ts.map +1 -1
- package/dist/interfaces/history-module.d.ts.map +1 -1
- package/dist/interfaces/index.d.ts +12 -9
- package/dist/interfaces/index.d.ts.map +1 -1
- package/dist/interfaces/index.js +2 -1
- package/dist/interfaces/index.js.map +1 -1
- package/dist/interfaces/manager.d.ts.map +1 -1
- package/dist/interfaces/media-provider.d.ts +86 -0
- package/dist/interfaces/media-provider.d.ts.map +1 -0
- package/dist/interfaces/media-provider.js +13 -0
- package/dist/interfaces/media-provider.js.map +1 -0
- package/dist/interfaces/messages.d.ts +23 -1
- package/dist/interfaces/messages.d.ts.map +1 -1
- package/dist/interfaces/messages.js.map +1 -1
- package/dist/interfaces/progress-reporting.d.ts.map +1 -1
- package/dist/interfaces/progress-reporting.js +1 -3
- package/dist/interfaces/progress-reporting.js.map +1 -1
- package/dist/interfaces/provider.d.ts +12 -1
- package/dist/interfaces/provider.d.ts.map +1 -1
- package/dist/interfaces/service.d.ts.map +1 -1
- package/dist/interfaces/tool.d.ts +1 -0
- package/dist/interfaces/tool.d.ts.map +1 -1
- package/dist/interfaces/types.d.ts.map +1 -1
- package/dist/interfaces/types.js +6 -6
- package/dist/interfaces/types.js.map +1 -1
- package/dist/interfaces/workflow-converter.d.ts.map +1 -1
- package/dist/interfaces/workflow-validator.d.ts.map +1 -1
- package/dist/interfaces/workflow-validator.js.map +1 -1
- package/dist/managers/agent-factory.d.ts.map +1 -1
- package/dist/managers/agent-factory.js +24 -16
- package/dist/managers/agent-factory.js.map +1 -1
- package/dist/managers/agent-factory.test.js +35 -25
- package/dist/managers/agent-factory.test.js.map +1 -1
- package/dist/managers/agent-templates.d.ts.map +1 -1
- package/dist/managers/agent-templates.js +22 -10
- package/dist/managers/agent-templates.js.map +1 -1
- package/dist/managers/agent-templates.test.d.ts +2 -0
- package/dist/managers/agent-templates.test.d.ts.map +1 -0
- package/dist/managers/agent-templates.test.js +175 -0
- package/dist/managers/agent-templates.test.js.map +1 -0
- package/dist/managers/ai-provider-manager.d.ts.map +1 -1
- package/dist/managers/ai-provider-manager.js +8 -10
- package/dist/managers/ai-provider-manager.js.map +1 -1
- package/dist/managers/ai-provider-manager.test.d.ts +2 -0
- package/dist/managers/ai-provider-manager.test.d.ts.map +1 -0
- package/dist/managers/ai-provider-manager.test.js +327 -0
- package/dist/managers/ai-provider-manager.test.js.map +1 -0
- package/dist/managers/conversation-history-manager.d.ts +13 -425
- package/dist/managers/conversation-history-manager.d.ts.map +1 -1
- package/dist/managers/conversation-history-manager.js +21 -537
- package/dist/managers/conversation-history-manager.js.map +1 -1
- package/dist/managers/conversation-history-manager.test.js +82 -43
- package/dist/managers/conversation-history-manager.test.js.map +1 -1
- package/dist/managers/conversation-message-factory.d.ts +40 -0
- package/dist/managers/conversation-message-factory.d.ts.map +1 -0
- package/dist/managers/conversation-message-factory.js +66 -0
- package/dist/managers/conversation-message-factory.js.map +1 -0
- package/dist/managers/conversation-message-factory.test.d.ts +2 -0
- package/dist/managers/conversation-message-factory.test.d.ts.map +1 -0
- package/dist/managers/conversation-message-factory.test.js +95 -0
- package/dist/managers/conversation-message-factory.test.js.map +1 -0
- package/dist/managers/conversation-session.d.ts +90 -0
- package/dist/managers/conversation-session.d.ts.map +1 -0
- package/dist/managers/conversation-session.js +177 -0
- package/dist/managers/conversation-session.js.map +1 -0
- package/dist/managers/index.d.ts +2 -2
- package/dist/managers/index.d.ts.map +1 -1
- package/dist/managers/index.js +1 -1
- package/dist/managers/index.js.map +1 -1
- package/dist/managers/module-registry-validation.d.ts +38 -0
- package/dist/managers/module-registry-validation.d.ts.map +1 -0
- package/dist/managers/module-registry-validation.js +100 -0
- package/dist/managers/module-registry-validation.js.map +1 -0
- package/dist/managers/module-registry-validation.test.d.ts +2 -0
- package/dist/managers/module-registry-validation.test.d.ts.map +1 -0
- package/dist/managers/module-registry-validation.test.js +144 -0
- package/dist/managers/module-registry-validation.test.js.map +1 -0
- package/dist/managers/module-registry.d.ts +13 -111
- package/dist/managers/module-registry.d.ts.map +1 -1
- package/dist/managers/module-registry.js +74 -344
- package/dist/managers/module-registry.js.map +1 -1
- package/dist/managers/module-type-registry-helpers.d.ts +34 -0
- package/dist/managers/module-type-registry-helpers.d.ts.map +1 -0
- package/dist/managers/module-type-registry-helpers.js +255 -0
- package/dist/managers/module-type-registry-helpers.js.map +1 -0
- package/dist/managers/module-type-registry.d.ts +10 -64
- package/dist/managers/module-type-registry.d.ts.map +1 -1
- package/dist/managers/module-type-registry.js +25 -373
- package/dist/managers/module-type-registry.js.map +1 -1
- package/dist/managers/plugins-helpers.d.ts +18 -0
- package/dist/managers/plugins-helpers.d.ts.map +1 -0
- package/dist/managers/plugins-helpers.js +118 -0
- package/dist/managers/plugins-helpers.js.map +1 -0
- package/dist/managers/plugins-helpers.test.d.ts +2 -0
- package/dist/managers/plugins-helpers.test.d.ts.map +1 -0
- package/dist/managers/plugins-helpers.test.js +68 -0
- package/dist/managers/plugins-helpers.test.js.map +1 -0
- package/dist/managers/plugins.d.ts +16 -109
- package/dist/managers/plugins.d.ts.map +1 -1
- package/dist/managers/plugins.js +29 -220
- package/dist/managers/plugins.js.map +1 -1
- package/dist/managers/plugins.test.d.ts +2 -0
- package/dist/managers/plugins.test.d.ts.map +1 -0
- package/dist/managers/plugins.test.js +160 -0
- package/dist/managers/plugins.test.js.map +1 -0
- package/dist/managers/tool-manager.d.ts +1 -1
- package/dist/managers/tool-manager.d.ts.map +1 -1
- package/dist/managers/tool-manager.js +15 -5
- package/dist/managers/tool-manager.js.map +1 -1
- package/dist/managers/tool-manager.test.js +32 -16
- package/dist/managers/tool-manager.test.js.map +1 -1
- package/dist/node/index.cjs +6 -4
- package/dist/node/index.d.cts +32 -2
- package/dist/node/index.d.ts +32 -2
- package/dist/node/index.js +6 -4
- package/dist/permissions/index.d.ts +7 -0
- package/dist/permissions/index.d.ts.map +1 -0
- package/dist/permissions/index.js +4 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/permissions/permission-gate.d.ts +38 -0
- package/dist/permissions/permission-gate.d.ts.map +1 -0
- package/dist/permissions/permission-gate.js +119 -0
- package/dist/permissions/permission-gate.js.map +1 -0
- package/dist/permissions/permission-mode.d.ts +25 -0
- package/dist/permissions/permission-mode.d.ts.map +1 -0
- package/dist/permissions/permission-mode.js +58 -0
- package/dist/permissions/permission-mode.js.map +1 -0
- package/dist/permissions/types.d.ts +27 -0
- package/dist/permissions/types.d.ts.map +1 -0
- package/dist/permissions/types.js +9 -0
- package/dist/permissions/types.js.map +1 -0
- package/dist/plugins/event-emitter/metrics.d.ts.map +1 -1
- package/dist/plugins/event-emitter/metrics.js +1 -1
- package/dist/plugins/event-emitter/metrics.js.map +1 -1
- package/dist/plugins/event-emitter/plugin-types.d.ts +88 -0
- package/dist/plugins/event-emitter/plugin-types.d.ts.map +1 -0
- package/dist/plugins/event-emitter/plugin-types.js +2 -0
- package/dist/plugins/event-emitter/plugin-types.js.map +1 -0
- package/dist/plugins/event-emitter/types.d.ts +3 -3
- package/dist/plugins/event-emitter/types.d.ts.map +1 -1
- package/dist/plugins/event-emitter/types.js +4 -4
- package/dist/plugins/event-emitter/types.js.map +1 -1
- package/dist/plugins/event-emitter-plugin.d.ts +9 -184
- package/dist/plugins/event-emitter-plugin.d.ts.map +1 -1
- package/dist/plugins/event-emitter-plugin.js +91 -235
- package/dist/plugins/event-emitter-plugin.js.map +1 -1
- package/dist/schemas/agent-template-schema.d.ts +12 -12
- package/dist/schemas/agent-template-schema.d.ts.map +1 -1
- package/dist/schemas/agent-template-schema.js +35 -33
- package/dist/schemas/agent-template-schema.js.map +1 -1
- package/dist/services/cache/cache-key-builder.d.ts +13 -0
- package/dist/services/cache/cache-key-builder.d.ts.map +1 -0
- package/dist/services/cache/cache-key-builder.js +30 -0
- package/dist/services/cache/cache-key-builder.js.map +1 -0
- package/dist/services/cache/cache-key-builder.test.d.ts +2 -0
- package/dist/services/cache/cache-key-builder.test.d.ts.map +1 -0
- package/dist/services/cache/cache-key-builder.test.js +56 -0
- package/dist/services/cache/cache-key-builder.test.js.map +1 -0
- package/dist/services/cache/execution-cache-service.d.ts +18 -0
- package/dist/services/cache/execution-cache-service.d.ts.map +1 -0
- package/dist/services/cache/execution-cache-service.js +26 -0
- package/dist/services/cache/execution-cache-service.js.map +1 -0
- package/dist/services/cache/execution-cache-service.test.d.ts +2 -0
- package/dist/services/cache/execution-cache-service.test.d.ts.map +1 -0
- package/dist/services/cache/execution-cache-service.test.js +59 -0
- package/dist/services/cache/execution-cache-service.test.js.map +1 -0
- package/dist/services/cache/index.d.ts +4 -0
- package/dist/services/cache/index.d.ts.map +1 -0
- package/dist/services/cache/index.js +4 -0
- package/dist/services/cache/index.js.map +1 -0
- package/dist/services/cache/memory-cache-storage.d.ts +25 -0
- package/dist/services/cache/memory-cache-storage.d.ts.map +1 -0
- package/dist/services/cache/memory-cache-storage.js +89 -0
- package/dist/services/cache/memory-cache-storage.js.map +1 -0
- package/dist/services/cache/memory-cache-storage.test.d.ts +2 -0
- package/dist/services/cache/memory-cache-storage.test.d.ts.map +1 -0
- package/dist/services/cache/memory-cache-storage.test.js +94 -0
- package/dist/services/cache/memory-cache-storage.test.js.map +1 -0
- package/dist/services/conversation-service/conversation-service.test.d.ts +2 -0
- package/dist/services/conversation-service/conversation-service.test.d.ts.map +1 -0
- package/dist/services/conversation-service/conversation-service.test.js +248 -0
- package/dist/services/conversation-service/conversation-service.test.js.map +1 -0
- package/dist/services/conversation-service/index.d.ts +10 -71
- package/dist/services/conversation-service/index.d.ts.map +1 -1
- package/dist/services/conversation-service/index.js +58 -355
- package/dist/services/conversation-service/index.js.map +1 -1
- package/dist/services/conversation-service/message-helpers.d.ts +47 -0
- package/dist/services/conversation-service/message-helpers.d.ts.map +1 -0
- package/dist/services/conversation-service/message-helpers.js +150 -0
- package/dist/services/conversation-service/message-helpers.js.map +1 -0
- package/dist/services/conversation-service/types.d.ts.map +1 -1
- package/dist/services/execution-constants.d.ts +16 -0
- package/dist/services/execution-constants.d.ts.map +1 -0
- package/dist/services/execution-constants.js +16 -0
- package/dist/services/execution-constants.js.map +1 -0
- package/dist/services/execution-event-emitter.d.ts +60 -0
- package/dist/services/execution-event-emitter.d.ts.map +1 -0
- package/dist/services/execution-event-emitter.js +323 -0
- package/dist/services/execution-event-emitter.js.map +1 -0
- package/dist/services/execution-round.d.ts +58 -0
- package/dist/services/execution-round.d.ts.map +1 -0
- package/dist/services/execution-round.js +323 -0
- package/dist/services/execution-round.js.map +1 -0
- package/dist/services/execution-round.test.d.ts +2 -0
- package/dist/services/execution-round.test.d.ts.map +1 -0
- package/dist/services/execution-round.test.js +188 -0
- package/dist/services/execution-round.test.js.map +1 -0
- package/dist/services/execution-service.d.ts +28 -125
- package/dist/services/execution-service.d.ts.map +1 -1
- package/dist/services/execution-service.js +222 -1134
- package/dist/services/execution-service.js.map +1 -1
- package/dist/services/execution-service.test.js +115 -72
- package/dist/services/execution-service.test.js.map +1 -1
- package/dist/services/execution-stream.d.ts +32 -0
- package/dist/services/execution-stream.d.ts.map +1 -0
- package/dist/services/execution-stream.js +268 -0
- package/dist/services/execution-stream.js.map +1 -0
- package/dist/services/execution-types.d.ts +122 -0
- package/dist/services/execution-types.d.ts.map +1 -0
- package/dist/services/execution-types.js +48 -0
- package/dist/services/execution-types.js.map +1 -0
- package/dist/services/history-module.d.ts.map +1 -1
- package/dist/services/history-module.js +1 -1
- package/dist/services/history-module.js.map +1 -1
- package/dist/services/history-module.test.d.ts +2 -0
- package/dist/services/history-module.test.d.ts.map +1 -0
- package/dist/services/history-module.test.js +137 -0
- package/dist/services/history-module.test.js.map +1 -0
- package/dist/services/in-memory-history-store.d.ts.map +1 -1
- package/dist/services/in-memory-history-store.js +1 -1
- package/dist/services/in-memory-history-store.js.map +1 -1
- package/dist/services/index.d.ts +0 -1
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +2 -3
- package/dist/services/index.js.map +1 -1
- package/dist/services/plugin-hook-dispatcher.d.ts +11 -0
- package/dist/services/plugin-hook-dispatcher.d.ts.map +1 -0
- package/dist/services/plugin-hook-dispatcher.js +68 -0
- package/dist/services/plugin-hook-dispatcher.js.map +1 -0
- package/dist/services/plugin-hook-dispatcher.test.d.ts +2 -0
- package/dist/services/plugin-hook-dispatcher.test.d.ts.map +1 -0
- package/dist/services/plugin-hook-dispatcher.test.js +93 -0
- package/dist/services/plugin-hook-dispatcher.test.js.map +1 -0
- package/dist/services/plugin-priority.test.d.ts +2 -0
- package/dist/services/plugin-priority.test.d.ts.map +1 -0
- package/dist/services/plugin-priority.test.js +119 -0
- package/dist/services/plugin-priority.test.js.map +1 -0
- package/dist/services/tool-execution-service.d.ts +1 -0
- package/dist/services/tool-execution-service.d.ts.map +1 -1
- package/dist/services/tool-execution-service.js +89 -46
- package/dist/services/tool-execution-service.js.map +1 -1
- package/dist/services/tool-execution-service.test.d.ts +2 -0
- package/dist/services/tool-execution-service.test.d.ts.map +1 -0
- package/dist/services/tool-execution-service.test.js +358 -0
- package/dist/services/tool-execution-service.test.js.map +1 -0
- package/dist/tool-registry/function-tool.d.ts +54 -0
- package/dist/tool-registry/function-tool.d.ts.map +1 -0
- package/dist/tool-registry/function-tool.js +190 -0
- package/dist/tool-registry/function-tool.js.map +1 -0
- package/dist/tool-registry/index.d.ts +3 -0
- package/dist/tool-registry/index.d.ts.map +1 -0
- package/dist/tool-registry/index.js +3 -0
- package/dist/tool-registry/index.js.map +1 -0
- package/dist/tool-registry/tool-registry.d.ts +54 -0
- package/dist/tool-registry/tool-registry.d.ts.map +1 -0
- package/dist/tool-registry/tool-registry.js +148 -0
- package/dist/tool-registry/tool-registry.js.map +1 -0
- package/dist/utils/errors.d.ts +11 -2
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +13 -2
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/errors.test.d.ts +2 -0
- package/dist/utils/errors.test.d.ts.map +1 -0
- package/dist/utils/errors.test.js +361 -0
- package/dist/utils/errors.test.js.map +1 -0
- package/dist/utils/execution-proxy.d.ts +7 -3
- package/dist/utils/execution-proxy.d.ts.map +1 -1
- package/dist/utils/execution-proxy.js +64 -42
- package/dist/utils/execution-proxy.js.map +1 -1
- package/dist/utils/execution-proxy.test.d.ts +2 -0
- package/dist/utils/execution-proxy.test.d.ts.map +1 -0
- package/dist/utils/execution-proxy.test.js +179 -0
- package/dist/utils/execution-proxy.test.js.map +1 -0
- package/dist/utils/logger.d.ts +3 -3
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +9 -5
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/message-converter.d.ts +1 -4
- package/dist/utils/message-converter.d.ts.map +1 -1
- package/dist/utils/message-converter.js +13 -12
- package/dist/utils/message-converter.js.map +1 -1
- package/dist/utils/message-converter.test.d.ts +2 -0
- package/dist/utils/message-converter.test.d.ts.map +1 -0
- package/dist/utils/message-converter.test.js +164 -0
- package/dist/utils/message-converter.test.js.map +1 -0
- package/dist/utils/periodic-task.d.ts +1 -1
- package/dist/utils/periodic-task.d.ts.map +1 -1
- package/dist/utils/periodic-task.js +1 -1
- package/dist/utils/periodic-task.js.map +1 -1
- package/dist/utils/periodic-task.test.d.ts +2 -0
- package/dist/utils/periodic-task.test.d.ts.map +1 -0
- package/dist/utils/periodic-task.test.js +87 -0
- package/dist/utils/periodic-task.test.js.map +1 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +17 -11
- package/dist/utils/validation.js.map +1 -1
- package/dist/utils/validation.test.d.ts +2 -0
- package/dist/utils/validation.test.d.ts.map +1 -0
- package/dist/utils/validation.test.js +249 -0
- package/dist/utils/validation.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,29 +1,17 @@
|
|
|
1
|
-
import { ToolExecutionService
|
|
1
|
+
import { ToolExecutionService } from './tool-execution-service';
|
|
2
2
|
import { createLogger } from '../utils/logger';
|
|
3
|
-
|
|
3
|
+
// Re-export constants for public API compatibility
|
|
4
|
+
export { EXECUTION_EVENTS, EXECUTION_EVENT_PREFIX } from './execution-constants';
|
|
5
|
+
import { EXECUTION_EVENTS } from './execution-constants';
|
|
6
|
+
import { PREVIEW_LENGTH, ID_RADIX, ID_RANDOM_LENGTH, } from './execution-types';
|
|
7
|
+
import { ExecutionEventEmitter } from './execution-event-emitter';
|
|
8
|
+
import { callPluginHook } from './plugin-hook-dispatcher';
|
|
9
|
+
import { executeStream as executeStreamFn } from './execution-stream';
|
|
10
|
+
import { executeRound } from './execution-round';
|
|
4
11
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
|
12
|
+
* Service that orchestrates the entire execution pipeline.
|
|
13
|
+
* Coordinates AI provider execution, tool execution service, and plugin lifecycle.
|
|
14
|
+
* Uses centralized conversation history management.
|
|
27
15
|
*/
|
|
28
16
|
export class ExecutionService {
|
|
29
17
|
toolExecutionService;
|
|
@@ -32,15 +20,9 @@ export class ExecutionService {
|
|
|
32
20
|
conversationHistory;
|
|
33
21
|
plugins = [];
|
|
34
22
|
logger;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
) {
|
|
23
|
+
eventEmitter;
|
|
24
|
+
cacheService;
|
|
25
|
+
constructor(aiProviders, tools, conversationHistory, eventService, executionContext, cacheService) {
|
|
44
26
|
this.toolExecutionService = new ToolExecutionService(tools);
|
|
45
27
|
this.aiProviders = aiProviders;
|
|
46
28
|
this.tools = tools;
|
|
@@ -50,30 +32,31 @@ export class ExecutionService {
|
|
|
50
32
|
if (!eventService) {
|
|
51
33
|
throw new Error('[EXECUTION] EventService is required');
|
|
52
34
|
}
|
|
53
|
-
this.
|
|
54
|
-
this.
|
|
55
|
-
this.ownerPathBase = this.buildBaseOwnerPath(executionContext);
|
|
56
|
-
this.toolEventServices = new Map();
|
|
57
|
-
this.agentOwnerPathBase = [];
|
|
35
|
+
this.eventEmitter = new ExecutionEventEmitter(eventService, this.logger, executionContext);
|
|
36
|
+
this.cacheService = cacheService;
|
|
58
37
|
}
|
|
59
|
-
/**
|
|
60
|
-
* Register a plugin
|
|
61
|
-
*/
|
|
38
|
+
/** Register a plugin */
|
|
62
39
|
registerPlugin(plugin) {
|
|
63
|
-
|
|
40
|
+
const pluginPriority = plugin.priority ?? 0;
|
|
41
|
+
const insertIndex = this.plugins.findIndex((p) => (p.priority ?? 0) < pluginPriority);
|
|
42
|
+
if (insertIndex === -1) {
|
|
43
|
+
this.plugins.push(plugin);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
this.plugins.splice(insertIndex, 0, plugin);
|
|
47
|
+
}
|
|
64
48
|
this.logger.debug('Plugin registered', {
|
|
65
49
|
pluginName: plugin.name,
|
|
50
|
+
priority: pluginPriority,
|
|
66
51
|
hasBeforeRun: typeof plugin.beforeRun,
|
|
67
52
|
hasAfterRun: typeof plugin.afterRun,
|
|
68
53
|
hasBeforeProviderCall: typeof plugin.beforeProviderCall,
|
|
69
|
-
hasAfterProviderCall: typeof plugin.afterProviderCall
|
|
54
|
+
hasAfterProviderCall: typeof plugin.afterProviderCall,
|
|
70
55
|
});
|
|
71
56
|
}
|
|
72
|
-
/**
|
|
73
|
-
* Remove a plugin
|
|
74
|
-
*/
|
|
57
|
+
/** Remove a plugin */
|
|
75
58
|
removePlugin(pluginName) {
|
|
76
|
-
const index = this.plugins.findIndex(p => p.name === pluginName);
|
|
59
|
+
const index = this.plugins.findIndex((p) => p.name === pluginName);
|
|
77
60
|
if (index !== -1) {
|
|
78
61
|
this.plugins.splice(index, 1);
|
|
79
62
|
this.logger.debug('Plugin removed', { pluginName });
|
|
@@ -81,24 +64,16 @@ export class ExecutionService {
|
|
|
81
64
|
}
|
|
82
65
|
return false;
|
|
83
66
|
}
|
|
84
|
-
/**
|
|
85
|
-
* Get a plugin by name
|
|
86
|
-
*/
|
|
67
|
+
/** Get a plugin by name */
|
|
87
68
|
getPlugin(pluginName) {
|
|
88
|
-
return this.plugins.find(p => p.name === pluginName)
|
|
69
|
+
return this.plugins.find((p) => p.name === pluginName);
|
|
89
70
|
}
|
|
90
|
-
/**
|
|
91
|
-
* Get all registered plugins
|
|
92
|
-
*/
|
|
71
|
+
/** Get all registered plugins */
|
|
93
72
|
getPlugins() {
|
|
94
73
|
return [...this.plugins];
|
|
95
74
|
}
|
|
96
|
-
/**
|
|
97
|
-
* Execute the full pipeline with centralized history management
|
|
98
|
-
*/
|
|
75
|
+
/** Execute the full pipeline with centralized history management */
|
|
99
76
|
async execute(input, messages, config, context) {
|
|
100
|
-
// [EXECUTION-DEBUG] ExecutionService.execute entrypoint
|
|
101
|
-
// Avoid console usage; use injected logger only.
|
|
102
77
|
const executionId = this.generateExecutionId();
|
|
103
78
|
const startTime = new Date();
|
|
104
79
|
const conversationId = this.requireConversationId(context, 'execute');
|
|
@@ -110,1128 +85,246 @@ export class ExecutionService {
|
|
|
110
85
|
conversationId,
|
|
111
86
|
...(context?.sessionId && { sessionId: context.sessionId }),
|
|
112
87
|
...(context?.userId && { userId: context.userId }),
|
|
113
|
-
...(context?.metadata && { metadata: context.metadata })
|
|
88
|
+
...(context?.metadata && { metadata: context.metadata }),
|
|
114
89
|
};
|
|
115
|
-
this.prepareOwnerPathBases(conversationId);
|
|
90
|
+
this.eventEmitter.prepareOwnerPathBases(conversationId);
|
|
116
91
|
this.logger.debug('Starting execution pipeline', {
|
|
117
92
|
executionId,
|
|
118
93
|
conversationId,
|
|
119
94
|
messageCount: messages.length,
|
|
120
|
-
hasContext: !!context
|
|
95
|
+
hasContext: !!context,
|
|
121
96
|
});
|
|
122
|
-
|
|
123
|
-
|
|
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);
|
|
97
|
+
const resolved = this.resolveProviderAndTools(config);
|
|
98
|
+
this.eventEmitter.emitExecutionStartEvent(input, config, messages, resolved, conversationId, executionId);
|
|
175
99
|
try {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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', {
|
|
100
|
+
const conversationSession = this.initializeConversationSession(conversationId, messages, config, executionId);
|
|
101
|
+
conversationSession.addUserMessage(input, { executionId });
|
|
102
|
+
this.eventEmitter.emitUserMessageEvent(input, conversationId, executionId);
|
|
103
|
+
await callPluginHook(this.plugins, 'beforeRun', {
|
|
240
104
|
input,
|
|
241
|
-
...(context?.metadata ? { metadata: context.metadata } : {})
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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');
|
|
105
|
+
...(context?.metadata ? { metadata: context.metadata } : {}),
|
|
106
|
+
}, this.logger);
|
|
107
|
+
this.validateProvider(resolved);
|
|
108
|
+
const roundState = {
|
|
109
|
+
toolsExecuted: [],
|
|
110
|
+
currentRound: 0,
|
|
111
|
+
runningAssistantCount: 0,
|
|
112
|
+
lastTrackedAssistantMessage: undefined,
|
|
113
|
+
cumulativeInputTokens: 0,
|
|
114
|
+
};
|
|
115
|
+
const initialMessages = conversationSession.getMessages();
|
|
116
|
+
for (const msg of initialMessages) {
|
|
117
|
+
if (msg.role === 'assistant') {
|
|
118
|
+
roundState.runningAssistantCount++;
|
|
119
|
+
roundState.lastTrackedAssistantMessage = msg;
|
|
618
120
|
}
|
|
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
121
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
this.
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
122
|
+
const maxRounds = 10;
|
|
123
|
+
const roundDeps = {
|
|
124
|
+
toolExecutionService: this.toolExecutionService,
|
|
125
|
+
plugins: this.plugins,
|
|
126
|
+
logger: this.logger,
|
|
127
|
+
eventEmitter: this.eventEmitter,
|
|
128
|
+
cacheService: this.cacheService,
|
|
129
|
+
};
|
|
130
|
+
while (roundState.currentRound < maxRounds) {
|
|
131
|
+
roundState.currentRound++;
|
|
132
|
+
const shouldBreak = await executeRound(roundState, maxRounds, conversationSession, conversationId, executionId, fullContext, config, resolved, roundDeps);
|
|
133
|
+
if (shouldBreak)
|
|
134
|
+
break;
|
|
673
135
|
}
|
|
674
|
-
|
|
675
|
-
|
|
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');
|
|
136
|
+
if (roundState.currentRound >= maxRounds) {
|
|
137
|
+
this.logger.warn('Maximum execution rounds reached', { maxRounds, conversationId });
|
|
681
138
|
}
|
|
682
|
-
const
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
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 });
|
|
139
|
+
const result = this.buildFinalResult(conversationSession, executionId, startTime, roundState.toolsExecuted);
|
|
140
|
+
await callPluginHook(this.plugins, 'afterRun', {
|
|
141
|
+
input,
|
|
142
|
+
response: result.response,
|
|
143
|
+
metadata: context?.metadata,
|
|
144
|
+
}, this.logger);
|
|
718
145
|
this.logger.debug('Execution pipeline completed successfully', {
|
|
719
146
|
executionId,
|
|
720
147
|
conversationId,
|
|
721
|
-
duration,
|
|
148
|
+
duration: result.duration,
|
|
722
149
|
tokensUsed: result.tokensUsed,
|
|
723
150
|
toolsExecuted: result.toolsExecuted.length,
|
|
724
|
-
rounds: currentRound
|
|
151
|
+
rounds: roundState.currentRound,
|
|
725
152
|
});
|
|
726
|
-
|
|
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, {
|
|
153
|
+
this.eventEmitter.emitExecution(EXECUTION_EVENTS.COMPLETE, {
|
|
731
154
|
result: {
|
|
732
155
|
success: true,
|
|
733
|
-
data: result.response.substring(0,
|
|
156
|
+
data: result.response.substring(0, PREVIEW_LENGTH) + '...',
|
|
734
157
|
},
|
|
735
158
|
metadata: {
|
|
736
159
|
method: 'execute',
|
|
737
160
|
success: true,
|
|
738
|
-
duration,
|
|
161
|
+
duration: result.duration,
|
|
739
162
|
tokensUsed: result.tokensUsed,
|
|
740
|
-
toolsExecuted: result.toolsExecuted
|
|
741
|
-
}
|
|
742
|
-
},
|
|
163
|
+
toolsExecuted: result.toolsExecuted,
|
|
164
|
+
},
|
|
165
|
+
}, conversationId, executionId);
|
|
743
166
|
return result;
|
|
744
167
|
}
|
|
745
168
|
catch (error) {
|
|
746
|
-
|
|
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);
|
|
169
|
+
await this.handleExecutionError(error, fullContext, startTime, conversationId, executionId);
|
|
768
170
|
throw error;
|
|
769
171
|
}
|
|
770
172
|
finally {
|
|
771
|
-
this.resetOwnerPathBases();
|
|
173
|
+
this.eventEmitter.resetOwnerPathBases();
|
|
772
174
|
}
|
|
773
175
|
}
|
|
774
|
-
/**
|
|
775
|
-
* Execute with streaming response
|
|
776
|
-
*/
|
|
176
|
+
/** Execute with streaming response */
|
|
777
177
|
async *executeStream(input, messages, config, context) {
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
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)}`;
|
|
178
|
+
yield* executeStreamFn(input, messages, config, context, {
|
|
179
|
+
aiProviders: this.aiProviders,
|
|
180
|
+
tools: this.tools,
|
|
181
|
+
conversationHistory: this.conversationHistory,
|
|
182
|
+
toolExecutionService: this.toolExecutionService,
|
|
183
|
+
plugins: this.plugins,
|
|
184
|
+
logger: this.logger,
|
|
185
|
+
eventEmitter: this.eventEmitter,
|
|
186
|
+
generateExecutionId: () => this.generateExecutionId(),
|
|
187
|
+
});
|
|
1029
188
|
}
|
|
1030
|
-
/**
|
|
1031
|
-
* Get execution statistics from plugins
|
|
1032
|
-
*/
|
|
189
|
+
/** Get execution statistics from plugins */
|
|
1033
190
|
async getStats() {
|
|
1034
|
-
|
|
191
|
+
return {
|
|
1035
192
|
pluginCount: this.plugins.length,
|
|
1036
|
-
pluginNames: this.plugins.map(p => p.name),
|
|
1037
|
-
historyStats: this.conversationHistory.getStats()
|
|
193
|
+
pluginNames: this.plugins.map((p) => p.name),
|
|
194
|
+
historyStats: this.conversationHistory.getStats(),
|
|
1038
195
|
};
|
|
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
196
|
}
|
|
1043
|
-
/**
|
|
1044
|
-
* Clear all plugins
|
|
1045
|
-
*/
|
|
197
|
+
/** Clear all plugins */
|
|
1046
198
|
clearPlugins() {
|
|
1047
199
|
this.plugins = [];
|
|
1048
200
|
this.logger.debug('All plugins cleared');
|
|
1049
201
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
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);
|
|
202
|
+
// --- Private helpers ---
|
|
203
|
+
resolveProviderAndTools(config) {
|
|
204
|
+
const currentInfo = this.aiProviders.getCurrentProvider();
|
|
205
|
+
const provider = currentInfo ? this.aiProviders.getProvider(currentInfo.provider) : null;
|
|
206
|
+
if (!currentInfo || !currentInfo.provider || !provider) {
|
|
207
|
+
throw new Error('[EXECUTION] Provider is required');
|
|
1125
208
|
}
|
|
1126
|
-
const
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
209
|
+
const availableTools = this.tools.getTools();
|
|
210
|
+
const aiProviderInfo = {
|
|
211
|
+
providerName: currentInfo.provider,
|
|
212
|
+
model: config.defaultModel.model,
|
|
213
|
+
temperature: config.defaultModel.temperature,
|
|
214
|
+
maxTokens: config.defaultModel.maxTokens,
|
|
215
|
+
};
|
|
216
|
+
const toolsInfo = availableTools.map((tool) => {
|
|
217
|
+
const paramSchema = tool.parameters;
|
|
218
|
+
const props = paramSchema?.properties;
|
|
219
|
+
if (!tool.description || tool.description.length === 0) {
|
|
220
|
+
throw new Error(`[EXECUTION] Tool "${tool.name}" is missing description`);
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
name: tool.name,
|
|
224
|
+
description: tool.description,
|
|
225
|
+
parameters: props && typeof props === 'object' ? Object.keys(props) : [],
|
|
226
|
+
};
|
|
1130
227
|
});
|
|
1131
|
-
|
|
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 }));
|
|
228
|
+
return { provider, currentInfo, aiProviderInfo, toolsInfo, availableTools };
|
|
1148
229
|
}
|
|
1149
|
-
|
|
1150
|
-
if (!
|
|
1151
|
-
throw new Error('
|
|
230
|
+
validateProvider(resolved) {
|
|
231
|
+
if (!resolved.currentInfo)
|
|
232
|
+
throw new Error('No AI provider configured');
|
|
233
|
+
if (!resolved.provider)
|
|
234
|
+
throw new Error(`AI provider '${resolved.currentInfo.provider}' not found`);
|
|
235
|
+
if (typeof resolved.provider.chat !== 'function') {
|
|
236
|
+
throw new Error('Provider must have chat method to support execution');
|
|
1152
237
|
}
|
|
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
238
|
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
239
|
+
initializeConversationSession(conversationId, messages, config, executionId) {
|
|
240
|
+
const session = this.conversationHistory.getConversationSession(conversationId);
|
|
241
|
+
if (session.getMessageCount() === 0 && messages.length > 0) {
|
|
242
|
+
for (const msg of messages) {
|
|
243
|
+
if (msg.role === 'user') {
|
|
244
|
+
session.addUserMessage(msg.content, msg.metadata, msg.parts);
|
|
245
|
+
}
|
|
246
|
+
else if (msg.role === 'assistant') {
|
|
247
|
+
session.addAssistantMessage(msg.content, msg.toolCalls, msg.metadata, msg.parts);
|
|
248
|
+
}
|
|
249
|
+
else if (msg.role === 'system') {
|
|
250
|
+
session.addSystemMessage(msg.content, msg.metadata, msg.parts);
|
|
251
|
+
}
|
|
252
|
+
else if (msg.role === 'tool') {
|
|
253
|
+
const toolName = msg.metadata?.['toolName'];
|
|
254
|
+
if (typeof toolName !== 'string' || toolName.length === 0) {
|
|
255
|
+
throw new Error('[EXECUTION] Tool message missing toolName metadata');
|
|
256
|
+
}
|
|
257
|
+
session.addToolMessageWithId(msg.content, msg.toolCallId, toolName, msg.metadata, msg.parts);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
1177
260
|
}
|
|
1178
|
-
|
|
1179
|
-
|
|
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');
|
|
261
|
+
if (config.systemMessage) {
|
|
262
|
+
session.addSystemMessage(config.systemMessage, { executionId });
|
|
1190
263
|
}
|
|
1191
|
-
|
|
1192
|
-
const path = [...base, { type: 'tool', id: toolCallId }];
|
|
1193
|
-
return {
|
|
1194
|
-
ownerType: TOOL_EVENT_PREFIX,
|
|
1195
|
-
ownerId: toolCallId,
|
|
1196
|
-
ownerPath: path
|
|
1197
|
-
};
|
|
264
|
+
return session;
|
|
1198
265
|
}
|
|
1199
|
-
|
|
1200
|
-
const
|
|
1201
|
-
const
|
|
1202
|
-
const
|
|
266
|
+
buildFinalResult(conversationSession, executionId, startTime, toolsExecuted) {
|
|
267
|
+
const finalMessages = conversationSession.getMessages();
|
|
268
|
+
const lastAssistantMessage = finalMessages.filter((msg) => msg.role === 'assistant').pop();
|
|
269
|
+
const hasValidResponse = !!lastAssistantMessage &&
|
|
270
|
+
typeof lastAssistantMessage.content === 'string' &&
|
|
271
|
+
lastAssistantMessage.content.length > 0;
|
|
272
|
+
const response = hasValidResponse
|
|
273
|
+
? lastAssistantMessage.content
|
|
274
|
+
: '(execution interrupted: no final assistant response — possible context overflow or max turn limit)';
|
|
275
|
+
const duration = Date.now() - startTime.getTime();
|
|
1203
276
|
return {
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
277
|
+
response,
|
|
278
|
+
messages: finalMessages.map((msg) => {
|
|
279
|
+
if (typeof msg.content !== 'string')
|
|
280
|
+
throw new Error('[EXECUTION] Message content is required');
|
|
281
|
+
return {
|
|
282
|
+
role: msg.role,
|
|
283
|
+
content: msg.content,
|
|
284
|
+
timestamp: msg.timestamp,
|
|
285
|
+
metadata: msg.metadata,
|
|
286
|
+
...(msg.role === 'assistant' && 'toolCalls' in msg ? { toolCalls: msg.toolCalls } : {}),
|
|
287
|
+
...(msg.role === 'tool' && 'toolCallId' in msg ? { toolCallId: msg.toolCallId } : {}),
|
|
288
|
+
};
|
|
289
|
+
}),
|
|
290
|
+
executionId,
|
|
291
|
+
duration,
|
|
292
|
+
tokensUsed: finalMessages
|
|
293
|
+
.filter((msg) => msg.metadata?.['usage'])
|
|
294
|
+
.reduce((sum, msg) => {
|
|
295
|
+
const usage = msg.metadata?.['usage'];
|
|
296
|
+
if (usage && typeof usage === 'object' && 'totalTokens' in usage) {
|
|
297
|
+
const totalTokens = Number(usage.totalTokens);
|
|
298
|
+
if (Number.isNaN(totalTokens))
|
|
299
|
+
throw new Error('[EXECUTION] totalTokens must be a number');
|
|
300
|
+
return sum + totalTokens;
|
|
301
|
+
}
|
|
302
|
+
return sum;
|
|
303
|
+
}, 0),
|
|
304
|
+
toolsExecuted,
|
|
305
|
+
success: hasValidResponse,
|
|
1207
306
|
};
|
|
1208
307
|
}
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
308
|
+
async handleExecutionError(error, fullContext, startTime, conversationId, executionId) {
|
|
309
|
+
const duration = Date.now() - startTime.getTime();
|
|
310
|
+
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
311
|
+
await callPluginHook(this.plugins, 'onError', {
|
|
312
|
+
error: normalizedError,
|
|
313
|
+
executionContext: this.convertExecutionContextToPluginFormat(fullContext),
|
|
314
|
+
}, this.logger);
|
|
315
|
+
this.logger.error('Execution pipeline failed', {
|
|
316
|
+
executionId,
|
|
317
|
+
conversationId,
|
|
318
|
+
duration,
|
|
319
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1219
320
|
});
|
|
321
|
+
this.eventEmitter.emitExecution(EXECUTION_EVENTS.ERROR, {
|
|
322
|
+
error: error instanceof Error ? error.message : String(error),
|
|
323
|
+
metadata: { method: 'execute', success: false, duration },
|
|
324
|
+
}, conversationId, executionId);
|
|
1220
325
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
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);
|
|
326
|
+
generateExecutionId() {
|
|
327
|
+
return `exec_${Date.now()}_${Math.random().toString(ID_RADIX).substr(2, ID_RANDOM_LENGTH)}`;
|
|
1235
328
|
}
|
|
1236
329
|
requireConversationId(context, label) {
|
|
1237
330
|
if (!context?.conversationId || context.conversationId.length === 0) {
|
|
@@ -1239,23 +332,18 @@ export class ExecutionService {
|
|
|
1239
332
|
}
|
|
1240
333
|
return context.conversationId;
|
|
1241
334
|
}
|
|
1242
|
-
/**
|
|
1243
|
-
* Convert IExecutionContext to IPluginContext compatible format
|
|
1244
|
-
*/
|
|
1245
335
|
convertExecutionContextToPluginFormat(context) {
|
|
1246
336
|
const conversationId = this.requireConversationId(context, 'plugin-context');
|
|
1247
337
|
const payload = {
|
|
1248
|
-
conversationId
|
|
338
|
+
conversationId,
|
|
1249
339
|
executionId: context.executionId,
|
|
1250
340
|
startTime: context.startTime.toISOString(),
|
|
1251
|
-
messageCount: context.messages.length
|
|
341
|
+
messageCount: context.messages.length,
|
|
1252
342
|
};
|
|
1253
|
-
if (context.sessionId)
|
|
343
|
+
if (context.sessionId)
|
|
1254
344
|
payload.sessionId = context.sessionId;
|
|
1255
|
-
|
|
1256
|
-
if (context.userId) {
|
|
345
|
+
if (context.userId)
|
|
1257
346
|
payload.userId = context.userId;
|
|
1258
|
-
}
|
|
1259
347
|
return payload;
|
|
1260
348
|
}
|
|
1261
349
|
}
|