@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,409 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Flow control"
|
|
3
|
+
description: "Redirect, complete, abort, or speak verbatim from a tool, hook, or webhook by emitting a directive."
|
|
4
|
+
type: guide
|
|
5
|
+
order: 3
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Flow control
|
|
9
|
+
|
|
10
|
+
> **Where this is introduced:** [Directives](../concepts/directives.md)
|
|
11
|
+
|
|
12
|
+
Most steps run, ask the model, write fields, and move on. Some don't.
|
|
13
|
+
A permission tool finds the caller is not eligible. A booking tool
|
|
14
|
+
finishes its work and wants the flow to end without the LLM phrasing a
|
|
15
|
+
confirmation. A webhook decides the next turn should start in a
|
|
16
|
+
different flow than where the user left off. Every one of these is the
|
|
17
|
+
same primitive: emit a [`Directive`](../reference/directive.md).
|
|
18
|
+
|
|
19
|
+
This guide is a tour of the recipes. Each section is a task and a
|
|
20
|
+
code-block that does it. The shape stays the same across all of them;
|
|
21
|
+
what changes is which fields you set and where the directive comes
|
|
22
|
+
from. The [Directive reference](../reference/directive.md) is the
|
|
23
|
+
canonical contract for every shorthand, object form, and validation
|
|
24
|
+
rule.
|
|
25
|
+
|
|
26
|
+
## The shape
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import type { Directive } from "@falai/agent";
|
|
30
|
+
|
|
31
|
+
const d: Directive = {
|
|
32
|
+
goTo: "Booking", // position (one max)
|
|
33
|
+
reply: "Routing you to booking.", // verbatim utterance
|
|
34
|
+
dataUpdate: { source: "tool" }, // state write
|
|
35
|
+
};
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Every field is optional. State writes (`dataUpdate`,
|
|
39
|
+
`contextUpdate`) and `reply` ride alongside any position field.
|
|
40
|
+
|
|
41
|
+
## Position fields and precedence
|
|
42
|
+
|
|
43
|
+
Position answers "where does the conversation go after this turn?"
|
|
44
|
+
|
|
45
|
+
| Field | Effect |
|
|
46
|
+
|------------|-----------------------------------------------------------------------|
|
|
47
|
+
| `goTo` | Jump to another flow. |
|
|
48
|
+
| `goToStep` | Jump to a step (within this flow, or — in object form — another flow).|
|
|
49
|
+
| `complete` | Mark the current flow done. Run the flow's completion path. |
|
|
50
|
+
| `abort` | End the conversation. Optionally clear the session. |
|
|
51
|
+
| `reset` | Restart the current flow. Optionally clear its declared fields. |
|
|
52
|
+
|
|
53
|
+
The fields are **mutually exclusive** — at most one per directive.
|
|
54
|
+
Setting two throws `FlowConfigurationError`. When more than one
|
|
55
|
+
emitter writes a position field on the same turn, the per-turn merge
|
|
56
|
+
picks one winner by precedence:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
abort > complete > goTo / goToStep > reset
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`abort` always wins — there's no "somewhere else" after the
|
|
63
|
+
conversation has ended. `complete` beats `goTo` — if a follow-up
|
|
64
|
+
jump belongs after completion, put it in `complete.next`. `goTo` and
|
|
65
|
+
`goToStep` share a tier (last emission wins). `reset` is lowest.
|
|
66
|
+
|
|
67
|
+
State writes and `reply` ride alongside whichever position wins.
|
|
68
|
+
|
|
69
|
+
## Recipe 1 — Redirect from a tool
|
|
70
|
+
|
|
71
|
+
Tools have two ways to emit a directive: imperative (`ctx.dispatch`)
|
|
72
|
+
mid-handler, or declarative (`ToolResult.directive`) on return. Both
|
|
73
|
+
land on the same per-turn bus and merge identically.
|
|
74
|
+
|
|
75
|
+
### Imperative — `ctx.dispatch`
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import type { Tool } from "@falai/agent";
|
|
79
|
+
|
|
80
|
+
const checkEligibility: Tool<{ userId: string }, BookingData, { ok: boolean }> = {
|
|
81
|
+
id: "check_eligibility",
|
|
82
|
+
description: "Verify the caller is allowed to book this destination.",
|
|
83
|
+
isReadOnly: () => true,
|
|
84
|
+
async handler(ctx) {
|
|
85
|
+
const ok = await isEligible(ctx.context.userId, ctx.data.destination);
|
|
86
|
+
if (!ok) {
|
|
87
|
+
ctx.dispatch({
|
|
88
|
+
goTo: "Denial",
|
|
89
|
+
reply: "Sorry — you're not eligible to book that destination.",
|
|
90
|
+
dataUpdate: { denialReason: "ineligible" },
|
|
91
|
+
});
|
|
92
|
+
return { ok: false };
|
|
93
|
+
}
|
|
94
|
+
return { ok: true };
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Multiple `dispatch` calls in one handler are allowed — they
|
|
100
|
+
concatenate alongside emissions from other tools and hooks before the
|
|
101
|
+
merge runs.
|
|
102
|
+
|
|
103
|
+
### Declarative — `ToolResult.directive`
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
async handler(ctx) {
|
|
107
|
+
const ok = await isEligible(ctx.context.userId, ctx.data.destination);
|
|
108
|
+
if (!ok) {
|
|
109
|
+
return {
|
|
110
|
+
data: { ok: false },
|
|
111
|
+
directive: {
|
|
112
|
+
goTo: "Denial",
|
|
113
|
+
reply: "Sorry — you're not eligible to book that destination.",
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return { data: { ok: true } };
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Reach for **imperative** when the handler still has work after the
|
|
122
|
+
decision. Reach for **declarative** when there's a single return
|
|
123
|
+
point.
|
|
124
|
+
|
|
125
|
+
## Recipe 2 — Complete with a chained next
|
|
126
|
+
|
|
127
|
+
A booking tool reserved the room. The flow is done, and the next
|
|
128
|
+
thing the agent should do is open a feedback flow. `complete` accepts
|
|
129
|
+
an object form whose `next` field is **another directive** applied
|
|
130
|
+
immediately after the flow's completion path runs:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import type { Tool, Directive } from "@falai/agent";
|
|
134
|
+
|
|
135
|
+
const bookHotel: Tool<unknown, BookingData, { id: string }> = {
|
|
136
|
+
id: "book_hotel",
|
|
137
|
+
description: "Reserve the hotel for the collected fields.",
|
|
138
|
+
async handler(ctx, args) {
|
|
139
|
+
const id = await reserve(args);
|
|
140
|
+
const directive: Directive = {
|
|
141
|
+
complete: {
|
|
142
|
+
reason: "reservation confirmed",
|
|
143
|
+
next: { goTo: "Feedback", reply: "Booked. Mind a quick survey?" },
|
|
144
|
+
},
|
|
145
|
+
dataUpdate: { bookingId: id },
|
|
146
|
+
};
|
|
147
|
+
return { data: { id }, directive };
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
What runs, in order: the tool's directive lands on the bus, the merge
|
|
153
|
+
picks `complete`, the flow's `hooks.onComplete` runs, then
|
|
154
|
+
`complete.next` is applied — `goTo: "Feedback"` redirects with the
|
|
155
|
+
verbatim reply as that turn's assistant message.
|
|
156
|
+
|
|
157
|
+
`complete.next` is one level deep on purpose — chains do not nest.
|
|
158
|
+
For the simple case, the shorthand `complete: true` is the right
|
|
159
|
+
call:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
return { data, directive: { complete: true, dataUpdate: { bookingId: id } } };
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Recipe 3 — Abort on a permission failure
|
|
166
|
+
|
|
167
|
+
`abort` ends the conversation. Use it when there's no flow to
|
|
168
|
+
redirect *to*:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import type { Tool, Directive } from "@falai/agent";
|
|
172
|
+
|
|
173
|
+
const verifyAccess: Tool = {
|
|
174
|
+
id: "verify_access",
|
|
175
|
+
isReadOnly: () => true,
|
|
176
|
+
async handler(ctx) {
|
|
177
|
+
const allowed = await acl.check(ctx.context.userId);
|
|
178
|
+
if (!allowed) {
|
|
179
|
+
const directive: Directive = {
|
|
180
|
+
abort: { reason: "caller is not on the allow-list", clearSession: true },
|
|
181
|
+
};
|
|
182
|
+
return { data: { allowed: false }, directive };
|
|
183
|
+
}
|
|
184
|
+
return { data: { allowed: true } };
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Two things to know:
|
|
190
|
+
|
|
191
|
+
- **`abort` cannot co-exist with `reply`.** Aborted conversations
|
|
192
|
+
don't deliver replies. To say something on the way out, use
|
|
193
|
+
`complete` plus `reply` instead.
|
|
194
|
+
- **`clearSession: true`** purges the session at the next persistence
|
|
195
|
+
write. Without it, the aborted session sticks around for traces.
|
|
196
|
+
|
|
197
|
+
## Recipe 4 — Reply verbatim from a finalize hook
|
|
198
|
+
|
|
199
|
+
Some utterances should be exact: confirmations, bridges, refusals,
|
|
200
|
+
boilerplate at flow boundaries. `reply: string` skips the LLM and
|
|
201
|
+
emits the literal text — no templating, no model rephrasing.
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
import type { Directive } from "@falai/agent";
|
|
205
|
+
|
|
206
|
+
const step = {
|
|
207
|
+
id: "confirm_handoff",
|
|
208
|
+
prompt: "Confirm the handoff if the queue is clear.",
|
|
209
|
+
hooks: {
|
|
210
|
+
finalize: ({ data }): Directive | void => {
|
|
211
|
+
if (data.handoffReady) {
|
|
212
|
+
return { reply: "Connecting you with a specialist now." };
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
The turn ends with `stoppedReason: "reply"` and the literal string as
|
|
220
|
+
`response.message`. State writes and a position field can ride
|
|
221
|
+
alongside:
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
finalize: ({ data }) => {
|
|
225
|
+
if (data.bookingId) {
|
|
226
|
+
return {
|
|
227
|
+
reply: `Booked. Confirmation: ${data.bookingId}.`,
|
|
228
|
+
dataUpdate: { confirmedAt: new Date().toISOString() },
|
|
229
|
+
complete: true,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
That single directive does three things at once. They're orthogonal
|
|
236
|
+
payloads — `reply`, `dataUpdate`, and the position field don't
|
|
237
|
+
compete for the same slot.
|
|
238
|
+
|
|
239
|
+
To skip the LLM **before** it runs (rather than from a finalize hook
|
|
240
|
+
*after*), use a [`PreDirective`](../reference/pre-directive.md) from
|
|
241
|
+
a prepare hook with `halt: true` — see below.
|
|
242
|
+
|
|
243
|
+
## PreDirective extras (pre-LLM only)
|
|
244
|
+
|
|
245
|
+
Pre-LLM hooks (`flow.hooks.onEnter`, `step.hooks.onEnter`,
|
|
246
|
+
`step.hooks.prepare`) return a [`PreDirective`](../reference/pre-directive.md) —
|
|
247
|
+
the `Directive` variant with three extra fields that only make sense
|
|
248
|
+
before this turn's LLM call.
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
interface PreDirective extends Directive {
|
|
252
|
+
appendPrompt?: string[];
|
|
253
|
+
injectTools?: Tool[];
|
|
254
|
+
halt?: boolean;
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Lifetime is one turn. None of the three fields persist on
|
|
259
|
+
`session.pendingDirective` — they're stripped before the write.
|
|
260
|
+
Returning a PreDirective from a post-LLM hook drops these fields with
|
|
261
|
+
a debug log.
|
|
262
|
+
|
|
263
|
+
### `appendPrompt` — nudge the system prompt
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
const flow = {
|
|
267
|
+
title: "Booking",
|
|
268
|
+
hooks: {
|
|
269
|
+
onEnter: (ctx) => {
|
|
270
|
+
if (ctx.context.user.tier === "vip") {
|
|
271
|
+
return { appendPrompt: ["Caller is a VIP — confirm preferences first."] };
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Each string is appended to the system prompt for this turn only.
|
|
279
|
+
Multiple emitters' arrays concatenate in emission order; duplicates
|
|
280
|
+
are preserved.
|
|
281
|
+
|
|
282
|
+
### `injectTools` — one-shot tool surface
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
const step = {
|
|
286
|
+
id: "verify",
|
|
287
|
+
prompt: "Verify the caller before proceeding.",
|
|
288
|
+
hooks: {
|
|
289
|
+
prepare: async (ctx) => {
|
|
290
|
+
if (!ctx.data.verified) return { injectTools: [lookupAccount] };
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Tools listed here are added for this turn only. Multiple emitters'
|
|
297
|
+
arrays concatenate, then dedupe by `Tool.id` (last definition wins).
|
|
298
|
+
|
|
299
|
+
### `halt` — skip the LLM call
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
prepare: async (ctx) => {
|
|
303
|
+
if (ctx.data.alreadyVerified) {
|
|
304
|
+
return { halt: true, reply: "Already verified. How can I help?" };
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
When any pre-phase emitter sets `halt: true`, the LLM call is
|
|
310
|
+
skipped. With `reply`, the turn ends `stoppedReason: "reply"`. Without
|
|
311
|
+
`reply`, the turn ends `stoppedReason: "halt"` and an empty body.
|
|
312
|
+
Multiple emitters merge by logical-OR.
|
|
313
|
+
|
|
314
|
+
## Recipe 5 — Dispatch from outside a turn
|
|
315
|
+
|
|
316
|
+
Tools and hooks emit directives onto the **per-turn** bus. Sometimes
|
|
317
|
+
the redirect comes from outside any turn — a webhook fires, a
|
|
318
|
+
scheduled job notices an idle session, an external system marks a
|
|
319
|
+
caller upgraded. There's no turn running, so there's no bus.
|
|
320
|
+
|
|
321
|
+
`Agent.dispatch(target, session)` writes a `pendingDirective` onto
|
|
322
|
+
the session without invoking a turn. The directive is consumed at the
|
|
323
|
+
**start of the next** `respond` call — before routing, before
|
|
324
|
+
pre-extraction, before any phase runs.
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
// Webhook handler: redirect a session from outside a turn.
|
|
328
|
+
import type { Directive } from "@falai/agent";
|
|
329
|
+
|
|
330
|
+
app.post("/webhook/account-upgraded", async (req, res) => {
|
|
331
|
+
const session = await agent.session.getOrCreate(req.body.sessionId);
|
|
332
|
+
await agent.dispatch(
|
|
333
|
+
{ goTo: "VipFlow", reply: "You've been upgraded. Let's start fresh." },
|
|
334
|
+
session
|
|
335
|
+
);
|
|
336
|
+
res.sendStatus(204);
|
|
337
|
+
});
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Two forms:
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
// String shorthand — desugars to { goTo: "Feedback" }
|
|
344
|
+
await agent.dispatch("Feedback", session);
|
|
345
|
+
|
|
346
|
+
// Full directive
|
|
347
|
+
await agent.dispatch({ goTo: "Billing", reply: "Transferring you now." }, session);
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
The call validates the directive (`flow.validate`), confirms any
|
|
351
|
+
`goTo`-named flow exists (throws `FlowConfigurationError` if not),
|
|
352
|
+
strips PreDirective-only fields, writes `pendingDirective` onto the
|
|
353
|
+
session, and persists if an adapter is configured.
|
|
354
|
+
|
|
355
|
+
`pendingDirective` is **single-shot** — consumed exactly once and
|
|
356
|
+
cleared. Calling `dispatch` again before the next turn overwrites the
|
|
357
|
+
previous one (last-wins). To merge with a pending directive instead
|
|
358
|
+
of overwriting, use `flow.merge`:
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
import { flow } from "@falai/agent";
|
|
362
|
+
|
|
363
|
+
const merged = flow.merge(
|
|
364
|
+
session.pendingDirective ?? {},
|
|
365
|
+
{ dataUpdate: { tier: "vip" } }
|
|
366
|
+
);
|
|
367
|
+
await agent.dispatch(merged, session);
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Picking the right tool
|
|
371
|
+
|
|
372
|
+
Where to emit:
|
|
373
|
+
|
|
374
|
+
| You're in a... | Type | Use |
|
|
375
|
+
|----------------|------|-----|
|
|
376
|
+
| Tool handler, mid-flight | `Directive` | `ctx.dispatch(d)` |
|
|
377
|
+
| Tool handler, on return | `Directive` | `return { data, directive: d }` |
|
|
378
|
+
| `prepare` / `onEnter` hook | `PreDirective` | `return d` |
|
|
379
|
+
| `finalize` / `onComplete` hook | `Directive` | `return d` |
|
|
380
|
+
| Branch `then` target | `Directive` | `then: d` (see [Branching](./branching.md)) |
|
|
381
|
+
| Outside a turn (webhook, job) | `Directive` | `await agent.dispatch(d, session)` |
|
|
382
|
+
|
|
383
|
+
Which position field:
|
|
384
|
+
|
|
385
|
+
- Inside the same flow → `goToStep`.
|
|
386
|
+
- Another flow → `goTo` (or `goToStep` with `flow:` set).
|
|
387
|
+
- Work is done → `complete` (with `complete.next` for follow-ups).
|
|
388
|
+
- No path forward → `abort` (`clearSession: true` if reuse is unsafe).
|
|
389
|
+
- Start the flow over → `reset`.
|
|
390
|
+
|
|
391
|
+
Code or model speaking:
|
|
392
|
+
|
|
393
|
+
- Verbatim → set `reply`.
|
|
394
|
+
- From the model → leave `reply` unset; let the LLM call run.
|
|
395
|
+
|
|
396
|
+
## See also
|
|
397
|
+
|
|
398
|
+
- [Directive reference](../reference/directive.md) — every field,
|
|
399
|
+
every shorthand, every validation rule.
|
|
400
|
+
- [PreDirective reference](../reference/pre-directive.md) —
|
|
401
|
+
pre-LLM-only fields and merge rules.
|
|
402
|
+
- [Directives concept](../concepts/directives.md) — the mental model
|
|
403
|
+
and the inheritance chain.
|
|
404
|
+
- [Branching](./branching.md) — when the redirect is source-local
|
|
405
|
+
rather than dynamic.
|
|
406
|
+
- [Turn pipeline](../concepts/pipeline.md) — when and where directives
|
|
407
|
+
apply within a turn.
|
|
408
|
+
|
|
409
|
+
**Next:** [Instructions](./instructions.md)
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Instructions"
|
|
3
|
+
description: "Shape how the agent talks with must / never / should at agent, flow, and step scope, and read back exactly which ones fired."
|
|
4
|
+
type: guide
|
|
5
|
+
order: 4
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Instructions
|
|
9
|
+
|
|
10
|
+
Use `Instruction` when the agent should always confirm dates, never quote prices it has not looked up, or — only inside the booking flow — try to compare two options before committing. One primitive covers all three. Severity comes from `kind`. Reach comes from where you declare the instruction. The framework reports back which instructions actually rendered on each turn, so the behavior surface is observable, not guessed.
|
|
11
|
+
|
|
12
|
+
This guide assumes a `createAgent` scaffold. If you need one, start from [Your first agent](../start/02-first-agent.md).
|
|
13
|
+
|
|
14
|
+
## Instruction shape
|
|
15
|
+
|
|
16
|
+
An `Instruction` is a plain object with one required field — `prompt` — and a handful of optional ones. The full contract lives in the [Instruction reference](../reference/instruction.md); the working subset for this guide is:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import type { Instruction } from "@falai/agent";
|
|
20
|
+
|
|
21
|
+
const ins: Instruction = {
|
|
22
|
+
kind: "must", // 'must' | 'never' | 'should' (default 'should')
|
|
23
|
+
when: "User asks about pricing", // optional AI-evaluated activation
|
|
24
|
+
if: (ctx) => ctx.context.tier === "pro", // optional code-evaluated activation
|
|
25
|
+
prompt: "Quote only rates fetched from the live API this turn.",
|
|
26
|
+
};
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`prompt` is the behavioral text. `kind` declares severity. `when` and `if` gate the instruction by activation, with `if` running first and `when` only evaluated if `if` passes. Everything else (`id`, `enabled`, `tags`, `metadata`) is bookkeeping you can ignore until you need it.
|
|
30
|
+
|
|
31
|
+
## The three `kind` values
|
|
32
|
+
|
|
33
|
+
`kind` answers *how strict is this?* Three values, no inheritance, no ordering:
|
|
34
|
+
|
|
35
|
+
| `kind` | Use it for | Example |
|
|
36
|
+
|--------|------------|---------|
|
|
37
|
+
| `must` | Absolute do. The agent is required to follow it whenever rendered. | `"Validate dates are in the future before booking."` |
|
|
38
|
+
| `never` | Absolute don't. The agent is forbidden from doing it. | `"Promise rates you have not looked up."` |
|
|
39
|
+
| `should` | Conditional nudge. Default kind. The agent should try, but it's not a hard line. | `"Offer to compare two options before committing."` |
|
|
40
|
+
|
|
41
|
+
Default is `should`. Reach for `must` or `never` only when the behavior is non-negotiable — they are louder in the prompt and less forgiving in tone. If three flows each need the same `must`, declare it once at the agent scope; if it only matters for one flow, declare it there.
|
|
42
|
+
|
|
43
|
+
## Agent vs flow vs step scope
|
|
44
|
+
|
|
45
|
+
The same shape attaches at three positions:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
createAgent({
|
|
49
|
+
instructions: [/* agent scope — every turn, every flow */],
|
|
50
|
+
flows: [
|
|
51
|
+
{
|
|
52
|
+
title: "Booking",
|
|
53
|
+
instructions: [/* flow scope — only when 'Booking' is active */],
|
|
54
|
+
steps: [
|
|
55
|
+
{
|
|
56
|
+
id: "payment",
|
|
57
|
+
instructions: [/* step scope — only when 'payment' is the current step */],
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Reach narrows as you nest. Agent-scope instructions render on every turn for every flow. Flow-scope instructions render only while that flow is active. Step-scope instructions render only while that step is current. Conditions on `when` and `if` apply on top — an agent-scope instruction with `when: "User is angry"` still requires that activation to fire, just like a step-scope one.
|
|
66
|
+
|
|
67
|
+
The composer renders the resolved set under a single `## Instructions` heading and tags each line with a scope caption so the model can read both *what* and *where from* in one pass:
|
|
68
|
+
|
|
69
|
+
| Scope | Caption | When it appears |
|
|
70
|
+
|-------|---------|-----------------|
|
|
71
|
+
| Agent | `[Always]` | Every turn. |
|
|
72
|
+
| Flow | `[In: <FlowTitle>]` | While the named flow is active. |
|
|
73
|
+
| Step | `[Step: <stepId>]` | While the named step is current. |
|
|
74
|
+
|
|
75
|
+
## Rendering format
|
|
76
|
+
|
|
77
|
+
Each active instruction lands in the prompt as a single bullet:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
- [<kind>] [<scope>] <prompt>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
A composed block looks like this:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
## Instructions
|
|
87
|
+
|
|
88
|
+
- [must] [Always] Validate dates are in the future before booking.
|
|
89
|
+
- [never] [Always] Promise rates you have not looked up.
|
|
90
|
+
- [should] [In: Booking] Offer to compare two options before committing.
|
|
91
|
+
- [must] [Step: payment] If the card is declined, never retry without confirmation.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The format is fixed. The kind prefix is always present (defaulting to `[should]`), the scope caption is always present, and the prompt text follows verbatim. There is nothing to configure — what you write in `prompt` is what the model reads.
|
|
95
|
+
|
|
96
|
+
## `appliedInstructions` on the response
|
|
97
|
+
|
|
98
|
+
Every `respond()` call returns an `appliedInstructions` array listing exactly which instructions were rendered into that turn's prompt. The set is deterministic — it comes from the prompt composer, not the model — so you can use it for observability, audits, and tests:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
const response = await agent.respond("I want to book a room.");
|
|
102
|
+
|
|
103
|
+
for (const a of response.appliedInstructions ?? []) {
|
|
104
|
+
console.log(`${a.scope}${a.scopeRef ? `:${a.scopeRef}` : ""} → ${a.id}`);
|
|
105
|
+
}
|
|
106
|
+
// global → ins_validate_dates
|
|
107
|
+
// global → ins_no_unquoted_prices
|
|
108
|
+
// flow:Booking → ins_offer_two_options
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Each `AppliedInstruction` carries the firing instruction's `id`, the originating `scope`, and a `scopeRef` that is the `flowTitle` for flow scope, the `stepId` for step scope, and `undefined` for agent scope. If you want stable ids in the report, set `id` on the instructions you care about — otherwise the framework auto-generates them.
|
|
112
|
+
|
|
113
|
+
The same array lands on the final chunk of `respondStream`:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
for await (const chunk of agent.respondStream("I want to book a room.")) {
|
|
117
|
+
if (chunk.done) {
|
|
118
|
+
console.log("rendered:", chunk.appliedInstructions);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`appliedInstructions` is empty on intermediate chunks and populated only when `done: true`.
|
|
124
|
+
|
|
125
|
+
## Recipe: agent-level absolutes
|
|
126
|
+
|
|
127
|
+
Two house rules every flow must respect:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const agent = createAgent({
|
|
131
|
+
name: "BookingBot",
|
|
132
|
+
provider: new GeminiProvider({ apiKey: process.env.GEMINI_API_KEY! }),
|
|
133
|
+
instructions: [
|
|
134
|
+
{ id: "ins_validate_dates", kind: "must", prompt: "Validate dates are in the future before booking." },
|
|
135
|
+
{ id: "ins_no_unquoted", kind: "never", prompt: "Promise rates you have not looked up." },
|
|
136
|
+
],
|
|
137
|
+
flows: [/* ... */],
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
These render with caption `[Always]` on every turn, regardless of which flow is active.
|
|
142
|
+
|
|
143
|
+
## Recipe: flow-level conditional
|
|
144
|
+
|
|
145
|
+
A flow-scope nudge that only fires when the user is comparison shopping:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const booking = {
|
|
149
|
+
title: "Booking",
|
|
150
|
+
instructions: [
|
|
151
|
+
{
|
|
152
|
+
id: "ins_offer_two_options",
|
|
153
|
+
kind: "should",
|
|
154
|
+
when: "User is comparing options or asking which is better",
|
|
155
|
+
prompt: "Offer to compare two options side by side before recommending one.",
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
steps: [/* ... */],
|
|
159
|
+
};
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
While `Booking` is active, the line renders with caption `[In: Booking]` only on turns where the AI condition resolves true. On other turns the entry stays out of the prompt and out of `appliedInstructions`.
|
|
163
|
+
|
|
164
|
+
## Recipe: step-level reminder
|
|
165
|
+
|
|
166
|
+
A `must` that scopes to a specific step, gated by a code condition:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
const paymentStep = {
|
|
170
|
+
id: "payment",
|
|
171
|
+
prompt: "Take payment.",
|
|
172
|
+
instructions: [
|
|
173
|
+
{
|
|
174
|
+
id: "ins_no_retry_on_decline",
|
|
175
|
+
kind: "must",
|
|
176
|
+
if: (ctx) => ctx.data.lastChargeStatus === "declined",
|
|
177
|
+
prompt: "If the card is declined, never retry without explicit user confirmation.",
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
};
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Renders with caption `[Step: payment]` only while `payment` is the current step *and* the most recent charge was declined. Move off the step or change `lastChargeStatus`, and it drops out cleanly.
|
|
184
|
+
|
|
185
|
+
## Recipe: reading `appliedInstructions` in a test
|
|
186
|
+
|
|
187
|
+
Because the set is deterministic, you can assert against it directly:
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import { test, expect } from "bun:test";
|
|
191
|
+
|
|
192
|
+
test("payment step renders the no-retry rule when the card was declined", async () => {
|
|
193
|
+
const response = await agent.respond("Try again.", {
|
|
194
|
+
sessionId: "s_1",
|
|
195
|
+
initialContext: {},
|
|
196
|
+
initialData: { lastChargeStatus: "declined" },
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const ids = response.appliedInstructions?.map(a => a.id) ?? [];
|
|
200
|
+
expect(ids).toContain("ins_no_retry_on_decline");
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
No fixtures, no LLM mocks — the rendered set is computable from configuration and condition state.
|
|
205
|
+
|
|
206
|
+
## Where this fits
|
|
207
|
+
|
|
208
|
+
`Instruction` shapes how the agent *talks*. To shape what it *does* — redirect, complete, abort — return a [Directive](../reference/directive.md) from a tool or hook (covered in [Flow control](./flow-control.md)). The two surfaces compose: an instruction nudges the model to confirm dates, a tool's directive completes the flow once the booking is written.
|
|
209
|
+
|
|
210
|
+
**Next:** [Persistence](./persistence.md)
|