@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
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionFinalizer owns end-of-turn session finalization: deterministic
|
|
3
|
+
* history compaction, persistence auto-save, the step `finalize` hook,
|
|
4
|
+
* and syncing the finalized session back to the agent's live session.
|
|
5
|
+
*
|
|
6
|
+
* Every turn finalizes exactly once: the non-streaming path in
|
|
7
|
+
* `respond()` after generation completes; the streaming path in the
|
|
8
|
+
* final-chunk interception loop after the post-signal phase (so
|
|
9
|
+
* post-phase session mutations are persisted), with only the
|
|
10
|
+
* pre-routing signal/auto-chain halt chunks finalizing at their own
|
|
11
|
+
* yield sites.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { AgentOptions, SessionState } from "../types";
|
|
15
|
+
import type { CompactionOptions } from "../types/compaction";
|
|
16
|
+
import type { PersistenceManager } from "./PersistenceManager";
|
|
17
|
+
import type { StepLifecycle } from "./StepLifecycle";
|
|
18
|
+
import { CompactionEngine } from "./CompactionEngine";
|
|
19
|
+
import { logger } from "../utils";
|
|
20
|
+
|
|
21
|
+
export class SessionFinalizer<TContext = unknown, TData = unknown> {
|
|
22
|
+
constructor(
|
|
23
|
+
private readonly deps: {
|
|
24
|
+
getCompactionOptions: () => CompactionOptions | undefined;
|
|
25
|
+
getPersistenceManager: () => PersistenceManager<TData> | undefined;
|
|
26
|
+
getAgentOptions: () => AgentOptions<TContext, TData>;
|
|
27
|
+
getCurrentSession: () => SessionState<TData> | undefined;
|
|
28
|
+
setCurrentSession: (session: SessionState<TData>) => void;
|
|
29
|
+
stepLifecycle: StepLifecycle<TContext, TData>;
|
|
30
|
+
/** ResponseModalOptions.enableAutoSave (undefined means enabled). */
|
|
31
|
+
enableAutoSave?: boolean;
|
|
32
|
+
}
|
|
33
|
+
) { }
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Handle session persistence and finalization.
|
|
37
|
+
*/
|
|
38
|
+
async finalize(session: SessionState<TData>, context: TContext): Promise<void> {
|
|
39
|
+
// Deterministic compaction: runs on every finalize (not just addMessage)
|
|
40
|
+
// so respond()-only callers get bounded history too
|
|
41
|
+
const compactionOptions = this.deps.getCompactionOptions();
|
|
42
|
+
if (compactionOptions && session.history && session.history.length > 0) {
|
|
43
|
+
try {
|
|
44
|
+
const result = await CompactionEngine.checkAndCompact(session.history, compactionOptions);
|
|
45
|
+
if (result.strategy !== 'none') {
|
|
46
|
+
session.history = result.history;
|
|
47
|
+
logger.info(
|
|
48
|
+
`[SessionFinalizer] Compaction applied: strategy='${result.strategy}', ` +
|
|
49
|
+
`estimatedTokens=${result.estimatedTokens}, messagesCompacted=${result.messagesCompacted}`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
} catch (error) {
|
|
53
|
+
logger.warn("[SessionFinalizer] Compaction failed at finalize, continuing without compaction", error);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Auto-save session step to persistence if configured
|
|
58
|
+
const persistenceManager = this.deps.getPersistenceManager();
|
|
59
|
+
const agentOptions = this.deps.getAgentOptions();
|
|
60
|
+
if (
|
|
61
|
+
persistenceManager &&
|
|
62
|
+
session.id &&
|
|
63
|
+
(this.deps.enableAutoSave !== false && agentOptions.persistence?.autoSave !== false)
|
|
64
|
+
) {
|
|
65
|
+
await persistenceManager.saveSessionState(session.id, session);
|
|
66
|
+
logger.debug(`[SessionFinalizer] Auto-saved session step to persistence: ${session.id}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Execute finalize function
|
|
70
|
+
await this.deps.stepLifecycle.runFinalize(session, context);
|
|
71
|
+
|
|
72
|
+
// Update current session if we have one
|
|
73
|
+
const currentSession = this.deps.getCurrentSession();
|
|
74
|
+
if (currentSession) {
|
|
75
|
+
this.deps.setCurrentSession(session);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -79,6 +79,14 @@ export class SessionManager<TData = unknown> {
|
|
|
79
79
|
effectiveSessionId
|
|
80
80
|
);
|
|
81
81
|
if (session) {
|
|
82
|
+
// Loaded session data wins over anything staged before it existed
|
|
83
|
+
const pending = this.agent?.consumePendingData();
|
|
84
|
+
if (pending && Object.keys(pending).length > 0) {
|
|
85
|
+
log.debug(
|
|
86
|
+
"SessionManager: discarding pre-session staged data in favor of loaded session state",
|
|
87
|
+
pending
|
|
88
|
+
);
|
|
89
|
+
}
|
|
82
90
|
this.currentSession = session;
|
|
83
91
|
return session;
|
|
84
92
|
}
|
|
@@ -99,6 +107,9 @@ export class SessionManager<TData = unknown> {
|
|
|
99
107
|
const session = createSession<TData>({
|
|
100
108
|
id: sessionId,
|
|
101
109
|
history: [], // Session manages its own history
|
|
110
|
+
// Seed with data staged before the session existed (initialData,
|
|
111
|
+
// pre-session updateCollectedData calls)
|
|
112
|
+
data: this.agent?.consumePendingData() ?? ({} as Partial<TData>),
|
|
102
113
|
});
|
|
103
114
|
|
|
104
115
|
this.currentSession = session;
|
|
@@ -237,15 +248,16 @@ export class SessionManager<TData = unknown> {
|
|
|
237
248
|
await this.getOrCreate();
|
|
238
249
|
|
|
239
250
|
if (this.currentSession && data) {
|
|
240
|
-
this.currentSession.data = {
|
|
241
|
-
...this.currentSession.data,
|
|
242
|
-
...data,
|
|
243
|
-
};
|
|
244
|
-
this.currentSession.metadata!.lastUpdatedAt = new Date();
|
|
245
|
-
|
|
246
|
-
// Synchronize with agent's collected data for bidirectional sync
|
|
247
251
|
if (this.agent) {
|
|
248
|
-
|
|
252
|
+
// Route through the agent so schema validation and onDataUpdate
|
|
253
|
+
// hooks run; it writes into this session's data directly
|
|
254
|
+
await this.agent.updateCollectedData(data);
|
|
255
|
+
} else {
|
|
256
|
+
this.currentSession.data = {
|
|
257
|
+
...this.currentSession.data,
|
|
258
|
+
...data,
|
|
259
|
+
};
|
|
260
|
+
this.currentSession.metadata!.lastUpdatedAt = new Date();
|
|
249
261
|
}
|
|
250
262
|
|
|
251
263
|
// Auto-save to persistence
|
|
@@ -306,7 +318,7 @@ export class SessionManager<TData = unknown> {
|
|
|
306
318
|
*
|
|
307
319
|
* @internal Called from ResponseModal after stream()/generate() completion
|
|
308
320
|
*/
|
|
309
|
-
syncSession(session: SessionState<TData>): void {
|
|
321
|
+
syncSession(session: SessionState<TData> | undefined): void {
|
|
310
322
|
this.currentSession = session;
|
|
311
323
|
}
|
|
312
324
|
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SignalCoordinator owns the signal pre/post phase orchestration for a turn:
|
|
3
|
+
*
|
|
4
|
+
* - `runPrePhase()` / `runPostPhase()` — delegation to the SignalProcessor,
|
|
5
|
+
* returning a stable empty shape when no processor is configured.
|
|
6
|
+
* - `applyPositionDirective()` — applies a pre-phase directive's position
|
|
7
|
+
* field (goTo, goToStep, complete, abort, reset) as the turn's routing
|
|
8
|
+
* decision, discarding the router's result.
|
|
9
|
+
* - `applyPostPhase()` — runs the post phase and applies its directive to
|
|
10
|
+
* the turn result in one step: session updates, pendingDirective for
|
|
11
|
+
* position fields (no mid-turn re-entry per D6), and the reply override
|
|
12
|
+
* of the user-visible message.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type { Directive, Event, SessionState } from "../types";
|
|
16
|
+
import type { SignalFiring } from "../types/signals";
|
|
17
|
+
import type { SignalProcessor } from "./SignalProcessor";
|
|
18
|
+
import type { Flow } from "./Flow";
|
|
19
|
+
import type { Step } from "./Step";
|
|
20
|
+
import { hasDirectivePositionField } from "./ResponsePipeline";
|
|
21
|
+
import { enterFlow, enterStep, mergeCollected, logger } from "../utils";
|
|
22
|
+
|
|
23
|
+
/** Result of a signal phase run (pre or post). */
|
|
24
|
+
export interface SignalPhaseResult<TContext = unknown, TData = unknown> {
|
|
25
|
+
firings: SignalFiring<TContext, TData>[];
|
|
26
|
+
updatedSession: SessionState<TData>;
|
|
27
|
+
mergedDirective: Directive<TContext, TData> | undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class SignalCoordinator<TContext = unknown, TData = unknown> {
|
|
31
|
+
constructor(
|
|
32
|
+
private readonly deps: {
|
|
33
|
+
getFlows: () => Flow<TContext, TData>[];
|
|
34
|
+
signalProcessor?: SignalProcessor<TContext, TData>;
|
|
35
|
+
}
|
|
36
|
+
) { }
|
|
37
|
+
|
|
38
|
+
/** Whether a signal processor is configured (zero-cost path when absent). */
|
|
39
|
+
get enabled(): boolean {
|
|
40
|
+
return this.deps.signalProcessor !== undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* PRE-SIGNAL PHASE — Evaluates pre/both signals in parallel with routing.
|
|
45
|
+
*
|
|
46
|
+
* Delegates to `signalProcessor.runPreSignalPhase(...)` when configured.
|
|
47
|
+
* When no signal processor is present (zero-cost path), returns a stable
|
|
48
|
+
* empty shape so callers don't need to branch.
|
|
49
|
+
*
|
|
50
|
+
* @requirements 2.1, 2.3, 8.6, 13.3
|
|
51
|
+
*/
|
|
52
|
+
async runPrePhase(
|
|
53
|
+
session: SessionState<TData>,
|
|
54
|
+
context: TContext,
|
|
55
|
+
history: Event[],
|
|
56
|
+
): Promise<SignalPhaseResult<TContext, TData>> {
|
|
57
|
+
if (!this.deps.signalProcessor) {
|
|
58
|
+
return { firings: [], updatedSession: session, mergedDirective: undefined };
|
|
59
|
+
}
|
|
60
|
+
const result = await this.deps.signalProcessor.runPreSignalPhase({ session, history, context });
|
|
61
|
+
return {
|
|
62
|
+
firings: result.firings,
|
|
63
|
+
updatedSession: result.updatedSession,
|
|
64
|
+
mergedDirective: result.mergedDirective,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* POST-SIGNAL PHASE — Evaluates post/both signals after finalize/onComplete.
|
|
70
|
+
*
|
|
71
|
+
* Delegates to `signalProcessor.runPostSignalPhase(...)` when configured.
|
|
72
|
+
* When no signal processor is present, returns a stable empty shape.
|
|
73
|
+
*
|
|
74
|
+
* Post-phase signals see the complete turn result: assistant message in history,
|
|
75
|
+
* collected data, tool results. Position directives from this phase set
|
|
76
|
+
* `session.pendingDirective` (no mid-turn re-entry per D6 decision).
|
|
77
|
+
*
|
|
78
|
+
* Pre-LLM-only fields (`appendPrompt`, `injectTools`, `halt`) are already
|
|
79
|
+
* dropped inside `runPostSignalPhase` per Phase 4.5 — this seam does NOT
|
|
80
|
+
* re-introduce them.
|
|
81
|
+
*
|
|
82
|
+
* @requirements 9.1, 9.2, 9.3, 9.4
|
|
83
|
+
*/
|
|
84
|
+
async runPostPhase(
|
|
85
|
+
session: SessionState<TData>,
|
|
86
|
+
context: TContext,
|
|
87
|
+
history: Event[],
|
|
88
|
+
): Promise<SignalPhaseResult<TContext, TData>> {
|
|
89
|
+
if (!this.deps.signalProcessor) {
|
|
90
|
+
return { firings: [], updatedSession: session, mergedDirective: undefined };
|
|
91
|
+
}
|
|
92
|
+
const result = await this.deps.signalProcessor.runPostSignalPhase({ session, history, context });
|
|
93
|
+
return {
|
|
94
|
+
firings: result.firings,
|
|
95
|
+
updatedSession: result.updatedSession,
|
|
96
|
+
mergedDirective: result.mergedDirective,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Run the post phase and apply its merged directive to the turn result:
|
|
102
|
+
* session updates from the phase, `pendingDirective` for position fields
|
|
103
|
+
* (Requirement 9.3, no mid-turn re-entry per D6), and the reply override
|
|
104
|
+
* of the user-visible message (undefined means "leave it unchanged"; an
|
|
105
|
+
* empty string is an explicit replacement).
|
|
106
|
+
*
|
|
107
|
+
* @requirements 9.1, 9.2, 9.3, 9.4
|
|
108
|
+
*/
|
|
109
|
+
async applyPostPhase(params: {
|
|
110
|
+
session: SessionState<TData>;
|
|
111
|
+
context: TContext;
|
|
112
|
+
historyEvents: Event[];
|
|
113
|
+
message: string;
|
|
114
|
+
}): Promise<{
|
|
115
|
+
session: SessionState<TData>;
|
|
116
|
+
message: string;
|
|
117
|
+
firings: SignalFiring<TContext, TData>[];
|
|
118
|
+
/** True when the directive's `reply` replaced the message. */
|
|
119
|
+
replyOverridden: boolean;
|
|
120
|
+
}> {
|
|
121
|
+
const postResult = await this.runPostPhase(
|
|
122
|
+
params.session, params.context, params.historyEvents,
|
|
123
|
+
);
|
|
124
|
+
let session = postResult.updatedSession;
|
|
125
|
+
|
|
126
|
+
// Requirement 9.3: Post-phase position directive sets session.pendingDirective
|
|
127
|
+
if (postResult.mergedDirective && hasDirectivePositionField(postResult.mergedDirective)) {
|
|
128
|
+
session = { ...session, pendingDirective: postResult.mergedDirective };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const replyOverridden = postResult.mergedDirective?.reply !== undefined;
|
|
132
|
+
const message = replyOverridden
|
|
133
|
+
? postResult.mergedDirective!.reply!
|
|
134
|
+
: params.message;
|
|
135
|
+
|
|
136
|
+
return { session, message, firings: postResult.firings, replyOverridden };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Apply a signal's position directive (goTo, goToStep, complete, abort, reset).
|
|
141
|
+
* Discards routing result and uses the signal's position decision.
|
|
142
|
+
*
|
|
143
|
+
* @requirements 8.3
|
|
144
|
+
*/
|
|
145
|
+
applyPositionDirective(
|
|
146
|
+
signalResult: {
|
|
147
|
+
firings: SignalFiring<TContext, TData>[];
|
|
148
|
+
updatedSession: SessionState<TData>;
|
|
149
|
+
mergedDirective: Directive<TContext, TData> | undefined;
|
|
150
|
+
},
|
|
151
|
+
): {
|
|
152
|
+
selectedFlow?: Flow<TContext, TData>;
|
|
153
|
+
selectedStep?: Step<TContext, TData>;
|
|
154
|
+
responseDirectives?: string[];
|
|
155
|
+
session: SessionState<TData>;
|
|
156
|
+
isFlowComplete: boolean;
|
|
157
|
+
signalFirings?: SignalFiring<TContext, TData>[];
|
|
158
|
+
signalPreDirective?: Directive<TContext, TData>;
|
|
159
|
+
signalHalted?: boolean;
|
|
160
|
+
signalHaltReply?: string;
|
|
161
|
+
} {
|
|
162
|
+
const directive = signalResult.mergedDirective!;
|
|
163
|
+
let session = signalResult.updatedSession;
|
|
164
|
+
const flows = this.deps.getFlows();
|
|
165
|
+
let selectedFlow: Flow<TContext, TData> | undefined;
|
|
166
|
+
let selectedStep: Step<TContext, TData> | undefined;
|
|
167
|
+
let isFlowComplete = false;
|
|
168
|
+
|
|
169
|
+
// Apply data updates if present alongside position
|
|
170
|
+
if (directive.dataUpdate) {
|
|
171
|
+
session = mergeCollected(session, directive.dataUpdate);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (directive.goTo) {
|
|
175
|
+
const flowTarget = typeof directive.goTo === 'string'
|
|
176
|
+
? directive.goTo
|
|
177
|
+
: directive.goTo.flow ?? directive.goTo.step;
|
|
178
|
+
|
|
179
|
+
if (flowTarget) {
|
|
180
|
+
const targetFlow = flows.find(f => f.id === flowTarget || f.title === flowTarget);
|
|
181
|
+
if (targetFlow) {
|
|
182
|
+
session = enterFlow(session, targetFlow.id, targetFlow.title);
|
|
183
|
+
selectedFlow = targetFlow;
|
|
184
|
+
|
|
185
|
+
if (typeof directive.goTo === 'object' && directive.goTo.step) {
|
|
186
|
+
const targetStep = targetFlow.getStep(directive.goTo.step);
|
|
187
|
+
if (targetStep) {
|
|
188
|
+
session = enterStep(session, targetStep.id, targetStep.description);
|
|
189
|
+
selectedStep = targetStep;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
logger.warn(`[Signals] Pre-phase goTo target not found: "${flowTarget}". Falling back to no flow.`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
} else if (directive.goToStep) {
|
|
197
|
+
const stepTarget = typeof directive.goToStep === 'string'
|
|
198
|
+
? directive.goToStep
|
|
199
|
+
: directive.goToStep.step;
|
|
200
|
+
const flowTarget = typeof directive.goToStep === 'object'
|
|
201
|
+
? directive.goToStep.flow
|
|
202
|
+
: undefined;
|
|
203
|
+
|
|
204
|
+
if (flowTarget) {
|
|
205
|
+
const targetFlow = flows.find(f => f.id === flowTarget || f.title === flowTarget);
|
|
206
|
+
if (targetFlow) {
|
|
207
|
+
session = enterFlow(session, targetFlow.id, targetFlow.title);
|
|
208
|
+
selectedFlow = targetFlow;
|
|
209
|
+
const targetStep = targetFlow.getStep(stepTarget);
|
|
210
|
+
if (targetStep) {
|
|
211
|
+
session = enterStep(session, targetStep.id, targetStep.description);
|
|
212
|
+
selectedStep = targetStep;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
} else if (session.currentFlow) {
|
|
216
|
+
const currentFlow = flows.find(f => f.id === session.currentFlow?.id);
|
|
217
|
+
if (currentFlow) {
|
|
218
|
+
selectedFlow = currentFlow;
|
|
219
|
+
const targetStep = currentFlow.getStep(stepTarget);
|
|
220
|
+
if (targetStep) {
|
|
221
|
+
session = enterStep(session, targetStep.id, targetStep.description);
|
|
222
|
+
selectedStep = targetStep;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
} else if (directive.complete) {
|
|
227
|
+
isFlowComplete = true;
|
|
228
|
+
} else if (directive.abort) {
|
|
229
|
+
// Abort — no flow, session cleared or marked
|
|
230
|
+
isFlowComplete = true;
|
|
231
|
+
} else if (directive.reset) {
|
|
232
|
+
if (session.currentFlow) {
|
|
233
|
+
const currentFlow = flows.find(f => f.id === session.currentFlow?.id);
|
|
234
|
+
if (currentFlow) {
|
|
235
|
+
selectedFlow = currentFlow;
|
|
236
|
+
const resetStep = typeof directive.reset === 'object' && directive.reset.step
|
|
237
|
+
? directive.reset.step
|
|
238
|
+
: undefined;
|
|
239
|
+
if (resetStep) {
|
|
240
|
+
const targetStep = currentFlow.getStep(resetStep);
|
|
241
|
+
if (targetStep) {
|
|
242
|
+
session = enterStep(session, targetStep.id, targetStep.description);
|
|
243
|
+
selectedStep = targetStep;
|
|
244
|
+
}
|
|
245
|
+
} else {
|
|
246
|
+
const initialStep = currentFlow.initialStep;
|
|
247
|
+
session = enterStep(session, initialStep.id, initialStep.description);
|
|
248
|
+
selectedStep = initialStep;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
selectedFlow,
|
|
256
|
+
selectedStep,
|
|
257
|
+
session,
|
|
258
|
+
isFlowComplete,
|
|
259
|
+
signalFirings: signalResult.firings,
|
|
260
|
+
signalPreDirective: signalResult.mergedDirective || undefined,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
SignalPredicateContext,
|
|
19
19
|
} from "../types/signals";
|
|
20
20
|
import { eventsToHistory, logger } from "../utils";
|
|
21
|
+
import { splitWhenConditions, evaluateIfPredicates } from "../utils/condition";
|
|
21
22
|
|
|
22
23
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
23
24
|
// Types
|
|
@@ -44,8 +45,8 @@ export interface EvaluateSignalsParams<TContext = unknown, TData = unknown> {
|
|
|
44
45
|
/**
|
|
45
46
|
* Builds the classifier prompt for a batch of signals.
|
|
46
47
|
*
|
|
47
|
-
* Splits `when` entries
|
|
48
|
-
* -
|
|
48
|
+
* Splits `when` entries with the shared ConditionWhen parser:
|
|
49
|
+
* - Positive entries → "TRIGGER WHEN (ANY matches)"
|
|
49
50
|
* - `!` entries → prefix stripped, "DO NOT TRIGGER WHEN (ANY inhibits)"
|
|
50
51
|
*
|
|
51
52
|
* Extraction schemas render under "WHEN MATCHED, EXTRACT".
|
|
@@ -80,11 +81,11 @@ export function buildSignalClassifierPrompt<TContext = unknown, TData = unknown>
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
// Split when entries
|
|
83
|
-
const
|
|
84
|
-
const positiveEntries =
|
|
85
|
-
const negativeEntries =
|
|
84
|
+
const whenConditions = splitWhenConditions(signal.when);
|
|
85
|
+
const positiveEntries = whenConditions.positive;
|
|
86
|
+
const negativeEntries = whenConditions.negative;
|
|
86
87
|
|
|
87
|
-
const isUnconditional =
|
|
88
|
+
const isUnconditional = positiveEntries.length === 0 && negativeEntries.length === 0;
|
|
88
89
|
|
|
89
90
|
if (isUnconditional && signal.extract) {
|
|
90
91
|
// Unconditional + extract → ALWAYS EXTRACT
|
|
@@ -94,6 +95,8 @@ export function buildSignalClassifierPrompt<TContext = unknown, TData = unknown>
|
|
|
94
95
|
for (const entry of positiveEntries) {
|
|
95
96
|
lines.push(` • ${entry}`);
|
|
96
97
|
}
|
|
98
|
+
} else if (negativeEntries.length > 0) {
|
|
99
|
+
lines.push(` TRIGGER WHEN: no positive condition; trigger unless an exclusion matches.`);
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
if (negativeEntries.length > 0) {
|
|
@@ -207,23 +210,9 @@ export class SignalEvaluator<TContext = unknown, TData = unknown> {
|
|
|
207
210
|
predicates: SignalPredicate<TContext, TData> | SignalPredicate<TContext, TData>[],
|
|
208
211
|
ctx: SignalPredicateContext<TContext, TData>,
|
|
209
212
|
): Promise<boolean> {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
try {
|
|
214
|
-
const result = await predicateArray[i](ctx);
|
|
215
|
-
if (!result) {
|
|
216
|
-
return false;
|
|
217
|
-
}
|
|
218
|
-
} catch (error) {
|
|
219
|
-
logger.error(
|
|
220
|
-
`[Signals] Predicate at index ${i} threw: ${error instanceof Error ? error.message : String(error)}`,
|
|
221
|
-
);
|
|
222
|
-
return false;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return true;
|
|
213
|
+
return evaluateIfPredicates<SignalPredicateContext<TContext, TData>>(
|
|
214
|
+
predicates, ctx, "Signals"
|
|
215
|
+
);
|
|
227
216
|
}
|
|
228
217
|
|
|
229
218
|
/**
|
|
@@ -350,12 +339,6 @@ export function splitIntoBatches<T>(items: T[], batchSize: number): T[][] {
|
|
|
350
339
|
// Internal helpers
|
|
351
340
|
// ──────────────────────────────────────────────────────────────────────────────
|
|
352
341
|
|
|
353
|
-
/** Normalize `when` to a string array. */
|
|
354
|
-
function normalizeWhen(when: string | string[] | undefined): string[] {
|
|
355
|
-
if (!when) return [];
|
|
356
|
-
return Array.isArray(when) ? when : [when];
|
|
357
|
-
}
|
|
358
|
-
|
|
359
342
|
/**
|
|
360
343
|
* Render extraction schema properties as human-readable lines for the prompt.
|
|
361
344
|
* Lists each property's name, type, and constraints (enum, min/max, format).
|
package/src/core/Step.ts
CHANGED
|
@@ -15,6 +15,7 @@ import type { StepResult, BranchSpec, BranchResult } from "../types/flow";
|
|
|
15
15
|
import { ToolScope, Template, TemplateContext } from "../types";
|
|
16
16
|
import type { ConditionWhen, ConditionIf } from "../types/flow";
|
|
17
17
|
import { generateStepId, logger } from "../utils";
|
|
18
|
+
import { splitWhenConditions } from "../utils/condition";
|
|
18
19
|
import { Agent } from './Agent'
|
|
19
20
|
|
|
20
21
|
/**
|
|
@@ -448,7 +449,8 @@ export class Step<TContext = unknown, TData = unknown> {
|
|
|
448
449
|
/**
|
|
449
450
|
* Evaluate when/if conditions using the v2 split logic.
|
|
450
451
|
* `if` (code predicate) evaluates first (free); `when` (AI) evaluates only when `if` passes.
|
|
451
|
-
* `if` predicates use AND semantics. `when` strings use OR semantics
|
|
452
|
+
* `if` predicates use AND semantics. Non-`!` `when` strings use OR semantics;
|
|
453
|
+
* `!` strings are exclusions where any match inhibits activation.
|
|
452
454
|
* When both fields are set, the passing `if` gate and AI match are combined with AND.
|
|
453
455
|
*/
|
|
454
456
|
async evaluateWhen(
|
|
@@ -456,6 +458,7 @@ export class Step<TContext = unknown, TData = unknown> {
|
|
|
456
458
|
): Promise<{
|
|
457
459
|
shouldActivate: boolean;
|
|
458
460
|
aiContextStrings: string[];
|
|
461
|
+
aiExclusionStrings: string[];
|
|
459
462
|
hasProgrammaticConditions: boolean;
|
|
460
463
|
}> {
|
|
461
464
|
// If neither `when` nor `if` is set, step is always eligible
|
|
@@ -463,6 +466,7 @@ export class Step<TContext = unknown, TData = unknown> {
|
|
|
463
466
|
return {
|
|
464
467
|
shouldActivate: true,
|
|
465
468
|
aiContextStrings: [],
|
|
469
|
+
aiExclusionStrings: [],
|
|
466
470
|
hasProgrammaticConditions: false
|
|
467
471
|
};
|
|
468
472
|
}
|
|
@@ -483,6 +487,7 @@ export class Step<TContext = unknown, TData = unknown> {
|
|
|
483
487
|
return {
|
|
484
488
|
shouldActivate: false,
|
|
485
489
|
aiContextStrings: [],
|
|
490
|
+
aiExclusionStrings: [],
|
|
486
491
|
hasProgrammaticConditions: true
|
|
487
492
|
};
|
|
488
493
|
}
|
|
@@ -491,6 +496,7 @@ export class Step<TContext = unknown, TData = unknown> {
|
|
|
491
496
|
return {
|
|
492
497
|
shouldActivate: false,
|
|
493
498
|
aiContextStrings: [],
|
|
499
|
+
aiExclusionStrings: [],
|
|
494
500
|
hasProgrammaticConditions: true
|
|
495
501
|
};
|
|
496
502
|
}
|
|
@@ -499,13 +505,14 @@ export class Step<TContext = unknown, TData = unknown> {
|
|
|
499
505
|
|
|
500
506
|
// `if` passed (or was absent) — now evaluate `when` (AI-evaluated strings)
|
|
501
507
|
if (this.when) {
|
|
502
|
-
const
|
|
508
|
+
const whenConditions = splitWhenConditions(this.when);
|
|
503
509
|
// `when` strings are handed to the AI — return them as aiContextStrings
|
|
504
510
|
// The programmatic result is true (strings don't fail programmatically;
|
|
505
511
|
// they're scored by the AI at routing time)
|
|
506
512
|
return {
|
|
507
513
|
shouldActivate: true,
|
|
508
|
-
aiContextStrings:
|
|
514
|
+
aiContextStrings: whenConditions.positive,
|
|
515
|
+
aiExclusionStrings: whenConditions.negative,
|
|
509
516
|
hasProgrammaticConditions: !!this.if
|
|
510
517
|
};
|
|
511
518
|
}
|
|
@@ -514,6 +521,7 @@ export class Step<TContext = unknown, TData = unknown> {
|
|
|
514
521
|
return {
|
|
515
522
|
shouldActivate: true,
|
|
516
523
|
aiContextStrings: [],
|
|
524
|
+
aiExclusionStrings: [],
|
|
517
525
|
hasProgrammaticConditions: true
|
|
518
526
|
};
|
|
519
527
|
}
|