@falai/agent 2.2.4 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/adapters/MemoryAdapter.d.ts.map +1 -1
- package/dist/adapters/MemoryAdapter.js +10 -1
- package/dist/adapters/MemoryAdapter.js.map +1 -1
- package/dist/adapters/MongoAdapter.d.ts.map +1 -1
- package/dist/adapters/MongoAdapter.js +33 -2
- package/dist/adapters/MongoAdapter.js.map +1 -1
- package/dist/adapters/OpenSearchAdapter.d.ts.map +1 -1
- package/dist/adapters/OpenSearchAdapter.js +15 -1
- package/dist/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -1
- package/dist/adapters/PostgreSQLAdapter.js +35 -5
- package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/adapters/PrismaAdapter.d.ts.map +1 -1
- package/dist/adapters/PrismaAdapter.js +58 -15
- package/dist/adapters/PrismaAdapter.js.map +1 -1
- package/dist/adapters/RedisAdapter.d.ts.map +1 -1
- package/dist/adapters/RedisAdapter.js +10 -1
- package/dist/adapters/RedisAdapter.js.map +1 -1
- package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/adapters/SQLiteAdapter.js +38 -6
- package/dist/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/cjs/adapters/MemoryAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/MemoryAdapter.js +10 -1
- package/dist/cjs/adapters/MemoryAdapter.js.map +1 -1
- package/dist/cjs/adapters/MongoAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/MongoAdapter.js +33 -2
- package/dist/cjs/adapters/MongoAdapter.js.map +1 -1
- package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/OpenSearchAdapter.js +15 -1
- package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.js +35 -5
- package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/cjs/adapters/PrismaAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/PrismaAdapter.js +58 -15
- package/dist/cjs/adapters/PrismaAdapter.js.map +1 -1
- package/dist/cjs/adapters/RedisAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/RedisAdapter.js +10 -1
- package/dist/cjs/adapters/RedisAdapter.js.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.js +38 -6
- package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/cjs/core/Agent.d.ts +28 -18
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +58 -68
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/AutoChainExecutor.d.ts.map +1 -1
- package/dist/cjs/core/AutoChainExecutor.js +14 -20
- package/dist/cjs/core/AutoChainExecutor.js.map +1 -1
- package/dist/cjs/core/BranchEvaluator.d.ts +4 -3
- package/dist/cjs/core/BranchEvaluator.d.ts.map +1 -1
- package/dist/cjs/core/BranchEvaluator.js +18 -23
- package/dist/cjs/core/BranchEvaluator.js.map +1 -1
- package/dist/cjs/core/Flow.d.ts +2 -1
- package/dist/cjs/core/Flow.d.ts.map +1 -1
- package/dist/cjs/core/Flow.js +10 -3
- package/dist/cjs/core/Flow.js.map +1 -1
- package/dist/cjs/core/FlowRouter.d.ts +1 -0
- package/dist/cjs/core/FlowRouter.d.ts.map +1 -1
- package/dist/cjs/core/FlowRouter.js +28 -5
- package/dist/cjs/core/FlowRouter.js.map +1 -1
- package/dist/cjs/core/PersistenceManager.d.ts +3 -0
- package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
- package/dist/cjs/core/PersistenceManager.js +57 -5
- package/dist/cjs/core/PersistenceManager.js.map +1 -1
- package/dist/cjs/core/PromptComposer.d.ts.map +1 -1
- package/dist/cjs/core/PromptComposer.js +24 -10
- package/dist/cjs/core/PromptComposer.js.map +1 -1
- package/dist/cjs/core/ResponseGenerationError.d.ts +30 -0
- package/dist/cjs/core/ResponseGenerationError.d.ts.map +1 -0
- package/dist/cjs/core/ResponseGenerationError.js +37 -0
- package/dist/cjs/core/ResponseGenerationError.js.map +1 -0
- package/dist/cjs/core/ResponseModal.d.ts +43 -102
- package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
- package/dist/cjs/core/ResponseModal.js +178 -1194
- package/dist/cjs/core/ResponseModal.js.map +1 -1
- package/dist/cjs/core/ResponsePipeline.d.ts +58 -152
- package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/cjs/core/ResponsePipeline.js +408 -457
- package/dist/cjs/core/ResponsePipeline.js.map +1 -1
- package/dist/cjs/core/SessionFinalizer.d.ts +34 -0
- package/dist/cjs/core/SessionFinalizer.d.ts.map +1 -0
- package/dist/cjs/core/SessionFinalizer.js +61 -0
- package/dist/cjs/core/SessionFinalizer.js.map +1 -0
- package/dist/cjs/core/SessionManager.d.ts +1 -1
- package/dist/cjs/core/SessionManager.d.ts.map +1 -1
- package/dist/cjs/core/SessionManager.js +18 -7
- package/dist/cjs/core/SessionManager.js.map +1 -1
- package/dist/cjs/core/SignalCoordinator.d.ts +103 -0
- package/dist/cjs/core/SignalCoordinator.d.ts.map +1 -0
- package/dist/cjs/core/SignalCoordinator.js +207 -0
- package/dist/cjs/core/SignalCoordinator.js.map +1 -0
- package/dist/cjs/core/SignalEvaluator.d.ts +2 -2
- package/dist/cjs/core/SignalEvaluator.d.ts.map +1 -1
- package/dist/cjs/core/SignalEvaluator.js +11 -26
- package/dist/cjs/core/SignalEvaluator.js.map +1 -1
- package/dist/cjs/core/Step.d.ts +3 -1
- package/dist/cjs/core/Step.d.ts.map +1 -1
- package/dist/cjs/core/Step.js +10 -3
- package/dist/cjs/core/Step.js.map +1 -1
- package/dist/cjs/core/StepLifecycle.d.ts +33 -0
- package/dist/cjs/core/StepLifecycle.d.ts.map +1 -0
- package/dist/cjs/core/StepLifecycle.js +97 -0
- package/dist/cjs/core/StepLifecycle.js.map +1 -0
- package/dist/cjs/core/ToolLoopExecutor.d.ts +104 -0
- package/dist/cjs/core/ToolLoopExecutor.d.ts.map +1 -0
- package/dist/cjs/core/ToolLoopExecutor.js +391 -0
- package/dist/cjs/core/ToolLoopExecutor.js.map +1 -0
- package/dist/cjs/core/ToolManager.d.ts +1 -1
- package/dist/cjs/core/ToolManager.d.ts.map +1 -1
- package/dist/cjs/core/ToolManager.js.map +1 -1
- package/dist/cjs/index.d.ts +4 -5
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +7 -6
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.d.ts +2 -0
- package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.js +28 -56
- package/dist/cjs/providers/AnthropicProvider.js.map +1 -1
- package/dist/cjs/providers/DeepSeekProvider.d.ts +25 -21
- package/dist/cjs/providers/DeepSeekProvider.d.ts.map +1 -1
- package/dist/cjs/providers/DeepSeekProvider.js +48 -407
- package/dist/cjs/providers/DeepSeekProvider.js.map +1 -1
- package/dist/cjs/providers/GeminiProvider.d.ts +2 -0
- package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/cjs/providers/GeminiProvider.js +27 -56
- package/dist/cjs/providers/GeminiProvider.js.map +1 -1
- package/dist/cjs/providers/OpenAICompatibleProvider.d.ts +129 -0
- package/dist/cjs/providers/OpenAICompatibleProvider.d.ts.map +1 -0
- package/dist/cjs/providers/OpenAICompatibleProvider.js +485 -0
- package/dist/cjs/providers/OpenAICompatibleProvider.js.map +1 -0
- package/dist/cjs/providers/OpenAIProvider.d.ts +9 -28
- package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.js +23 -417
- package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.d.ts +10 -27
- package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.js +28 -417
- package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
- package/dist/cjs/providers/errorClassification.d.ts +61 -0
- package/dist/cjs/providers/errorClassification.d.ts.map +1 -0
- package/dist/cjs/providers/errorClassification.js +123 -0
- package/dist/cjs/providers/errorClassification.js.map +1 -0
- package/dist/cjs/providers/index.d.ts +4 -0
- package/dist/cjs/providers/index.d.ts.map +1 -1
- package/dist/cjs/providers/index.js +7 -1
- package/dist/cjs/providers/index.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +2 -1
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/ai.d.ts +20 -0
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/cjs/types/errors.d.ts +33 -0
- package/dist/cjs/types/errors.d.ts.map +1 -1
- package/dist/cjs/types/errors.js +37 -1
- package/dist/cjs/types/errors.js.map +1 -1
- package/dist/cjs/types/flow.d.ts +10 -5
- package/dist/cjs/types/flow.d.ts.map +1 -1
- package/dist/cjs/types/history.d.ts +1 -1
- package/dist/cjs/types/history.d.ts.map +1 -1
- package/dist/cjs/types/index.d.ts +5 -4
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js +3 -1
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/persistence.d.ts +43 -2
- package/dist/cjs/types/persistence.d.ts.map +1 -1
- package/dist/cjs/types/session.d.ts +8 -0
- package/dist/cjs/types/session.d.ts.map +1 -1
- package/dist/cjs/types/signals.d.ts +12 -2
- package/dist/cjs/types/signals.d.ts.map +1 -1
- package/dist/cjs/types/template.d.ts +3 -1
- package/dist/cjs/types/template.d.ts.map +1 -1
- package/dist/cjs/types/tool.d.ts +4 -4
- package/dist/cjs/types/tool.d.ts.map +1 -1
- package/dist/cjs/utils/condition.d.ts +19 -0
- package/dist/cjs/utils/condition.d.ts.map +1 -1
- package/dist/cjs/utils/condition.js +86 -15
- package/dist/cjs/utils/condition.js.map +1 -1
- package/dist/cjs/utils/session.d.ts +1 -0
- package/dist/cjs/utils/session.d.ts.map +1 -1
- package/dist/cjs/utils/session.js +1 -0
- package/dist/cjs/utils/session.js.map +1 -1
- package/dist/core/Agent.d.ts +28 -18
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +58 -68
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/AutoChainExecutor.d.ts.map +1 -1
- package/dist/core/AutoChainExecutor.js +14 -20
- package/dist/core/AutoChainExecutor.js.map +1 -1
- package/dist/core/BranchEvaluator.d.ts +4 -3
- package/dist/core/BranchEvaluator.d.ts.map +1 -1
- package/dist/core/BranchEvaluator.js +18 -23
- package/dist/core/BranchEvaluator.js.map +1 -1
- package/dist/core/Flow.d.ts +2 -1
- package/dist/core/Flow.d.ts.map +1 -1
- package/dist/core/Flow.js +10 -3
- package/dist/core/Flow.js.map +1 -1
- package/dist/core/FlowRouter.d.ts +1 -0
- package/dist/core/FlowRouter.d.ts.map +1 -1
- package/dist/core/FlowRouter.js +28 -5
- package/dist/core/FlowRouter.js.map +1 -1
- package/dist/core/PersistenceManager.d.ts +3 -0
- package/dist/core/PersistenceManager.d.ts.map +1 -1
- package/dist/core/PersistenceManager.js +58 -6
- package/dist/core/PersistenceManager.js.map +1 -1
- package/dist/core/PromptComposer.d.ts.map +1 -1
- package/dist/core/PromptComposer.js +24 -10
- package/dist/core/PromptComposer.js.map +1 -1
- package/dist/core/ResponseGenerationError.d.ts +30 -0
- package/dist/core/ResponseGenerationError.d.ts.map +1 -0
- package/dist/core/ResponseGenerationError.js +33 -0
- package/dist/core/ResponseGenerationError.js.map +1 -0
- package/dist/core/ResponseModal.d.ts +43 -102
- package/dist/core/ResponseModal.d.ts.map +1 -1
- package/dist/core/ResponseModal.js +171 -1186
- package/dist/core/ResponseModal.js.map +1 -1
- package/dist/core/ResponsePipeline.d.ts +58 -152
- package/dist/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/core/ResponsePipeline.js +409 -458
- package/dist/core/ResponsePipeline.js.map +1 -1
- package/dist/core/SessionFinalizer.d.ts +34 -0
- package/dist/core/SessionFinalizer.d.ts.map +1 -0
- package/dist/core/SessionFinalizer.js +57 -0
- package/dist/core/SessionFinalizer.js.map +1 -0
- package/dist/core/SessionManager.d.ts +1 -1
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +18 -7
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/SignalCoordinator.d.ts +103 -0
- package/dist/core/SignalCoordinator.d.ts.map +1 -0
- package/dist/core/SignalCoordinator.js +203 -0
- package/dist/core/SignalCoordinator.js.map +1 -0
- package/dist/core/SignalEvaluator.d.ts +2 -2
- package/dist/core/SignalEvaluator.d.ts.map +1 -1
- package/dist/core/SignalEvaluator.js +11 -26
- package/dist/core/SignalEvaluator.js.map +1 -1
- package/dist/core/Step.d.ts +3 -1
- package/dist/core/Step.d.ts.map +1 -1
- package/dist/core/Step.js +10 -3
- package/dist/core/Step.js.map +1 -1
- package/dist/core/StepLifecycle.d.ts +33 -0
- package/dist/core/StepLifecycle.d.ts.map +1 -0
- package/dist/core/StepLifecycle.js +93 -0
- package/dist/core/StepLifecycle.js.map +1 -0
- package/dist/core/ToolLoopExecutor.d.ts +104 -0
- package/dist/core/ToolLoopExecutor.d.ts.map +1 -0
- package/dist/core/ToolLoopExecutor.js +387 -0
- package/dist/core/ToolLoopExecutor.js.map +1 -0
- package/dist/core/ToolManager.d.ts +1 -1
- package/dist/core/ToolManager.d.ts.map +1 -1
- package/dist/core/ToolManager.js.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/providers/AnthropicProvider.d.ts +2 -0
- package/dist/providers/AnthropicProvider.d.ts.map +1 -1
- package/dist/providers/AnthropicProvider.js +22 -50
- package/dist/providers/AnthropicProvider.js.map +1 -1
- package/dist/providers/DeepSeekProvider.d.ts +25 -21
- package/dist/providers/DeepSeekProvider.d.ts.map +1 -1
- package/dist/providers/DeepSeekProvider.js +49 -408
- package/dist/providers/DeepSeekProvider.js.map +1 -1
- package/dist/providers/GeminiProvider.d.ts +2 -0
- package/dist/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/providers/GeminiProvider.js +21 -50
- package/dist/providers/GeminiProvider.js.map +1 -1
- package/dist/providers/OpenAICompatibleProvider.d.ts +129 -0
- package/dist/providers/OpenAICompatibleProvider.d.ts.map +1 -0
- package/dist/providers/OpenAICompatibleProvider.js +481 -0
- package/dist/providers/OpenAICompatibleProvider.js.map +1 -0
- package/dist/providers/OpenAIProvider.d.ts +9 -28
- package/dist/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/OpenAIProvider.js +23 -417
- package/dist/providers/OpenAIProvider.js.map +1 -1
- package/dist/providers/OpenRouterProvider.d.ts +10 -27
- package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/providers/OpenRouterProvider.js +28 -417
- package/dist/providers/OpenRouterProvider.js.map +1 -1
- package/dist/providers/errorClassification.d.ts +61 -0
- package/dist/providers/errorClassification.d.ts.map +1 -0
- package/dist/providers/errorClassification.js +116 -0
- package/dist/providers/errorClassification.js.map +1 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +2 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/types/agent.d.ts +2 -1
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/ai.d.ts +20 -0
- package/dist/types/ai.d.ts.map +1 -1
- package/dist/types/errors.d.ts +33 -0
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/errors.js +34 -0
- package/dist/types/errors.js.map +1 -1
- package/dist/types/flow.d.ts +10 -5
- package/dist/types/flow.d.ts.map +1 -1
- package/dist/types/history.d.ts +1 -1
- package/dist/types/history.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/persistence.d.ts +43 -2
- package/dist/types/persistence.d.ts.map +1 -1
- package/dist/types/session.d.ts +8 -0
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/signals.d.ts +12 -2
- package/dist/types/signals.d.ts.map +1 -1
- package/dist/types/template.d.ts +3 -1
- package/dist/types/template.d.ts.map +1 -1
- package/dist/types/tool.d.ts +4 -4
- package/dist/types/tool.d.ts.map +1 -1
- package/dist/utils/condition.d.ts +19 -0
- package/dist/utils/condition.d.ts.map +1 -1
- package/dist/utils/condition.js +84 -15
- package/dist/utils/condition.js.map +1 -1
- package/dist/utils/session.d.ts +1 -0
- package/dist/utils/session.d.ts.map +1 -1
- package/dist/utils/session.js +1 -0
- package/dist/utils/session.js.map +1 -1
- package/docs/README.md +1 -1
- package/docs/guides/branching.md +1 -1
- package/docs/guides/compaction.md +12 -5
- package/docs/guides/conditions.md +15 -2
- package/docs/guides/error-handling.md +59 -9
- package/docs/guides/instructions.md +2 -2
- package/docs/guides/persistence.md +69 -2
- package/docs/guides/streaming.md +2 -0
- package/docs/migration/README.md +5 -1
- package/docs/migration/v2-3-to-v2-4.md +316 -0
- package/docs/reference/adapters.md +55 -7
- package/docs/reference/branches.md +2 -2
- package/docs/reference/create-agent.md +3 -3
- package/docs/reference/errors.md +66 -1
- package/docs/reference/flow.md +1 -1
- package/docs/reference/instruction.md +4 -4
- package/docs/reference/providers.md +100 -3
- package/docs/reference/signals.md +11 -3
- package/docs/reference/step.md +2 -2
- package/docs/reference/tool.md +3 -1
- package/docs/start/05-go-to-production.md +3 -0
- package/package.json +1 -1
- package/src/adapters/MemoryAdapter.ts +15 -1
- package/src/adapters/MongoAdapter.ts +41 -2
- package/src/adapters/OpenSearchAdapter.ts +24 -1
- package/src/adapters/PostgreSQLAdapter.ts +45 -5
- package/src/adapters/PrismaAdapter.ts +82 -16
- package/src/adapters/RedisAdapter.ts +19 -1
- package/src/adapters/SQLiteAdapter.ts +47 -5
- package/src/core/Agent.ts +70 -85
- package/src/core/AutoChainExecutor.ts +27 -57
- package/src/core/BranchEvaluator.ts +24 -30
- package/src/core/Flow.ts +10 -3
- package/src/core/FlowRouter.ts +36 -4
- package/src/core/PersistenceManager.ts +79 -10
- package/src/core/PromptComposer.ts +25 -12
- package/src/core/ResponseGenerationError.ts +56 -0
- package/src/core/ResponseModal.ts +233 -1482
- package/src/core/ResponsePipeline.ts +492 -662
- package/src/core/SessionFinalizer.ts +78 -0
- package/src/core/SessionManager.ts +21 -9
- package/src/core/SignalCoordinator.ts +263 -0
- package/src/core/SignalEvaluator.ts +12 -29
- package/src/core/Step.ts +11 -3
- package/src/core/StepLifecycle.ts +139 -0
- package/src/core/ToolLoopExecutor.ts +492 -0
- package/src/core/ToolManager.ts +2 -1
- package/src/index.ts +7 -5
- package/src/providers/AnthropicProvider.ts +30 -72
- package/src/providers/DeepSeekProvider.ts +74 -586
- package/src/providers/GeminiProvider.ts +29 -70
- package/src/providers/OpenAICompatibleProvider.ts +738 -0
- package/src/providers/OpenAIProvider.ts +29 -602
- package/src/providers/OpenRouterProvider.ts +38 -596
- package/src/providers/errorClassification.ts +172 -0
- package/src/providers/index.ts +13 -0
- package/src/types/agent.ts +2 -1
- package/src/types/ai.ts +22 -0
- package/src/types/errors.ts +57 -0
- package/src/types/flow.ts +10 -5
- package/src/types/history.ts +1 -2
- package/src/types/index.ts +5 -1
- package/src/types/persistence.ts +50 -2
- package/src/types/session.ts +9 -0
- package/src/types/signals.ts +14 -2
- package/src/types/template.ts +3 -1
- package/src/types/tool.ts +10 -10
- package/src/utils/condition.ts +115 -18
- package/src/utils/session.ts +2 -0
|
@@ -4,41 +4,17 @@
|
|
|
4
4
|
* Provides both streaming and non-streaming response generation with unified logic
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.ResponseModal =
|
|
7
|
+
exports.ResponseModal = void 0;
|
|
8
8
|
const ResponseEngine_1 = require("./ResponseEngine");
|
|
9
9
|
const ResponsePipeline_1 = require("./ResponsePipeline");
|
|
10
10
|
const AutoChainExecutor_1 = require("./AutoChainExecutor");
|
|
11
|
+
const StepLifecycle_1 = require("./StepLifecycle");
|
|
12
|
+
const SessionFinalizer_1 = require("./SessionFinalizer");
|
|
13
|
+
const ToolLoopExecutor_1 = require("./ToolLoopExecutor");
|
|
14
|
+
const SignalCoordinator_1 = require("./SignalCoordinator");
|
|
15
|
+
const ResponseGenerationError_1 = require("./ResponseGenerationError");
|
|
11
16
|
const utils_1 = require("../utils");
|
|
12
17
|
const template_1 = require("../utils/template");
|
|
13
|
-
/**
|
|
14
|
-
* Error class for response generation failures
|
|
15
|
-
*/
|
|
16
|
-
class ResponseGenerationError extends Error {
|
|
17
|
-
constructor(message, details) {
|
|
18
|
-
super(message);
|
|
19
|
-
this.details = details;
|
|
20
|
-
this.name = 'ResponseGenerationError';
|
|
21
|
-
// Preserve stack trace from original error if available
|
|
22
|
-
if (details?.originalError instanceof Error && details.originalError.stack) {
|
|
23
|
-
this.stack = `${this.stack}\nCaused by: ${details.originalError.stack}`;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Create a ResponseGenerationError from an unknown error
|
|
28
|
-
*/
|
|
29
|
-
static fromError(error, phase, params, context) {
|
|
30
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
31
|
-
return new ResponseGenerationError(`[ResponseGenerationError] Response generation failed in ${phase}: ${message}. ` +
|
|
32
|
-
`Check provider configuration and the ${phase} phase handler.`, { originalError: error, params, phase, context });
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Check if an error is a ResponseGenerationError
|
|
36
|
-
*/
|
|
37
|
-
static isResponseGenerationError(error) {
|
|
38
|
-
return error instanceof ResponseGenerationError;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
exports.ResponseGenerationError = ResponseGenerationError;
|
|
42
18
|
/**
|
|
43
19
|
* ResponseModal class that encapsulates all response generation logic
|
|
44
20
|
* Uses unified approach for both streaming and non-streaming responses
|
|
@@ -49,25 +25,65 @@ class ResponseModal {
|
|
|
49
25
|
this.options = options;
|
|
50
26
|
// Initialize response engine
|
|
51
27
|
this.responseEngine = new ResponseEngine_1.ResponseEngine(this.agent.promptSectionCache);
|
|
28
|
+
// Signal pre/post phase orchestration
|
|
29
|
+
this.signalCoordinator = new SignalCoordinator_1.SignalCoordinator({
|
|
30
|
+
getFlows: () => this.agent.getFlows(),
|
|
31
|
+
signalProcessor: this.agent.signalProcessor,
|
|
32
|
+
});
|
|
52
33
|
// Initialize response pipeline with agent dependencies
|
|
53
34
|
this.responsePipeline = new ResponsePipeline_1.ResponsePipeline(this.agent.getAgentOptions(), () => this.agent.getFlows(), // Pass a function to get flows dynamically
|
|
54
|
-
this.agent.
|
|
35
|
+
this.agent.getFlowRouter(), this.signalCoordinator, this.agent.updateCollectedData.bind(this.agent), () => this.agent.schema);
|
|
36
|
+
// Step prepare/finalize execution, shared by the prepare phase and finalizer
|
|
37
|
+
this.stepLifecycle = new StepLifecycle_1.StepLifecycle({
|
|
38
|
+
getFlows: () => this.agent.getFlows(),
|
|
39
|
+
toolManager: this.getToolManager(),
|
|
40
|
+
updateContext: this.agent.updateContext.bind(this.agent),
|
|
41
|
+
updateData: this.agent.updateCollectedData.bind(this.agent),
|
|
42
|
+
});
|
|
43
|
+
// Single owner of end-of-turn finalization (compaction + persistence + sync)
|
|
44
|
+
this.sessionFinalizer = new SessionFinalizer_1.SessionFinalizer({
|
|
45
|
+
getCompactionOptions: () => this.agent.getCompactionOptions(),
|
|
46
|
+
getPersistenceManager: () => this.agent.getPersistenceManager(),
|
|
47
|
+
getAgentOptions: () => this.agent.getAgentOptions(),
|
|
48
|
+
getCurrentSession: () => this.agent.currentSession,
|
|
49
|
+
setCurrentSession: (session) => { this.agent.currentSession = session; },
|
|
50
|
+
stepLifecycle: this.stepLifecycle,
|
|
51
|
+
enableAutoSave: this.options?.enableAutoSave,
|
|
52
|
+
});
|
|
53
|
+
// Tool follow-up loop (run tools, ask the LLM again) + streaming batch execution
|
|
54
|
+
this.toolLoopExecutor = new ToolLoopExecutor_1.ToolLoopExecutor({
|
|
55
|
+
toolManager: this.getToolManager(),
|
|
56
|
+
getAgentOptions: () => this.agent.getAgentOptions(),
|
|
57
|
+
updateContext: this.agent.updateContext.bind(this.agent),
|
|
58
|
+
updateCollectedData: this.agent.updateCollectedData.bind(this.agent),
|
|
59
|
+
updateSessionData: this.agent.getUpdateDataMethod(),
|
|
60
|
+
maxToolLoops: this.options?.maxToolLoops,
|
|
61
|
+
});
|
|
55
62
|
}
|
|
56
63
|
/**
|
|
57
64
|
* Generate a non-streaming response using unified logic
|
|
58
65
|
*/
|
|
59
66
|
async respond(params) {
|
|
67
|
+
// Snapshot the managed session so a failed turn has no in-memory effect:
|
|
68
|
+
// without this, mutations made before the failure leave the live session
|
|
69
|
+
// diverged from persisted state
|
|
70
|
+
const preTurnSession = this.agent.session.current
|
|
71
|
+
? (0, utils_1.cloneDeep)(this.agent.session.current)
|
|
72
|
+
: undefined;
|
|
60
73
|
try {
|
|
61
74
|
// Use unified response preparation and routing
|
|
62
75
|
const responseContext = await this.prepareUnifiedResponseContext(params);
|
|
63
76
|
// Generate response using unified logic
|
|
64
77
|
const result = await this.generateUnifiedResponse(responseContext);
|
|
65
|
-
// Finalize session
|
|
66
|
-
await this.
|
|
78
|
+
// Finalize session — the non-streaming turn's single finalize
|
|
79
|
+
await this.sessionFinalizer.finalize(result.session, responseContext.effectiveContext);
|
|
67
80
|
return result;
|
|
68
81
|
}
|
|
69
82
|
catch (error) {
|
|
70
|
-
|
|
83
|
+
if (preTurnSession) {
|
|
84
|
+
this.agent.session.syncSession(preTurnSession);
|
|
85
|
+
}
|
|
86
|
+
throw new ResponseGenerationError_1.ResponseGenerationError(`[ResponseGenerationError] Response generation failed: ${error instanceof Error ? error.message : String(error)}. ` +
|
|
71
87
|
`Check provider configuration and network connectivity.`, { originalError: error, params, phase: 'response_generation' });
|
|
72
88
|
}
|
|
73
89
|
}
|
|
@@ -75,6 +91,10 @@ class ResponseModal {
|
|
|
75
91
|
* Generate a streaming response using unified logic
|
|
76
92
|
*/
|
|
77
93
|
async *respondStream(params) {
|
|
94
|
+
// Same failed-turn rollback semantics as respond()
|
|
95
|
+
const preTurnSession = this.agent.session.current
|
|
96
|
+
? (0, utils_1.cloneDeep)(this.agent.session.current)
|
|
97
|
+
: undefined;
|
|
78
98
|
try {
|
|
79
99
|
// Use unified response preparation and routing
|
|
80
100
|
const responseContext = await this.prepareUnifiedResponseContext(params);
|
|
@@ -82,13 +102,16 @@ class ResponseModal {
|
|
|
82
102
|
yield* this.generateUnifiedStreamingResponse(responseContext);
|
|
83
103
|
}
|
|
84
104
|
catch (error) {
|
|
105
|
+
if (preTurnSession) {
|
|
106
|
+
this.agent.session.syncSession(preTurnSession);
|
|
107
|
+
}
|
|
85
108
|
// Stream error to caller
|
|
86
109
|
yield {
|
|
87
110
|
delta: "",
|
|
88
111
|
accumulated: "",
|
|
89
112
|
done: true,
|
|
90
113
|
session: params.session || await this.agent.session.getOrCreate(),
|
|
91
|
-
error: new ResponseGenerationError(`Streaming response failed: ${error instanceof Error ? error.message : String(error)}`, { originalError: error, params, phase: 'streaming' }),
|
|
114
|
+
error: new ResponseGenerationError_1.ResponseGenerationError(`Streaming response failed: ${error instanceof Error ? error.message : String(error)}`, { originalError: error, params, phase: 'streaming' }),
|
|
92
115
|
};
|
|
93
116
|
}
|
|
94
117
|
}
|
|
@@ -109,16 +132,9 @@ class ResponseModal {
|
|
|
109
132
|
}
|
|
110
133
|
history = this.agent.session.getHistory();
|
|
111
134
|
}
|
|
112
|
-
// Get or create session
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const collectedData = this.agent.getCollectedData();
|
|
116
|
-
if (Object.keys(collectedData).length > 0) {
|
|
117
|
-
session = (0, utils_1.mergeCollected)(session, collectedData);
|
|
118
|
-
// Update the session manager with the merged data
|
|
119
|
-
await this.agent.session.setData(collectedData);
|
|
120
|
-
utils_1.logger.debug("[ResponseModal] Merged agent collected data into stream session:", collectedData);
|
|
121
|
-
}
|
|
135
|
+
// Get or create session — session.data is the single source of truth,
|
|
136
|
+
// so no agent-side data merge is needed
|
|
137
|
+
const session = await this.agent.session.getOrCreate();
|
|
122
138
|
// Stream response using existing respondStream method
|
|
123
139
|
let finalMessage = "";
|
|
124
140
|
let finalizedSession;
|
|
@@ -162,16 +178,9 @@ class ResponseModal {
|
|
|
162
178
|
}
|
|
163
179
|
history = this.agent.session.getHistory();
|
|
164
180
|
}
|
|
165
|
-
// Get or create session
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const collectedData = this.agent.getCollectedData();
|
|
169
|
-
if (Object.keys(collectedData).length > 0) {
|
|
170
|
-
session = (0, utils_1.mergeCollected)(session, collectedData);
|
|
171
|
-
// Update the session manager with the merged data
|
|
172
|
-
await this.agent.session.setData(collectedData);
|
|
173
|
-
utils_1.logger.debug("[ResponseModal] Merged agent collected data into generate session:", collectedData);
|
|
174
|
-
}
|
|
181
|
+
// Get or create session — session.data is the single source of truth,
|
|
182
|
+
// so no agent-side data merge is needed
|
|
183
|
+
const session = await this.agent.session.getOrCreate();
|
|
175
184
|
// Generate response using existing respond method
|
|
176
185
|
const result = await this.respond({
|
|
177
186
|
history,
|
|
@@ -215,14 +224,6 @@ class ResponseModal {
|
|
|
215
224
|
getToolManager() {
|
|
216
225
|
return this.agent.tool;
|
|
217
226
|
}
|
|
218
|
-
/**
|
|
219
|
-
* Post-phase signal replies replace the user-visible message after the
|
|
220
|
-
* response has otherwise completed. Undefined means "leave it unchanged";
|
|
221
|
-
* an empty string is an explicit replacement.
|
|
222
|
-
*/
|
|
223
|
-
applyPostSignalReply(message, directive) {
|
|
224
|
-
return directive?.reply !== undefined ? directive.reply : message;
|
|
225
|
-
}
|
|
226
227
|
/**
|
|
227
228
|
* Collect scoped instructions from agent, flow, and step into a ScopedInstructions value.
|
|
228
229
|
* @private
|
|
@@ -246,63 +247,64 @@ class ResponseModal {
|
|
|
246
247
|
const { history: simpleHistory, contextOverride, signal } = params;
|
|
247
248
|
// Validate input parameters
|
|
248
249
|
if (!simpleHistory) {
|
|
249
|
-
throw new ResponseGenerationError('[ResponseGenerationError] Missing history: history is required for response generation. ' +
|
|
250
|
+
throw new ResponseGenerationError_1.ResponseGenerationError('[ResponseGenerationError] Missing history: history is required for response generation. ' +
|
|
250
251
|
'Pass a valid history array to the respond/stream method.', { params, phase: 'validation' });
|
|
251
252
|
}
|
|
252
253
|
// Convert HistoryItem[] to Event[] for internal processing
|
|
253
254
|
const historyEvents = (0, utils_1.historyToEvents)(simpleHistory);
|
|
254
255
|
// Keep original HistoryItem[] format for external APIs
|
|
255
256
|
const history = simpleHistory;
|
|
256
|
-
// Use ResponsePipeline for
|
|
257
|
-
//
|
|
257
|
+
// Use ResponsePipeline for context and session preparation; context
|
|
258
|
+
// and session are passed explicitly — the pipeline holds no state
|
|
258
259
|
let responseContext;
|
|
259
260
|
try {
|
|
260
|
-
// Set current context and session in pipeline for consistency
|
|
261
|
-
this.responsePipeline.setContext(await this.agent.getContext());
|
|
262
|
-
this.responsePipeline.setCurrentSession(this.agent.currentSession);
|
|
263
261
|
responseContext = await this.responsePipeline.prepareResponseContext({
|
|
264
262
|
contextOverride,
|
|
265
263
|
session: params.session ? (0, utils_1.cloneDeep)(params.session) : undefined,
|
|
264
|
+
currentContext: await this.agent.getContext(),
|
|
265
|
+
currentSession: this.agent.currentSession,
|
|
266
266
|
});
|
|
267
267
|
}
|
|
268
268
|
catch (error) {
|
|
269
|
-
throw ResponseGenerationError.fromError(error, 'pipeline_context_preparation', params);
|
|
269
|
+
throw ResponseGenerationError_1.ResponseGenerationError.fromError(error, 'pipeline_context_preparation', params);
|
|
270
270
|
}
|
|
271
|
-
const { effectiveContext } = responseContext;
|
|
271
|
+
const { effectiveContext, contextAfterHook } = responseContext;
|
|
272
272
|
let session = responseContext.session;
|
|
273
|
-
//
|
|
274
|
-
|
|
275
|
-
if (storedContext !== undefined) {
|
|
273
|
+
// Sync the beforeRespond hook's context result back to the agent
|
|
274
|
+
if (contextAfterHook !== undefined) {
|
|
276
275
|
try {
|
|
277
|
-
await this.agent.updateContext(
|
|
276
|
+
await this.agent.updateContext(contextAfterHook);
|
|
278
277
|
}
|
|
279
278
|
catch (error) {
|
|
280
|
-
throw ResponseGenerationError.fromError(error, 'context_update_from_pipeline', params, {
|
|
279
|
+
throw ResponseGenerationError_1.ResponseGenerationError.fromError(error, 'context_update_from_pipeline', params, { contextAfterHook });
|
|
281
280
|
}
|
|
282
281
|
}
|
|
283
|
-
//
|
|
284
|
-
|
|
285
|
-
|
|
282
|
+
// Apply data staged before any session existed (initialData,
|
|
283
|
+
// pre-session updateCollectedData calls). Reading the live session's
|
|
284
|
+
// data here would leak state across sessions when an explicit
|
|
285
|
+
// session is passed, so only the staging buffer is merged.
|
|
286
|
+
const stagedData = this.agent.consumePendingData();
|
|
287
|
+
if (Object.keys(stagedData).length > 0) {
|
|
286
288
|
try {
|
|
287
|
-
session = (0, utils_1.mergeCollected)(session,
|
|
288
|
-
utils_1.logger.debug("[ResponseModal] Merged agent
|
|
289
|
+
session = (0, utils_1.mergeCollected)(session, stagedData);
|
|
290
|
+
utils_1.logger.debug("[ResponseModal] Merged staged agent data into session:", stagedData);
|
|
289
291
|
}
|
|
290
292
|
catch (error) {
|
|
291
|
-
throw ResponseGenerationError.fromError(error, 'data_merging', params, {
|
|
293
|
+
throw ResponseGenerationError_1.ResponseGenerationError.fromError(error, 'data_merging', params, { stagedData });
|
|
292
294
|
}
|
|
293
295
|
}
|
|
294
296
|
// PHASE 1: PREPARE - Execute prepare function if current step has one
|
|
295
297
|
try {
|
|
296
|
-
await this.
|
|
298
|
+
await this.stepLifecycle.runPrepare(session, effectiveContext);
|
|
297
299
|
}
|
|
298
300
|
catch (error) {
|
|
299
|
-
throw ResponseGenerationError.fromError(error, 'step_preparation', params, { session, effectiveContext });
|
|
301
|
+
throw ResponseGenerationError_1.ResponseGenerationError.fromError(error, 'step_preparation', params, { session, effectiveContext });
|
|
300
302
|
}
|
|
301
303
|
// PHASE 2: ROUTING + STEP SELECTION - Determine which flow and step to use
|
|
302
304
|
// Performs pre-extraction and step selection
|
|
303
305
|
let routingResult;
|
|
304
306
|
try {
|
|
305
|
-
routingResult = await this.
|
|
307
|
+
routingResult = await this.responsePipeline.routeAndSelectStep({
|
|
306
308
|
session,
|
|
307
309
|
history: historyEvents,
|
|
308
310
|
context: effectiveContext,
|
|
@@ -310,7 +312,7 @@ class ResponseModal {
|
|
|
310
312
|
});
|
|
311
313
|
}
|
|
312
314
|
catch (error) {
|
|
313
|
-
throw ResponseGenerationError.fromError(error, 'routing_and_step_selection', params, { session, effectiveContext });
|
|
315
|
+
throw ResponseGenerationError_1.ResponseGenerationError.fromError(error, 'routing_and_step_selection', params, { session, effectiveContext });
|
|
314
316
|
}
|
|
315
317
|
return {
|
|
316
318
|
effectiveContext,
|
|
@@ -329,447 +331,10 @@ class ResponseModal {
|
|
|
329
331
|
}
|
|
330
332
|
catch (error) {
|
|
331
333
|
// Re-throw ResponseGenerationError as-is, wrap others
|
|
332
|
-
if (ResponseGenerationError.isResponseGenerationError(error)) {
|
|
334
|
+
if (ResponseGenerationError_1.ResponseGenerationError.isResponseGenerationError(error)) {
|
|
333
335
|
throw error;
|
|
334
336
|
}
|
|
335
|
-
throw ResponseGenerationError.fromError(error, 'preparation', params);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
/**
|
|
339
|
-
* Unified routing and step selection logic using ResponsePipeline for optimization
|
|
340
|
-
* @private
|
|
341
|
-
*/
|
|
342
|
-
async handleUnifiedRoutingAndStepSelection(params) {
|
|
343
|
-
try {
|
|
344
|
-
// Create a fresh chain tracker for this turn (Requirement 22.1)
|
|
345
|
-
this.responsePipeline.createChainTracker();
|
|
346
|
-
// ROUTING SKIP OPTIMIZATION (Requirements 20.1, 20.2, 20.3):
|
|
347
|
-
// When the current step has collect fields AND pre-extraction populates at least
|
|
348
|
-
// one of those fields, skip FlowRouter.decideFlowAndStep for this turn.
|
|
349
|
-
const routingSkipResult = await this.attemptRoutingSkipForCollect(params);
|
|
350
|
-
if (routingSkipResult) {
|
|
351
|
-
// Even when routing is skipped, run pre-signal phase if processor is present
|
|
352
|
-
if (this.agent.signalProcessor) {
|
|
353
|
-
const signalResult = await this.responsePipeline.runPreSignalPhase(params.session, params.context, params.history);
|
|
354
|
-
// If signal halts, override the routing skip result
|
|
355
|
-
if (signalResult.mergedDirective?.halt) {
|
|
356
|
-
return {
|
|
357
|
-
...routingSkipResult,
|
|
358
|
-
session: signalResult.updatedSession,
|
|
359
|
-
signalFirings: signalResult.firings,
|
|
360
|
-
signalHalted: true,
|
|
361
|
-
signalHaltReply: signalResult.mergedDirective.reply,
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
// If signal has position fields, override routing skip result
|
|
365
|
-
if ((0, ResponsePipeline_1.hasDirectivePositionField)(signalResult.mergedDirective)) {
|
|
366
|
-
return this.applySignalPositionDirective(signalResult, params);
|
|
367
|
-
}
|
|
368
|
-
// Non-position directive: propagate for pre-LLM augmentation
|
|
369
|
-
return {
|
|
370
|
-
...routingSkipResult,
|
|
371
|
-
session: signalResult.updatedSession,
|
|
372
|
-
signalFirings: signalResult.firings,
|
|
373
|
-
signalPreDirective: signalResult.mergedDirective || undefined,
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
return routingSkipResult;
|
|
377
|
-
}
|
|
378
|
-
// ── PARALLEL PRE-SIGNAL PHASE + ROUTING (Algorithm 5) ────────────────
|
|
379
|
-
// When signalProcessor is present, run pre-signals in parallel with routing.
|
|
380
|
-
// When absent, call the router directly (zero overhead, preserve current behavior).
|
|
381
|
-
if (this.agent.signalProcessor) {
|
|
382
|
-
// Run pre-signal phase in parallel with routing (Requirement 8.1)
|
|
383
|
-
const [signalResult, routingResult] = await Promise.all([
|
|
384
|
-
this.responsePipeline.runPreSignalPhase(params.session, params.context, params.history),
|
|
385
|
-
this.responsePipeline.handleRoutingAndStepSelection({
|
|
386
|
-
session: params.session,
|
|
387
|
-
history: params.history,
|
|
388
|
-
context: params.context,
|
|
389
|
-
signal: params.signal,
|
|
390
|
-
}),
|
|
391
|
-
]);
|
|
392
|
-
// ── Requirement 8.2: halt → discard routing, skip LLM ────────────
|
|
393
|
-
if (signalResult.mergedDirective?.halt) {
|
|
394
|
-
return {
|
|
395
|
-
selectedFlow: undefined,
|
|
396
|
-
selectedStep: undefined,
|
|
397
|
-
session: signalResult.updatedSession,
|
|
398
|
-
isFlowComplete: false,
|
|
399
|
-
signalFirings: signalResult.firings,
|
|
400
|
-
signalHalted: true,
|
|
401
|
-
signalHaltReply: signalResult.mergedDirective.reply,
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
// ── Requirement 8.3: position directive → discard routing, apply signal position ──
|
|
405
|
-
if ((0, ResponsePipeline_1.hasDirectivePositionField)(signalResult.mergedDirective)) {
|
|
406
|
-
return this.applySignalPositionDirective(signalResult, params);
|
|
407
|
-
}
|
|
408
|
-
// ── Requirement 8.4: non-position directive → use routing, propagate augmentation ──
|
|
409
|
-
// ── Requirement 8.5: no directive → use routing as-is ─────────────
|
|
410
|
-
let updatedSession = signalResult.updatedSession;
|
|
411
|
-
// Apply data/context updates from signal to the routed session
|
|
412
|
-
if (signalResult.mergedDirective?.dataUpdate) {
|
|
413
|
-
updatedSession = (0, utils_1.mergeCollected)(updatedSession, signalResult.mergedDirective.dataUpdate);
|
|
414
|
-
}
|
|
415
|
-
// Use routing result for flow/step, but carry signal session state
|
|
416
|
-
// Merge routing session changes on top of signal session
|
|
417
|
-
const routingSession = routingResult.session;
|
|
418
|
-
updatedSession = {
|
|
419
|
-
...updatedSession,
|
|
420
|
-
currentFlow: routingSession.currentFlow,
|
|
421
|
-
currentStep: routingSession.currentStep,
|
|
422
|
-
flowHistory: routingSession.flowHistory,
|
|
423
|
-
pendingDirective: routingSession.pendingDirective,
|
|
424
|
-
};
|
|
425
|
-
const isFlowComplete = routingResult.isFlowComplete;
|
|
426
|
-
// PRE-EXTRACTION: same logic as below — extract data from user message
|
|
427
|
-
if (routingResult.selectedFlow && !isFlowComplete) {
|
|
428
|
-
if (this.shouldPreExtractData(routingResult.selectedFlow)) {
|
|
429
|
-
utils_1.logger.debug(`[ResponseModal] Pre-extracting data for flow: ${routingResult.selectedFlow.title}`);
|
|
430
|
-
const extractedData = await this.preExtractFlowData({
|
|
431
|
-
route: routingResult.selectedFlow,
|
|
432
|
-
history: params.history,
|
|
433
|
-
context: params.context,
|
|
434
|
-
session: updatedSession,
|
|
435
|
-
signal: params.signal,
|
|
436
|
-
});
|
|
437
|
-
if (extractedData && Object.keys(extractedData).length > 0) {
|
|
438
|
-
utils_1.logger.debug(`[ResponseModal] Pre-extracted data:`, extractedData);
|
|
439
|
-
updatedSession = (0, utils_1.mergeCollected)(updatedSession, extractedData);
|
|
440
|
-
await this.agent.updateCollectedData(extractedData);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
// Determine next step
|
|
445
|
-
const stepResult = await this.responsePipeline.determineNextStep({
|
|
446
|
-
selectedFlow: routingResult.selectedFlow,
|
|
447
|
-
selectedStep: routingResult.selectedStep,
|
|
448
|
-
session: updatedSession,
|
|
449
|
-
isFlowComplete,
|
|
450
|
-
});
|
|
451
|
-
return {
|
|
452
|
-
selectedFlow: stepResult.flowChanged || routingResult.selectedFlow,
|
|
453
|
-
selectedStep: stepResult.nextStep,
|
|
454
|
-
responseDirectives: routingResult.responseDirectives,
|
|
455
|
-
session: stepResult.session,
|
|
456
|
-
isFlowComplete: stepResult.flowChanged ? false : isFlowComplete,
|
|
457
|
-
signalFirings: signalResult.firings,
|
|
458
|
-
signalPreDirective: signalResult.mergedDirective || undefined,
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
// ── No signal processor: existing behavior (zero overhead) ────────────
|
|
462
|
-
const routingResult = await this.responsePipeline.handleRoutingAndStepSelection({
|
|
463
|
-
session: params.session,
|
|
464
|
-
history: params.history,
|
|
465
|
-
context: params.context,
|
|
466
|
-
signal: params.signal,
|
|
467
|
-
});
|
|
468
|
-
let updatedSession = routingResult.session;
|
|
469
|
-
const isFlowComplete = routingResult.isFlowComplete;
|
|
470
|
-
// PRE-EXTRACTION: If entering a flow that collects data, extract data from user message first
|
|
471
|
-
// This allows us to skip steps whose data is already provided
|
|
472
|
-
if (routingResult.selectedFlow && !isFlowComplete) {
|
|
473
|
-
// Always pre-extract when flow collects data (not just on new flow entry)
|
|
474
|
-
// This ensures step selection has the most up-to-date data
|
|
475
|
-
if (this.shouldPreExtractData(routingResult.selectedFlow)) {
|
|
476
|
-
utils_1.logger.debug(`[ResponseModal] Pre-extracting data for flow: ${routingResult.selectedFlow.title}`);
|
|
477
|
-
const extractedData = await this.preExtractFlowData({
|
|
478
|
-
route: routingResult.selectedFlow,
|
|
479
|
-
history: params.history,
|
|
480
|
-
context: params.context,
|
|
481
|
-
session: updatedSession,
|
|
482
|
-
signal: params.signal,
|
|
483
|
-
});
|
|
484
|
-
if (extractedData && Object.keys(extractedData).length > 0) {
|
|
485
|
-
utils_1.logger.debug(`[ResponseModal] Pre-extracted data:`, extractedData);
|
|
486
|
-
// Merge pre-extracted data into session before step selection
|
|
487
|
-
updatedSession = (0, utils_1.mergeCollected)(updatedSession, extractedData);
|
|
488
|
-
// Also update agent's collected data
|
|
489
|
-
await this.agent.updateCollectedData(extractedData);
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
// Determine next step using pipeline method for consistency
|
|
494
|
-
const stepResult = await this.responsePipeline.determineNextStep({
|
|
495
|
-
selectedFlow: routingResult.selectedFlow,
|
|
496
|
-
selectedStep: routingResult.selectedStep,
|
|
497
|
-
session: updatedSession, // Use updated session with pre-extracted data
|
|
498
|
-
isFlowComplete, // Use updated completion status
|
|
499
|
-
});
|
|
500
|
-
return {
|
|
501
|
-
selectedFlow: stepResult.flowChanged || routingResult.selectedFlow,
|
|
502
|
-
selectedStep: stepResult.nextStep, // Use the determined next step
|
|
503
|
-
responseDirectives: routingResult.responseDirectives,
|
|
504
|
-
session: stepResult.session,
|
|
505
|
-
// If a branch changed the flow, the original isFlowComplete no longer applies
|
|
506
|
-
isFlowComplete: stepResult.flowChanged ? false : isFlowComplete,
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
catch (error) {
|
|
510
|
-
throw ResponseGenerationError.fromError(error, 'routing_optimization', params);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
/**
|
|
514
|
-
* Apply a signal's position directive (goTo, goToStep, complete, abort, reset).
|
|
515
|
-
* Discards routing result and uses the signal's position decision.
|
|
516
|
-
* @private
|
|
517
|
-
* @requirements 8.3
|
|
518
|
-
*/
|
|
519
|
-
applySignalPositionDirective(signalResult, _params) {
|
|
520
|
-
const directive = signalResult.mergedDirective;
|
|
521
|
-
let session = signalResult.updatedSession;
|
|
522
|
-
const flows = this.agent.getFlows();
|
|
523
|
-
let selectedFlow;
|
|
524
|
-
let selectedStep;
|
|
525
|
-
let isFlowComplete = false;
|
|
526
|
-
// Apply data updates if present alongside position
|
|
527
|
-
if (directive.dataUpdate) {
|
|
528
|
-
session = (0, utils_1.mergeCollected)(session, directive.dataUpdate);
|
|
529
|
-
}
|
|
530
|
-
if (directive.goTo) {
|
|
531
|
-
const flowTarget = typeof directive.goTo === 'string'
|
|
532
|
-
? directive.goTo
|
|
533
|
-
: directive.goTo.flow ?? directive.goTo.step;
|
|
534
|
-
if (flowTarget) {
|
|
535
|
-
const targetFlow = flows.find(f => f.id === flowTarget || f.title === flowTarget);
|
|
536
|
-
if (targetFlow) {
|
|
537
|
-
session = (0, utils_1.enterFlow)(session, targetFlow.id, targetFlow.title);
|
|
538
|
-
selectedFlow = targetFlow;
|
|
539
|
-
if (typeof directive.goTo === 'object' && directive.goTo.step) {
|
|
540
|
-
const targetStep = targetFlow.getStep(directive.goTo.step);
|
|
541
|
-
if (targetStep) {
|
|
542
|
-
session = (0, utils_1.enterStep)(session, targetStep.id, targetStep.description);
|
|
543
|
-
selectedStep = targetStep;
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
else {
|
|
548
|
-
utils_1.logger.warn(`[Signals] Pre-phase goTo target not found: "${flowTarget}". Falling back to no flow.`);
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
else if (directive.goToStep) {
|
|
553
|
-
const stepTarget = typeof directive.goToStep === 'string'
|
|
554
|
-
? directive.goToStep
|
|
555
|
-
: directive.goToStep.step;
|
|
556
|
-
const flowTarget = typeof directive.goToStep === 'object'
|
|
557
|
-
? directive.goToStep.flow
|
|
558
|
-
: undefined;
|
|
559
|
-
if (flowTarget) {
|
|
560
|
-
const targetFlow = flows.find(f => f.id === flowTarget || f.title === flowTarget);
|
|
561
|
-
if (targetFlow) {
|
|
562
|
-
session = (0, utils_1.enterFlow)(session, targetFlow.id, targetFlow.title);
|
|
563
|
-
selectedFlow = targetFlow;
|
|
564
|
-
const targetStep = targetFlow.getStep(stepTarget);
|
|
565
|
-
if (targetStep) {
|
|
566
|
-
session = (0, utils_1.enterStep)(session, targetStep.id, targetStep.description);
|
|
567
|
-
selectedStep = targetStep;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
else if (session.currentFlow) {
|
|
572
|
-
const currentFlow = flows.find(f => f.id === session.currentFlow?.id);
|
|
573
|
-
if (currentFlow) {
|
|
574
|
-
selectedFlow = currentFlow;
|
|
575
|
-
const targetStep = currentFlow.getStep(stepTarget);
|
|
576
|
-
if (targetStep) {
|
|
577
|
-
session = (0, utils_1.enterStep)(session, targetStep.id, targetStep.description);
|
|
578
|
-
selectedStep = targetStep;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
else if (directive.complete) {
|
|
584
|
-
isFlowComplete = true;
|
|
585
|
-
}
|
|
586
|
-
else if (directive.abort) {
|
|
587
|
-
// Abort — no flow, session cleared or marked
|
|
588
|
-
isFlowComplete = true;
|
|
589
|
-
}
|
|
590
|
-
else if (directive.reset) {
|
|
591
|
-
if (session.currentFlow) {
|
|
592
|
-
const currentFlow = flows.find(f => f.id === session.currentFlow?.id);
|
|
593
|
-
if (currentFlow) {
|
|
594
|
-
selectedFlow = currentFlow;
|
|
595
|
-
const resetStep = typeof directive.reset === 'object' && directive.reset.step
|
|
596
|
-
? directive.reset.step
|
|
597
|
-
: undefined;
|
|
598
|
-
if (resetStep) {
|
|
599
|
-
const targetStep = currentFlow.getStep(resetStep);
|
|
600
|
-
if (targetStep) {
|
|
601
|
-
session = (0, utils_1.enterStep)(session, targetStep.id, targetStep.description);
|
|
602
|
-
selectedStep = targetStep;
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
else {
|
|
606
|
-
const initialStep = currentFlow.initialStep;
|
|
607
|
-
session = (0, utils_1.enterStep)(session, initialStep.id, initialStep.description);
|
|
608
|
-
selectedStep = initialStep;
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
return {
|
|
614
|
-
selectedFlow,
|
|
615
|
-
selectedStep,
|
|
616
|
-
session,
|
|
617
|
-
isFlowComplete,
|
|
618
|
-
signalFirings: signalResult.firings,
|
|
619
|
-
signalPreDirective: signalResult.mergedDirective || undefined,
|
|
620
|
-
};
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* Routing skip optimization (Requirements 20.1, 20.2, 20.3):
|
|
624
|
-
* When the current step declares `collect` fields AND pre-extraction populates
|
|
625
|
-
* at least one of those fields from the user's message, skip routing for this turn.
|
|
626
|
-
*
|
|
627
|
-
* Returns the routing result if the skip applies, or undefined to fall through
|
|
628
|
-
* to normal routing.
|
|
629
|
-
* @private
|
|
630
|
-
*/
|
|
631
|
-
async attemptRoutingSkipForCollect(params) {
|
|
632
|
-
const { session } = params;
|
|
633
|
-
// Only applies when we already have a current flow and step
|
|
634
|
-
if (!session.currentFlow || !session.currentStep) {
|
|
635
|
-
return undefined;
|
|
636
|
-
}
|
|
637
|
-
// Also skip this optimization if there's a pending directive (it takes priority)
|
|
638
|
-
if (session.pendingDirective) {
|
|
639
|
-
return undefined;
|
|
640
|
-
}
|
|
641
|
-
// Look up the actual Flow and Step objects to access `collect`
|
|
642
|
-
const currentFlow = this.agent.getFlows().find((f) => f.id === session.currentFlow?.id);
|
|
643
|
-
if (!currentFlow) {
|
|
644
|
-
return undefined;
|
|
645
|
-
}
|
|
646
|
-
const currentStep = currentFlow.getStep(session.currentStep.id);
|
|
647
|
-
if (!currentStep || !currentStep.collect || currentStep.collect.length === 0) {
|
|
648
|
-
return undefined;
|
|
649
|
-
}
|
|
650
|
-
// We have a step with collect fields. Run pre-extraction to see if the
|
|
651
|
-
// user's message populates any of them.
|
|
652
|
-
const collectFields = currentStep.collect;
|
|
653
|
-
// Snapshot current data for comparison
|
|
654
|
-
const dataBefore = { ...session.data };
|
|
655
|
-
// Run pre-extraction against the current flow
|
|
656
|
-
const extractedData = await this.preExtractFlowData({
|
|
657
|
-
route: currentFlow,
|
|
658
|
-
history: params.history,
|
|
659
|
-
context: params.context,
|
|
660
|
-
session,
|
|
661
|
-
signal: params.signal,
|
|
662
|
-
});
|
|
663
|
-
if (!extractedData || Object.keys(extractedData).length === 0) {
|
|
664
|
-
return undefined;
|
|
665
|
-
}
|
|
666
|
-
// Determine which collect fields were newly populated by pre-extraction
|
|
667
|
-
const populatedCollectFields = [];
|
|
668
|
-
for (const field of collectFields) {
|
|
669
|
-
const key = field;
|
|
670
|
-
const hadValue = dataBefore[field] !== undefined && dataBefore[field] !== null;
|
|
671
|
-
const hasNewValue = extractedData[field] !== undefined && extractedData[field] !== null;
|
|
672
|
-
if (hasNewValue && !hadValue) {
|
|
673
|
-
populatedCollectFields.push(key);
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
if (populatedCollectFields.length === 0) {
|
|
677
|
-
// Pre-extraction didn't populate any declared collect field — no skip
|
|
678
|
-
return undefined;
|
|
679
|
-
}
|
|
680
|
-
// ROUTING SKIP: pre-extraction populated collect fields → retain current flow/step
|
|
681
|
-
utils_1.logger.debug(`[ResponseModal] Routing skip: pre-extraction populated collect fields [${populatedCollectFields.join(', ')}] for step "${currentStep.id}" — skipping FlowRouter`);
|
|
682
|
-
// Merge extracted data into session
|
|
683
|
-
const updatedSession = (0, utils_1.mergeCollected)(session, extractedData);
|
|
684
|
-
await this.agent.updateCollectedData(extractedData);
|
|
685
|
-
// Determine next step using pipeline method for consistency
|
|
686
|
-
// Pass the current flow/step as the routing result (retained)
|
|
687
|
-
const stepResult = await this.responsePipeline.determineNextStep({
|
|
688
|
-
selectedFlow: currentFlow,
|
|
689
|
-
selectedStep: currentStep,
|
|
690
|
-
session: updatedSession,
|
|
691
|
-
isFlowComplete: false,
|
|
692
|
-
});
|
|
693
|
-
return {
|
|
694
|
-
selectedFlow: stepResult.flowChanged || currentFlow,
|
|
695
|
-
selectedStep: stepResult.nextStep,
|
|
696
|
-
responseDirectives: undefined,
|
|
697
|
-
session: stepResult.session,
|
|
698
|
-
isFlowComplete: stepResult.flowChanged ? false : false,
|
|
699
|
-
};
|
|
700
|
-
}
|
|
701
|
-
/**
|
|
702
|
-
* Check if a flow should pre-extract data before determining the initial step
|
|
703
|
-
* @private
|
|
704
|
-
*/
|
|
705
|
-
shouldPreExtractData(flow) {
|
|
706
|
-
// Pre-extract if flow has declared required or optional fields
|
|
707
|
-
if (flow.requiredFields && flow.requiredFields.length > 0) {
|
|
708
|
-
return true;
|
|
709
|
-
}
|
|
710
|
-
if (flow.optionalFields && flow.optionalFields.length > 0) {
|
|
711
|
-
return true;
|
|
712
|
-
}
|
|
713
|
-
// Pre-extract if any step in the flow collects data
|
|
714
|
-
const steps = flow.getAllSteps();
|
|
715
|
-
const hasDataCollectionSteps = steps.some(step => step.collect && step.collect.length > 0);
|
|
716
|
-
return hasDataCollectionSteps;
|
|
717
|
-
}
|
|
718
|
-
/**
|
|
719
|
-
* Pre-extract data from user message when entering a flow
|
|
720
|
-
* This allows skipping steps whose data is already provided
|
|
721
|
-
* @private
|
|
722
|
-
*/
|
|
723
|
-
async preExtractFlowData(params) {
|
|
724
|
-
const { route: flow, history, signal } = params;
|
|
725
|
-
// Build a schema for data extraction based on flow's fields
|
|
726
|
-
const extractionSchema = this.agent.schema;
|
|
727
|
-
if (!extractionSchema) {
|
|
728
|
-
utils_1.logger.warn(`[ResponseModal] No schema available for pre-extraction`);
|
|
729
|
-
return {};
|
|
730
|
-
}
|
|
731
|
-
// Get last user message
|
|
732
|
-
const lastMessage = (0, utils_1.getLastMessageFromHistory)(history);
|
|
733
|
-
// Build extraction prompt
|
|
734
|
-
const extractionPrompt = [
|
|
735
|
-
`Extract any relevant information from the user's message that matches the following data fields.`,
|
|
736
|
-
`Only extract information that is explicitly stated or clearly implied.`,
|
|
737
|
-
``,
|
|
738
|
-
`User's message: "${lastMessage}"`,
|
|
739
|
-
``,
|
|
740
|
-
`Extract data for these fields if present:`,
|
|
741
|
-
];
|
|
742
|
-
// Add field descriptions
|
|
743
|
-
if (flow.requiredFields) {
|
|
744
|
-
extractionPrompt.push(`Required fields: ${flow.requiredFields.join(', ')}`);
|
|
745
|
-
}
|
|
746
|
-
if (flow.optionalFields) {
|
|
747
|
-
extractionPrompt.push(`Optional fields: ${flow.optionalFields.join(', ')}`);
|
|
748
|
-
}
|
|
749
|
-
extractionPrompt.push(``, `Return ONLY the extracted data as JSON. If no data can be extracted, return an empty object {}.`);
|
|
750
|
-
// Convert Event[] to HistoryItem[] for provider call
|
|
751
|
-
const historyItems = (0, utils_1.eventsToHistory)(history);
|
|
752
|
-
// Call AI to extract data
|
|
753
|
-
const agentOptions = this.agent.getAgentOptions();
|
|
754
|
-
try {
|
|
755
|
-
const result = await agentOptions.provider.generateMessage({
|
|
756
|
-
prompt: extractionPrompt.join('\n'),
|
|
757
|
-
history: historyItems,
|
|
758
|
-
context: {}, // Passed as empty object so AI doesn't "extract" from context
|
|
759
|
-
// NOTE: context is intentionally NOT passed here.
|
|
760
|
-
// Passing context caused the AI to "extract" data from the lead's context
|
|
761
|
-
// (e.g., name, sector, city) instead of from what the user actually said.
|
|
762
|
-
signal,
|
|
763
|
-
parameters: {
|
|
764
|
-
jsonSchema: extractionSchema,
|
|
765
|
-
schemaName: 'data_extraction',
|
|
766
|
-
},
|
|
767
|
-
});
|
|
768
|
-
return result.structured || {};
|
|
769
|
-
}
|
|
770
|
-
catch (error) {
|
|
771
|
-
utils_1.logger.error(`[ResponseModal] Pre-extraction failed:`, error);
|
|
772
|
-
return {};
|
|
337
|
+
throw ResponseGenerationError_1.ResponseGenerationError.fromError(error, 'preparation', params);
|
|
773
338
|
}
|
|
774
339
|
}
|
|
775
340
|
/**
|
|
@@ -789,15 +354,12 @@ class ResponseModal {
|
|
|
789
354
|
if (signalHalted) {
|
|
790
355
|
const haltMessage = signalHaltReply || '';
|
|
791
356
|
// Run post-signal phase even on halt (post-phase sees complete turn context)
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
}
|
|
799
|
-
const message = this.applyPostSignalReply(haltMessage, postResult.mergedDirective);
|
|
800
|
-
await this.finalizeSession(session, effectiveContext);
|
|
357
|
+
const post = await this.signalCoordinator.applyPostPhase({
|
|
358
|
+
session, context: effectiveContext, historyEvents, message: haltMessage,
|
|
359
|
+
});
|
|
360
|
+
session = post.session;
|
|
361
|
+
signalFirings.push(...post.firings);
|
|
362
|
+
const message = post.message;
|
|
801
363
|
return {
|
|
802
364
|
message,
|
|
803
365
|
session,
|
|
@@ -831,12 +393,12 @@ class ResponseModal {
|
|
|
831
393
|
flow: selectedFlow,
|
|
832
394
|
});
|
|
833
395
|
session = autoResult.session;
|
|
834
|
-
// Handle halt: emit verbatim reply,
|
|
396
|
+
// Handle halt: emit verbatim reply, return — no LLM call.
|
|
397
|
+
// respond() finalizes the returned session exactly once.
|
|
835
398
|
if (autoResult.stoppedReason === 'halt') {
|
|
836
399
|
message = autoResult.mergedDirective?.reply || '';
|
|
837
400
|
stoppedReason = 'halt';
|
|
838
401
|
executedSteps = [];
|
|
839
|
-
await this.finalizeSession(session, effectiveContext);
|
|
840
402
|
return {
|
|
841
403
|
message,
|
|
842
404
|
session,
|
|
@@ -858,7 +420,6 @@ class ResponseModal {
|
|
|
858
420
|
context: effectiveContext,
|
|
859
421
|
history,
|
|
860
422
|
});
|
|
861
|
-
await this.finalizeSession(session, effectiveContext);
|
|
862
423
|
return {
|
|
863
424
|
message: '',
|
|
864
425
|
session,
|
|
@@ -938,17 +499,13 @@ class ResponseModal {
|
|
|
938
499
|
// Runs after finalize/onComplete and before session persistence.
|
|
939
500
|
// Post-phase signals see the complete turn result: assistant message in
|
|
940
501
|
// history, collected data, tool results.
|
|
941
|
-
const
|
|
942
|
-
|
|
502
|
+
const post = await this.signalCoordinator.applyPostPhase({
|
|
503
|
+
session, context: effectiveContext, historyEvents, message,
|
|
504
|
+
});
|
|
505
|
+
session = post.session;
|
|
943
506
|
// Append post-phase firings to the accumulator (preserves fire order)
|
|
944
|
-
signalFirings.push(...
|
|
945
|
-
|
|
946
|
-
// (no mid-turn re-entry per D6 decision). Pre-LLM-only fields are already
|
|
947
|
-
// dropped inside runPostSignalPhase per Phase 4.5.
|
|
948
|
-
if (postResult.mergedDirective && (0, ResponsePipeline_1.hasDirectivePositionField)(postResult.mergedDirective)) {
|
|
949
|
-
session = { ...session, pendingDirective: postResult.mergedDirective };
|
|
950
|
-
}
|
|
951
|
-
message = this.applyPostSignalReply(message, postResult.mergedDirective);
|
|
507
|
+
signalFirings.push(...post.firings);
|
|
508
|
+
message = post.message;
|
|
952
509
|
// Ensure response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
953
510
|
// - executedSteps: array of steps executed (empty array if none)
|
|
954
511
|
// - stoppedReason: why execution stopped (undefined for fallback)
|
|
@@ -964,43 +521,6 @@ class ResponseModal {
|
|
|
964
521
|
triggeredSignals: signalFirings.length > 0 ? signalFirings : undefined,
|
|
965
522
|
};
|
|
966
523
|
}
|
|
967
|
-
/**
|
|
968
|
-
* Execute prepare function for current step if available
|
|
969
|
-
* @private
|
|
970
|
-
*/
|
|
971
|
-
async executeStepPrepare(session, context) {
|
|
972
|
-
if (session.currentFlow && session.currentStep) {
|
|
973
|
-
const currentFlow = this.agent.getFlows().find((r) => r.id === session.currentFlow?.id);
|
|
974
|
-
if (currentFlow) {
|
|
975
|
-
const currentStep = currentFlow.getStep(session.currentStep.id);
|
|
976
|
-
// Skip auto-steps — their prepare is handled by AutoChainExecutor
|
|
977
|
-
if (currentStep?.auto) {
|
|
978
|
-
utils_1.logger.debug(`[ResponseModal] Skipping pre-routing prepare for auto-step: ${currentStep.id}`);
|
|
979
|
-
return;
|
|
980
|
-
}
|
|
981
|
-
if (currentStep?.prepare) {
|
|
982
|
-
utils_1.logger.debug(`[ResponseModal] Executing prepare for step: ${currentStep.id}`);
|
|
983
|
-
await this.executePrepareFinalize(currentStep.prepare, context, session.data, currentFlow, currentStep);
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
/**
|
|
989
|
-
* Execute finalize function for current step if available
|
|
990
|
-
* @private
|
|
991
|
-
*/
|
|
992
|
-
async executeStepFinalize(session, context) {
|
|
993
|
-
if (session.currentFlow && session.currentStep) {
|
|
994
|
-
const currentFlow = this.agent.getFlows().find((r) => r.id === session.currentFlow?.id);
|
|
995
|
-
if (currentFlow) {
|
|
996
|
-
const currentStep = currentFlow.getStep(session.currentStep.id);
|
|
997
|
-
if (currentStep?.finalize) {
|
|
998
|
-
utils_1.logger.debug(`[ResponseModal] Executing finalize for step: ${currentStep.id}`);
|
|
999
|
-
await this.executePrepareFinalize(currentStep.finalize, context, session.data, currentFlow, currentStep);
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
524
|
/**
|
|
1005
525
|
* Process flow response with unified tool execution and data collection
|
|
1006
526
|
* @private
|
|
@@ -1008,79 +528,20 @@ class ResponseModal {
|
|
|
1008
528
|
async processFlowResponse(params) {
|
|
1009
529
|
const { selectedFlow, selectedStep, responseDirectives, history, context, historyEvents, signal, transientAppendage, mergedPreDirective } = params;
|
|
1010
530
|
let session = params.session;
|
|
1011
|
-
//
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
utils_1.logger.debug(`[ResponseModal] Step determination: flow match=${isInSameFlow}, currentFlow=${session.currentFlow?.id}, selectedFlow=${selectedFlow.id}, currentStep=${currentStep?.id || 'none'}`);
|
|
1023
|
-
// STEP 1 (Algorithm 1): branches win over linear chain
|
|
1024
|
-
if (currentStep?.branches && currentStep.branches.length > 0) {
|
|
1025
|
-
const branchResult = await this.responsePipeline.evaluateStepBranches(currentStep, selectedFlow, session, context);
|
|
1026
|
-
if (branchResult) {
|
|
1027
|
-
if (branchResult.nextStep) {
|
|
1028
|
-
nextStep = branchResult.nextStep;
|
|
1029
|
-
session = branchResult.session;
|
|
1030
|
-
}
|
|
1031
|
-
else {
|
|
1032
|
-
// Flow transition or completion — no local step to render
|
|
1033
|
-
// Return empty message with updated session; caller handles flow transition
|
|
1034
|
-
return { message: '', session: branchResult.session };
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
if (!nextStep) {
|
|
1039
|
-
// Get candidate steps based on current position in the flow
|
|
1040
|
-
const flowRouter = this.agent.getFlowRouter();
|
|
1041
|
-
const candidates = await flowRouter.getCandidateStepsWithConditions(selectedFlow, currentStep, // Pass current step instead of undefined to maintain progression
|
|
1042
|
-
(0, template_1.createTemplateContext)({ data: session.data, session, context }));
|
|
1043
|
-
utils_1.logger.debug(`[ResponseModal] Found ${candidates.length} candidate steps${currentStep ? ' from current step ' + currentStep.id : ' (new flow entry)'}`);
|
|
1044
|
-
if (candidates.length > 0) {
|
|
1045
|
-
nextStep = candidates[0].step;
|
|
1046
|
-
utils_1.logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new flow'}`);
|
|
1047
|
-
}
|
|
1048
|
-
else {
|
|
1049
|
-
// Fallback to initial step even if it should be skipped
|
|
1050
|
-
nextStep = selectedFlow.initialStep;
|
|
1051
|
-
utils_1.logger.warn(`[FlowConfigurationError] No valid steps found: all candidates were skipped in flow. Falling back to initial step "${nextStep.id}". Review step skip conditions.`);
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
// Update session with next step
|
|
1056
|
-
// If the next step has requires fields that are missing, stay at the previous step
|
|
1057
|
-
if (nextStep.requires && nextStep.requires.length > 0) {
|
|
1058
|
-
const sessionData = session.data || {};
|
|
1059
|
-
const missingRequires = nextStep.requires.filter(field => sessionData[String(field)] === undefined);
|
|
1060
|
-
if (missingRequires.length > 0) {
|
|
1061
|
-
const warning = `[FlowConfigurationError] Cannot advance to step "${nextStep.description || nextStep.id}": ` +
|
|
1062
|
-
`missing required fields [${missingRequires.join(', ')}]. Staying at current step. Ensure preceding steps collect these fields.`;
|
|
1063
|
-
utils_1.logger.warn(warning);
|
|
1064
|
-
console.warn(warning);
|
|
1065
|
-
// Stay at the current step - don't enter the next one
|
|
1066
|
-
const currentStepId = session.currentStep?.id;
|
|
1067
|
-
if (currentStepId) {
|
|
1068
|
-
const currentStepInstance = selectedFlow.getStep(currentStepId);
|
|
1069
|
-
if (currentStepInstance) {
|
|
1070
|
-
nextStep = currentStepInstance;
|
|
1071
|
-
utils_1.logger.debug(`[ResponseModal] Staying at current step: ${nextStep.id} due to missing requires`);
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
else {
|
|
1076
|
-
session = (0, utils_1.enterStep)(session, nextStep.id, nextStep.description);
|
|
1077
|
-
utils_1.logger.debug(`[ResponseModal] Entered step: ${nextStep.id}`);
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
else {
|
|
1081
|
-
session = (0, utils_1.enterStep)(session, nextStep.id, nextStep.description);
|
|
1082
|
-
utils_1.logger.debug(`[ResponseModal] Entered step: ${nextStep.id}`);
|
|
531
|
+
// Resolve the step to render (branches win over linear chain; requires enforced)
|
|
532
|
+
const stepResolution = await this.responsePipeline.resolveRenderStep({
|
|
533
|
+
selectedFlow,
|
|
534
|
+
selectedStep,
|
|
535
|
+
session,
|
|
536
|
+
context,
|
|
537
|
+
});
|
|
538
|
+
if (stepResolution.flowTransition) {
|
|
539
|
+
// Flow transition or completion — no local step to render
|
|
540
|
+
// Return empty message with updated session; caller handles flow transition
|
|
541
|
+
return { message: '', session: stepResolution.session };
|
|
1083
542
|
}
|
|
543
|
+
const nextStep = stepResolution.nextStep;
|
|
544
|
+
session = stepResolution.session;
|
|
1084
545
|
// Build response schema for this flow (with collect fields from step)
|
|
1085
546
|
const responseSchema = this.responseEngine.responseSchemaForFlow(selectedFlow, nextStep, this.agent.schema);
|
|
1086
547
|
// ── HALT SHORT-CIRCUIT (Requirement 2.5, 2.6, 2.7) ──────────────────────
|
|
@@ -1153,7 +614,7 @@ class ResponseModal {
|
|
|
1153
614
|
toolNames: toolCalls?.map(tc => tc.toolName) || [],
|
|
1154
615
|
});
|
|
1155
616
|
// Execute tools with unified loop handling
|
|
1156
|
-
const toolResult = await this.
|
|
617
|
+
const toolResult = await this.toolLoopExecutor.runLoop({
|
|
1157
618
|
toolCalls,
|
|
1158
619
|
context,
|
|
1159
620
|
session,
|
|
@@ -1199,14 +660,13 @@ class ResponseModal {
|
|
|
1199
660
|
if (signalHalted) {
|
|
1200
661
|
const haltMessage = signalHaltReply || '';
|
|
1201
662
|
// Run post-signal phase even on halt
|
|
1202
|
-
const
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
await this.finalizeSession(session, effectiveContext);
|
|
663
|
+
const post = await this.signalCoordinator.applyPostPhase({
|
|
664
|
+
session, context: effectiveContext, historyEvents, message: haltMessage,
|
|
665
|
+
});
|
|
666
|
+
session = post.session;
|
|
667
|
+
signalFirings.push(...post.firings);
|
|
668
|
+
const message = post.message;
|
|
669
|
+
await this.sessionFinalizer.finalize(session, effectiveContext);
|
|
1210
670
|
yield {
|
|
1211
671
|
delta: message,
|
|
1212
672
|
accumulated: message,
|
|
@@ -1239,7 +699,7 @@ class ResponseModal {
|
|
|
1239
699
|
// Handle halt: emit verbatim reply as a single chunk, done.
|
|
1240
700
|
if (autoResult.stoppedReason === 'halt') {
|
|
1241
701
|
const reply = autoResult.mergedDirective?.reply || '';
|
|
1242
|
-
await this.
|
|
702
|
+
await this.sessionFinalizer.finalize(session, effectiveContext);
|
|
1243
703
|
yield {
|
|
1244
704
|
delta: reply,
|
|
1245
705
|
accumulated: reply,
|
|
@@ -1316,24 +776,26 @@ class ResponseModal {
|
|
|
1316
776
|
session,
|
|
1317
777
|
});
|
|
1318
778
|
}
|
|
1319
|
-
// ── Intercept the inner stream
|
|
1320
|
-
//
|
|
1321
|
-
//
|
|
1322
|
-
// (Requirement 11.2).
|
|
779
|
+
// ── Intercept the inner stream on the final chunk ──────────────────────
|
|
780
|
+
// Mirrors the non-streaming path: post-signal phase runs first, then the
|
|
781
|
+
// session (including post-phase mutations) is finalized exactly once,
|
|
782
|
+
// attaching triggeredSignals to the final chunk (Requirement 11.2).
|
|
1323
783
|
for await (const chunk of innerStream) {
|
|
1324
784
|
if (chunk.done) {
|
|
1325
785
|
// Run post-signal phase on final chunk (Requirement 9.1, 9.2)
|
|
1326
|
-
const
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
const
|
|
1335
|
-
|
|
1336
|
-
|
|
786
|
+
const post = await this.signalCoordinator.applyPostPhase({
|
|
787
|
+
session: chunk.session || session,
|
|
788
|
+
context: effectiveContext,
|
|
789
|
+
historyEvents,
|
|
790
|
+
message: chunk.accumulated,
|
|
791
|
+
});
|
|
792
|
+
const finalSession = post.session;
|
|
793
|
+
signalFirings.push(...post.firings);
|
|
794
|
+
const accumulated = post.message;
|
|
795
|
+
const delta = post.replyOverridden ? accumulated : chunk.delta;
|
|
796
|
+
// Single streaming exit: finalize the post-phase session so
|
|
797
|
+
// post-signal mutations (e.g. pendingDirective) are persisted
|
|
798
|
+
await this.sessionFinalizer.finalize(finalSession, effectiveContext);
|
|
1337
799
|
yield {
|
|
1338
800
|
...chunk,
|
|
1339
801
|
delta,
|
|
@@ -1354,80 +816,25 @@ class ResponseModal {
|
|
|
1354
816
|
async *processFlowStreamingResponse(params) {
|
|
1355
817
|
const { selectedFlow, selectedStep, responseDirectives, history, context, historyEvents, signal, transientAppendage, mergedPreDirective } = params;
|
|
1356
818
|
let session = params.session;
|
|
1357
|
-
//
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
session = branchResult.session;
|
|
1374
|
-
nextStep = branchResult.nextStep;
|
|
1375
|
-
}
|
|
1376
|
-
else {
|
|
1377
|
-
// Flow transition or completion — no step to render
|
|
1378
|
-
yield {
|
|
1379
|
-
delta: '',
|
|
1380
|
-
accumulated: '',
|
|
1381
|
-
done: true,
|
|
1382
|
-
session: branchResult.session,
|
|
1383
|
-
};
|
|
1384
|
-
return;
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
if (!nextStep) {
|
|
1389
|
-
// Get candidate steps based on current position in the flow
|
|
1390
|
-
const flowRouter = this.agent.getFlowRouter();
|
|
1391
|
-
const candidates = await flowRouter.getCandidateStepsWithConditions(selectedFlow, currentStep, // Pass current step instead of undefined to maintain progression
|
|
1392
|
-
(0, template_1.createTemplateContext)({ data: session.data, session, context }));
|
|
1393
|
-
if (candidates.length > 0) {
|
|
1394
|
-
nextStep = candidates[0].step;
|
|
1395
|
-
utils_1.logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new flow'}`);
|
|
1396
|
-
}
|
|
1397
|
-
else {
|
|
1398
|
-
nextStep = selectedFlow.initialStep;
|
|
1399
|
-
utils_1.logger.warn(`[FlowConfigurationError] No valid steps found: all candidates were skipped in flow. Falling back to initial step "${nextStep.id}". Review step skip conditions.`);
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
// Update session with next step
|
|
1404
|
-
// If the next step has requires fields that are missing, stay at the previous step
|
|
1405
|
-
if (nextStep.requires && nextStep.requires.length > 0) {
|
|
1406
|
-
const sessionData = session.data || {};
|
|
1407
|
-
const missingRequires = nextStep.requires.filter(field => sessionData[String(field)] === undefined);
|
|
1408
|
-
if (missingRequires.length > 0) {
|
|
1409
|
-
const warning = `[FlowConfigurationError] Cannot advance to step "${nextStep.description || nextStep.id}": ` +
|
|
1410
|
-
`missing required fields [${missingRequires.join(', ')}]. Staying at current step. Ensure preceding steps collect these fields.`;
|
|
1411
|
-
utils_1.logger.warn(warning);
|
|
1412
|
-
console.warn(warning);
|
|
1413
|
-
const currentStepId = session.currentStep?.id;
|
|
1414
|
-
if (currentStepId) {
|
|
1415
|
-
const currentStepInstance = selectedFlow.getStep(currentStepId);
|
|
1416
|
-
if (currentStepInstance) {
|
|
1417
|
-
nextStep = currentStepInstance;
|
|
1418
|
-
utils_1.logger.debug(`[ResponseModal] Staying at current step: ${nextStep.id} due to missing requires`);
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
else {
|
|
1423
|
-
session = (0, utils_1.enterStep)(session, nextStep.id, nextStep.description);
|
|
1424
|
-
utils_1.logger.debug(`[ResponseModal] Entered step: ${nextStep.id}`);
|
|
1425
|
-
}
|
|
1426
|
-
}
|
|
1427
|
-
else {
|
|
1428
|
-
session = (0, utils_1.enterStep)(session, nextStep.id, nextStep.description);
|
|
1429
|
-
utils_1.logger.debug(`[ResponseModal] Entered step: ${nextStep.id}`);
|
|
819
|
+
// Resolve the step to render (same logic as non-streaming)
|
|
820
|
+
const stepResolution = await this.responsePipeline.resolveRenderStep({
|
|
821
|
+
selectedFlow,
|
|
822
|
+
selectedStep,
|
|
823
|
+
session,
|
|
824
|
+
context,
|
|
825
|
+
});
|
|
826
|
+
if (stepResolution.flowTransition) {
|
|
827
|
+
// Flow transition or completion — no step to render
|
|
828
|
+
yield {
|
|
829
|
+
delta: '',
|
|
830
|
+
accumulated: '',
|
|
831
|
+
done: true,
|
|
832
|
+
session: stepResolution.session,
|
|
833
|
+
};
|
|
834
|
+
return;
|
|
1430
835
|
}
|
|
836
|
+
const nextStep = stepResolution.nextStep;
|
|
837
|
+
session = stepResolution.session;
|
|
1431
838
|
// Build response schema and prompt (same as non-streaming)
|
|
1432
839
|
const responseSchema = this.responseEngine.responseSchemaForFlow(selectedFlow, nextStep, this.agent.schema);
|
|
1433
840
|
// ── HALT SHORT-CIRCUIT (Requirement 2.5, 2.6, 2.7) ──────────────────────
|
|
@@ -1437,7 +844,6 @@ class ResponseModal {
|
|
|
1437
844
|
const reply = mergedPreDirective.reply || '';
|
|
1438
845
|
const reason = mergedPreDirective.reply ? 'reply' : 'halt';
|
|
1439
846
|
utils_1.logger.debug(`[ResponseModal] Halt (streaming) — skipping LLM call for step ${nextStep.id}, stoppedReason: ${reason}`);
|
|
1440
|
-
await this.finalizeSession(session, context);
|
|
1441
847
|
yield {
|
|
1442
848
|
delta: reply,
|
|
1443
849
|
accumulated: reply,
|
|
@@ -1455,7 +861,6 @@ class ResponseModal {
|
|
|
1455
861
|
if (nextStep.reply != null) {
|
|
1456
862
|
const effectiveReply = mergedPreDirective?.reply ?? await (0, utils_1.render)(nextStep.reply, (0, template_1.createTemplateContext)({ data: session.data || {}, context, session }));
|
|
1457
863
|
utils_1.logger.debug(`[ResponseModal] Step.reply (streaming) — skipping LLM call for step ${nextStep.id}`);
|
|
1458
|
-
await this.finalizeSession(session, context);
|
|
1459
864
|
yield {
|
|
1460
865
|
delta: effectiveReply,
|
|
1461
866
|
accumulated: effectiveReply,
|
|
@@ -1504,70 +909,23 @@ class ResponseModal {
|
|
|
1504
909
|
// Extract tool calls from AI response on final chunk
|
|
1505
910
|
if (chunk.done && chunk.structured?.toolCalls) {
|
|
1506
911
|
toolCalls = chunk.structured.toolCalls;
|
|
1507
|
-
|
|
1508
|
-
//
|
|
1509
|
-
{
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
step: nextStep,
|
|
1525
|
-
})) {
|
|
1526
|
-
// Apply context updates
|
|
1527
|
-
if (update.contextUpdate) {
|
|
1528
|
-
try {
|
|
1529
|
-
await this.agent.updateContext(update.contextUpdate);
|
|
1530
|
-
}
|
|
1531
|
-
catch (error) {
|
|
1532
|
-
utils_1.logger.error(`[ResponseModal] Failed to update context from concurrent tool:`, error);
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
// Apply data updates
|
|
1536
|
-
if (update.dataUpdate) {
|
|
1537
|
-
try {
|
|
1538
|
-
const updateDataMethod = this.agent.getUpdateDataMethod();
|
|
1539
|
-
session = await updateDataMethod(session, update.dataUpdate);
|
|
1540
|
-
}
|
|
1541
|
-
catch (error) {
|
|
1542
|
-
utils_1.logger.error(`[ResponseModal] Failed to update data from concurrent tool:`, error);
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
// Yield progress updates immediately
|
|
1546
|
-
if (update.progress) {
|
|
1547
|
-
yield {
|
|
1548
|
-
delta: '',
|
|
1549
|
-
accumulated: chunk.accumulated,
|
|
1550
|
-
done: false,
|
|
1551
|
-
session,
|
|
1552
|
-
toolCalls: undefined,
|
|
1553
|
-
isFlowComplete: false,
|
|
1554
|
-
metadata: { toolProgress: update.progress, toolCallId: update.toolCallId },
|
|
1555
|
-
};
|
|
1556
|
-
}
|
|
1557
|
-
}
|
|
1558
|
-
utils_1.logger.debug(`[ResponseModal] Concurrent tool execution completed for ${toolCallRequests.length} tools`);
|
|
1559
|
-
}
|
|
1560
|
-
catch (error) {
|
|
1561
|
-
utils_1.logger.error(`[ResponseModal] Concurrent tool execution failed, falling back to sequential:`, error);
|
|
1562
|
-
// Fall back to the unified tool loop on failure
|
|
1563
|
-
const toolResult = await this.executeUnifiedToolLoop({
|
|
1564
|
-
toolCalls, context, session, history, selectedFlow,
|
|
1565
|
-
responsePrompt, availableTools, responseSchema, signal,
|
|
1566
|
-
});
|
|
1567
|
-
session = toolResult.session;
|
|
1568
|
-
toolCalls = toolResult.finalToolCalls;
|
|
1569
|
-
}
|
|
1570
|
-
}
|
|
912
|
+
// Concurrent execution for the initial batch of tool calls,
|
|
913
|
+
// yielding tool-progress chunks as they arrive
|
|
914
|
+
const batchResult = yield* this.toolLoopExecutor.runStreamingBatch({
|
|
915
|
+
toolCalls,
|
|
916
|
+
context,
|
|
917
|
+
session,
|
|
918
|
+
history,
|
|
919
|
+
selectedFlow,
|
|
920
|
+
step: nextStep,
|
|
921
|
+
accumulated: chunk.accumulated,
|
|
922
|
+
responsePrompt,
|
|
923
|
+
availableTools,
|
|
924
|
+
responseSchema,
|
|
925
|
+
signal,
|
|
926
|
+
});
|
|
927
|
+
session = batchResult.session;
|
|
928
|
+
toolCalls = batchResult.toolCalls;
|
|
1571
929
|
}
|
|
1572
930
|
// Extract collected data on final chunk
|
|
1573
931
|
if (chunk.done && chunk.structured && nextStep.collect) {
|
|
@@ -1578,10 +936,6 @@ class ResponseModal {
|
|
|
1578
936
|
session,
|
|
1579
937
|
});
|
|
1580
938
|
}
|
|
1581
|
-
// Handle session finalization on final chunk
|
|
1582
|
-
if (chunk.done) {
|
|
1583
|
-
await this.finalizeSession(session, context);
|
|
1584
|
-
}
|
|
1585
939
|
// Response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
1586
940
|
// - executedSteps: single step executed in this response
|
|
1587
941
|
// - stoppedReason: 'needs_input' for single-step execution (waiting for user input)
|
|
@@ -1609,293 +963,6 @@ class ResponseModal {
|
|
|
1609
963
|
}
|
|
1610
964
|
}
|
|
1611
965
|
/**
|
|
1612
|
-
* Unified tool execution logic with loop handling
|
|
1613
|
-
* Consolidates the complex tool execution logic from both streaming and non-streaming responses
|
|
1614
|
-
* @private
|
|
1615
|
-
*/
|
|
1616
|
-
async executeUnifiedToolLoop(params) {
|
|
1617
|
-
try {
|
|
1618
|
-
const { context, history, selectedFlow, responsePrompt, availableTools, responseSchema, signal } = params;
|
|
1619
|
-
let { toolCalls, session } = params;
|
|
1620
|
-
// Convert HistoryItem[] to Event[] for internal processing
|
|
1621
|
-
const historyEvents = (0, utils_1.historyToEvents)(history);
|
|
1622
|
-
// Map to store tool execution results for history
|
|
1623
|
-
const toolResultsMap = new Map();
|
|
1624
|
-
// Map to store tool call arguments for history reconstruction
|
|
1625
|
-
const toolArgsMap = new Map();
|
|
1626
|
-
// Execute initial dynamic tool calls
|
|
1627
|
-
if (toolCalls && toolCalls.length > 0) {
|
|
1628
|
-
utils_1.logger.debug(`[ResponseModal] Executing ${toolCalls.length} dynamic tool calls:`, toolCalls.map(tc => tc.toolName));
|
|
1629
|
-
for (const toolCall of toolCalls) {
|
|
1630
|
-
const tool = this.findAvailableTool(toolCall.toolName, selectedFlow);
|
|
1631
|
-
if (!tool) {
|
|
1632
|
-
utils_1.logger.warn(`[ToolExecutionError] Tool not found: "${toolCall.toolName}" is not registered in any scope. Skipping this tool call. Register the tool or check the tool name.`);
|
|
1633
|
-
continue;
|
|
1634
|
-
}
|
|
1635
|
-
try {
|
|
1636
|
-
// Use ToolManager for unified tool execution
|
|
1637
|
-
const toolManager = this.getToolManager();
|
|
1638
|
-
const toolResult = await toolManager.executeTool({
|
|
1639
|
-
tool: tool,
|
|
1640
|
-
context,
|
|
1641
|
-
updateContext: this.agent.updateContext.bind(this.agent),
|
|
1642
|
-
updateData: this.agent.updateCollectedData.bind(this.agent),
|
|
1643
|
-
history: historyEvents, // Use Event[] for tool execution
|
|
1644
|
-
data: session.data,
|
|
1645
|
-
toolArguments: toolCall.arguments,
|
|
1646
|
-
});
|
|
1647
|
-
// Store the actual tool result data for history
|
|
1648
|
-
toolResultsMap.set(toolCall.toolName, (0, utils_1.serializeToolResult)(toolResult));
|
|
1649
|
-
toolArgsMap.set(toolCall.toolName, toolCall.arguments);
|
|
1650
|
-
// Check if tool execution was successful
|
|
1651
|
-
if (!toolResult.success) {
|
|
1652
|
-
utils_1.logger.error(`[ResponseModal] Tool execution failed: ${toolCall.toolName} - ${toolResult.error}`);
|
|
1653
|
-
// Continue with other tools rather than failing completely
|
|
1654
|
-
continue;
|
|
1655
|
-
}
|
|
1656
|
-
// Update context with tool results
|
|
1657
|
-
if (toolResult.contextUpdate) {
|
|
1658
|
-
try {
|
|
1659
|
-
await this.agent.updateContext(toolResult.contextUpdate);
|
|
1660
|
-
}
|
|
1661
|
-
catch (error) {
|
|
1662
|
-
utils_1.logger.error(`[ResponseModal] Failed to update context from tool ${toolCall.toolName}:`, error);
|
|
1663
|
-
// Continue execution but log the error
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
// Update collected data with tool results
|
|
1667
|
-
if (toolResult.dataUpdate) {
|
|
1668
|
-
try {
|
|
1669
|
-
const updateDataMethod = this.agent.getUpdateDataMethod();
|
|
1670
|
-
session = await updateDataMethod(session, toolResult.dataUpdate);
|
|
1671
|
-
utils_1.logger.debug(`[ResponseModal] Tool updated collected data:`, toolResult.dataUpdate);
|
|
1672
|
-
}
|
|
1673
|
-
catch (error) {
|
|
1674
|
-
utils_1.logger.error(`[ResponseModal] Failed to update data from tool ${toolCall.toolName}:`, error);
|
|
1675
|
-
// Continue execution but log the error
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
utils_1.logger.debug(`[ResponseModal] Executed dynamic tool: ${toolCall.toolName} (success: ${toolResult.success})`);
|
|
1679
|
-
}
|
|
1680
|
-
catch (error) {
|
|
1681
|
-
utils_1.logger.error(`[ResponseModal] Tool execution error for ${toolCall.toolName}:`, error);
|
|
1682
|
-
// Continue with other tools rather than failing the entire response
|
|
1683
|
-
continue;
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
|
-
}
|
|
1687
|
-
// TOOL LOOP: Allow AI to make follow-up tool calls after initial tool execution
|
|
1688
|
-
const MAX_TOOL_LOOPS = this.options?.maxToolLoops || 5;
|
|
1689
|
-
let toolLoopCount = 0;
|
|
1690
|
-
let hasToolCalls = toolCalls && toolCalls.length > 0;
|
|
1691
|
-
let finalMessage;
|
|
1692
|
-
let followUpStructured;
|
|
1693
|
-
while (hasToolCalls && toolLoopCount < MAX_TOOL_LOOPS) {
|
|
1694
|
-
toolLoopCount++;
|
|
1695
|
-
utils_1.logger.debug(`[ResponseModal] Starting tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS} with ${toolCalls?.length || 0} tool calls`);
|
|
1696
|
-
// Create tool result history items
|
|
1697
|
-
const toolResultHistoryItems = [];
|
|
1698
|
-
for (const toolCall of toolCalls || []) {
|
|
1699
|
-
const tool = this.findAvailableTool(toolCall.toolName, selectedFlow);
|
|
1700
|
-
if (tool) {
|
|
1701
|
-
// Create HistoryItem format for tool results
|
|
1702
|
-
// Add assistant message with tool_calls
|
|
1703
|
-
toolResultHistoryItems.push({
|
|
1704
|
-
role: "assistant",
|
|
1705
|
-
content: null,
|
|
1706
|
-
tool_calls: [{
|
|
1707
|
-
id: toolCall.toolName,
|
|
1708
|
-
name: toolCall.toolName,
|
|
1709
|
-
arguments: toolCall.arguments,
|
|
1710
|
-
}],
|
|
1711
|
-
});
|
|
1712
|
-
// Add tool result
|
|
1713
|
-
toolResultHistoryItems.push({
|
|
1714
|
-
role: "tool",
|
|
1715
|
-
tool_call_id: toolCall.toolName,
|
|
1716
|
-
name: toolCall.toolName,
|
|
1717
|
-
content: toolResultsMap.get(toolCall.toolName) || "Tool executed successfully",
|
|
1718
|
-
});
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
// Create updated history with tool results
|
|
1722
|
-
const updatedHistory = [...history, ...toolResultHistoryItems];
|
|
1723
|
-
// Make follow-up AI call to see if more tools are needed
|
|
1724
|
-
// After first iteration, don't provide tools to force a text response
|
|
1725
|
-
const agentOptions = this.agent.getAgentOptions();
|
|
1726
|
-
const shouldProvideTools = toolLoopCount === 1;
|
|
1727
|
-
utils_1.logger.debug(`[ResponseModal] Making follow-up AI call (loop ${toolLoopCount}):`, {
|
|
1728
|
-
providingTools: shouldProvideTools,
|
|
1729
|
-
toolsCount: shouldProvideTools ? availableTools.length : 0,
|
|
1730
|
-
addingTextInstruction: toolLoopCount > 1,
|
|
1731
|
-
});
|
|
1732
|
-
const followUpResult = await agentOptions.provider.generateMessage({
|
|
1733
|
-
prompt: responsePrompt + (toolLoopCount > 1 ? "\n\nProvide a text response to the user based on the tool results." : ""),
|
|
1734
|
-
history: updatedHistory, // Use HistoryItem[] for AI provider
|
|
1735
|
-
context,
|
|
1736
|
-
tools: shouldProvideTools ? availableTools : [], // Only provide tools on first iteration
|
|
1737
|
-
parameters: responseSchema ? {
|
|
1738
|
-
jsonSchema: responseSchema,
|
|
1739
|
-
schemaName: "tool_followup",
|
|
1740
|
-
} : undefined,
|
|
1741
|
-
signal,
|
|
1742
|
-
});
|
|
1743
|
-
// Check if follow-up call has more tool calls
|
|
1744
|
-
const followUpToolCalls = followUpResult.structured?.toolCalls;
|
|
1745
|
-
hasToolCalls = followUpToolCalls && followUpToolCalls.length > 0;
|
|
1746
|
-
utils_1.logger.debug(`[ResponseModal] Follow-up AI response (loop ${toolLoopCount}):`, {
|
|
1747
|
-
hasMessage: !!followUpResult.message,
|
|
1748
|
-
messageLength: followUpResult.message?.length || 0,
|
|
1749
|
-
hasToolCalls,
|
|
1750
|
-
toolCallsCount: followUpToolCalls?.length || 0,
|
|
1751
|
-
toolNames: followUpToolCalls?.map(tc => tc.toolName) || [],
|
|
1752
|
-
});
|
|
1753
|
-
if (hasToolCalls) {
|
|
1754
|
-
utils_1.logger.debug(`[ResponseModal] Follow-up call produced ${followUpToolCalls.length} additional tool calls`);
|
|
1755
|
-
// Execute the follow-up tool calls
|
|
1756
|
-
for (const toolCall of followUpToolCalls) {
|
|
1757
|
-
const tool = this.findAvailableTool(toolCall.toolName, selectedFlow);
|
|
1758
|
-
if (!tool) {
|
|
1759
|
-
utils_1.logger.warn(`[ToolExecutionError] Tool not found in follow-up: "${toolCall.toolName}" is not registered in any scope. Skipping this tool call. Register the tool or check the tool name.`);
|
|
1760
|
-
continue;
|
|
1761
|
-
}
|
|
1762
|
-
try {
|
|
1763
|
-
// Use ToolManager for unified tool execution
|
|
1764
|
-
const toolManager = this.getToolManager();
|
|
1765
|
-
const toolResult = await toolManager.executeTool({
|
|
1766
|
-
tool: tool,
|
|
1767
|
-
context,
|
|
1768
|
-
updateContext: this.agent.updateContext.bind(this.agent),
|
|
1769
|
-
updateData: this.agent.updateCollectedData.bind(this.agent),
|
|
1770
|
-
history: (0, utils_1.historyToEvents)(updatedHistory), // Convert to Event[] for tool execution
|
|
1771
|
-
data: session.data,
|
|
1772
|
-
toolArguments: toolCall.arguments,
|
|
1773
|
-
});
|
|
1774
|
-
// Check if tool execution was successful
|
|
1775
|
-
if (!toolResult.success) {
|
|
1776
|
-
utils_1.logger.error(`[ResponseModal] Follow-up tool execution failed: ${toolCall.toolName} - ${toolResult.error}`);
|
|
1777
|
-
continue;
|
|
1778
|
-
}
|
|
1779
|
-
// Update context with follow-up tool results
|
|
1780
|
-
if (toolResult.contextUpdate) {
|
|
1781
|
-
try {
|
|
1782
|
-
await this.agent.updateContext(toolResult.contextUpdate);
|
|
1783
|
-
}
|
|
1784
|
-
catch (error) {
|
|
1785
|
-
utils_1.logger.error(`[ResponseModal] Failed to update context from follow-up tool ${toolCall.toolName}:`, error);
|
|
1786
|
-
}
|
|
1787
|
-
}
|
|
1788
|
-
if (toolResult.dataUpdate) {
|
|
1789
|
-
try {
|
|
1790
|
-
const updateDataMethod = this.agent.getUpdateDataMethod();
|
|
1791
|
-
session = await updateDataMethod(session, toolResult.dataUpdate);
|
|
1792
|
-
utils_1.logger.debug(`[ResponseModal] Follow-up tool updated collected data:`, toolResult.dataUpdate);
|
|
1793
|
-
}
|
|
1794
|
-
catch (error) {
|
|
1795
|
-
utils_1.logger.error(`[ResponseModal] Failed to update data from follow-up tool ${toolCall.toolName}:`, error);
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1798
|
-
// Store the follow-up tool result for potential next loop iteration
|
|
1799
|
-
toolResultsMap.set(toolCall.toolName, (0, utils_1.serializeToolResult)(toolResult));
|
|
1800
|
-
toolArgsMap.set(toolCall.toolName, toolCall.arguments);
|
|
1801
|
-
utils_1.logger.debug(`[ResponseModal] Executed follow-up tool: ${toolCall.toolName} (success: ${toolResult.success})`);
|
|
1802
|
-
}
|
|
1803
|
-
catch (error) {
|
|
1804
|
-
utils_1.logger.error(`[ResponseModal] Follow-up tool execution error for ${toolCall.toolName}:`, error);
|
|
1805
|
-
continue;
|
|
1806
|
-
}
|
|
1807
|
-
}
|
|
1808
|
-
// Update toolCalls for next iteration or final response
|
|
1809
|
-
toolCalls = followUpToolCalls;
|
|
1810
|
-
}
|
|
1811
|
-
else {
|
|
1812
|
-
utils_1.logger.debug(`[ResponseModal] Tool loop completed after ${toolLoopCount} iterations`);
|
|
1813
|
-
// Update final message and toolCalls from follow-up result if no more tools
|
|
1814
|
-
finalMessage = followUpResult.structured?.message || followUpResult.message;
|
|
1815
|
-
followUpStructured = followUpResult.structured;
|
|
1816
|
-
toolCalls = followUpToolCalls || [];
|
|
1817
|
-
break;
|
|
1818
|
-
}
|
|
1819
|
-
}
|
|
1820
|
-
if (toolLoopCount >= MAX_TOOL_LOOPS) {
|
|
1821
|
-
utils_1.logger.warn(`[ResponseGenerationError] Tool loop limit reached: ${toolLoopCount} iterations hit the cap (${MAX_TOOL_LOOPS}). Stopping tool execution. Increase MAX_TOOL_LOOPS or reduce recursive tool calls.`);
|
|
1822
|
-
}
|
|
1823
|
-
// If tools were executed but no final text message was produced,
|
|
1824
|
-
// make one more LLM call to generate a proper text response from tool results.
|
|
1825
|
-
// This prevents the original tool-invocation message (e.g. "Let me check...")
|
|
1826
|
-
// from being returned as the final user-facing response.
|
|
1827
|
-
if (!finalMessage && toolLoopCount > 0) {
|
|
1828
|
-
utils_1.logger.debug(`[ResponseModal] No final message after tool loop, making additional LLM call for text response`);
|
|
1829
|
-
// Build tool result history from toolResultsMap which contains ALL
|
|
1830
|
-
// tool executions (initial + follow-up). We can't use `toolCalls` here
|
|
1831
|
-
// because it was reassigned to the (empty) follow-up tool calls when
|
|
1832
|
-
// the while loop broke out.
|
|
1833
|
-
const finalToolResultHistoryItems = [];
|
|
1834
|
-
for (const [toolName, toolResult] of toolResultsMap) {
|
|
1835
|
-
finalToolResultHistoryItems.push({
|
|
1836
|
-
role: "assistant",
|
|
1837
|
-
content: null,
|
|
1838
|
-
tool_calls: [{
|
|
1839
|
-
id: toolName,
|
|
1840
|
-
name: toolName,
|
|
1841
|
-
arguments: toolArgsMap.get(toolName) || {},
|
|
1842
|
-
}],
|
|
1843
|
-
});
|
|
1844
|
-
finalToolResultHistoryItems.push({
|
|
1845
|
-
role: "tool",
|
|
1846
|
-
tool_call_id: toolName,
|
|
1847
|
-
name: toolName,
|
|
1848
|
-
content: toolResult,
|
|
1849
|
-
});
|
|
1850
|
-
}
|
|
1851
|
-
const finalHistory = [...history, ...finalToolResultHistoryItems];
|
|
1852
|
-
const agentOptions = this.agent.getAgentOptions();
|
|
1853
|
-
try {
|
|
1854
|
-
const textResult = await agentOptions.provider.generateMessage({
|
|
1855
|
-
prompt: responsePrompt + "\n\nProvide a text response to the user based on the tool results. Do not call any tools.",
|
|
1856
|
-
history: finalHistory,
|
|
1857
|
-
context,
|
|
1858
|
-
tools: [], // No tools - force text response
|
|
1859
|
-
parameters: responseSchema ? {
|
|
1860
|
-
jsonSchema: responseSchema,
|
|
1861
|
-
schemaName: "tool_final_text",
|
|
1862
|
-
} : undefined,
|
|
1863
|
-
signal,
|
|
1864
|
-
});
|
|
1865
|
-
finalMessage = textResult.structured?.message || textResult.message;
|
|
1866
|
-
if (textResult.structured) {
|
|
1867
|
-
followUpStructured = textResult.structured;
|
|
1868
|
-
}
|
|
1869
|
-
utils_1.logger.debug(`[ResponseModal] Generated final text response after tool loop:`, {
|
|
1870
|
-
hasMessage: !!finalMessage,
|
|
1871
|
-
messageLength: finalMessage?.length || 0,
|
|
1872
|
-
});
|
|
1873
|
-
}
|
|
1874
|
-
catch (error) {
|
|
1875
|
-
utils_1.logger.error(`[ResponseModal] Failed to generate final text response after tool loop:`, error);
|
|
1876
|
-
// finalMessage remains undefined; caller will use original message as fallback
|
|
1877
|
-
}
|
|
1878
|
-
}
|
|
1879
|
-
utils_1.logger.debug(`[ResponseModal] Tool loop completed:`, {
|
|
1880
|
-
totalIterations: toolLoopCount,
|
|
1881
|
-
hasFinalMessage: !!finalMessage,
|
|
1882
|
-
finalMessageLength: finalMessage?.length || 0,
|
|
1883
|
-
finalToolCallsCount: toolCalls?.length || 0,
|
|
1884
|
-
});
|
|
1885
|
-
return {
|
|
1886
|
-
session,
|
|
1887
|
-
finalToolCalls: toolCalls,
|
|
1888
|
-
finalMessage,
|
|
1889
|
-
structured: followUpStructured,
|
|
1890
|
-
};
|
|
1891
|
-
}
|
|
1892
|
-
catch (error) {
|
|
1893
|
-
throw ResponseGenerationError.fromError(error, 'tool_execution', params, {
|
|
1894
|
-
toolCallsCount: params.toolCalls?.length || 0,
|
|
1895
|
-
availableToolsCount: params.availableTools.length
|
|
1896
|
-
});
|
|
1897
|
-
}
|
|
1898
|
-
} /**
|
|
1899
966
|
* Unified data collection from AI response
|
|
1900
967
|
* @private
|
|
1901
968
|
*/
|
|
@@ -2041,10 +1108,6 @@ class ResponseModal {
|
|
|
2041
1108
|
}
|
|
2042
1109
|
return nextSession;
|
|
2043
1110
|
}
|
|
2044
|
-
/**
|
|
2045
|
-
* Stream flow completion response
|
|
2046
|
-
* @private
|
|
2047
|
-
*/
|
|
2048
1111
|
/**
|
|
2049
1112
|
* Stream a flow completion as a single terminal chunk.
|
|
2050
1113
|
*
|
|
@@ -2066,7 +1129,6 @@ class ResponseModal {
|
|
|
2066
1129
|
context,
|
|
2067
1130
|
history,
|
|
2068
1131
|
});
|
|
2069
|
-
await this.finalizeSession(session, context);
|
|
2070
1132
|
yield {
|
|
2071
1133
|
delta: '',
|
|
2072
1134
|
accumulated: '',
|
|
@@ -2141,10 +1203,6 @@ class ResponseModal {
|
|
|
2141
1203
|
},
|
|
2142
1204
|
});
|
|
2143
1205
|
for await (const chunk of stream) {
|
|
2144
|
-
// Update current session if we have one
|
|
2145
|
-
if (chunk.done) {
|
|
2146
|
-
await this.finalizeSession(session, context);
|
|
2147
|
-
}
|
|
2148
1206
|
// Response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
2149
1207
|
// - executedSteps: empty for fallback (no flow/step execution)
|
|
2150
1208
|
// - stoppedReason: undefined for fallback (no flow context)
|
|
@@ -2164,39 +1222,9 @@ class ResponseModal {
|
|
|
2164
1222
|
};
|
|
2165
1223
|
}
|
|
2166
1224
|
}
|
|
2167
|
-
/**
|
|
2168
|
-
* Handle session persistence and finalization
|
|
2169
|
-
* @private
|
|
2170
|
-
*/
|
|
2171
|
-
async finalizeSession(session, context) {
|
|
2172
|
-
// Auto-save session step to persistence if configured
|
|
2173
|
-
const persistenceManager = this.agent.getPersistenceManager();
|
|
2174
|
-
const agentOptions = this.agent.getAgentOptions();
|
|
2175
|
-
if (persistenceManager &&
|
|
2176
|
-
session.id &&
|
|
2177
|
-
(this.options?.enableAutoSave !== false && agentOptions.persistence?.autoSave !== false)) {
|
|
2178
|
-
await persistenceManager.saveSessionState(session.id, session);
|
|
2179
|
-
utils_1.logger.debug(`[ResponseModal] Auto-saved session step to persistence: ${session.id}`);
|
|
2180
|
-
}
|
|
2181
|
-
// Execute finalize function
|
|
2182
|
-
await this.executeStepFinalize(session, context);
|
|
2183
|
-
// Update current session if we have one
|
|
2184
|
-
const currentSession = this.agent.currentSession;
|
|
2185
|
-
if (currentSession) {
|
|
2186
|
-
this.agent.currentSession = session;
|
|
2187
|
-
}
|
|
2188
|
-
}
|
|
2189
1225
|
// ============================================================================
|
|
2190
1226
|
// UTILITY METHODS - Helper methods for tool management and other utilities
|
|
2191
1227
|
// ============================================================================
|
|
2192
|
-
/**
|
|
2193
|
-
* Find an available tool by name for the given flow.
|
|
2194
|
-
* Delegates to ToolManager for unified tool resolution.
|
|
2195
|
-
* @private
|
|
2196
|
-
*/
|
|
2197
|
-
findAvailableTool(toolName, flow) {
|
|
2198
|
-
return this.getToolManager().find(toolName, undefined, undefined, flow);
|
|
2199
|
-
}
|
|
2200
1228
|
/**
|
|
2201
1229
|
* Collect all available tools for the given flow and step context.
|
|
2202
1230
|
* Delegates to ToolManager for unified tool resolution and deduplication.
|
|
@@ -2211,50 +1239,6 @@ class ResponseModal {
|
|
|
2211
1239
|
parameters: tool.parameters,
|
|
2212
1240
|
}));
|
|
2213
1241
|
}
|
|
2214
|
-
/**
|
|
2215
|
-
* Execute a prepare or finalize function/tool
|
|
2216
|
-
* @private
|
|
2217
|
-
*/
|
|
2218
|
-
async executePrepareFinalize(prepareOrFinalize, context, data, flow, step) {
|
|
2219
|
-
if (!prepareOrFinalize)
|
|
2220
|
-
return;
|
|
2221
|
-
if (typeof prepareOrFinalize === "function") {
|
|
2222
|
-
// It's a function - call it directly
|
|
2223
|
-
await prepareOrFinalize(context, data);
|
|
2224
|
-
}
|
|
2225
|
-
else {
|
|
2226
|
-
// It's a tool reference - find and execute the tool
|
|
2227
|
-
let tool;
|
|
2228
|
-
if (typeof prepareOrFinalize === "string") {
|
|
2229
|
-
// Tool ID - use ToolManager for unified resolution
|
|
2230
|
-
tool = this.getToolManager().find(prepareOrFinalize, undefined, step, flow);
|
|
2231
|
-
}
|
|
2232
|
-
else {
|
|
2233
|
-
// Tool object - use directly
|
|
2234
|
-
tool = prepareOrFinalize;
|
|
2235
|
-
}
|
|
2236
|
-
if (tool) {
|
|
2237
|
-
// Use ToolManager for unified tool execution
|
|
2238
|
-
const result = await this.getToolManager().executeTool({
|
|
2239
|
-
tool,
|
|
2240
|
-
context,
|
|
2241
|
-
updateContext: this.agent.updateContext.bind(this.agent),
|
|
2242
|
-
updateData: this.agent.updateCollectedData.bind(this.agent),
|
|
2243
|
-
history: [], // Empty history for prepare/finalize
|
|
2244
|
-
data,
|
|
2245
|
-
});
|
|
2246
|
-
if (!result.success) {
|
|
2247
|
-
utils_1.logger.error(`[ResponseModal] Tool execution failed in prepare/finalize: ${result.error}`);
|
|
2248
|
-
throw new Error(`Tool execution failed: ${result.error}`);
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
else {
|
|
2252
|
-
utils_1.logger.warn(`[ResponseModal] Tool not found for prepare/finalize: ${typeof prepareOrFinalize === "string"
|
|
2253
|
-
? prepareOrFinalize
|
|
2254
|
-
: "inline tool"}`);
|
|
2255
|
-
}
|
|
2256
|
-
}
|
|
2257
|
-
}
|
|
2258
1242
|
}
|
|
2259
1243
|
exports.ResponseModal = ResponseModal;
|
|
2260
1244
|
//# sourceMappingURL=ResponseModal.js.map
|