@falai/agent 1.2.8 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -886
- package/dist/adapters/MemoryAdapter.js +2 -2
- package/dist/adapters/MemoryAdapter.js.map +1 -1
- package/dist/adapters/MongoAdapter.js +2 -2
- package/dist/adapters/MongoAdapter.js.map +1 -1
- package/dist/adapters/OpenSearchAdapter.d.ts.map +1 -1
- package/dist/adapters/OpenSearchAdapter.js +9 -7
- package/dist/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/adapters/PostgreSQLAdapter.d.ts +14 -0
- package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -1
- package/dist/adapters/PostgreSQLAdapter.js +25 -9
- package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/adapters/PrismaAdapter.js +5 -5
- package/dist/adapters/PrismaAdapter.js.map +1 -1
- package/dist/adapters/RedisAdapter.js +2 -2
- package/dist/adapters/RedisAdapter.js.map +1 -1
- package/dist/adapters/SQLiteAdapter.d.ts +17 -0
- package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/adapters/SQLiteAdapter.js +30 -11
- package/dist/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/cjs/adapters/MemoryAdapter.js +2 -2
- package/dist/cjs/adapters/MemoryAdapter.js.map +1 -1
- package/dist/cjs/adapters/MongoAdapter.js +2 -2
- package/dist/cjs/adapters/MongoAdapter.js.map +1 -1
- package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/OpenSearchAdapter.js +9 -7
- package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.d.ts +14 -0
- package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.js +25 -9
- package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/cjs/adapters/PrismaAdapter.js +5 -5
- package/dist/cjs/adapters/PrismaAdapter.js.map +1 -1
- package/dist/cjs/adapters/RedisAdapter.js +2 -2
- package/dist/cjs/adapters/RedisAdapter.js.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.d.ts +17 -0
- package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.js +30 -11
- package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/cjs/constants/index.d.ts +0 -9
- package/dist/cjs/constants/index.d.ts.map +1 -1
- package/dist/cjs/constants/index.js +2 -11
- package/dist/cjs/constants/index.js.map +1 -1
- package/dist/cjs/core/Agent.d.ts +119 -153
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +471 -324
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/AutoChainExecutor.d.ts +107 -0
- package/dist/cjs/core/AutoChainExecutor.d.ts.map +1 -0
- package/dist/cjs/core/AutoChainExecutor.js +297 -0
- package/dist/cjs/core/AutoChainExecutor.js.map +1 -0
- package/dist/cjs/core/BranchEvaluator.d.ts +54 -0
- package/dist/cjs/core/BranchEvaluator.d.ts.map +1 -0
- package/dist/cjs/core/BranchEvaluator.js +130 -0
- package/dist/cjs/core/BranchEvaluator.js.map +1 -0
- package/dist/cjs/core/DirectiveBus.d.ts +88 -0
- package/dist/cjs/core/DirectiveBus.d.ts.map +1 -0
- package/dist/cjs/core/DirectiveBus.js +196 -0
- package/dist/cjs/core/DirectiveBus.js.map +1 -0
- package/dist/cjs/core/DirectiveChainTracker.d.ts +49 -0
- package/dist/cjs/core/DirectiveChainTracker.d.ts.map +1 -0
- package/dist/cjs/core/DirectiveChainTracker.js +121 -0
- package/dist/cjs/core/DirectiveChainTracker.js.map +1 -0
- package/dist/cjs/core/Flow.d.ts +186 -0
- package/dist/cjs/core/Flow.d.ts.map +1 -0
- package/dist/cjs/core/Flow.js +550 -0
- package/dist/cjs/core/Flow.js.map +1 -0
- package/dist/cjs/core/FlowRouter.d.ts +182 -0
- package/dist/cjs/core/FlowRouter.d.ts.map +1 -0
- package/dist/cjs/core/{RoutingEngine.js → FlowRouter.js} +323 -306
- package/dist/cjs/core/FlowRouter.js.map +1 -0
- package/dist/cjs/core/PersistenceManager.d.ts +2 -2
- package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
- package/dist/cjs/core/PersistenceManager.js +7 -7
- package/dist/cjs/core/PersistenceManager.js.map +1 -1
- package/dist/cjs/core/PromptComposer.d.ts +21 -8
- package/dist/cjs/core/PromptComposer.d.ts.map +1 -1
- package/dist/cjs/core/PromptComposer.js +182 -105
- package/dist/cjs/core/PromptComposer.js.map +1 -1
- package/dist/cjs/core/PromptSectionCache.d.ts +1 -1
- package/dist/cjs/core/PromptSectionCache.js +1 -1
- package/dist/cjs/core/ResponseEngine.d.ts +18 -8
- package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
- package/dist/cjs/core/ResponseEngine.js +38 -36
- package/dist/cjs/core/ResponseEngine.js.map +1 -1
- package/dist/cjs/core/ResponseModal.d.ts +73 -56
- package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
- package/dist/cjs/core/ResponseModal.js +1191 -1014
- package/dist/cjs/core/ResponseModal.js.map +1 -1
- package/dist/cjs/core/ResponsePipeline.d.ts +124 -26
- package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/cjs/core/ResponsePipeline.js +509 -136
- package/dist/cjs/core/ResponsePipeline.js.map +1 -1
- package/dist/cjs/core/SignalEvaluator.d.ts +86 -0
- package/dist/cjs/core/SignalEvaluator.d.ts.map +1 -0
- package/dist/cjs/core/SignalEvaluator.js +333 -0
- package/dist/cjs/core/SignalEvaluator.js.map +1 -0
- package/dist/cjs/core/SignalProcessor.d.ts +152 -0
- package/dist/cjs/core/SignalProcessor.d.ts.map +1 -0
- package/dist/cjs/core/SignalProcessor.js +562 -0
- package/dist/cjs/core/SignalProcessor.js.map +1 -0
- package/dist/cjs/core/Step.d.ts +43 -32
- package/dist/cjs/core/Step.d.ts.map +1 -1
- package/dist/cjs/core/Step.js +221 -126
- package/dist/cjs/core/Step.js.map +1 -1
- package/dist/cjs/core/StreamingToolExecutor.d.ts +2 -2
- package/dist/cjs/core/StreamingToolExecutor.d.ts.map +1 -1
- package/dist/cjs/core/StreamingToolExecutor.js.map +1 -1
- package/dist/cjs/core/ToolManager.d.ts +44 -13
- package/dist/cjs/core/ToolManager.d.ts.map +1 -1
- package/dist/cjs/core/ToolManager.js +174 -91
- package/dist/cjs/core/ToolManager.js.map +1 -1
- package/dist/cjs/core/createAgent.d.ts +35 -0
- package/dist/cjs/core/createAgent.d.ts.map +1 -0
- package/dist/cjs/core/createAgent.js +39 -0
- package/dist/cjs/core/createAgent.js.map +1 -0
- package/dist/cjs/core/flow-namespace.d.ts +49 -0
- package/dist/cjs/core/flow-namespace.d.ts.map +1 -0
- package/dist/cjs/core/flow-namespace.js +171 -0
- package/dist/cjs/core/flow-namespace.js.map +1 -0
- package/dist/cjs/index.d.ts +11 -14
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +18 -22
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +183 -54
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/agent.js +0 -6
- package/dist/cjs/types/agent.js.map +1 -1
- package/dist/cjs/types/ai.d.ts +3 -3
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/cjs/types/errors.d.ts +15 -0
- package/dist/cjs/types/errors.d.ts.map +1 -0
- package/dist/cjs/types/errors.js +22 -0
- package/dist/cjs/types/errors.js.map +1 -0
- package/dist/cjs/types/flow.d.ts +513 -0
- package/dist/cjs/types/flow.d.ts.map +1 -0
- package/dist/cjs/types/{route.js → flow.js} +2 -2
- package/dist/cjs/types/flow.js.map +1 -0
- package/dist/cjs/types/index.d.ts +7 -6
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js +6 -2
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/persistence.d.ts +11 -7
- package/dist/cjs/types/persistence.d.ts.map +1 -1
- package/dist/cjs/types/routing.d.ts +1 -1
- package/dist/cjs/types/routing.d.ts.map +1 -1
- package/dist/cjs/types/session.d.ts +24 -23
- package/dist/cjs/types/session.d.ts.map +1 -1
- package/dist/cjs/types/signals.d.ts +248 -0
- package/dist/cjs/types/signals.d.ts.map +1 -0
- package/dist/cjs/types/signals.js +11 -0
- package/dist/cjs/types/signals.js.map +1 -0
- package/dist/cjs/types/template.d.ts +2 -8
- package/dist/cjs/types/template.d.ts.map +1 -1
- package/dist/cjs/types/tool.d.ts +36 -29
- package/dist/cjs/types/tool.d.ts.map +1 -1
- package/dist/cjs/types/tool.js +1 -1
- package/dist/cjs/types/tool.js.map +1 -1
- package/dist/cjs/utils/condition.d.ts +7 -1
- package/dist/cjs/utils/condition.d.ts.map +1 -1
- package/dist/cjs/utils/condition.js.map +1 -1
- package/dist/cjs/utils/id.d.ts +13 -5
- package/dist/cjs/utils/id.d.ts.map +1 -1
- package/dist/cjs/utils/id.js +24 -10
- package/dist/cjs/utils/id.js.map +1 -1
- package/dist/cjs/utils/index.d.ts +2 -2
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +7 -3
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/session.d.ts +44 -5
- package/dist/cjs/utils/session.d.ts.map +1 -1
- package/dist/cjs/utils/session.js +197 -38
- package/dist/cjs/utils/session.js.map +1 -1
- package/dist/constants/index.d.ts +0 -9
- package/dist/constants/index.d.ts.map +1 -1
- package/dist/constants/index.js +3 -9
- package/dist/constants/index.js.map +1 -1
- package/dist/core/Agent.d.ts +119 -153
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +472 -325
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/AutoChainExecutor.d.ts +107 -0
- package/dist/core/AutoChainExecutor.d.ts.map +1 -0
- package/dist/core/AutoChainExecutor.js +293 -0
- package/dist/core/AutoChainExecutor.js.map +1 -0
- package/dist/core/BranchEvaluator.d.ts +54 -0
- package/dist/core/BranchEvaluator.d.ts.map +1 -0
- package/dist/core/BranchEvaluator.js +126 -0
- package/dist/core/BranchEvaluator.js.map +1 -0
- package/dist/core/DirectiveBus.d.ts +88 -0
- package/dist/core/DirectiveBus.d.ts.map +1 -0
- package/dist/core/DirectiveBus.js +192 -0
- package/dist/core/DirectiveBus.js.map +1 -0
- package/dist/core/DirectiveChainTracker.d.ts +49 -0
- package/dist/core/DirectiveChainTracker.d.ts.map +1 -0
- package/dist/core/DirectiveChainTracker.js +117 -0
- package/dist/core/DirectiveChainTracker.js.map +1 -0
- package/dist/core/Flow.d.ts +186 -0
- package/dist/core/Flow.d.ts.map +1 -0
- package/dist/core/Flow.js +546 -0
- package/dist/core/Flow.js.map +1 -0
- package/dist/core/FlowRouter.d.ts +182 -0
- package/dist/core/FlowRouter.d.ts.map +1 -0
- package/dist/core/{RoutingEngine.js → FlowRouter.js} +322 -305
- package/dist/core/FlowRouter.js.map +1 -0
- package/dist/core/PersistenceManager.d.ts +2 -2
- package/dist/core/PersistenceManager.d.ts.map +1 -1
- package/dist/core/PersistenceManager.js +7 -7
- package/dist/core/PersistenceManager.js.map +1 -1
- package/dist/core/PromptComposer.d.ts +21 -8
- package/dist/core/PromptComposer.d.ts.map +1 -1
- package/dist/core/PromptComposer.js +183 -106
- package/dist/core/PromptComposer.js.map +1 -1
- package/dist/core/PromptSectionCache.d.ts +1 -1
- package/dist/core/PromptSectionCache.js +1 -1
- package/dist/core/ResponseEngine.d.ts +18 -8
- package/dist/core/ResponseEngine.d.ts.map +1 -1
- package/dist/core/ResponseEngine.js +38 -36
- package/dist/core/ResponseEngine.js.map +1 -1
- package/dist/core/ResponseModal.d.ts +73 -56
- package/dist/core/ResponseModal.d.ts.map +1 -1
- package/dist/core/ResponseModal.js +1193 -1016
- package/dist/core/ResponseModal.js.map +1 -1
- package/dist/core/ResponsePipeline.d.ts +124 -26
- package/dist/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/core/ResponsePipeline.js +509 -137
- package/dist/core/ResponsePipeline.js.map +1 -1
- package/dist/core/SignalEvaluator.d.ts +86 -0
- package/dist/core/SignalEvaluator.d.ts.map +1 -0
- package/dist/core/SignalEvaluator.js +326 -0
- package/dist/core/SignalEvaluator.js.map +1 -0
- package/dist/core/SignalProcessor.d.ts +152 -0
- package/dist/core/SignalProcessor.d.ts.map +1 -0
- package/dist/core/SignalProcessor.js +555 -0
- package/dist/core/SignalProcessor.js.map +1 -0
- package/dist/core/Step.d.ts +43 -32
- package/dist/core/Step.d.ts.map +1 -1
- package/dist/core/Step.js +220 -126
- package/dist/core/Step.js.map +1 -1
- package/dist/core/StreamingToolExecutor.d.ts +2 -2
- package/dist/core/StreamingToolExecutor.d.ts.map +1 -1
- package/dist/core/StreamingToolExecutor.js.map +1 -1
- package/dist/core/ToolManager.d.ts +44 -13
- package/dist/core/ToolManager.d.ts.map +1 -1
- package/dist/core/ToolManager.js +174 -91
- package/dist/core/ToolManager.js.map +1 -1
- package/dist/core/createAgent.d.ts +35 -0
- package/dist/core/createAgent.d.ts.map +1 -0
- package/dist/core/createAgent.js +36 -0
- package/dist/core/createAgent.js.map +1 -0
- package/dist/core/flow-namespace.d.ts +49 -0
- package/dist/core/flow-namespace.d.ts.map +1 -0
- package/dist/core/flow-namespace.js +168 -0
- package/dist/core/flow-namespace.js.map +1 -0
- package/dist/index.d.ts +11 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -12
- package/dist/index.js.map +1 -1
- package/dist/types/agent.d.ts +183 -54
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/agent.js +0 -6
- package/dist/types/agent.js.map +1 -1
- package/dist/types/ai.d.ts +3 -3
- package/dist/types/ai.d.ts.map +1 -1
- package/dist/types/errors.d.ts +15 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +18 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/flow.d.ts +513 -0
- package/dist/types/flow.d.ts.map +1 -0
- package/dist/types/flow.js +5 -0
- package/dist/types/flow.js.map +1 -0
- package/dist/types/index.d.ts +7 -6
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +4 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/persistence.d.ts +11 -7
- package/dist/types/persistence.d.ts.map +1 -1
- package/dist/types/routing.d.ts +1 -1
- package/dist/types/routing.d.ts.map +1 -1
- package/dist/types/session.d.ts +24 -23
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/signals.d.ts +248 -0
- package/dist/types/signals.d.ts.map +1 -0
- package/dist/types/signals.js +10 -0
- package/dist/types/signals.js.map +1 -0
- package/dist/types/template.d.ts +2 -8
- package/dist/types/template.d.ts.map +1 -1
- package/dist/types/tool.d.ts +36 -29
- package/dist/types/tool.d.ts.map +1 -1
- package/dist/types/tool.js +1 -1
- package/dist/types/tool.js.map +1 -1
- package/dist/utils/condition.d.ts +7 -1
- package/dist/utils/condition.d.ts.map +1 -1
- package/dist/utils/condition.js.map +1 -1
- package/dist/utils/id.d.ts +13 -5
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +22 -9
- package/dist/utils/id.js.map +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -2
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/session.d.ts +44 -5
- package/dist/utils/session.d.ts.map +1 -1
- package/dist/utils/session.js +193 -37
- package/dist/utils/session.js.map +1 -1
- package/docs/README.md +15 -202
- package/docs/concepts/architecture.md +281 -0
- package/docs/concepts/directives.md +400 -0
- package/docs/concepts/pipeline.md +399 -0
- package/docs/guides/branching.md +263 -0
- package/docs/guides/compaction.md +163 -0
- package/docs/guides/conditions.md +167 -0
- package/docs/guides/error-handling.md +176 -0
- package/docs/guides/flow-control.md +409 -0
- package/docs/guides/instructions.md +210 -0
- package/docs/guides/persistence.md +182 -0
- package/docs/guides/streaming.md +137 -0
- package/docs/migration/README.md +15 -0
- package/docs/migration/route-to-flow.md +560 -0
- package/docs/migration/v1-to-v2.md +909 -0
- package/docs/reference/adapters.md +481 -0
- package/docs/reference/branches.md +241 -0
- package/docs/reference/create-agent.md +186 -0
- package/docs/reference/directive.md +243 -0
- package/docs/reference/errors.md +122 -0
- package/docs/reference/flow.md +238 -0
- package/docs/reference/instruction.md +177 -0
- package/docs/reference/pre-directive.md +131 -0
- package/docs/reference/providers.md +227 -0
- package/docs/reference/signals.md +356 -0
- package/docs/reference/step.md +339 -0
- package/docs/reference/tool.md +269 -0
- package/docs/start/01-install.md +81 -0
- package/docs/start/02-first-agent.md +196 -0
- package/docs/start/03-collect-data.md +222 -0
- package/docs/start/04-add-tools.md +276 -0
- package/docs/start/05-go-to-production.md +216 -0
- package/examples/01-quickstart.ts +20 -0
- package/examples/02-data-extraction.ts +90 -0
- package/examples/03-tools.ts +136 -0
- package/examples/04-instructions.ts +100 -0
- package/examples/05-branching.ts +140 -0
- package/examples/06-flow-control.ts +103 -0
- package/examples/07-streaming.ts +69 -0
- package/examples/08-persistence.ts +98 -0
- package/examples/09-signals.ts +144 -0
- package/examples/tsconfig.json +30 -0
- package/package.json +2 -1
- package/src/adapters/MemoryAdapter.ts +3 -3
- package/src/adapters/MongoAdapter.ts +3 -3
- package/src/adapters/OpenSearchAdapter.ts +10 -8
- package/src/adapters/PostgreSQLAdapter.ts +26 -10
- package/src/adapters/PrismaAdapter.ts +6 -6
- package/src/adapters/RedisAdapter.ts +3 -3
- package/src/adapters/SQLiteAdapter.ts +31 -12
- package/src/constants/index.ts +2 -10
- package/src/core/Agent.ts +585 -374
- package/src/core/AutoChainExecutor.ts +440 -0
- package/src/core/BranchEvaluator.ts +167 -0
- package/src/core/DirectiveBus.ts +248 -0
- package/src/core/DirectiveChainTracker.ts +144 -0
- package/src/core/Flow.ts +666 -0
- package/src/core/{RoutingEngine.ts → FlowRouter.ts} +385 -365
- package/src/core/PersistenceManager.ts +8 -8
- package/src/core/PromptComposer.ts +209 -140
- package/src/core/PromptSectionCache.ts +1 -1
- package/src/core/ResponseEngine.ts +61 -46
- package/src/core/ResponseModal.ts +1453 -1240
- package/src/core/ResponsePipeline.ts +655 -175
- package/src/core/SignalEvaluator.ts +420 -0
- package/src/core/SignalProcessor.ts +723 -0
- package/src/core/Step.ts +279 -176
- package/src/core/StreamingToolExecutor.ts +4 -4
- package/src/core/ToolManager.ts +200 -97
- package/src/core/createAgent.ts +40 -0
- package/src/core/flow-namespace.ts +219 -0
- package/src/index.ts +42 -36
- package/src/types/agent.ts +182 -53
- package/src/types/ai.ts +3 -3
- package/src/types/errors.ts +18 -0
- package/src/types/flow.ts +590 -0
- package/src/types/index.ts +43 -16
- package/src/types/persistence.ts +12 -8
- package/src/types/routing.ts +1 -1
- package/src/types/session.ts +26 -23
- package/src/types/signals.ts +321 -0
- package/src/types/template.ts +3 -11
- package/src/types/tool.ts +50 -42
- package/src/utils/condition.ts +13 -4
- package/src/utils/id.ts +27 -9
- package/src/utils/index.ts +6 -2
- package/src/utils/session.ts +238 -42
- package/dist/cjs/core/BatchExecutor.d.ts +0 -359
- package/dist/cjs/core/BatchExecutor.d.ts.map +0 -1
- package/dist/cjs/core/BatchExecutor.js +0 -861
- package/dist/cjs/core/BatchExecutor.js.map +0 -1
- package/dist/cjs/core/BatchPromptBuilder.d.ts +0 -89
- package/dist/cjs/core/BatchPromptBuilder.d.ts.map +0 -1
- package/dist/cjs/core/BatchPromptBuilder.js +0 -223
- package/dist/cjs/core/BatchPromptBuilder.js.map +0 -1
- package/dist/cjs/core/Route.d.ts +0 -180
- package/dist/cjs/core/Route.d.ts.map +0 -1
- package/dist/cjs/core/Route.js +0 -542
- package/dist/cjs/core/Route.js.map +0 -1
- package/dist/cjs/core/RoutingEngine.d.ts +0 -185
- package/dist/cjs/core/RoutingEngine.d.ts.map +0 -1
- package/dist/cjs/core/RoutingEngine.js.map +0 -1
- package/dist/cjs/types/route.d.ts +0 -336
- package/dist/cjs/types/route.d.ts.map +0 -1
- package/dist/cjs/types/route.js.map +0 -1
- package/dist/core/BatchExecutor.d.ts +0 -359
- package/dist/core/BatchExecutor.d.ts.map +0 -1
- package/dist/core/BatchExecutor.js +0 -856
- package/dist/core/BatchExecutor.js.map +0 -1
- package/dist/core/BatchPromptBuilder.d.ts +0 -89
- package/dist/core/BatchPromptBuilder.d.ts.map +0 -1
- package/dist/core/BatchPromptBuilder.js +0 -219
- package/dist/core/BatchPromptBuilder.js.map +0 -1
- package/dist/core/Route.d.ts +0 -180
- package/dist/core/Route.d.ts.map +0 -1
- package/dist/core/Route.js +0 -538
- package/dist/core/Route.js.map +0 -1
- package/dist/core/RoutingEngine.d.ts +0 -185
- package/dist/core/RoutingEngine.d.ts.map +0 -1
- package/dist/core/RoutingEngine.js.map +0 -1
- package/dist/types/route.d.ts +0 -336
- package/dist/types/route.d.ts.map +0 -1
- package/dist/types/route.js +0 -5
- package/dist/types/route.js.map +0 -1
- package/docs/CONTRIBUTING.md +0 -521
- package/docs/api/README.md +0 -3299
- package/docs/api/overview.md +0 -1410
- package/docs/architecture/data-extraction-flow.md +0 -360
- package/docs/architecture/multi-step-execution.md +0 -277
- package/docs/core/agent/README.md +0 -938
- package/docs/core/agent/context-management.md +0 -796
- package/docs/core/agent/rules-and-prohibitions.md +0 -113
- package/docs/core/agent/session-management.md +0 -693
- package/docs/core/ai-integration/prompt-composition.md +0 -355
- package/docs/core/ai-integration/providers.md +0 -515
- package/docs/core/ai-integration/response-processing.md +0 -433
- package/docs/core/conversation-flows/data-collection.md +0 -772
- package/docs/core/conversation-flows/route-dsl.md +0 -509
- package/docs/core/conversation-flows/routes.md +0 -249
- package/docs/core/conversation-flows/step-transitions.md +0 -731
- package/docs/core/conversation-flows/steps.md +0 -268
- package/docs/core/error-handling.md +0 -830
- package/docs/core/persistence/adapters.md +0 -255
- package/docs/core/persistence/session-storage.md +0 -656
- package/docs/core/routing/intelligent-routing.md +0 -470
- package/docs/core/tools/enhanced-tool.md +0 -186
- package/docs/core/tools/streaming-execution.md +0 -161
- package/docs/core/tools/tool-definition.md +0 -970
- package/docs/core/tools/tool-scoping.md +0 -819
- package/docs/guides/advanced-patterns/publishing.md +0 -186
- package/docs/guides/context-compaction.md +0 -96
- package/docs/guides/error-handling-patterns.md +0 -578
- package/docs/guides/getting-started/README.md +0 -795
- package/docs/guides/migration/README.md +0 -101
- package/docs/guides/migration/flexible-routing-conditions.md +0 -375
- package/docs/guides/migration/multi-step-execution.md +0 -393
- package/docs/guides/migration/response-modal-refactor.md +0 -518
- package/docs/guides/prompt-optimization.md +0 -164
- package/examples/advanced-patterns/context-compaction.ts +0 -223
- package/examples/advanced-patterns/knowledge-based-agent.ts +0 -735
- package/examples/advanced-patterns/persistent-onboarding.ts +0 -728
- package/examples/advanced-patterns/route-lifecycle-hooks.ts +0 -556
- package/examples/advanced-patterns/streaming-responses.ts +0 -656
- package/examples/ai-providers/anthropic-integration.ts +0 -388
- package/examples/ai-providers/openai-integration.ts +0 -228
- package/examples/condition-patterns/function-only-conditions.ts +0 -365
- package/examples/condition-patterns/mixed-array-conditions.ts +0 -477
- package/examples/condition-patterns/route-skipif-patterns.ts +0 -468
- package/examples/condition-patterns/step-skipif-patterns.ts +0 -0
- package/examples/condition-patterns/string-only-conditions.ts +0 -296
- package/examples/conversation-flows/completion-transitions.ts +0 -318
- package/examples/core-concepts/basic-agent.ts +0 -503
- package/examples/core-concepts/modern-streaming-api.ts +0 -309
- package/examples/core-concepts/schema-driven-extraction.ts +0 -332
- package/examples/core-concepts/session-management.ts +0 -494
- package/examples/integrations/database-integration.ts +0 -631
- package/examples/integrations/healthcare-integration.ts +0 -595
- package/examples/integrations/search-integration.ts +0 -530
- package/examples/integrations/server-session-management.ts +0 -307
- package/examples/persistence/custom-adapter.ts +0 -526
- package/examples/persistence/database-persistence.ts +0 -583
- package/examples/persistence/memory-sessions.ts +0 -495
- package/examples/persistence/prisma-schema.example.prisma +0 -74
- package/examples/persistence/redis-persistence.ts +0 -488
- package/examples/tools/basic-tools.ts +0 -765
- package/examples/tools/data-enrichment-tools.ts +0 -593
- package/examples/tools/enhanced-tool-metadata.ts +0 -268
- package/examples/tools/streaming-tool-execution.ts +0 -283
- package/src/core/BatchExecutor.ts +0 -1187
- package/src/core/BatchPromptBuilder.ts +0 -299
- package/src/core/Route.ts +0 -678
- package/src/types/route.ts +0 -392
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Compaction"
|
|
3
|
+
description: "Keep prompts within token limits across long sessions by layering tool-result budgeting, micro-compaction, and LLM summarization in cost order."
|
|
4
|
+
type: guide
|
|
5
|
+
order: 8
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Compaction
|
|
9
|
+
|
|
10
|
+
> **Where this is introduced:** [Errors](./error-handling.md)
|
|
11
|
+
|
|
12
|
+
Long-running sessions accumulate history. Tool calls return verbose
|
|
13
|
+
JSON, turns pile up, and at some point the next provider call runs
|
|
14
|
+
out of token budget. Compaction is the framework's answer: a layered
|
|
15
|
+
strategy that trims and summarizes `session.history` before each turn
|
|
16
|
+
so the prompt fits without dropping anything load-bearing. Layers run
|
|
17
|
+
in cost order — character-level truncation first, an LLM summarization
|
|
18
|
+
call only when nothing cheaper closes the gap.
|
|
19
|
+
|
|
20
|
+
This guide is task-shaped: enable compaction, choose a budget, and
|
|
21
|
+
understand which layer fires when.
|
|
22
|
+
|
|
23
|
+
## Enable compaction
|
|
24
|
+
|
|
25
|
+
Compaction is opt-in. Set `AgentOptions.compaction` and the agent
|
|
26
|
+
validates the config at construction time, then runs the engine on
|
|
27
|
+
every `respond` / `respondStream` call before the prompt is composed.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { createAgent, GeminiProvider } from "@falai/agent";
|
|
31
|
+
|
|
32
|
+
const agent = createAgent({
|
|
33
|
+
name: "Concierge",
|
|
34
|
+
provider: new GeminiProvider({ apiKey: process.env.GEMINI_API_KEY! }),
|
|
35
|
+
schema: { /* ... */ },
|
|
36
|
+
flows: [/* ... */],
|
|
37
|
+
|
|
38
|
+
compaction: {
|
|
39
|
+
maxTokens: 32_000, // total token budget for the prompt
|
|
40
|
+
compactionThreshold: 0.8, // fire when history hits 80% of maxTokens (default)
|
|
41
|
+
preserveRecentCount: 4, // never touch the last 4 history items (default)
|
|
42
|
+
maxToolResultChars: 5_000, // global cap per tool message (default)
|
|
43
|
+
// enabled: true, // default true when `compaction` is provided
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The four knobs map onto the
|
|
49
|
+
[`AgentCompactionConfig`](../reference/create-agent.md) interface.
|
|
50
|
+
`maxTokens` is the only required field; the rest fall back to the
|
|
51
|
+
defaults shown above. The agent calls `validateOptions` synchronously
|
|
52
|
+
at construction, so misvalued thresholds (`compactionThreshold` outside
|
|
53
|
+
`[0.5, 0.95]`, `preserveRecentCount < 2`, `maxToolResultChars <= 0`)
|
|
54
|
+
throw immediately rather than silently no-oping at runtime.
|
|
55
|
+
|
|
56
|
+
A second knob lives on every `Tool`: `maxResultSizeChars`. That value
|
|
57
|
+
is enforced by the tool executor the moment a tool returns, before the
|
|
58
|
+
result enters history at all. It and the agent-level `maxToolResultChars`
|
|
59
|
+
work together — per-tool first, global later.
|
|
60
|
+
|
|
61
|
+
## How a turn checks the budget
|
|
62
|
+
|
|
63
|
+
Before each turn, the session manager calls
|
|
64
|
+
`CompactionEngine.checkAndCompact(session.history, options)`. The
|
|
65
|
+
engine estimates the current token count using a character-based
|
|
66
|
+
heuristic (~4 characters per token), compares against
|
|
67
|
+
`maxTokens * compactionThreshold`, and applies the cheapest layer that
|
|
68
|
+
brings history below the threshold. If even the most expensive layer
|
|
69
|
+
cannot, an aggressive truncation fallback removes the oldest items
|
|
70
|
+
until the budget fits.
|
|
71
|
+
|
|
72
|
+
`preserveRecentCount` is honored by every layer. The trailing N items
|
|
73
|
+
of `session.history` are never modified, summarized, or removed —
|
|
74
|
+
recent turns are the one piece of context the engine refuses to spend.
|
|
75
|
+
|
|
76
|
+
## Layer 1 — tool-result budgeting
|
|
77
|
+
|
|
78
|
+
`tool_result_budget` is the cheapest layer. It walks history, finds
|
|
79
|
+
items with `role: "tool"`, and truncates any whose stringified content
|
|
80
|
+
exceeds `maxToolResultChars`. Truncated items get a deterministic
|
|
81
|
+
notice appended:
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
[Truncated: 12834 chars total, showing first 5000]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Character-level and synchronous — no LLM call, no network. It fires
|
|
88
|
+
whenever history crosses the threshold and at least one tool message
|
|
89
|
+
is oversized. For agents that orchestrate verbose APIs (search, SQL,
|
|
90
|
+
web fetches) this layer alone usually keeps the prompt in budget.
|
|
91
|
+
|
|
92
|
+
The per-tool counterpart is `Tool.maxResultSizeChars`. Set it on
|
|
93
|
+
high-volume tools to truncate at execution time, before the result
|
|
94
|
+
ever lands in history. Combine the two: a tight per-tool cap on a
|
|
95
|
+
known-chatty tool, plus a global ceiling at the agent level.
|
|
96
|
+
|
|
97
|
+
## Layer 2 — micro-compaction
|
|
98
|
+
|
|
99
|
+
If `tool_result_budget` is not enough, `micro_compact` runs over the
|
|
100
|
+
already-budgeted history. It compresses verbose tool outputs inline
|
|
101
|
+
by collapsing whitespace runs to a single space and trimming the
|
|
102
|
+
edges. Tool results are the only target — user, assistant, and system
|
|
103
|
+
messages pass through unchanged.
|
|
104
|
+
|
|
105
|
+
Still LLM-free and deterministic. Most effective on tool results that
|
|
106
|
+
contain pretty-printed JSON or multiline text where formatting is
|
|
107
|
+
whitespace-heavy. The recent-N tail (`preserveRecentCount`) is
|
|
108
|
+
preserved verbatim during this pass; the cutoff is `history.length -
|
|
109
|
+
preserveRecentCount`, and only items before that cutoff are
|
|
110
|
+
compressed.
|
|
111
|
+
|
|
112
|
+
## Layer 3 — LLM summarization
|
|
113
|
+
|
|
114
|
+
When neither character-level layer brings the prompt under threshold,
|
|
115
|
+
`auto_compact` dispatches a single `provider.generateMessage` call
|
|
116
|
+
asking the agent's own LLM to summarize the older portion. The result
|
|
117
|
+
becomes one synthetic system message:
|
|
118
|
+
|
|
119
|
+
```text
|
|
120
|
+
[Conversation Summary]
|
|
121
|
+
<summary text from the provider>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
That synthetic item replaces every history item before the
|
|
125
|
+
`preserveRecentCount` tail. The recent tail is appended unchanged. If
|
|
126
|
+
the provider call fails — quota, network, any caught exception — the
|
|
127
|
+
engine falls back to `aggressiveTruncate`: walk older messages newest
|
|
128
|
+
to oldest, keep as many as fit under `maxTokens * compactionThreshold`,
|
|
129
|
+
drop the rest. The strategy field on the result still reads
|
|
130
|
+
`"auto_compact"` so callers can see that summarization was attempted.
|
|
131
|
+
|
|
132
|
+
This layer costs a real provider round-trip. It only fires when
|
|
133
|
+
character-level layers cannot close the gap — in practice, sessions
|
|
134
|
+
with hundreds of long turns or tools that return narrative prose
|
|
135
|
+
rather than structured data.
|
|
136
|
+
|
|
137
|
+
## When each layer fires
|
|
138
|
+
|
|
139
|
+
The `compactionThreshold` ratio is the gate for all three layers. Below
|
|
140
|
+
threshold, `checkAndCompact` returns `strategy: "none"` and history
|
|
141
|
+
passes through untouched. At or above threshold, the engine attempts
|
|
142
|
+
each layer in order and stops as soon as the result drops below the
|
|
143
|
+
threshold:
|
|
144
|
+
|
|
145
|
+
| Estimated tokens | Strategy that fires |
|
|
146
|
+
|------------------|---------------------|
|
|
147
|
+
| `< maxTokens * compactionThreshold` | `none` |
|
|
148
|
+
| `≥ threshold`, oversized tool messages exist | `tool_result_budget` |
|
|
149
|
+
| `≥ threshold` after budgeting | `micro_compact` |
|
|
150
|
+
| `≥ threshold` after micro-compaction | `auto_compact` (LLM call) |
|
|
151
|
+
| LLM call failed | `auto_compact` (truncation fallback) |
|
|
152
|
+
|
|
153
|
+
The result's `messagesCompacted` count and optional `summary` field
|
|
154
|
+
are logged at `info` level so production logs show which layer fired
|
|
155
|
+
on which turn.
|
|
156
|
+
|
|
157
|
+
A practical defaults sketch: set `maxTokens` to ~80% of the model's
|
|
158
|
+
context window, leave `compactionThreshold` at the 0.8 default, and
|
|
159
|
+
put a tight per-tool `maxResultSizeChars` on any tool that talks to
|
|
160
|
+
a search API or a database. Pick the budget, set the caps, let the
|
|
161
|
+
layers absorb the noise.
|
|
162
|
+
|
|
163
|
+
**Next:** [Architecture](../concepts/architecture.md)
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "When and if"
|
|
3
|
+
description: "Pick between AI-evaluated `when` strings and code-evaluated `if` predicates, and combine them to save tokens."
|
|
4
|
+
type: guide
|
|
5
|
+
order: 1
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# When and if
|
|
9
|
+
|
|
10
|
+
Conditions decide whether a flow activates, a step runs, an instruction renders, or a branch fires. v2 splits them into two distinct fields with different evaluators:
|
|
11
|
+
|
|
12
|
+
- `when` — strings the LLM evaluates against intent and the conversation. Costs tokens.
|
|
13
|
+
- `if` — TypeScript predicates the engine evaluates locally. Free.
|
|
14
|
+
|
|
15
|
+
The split is the same everywhere: `Flow`, `Step`, `Instruction`, and `BranchEntry` all expose `when?` and `if?` with identical semantics. This guide shows how to pick between them, how arrays combine, and what happens when both are set. If you are migrating from v1, the [v1 → v2 migration guide](../migration/v1-to-v2.md) covers the renamed condition fields.
|
|
16
|
+
|
|
17
|
+
## Pick the right field
|
|
18
|
+
|
|
19
|
+
Reach for `if` first. It's free, deterministic, and reads clearly in code review.
|
|
20
|
+
|
|
21
|
+
| Question to answer | Use |
|
|
22
|
+
| --------------------------------------------------------------- | -------- |
|
|
23
|
+
| Is this user authenticated? Is `data.tier === 'pro'`? | `if` |
|
|
24
|
+
| Is the feature flag on? Is the order older than 90 days? | `if` |
|
|
25
|
+
| Did the user ask about pricing? Are they expressing frustration? | `when` |
|
|
26
|
+
| Is the user describing a refund scenario in their own words? | `when` |
|
|
27
|
+
|
|
28
|
+
If the answer lives in `data`, `context`, or `session`, it's `if`. If the answer requires reading the user's intent from natural language, it's `when`.
|
|
29
|
+
|
|
30
|
+
## `when` — AI strings
|
|
31
|
+
|
|
32
|
+
`when` accepts a string or an array of strings. Functions are rejected at construction time with `FlowConfigurationError`.
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
{
|
|
36
|
+
title: "Refund",
|
|
37
|
+
when: "the user is requesting a refund",
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Multiple strings combine with **AND** semantics — every clause must pass for the condition to match.
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
{
|
|
45
|
+
title: "Premium Refund",
|
|
46
|
+
when: [
|
|
47
|
+
"the user is requesting a refund",
|
|
48
|
+
"the user is asking about an enterprise plan",
|
|
49
|
+
],
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The strings are sent to the LLM as part of the routing or activation prompt. Keep them short, intent-shaped, and free of code-style boolean expressions — `"the user wants to cancel"` lands; `"data.cancelRequested === true"` does not.
|
|
54
|
+
|
|
55
|
+
## `if` — code predicates
|
|
56
|
+
|
|
57
|
+
`if` accepts a function or an array of functions. Each predicate receives a `TemplateContext`-shaped argument (`{ context, data, session, history, helpers }`) and returns `boolean | Promise<boolean>`.
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
{
|
|
61
|
+
title: "Enterprise",
|
|
62
|
+
if: ({ context }) => context.tier === "enterprise",
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Arrays combine with **AND** semantics — every predicate must return truthy.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
{
|
|
70
|
+
if: [
|
|
71
|
+
({ context }) => context.authenticated,
|
|
72
|
+
({ data }) => (data.cartTotal ?? 0) > 100,
|
|
73
|
+
],
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Predicates that throw or reject are caught, logged, and treated as `false` for that evaluation. They never corrupt the session — the worst case is the condition fails to match.
|
|
78
|
+
|
|
79
|
+
### What's in the predicate context
|
|
80
|
+
|
|
81
|
+
Predicates receive a context object with the same shape used everywhere templates and conditions evaluate. The fields you'll reach for most:
|
|
82
|
+
|
|
83
|
+
| Field | Type | Notes |
|
|
84
|
+
| ---------- | ------------------------ | ---------------------------------------------------------------- |
|
|
85
|
+
| `data` | `Partial<TData>` | Collected schema fields. Null-check anything not in `requires`. |
|
|
86
|
+
| `context` | `TContext` | Agent-level ambient context (user, env, services). |
|
|
87
|
+
| `session` | `SessionState<TData>` | Current flow id, current step id, full history. |
|
|
88
|
+
| `history` | `Event[]` | Read-only conversation history. |
|
|
89
|
+
|
|
90
|
+
Predicates can be `async`. Awaiting a database lookup or feature-flag service is supported, but remember: every predicate runs every time its host primitive is evaluated. Keep them cheap, or memoize the work in a hook upstream.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
{
|
|
94
|
+
if: async ({ context, data }) =>
|
|
95
|
+
await context.flags.isEnabled("v2_pricing", data.userId),
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## When both are set
|
|
100
|
+
|
|
101
|
+
Setting both `when` and `if` on the same primitive runs `if` **first**, free. `when` is only sent to the LLM when every `if` predicate passes. The order is deliberate: predicates short-circuit the LLM call when the answer is already disqualified.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
{
|
|
105
|
+
title: "US Pricing",
|
|
106
|
+
if: ({ context }) => context.country === "US" && context.flags.usPricing,
|
|
107
|
+
when: "the user is asking about pricing",
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
In the snippet above, non-US users skip the AI evaluation entirely. The `when` string costs tokens only when the predicate already says "this user is in scope, ask the AI whether they're asking about pricing."
|
|
112
|
+
|
|
113
|
+
This pattern is the recommended shape any time a condition has both a cheap precondition and an intent classification. Lead with `if` to gate. Use `when` to interpret.
|
|
114
|
+
|
|
115
|
+
## Where the split lives
|
|
116
|
+
|
|
117
|
+
The same `when` / `if` shape attaches to four primitives. Semantics are identical in each location:
|
|
118
|
+
|
|
119
|
+
| Primitive | Field path | What it gates |
|
|
120
|
+
| --------------- | ----------------------- | -------------------------------------------------- |
|
|
121
|
+
| Flow | `FlowOptions.when/if` | Whether the router selects this flow this turn |
|
|
122
|
+
| Step | `StepOptions.when/if` | Whether the step is reachable in the current flow |
|
|
123
|
+
| Instruction | `Instruction.when/if` | Whether the instruction renders into the prompt |
|
|
124
|
+
| BranchEntry | `BranchEntry.when/if` | Whether this branch entry matches inside `step.branches` |
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// Flow scope — gate flow selection
|
|
128
|
+
{ title: "Refund", when: "user wants a refund", if: ({ context }) => context.authenticated }
|
|
129
|
+
|
|
130
|
+
// Step scope — gate step reachability
|
|
131
|
+
{ id: "verify_payment", when: "user is confirming the order", if: ({ data }) => !!data.cardToken }
|
|
132
|
+
|
|
133
|
+
// Instruction scope — render only when relevant
|
|
134
|
+
{ kind: "should", when: "user mentions a discount code", prompt: "Validate the code before applying it." }
|
|
135
|
+
|
|
136
|
+
// Branch scope — pick a successor
|
|
137
|
+
branches: [
|
|
138
|
+
{ if: ({ data }) => data.tier === "enterprise", when: "user wants pricing", then: "enterprise_pricing" },
|
|
139
|
+
{ then: "default_pricing" },
|
|
140
|
+
]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## `step.skip` is the OR companion
|
|
144
|
+
|
|
145
|
+
One adjacent field rounds out the picture. `step.skip` is **function-only** with **OR** semantics — when any predicate returns truthy, the step is bypassed. Use it for "skip when this field already exists" cases:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
{
|
|
149
|
+
id: "ask_email",
|
|
150
|
+
collect: ["email"],
|
|
151
|
+
skip: ({ data }) => !!data.email,
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`skip` does not accept strings. There is no AI counterpart — skipping is a code decision by design.
|
|
156
|
+
|
|
157
|
+
## Quick reference
|
|
158
|
+
|
|
159
|
+
A short checklist before shipping a condition:
|
|
160
|
+
|
|
161
|
+
- Does it read a field, flag, or context value? Use `if`.
|
|
162
|
+
- Does it interpret natural language? Use `when`.
|
|
163
|
+
- Multiple clauses that all must pass? Drop them in an array — both fields AND.
|
|
164
|
+
- Need to skip when a value is already collected? `step.skip` (OR semantics).
|
|
165
|
+
- Both fields set? `if` runs first, free; `when` only fires if `if` passes.
|
|
166
|
+
|
|
167
|
+
**Next:** [Branching](./branching.md)
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Errors"
|
|
3
|
+
description: "Catch the typed error classes by class, narrow them with instanceof, and recover with the right pattern for each failure mode."
|
|
4
|
+
type: guide
|
|
5
|
+
order: 7
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Errors
|
|
9
|
+
|
|
10
|
+
`@falai/agent` throws typed `Error` subclasses for every failure mode the framework owns. Catching `Error` is fine for telemetry, but recovering well needs class-level narrowing — a `DataValidationError` wants a re-prompt, a `ToolExecutionError` wants a soft message and maybe a redirect, a `FlowConfigurationError` wants to crash the build. This page is the recipe for each. The full surface lives in the [errors reference](../reference/errors.md).
|
|
11
|
+
|
|
12
|
+
## The format contract
|
|
13
|
+
|
|
14
|
+
Every thrown message follows the same shape:
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
[<ErrorClass>] <what>: <why>. <how to fix>.
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The bracketed prefix mirrors the class name. The colon separates `<what>` from `<why>`. The trailing sentence is `<how to fix>`. The contract is uniform across the five classes the framework throws — `FlowConfigurationError`, `DataValidationError`, `ToolExecutionError`, `ResponseGenerationError`, and `NotImplementedError` — so log lines and `try/catch` blocks parse the same way regardless of which class fired.
|
|
21
|
+
|
|
22
|
+
The format applies to framework-thrown errors. If you write a custom tool or hook that throws, follow the same shape so downstream handlers stay uniform.
|
|
23
|
+
|
|
24
|
+
## The five classes
|
|
25
|
+
|
|
26
|
+
| Class | Thrown when | Recover by |
|
|
27
|
+
|-------|-------------|------------|
|
|
28
|
+
| `FlowConfigurationError` | Misconfigured agent: duplicate ids, unknown `collect` keys, malformed `Directive`, branch targets that don't resolve, auto-step cycles, function on `when`. | Don't. Surface in CI. |
|
|
29
|
+
| `DataValidationError` | A user message produces a value that violates the declared `schema`. | Re-prompt the user for the offending fields. |
|
|
30
|
+
| `ToolExecutionError` | A tool handler throws, all retries fail, or `validateInput` cannot correct invalid args. | User-friendly message, optional retry, optional `agent.dispatch` to a recovery flow. |
|
|
31
|
+
| `ResponseGenerationError` | The provider call fails or the response cannot be parsed. | Backoff retry, fall back to a different provider, or surface a soft failure. |
|
|
32
|
+
| `NotImplementedError` | A reserved option is set to a value this version does not support (e.g. `routerMode: 'embedding'` in v2.0). | Use a supported value. Same posture as `FlowConfigurationError`. |
|
|
33
|
+
|
|
34
|
+
`FlowConfigurationError`, `ToolExecutionError`, and `NotImplementedError` are exported from `@falai/agent` and matchable with `instanceof`. `DataValidationError` and `ResponseGenerationError` are internal — match them by `error.name`.
|
|
35
|
+
|
|
36
|
+
## Pattern 1: try/catch + instanceof narrowing
|
|
37
|
+
|
|
38
|
+
Wrap every `agent.respond` and `agent.respondStream` call site. Narrow by class, return the right user-facing string per branch, rethrow what cannot be recovered.
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import {
|
|
42
|
+
FlowConfigurationError,
|
|
43
|
+
ToolExecutionError,
|
|
44
|
+
NotImplementedError,
|
|
45
|
+
} from "@falai/agent";
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const response = await agent.respond({ history, session });
|
|
49
|
+
return response.message;
|
|
50
|
+
} catch (err) {
|
|
51
|
+
if (err instanceof FlowConfigurationError) throw err; // bug — bubble up
|
|
52
|
+
if (err instanceof NotImplementedError) throw err; // config bug — bubble up
|
|
53
|
+
if (err instanceof ToolExecutionError) {
|
|
54
|
+
log.warn({ toolId: err.toolId, cause: err.cause }, err.message);
|
|
55
|
+
return "Sorry — that action failed. Try again in a moment.";
|
|
56
|
+
}
|
|
57
|
+
if (err instanceof Error && err.name === "DataValidationError") {
|
|
58
|
+
return "I need a couple of details cleared up — let's try that again.";
|
|
59
|
+
}
|
|
60
|
+
if (err instanceof Error && err.name === "ResponseGenerationError") {
|
|
61
|
+
return "I'm having trouble reaching the model. Please retry.";
|
|
62
|
+
}
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The two unrecoverable classes — `FlowConfigurationError` and `NotImplementedError` — get rethrown so the process crashes loudly. The other three return a graceful message. Anything unexpected falls through to the outer rethrow.
|
|
68
|
+
|
|
69
|
+
## Pattern 2: DataValidationError → re-prompt
|
|
70
|
+
|
|
71
|
+
A `DataValidationError` carries an `errors: ValidationError[]` array naming the offending fields. Use it to ask the user a targeted clarifying question instead of a generic one.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
} catch (err) {
|
|
75
|
+
if (err instanceof Error && err.name === "DataValidationError") {
|
|
76
|
+
const fields = (err as { errors: { path: string; message: string }[] }).errors
|
|
77
|
+
.map((e) => `${e.path} (${e.message})`)
|
|
78
|
+
.join(", ");
|
|
79
|
+
return `I couldn't read these from your message: ${fields}. Mind clarifying?`;
|
|
80
|
+
}
|
|
81
|
+
// ...
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The framework does not retry by itself — the next user turn is the retry. Keep `session` alive between turns so the partial collection survives.
|
|
86
|
+
|
|
87
|
+
## Pattern 3: ToolExecutionError → message, retry, or dispatch
|
|
88
|
+
|
|
89
|
+
Tool failures have three shapes. Pick by what the failing tool was doing.
|
|
90
|
+
|
|
91
|
+
**Soft failure — speak and continue.** A read-only tool that timed out: tell the user, let the conversation move on.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
if (err instanceof ToolExecutionError) {
|
|
95
|
+
log.warn({ toolId: err.toolId }, err.message);
|
|
96
|
+
return "I couldn't fetch that just now. Want to try again?";
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Optional retry.** Wrap the `respond` call in a small retry loop for transient errors.
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
104
|
+
try {
|
|
105
|
+
return (await agent.respond({ history, session })).message;
|
|
106
|
+
} catch (err) {
|
|
107
|
+
if (err instanceof ToolExecutionError && attempt === 0) {
|
|
108
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
throw err;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Recovery flow.** Hard failures — a payment tool that hit a permanent denial — should redirect into a recovery flow rather than echo the error. Dispatch a directive against the session so the *next* turn enters the recovery flow.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
if (err instanceof ToolExecutionError && err.toolId === "charge_card") {
|
|
120
|
+
await agent.dispatch(session, { goTo: "PaymentRecovery" });
|
|
121
|
+
return "I hit a snag with that payment. Let me walk you through it.";
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The dispatched [`Directive`](../reference/directive.md) lands in `session.pendingDirective` and is consumed at the start of the next turn.
|
|
126
|
+
|
|
127
|
+
## Pattern 4: ResponseGenerationError → backoff or fallback provider
|
|
128
|
+
|
|
129
|
+
Provider errors are usually transient. Retry with backoff first; fall back to a second provider only if the primary keeps failing.
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
async function respondWithFallback(history: HistoryItem[], session: Session) {
|
|
133
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
134
|
+
try {
|
|
135
|
+
return await primaryAgent.respond({ history, session });
|
|
136
|
+
} catch (err) {
|
|
137
|
+
if (err instanceof Error && err.name === "ResponseGenerationError") {
|
|
138
|
+
await new Promise((r) => setTimeout(r, 200 * 2 ** attempt));
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
throw err;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return fallbackAgent.respond({ history, session });
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Both agents share the same `flows`, `tools`, and `schema` — only the `provider` differs. The session is provider-agnostic, so the fallback picks up exactly where the primary left off.
|
|
149
|
+
|
|
150
|
+
## Pattern 5: FlowConfigurationError → don't catch in production
|
|
151
|
+
|
|
152
|
+
`FlowConfigurationError` is a *bug*, not a runtime condition. It fires when the agent definition is malformed: a step references a flow id that doesn't exist, two steps share a `collect` key, a branch target points nowhere, an auto-step chain loops. The right place to catch it is the test runner and CI — never the request path.
|
|
153
|
+
|
|
154
|
+
Smoke-test agent construction in CI so misconfiguration crashes the build rather than the first user request:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { describe, expect, it } from "bun:test";
|
|
158
|
+
import { FlowConfigurationError } from "@falai/agent";
|
|
159
|
+
import { buildAgent } from "../src/agent";
|
|
160
|
+
|
|
161
|
+
describe("agent construction", () => {
|
|
162
|
+
it("builds without configuration errors", () => {
|
|
163
|
+
expect(() => buildAgent()).not.toThrow(FlowConfigurationError);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
In the request handler, let it bubble all the way up. A 500 plus a loud log is the correct outcome — the next deploy is the fix.
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
if (err instanceof FlowConfigurationError) throw err;
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`NotImplementedError` follows the same posture: it means a reserved option was set to a value this version doesn't support. Read the message, fix the config, ship the fix. Don't catch it.
|
|
175
|
+
|
|
176
|
+
**Next:** [Compaction](./compaction.md)
|