@falai/agent 1.2.8 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -886
- package/dist/adapters/MemoryAdapter.js +2 -2
- package/dist/adapters/MemoryAdapter.js.map +1 -1
- package/dist/adapters/MongoAdapter.js +2 -2
- package/dist/adapters/MongoAdapter.js.map +1 -1
- package/dist/adapters/OpenSearchAdapter.d.ts.map +1 -1
- package/dist/adapters/OpenSearchAdapter.js +9 -7
- package/dist/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/adapters/PostgreSQLAdapter.d.ts +14 -0
- package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -1
- package/dist/adapters/PostgreSQLAdapter.js +25 -9
- package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/adapters/PrismaAdapter.js +5 -5
- package/dist/adapters/PrismaAdapter.js.map +1 -1
- package/dist/adapters/RedisAdapter.js +2 -2
- package/dist/adapters/RedisAdapter.js.map +1 -1
- package/dist/adapters/SQLiteAdapter.d.ts +17 -0
- package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/adapters/SQLiteAdapter.js +30 -11
- package/dist/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/cjs/adapters/MemoryAdapter.js +2 -2
- package/dist/cjs/adapters/MemoryAdapter.js.map +1 -1
- package/dist/cjs/adapters/MongoAdapter.js +2 -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 +9 -7
- package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.d.ts +14 -0
- package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.js +25 -9
- package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/cjs/adapters/PrismaAdapter.js +5 -5
- package/dist/cjs/adapters/PrismaAdapter.js.map +1 -1
- package/dist/cjs/adapters/RedisAdapter.js +2 -2
- package/dist/cjs/adapters/RedisAdapter.js.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.d.ts +17 -0
- package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.js +30 -11
- package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/cjs/constants/index.d.ts +0 -9
- package/dist/cjs/constants/index.d.ts.map +1 -1
- package/dist/cjs/constants/index.js +2 -11
- package/dist/cjs/constants/index.js.map +1 -1
- package/dist/cjs/core/Agent.d.ts +119 -153
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +471 -324
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/AutoChainExecutor.d.ts +107 -0
- package/dist/cjs/core/AutoChainExecutor.d.ts.map +1 -0
- package/dist/cjs/core/AutoChainExecutor.js +297 -0
- package/dist/cjs/core/AutoChainExecutor.js.map +1 -0
- package/dist/cjs/core/BranchEvaluator.d.ts +54 -0
- package/dist/cjs/core/BranchEvaluator.d.ts.map +1 -0
- package/dist/cjs/core/BranchEvaluator.js +130 -0
- package/dist/cjs/core/BranchEvaluator.js.map +1 -0
- package/dist/cjs/core/DirectiveBus.d.ts +88 -0
- package/dist/cjs/core/DirectiveBus.d.ts.map +1 -0
- package/dist/cjs/core/DirectiveBus.js +196 -0
- package/dist/cjs/core/DirectiveBus.js.map +1 -0
- package/dist/cjs/core/DirectiveChainTracker.d.ts +49 -0
- package/dist/cjs/core/DirectiveChainTracker.d.ts.map +1 -0
- package/dist/cjs/core/DirectiveChainTracker.js +121 -0
- package/dist/cjs/core/DirectiveChainTracker.js.map +1 -0
- package/dist/cjs/core/Flow.d.ts +186 -0
- package/dist/cjs/core/Flow.d.ts.map +1 -0
- package/dist/cjs/core/Flow.js +550 -0
- package/dist/cjs/core/Flow.js.map +1 -0
- package/dist/cjs/core/FlowRouter.d.ts +182 -0
- package/dist/cjs/core/FlowRouter.d.ts.map +1 -0
- package/dist/cjs/core/{RoutingEngine.js → FlowRouter.js} +323 -306
- package/dist/cjs/core/FlowRouter.js.map +1 -0
- package/dist/cjs/core/PersistenceManager.d.ts +2 -2
- package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
- package/dist/cjs/core/PersistenceManager.js +7 -7
- package/dist/cjs/core/PersistenceManager.js.map +1 -1
- package/dist/cjs/core/PromptComposer.d.ts +21 -8
- package/dist/cjs/core/PromptComposer.d.ts.map +1 -1
- package/dist/cjs/core/PromptComposer.js +182 -105
- package/dist/cjs/core/PromptComposer.js.map +1 -1
- package/dist/cjs/core/PromptSectionCache.d.ts +1 -1
- package/dist/cjs/core/PromptSectionCache.js +1 -1
- package/dist/cjs/core/ResponseEngine.d.ts +18 -8
- package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
- package/dist/cjs/core/ResponseEngine.js +38 -36
- package/dist/cjs/core/ResponseEngine.js.map +1 -1
- package/dist/cjs/core/ResponseModal.d.ts +73 -56
- package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
- package/dist/cjs/core/ResponseModal.js +1191 -1014
- package/dist/cjs/core/ResponseModal.js.map +1 -1
- package/dist/cjs/core/ResponsePipeline.d.ts +124 -26
- package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/cjs/core/ResponsePipeline.js +509 -136
- package/dist/cjs/core/ResponsePipeline.js.map +1 -1
- package/dist/cjs/core/SignalEvaluator.d.ts +86 -0
- package/dist/cjs/core/SignalEvaluator.d.ts.map +1 -0
- package/dist/cjs/core/SignalEvaluator.js +333 -0
- package/dist/cjs/core/SignalEvaluator.js.map +1 -0
- package/dist/cjs/core/SignalProcessor.d.ts +152 -0
- package/dist/cjs/core/SignalProcessor.d.ts.map +1 -0
- package/dist/cjs/core/SignalProcessor.js +562 -0
- package/dist/cjs/core/SignalProcessor.js.map +1 -0
- package/dist/cjs/core/Step.d.ts +43 -32
- package/dist/cjs/core/Step.d.ts.map +1 -1
- package/dist/cjs/core/Step.js +221 -126
- package/dist/cjs/core/Step.js.map +1 -1
- package/dist/cjs/core/StreamingToolExecutor.d.ts +2 -2
- package/dist/cjs/core/StreamingToolExecutor.d.ts.map +1 -1
- package/dist/cjs/core/StreamingToolExecutor.js.map +1 -1
- package/dist/cjs/core/ToolManager.d.ts +44 -13
- package/dist/cjs/core/ToolManager.d.ts.map +1 -1
- package/dist/cjs/core/ToolManager.js +174 -91
- package/dist/cjs/core/ToolManager.js.map +1 -1
- package/dist/cjs/core/createAgent.d.ts +35 -0
- package/dist/cjs/core/createAgent.d.ts.map +1 -0
- package/dist/cjs/core/createAgent.js +39 -0
- package/dist/cjs/core/createAgent.js.map +1 -0
- package/dist/cjs/core/flow-namespace.d.ts +49 -0
- package/dist/cjs/core/flow-namespace.d.ts.map +1 -0
- package/dist/cjs/core/flow-namespace.js +171 -0
- package/dist/cjs/core/flow-namespace.js.map +1 -0
- package/dist/cjs/index.d.ts +11 -14
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +18 -22
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +183 -54
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/agent.js +0 -6
- package/dist/cjs/types/agent.js.map +1 -1
- package/dist/cjs/types/ai.d.ts +3 -3
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/cjs/types/errors.d.ts +15 -0
- package/dist/cjs/types/errors.d.ts.map +1 -0
- package/dist/cjs/types/errors.js +22 -0
- package/dist/cjs/types/errors.js.map +1 -0
- package/dist/cjs/types/flow.d.ts +513 -0
- package/dist/cjs/types/flow.d.ts.map +1 -0
- package/dist/cjs/types/{route.js → flow.js} +2 -2
- package/dist/cjs/types/flow.js.map +1 -0
- package/dist/cjs/types/index.d.ts +7 -6
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js +6 -2
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/persistence.d.ts +11 -7
- package/dist/cjs/types/persistence.d.ts.map +1 -1
- package/dist/cjs/types/routing.d.ts +1 -1
- package/dist/cjs/types/routing.d.ts.map +1 -1
- package/dist/cjs/types/session.d.ts +24 -23
- package/dist/cjs/types/session.d.ts.map +1 -1
- package/dist/cjs/types/signals.d.ts +248 -0
- package/dist/cjs/types/signals.d.ts.map +1 -0
- package/dist/cjs/types/signals.js +11 -0
- package/dist/cjs/types/signals.js.map +1 -0
- package/dist/cjs/types/template.d.ts +2 -8
- package/dist/cjs/types/template.d.ts.map +1 -1
- package/dist/cjs/types/tool.d.ts +36 -29
- package/dist/cjs/types/tool.d.ts.map +1 -1
- package/dist/cjs/types/tool.js +1 -1
- package/dist/cjs/types/tool.js.map +1 -1
- package/dist/cjs/utils/condition.d.ts +7 -1
- package/dist/cjs/utils/condition.d.ts.map +1 -1
- package/dist/cjs/utils/condition.js.map +1 -1
- package/dist/cjs/utils/id.d.ts +13 -5
- package/dist/cjs/utils/id.d.ts.map +1 -1
- package/dist/cjs/utils/id.js +24 -10
- package/dist/cjs/utils/id.js.map +1 -1
- package/dist/cjs/utils/index.d.ts +2 -2
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +7 -3
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/session.d.ts +44 -5
- package/dist/cjs/utils/session.d.ts.map +1 -1
- package/dist/cjs/utils/session.js +197 -38
- package/dist/cjs/utils/session.js.map +1 -1
- package/dist/constants/index.d.ts +0 -9
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +3 -9
- package/dist/constants/index.js.map +1 -1
- package/dist/core/Agent.d.ts +119 -153
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +472 -325
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/AutoChainExecutor.d.ts +107 -0
- package/dist/core/AutoChainExecutor.d.ts.map +1 -0
- package/dist/core/AutoChainExecutor.js +293 -0
- package/dist/core/AutoChainExecutor.js.map +1 -0
- package/dist/core/BranchEvaluator.d.ts +54 -0
- package/dist/core/BranchEvaluator.d.ts.map +1 -0
- package/dist/core/BranchEvaluator.js +126 -0
- package/dist/core/BranchEvaluator.js.map +1 -0
- package/dist/core/DirectiveBus.d.ts +88 -0
- package/dist/core/DirectiveBus.d.ts.map +1 -0
- package/dist/core/DirectiveBus.js +192 -0
- package/dist/core/DirectiveBus.js.map +1 -0
- package/dist/core/DirectiveChainTracker.d.ts +49 -0
- package/dist/core/DirectiveChainTracker.d.ts.map +1 -0
- package/dist/core/DirectiveChainTracker.js +117 -0
- package/dist/core/DirectiveChainTracker.js.map +1 -0
- package/dist/core/Flow.d.ts +186 -0
- package/dist/core/Flow.d.ts.map +1 -0
- package/dist/core/Flow.js +546 -0
- package/dist/core/Flow.js.map +1 -0
- package/dist/core/FlowRouter.d.ts +182 -0
- package/dist/core/FlowRouter.d.ts.map +1 -0
- package/dist/core/{RoutingEngine.js → FlowRouter.js} +322 -305
- package/dist/core/FlowRouter.js.map +1 -0
- package/dist/core/PersistenceManager.d.ts +2 -2
- package/dist/core/PersistenceManager.d.ts.map +1 -1
- package/dist/core/PersistenceManager.js +7 -7
- package/dist/core/PersistenceManager.js.map +1 -1
- package/dist/core/PromptComposer.d.ts +21 -8
- package/dist/core/PromptComposer.d.ts.map +1 -1
- package/dist/core/PromptComposer.js +183 -106
- package/dist/core/PromptComposer.js.map +1 -1
- package/dist/core/PromptSectionCache.d.ts +1 -1
- package/dist/core/PromptSectionCache.js +1 -1
- package/dist/core/ResponseEngine.d.ts +18 -8
- package/dist/core/ResponseEngine.d.ts.map +1 -1
- package/dist/core/ResponseEngine.js +38 -36
- package/dist/core/ResponseEngine.js.map +1 -1
- package/dist/core/ResponseModal.d.ts +73 -56
- package/dist/core/ResponseModal.d.ts.map +1 -1
- package/dist/core/ResponseModal.js +1193 -1016
- package/dist/core/ResponseModal.js.map +1 -1
- package/dist/core/ResponsePipeline.d.ts +124 -26
- package/dist/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/core/ResponsePipeline.js +509 -137
- package/dist/core/ResponsePipeline.js.map +1 -1
- package/dist/core/SignalEvaluator.d.ts +86 -0
- package/dist/core/SignalEvaluator.d.ts.map +1 -0
- package/dist/core/SignalEvaluator.js +326 -0
- package/dist/core/SignalEvaluator.js.map +1 -0
- package/dist/core/SignalProcessor.d.ts +152 -0
- package/dist/core/SignalProcessor.d.ts.map +1 -0
- package/dist/core/SignalProcessor.js +555 -0
- package/dist/core/SignalProcessor.js.map +1 -0
- package/dist/core/Step.d.ts +43 -32
- package/dist/core/Step.d.ts.map +1 -1
- package/dist/core/Step.js +220 -126
- package/dist/core/Step.js.map +1 -1
- package/dist/core/StreamingToolExecutor.d.ts +2 -2
- package/dist/core/StreamingToolExecutor.d.ts.map +1 -1
- package/dist/core/StreamingToolExecutor.js.map +1 -1
- package/dist/core/ToolManager.d.ts +44 -13
- package/dist/core/ToolManager.d.ts.map +1 -1
- package/dist/core/ToolManager.js +174 -91
- package/dist/core/ToolManager.js.map +1 -1
- package/dist/core/createAgent.d.ts +35 -0
- package/dist/core/createAgent.d.ts.map +1 -0
- package/dist/core/createAgent.js +36 -0
- package/dist/core/createAgent.js.map +1 -0
- package/dist/core/flow-namespace.d.ts +49 -0
- package/dist/core/flow-namespace.d.ts.map +1 -0
- package/dist/core/flow-namespace.js +168 -0
- package/dist/core/flow-namespace.js.map +1 -0
- package/dist/index.d.ts +11 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -12
- package/dist/index.js.map +1 -1
- package/dist/types/agent.d.ts +183 -54
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/agent.js +0 -6
- package/dist/types/agent.js.map +1 -1
- package/dist/types/ai.d.ts +3 -3
- package/dist/types/ai.d.ts.map +1 -1
- package/dist/types/errors.d.ts +15 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +18 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/flow.d.ts +513 -0
- package/dist/types/flow.d.ts.map +1 -0
- package/dist/types/flow.js +5 -0
- package/dist/types/flow.js.map +1 -0
- package/dist/types/index.d.ts +7 -6
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +4 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/persistence.d.ts +11 -7
- package/dist/types/persistence.d.ts.map +1 -1
- package/dist/types/routing.d.ts +1 -1
- package/dist/types/routing.d.ts.map +1 -1
- package/dist/types/session.d.ts +24 -23
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/signals.d.ts +248 -0
- package/dist/types/signals.d.ts.map +1 -0
- package/dist/types/signals.js +10 -0
- package/dist/types/signals.js.map +1 -0
- package/dist/types/template.d.ts +2 -8
- package/dist/types/template.d.ts.map +1 -1
- package/dist/types/tool.d.ts +36 -29
- package/dist/types/tool.d.ts.map +1 -1
- package/dist/types/tool.js +1 -1
- package/dist/types/tool.js.map +1 -1
- package/dist/utils/condition.d.ts +7 -1
- package/dist/utils/condition.d.ts.map +1 -1
- package/dist/utils/condition.js.map +1 -1
- package/dist/utils/id.d.ts +13 -5
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +22 -9
- package/dist/utils/id.js.map +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -2
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/session.d.ts +44 -5
- package/dist/utils/session.d.ts.map +1 -1
- package/dist/utils/session.js +193 -37
- package/dist/utils/session.js.map +1 -1
- package/docs/README.md +15 -202
- package/docs/concepts/architecture.md +281 -0
- package/docs/concepts/directives.md +400 -0
- package/docs/concepts/pipeline.md +399 -0
- package/docs/guides/branching.md +263 -0
- package/docs/guides/compaction.md +163 -0
- package/docs/guides/conditions.md +167 -0
- package/docs/guides/error-handling.md +176 -0
- package/docs/guides/flow-control.md +409 -0
- package/docs/guides/instructions.md +210 -0
- package/docs/guides/persistence.md +182 -0
- package/docs/guides/streaming.md +137 -0
- package/docs/migration/README.md +15 -0
- package/docs/migration/route-to-flow.md +560 -0
- package/docs/migration/v1-to-v2.md +909 -0
- package/docs/reference/adapters.md +481 -0
- package/docs/reference/branches.md +241 -0
- package/docs/reference/create-agent.md +186 -0
- package/docs/reference/directive.md +243 -0
- package/docs/reference/errors.md +122 -0
- package/docs/reference/flow.md +238 -0
- package/docs/reference/instruction.md +177 -0
- package/docs/reference/pre-directive.md +131 -0
- package/docs/reference/providers.md +227 -0
- package/docs/reference/signals.md +356 -0
- package/docs/reference/step.md +339 -0
- package/docs/reference/tool.md +269 -0
- package/docs/start/01-install.md +81 -0
- package/docs/start/02-first-agent.md +196 -0
- package/docs/start/03-collect-data.md +222 -0
- package/docs/start/04-add-tools.md +276 -0
- package/docs/start/05-go-to-production.md +216 -0
- package/examples/01-quickstart.ts +20 -0
- package/examples/02-data-extraction.ts +90 -0
- package/examples/03-tools.ts +136 -0
- package/examples/04-instructions.ts +100 -0
- package/examples/05-branching.ts +140 -0
- package/examples/06-flow-control.ts +103 -0
- package/examples/07-streaming.ts +69 -0
- package/examples/08-persistence.ts +98 -0
- package/examples/09-signals.ts +144 -0
- package/examples/tsconfig.json +30 -0
- package/package.json +2 -1
- package/src/adapters/MemoryAdapter.ts +3 -3
- package/src/adapters/MongoAdapter.ts +3 -3
- package/src/adapters/OpenSearchAdapter.ts +10 -8
- package/src/adapters/PostgreSQLAdapter.ts +26 -10
- package/src/adapters/PrismaAdapter.ts +6 -6
- package/src/adapters/RedisAdapter.ts +3 -3
- package/src/adapters/SQLiteAdapter.ts +31 -12
- package/src/constants/index.ts +2 -10
- package/src/core/Agent.ts +585 -374
- package/src/core/AutoChainExecutor.ts +440 -0
- package/src/core/BranchEvaluator.ts +167 -0
- package/src/core/DirectiveBus.ts +248 -0
- package/src/core/DirectiveChainTracker.ts +144 -0
- package/src/core/Flow.ts +666 -0
- package/src/core/{RoutingEngine.ts → FlowRouter.ts} +385 -365
- package/src/core/PersistenceManager.ts +8 -8
- package/src/core/PromptComposer.ts +209 -140
- package/src/core/PromptSectionCache.ts +1 -1
- package/src/core/ResponseEngine.ts +61 -46
- package/src/core/ResponseModal.ts +1453 -1240
- package/src/core/ResponsePipeline.ts +655 -175
- package/src/core/SignalEvaluator.ts +420 -0
- package/src/core/SignalProcessor.ts +723 -0
- package/src/core/Step.ts +279 -176
- package/src/core/StreamingToolExecutor.ts +4 -4
- package/src/core/ToolManager.ts +200 -97
- package/src/core/createAgent.ts +40 -0
- package/src/core/flow-namespace.ts +219 -0
- package/src/index.ts +42 -36
- package/src/types/agent.ts +182 -53
- package/src/types/ai.ts +3 -3
- package/src/types/errors.ts +18 -0
- package/src/types/flow.ts +590 -0
- package/src/types/index.ts +43 -16
- package/src/types/persistence.ts +12 -8
- package/src/types/routing.ts +1 -1
- package/src/types/session.ts +26 -23
- package/src/types/signals.ts +321 -0
- package/src/types/template.ts +3 -11
- package/src/types/tool.ts +50 -42
- package/src/utils/condition.ts +13 -4
- package/src/utils/id.ts +27 -9
- package/src/utils/index.ts +6 -2
- package/src/utils/session.ts +238 -42
- package/dist/cjs/core/BatchExecutor.d.ts +0 -359
- package/dist/cjs/core/BatchExecutor.d.ts.map +0 -1
- package/dist/cjs/core/BatchExecutor.js +0 -861
- package/dist/cjs/core/BatchExecutor.js.map +0 -1
- package/dist/cjs/core/BatchPromptBuilder.d.ts +0 -89
- package/dist/cjs/core/BatchPromptBuilder.d.ts.map +0 -1
- package/dist/cjs/core/BatchPromptBuilder.js +0 -223
- package/dist/cjs/core/BatchPromptBuilder.js.map +0 -1
- package/dist/cjs/core/Route.d.ts +0 -180
- package/dist/cjs/core/Route.d.ts.map +0 -1
- package/dist/cjs/core/Route.js +0 -542
- package/dist/cjs/core/Route.js.map +0 -1
- package/dist/cjs/core/RoutingEngine.d.ts +0 -185
- package/dist/cjs/core/RoutingEngine.d.ts.map +0 -1
- package/dist/cjs/core/RoutingEngine.js.map +0 -1
- package/dist/cjs/types/route.d.ts +0 -336
- package/dist/cjs/types/route.d.ts.map +0 -1
- package/dist/cjs/types/route.js.map +0 -1
- package/dist/core/BatchExecutor.d.ts +0 -359
- package/dist/core/BatchExecutor.d.ts.map +0 -1
- package/dist/core/BatchExecutor.js +0 -856
- package/dist/core/BatchExecutor.js.map +0 -1
- package/dist/core/BatchPromptBuilder.d.ts +0 -89
- package/dist/core/BatchPromptBuilder.d.ts.map +0 -1
- package/dist/core/BatchPromptBuilder.js +0 -219
- package/dist/core/BatchPromptBuilder.js.map +0 -1
- package/dist/core/Route.d.ts +0 -180
- package/dist/core/Route.d.ts.map +0 -1
- package/dist/core/Route.js +0 -538
- package/dist/core/Route.js.map +0 -1
- package/dist/core/RoutingEngine.d.ts +0 -185
- package/dist/core/RoutingEngine.d.ts.map +0 -1
- package/dist/core/RoutingEngine.js.map +0 -1
- package/dist/types/route.d.ts +0 -336
- package/dist/types/route.d.ts.map +0 -1
- package/dist/types/route.js +0 -5
- package/dist/types/route.js.map +0 -1
- package/docs/CONTRIBUTING.md +0 -521
- package/docs/api/README.md +0 -3299
- package/docs/api/overview.md +0 -1410
- package/docs/architecture/data-extraction-flow.md +0 -360
- package/docs/architecture/multi-step-execution.md +0 -277
- package/docs/core/agent/README.md +0 -938
- package/docs/core/agent/context-management.md +0 -796
- package/docs/core/agent/rules-and-prohibitions.md +0 -113
- package/docs/core/agent/session-management.md +0 -693
- package/docs/core/ai-integration/prompt-composition.md +0 -355
- package/docs/core/ai-integration/providers.md +0 -515
- package/docs/core/ai-integration/response-processing.md +0 -433
- package/docs/core/conversation-flows/data-collection.md +0 -772
- package/docs/core/conversation-flows/route-dsl.md +0 -509
- package/docs/core/conversation-flows/routes.md +0 -249
- package/docs/core/conversation-flows/step-transitions.md +0 -731
- package/docs/core/conversation-flows/steps.md +0 -268
- package/docs/core/error-handling.md +0 -830
- package/docs/core/persistence/adapters.md +0 -255
- package/docs/core/persistence/session-storage.md +0 -656
- package/docs/core/routing/intelligent-routing.md +0 -470
- package/docs/core/tools/enhanced-tool.md +0 -186
- package/docs/core/tools/streaming-execution.md +0 -161
- package/docs/core/tools/tool-definition.md +0 -970
- package/docs/core/tools/tool-scoping.md +0 -819
- package/docs/guides/advanced-patterns/publishing.md +0 -186
- package/docs/guides/context-compaction.md +0 -96
- package/docs/guides/error-handling-patterns.md +0 -578
- package/docs/guides/getting-started/README.md +0 -795
- package/docs/guides/migration/README.md +0 -101
- package/docs/guides/migration/flexible-routing-conditions.md +0 -375
- package/docs/guides/migration/multi-step-execution.md +0 -393
- package/docs/guides/migration/response-modal-refactor.md +0 -518
- package/docs/guides/prompt-optimization.md +0 -164
- package/examples/advanced-patterns/context-compaction.ts +0 -223
- package/examples/advanced-patterns/knowledge-based-agent.ts +0 -735
- package/examples/advanced-patterns/persistent-onboarding.ts +0 -728
- package/examples/advanced-patterns/route-lifecycle-hooks.ts +0 -556
- package/examples/advanced-patterns/streaming-responses.ts +0 -656
- package/examples/ai-providers/anthropic-integration.ts +0 -388
- package/examples/ai-providers/openai-integration.ts +0 -228
- package/examples/condition-patterns/function-only-conditions.ts +0 -365
- package/examples/condition-patterns/mixed-array-conditions.ts +0 -477
- package/examples/condition-patterns/route-skipif-patterns.ts +0 -468
- package/examples/condition-patterns/step-skipif-patterns.ts +0 -0
- package/examples/condition-patterns/string-only-conditions.ts +0 -296
- package/examples/conversation-flows/completion-transitions.ts +0 -318
- package/examples/core-concepts/basic-agent.ts +0 -503
- package/examples/core-concepts/modern-streaming-api.ts +0 -309
- package/examples/core-concepts/schema-driven-extraction.ts +0 -332
- package/examples/core-concepts/session-management.ts +0 -494
- package/examples/integrations/database-integration.ts +0 -631
- package/examples/integrations/healthcare-integration.ts +0 -595
- package/examples/integrations/search-integration.ts +0 -530
- package/examples/integrations/server-session-management.ts +0 -307
- package/examples/persistence/custom-adapter.ts +0 -526
- package/examples/persistence/database-persistence.ts +0 -583
- package/examples/persistence/memory-sessions.ts +0 -495
- package/examples/persistence/prisma-schema.example.prisma +0 -74
- package/examples/persistence/redis-persistence.ts +0 -488
- package/examples/tools/basic-tools.ts +0 -765
- package/examples/tools/data-enrichment-tools.ts +0 -593
- package/examples/tools/enhanced-tool-metadata.ts +0 -268
- package/examples/tools/streaming-tool-execution.ts +0 -283
- package/src/core/BatchExecutor.ts +0 -1187
- package/src/core/BatchPromptBuilder.ts +0 -299
- package/src/core/Route.ts +0 -678
- package/src/types/route.ts +0 -392
|
@@ -8,25 +8,52 @@ import type {
|
|
|
8
8
|
SessionState,
|
|
9
9
|
AgentStructuredResponse,
|
|
10
10
|
Tool,
|
|
11
|
-
|
|
11
|
+
Directive,
|
|
12
|
+
PreDirective,
|
|
12
13
|
} from "../types";
|
|
14
|
+
import type { SignalFiring } from "../types/signals";
|
|
15
|
+
import type { SignalProcessor } from "./SignalProcessor";
|
|
13
16
|
import type { HistoryItem } from "../types/history";
|
|
14
17
|
import {
|
|
15
18
|
createSession,
|
|
16
|
-
enterRoute,
|
|
17
19
|
enterStep,
|
|
18
20
|
mergeCollected,
|
|
21
|
+
completeCurrentFlow,
|
|
19
22
|
logger,
|
|
20
|
-
render,
|
|
21
23
|
historyToEvents,
|
|
22
24
|
serializeToolResult,
|
|
23
25
|
} from "../utils";
|
|
26
|
+
import { enterFlow } from "../utils/session";
|
|
24
27
|
import { createTemplateContext } from "../utils/template";
|
|
25
|
-
import {
|
|
26
|
-
import { Step } from "../core/Step";
|
|
27
|
-
import {
|
|
28
|
+
import { Flow } from "./Flow";
|
|
29
|
+
import { Step, FlowConfigurationError } from "../core/Step";
|
|
30
|
+
import { FlowRouter } from "./FlowRouter";
|
|
28
31
|
import type { ToolManager } from "../core/ToolManager";
|
|
29
|
-
import {
|
|
32
|
+
import { evaluateBranches, createAiConditionEvaluator } from "./BranchEvaluator";
|
|
33
|
+
import { DirectiveChainTracker } from "./DirectiveChainTracker";
|
|
34
|
+
import { DirectiveBus } from "./DirectiveBus";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Position fields on a Directive that represent a navigation decision.
|
|
38
|
+
* When any of these is set, the directive "wins" the turn's position decision
|
|
39
|
+
* and downstream resolution (branches, linear, AI) must not run.
|
|
40
|
+
*/
|
|
41
|
+
const DIRECTIVE_POSITION_FIELDS = ['goTo', 'goToStep', 'complete', 'abort', 'reset'] as const;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Returns `true` if the given directive has at least one position field set.
|
|
45
|
+
* Used as the guard at the directive-bus / branch-evaluation seam:
|
|
46
|
+
* if the bus produced a winner with a position field, `evaluateStepBranches`
|
|
47
|
+
* (and linear/AI selection) must not run.
|
|
48
|
+
*/
|
|
49
|
+
export function hasDirectivePositionField<TContext = unknown, TData = unknown>(
|
|
50
|
+
directive: Directive<TContext, TData> | undefined | null,
|
|
51
|
+
): boolean {
|
|
52
|
+
if (!directive) return false;
|
|
53
|
+
return DIRECTIVE_POSITION_FIELDS.some(
|
|
54
|
+
(field) => (directive as Record<string, unknown>)[field] !== undefined,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
30
57
|
|
|
31
58
|
export interface ResponsePreparationResult<TContext, TData = unknown> {
|
|
32
59
|
effectiveContext: TContext;
|
|
@@ -34,12 +61,12 @@ export interface ResponsePreparationResult<TContext, TData = unknown> {
|
|
|
34
61
|
}
|
|
35
62
|
|
|
36
63
|
export interface RoutingResult<TContext, TData = unknown> {
|
|
37
|
-
|
|
64
|
+
selectedFlow: Flow<TContext, TData> | undefined;
|
|
38
65
|
selectedStep: Step<TContext, TData> | undefined;
|
|
39
66
|
responseDirectives: string[] | undefined;
|
|
40
67
|
session: SessionState<TData>;
|
|
41
|
-
|
|
42
|
-
|
|
68
|
+
isFlowComplete: boolean;
|
|
69
|
+
completedFlows?: Flow<TContext, TData>[];
|
|
43
70
|
}
|
|
44
71
|
|
|
45
72
|
export interface ToolExecutionResult<TData = unknown> {
|
|
@@ -60,11 +87,18 @@ export interface DataCollectionResult<TData = unknown> {
|
|
|
60
87
|
* Shared response processing logic between respond() and respondStream() methods
|
|
61
88
|
*/
|
|
62
89
|
export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
90
|
+
/**
|
|
91
|
+
* Per-turn directive chain tracker. Created fresh at the start of each turn
|
|
92
|
+
* via `createChainTracker()`. Used by directive application points to detect
|
|
93
|
+
* infinite redirection loops.
|
|
94
|
+
*/
|
|
95
|
+
private _chainTracker: DirectiveChainTracker | undefined;
|
|
96
|
+
|
|
63
97
|
constructor(
|
|
64
98
|
private readonly options: AgentOptions<TContext, TData>,
|
|
65
|
-
private readonly
|
|
99
|
+
private readonly getFlows: () => Flow<TContext, TData>[],
|
|
66
100
|
private readonly tools: Tool<TContext, TData>[],
|
|
67
|
-
private readonly
|
|
101
|
+
private readonly flowRouter: FlowRouter<TContext, TData>,
|
|
68
102
|
private readonly updateContext: (
|
|
69
103
|
updates: Partial<TContext>
|
|
70
104
|
) => Promise<void>,
|
|
@@ -75,9 +109,108 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
75
109
|
private readonly updateCollectedData?: (
|
|
76
110
|
updates: Partial<TData>
|
|
77
111
|
) => Promise<void>,
|
|
78
|
-
private readonly toolManager?: ToolManager<TContext, TData
|
|
112
|
+
private readonly toolManager?: ToolManager<TContext, TData>,
|
|
113
|
+
private readonly signalProcessor?: SignalProcessor<TContext, TData>
|
|
79
114
|
) { }
|
|
80
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Create a fresh chain tracker for the current turn.
|
|
118
|
+
* Call at the start of each turn; the tracker is discarded at turn end.
|
|
119
|
+
*/
|
|
120
|
+
createChainTracker(): DirectiveChainTracker {
|
|
121
|
+
const maxChain = this.options.maxDirectiveChain ?? 10;
|
|
122
|
+
this._chainTracker = new DirectiveChainTracker(maxChain);
|
|
123
|
+
return this._chainTracker;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get the current turn's chain tracker (creates one if none exists).
|
|
128
|
+
*/
|
|
129
|
+
get chainTracker(): DirectiveChainTracker {
|
|
130
|
+
if (!this._chainTracker) {
|
|
131
|
+
return this.createChainTracker();
|
|
132
|
+
}
|
|
133
|
+
return this._chainTracker;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Create a fresh DirectiveBus for a new turn.
|
|
138
|
+
* The bus collects directives from hooks, tools, and branches during the turn
|
|
139
|
+
* and merges them at phase boundaries via Algorithm 4.
|
|
140
|
+
*/
|
|
141
|
+
createDirectiveBus(): DirectiveBus<TContext, TData> {
|
|
142
|
+
return new DirectiveBus<TContext, TData>();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
146
|
+
// Signal pipeline phases
|
|
147
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* PRE-SIGNAL PHASE — Evaluates pre/both signals in parallel with routing.
|
|
151
|
+
*
|
|
152
|
+
* Delegates to `signalProcessor.runPreSignalPhase(...)` when configured.
|
|
153
|
+
* When no signal processor is present (zero-cost path), returns a stable
|
|
154
|
+
* empty shape so callers don't need to branch.
|
|
155
|
+
*
|
|
156
|
+
* @requirements 2.1, 2.3, 8.6, 13.3
|
|
157
|
+
*/
|
|
158
|
+
async runPreSignalPhase(
|
|
159
|
+
session: SessionState<TData>,
|
|
160
|
+
context: TContext,
|
|
161
|
+
history: Event[],
|
|
162
|
+
): Promise<{
|
|
163
|
+
firings: SignalFiring<TContext, TData>[];
|
|
164
|
+
updatedSession: SessionState<TData>;
|
|
165
|
+
mergedDirective: PreDirective<TContext, TData> | undefined;
|
|
166
|
+
}> {
|
|
167
|
+
if (!this.signalProcessor) {
|
|
168
|
+
return { firings: [], updatedSession: session, mergedDirective: undefined };
|
|
169
|
+
}
|
|
170
|
+
const result = await this.signalProcessor.runPreSignalPhase({ session, history, context });
|
|
171
|
+
return {
|
|
172
|
+
firings: result.firings,
|
|
173
|
+
updatedSession: result.updatedSession,
|
|
174
|
+
mergedDirective: result.mergedDirective,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* POST-SIGNAL PHASE — Evaluates post/both signals after finalize/onComplete.
|
|
180
|
+
*
|
|
181
|
+
* Delegates to `signalProcessor.runPostSignalPhase(...)` when configured.
|
|
182
|
+
* When no signal processor is present, returns a stable empty shape.
|
|
183
|
+
*
|
|
184
|
+
* Post-phase signals see the complete turn result: assistant message in history,
|
|
185
|
+
* collected data, tool results. Position directives from this phase set
|
|
186
|
+
* `session.pendingDirective` (no mid-turn re-entry per D6 decision).
|
|
187
|
+
*
|
|
188
|
+
* Pre-LLM-only fields (`appendPrompt`, `injectTools`, `halt`) are already
|
|
189
|
+
* dropped inside `runPostSignalPhase` per Phase 4.5 — this seam does NOT
|
|
190
|
+
* re-introduce them.
|
|
191
|
+
*
|
|
192
|
+
* @requirements 9.1, 9.2, 9.3, 9.4
|
|
193
|
+
*/
|
|
194
|
+
async runPostSignalPhase(
|
|
195
|
+
session: SessionState<TData>,
|
|
196
|
+
context: TContext,
|
|
197
|
+
history: Event[],
|
|
198
|
+
): Promise<{
|
|
199
|
+
firings: SignalFiring<TContext, TData>[];
|
|
200
|
+
updatedSession: SessionState<TData>;
|
|
201
|
+
mergedDirective: Directive<TContext, TData> | undefined;
|
|
202
|
+
}> {
|
|
203
|
+
if (!this.signalProcessor) {
|
|
204
|
+
return { firings: [], updatedSession: session, mergedDirective: undefined };
|
|
205
|
+
}
|
|
206
|
+
const result = await this.signalProcessor.runPostSignalPhase({ session, history, context });
|
|
207
|
+
return {
|
|
208
|
+
firings: result.firings,
|
|
209
|
+
updatedSession: result.updatedSession,
|
|
210
|
+
mergedDirective: result.mergedDirective,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
81
214
|
/**
|
|
82
215
|
* Prepare context and session for response generation
|
|
83
216
|
*/
|
|
@@ -123,63 +256,169 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
123
256
|
}): Promise<RoutingResult<TContext, TData>> {
|
|
124
257
|
const { session, history, context, signal } = params;
|
|
125
258
|
|
|
126
|
-
// PHASE 2: ROUTING + STEP SELECTION - Determine which
|
|
127
|
-
let
|
|
259
|
+
// PHASE 2: ROUTING + STEP SELECTION - Determine which flow and step to use (combined)
|
|
260
|
+
let selectedFlow: Flow<TContext, TData> | undefined;
|
|
128
261
|
let responseDirectives: string[] | undefined;
|
|
129
262
|
let selectedStep: Step<TContext, TData> | undefined;
|
|
130
|
-
let
|
|
131
|
-
let
|
|
263
|
+
let isFlowComplete = false;
|
|
264
|
+
let completedFlows: Flow<TContext, TData>[] = [];
|
|
132
265
|
let targetSession = session;
|
|
133
266
|
|
|
134
|
-
// Get
|
|
135
|
-
const
|
|
267
|
+
// Get flows early since we need them for pending directives
|
|
268
|
+
const flows = this.getFlows();
|
|
136
269
|
|
|
137
|
-
// Check for pending
|
|
138
|
-
if (targetSession.
|
|
139
|
-
const
|
|
140
|
-
|
|
270
|
+
// Check for pending directive from previous flow completion or external dispatch
|
|
271
|
+
if (targetSession.pendingDirective) {
|
|
272
|
+
const directive = targetSession.pendingDirective;
|
|
273
|
+
logger.debug(
|
|
274
|
+
`[ResponseHandler] Applying pending directive at start of turn`
|
|
141
275
|
);
|
|
142
276
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
277
|
+
// Track directive chain depth (Requirement 22.1)
|
|
278
|
+
const tracker = this.chainTracker;
|
|
279
|
+
tracker.record(directive, "pending");
|
|
280
|
+
// If abort (chain breaker), the tracker stops counting; apply normally below
|
|
281
|
+
|
|
282
|
+
// Clear pendingDirective before application (unless complete.next chains another)
|
|
283
|
+
let nextDirective: typeof targetSession.pendingDirective | undefined = undefined;
|
|
284
|
+
if (
|
|
285
|
+
directive.complete &&
|
|
286
|
+
typeof directive.complete === 'object' &&
|
|
287
|
+
directive.complete.next
|
|
288
|
+
) {
|
|
289
|
+
nextDirective = directive.complete.next;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
targetSession = {
|
|
293
|
+
...targetSession,
|
|
294
|
+
pendingDirective: nextDirective,
|
|
295
|
+
};
|
|
157
296
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
297
|
+
// Apply the directive: resolve position field to a flow/step
|
|
298
|
+
if (directive.goTo) {
|
|
299
|
+
const flowTarget = typeof directive.goTo === 'string'
|
|
300
|
+
? directive.goTo
|
|
301
|
+
: directive.goTo.flow;
|
|
302
|
+
|
|
303
|
+
if (flowTarget) {
|
|
304
|
+
const targetFlow = flows.find(
|
|
305
|
+
(r) => r.id === flowTarget || r.title === flowTarget
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
if (targetFlow) {
|
|
309
|
+
logger.debug(
|
|
310
|
+
`[ResponseHandler] Pending directive goTo → flow: ${targetFlow.title}`
|
|
311
|
+
);
|
|
312
|
+
targetSession = enterFlow(
|
|
313
|
+
targetSession,
|
|
314
|
+
targetFlow.id,
|
|
315
|
+
targetFlow.title
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
// Merge initial data if available
|
|
319
|
+
if (targetFlow.initialData) {
|
|
320
|
+
targetSession = mergeCollected(
|
|
321
|
+
targetSession,
|
|
322
|
+
targetFlow.initialData
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Merge directive-carried data if present
|
|
327
|
+
if (typeof directive.goTo === 'object' && directive.goTo.data) {
|
|
328
|
+
targetSession = mergeCollected(
|
|
329
|
+
targetSession,
|
|
330
|
+
directive.goTo.data
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
selectedFlow = targetFlow;
|
|
335
|
+
|
|
336
|
+
// If goTo specifies a step, enter it
|
|
337
|
+
if (typeof directive.goTo === 'object' && directive.goTo.step) {
|
|
338
|
+
const stepTarget = directive.goTo.step;
|
|
339
|
+
const targetStep = targetFlow.getStep(stepTarget);
|
|
340
|
+
if (targetStep) {
|
|
341
|
+
targetSession = enterStep(targetSession, targetStep.id, targetStep.description);
|
|
342
|
+
selectedStep = targetStep;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
logger.warn(
|
|
347
|
+
`[FlowConfigurationError] Pending directive goTo target not found: flow "${flowTarget}" does not exist. Falling back to normal routing. Fix the goTo reference or remove the pending directive.`
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
} else if (directive.goToStep) {
|
|
352
|
+
const stepTarget = typeof directive.goToStep === 'string'
|
|
353
|
+
? directive.goToStep
|
|
354
|
+
: directive.goToStep.step;
|
|
355
|
+
const flowTarget = typeof directive.goToStep === 'object'
|
|
356
|
+
? directive.goToStep.flow
|
|
357
|
+
: undefined;
|
|
358
|
+
|
|
359
|
+
if (flowTarget) {
|
|
360
|
+
const targetFlow = flows.find(
|
|
361
|
+
(r) => r.id === flowTarget || r.title === flowTarget
|
|
163
362
|
);
|
|
363
|
+
if (targetFlow) {
|
|
364
|
+
targetSession = enterFlow(targetSession, targetFlow.id, targetFlow.title);
|
|
365
|
+
selectedFlow = targetFlow;
|
|
366
|
+
const targetStep = targetFlow.getStep(stepTarget);
|
|
367
|
+
if (targetStep) {
|
|
368
|
+
targetSession = enterStep(targetSession, targetStep.id, targetStep.description);
|
|
369
|
+
selectedStep = targetStep;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
} else if (targetSession.currentFlow) {
|
|
373
|
+
// Step within current flow
|
|
374
|
+
const currentFlow = flows.find(r => r.id === targetSession.currentFlow?.id);
|
|
375
|
+
if (currentFlow) {
|
|
376
|
+
selectedFlow = currentFlow;
|
|
377
|
+
const targetStep = currentFlow.getStep(stepTarget);
|
|
378
|
+
if (targetStep) {
|
|
379
|
+
targetSession = enterStep(targetSession, targetStep.id, targetStep.description);
|
|
380
|
+
selectedStep = targetStep;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
} else if (directive.reset) {
|
|
385
|
+
// Reset current flow
|
|
386
|
+
if (targetSession.currentFlow) {
|
|
387
|
+
const currentFlow = flows.find(r => r.id === targetSession.currentFlow?.id);
|
|
388
|
+
if (currentFlow) {
|
|
389
|
+
const resetStep = typeof directive.reset === 'object' && directive.reset.step
|
|
390
|
+
? directive.reset.step
|
|
391
|
+
: undefined;
|
|
392
|
+
selectedFlow = currentFlow;
|
|
393
|
+
if (resetStep) {
|
|
394
|
+
const targetStep = currentFlow.getStep(resetStep);
|
|
395
|
+
if (targetStep) {
|
|
396
|
+
targetSession = enterStep(targetSession, targetStep.id, targetStep.description);
|
|
397
|
+
selectedStep = targetStep;
|
|
398
|
+
}
|
|
399
|
+
} else {
|
|
400
|
+
// Reset to initial step
|
|
401
|
+
const initialStep = currentFlow.initialStep;
|
|
402
|
+
targetSession = enterStep(targetSession, initialStep.id, initialStep.description);
|
|
403
|
+
selectedStep = initialStep;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
164
406
|
}
|
|
407
|
+
}
|
|
408
|
+
// For complete/abort, selectedFlow stays undefined → handled downstream
|
|
165
409
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
`[ResponseHandler] Pending transition target route not found: ${targetSession.pendingTransition.targetRouteId}`
|
|
170
|
-
);
|
|
171
|
-
// Clear invalid transition
|
|
172
|
-
targetSession = {
|
|
173
|
-
...targetSession,
|
|
174
|
-
pendingTransition: undefined,
|
|
175
|
-
};
|
|
410
|
+
// Apply state writes from the directive
|
|
411
|
+
if (directive.dataUpdate) {
|
|
412
|
+
targetSession = mergeCollected(targetSession, directive.dataUpdate);
|
|
176
413
|
}
|
|
414
|
+
|
|
415
|
+
// Skip FlowRouter.decideFlowAndStep — the directive resolved the position
|
|
177
416
|
}
|
|
178
417
|
|
|
179
418
|
// If no pending transition or transition handled, do normal routing
|
|
180
|
-
if (
|
|
181
|
-
const orchestration = await this.
|
|
182
|
-
|
|
419
|
+
if (flows.length > 0 && !selectedFlow) {
|
|
420
|
+
const orchestration = await this.flowRouter.decideFlowAndStep({
|
|
421
|
+
flows: flows,
|
|
183
422
|
session: targetSession,
|
|
184
423
|
history,
|
|
185
424
|
agentOptions: this.options,
|
|
@@ -188,28 +427,28 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
188
427
|
signal,
|
|
189
428
|
});
|
|
190
429
|
|
|
191
|
-
|
|
430
|
+
selectedFlow = orchestration.selectedFlow;
|
|
192
431
|
selectedStep = orchestration.selectedStep;
|
|
193
432
|
responseDirectives = orchestration.responseDirectives;
|
|
194
433
|
targetSession = orchestration.session;
|
|
195
|
-
|
|
196
|
-
|
|
434
|
+
isFlowComplete = orchestration.isFlowComplete || false;
|
|
435
|
+
completedFlows = orchestration.completedFlows || [];
|
|
197
436
|
|
|
198
|
-
// Log if
|
|
199
|
-
if (
|
|
437
|
+
// Log if flow is complete
|
|
438
|
+
if (isFlowComplete) {
|
|
200
439
|
logger.debug(
|
|
201
|
-
`[ResponseHandler]
|
|
440
|
+
`[ResponseHandler] Flow complete: all required data collected or last step reached`
|
|
202
441
|
);
|
|
203
442
|
}
|
|
204
443
|
}
|
|
205
444
|
|
|
206
445
|
return {
|
|
207
|
-
|
|
446
|
+
selectedFlow,
|
|
208
447
|
selectedStep,
|
|
209
448
|
responseDirectives,
|
|
210
449
|
session: targetSession,
|
|
211
|
-
|
|
212
|
-
|
|
450
|
+
isFlowComplete,
|
|
451
|
+
completedFlows,
|
|
213
452
|
};
|
|
214
453
|
}
|
|
215
454
|
|
|
@@ -217,14 +456,52 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
217
456
|
* Determine next step and update session
|
|
218
457
|
*/
|
|
219
458
|
async determineNextStep(params: {
|
|
220
|
-
|
|
459
|
+
selectedFlow: Flow<TContext, TData> | undefined;
|
|
221
460
|
selectedStep: Step<TContext, TData> | undefined;
|
|
222
461
|
session: SessionState<TData>;
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
462
|
+
isFlowComplete: boolean;
|
|
463
|
+
/** Merged directive from the directive bus (pre-LLM + post-LLM phases). */
|
|
464
|
+
busDirective?: Directive<TContext, TData>;
|
|
465
|
+
}): Promise<{ nextStep: Step<TContext, TData> | undefined; session: SessionState<TData>; flowChanged?: Flow<TContext, TData> }> {
|
|
466
|
+
const { selectedFlow, selectedStep, session, isFlowComplete, busDirective } = params;
|
|
467
|
+
|
|
468
|
+
if (!selectedFlow) {
|
|
469
|
+
return { nextStep: undefined, session };
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// ─── GUARD: directive bus winner with a position field preempts branches ───
|
|
473
|
+
// Resolution precedence (design.md): bus > branches > linear > AI.
|
|
474
|
+
// If the bus produced a directive with a position field (goTo, goToStep,
|
|
475
|
+
// complete, abort, reset), that decision wins the turn. Do NOT evaluate
|
|
476
|
+
// branches or linear/AI selection — the caller applies the bus directive.
|
|
477
|
+
if (hasDirectivePositionField(busDirective)) {
|
|
478
|
+
logger.debug(
|
|
479
|
+
`[ResponseHandler] Directive bus winner has position field — skipping branch evaluation and linear/AI selection`,
|
|
480
|
+
);
|
|
481
|
+
return { nextStep: undefined, session };
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// STEP 1 (Algorithm 1): branches win over linear chain AND flow completion.
|
|
485
|
+
// Evaluate branches before checking isFlowComplete — a branch can redirect
|
|
486
|
+
// even from the "last" step (which getCandidateStepsWithConditions marks as complete).
|
|
487
|
+
if (!selectedStep) {
|
|
488
|
+
const currentStep = session.currentFlow?.id === selectedFlow.id && session.currentStep
|
|
489
|
+
? selectedFlow.getStep(session.currentStep.id)
|
|
490
|
+
: undefined;
|
|
491
|
+
|
|
492
|
+
if (currentStep?.branches && currentStep.branches.length > 0) {
|
|
493
|
+
const contextToUse = this.getStoredContext();
|
|
494
|
+
const branchResult = await this.evaluateStepBranches(
|
|
495
|
+
currentStep, selectedFlow, session, contextToUse as TContext
|
|
496
|
+
);
|
|
497
|
+
if (branchResult) {
|
|
498
|
+
return branchResult;
|
|
499
|
+
}
|
|
500
|
+
// undefined → fall through to linear/AI selection or flow completion
|
|
501
|
+
}
|
|
502
|
+
}
|
|
226
503
|
|
|
227
|
-
if (
|
|
504
|
+
if (isFlowComplete) {
|
|
228
505
|
return { nextStep: undefined, session };
|
|
229
506
|
}
|
|
230
507
|
|
|
@@ -234,15 +511,16 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
234
511
|
if (selectedStep) {
|
|
235
512
|
nextStep = selectedStep;
|
|
236
513
|
} else {
|
|
237
|
-
// Determine current step from session if we're already in this
|
|
238
|
-
const currentStep = session.
|
|
239
|
-
?
|
|
514
|
+
// Determine current step from session if we're already in this flow
|
|
515
|
+
const currentStep = session.currentFlow?.id === selectedFlow.id && session.currentStep
|
|
516
|
+
? selectedFlow.getStep(session.currentStep.id)
|
|
240
517
|
: undefined;
|
|
241
518
|
|
|
242
519
|
const contextToUse = this.getStoredContext();
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
520
|
+
|
|
521
|
+
// Get candidate steps based on current position in the flow
|
|
522
|
+
const candidates = await this.flowRouter.getCandidateStepsWithConditions(
|
|
523
|
+
selectedFlow,
|
|
246
524
|
currentStep, // Pass current step instead of undefined to maintain progression
|
|
247
525
|
createTemplateContext({ data: session.data, session, context: contextToUse })
|
|
248
526
|
);
|
|
@@ -250,13 +528,13 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
250
528
|
if (candidates.length > 0) {
|
|
251
529
|
nextStep = candidates[0].step;
|
|
252
530
|
logger.debug(
|
|
253
|
-
`[ResponseHandler] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new
|
|
531
|
+
`[ResponseHandler] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new flow'}`
|
|
254
532
|
);
|
|
255
533
|
} else {
|
|
256
534
|
// Fallback to initial step even if it should be skipped
|
|
257
|
-
nextStep =
|
|
535
|
+
nextStep = selectedFlow.initialStep;
|
|
258
536
|
logger.warn(
|
|
259
|
-
`[
|
|
537
|
+
`[FlowConfigurationError] No valid steps found in flow "${selectedFlow.title}": all candidates were skipped. Falling back to initial step "${nextStep.id}". Review step skip conditions.`
|
|
260
538
|
);
|
|
261
539
|
}
|
|
262
540
|
}
|
|
@@ -273,8 +551,8 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
273
551
|
);
|
|
274
552
|
// Stay at current step - don't enter the next one
|
|
275
553
|
const currentStepId = session.currentStep?.id;
|
|
276
|
-
if (currentStepId &&
|
|
277
|
-
const currentStepInstance =
|
|
554
|
+
if (currentStepId && selectedFlow) {
|
|
555
|
+
const currentStepInstance = selectedFlow.getStep(currentStepId);
|
|
278
556
|
if (currentStepInstance) {
|
|
279
557
|
nextStep = currentStepInstance;
|
|
280
558
|
}
|
|
@@ -294,12 +572,207 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
294
572
|
return { nextStep, session: updatedSession };
|
|
295
573
|
}
|
|
296
574
|
|
|
575
|
+
/**
|
|
576
|
+
* Evaluate branches on a step and resolve the `then` value.
|
|
577
|
+
*
|
|
578
|
+
* Resolution rules (Algorithm 1, STEP 1 + then resolution):
|
|
579
|
+
* - String `then` → look up in current flow's step registry first (local step wins).
|
|
580
|
+
* - Not a local step → look up in agent's flow registry; if found, treat as goTo directive.
|
|
581
|
+
* - Neither → throw FlowConfigurationError.
|
|
582
|
+
* - Directive `then` → apply directly (bypass directive bus merge).
|
|
583
|
+
*
|
|
584
|
+
* Returns the resolved { nextStep, session, flowChanged? } or undefined if no branch matched.
|
|
585
|
+
*/
|
|
586
|
+
async evaluateStepBranches(
|
|
587
|
+
currentStep: Step<TContext, TData>,
|
|
588
|
+
selectedFlow: Flow<TContext, TData>,
|
|
589
|
+
session: SessionState<TData>,
|
|
590
|
+
context: TContext,
|
|
591
|
+
): Promise<{ nextStep: Step<TContext, TData> | undefined; session: SessionState<TData>; flowChanged?: Flow<TContext, TData> } | undefined> {
|
|
592
|
+
const history = session.history ? historyToEvents(session.history) : [];
|
|
593
|
+
|
|
594
|
+
// Build the BranchPredicateContext
|
|
595
|
+
const branchCtx = {
|
|
596
|
+
data: session.data,
|
|
597
|
+
context,
|
|
598
|
+
session,
|
|
599
|
+
history,
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
// Create the AI condition evaluator
|
|
603
|
+
const aiEvaluator = createAiConditionEvaluator(
|
|
604
|
+
this.options.provider,
|
|
605
|
+
history,
|
|
606
|
+
context,
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
const result = await evaluateBranches(
|
|
610
|
+
currentStep.branches!,
|
|
611
|
+
branchCtx,
|
|
612
|
+
aiEvaluator,
|
|
613
|
+
);
|
|
614
|
+
|
|
615
|
+
if (result === undefined) {
|
|
616
|
+
return undefined; // No branch matched → fall through to linear/AI selection
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// Task 4.3: Directive `then` value — apply directly
|
|
620
|
+
if (typeof result === 'object' && result !== null) {
|
|
621
|
+
const directive = result;
|
|
622
|
+
return this.applyBranchDirective(directive, selectedFlow, session);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Task 4.2: String `then` resolution
|
|
626
|
+
// 1. Look up in current flow's step registry first (local step wins)
|
|
627
|
+
const localStep = selectedFlow.getStep(result);
|
|
628
|
+
if (localStep) {
|
|
629
|
+
const updatedSession = enterStep(session, localStep.id, localStep.description);
|
|
630
|
+
logger.debug(`[ResponseHandler] Branch resolved to local step: ${localStep.id}`);
|
|
631
|
+
return { nextStep: localStep, session: updatedSession };
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// 2. Look up in agent's flow registry
|
|
635
|
+
const flows = this.getFlows();
|
|
636
|
+
const targetFlow = flows.find(f => f.id === result || f.title === result);
|
|
637
|
+
if (targetFlow) {
|
|
638
|
+
// Treat as applyDirective({ goTo: result }) — enter the target flow
|
|
639
|
+
logger.debug(`[ResponseHandler] Branch resolved to flow: ${targetFlow.title}`);
|
|
640
|
+
const updatedSession = enterFlow(session, targetFlow.id, targetFlow.title);
|
|
641
|
+
return { nextStep: undefined, session: updatedSession, flowChanged: targetFlow };
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// 3. Neither → throw FlowConfigurationError
|
|
645
|
+
throw new FlowConfigurationError(
|
|
646
|
+
`[FlowConfigurationError] Unresolved branch target: "${result}" does not match any step in flow "${selectedFlow.id}" or any flow in the agent. ` +
|
|
647
|
+
`Source: ${selectedFlow.id}.${currentStep.id}. Fix the branch "then" value to reference a valid step id or flow id/title.`
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Apply a Directive returned by a branch entry's `then` value.
|
|
653
|
+
* Branches bypass the directive bus — the Directive is the position decision.
|
|
654
|
+
*/
|
|
655
|
+
private applyBranchDirective(
|
|
656
|
+
directive: Directive<TContext, TData>,
|
|
657
|
+
selectedFlow: Flow<TContext, TData>,
|
|
658
|
+
session: SessionState<TData>,
|
|
659
|
+
): { nextStep: Step<TContext, TData> | undefined; session: SessionState<TData>; flowChanged?: Flow<TContext, TData> } {
|
|
660
|
+
// Track directive chain depth (Requirement 22.1)
|
|
661
|
+
const tracker = this.chainTracker;
|
|
662
|
+
tracker.record(directive, `branch:${selectedFlow.id}`);
|
|
663
|
+
|
|
664
|
+
let updatedSession = session;
|
|
665
|
+
|
|
666
|
+
// Apply state writes first
|
|
667
|
+
if (directive.dataUpdate) {
|
|
668
|
+
updatedSession = mergeCollected(updatedSession, directive.dataUpdate);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// Handle position fields
|
|
672
|
+
if (directive.goToStep) {
|
|
673
|
+
const stepTarget = typeof directive.goToStep === 'string'
|
|
674
|
+
? directive.goToStep
|
|
675
|
+
: directive.goToStep.step;
|
|
676
|
+
const flowTarget = typeof directive.goToStep === 'object'
|
|
677
|
+
? directive.goToStep.flow
|
|
678
|
+
: undefined;
|
|
679
|
+
|
|
680
|
+
if (flowTarget) {
|
|
681
|
+
// Cross-flow step reference — enter the target flow first
|
|
682
|
+
const flows = this.getFlows();
|
|
683
|
+
const targetFlow = flows.find(f => f.id === flowTarget || f.title === flowTarget);
|
|
684
|
+
if (targetFlow) {
|
|
685
|
+
updatedSession = enterFlow(updatedSession, targetFlow.id, targetFlow.title);
|
|
686
|
+
updatedSession = enterStep(updatedSession, stepTarget);
|
|
687
|
+
// Try to resolve the target step instance for the caller
|
|
688
|
+
const targetStepInstance = targetFlow.getStep(stepTarget);
|
|
689
|
+
logger.debug(`[ResponseHandler] Branch directive goToStep → ${flowTarget}.${stepTarget}`);
|
|
690
|
+
return { nextStep: targetStepInstance || undefined, session: updatedSession, flowChanged: targetFlow };
|
|
691
|
+
}
|
|
692
|
+
throw new FlowConfigurationError(
|
|
693
|
+
`[FlowConfigurationError] Branch directive goToStep targets unknown flow: "${flowTarget}" does not match any flow id or title. ` +
|
|
694
|
+
`Fix the goToStep.flow value or use goTo to target a known flow.`
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// Local step reference
|
|
699
|
+
const targetStep = selectedFlow.getStep(stepTarget);
|
|
700
|
+
if (targetStep) {
|
|
701
|
+
updatedSession = enterStep(updatedSession, targetStep.id, targetStep.description);
|
|
702
|
+
logger.debug(`[ResponseHandler] Branch directive goToStep → ${targetStep.id}`);
|
|
703
|
+
return { nextStep: targetStep, session: updatedSession };
|
|
704
|
+
}
|
|
705
|
+
throw new FlowConfigurationError(
|
|
706
|
+
`[FlowConfigurationError] Branch directive goToStep targets unknown step: "${stepTarget}" does not exist in flow "${selectedFlow.id}". ` +
|
|
707
|
+
`Fix the goToStep value to reference a valid step id in the current flow.`
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
if (directive.goTo) {
|
|
712
|
+
const flowTarget = typeof directive.goTo === 'string'
|
|
713
|
+
? directive.goTo
|
|
714
|
+
: directive.goTo.flow ?? directive.goTo.step;
|
|
715
|
+
|
|
716
|
+
if (flowTarget) {
|
|
717
|
+
const flows = this.getFlows();
|
|
718
|
+
const targetFlow = flows.find(f => f.id === flowTarget || f.title === flowTarget);
|
|
719
|
+
if (targetFlow) {
|
|
720
|
+
updatedSession = enterFlow(updatedSession, targetFlow.id, targetFlow.title);
|
|
721
|
+
|
|
722
|
+
// If goTo is an object with a step field, enter that step too
|
|
723
|
+
if (typeof directive.goTo === 'object' && directive.goTo.step) {
|
|
724
|
+
updatedSession = enterStep(updatedSession, directive.goTo.step);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
logger.debug(`[ResponseHandler] Branch directive goTo → ${targetFlow.title}`);
|
|
728
|
+
return { nextStep: undefined, session: updatedSession, flowChanged: targetFlow };
|
|
729
|
+
}
|
|
730
|
+
throw new FlowConfigurationError(
|
|
731
|
+
`[FlowConfigurationError] Branch directive goTo targets unknown flow: "${flowTarget}" does not match any flow id or title. ` +
|
|
732
|
+
`Fix the goTo value to reference a valid flow.`
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
if (directive.complete) {
|
|
738
|
+
logger.debug(`[ResponseHandler] Branch directive complete`);
|
|
739
|
+
return { nextStep: undefined, session: updatedSession };
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
if (directive.abort) {
|
|
743
|
+
logger.debug(`[ResponseHandler] Branch directive abort`);
|
|
744
|
+
return { nextStep: undefined, session: updatedSession };
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
if (directive.reset) {
|
|
748
|
+
const resetStep = typeof directive.reset === 'object' && directive.reset.step
|
|
749
|
+
? directive.reset.step
|
|
750
|
+
: undefined;
|
|
751
|
+
if (resetStep) {
|
|
752
|
+
const targetStep = selectedFlow.getStep(resetStep);
|
|
753
|
+
if (targetStep) {
|
|
754
|
+
updatedSession = enterStep(updatedSession, targetStep.id, targetStep.description);
|
|
755
|
+
return { nextStep: targetStep, session: updatedSession };
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
// Reset to initial step
|
|
759
|
+
const initialStep = selectedFlow.initialStep;
|
|
760
|
+
updatedSession = enterStep(updatedSession, initialStep.id, initialStep.description);
|
|
761
|
+
logger.debug(`[ResponseHandler] Branch directive reset → ${initialStep.id}`);
|
|
762
|
+
return { nextStep: initialStep, session: updatedSession };
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// Directive with only non-position fields (e.g., just dataUpdate/contextUpdate/reply)
|
|
766
|
+
// No position change — fall through to linear selection
|
|
767
|
+
return { nextStep: undefined, session: updatedSession };
|
|
768
|
+
}
|
|
769
|
+
|
|
297
770
|
/**
|
|
298
771
|
* Execute tool calls and handle results
|
|
299
772
|
*/
|
|
300
773
|
async executeToolCalls(params: {
|
|
301
774
|
toolCalls: Array<{ toolName: string; arguments: Record<string, unknown> }>;
|
|
302
|
-
|
|
775
|
+
selectedFlow?: Flow<TContext, TData>;
|
|
303
776
|
context: TContext;
|
|
304
777
|
session: SessionState<TData>;
|
|
305
778
|
history: Event[];
|
|
@@ -307,7 +780,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
307
780
|
}): Promise<ToolExecutionResult<TData>> {
|
|
308
781
|
const {
|
|
309
782
|
toolCalls,
|
|
310
|
-
|
|
783
|
+
selectedFlow,
|
|
311
784
|
context,
|
|
312
785
|
session,
|
|
313
786
|
history,
|
|
@@ -331,9 +804,9 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
331
804
|
const toolResults = new Map<string, string>();
|
|
332
805
|
|
|
333
806
|
for (const toolCall of toolCalls) {
|
|
334
|
-
const tool = this.findAvailableTool(toolCall.toolName,
|
|
807
|
+
const tool = this.findAvailableTool(toolCall.toolName, selectedFlow);
|
|
335
808
|
if (!tool) {
|
|
336
|
-
logger.warn(`[
|
|
809
|
+
logger.warn(`[ToolExecutionError] Tool not found: "${toolCall.toolName}" is not registered in any scope (transient, step, flow, or agent). Skipping this tool call. Register the tool or check the tool name.`);
|
|
337
810
|
continue;
|
|
338
811
|
}
|
|
339
812
|
|
|
@@ -377,7 +850,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
377
850
|
}
|
|
378
851
|
|
|
379
852
|
logger.debug(
|
|
380
|
-
`[ResponseHandler] Executed ${isStreaming ? "streaming " : ""}tool: ${String(tool.id || tool.
|
|
853
|
+
`[ResponseHandler] Executed ${isStreaming ? "streaming " : ""}tool: ${String(tool.id || tool.id || 'unknown')
|
|
381
854
|
} (success: ${result.success})`
|
|
382
855
|
);
|
|
383
856
|
}
|
|
@@ -396,7 +869,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
396
869
|
initialToolCalls:
|
|
397
870
|
| Array<{ toolName: string; arguments: Record<string, unknown> }>
|
|
398
871
|
| undefined;
|
|
399
|
-
|
|
872
|
+
selectedFlow?: Flow<TContext, TData>;
|
|
400
873
|
nextStep: Step<TContext, TData>;
|
|
401
874
|
responsePrompt: string;
|
|
402
875
|
history: HistoryItem[];
|
|
@@ -407,7 +880,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
407
880
|
}): Promise<ToolExecutionResult<TData>> {
|
|
408
881
|
const {
|
|
409
882
|
initialToolCalls,
|
|
410
|
-
|
|
883
|
+
selectedFlow,
|
|
411
884
|
nextStep,
|
|
412
885
|
responsePrompt,
|
|
413
886
|
history,
|
|
@@ -435,7 +908,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
435
908
|
// Add tool execution results to history so AI knows what happened
|
|
436
909
|
const toolResultItems: HistoryItem[] = [];
|
|
437
910
|
for (const toolCall of currentToolCalls || []) {
|
|
438
|
-
const tool = this.findAvailableTool(toolCall.toolName,
|
|
911
|
+
const tool = this.findAvailableTool(toolCall.toolName, selectedFlow);
|
|
439
912
|
if (tool) {
|
|
440
913
|
toolResultItems.push({
|
|
441
914
|
role: "assistant" as const,
|
|
@@ -463,7 +936,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
463
936
|
prompt: responsePrompt,
|
|
464
937
|
history: updatedHistory,
|
|
465
938
|
context,
|
|
466
|
-
tools: this.collectAvailableTools(
|
|
939
|
+
tools: this.collectAvailableTools(selectedFlow, nextStep),
|
|
467
940
|
parameters: {
|
|
468
941
|
jsonSchema: responseSchema,
|
|
469
942
|
schemaName: isStreaming ? "tool_followup_streaming" : "tool_followup",
|
|
@@ -483,7 +956,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
483
956
|
// Execute the follow-up tool calls
|
|
484
957
|
const toolResult = await this.executeToolCalls({
|
|
485
958
|
toolCalls: followUpToolCalls!,
|
|
486
|
-
|
|
959
|
+
selectedFlow,
|
|
487
960
|
context,
|
|
488
961
|
session: currentSession,
|
|
489
962
|
history: historyToEvents(updatedHistory),
|
|
@@ -506,8 +979,7 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
506
979
|
|
|
507
980
|
if (toolLoopCount >= MAX_TOOL_LOOPS) {
|
|
508
981
|
logger.warn(
|
|
509
|
-
`[
|
|
510
|
-
}Tool loop limit reached (${MAX_TOOL_LOOPS}), stopping`
|
|
982
|
+
`[ResponseGenerationError] ${isStreaming ? "Streaming t" : "T"}ool loop limit reached: ${toolLoopCount} iterations hit the cap (${MAX_TOOL_LOOPS}). Stopping tool execution. Increase MAX_TOOL_LOOPS or reduce recursive tool calls.`
|
|
511
983
|
);
|
|
512
984
|
}
|
|
513
985
|
|
|
@@ -580,66 +1052,74 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
580
1052
|
}
|
|
581
1053
|
|
|
582
1054
|
/**
|
|
583
|
-
* Handle
|
|
1055
|
+
* Handle flow completion: pure state transition.
|
|
1056
|
+
*
|
|
1057
|
+
* Releases the session to idle (`currentFlow`/`currentStep` cleared),
|
|
1058
|
+
* marks the active `flowHistory` entry completed, and (when `onComplete`
|
|
1059
|
+
* is set) wires `pendingDirective` for the next turn. The framework
|
|
1060
|
+
* emits no message of its own at the completion boundary; callers that
|
|
1061
|
+
* need closing copy should add a final interactive step.
|
|
584
1062
|
*/
|
|
585
|
-
async
|
|
586
|
-
|
|
1063
|
+
async handleFlowCompletion(params: {
|
|
1064
|
+
selectedFlow: Flow<TContext, TData>;
|
|
587
1065
|
session: SessionState<TData>;
|
|
588
1066
|
context: TContext;
|
|
589
1067
|
history: Event[];
|
|
590
1068
|
}): Promise<{ session: SessionState<TData>; hasTransition: boolean }> {
|
|
591
|
-
const {
|
|
1069
|
+
const { selectedFlow, session, context } = params;
|
|
592
1070
|
|
|
593
1071
|
// Check for onComplete transition
|
|
594
|
-
const transitionConfig = await
|
|
1072
|
+
const transitionConfig = await selectedFlow.evaluateOnComplete(
|
|
595
1073
|
{ data: session.data },
|
|
596
1074
|
context
|
|
597
1075
|
);
|
|
598
1076
|
|
|
1077
|
+
// Release to idle. When the flow is reentrant, scrub its owned
|
|
1078
|
+
// fields so a future re-selection doesn't short-circuit on stale data.
|
|
1079
|
+
const ownedFields = selectedFlow.reentrant
|
|
1080
|
+
? [
|
|
1081
|
+
...(selectedFlow.requiredFields ?? []),
|
|
1082
|
+
...(selectedFlow.optionalFields ?? []),
|
|
1083
|
+
]
|
|
1084
|
+
: undefined;
|
|
1085
|
+
let updatedSession = completeCurrentFlow(session, {
|
|
1086
|
+
clearOwnedFields: ownedFields,
|
|
1087
|
+
});
|
|
1088
|
+
|
|
599
1089
|
if (transitionConfig) {
|
|
600
|
-
//
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
r.title === transitionConfig.nextStep
|
|
605
|
-
);
|
|
1090
|
+
// Extract target from directive's goTo field
|
|
1091
|
+
const goToTarget = typeof transitionConfig.goTo === 'string'
|
|
1092
|
+
? transitionConfig.goTo
|
|
1093
|
+
: transitionConfig.goTo?.flow;
|
|
606
1094
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
// Set pending transition in session
|
|
620
|
-
const updatedSession = {
|
|
621
|
-
...session,
|
|
622
|
-
pendingTransition: {
|
|
623
|
-
targetRouteId: targetRoute.id,
|
|
624
|
-
condition: renderedCondition,
|
|
625
|
-
reason: "route_complete" as const,
|
|
1095
|
+
// Find target flow by ID or title
|
|
1096
|
+
const targetFlow = goToTarget ? this.getFlows().find(
|
|
1097
|
+
(r) =>
|
|
1098
|
+
r.id === goToTarget ||
|
|
1099
|
+
r.title === goToTarget
|
|
1100
|
+
) : undefined;
|
|
1101
|
+
|
|
1102
|
+
if (targetFlow) {
|
|
1103
|
+
updatedSession = {
|
|
1104
|
+
...updatedSession,
|
|
1105
|
+
pendingDirective: {
|
|
1106
|
+
goTo: targetFlow.id,
|
|
626
1107
|
},
|
|
627
1108
|
};
|
|
628
1109
|
logger.debug(
|
|
629
|
-
`[ResponseHandler]
|
|
1110
|
+
`[ResponseHandler] Flow ${selectedFlow.title} completed with pending directive to: ${targetFlow.title}`
|
|
630
1111
|
);
|
|
631
1112
|
return { session: updatedSession, hasTransition: true };
|
|
632
|
-
} else {
|
|
1113
|
+
} else if (goToTarget) {
|
|
633
1114
|
logger.warn(
|
|
634
|
-
`[
|
|
1115
|
+
`[FlowConfigurationError] onComplete target not found: flow "${selectedFlow.title}" completed but onComplete target "${goToTarget}" does not match any flow. ` +
|
|
1116
|
+
`Fix the onComplete value to reference an existing flow id/title, or remove onComplete to release the session to idle.`
|
|
635
1117
|
);
|
|
636
1118
|
}
|
|
637
1119
|
}
|
|
638
1120
|
|
|
639
|
-
// Set step to END_ROUTE marker
|
|
640
|
-
const updatedSession = enterStep(session, END_ROUTE_ID, "Route completed");
|
|
641
1121
|
logger.debug(
|
|
642
|
-
`[ResponseHandler]
|
|
1122
|
+
`[ResponseHandler] Flow ${selectedFlow.title} completed; session released to idle.`
|
|
643
1123
|
);
|
|
644
1124
|
|
|
645
1125
|
return { session: updatedSession, hasTransition: false };
|
|
@@ -647,46 +1127,46 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
647
1127
|
|
|
648
1128
|
|
|
649
1129
|
/**
|
|
650
|
-
* Find an available tool by name for the given
|
|
1130
|
+
* Find an available tool by name for the given flow using ToolManager
|
|
651
1131
|
* Delegates to ToolManager for unified tool resolution
|
|
652
1132
|
*/
|
|
653
1133
|
private findAvailableTool(
|
|
654
1134
|
toolName: string,
|
|
655
|
-
|
|
1135
|
+
flow?: Flow<TContext, TData>
|
|
656
1136
|
): Tool<TContext, TData> | undefined {
|
|
657
1137
|
// Use ToolManager for unified tool resolution if available
|
|
658
1138
|
if (this.toolManager) {
|
|
659
|
-
return this.toolManager.find(toolName, undefined, undefined,
|
|
1139
|
+
return this.toolManager.find(toolName, undefined, undefined, flow);
|
|
660
1140
|
}
|
|
661
1141
|
|
|
662
1142
|
// Fallback to legacy resolution if ToolManager not available
|
|
663
1143
|
logger.warn(`[ResponsePipeline] ToolManager not available, using legacy tool resolution for: ${toolName}`);
|
|
664
1144
|
|
|
665
|
-
// Check
|
|
666
|
-
if (
|
|
667
|
-
const
|
|
1145
|
+
// Check flow-level tools first (if flow provided)
|
|
1146
|
+
if (flow) {
|
|
1147
|
+
const flowTool = flow
|
|
668
1148
|
.getTools()
|
|
669
|
-
.find((tool) => tool.id === toolName || tool.
|
|
670
|
-
if (
|
|
1149
|
+
.find((tool) => tool.id === toolName || tool.id === toolName);
|
|
1150
|
+
if (flowTool) return flowTool;
|
|
671
1151
|
}
|
|
672
1152
|
|
|
673
1153
|
// Fall back to agent-level tools
|
|
674
1154
|
return this.tools.find(
|
|
675
|
-
(tool) => tool.id === toolName || tool.
|
|
1155
|
+
(tool) => tool.id === toolName || tool.id === toolName
|
|
676
1156
|
);
|
|
677
1157
|
}
|
|
678
1158
|
|
|
679
1159
|
/**
|
|
680
|
-
* Collect all available tools for the given
|
|
1160
|
+
* Collect all available tools for the given flow and step context using ToolManager
|
|
681
1161
|
* Delegates to ToolManager for unified tool resolution and deduplication
|
|
682
1162
|
*/
|
|
683
1163
|
private collectAvailableTools(
|
|
684
|
-
|
|
1164
|
+
flow?: Flow<TContext, TData>,
|
|
685
1165
|
step?: Step<TContext, TData>
|
|
686
1166
|
): Array<{ id: string; description?: string; parameters?: unknown }> {
|
|
687
1167
|
// Use ToolManager for unified tool collection if available
|
|
688
1168
|
if (this.toolManager) {
|
|
689
|
-
const availableTools = this.toolManager.getAvailable(undefined, step,
|
|
1169
|
+
const availableTools = this.toolManager.getAvailable(undefined, step, flow);
|
|
690
1170
|
return availableTools.map((tool) => ({
|
|
691
1171
|
id: tool.id,
|
|
692
1172
|
description: tool.description,
|
|
@@ -707,9 +1187,9 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
707
1187
|
availableTools.set(tool.id, tool);
|
|
708
1188
|
});
|
|
709
1189
|
|
|
710
|
-
// Add
|
|
711
|
-
if (
|
|
712
|
-
|
|
1190
|
+
// Add flow-level tools (these take precedence)
|
|
1191
|
+
if (flow) {
|
|
1192
|
+
flow.getTools().forEach((tool) => {
|
|
713
1193
|
availableTools.set(tool.id, tool);
|
|
714
1194
|
});
|
|
715
1195
|
}
|
|
@@ -798,63 +1278,63 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
798
1278
|
}
|
|
799
1279
|
|
|
800
1280
|
/**
|
|
801
|
-
* Handle cross-
|
|
802
|
-
* This method evaluates all
|
|
1281
|
+
* Handle cross-flow completion evaluation and notifications
|
|
1282
|
+
* This method evaluates all flows for completion and can trigger completion handlers
|
|
803
1283
|
*/
|
|
804
|
-
async
|
|
805
|
-
|
|
1284
|
+
async handleCrossFlowCompletion(params: {
|
|
1285
|
+
flows: Flow<TContext, TData>[];
|
|
806
1286
|
session: SessionState<TData>;
|
|
807
1287
|
context: TContext;
|
|
808
1288
|
history: Event[];
|
|
809
1289
|
}): Promise<{
|
|
810
1290
|
session: SessionState<TData>;
|
|
811
|
-
|
|
1291
|
+
completedFlows: Flow<TContext, TData>[];
|
|
812
1292
|
pendingTransitions: Array<{
|
|
813
|
-
|
|
814
|
-
transitionConfig:
|
|
1293
|
+
flow: Flow<TContext, TData>;
|
|
1294
|
+
transitionConfig: Directive<TContext, TData>;
|
|
815
1295
|
}>;
|
|
816
1296
|
}> {
|
|
817
|
-
const {
|
|
1297
|
+
const { flows, session, context } = params;
|
|
818
1298
|
|
|
819
|
-
// Evaluate all
|
|
820
|
-
const
|
|
1299
|
+
// Evaluate all flows for completion
|
|
1300
|
+
const completedFlows: Flow<TContext, TData>[] = [];
|
|
821
1301
|
const pendingTransitions: Array<{
|
|
822
|
-
|
|
823
|
-
transitionConfig:
|
|
1302
|
+
flow: Flow<TContext, TData>;
|
|
1303
|
+
transitionConfig: Directive<TContext, TData>;
|
|
824
1304
|
}> = [];
|
|
825
1305
|
|
|
826
|
-
for (const
|
|
827
|
-
if (
|
|
828
|
-
|
|
1306
|
+
for (const flow of flows) {
|
|
1307
|
+
if (flow.isComplete(session.data || {})) {
|
|
1308
|
+
completedFlows.push(flow);
|
|
829
1309
|
|
|
830
1310
|
// Check for onComplete transitions
|
|
831
|
-
const transitionConfig = await
|
|
1311
|
+
const transitionConfig = await flow.evaluateOnComplete(
|
|
832
1312
|
{ data: session.data },
|
|
833
1313
|
context
|
|
834
1314
|
);
|
|
835
1315
|
|
|
836
1316
|
if (transitionConfig) {
|
|
837
|
-
pendingTransitions.push({
|
|
1317
|
+
pendingTransitions.push({ flow, transitionConfig });
|
|
838
1318
|
}
|
|
839
1319
|
|
|
840
1320
|
logger.debug(
|
|
841
|
-
`[ResponsePipeline]
|
|
842
|
-
`(${Math.round(
|
|
1321
|
+
`[ResponsePipeline] Flow completed: ${flow.title} ` +
|
|
1322
|
+
`(${Math.round(flow.getCompletionProgress(session.data || {}) * 100)}%)`
|
|
843
1323
|
);
|
|
844
1324
|
}
|
|
845
1325
|
}
|
|
846
1326
|
|
|
847
|
-
// Log completion status for all
|
|
848
|
-
if (
|
|
1327
|
+
// Log completion status for all flows
|
|
1328
|
+
if (completedFlows.length > 0) {
|
|
849
1329
|
logger.debug(
|
|
850
|
-
`[ResponsePipeline] Cross-
|
|
851
|
-
`${
|
|
1330
|
+
`[ResponsePipeline] Cross-flow completion evaluation: ` +
|
|
1331
|
+
`${completedFlows.length}/${flows.length} flows complete`
|
|
852
1332
|
);
|
|
853
1333
|
}
|
|
854
1334
|
|
|
855
1335
|
return {
|
|
856
1336
|
session,
|
|
857
|
-
|
|
1337
|
+
completedFlows,
|
|
858
1338
|
pendingTransitions,
|
|
859
1339
|
};
|
|
860
1340
|
}
|
|
@@ -866,9 +1346,9 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
866
1346
|
async updateDataFlow(params: {
|
|
867
1347
|
session: SessionState<TData>;
|
|
868
1348
|
dataUpdate: Partial<TData>;
|
|
869
|
-
|
|
1349
|
+
flows: Flow<TContext, TData>[];
|
|
870
1350
|
}): Promise<SessionState<TData>> {
|
|
871
|
-
const { session, dataUpdate,
|
|
1351
|
+
const { session, dataUpdate, flows } = params;
|
|
872
1352
|
|
|
873
1353
|
// Update session data
|
|
874
1354
|
const updatedSession = await this.updateData(session, dataUpdate);
|
|
@@ -878,18 +1358,18 @@ export class ResponsePipeline<TContext = unknown, TData = unknown> {
|
|
|
878
1358
|
await this.updateCollectedData(dataUpdate);
|
|
879
1359
|
}
|
|
880
1360
|
|
|
881
|
-
// Evaluate
|
|
882
|
-
const completionResults = await this.
|
|
883
|
-
|
|
1361
|
+
// Evaluate flow completions after data update
|
|
1362
|
+
const completionResults = await this.handleCrossFlowCompletion({
|
|
1363
|
+
flows,
|
|
884
1364
|
session: updatedSession,
|
|
885
1365
|
context: this.context!,
|
|
886
1366
|
history: [],
|
|
887
1367
|
});
|
|
888
1368
|
|
|
889
|
-
// Log any newly completed
|
|
890
|
-
if (completionResults.
|
|
1369
|
+
// Log any newly completed flows
|
|
1370
|
+
if (completionResults.completedFlows.length > 0) {
|
|
891
1371
|
logger.debug(
|
|
892
|
-
`[ResponsePipeline] Data update resulted in ${completionResults.
|
|
1372
|
+
`[ResponsePipeline] Data update resulted in ${completionResults.completedFlows.length} completed flows`
|
|
893
1373
|
);
|
|
894
1374
|
}
|
|
895
1375
|
|