@falai/agent 1.2.8 → 2.0.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 +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/providers/AnthropicProvider.d.ts +1 -1
- package/dist/cjs/providers/AnthropicProvider.js +1 -1
- package/dist/cjs/providers/GeminiProvider.d.ts +1 -1
- package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/cjs/providers/GeminiProvider.js +1 -1
- package/dist/cjs/providers/GeminiProvider.js.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.d.ts +1 -1
- package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.js +1 -1
- package/dist/cjs/providers/OpenAIProvider.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/providers/AnthropicProvider.d.ts +1 -1
- package/dist/providers/AnthropicProvider.js +1 -1
- package/dist/providers/GeminiProvider.d.ts +1 -1
- package/dist/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/providers/GeminiProvider.js +1 -1
- package/dist/providers/GeminiProvider.js.map +1 -1
- package/dist/providers/OpenAIProvider.d.ts +1 -1
- package/dist/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/OpenAIProvider.js +1 -1
- package/dist/providers/OpenAIProvider.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 +22 -200
- 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 +14 -0
- package/docs/migration/route-to-flow.md +561 -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/providers/AnthropicProvider.ts +2 -2
- package/src/providers/GeminiProvider.ts +2 -2
- package/src/providers/OpenAIProvider.ts +2 -2
- 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
|
@@ -0,0 +1,723 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/**
|
|
3
|
+
* SignalProcessor — Orchestration for signal phase execution.
|
|
4
|
+
*
|
|
5
|
+
* Owns:
|
|
6
|
+
* - `behaviorAllowsExecution`: Behavior gating (Algorithm 2)
|
|
7
|
+
* - `recordTrigger`: Immutable session update for trigger state
|
|
8
|
+
* - `buildSignalContext`: Constructs the handler context (D-Q12 writers)
|
|
9
|
+
* - `runPhase` / `runPreSignalPhase` / `runPostSignalPhase`: Phase orchestration (Algorithm 1)
|
|
10
|
+
*
|
|
11
|
+
* @module SignalProcessor
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { AiProvider } from "../types/ai";
|
|
15
|
+
import type { Event } from "../types/history";
|
|
16
|
+
import { MessageRole as MessageRoleEnum } from "../types/history";
|
|
17
|
+
import type { SessionState } from "../types/session";
|
|
18
|
+
import type { PreDirective, Directive } from "../types/flow";
|
|
19
|
+
import type {
|
|
20
|
+
Signal,
|
|
21
|
+
SignalContext,
|
|
22
|
+
SignalDirective,
|
|
23
|
+
SignalFiring,
|
|
24
|
+
SignalPredicateContext,
|
|
25
|
+
SignalTriggerState,
|
|
26
|
+
} from "../types/signals";
|
|
27
|
+
import type { SignalEvaluator } from "./SignalEvaluator";
|
|
28
|
+
import { logger } from "../utils";
|
|
29
|
+
|
|
30
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
31
|
+
// behaviorAllowsExecution — Algorithm 2
|
|
32
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Determines whether a signal's behavior gating allows execution this turn.
|
|
36
|
+
*
|
|
37
|
+
* Algorithm 2 from the design document:
|
|
38
|
+
* - `'always'` (or unset) → always allowed
|
|
39
|
+
* - `'once'` → allowed only if no prior trigger exists
|
|
40
|
+
* - `'cooldown'` → allowed when elapsed time since last trigger >= cooldownMs;
|
|
41
|
+
* when `cooldownMs` is missing, treated as `'always'` (misconfigured)
|
|
42
|
+
* - Missing trigger (first-time) → allowed regardless of behavior
|
|
43
|
+
*
|
|
44
|
+
* Pure function; no I/O.
|
|
45
|
+
*
|
|
46
|
+
* @param signal - The signal definition (with id, behavior, cooldownMs)
|
|
47
|
+
* @param trigger - The existing trigger state from `session.signals.triggers[signal.id]`, or undefined
|
|
48
|
+
* @returns true if the signal is allowed to execute
|
|
49
|
+
*
|
|
50
|
+
* @requirements 5.1, 5.2, 5.3, 5.4
|
|
51
|
+
*/
|
|
52
|
+
export function behaviorAllowsExecution<TContext = unknown, TData = unknown>(
|
|
53
|
+
signal: Signal<TContext, TData, any>,
|
|
54
|
+
trigger: SignalTriggerState | undefined,
|
|
55
|
+
): boolean {
|
|
56
|
+
// No prior trigger → always allowed (first-time execution)
|
|
57
|
+
if (trigger == null) return true;
|
|
58
|
+
|
|
59
|
+
const behavior = signal.behavior ?? 'always';
|
|
60
|
+
|
|
61
|
+
if (behavior === 'always') return true;
|
|
62
|
+
if (behavior === 'once') return false;
|
|
63
|
+
|
|
64
|
+
if (behavior === 'cooldown') {
|
|
65
|
+
// Misconfigured: cooldown without cooldownMs → treat as 'always'
|
|
66
|
+
if (signal.cooldownMs == null) return true;
|
|
67
|
+
|
|
68
|
+
const lastTriggeredTime = trigger.lastTriggeredAt instanceof Date
|
|
69
|
+
? trigger.lastTriggeredAt.getTime()
|
|
70
|
+
: new Date(trigger.lastTriggeredAt).getTime();
|
|
71
|
+
|
|
72
|
+
const elapsedMs = Date.now() - lastTriggeredTime;
|
|
73
|
+
return elapsedMs >= signal.cooldownMs;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Unknown behavior value → allow (defensive)
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
81
|
+
// recordTrigger — Immutable session update
|
|
82
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Records a signal trigger on the session, returning a new session object
|
|
86
|
+
* (immutable update — never mutates input).
|
|
87
|
+
*
|
|
88
|
+
* - On first trigger: sets `firstTriggeredAt` and `lastTriggeredAt` to now,
|
|
89
|
+
* `count = 1`, plus `lastReason` and `lastPhase`.
|
|
90
|
+
* - On subsequent triggers: leaves `firstTriggeredAt` unchanged, increments
|
|
91
|
+
* `count`, updates `lastTriggeredAt`, `lastReason`, `lastPhase`.
|
|
92
|
+
*
|
|
93
|
+
* @param session - Current session state (not mutated)
|
|
94
|
+
* @param signal - The signal that fired
|
|
95
|
+
* @param reason - The match reason (AI rationale, 'code-only', or 'unconditional')
|
|
96
|
+
* @param phase - The phase in which the signal fired
|
|
97
|
+
* @returns A new session with updated `signals.triggers[signal.id]`
|
|
98
|
+
*
|
|
99
|
+
* @requirements 10.1, 10.2
|
|
100
|
+
*/
|
|
101
|
+
export function recordTrigger<TData = unknown>(
|
|
102
|
+
session: SessionState<TData>,
|
|
103
|
+
signal: Signal<any, TData, any>,
|
|
104
|
+
reason: string,
|
|
105
|
+
phase: 'pre' | 'post',
|
|
106
|
+
): SessionState<TData> {
|
|
107
|
+
const signalId = signal.id ?? 'unknown';
|
|
108
|
+
const now = new Date();
|
|
109
|
+
|
|
110
|
+
const existingTriggers = session.signals?.triggers ?? {};
|
|
111
|
+
const existingTrigger = existingTriggers[signalId];
|
|
112
|
+
|
|
113
|
+
let updatedTrigger: SignalTriggerState;
|
|
114
|
+
|
|
115
|
+
if (existingTrigger == null) {
|
|
116
|
+
// First trigger
|
|
117
|
+
updatedTrigger = {
|
|
118
|
+
firstTriggeredAt: now,
|
|
119
|
+
lastTriggeredAt: now,
|
|
120
|
+
count: 1,
|
|
121
|
+
lastReason: reason,
|
|
122
|
+
lastPhase: phase,
|
|
123
|
+
};
|
|
124
|
+
} else {
|
|
125
|
+
// Subsequent trigger — preserve firstTriggeredAt, increment count
|
|
126
|
+
updatedTrigger = {
|
|
127
|
+
firstTriggeredAt: existingTrigger.firstTriggeredAt,
|
|
128
|
+
lastTriggeredAt: now,
|
|
129
|
+
count: existingTrigger.count + 1,
|
|
130
|
+
lastReason: reason,
|
|
131
|
+
lastPhase: phase,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
...session,
|
|
137
|
+
signals: {
|
|
138
|
+
...session.signals,
|
|
139
|
+
triggers: {
|
|
140
|
+
...existingTriggers,
|
|
141
|
+
[signalId]: updatedTrigger,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
148
|
+
// buildSignalContext — Constructs the handler context
|
|
149
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Parameters for building the SignalContext.
|
|
153
|
+
*/
|
|
154
|
+
export interface BuildSignalContextParams<TContext = unknown, TData = unknown, TExtract = void> {
|
|
155
|
+
signal: Signal<TContext, TData, TExtract>;
|
|
156
|
+
reason: string;
|
|
157
|
+
extracted: TExtract extends void ? undefined : TExtract;
|
|
158
|
+
phase: 'pre' | 'post';
|
|
159
|
+
session: SessionState<TData>;
|
|
160
|
+
context: TContext;
|
|
161
|
+
history: Event[];
|
|
162
|
+
/** Turn-local directive bus — `dispatch` pushes onto this array. */
|
|
163
|
+
directiveBus: SignalDirective<TContext, TData>[];
|
|
164
|
+
/** Session updater — called when handler invokes `updateContext`. */
|
|
165
|
+
onUpdateSession: (updatedSession: SessionState<TData>) => void;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Builds the `SignalContext` passed to signal handlers.
|
|
170
|
+
*
|
|
171
|
+
* - `updateContext` and `updateData` replicate the ToolContext D-Q12 writer
|
|
172
|
+
* pattern: shallow-merge partial updates into the session, call the
|
|
173
|
+
* `onUpdateSession` callback so the processor can track mutations.
|
|
174
|
+
* - `dispatch` pushes a `SignalDirective` onto the turn-local bus.
|
|
175
|
+
* - `lastUserMessage` is derived from the last user-role event in history.
|
|
176
|
+
* - `triggeredAt` is set to `new Date()` at construction time.
|
|
177
|
+
* - `matched` is always `true` (literal type).
|
|
178
|
+
*
|
|
179
|
+
* @requirements 6.1, 6.2, 6.3
|
|
180
|
+
*/
|
|
181
|
+
export function buildSignalContext<TContext = unknown, TData = unknown, TExtract = void>(
|
|
182
|
+
params: BuildSignalContextParams<TContext, TData, TExtract>,
|
|
183
|
+
): SignalContext<TContext, TData, TExtract> {
|
|
184
|
+
const {
|
|
185
|
+
signal,
|
|
186
|
+
reason,
|
|
187
|
+
extracted,
|
|
188
|
+
phase,
|
|
189
|
+
session,
|
|
190
|
+
context,
|
|
191
|
+
history,
|
|
192
|
+
directiveBus,
|
|
193
|
+
onUpdateSession,
|
|
194
|
+
} = params;
|
|
195
|
+
|
|
196
|
+
// Derive lastUserMessage from the last user-role event
|
|
197
|
+
const lastUserMessage = deriveLastUserMessage(history);
|
|
198
|
+
|
|
199
|
+
// D-Q12 contract writers — same signature as ToolContext
|
|
200
|
+
const updateContext = (updates: Partial<TContext>): Promise<void> => {
|
|
201
|
+
// Context is agent-level (not on session directly). Push a contextUpdate
|
|
202
|
+
// directive so the pipeline applies the merge after handler returns.
|
|
203
|
+
directiveBus.push({ contextUpdate: updates } as SignalDirective<TContext, TData>);
|
|
204
|
+
return Promise.resolve();
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const updateData = (updates: Partial<TData>): Promise<void> => {
|
|
208
|
+
const updatedData = { ...session.data, ...updates };
|
|
209
|
+
const updatedSession: SessionState<TData> = {
|
|
210
|
+
...session,
|
|
211
|
+
data: updatedData,
|
|
212
|
+
};
|
|
213
|
+
onUpdateSession(updatedSession);
|
|
214
|
+
// Also push a dataUpdate directive for the pipeline
|
|
215
|
+
directiveBus.push({ dataUpdate: updates } as SignalDirective<TContext, TData>);
|
|
216
|
+
return Promise.resolve();
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const dispatch = (directive: SignalDirective<TContext, TData>): void => {
|
|
220
|
+
directiveBus.push(directive);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
signal,
|
|
225
|
+
phase,
|
|
226
|
+
matched: true,
|
|
227
|
+
reason,
|
|
228
|
+
extracted,
|
|
229
|
+
session,
|
|
230
|
+
context,
|
|
231
|
+
data: session.data,
|
|
232
|
+
history,
|
|
233
|
+
lastUserMessage,
|
|
234
|
+
triggeredAt: new Date(),
|
|
235
|
+
updateContext,
|
|
236
|
+
updateData,
|
|
237
|
+
dispatch,
|
|
238
|
+
} as SignalContext<TContext, TData, TExtract>;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
242
|
+
// Internal helpers
|
|
243
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Extracts the last user message from history events.
|
|
247
|
+
* Walks backward to find the most recent user-role message event.
|
|
248
|
+
*/
|
|
249
|
+
function deriveLastUserMessage(history: Event[]): string | undefined {
|
|
250
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
251
|
+
const event = history[i];
|
|
252
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
|
253
|
+
if (event.source === MessageRoleEnum.USER && event.kind === 'message') {
|
|
254
|
+
const data = event.data as { message?: string; participant?: { display_name?: string } };
|
|
255
|
+
if (data?.message) {
|
|
256
|
+
return data.message;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
264
|
+
// SignalProcessor — Full Algorithm 1 implementation
|
|
265
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
266
|
+
|
|
267
|
+
/** Internal matched-signal entry carried through the pipeline. */
|
|
268
|
+
interface MatchedEntry<TContext, TData> {
|
|
269
|
+
signal: Signal<TContext, TData, any>;
|
|
270
|
+
reason: string;
|
|
271
|
+
extracted?: unknown;
|
|
272
|
+
/** Original index in the signals array (declaration order). */
|
|
273
|
+
declarationIndex: number;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* SignalProcessor — Orchestrates signal phase execution.
|
|
278
|
+
*
|
|
279
|
+
* Constructed only when `options.signals` is non-empty (Requirement 2.3).
|
|
280
|
+
* Owns the full Algorithm 1 lifecycle: filtering, gating, evaluation,
|
|
281
|
+
* handler invocation, directive collection, and state persistence.
|
|
282
|
+
*/
|
|
283
|
+
export class SignalProcessor<TContext = unknown, TData = unknown> {
|
|
284
|
+
constructor(
|
|
285
|
+
private readonly signals: Signal<TContext, TData, any>[],
|
|
286
|
+
private readonly provider: AiProvider,
|
|
287
|
+
private readonly evaluator: SignalEvaluator<TContext, TData>,
|
|
288
|
+
private readonly options: { batchSize: number },
|
|
289
|
+
) { }
|
|
290
|
+
|
|
291
|
+
/** @internal Expose internals for testability. */
|
|
292
|
+
get _internals() {
|
|
293
|
+
return { signals: this.signals, provider: this.provider, evaluator: this.evaluator, options: this.options };
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Pre-signal phase. Delegates to `runPhase('pre', ...)`.
|
|
298
|
+
* Return type narrows `mergedDirective` to `PreDirective | undefined`.
|
|
299
|
+
*/
|
|
300
|
+
async runPreSignalPhase(params: {
|
|
301
|
+
session: SessionState<TData>;
|
|
302
|
+
history: Event[];
|
|
303
|
+
context: TContext;
|
|
304
|
+
}): Promise<{
|
|
305
|
+
mergedDirective?: PreDirective<TContext, TData>;
|
|
306
|
+
firings: SignalFiring<TContext, TData>[];
|
|
307
|
+
updatedSession: SessionState<TData>;
|
|
308
|
+
}> {
|
|
309
|
+
return await this.runPhase('pre', params);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Post-signal phase. Delegates to `runPhase('post', ...)`.
|
|
314
|
+
* Return type narrows `mergedDirective` to `Directive | undefined`.
|
|
315
|
+
* Pre-LLM-only fields (`appendPrompt`, `injectTools`, `halt`) are
|
|
316
|
+
* already dropped inside `runPhase` for the post phase.
|
|
317
|
+
*/
|
|
318
|
+
async runPostSignalPhase(params: {
|
|
319
|
+
session: SessionState<TData>;
|
|
320
|
+
history: Event[];
|
|
321
|
+
context: TContext;
|
|
322
|
+
}): Promise<{
|
|
323
|
+
mergedDirective?: Directive<TContext, TData>;
|
|
324
|
+
firings: SignalFiring<TContext, TData>[];
|
|
325
|
+
updatedSession: SessionState<TData>;
|
|
326
|
+
}> {
|
|
327
|
+
return await this.runPhase('post', params);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
331
|
+
// Private: Algorithm 1 — Phase orchestration
|
|
332
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
333
|
+
|
|
334
|
+
private async runPhase(
|
|
335
|
+
phase: 'pre' | 'post',
|
|
336
|
+
params: { session: SessionState<TData>; history: Event[]; context: TContext },
|
|
337
|
+
): Promise<{
|
|
338
|
+
mergedDirective?: PreDirective<TContext, TData>;
|
|
339
|
+
firings: SignalFiring<TContext, TData>[];
|
|
340
|
+
updatedSession: SessionState<TData>;
|
|
341
|
+
}> {
|
|
342
|
+
const { session, history, context } = params;
|
|
343
|
+
|
|
344
|
+
// ── STEP 0: zero-cost fast path ──────────────────────────────────────
|
|
345
|
+
if (this.signals.length === 0) {
|
|
346
|
+
return { firings: [], updatedSession: session };
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// ── STEP 1: filter eligible signals for this phase ───────────────────
|
|
350
|
+
const eligible = this.signals.filter(
|
|
351
|
+
(s) => s.enabled !== false && (s.phase === phase || s.phase === 'both'),
|
|
352
|
+
);
|
|
353
|
+
if (eligible.length === 0) {
|
|
354
|
+
return { firings: [], updatedSession: session };
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
logger.debug(`[Signals] Phase "${phase}" eligible signals: [${eligible.map(s => s.id ?? 'unknown').join(', ')}]`);
|
|
358
|
+
|
|
359
|
+
// ── STEP 2: filter by behavior gating ────────────────────────────────
|
|
360
|
+
const gated = eligible.filter((s) =>
|
|
361
|
+
behaviorAllowsExecution(s, session.signals?.triggers?.[s.id ?? 'unknown']),
|
|
362
|
+
);
|
|
363
|
+
if (gated.length === 0) {
|
|
364
|
+
return { firings: [], updatedSession: session };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
logger.debug(`[Signals] Phase "${phase}" after behavior gating: [${gated.map(s => s.id ?? 'unknown').join(', ')}]`);
|
|
368
|
+
|
|
369
|
+
// ── STEP 3: partition by evaluation mode ─────────────────────────────
|
|
370
|
+
const unconditional: Signal<TContext, TData, any>[] = [];
|
|
371
|
+
const codeOnly: Signal<TContext, TData, any>[] = [];
|
|
372
|
+
const llmConditioned: Signal<TContext, TData, any>[] = [];
|
|
373
|
+
|
|
374
|
+
for (const s of gated) {
|
|
375
|
+
if (s.when != null) {
|
|
376
|
+
llmConditioned.push(s);
|
|
377
|
+
} else if (s.if != null) {
|
|
378
|
+
codeOnly.push(s);
|
|
379
|
+
} else {
|
|
380
|
+
unconditional.push(s);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Build predicate context (shared across code-only and if-gating)
|
|
385
|
+
const predicateCtx: SignalPredicateContext<TContext, TData> = {
|
|
386
|
+
data: session.data,
|
|
387
|
+
context,
|
|
388
|
+
session,
|
|
389
|
+
history,
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
// ── STEP 4: unconditional signals — always match ─────────────────────
|
|
393
|
+
const matched: MatchedEntry<TContext, TData>[] = [];
|
|
394
|
+
|
|
395
|
+
for (const s of unconditional) {
|
|
396
|
+
matched.push({
|
|
397
|
+
signal: s,
|
|
398
|
+
reason: 'unconditional',
|
|
399
|
+
declarationIndex: this.signals.indexOf(s),
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// ── STEP 5: code-only signals → evaluateIf ──────────────────────────
|
|
404
|
+
for (const s of codeOnly) {
|
|
405
|
+
const passes = await this.evaluator.evaluateIf(s.if!, predicateCtx);
|
|
406
|
+
if (passes) {
|
|
407
|
+
matched.push({
|
|
408
|
+
signal: s,
|
|
409
|
+
reason: 'code-only',
|
|
410
|
+
declarationIndex: this.signals.indexOf(s),
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// ── STEP 6: LLM-conditioned signals ─────────────────────────────────
|
|
416
|
+
if (llmConditioned.length > 0) {
|
|
417
|
+
// Gate by `if` first to skip token cost
|
|
418
|
+
const ifGated: Signal<TContext, TData, any>[] = [];
|
|
419
|
+
for (const s of llmConditioned) {
|
|
420
|
+
if (s.if == null) {
|
|
421
|
+
ifGated.push(s);
|
|
422
|
+
} else {
|
|
423
|
+
const passes = await this.evaluator.evaluateIf(s.if, predicateCtx);
|
|
424
|
+
if (passes) {
|
|
425
|
+
ifGated.push(s);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (ifGated.length > 0) {
|
|
431
|
+
const classifierStart = performance.now();
|
|
432
|
+
const classifierResults = await this.evaluator.evaluateSignalsBatched({
|
|
433
|
+
signals: ifGated,
|
|
434
|
+
batchSize: this.options.batchSize,
|
|
435
|
+
session,
|
|
436
|
+
history,
|
|
437
|
+
context,
|
|
438
|
+
});
|
|
439
|
+
const classifierDurationMs = performance.now() - classifierStart;
|
|
440
|
+
logger.debug(`[Signals] Phase "${phase}" classifier call duration: ${classifierDurationMs.toFixed(1)}ms for ${ifGated.length} LLM-conditioned signals`);
|
|
441
|
+
|
|
442
|
+
for (const s of ifGated) {
|
|
443
|
+
const id = s.id ?? 'unknown';
|
|
444
|
+
const result = classifierResults[id];
|
|
445
|
+
if (result?.matched) {
|
|
446
|
+
matched.push({
|
|
447
|
+
signal: s,
|
|
448
|
+
reason: result.reason ?? 'matched',
|
|
449
|
+
extracted: result.extracted,
|
|
450
|
+
declarationIndex: this.signals.indexOf(s),
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// ── STEP 6b: unconditional + extract signals ────────────────────────
|
|
458
|
+
const unconditionalWithExtract = unconditional.filter((s) => s.extract != null);
|
|
459
|
+
if (unconditionalWithExtract.length > 0) {
|
|
460
|
+
const extractResults = await this.evaluator.evaluateSignals({
|
|
461
|
+
signals: unconditionalWithExtract,
|
|
462
|
+
session,
|
|
463
|
+
history,
|
|
464
|
+
context,
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
// Attach extracted data to already-matched unconditional entries
|
|
468
|
+
for (const s of unconditionalWithExtract) {
|
|
469
|
+
const id = s.id ?? 'unknown';
|
|
470
|
+
const entry = matched.find((m) => m.signal === s);
|
|
471
|
+
if (entry) {
|
|
472
|
+
entry.extracted = extractResults[id]?.extracted;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// ── STEP 7: sort by priority desc, declaration order tiebreaker ──────
|
|
478
|
+
matched.sort((a, b) => {
|
|
479
|
+
const priorityDiff = (b.signal.priority ?? 0) - (a.signal.priority ?? 0);
|
|
480
|
+
if (priorityDiff !== 0) return priorityDiff;
|
|
481
|
+
return a.declarationIndex - b.declarationIndex;
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
// ── STEP 8: invoke handlers; collect directives; track state ─────────
|
|
485
|
+
const bus: SignalDirective<TContext, TData>[] = [];
|
|
486
|
+
const firings: SignalFiring<TContext, TData>[] = [];
|
|
487
|
+
let updatedSession = session;
|
|
488
|
+
|
|
489
|
+
for (const m of matched) {
|
|
490
|
+
// Turn-local directive bus for this handler (captures dispatch calls)
|
|
491
|
+
const handlerBus: SignalDirective<TContext, TData>[] = [];
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
const sigCtx = buildSignalContext<TContext, TData, any>({
|
|
495
|
+
signal: m.signal,
|
|
496
|
+
reason: m.reason,
|
|
497
|
+
extracted: m.extracted,
|
|
498
|
+
phase,
|
|
499
|
+
session: updatedSession,
|
|
500
|
+
context,
|
|
501
|
+
history,
|
|
502
|
+
directiveBus: handlerBus,
|
|
503
|
+
onUpdateSession: (s) => { updatedSession = s; },
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
const start = performance.now();
|
|
507
|
+
|
|
508
|
+
try {
|
|
509
|
+
|
|
510
|
+
const handlerResult = await m.signal.handler(sigCtx);
|
|
511
|
+
|
|
512
|
+
// Collect directives from dispatch calls
|
|
513
|
+
for (const d of handlerBus) {
|
|
514
|
+
bus.push(d);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
let resolvedDirective: SignalDirective<TContext, TData> | undefined;
|
|
518
|
+
|
|
519
|
+
if (handlerResult != null && typeof handlerResult === 'object') {
|
|
520
|
+
resolvedDirective = { ...handlerResult } as SignalDirective<TContext, TData>;
|
|
521
|
+
|
|
522
|
+
// Resolve replyWith → reply
|
|
523
|
+
if (resolvedDirective.replyWith != null) {
|
|
524
|
+
if (typeof resolvedDirective.replyWith === 'function') {
|
|
525
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
526
|
+
resolvedDirective.reply = resolvedDirective.replyWith(sigCtx);
|
|
527
|
+
} else {
|
|
528
|
+
resolvedDirective.reply = resolvedDirective.replyWith;
|
|
529
|
+
}
|
|
530
|
+
delete resolvedDirective.replyWith;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
bus.push(resolvedDirective);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Update session via recordTrigger
|
|
537
|
+
updatedSession = recordTrigger(updatedSession, m.signal, m.reason, phase);
|
|
538
|
+
|
|
539
|
+
const handlerDurationMs = performance.now() - start;
|
|
540
|
+
|
|
541
|
+
// Debug: per-handler duration and emitted directive fields
|
|
542
|
+
const directiveFields = resolvedDirective
|
|
543
|
+
? Object.keys(resolvedDirective).filter(k => resolvedDirective[k as keyof typeof resolvedDirective] !== undefined)
|
|
544
|
+
: [];
|
|
545
|
+
logger.debug(
|
|
546
|
+
`[Signals] Phase "${phase}" handler "${m.signal.id ?? 'unknown'}" completed in ${handlerDurationMs.toFixed(1)}ms` +
|
|
547
|
+
(directiveFields.length > 0 ? `, directive fields: [${directiveFields.join(', ')}]` : ', no directive'),
|
|
548
|
+
);
|
|
549
|
+
|
|
550
|
+
// Record firing
|
|
551
|
+
firings.push({
|
|
552
|
+
id: m.signal.id ?? 'unknown',
|
|
553
|
+
phase,
|
|
554
|
+
reason: m.reason,
|
|
555
|
+
extracted: m.extracted,
|
|
556
|
+
directive: resolvedDirective,
|
|
557
|
+
durationMs: handlerDurationMs,
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
// stopOtherSignals → break iteration
|
|
561
|
+
if (resolvedDirective?.stopOtherSignals === true) {
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
} catch (error) {
|
|
565
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
566
|
+
const handlerDurationMs = performance.now() - start;
|
|
567
|
+
|
|
568
|
+
// Handler errors logged at ERROR regardless of debug flag (Requirement 13.2)
|
|
569
|
+
logger.error(`[Signals] Handler threw for signal "${m.signal.id ?? 'unknown'}": ${errorMessage}`);
|
|
570
|
+
|
|
571
|
+
// Still record trigger even on error (the signal matched)
|
|
572
|
+
updatedSession = recordTrigger(updatedSession, m.signal, m.reason, phase);
|
|
573
|
+
|
|
574
|
+
firings.push({
|
|
575
|
+
id: m.signal.id ?? 'unknown',
|
|
576
|
+
phase,
|
|
577
|
+
reason: m.reason,
|
|
578
|
+
handlerError: errorMessage,
|
|
579
|
+
durationMs: handlerDurationMs,
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// Continue iteration — handler errors never break the turn
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// ── STEP 9: merge directives ─────────────────────────────────────────
|
|
587
|
+
let mergedDirective: PreDirective<TContext, TData> | undefined;
|
|
588
|
+
|
|
589
|
+
if (bus.length > 0) {
|
|
590
|
+
mergedDirective = this.mergeDirectives(bus);
|
|
591
|
+
|
|
592
|
+
// For post-phase, drop pre-LLM-only fields with debug warning
|
|
593
|
+
if (phase === 'post') {
|
|
594
|
+
if (mergedDirective.appendPrompt != null) {
|
|
595
|
+
logger.debug('[Signals] Dropping appendPrompt from post-phase signal directive (pre-LLM-only field)');
|
|
596
|
+
delete mergedDirective.appendPrompt;
|
|
597
|
+
}
|
|
598
|
+
if (mergedDirective.injectTools != null) {
|
|
599
|
+
logger.debug('[Signals] Dropping injectTools from post-phase signal directive (pre-LLM-only field)');
|
|
600
|
+
delete mergedDirective.injectTools;
|
|
601
|
+
}
|
|
602
|
+
if (mergedDirective.halt != null) {
|
|
603
|
+
logger.debug('[Signals] Dropping halt from post-phase signal directive (pre-LLM-only field)');
|
|
604
|
+
delete mergedDirective.halt;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Check if merged directive is now empty after stripping
|
|
609
|
+
const hasFields = Object.keys(mergedDirective).length > 0;
|
|
610
|
+
if (!hasFields) {
|
|
611
|
+
mergedDirective = undefined;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
return { mergedDirective, firings, updatedSession };
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
619
|
+
// Directive merging — Algorithm 4 pattern
|
|
620
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Merges an array of signal directives into a single directive.
|
|
624
|
+
*
|
|
625
|
+
* Merge strategy (matches Algorithm 4 / AutoChainExecutor pattern):
|
|
626
|
+
* - Position fields (`goTo`, `goToStep`, `complete`, `abort`, `reset`, `halt`): last-write-wins
|
|
627
|
+
* - `reply`: last-write-wins
|
|
628
|
+
* - `appendPrompt`: array-concat
|
|
629
|
+
* - `injectTools`: array-concat
|
|
630
|
+
* - `dataUpdate`: shallow-merge (later values overwrite earlier for same key)
|
|
631
|
+
* - `contextUpdate`: shallow-merge
|
|
632
|
+
* - `stopOtherSignals`: OR (any true → true)
|
|
633
|
+
*/
|
|
634
|
+
private mergeDirectives(
|
|
635
|
+
directives: SignalDirective<TContext, TData>[],
|
|
636
|
+
): PreDirective<TContext, TData> {
|
|
637
|
+
const merged: PreDirective<TContext, TData> = {};
|
|
638
|
+
|
|
639
|
+
for (const d of directives) {
|
|
640
|
+
// Position fields — last-write-wins
|
|
641
|
+
if (d.goTo !== undefined) {
|
|
642
|
+
merged.goTo = d.goTo;
|
|
643
|
+
// Clear other position fields
|
|
644
|
+
delete merged.goToStep;
|
|
645
|
+
delete merged.complete;
|
|
646
|
+
delete merged.abort;
|
|
647
|
+
delete merged.reset;
|
|
648
|
+
}
|
|
649
|
+
if (d.goToStep !== undefined) {
|
|
650
|
+
merged.goToStep = d.goToStep;
|
|
651
|
+
delete merged.goTo;
|
|
652
|
+
delete merged.complete;
|
|
653
|
+
delete merged.abort;
|
|
654
|
+
delete merged.reset;
|
|
655
|
+
}
|
|
656
|
+
if (d.complete !== undefined) {
|
|
657
|
+
merged.complete = d.complete;
|
|
658
|
+
delete merged.goTo;
|
|
659
|
+
delete merged.goToStep;
|
|
660
|
+
delete merged.abort;
|
|
661
|
+
delete merged.reset;
|
|
662
|
+
}
|
|
663
|
+
if (d.abort !== undefined) {
|
|
664
|
+
merged.abort = d.abort;
|
|
665
|
+
delete merged.goTo;
|
|
666
|
+
delete merged.goToStep;
|
|
667
|
+
delete merged.complete;
|
|
668
|
+
delete merged.reset;
|
|
669
|
+
}
|
|
670
|
+
if (d.reset !== undefined) {
|
|
671
|
+
merged.reset = d.reset;
|
|
672
|
+
delete merged.goTo;
|
|
673
|
+
delete merged.goToStep;
|
|
674
|
+
delete merged.complete;
|
|
675
|
+
delete merged.abort;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// halt — last-write-wins
|
|
679
|
+
if (d.halt !== undefined) {
|
|
680
|
+
merged.halt = d.halt;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// reply — last-write-wins
|
|
684
|
+
if (d.reply !== undefined) {
|
|
685
|
+
merged.reply = d.reply;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// appendPrompt — array-concat
|
|
689
|
+
if (d.appendPrompt != null) {
|
|
690
|
+
merged.appendPrompt = [
|
|
691
|
+
...(merged.appendPrompt ?? []),
|
|
692
|
+
...d.appendPrompt,
|
|
693
|
+
];
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// injectTools — array-concat
|
|
697
|
+
if (d.injectTools != null) {
|
|
698
|
+
merged.injectTools = [
|
|
699
|
+
...(merged.injectTools ?? []),
|
|
700
|
+
...d.injectTools,
|
|
701
|
+
];
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// dataUpdate — shallow-merge
|
|
705
|
+
if (d.dataUpdate != null) {
|
|
706
|
+
merged.dataUpdate = {
|
|
707
|
+
...(merged.dataUpdate ?? {}),
|
|
708
|
+
...d.dataUpdate,
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// contextUpdate — shallow-merge
|
|
713
|
+
if (d.contextUpdate != null) {
|
|
714
|
+
merged.contextUpdate = {
|
|
715
|
+
...(merged.contextUpdate ?? {}),
|
|
716
|
+
...d.contextUpdate,
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
return merged;
|
|
722
|
+
}
|
|
723
|
+
}
|