@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,276 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Add tools"
|
|
3
|
+
description: "Extend the booking agent with tools that book the room, gate eligibility, and redirect on failure."
|
|
4
|
+
type: tutorial
|
|
5
|
+
order: 4
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Add tools
|
|
9
|
+
|
|
10
|
+
So far the agent talks. Now it acts. You will add a tool that books a hotel room and a tool that checks whether the user is allowed to book at all. Along the way you will see how `ctx.dispatch` and `ToolResult.directive` both land on the same directive bus, and why most tools only need an `id` and a `handler` to start.
|
|
11
|
+
|
|
12
|
+
So far the agent only collects fields. This page adds two tools:
|
|
13
|
+
|
|
14
|
+
- `book_hotel` — runs once the required fields are in, returns a
|
|
15
|
+
booking id, and (optionally) finishes the flow with a directive.
|
|
16
|
+
- `check_eligibility` — runs early and redirects to a denial flow
|
|
17
|
+
when the caller is not allowed. You'll see both forms of
|
|
18
|
+
redirection: imperative (`ctx.dispatch`) and declarative
|
|
19
|
+
(`ToolResult.directive`).
|
|
20
|
+
|
|
21
|
+
You'll also meet the optional metadata fields — `isReadOnly`,
|
|
22
|
+
`validateInput`, `checkPermissions` — that let tools opt into safer
|
|
23
|
+
defaults when you need them.
|
|
24
|
+
|
|
25
|
+
> Tool surface used here is the canonical [Tool reference](../reference/tool.md).
|
|
26
|
+
> `Tool.id` is the sole identifier — there's no separate `name`.
|
|
27
|
+
|
|
28
|
+
## Recap: where we left off
|
|
29
|
+
|
|
30
|
+
`docs/start/03-collect-data.md` left us with a `Book Hotel` flow that
|
|
31
|
+
collects `destination`, `checkIn`, and `guests`, and a `confirm` step
|
|
32
|
+
that waits until all three are populated. We'll hand the `confirm`
|
|
33
|
+
step a tool that actually books the room, plus an eligibility check
|
|
34
|
+
to gate it.
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
interface BookingData {
|
|
38
|
+
destination: string;
|
|
39
|
+
checkIn: string;
|
|
40
|
+
guests: number;
|
|
41
|
+
bookingId?: string;
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 1. Add `book_hotel`
|
|
46
|
+
|
|
47
|
+
A tool is an object with an `id`, an optional `description` and
|
|
48
|
+
`parameters` schema, and a `handler` that returns the result the AI
|
|
49
|
+
will see. The handler receives a `ToolContext` (`ctx`) — the read
|
|
50
|
+
surface over `data`, `context`, and the session.
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import type { Tool } from "@falai/agent";
|
|
54
|
+
|
|
55
|
+
const bookHotel: Tool<unknown, BookingData, { bookingId: string }> = {
|
|
56
|
+
id: "book_hotel",
|
|
57
|
+
description: "Reserve the hotel for the collected destination, dates, and guest count.",
|
|
58
|
+
parameters: {
|
|
59
|
+
type: "object",
|
|
60
|
+
properties: {
|
|
61
|
+
destination: { type: "string" },
|
|
62
|
+
checkIn: { type: "string" },
|
|
63
|
+
guests: { type: "number" },
|
|
64
|
+
},
|
|
65
|
+
required: ["destination", "checkIn", "guests"],
|
|
66
|
+
},
|
|
67
|
+
async handler(ctx, args) {
|
|
68
|
+
const bookingId = await reserve(args);
|
|
69
|
+
return {
|
|
70
|
+
data: { bookingId },
|
|
71
|
+
dataUpdate: { bookingId },
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The handler returns a `ToolResult`:
|
|
78
|
+
|
|
79
|
+
- `data` is what the AI sees as the tool result (used to compose the
|
|
80
|
+
next assistant message).
|
|
81
|
+
- `dataUpdate` is shallow-merged into `session.data`, so the booking
|
|
82
|
+
id sticks for the rest of the conversation.
|
|
83
|
+
|
|
84
|
+
Wire the tool to the `confirm` step:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
{
|
|
88
|
+
id: "confirm",
|
|
89
|
+
prompt: "Confirm the trip and call book_hotel.",
|
|
90
|
+
requires: ["destination", "checkIn", "guests"],
|
|
91
|
+
tools: [bookHotel],
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The AI now has the tool available on `confirm`. Once the three
|
|
96
|
+
fields are set, it can call `book_hotel`, get the id back, and
|
|
97
|
+
confirm the booking in the reply.
|
|
98
|
+
|
|
99
|
+
### Optional: finish the flow declaratively
|
|
100
|
+
|
|
101
|
+
If you want the tool itself to close the flow — instead of relying
|
|
102
|
+
on the next turn to notice `requiredFields` are satisfied — return a
|
|
103
|
+
`directive` alongside the data:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
async handler(ctx, args) {
|
|
107
|
+
const bookingId = await reserve(args);
|
|
108
|
+
return {
|
|
109
|
+
data: { bookingId },
|
|
110
|
+
directive: {
|
|
111
|
+
complete: { reason: "reservation confirmed" },
|
|
112
|
+
dataUpdate: { bookingId },
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`ToolResult.directive` is the **declarative** form of redirection: a
|
|
119
|
+
directive returned with the result. Whatever you can say with
|
|
120
|
+
`ctx.dispatch` mid-handler, you can say with `directive` on return.
|
|
121
|
+
They merge identically. See [Directives](../concepts/directives.md)
|
|
122
|
+
for the full shape.
|
|
123
|
+
|
|
124
|
+
## 2. Add `check_eligibility` — imperative form
|
|
125
|
+
|
|
126
|
+
Some destinations are off-limits for some users. We want a tool that
|
|
127
|
+
runs before the AI starts pitching options, decides whether the
|
|
128
|
+
caller can proceed, and — when not — bails out into a denial flow.
|
|
129
|
+
|
|
130
|
+
The imperative form uses `ctx.dispatch` to emit a directive
|
|
131
|
+
mid-handler:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const checkEligibilityImperative: Tool<{ userId: string }, BookingData, { ok: boolean }> = {
|
|
135
|
+
id: "check_eligibility",
|
|
136
|
+
description: "Verify the caller is allowed to book this destination.",
|
|
137
|
+
isReadOnly: () => true,
|
|
138
|
+
async handler(ctx) {
|
|
139
|
+
const ok = await isEligible(ctx.context.userId, ctx.data.destination);
|
|
140
|
+
|
|
141
|
+
if (!ok) {
|
|
142
|
+
// Stop reasoning down this path — jump to the denial flow.
|
|
143
|
+
ctx.dispatch({
|
|
144
|
+
goTo: "Denial",
|
|
145
|
+
reply: "Sorry — you're not eligible to book that destination.",
|
|
146
|
+
});
|
|
147
|
+
return { ok: false };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { ok: true };
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
What just happened:
|
|
156
|
+
|
|
157
|
+
- `ctx.dispatch(directive)` puts the directive on this turn's
|
|
158
|
+
directive bus. Algorithm 4 picks it up alongside any other
|
|
159
|
+
emissions.
|
|
160
|
+
- `goTo: "Denial"` redirects to a sibling flow named `"Denial"`.
|
|
161
|
+
- `reply` is the verbatim assistant utterance — the LLM call this
|
|
162
|
+
turn is skipped and the literal string is what the user sees.
|
|
163
|
+
- The handler still returns `{ ok: false }` so the trace is honest
|
|
164
|
+
about what the tool did.
|
|
165
|
+
|
|
166
|
+
For the redirect to work, the agent needs a `Denial` flow. It can
|
|
167
|
+
be as small as:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
{
|
|
171
|
+
title: "Denial",
|
|
172
|
+
steps: [{ id: "explain",
|
|
173
|
+
prompt: "Explain why the booking is not possible and offer help." }],
|
|
174
|
+
},
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Wire the eligibility check on the `confirm` step (or earlier — your
|
|
178
|
+
call):
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
{
|
|
182
|
+
id: "confirm",
|
|
183
|
+
prompt: "Confirm the trip and call book_hotel.",
|
|
184
|
+
requires: ["destination", "checkIn", "guests"],
|
|
185
|
+
tools: [checkEligibilityImperative, bookHotel],
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 3. Same tool — declarative form
|
|
190
|
+
|
|
191
|
+
Many handlers don't need to dispatch mid-flight. They can compute
|
|
192
|
+
the answer, build the directive, and return it on the result.
|
|
193
|
+
`ToolResult.directive` is identical in effect to `ctx.dispatch` —
|
|
194
|
+
same merge, same precedence, same shape.
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
const checkEligibilityDeclarative: Tool<{ userId: string }, BookingData, { ok: boolean }> = {
|
|
198
|
+
id: "check_eligibility",
|
|
199
|
+
description: "Verify the caller is allowed to book this destination.",
|
|
200
|
+
isReadOnly: () => true,
|
|
201
|
+
async handler(ctx) {
|
|
202
|
+
const ok = await isEligible(ctx.context.userId, ctx.data.destination);
|
|
203
|
+
|
|
204
|
+
if (!ok) {
|
|
205
|
+
return {
|
|
206
|
+
data: { ok: false },
|
|
207
|
+
directive: {
|
|
208
|
+
goTo: "Denial",
|
|
209
|
+
reply: "Sorry — you're not eligible to book that destination.",
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return { data: { ok: true } };
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
When to reach for which:
|
|
220
|
+
|
|
221
|
+
- **Imperative** — you need to dispatch before the handler is done
|
|
222
|
+
(e.g. an early branch decides the rest of the work is moot but
|
|
223
|
+
the result payload still has to be computed for the trace).
|
|
224
|
+
- **Declarative** — single return point, directive next to the data
|
|
225
|
+
it goes with. Easier to read; preferred when there's no reason to
|
|
226
|
+
split.
|
|
227
|
+
|
|
228
|
+
Both forms can co-exist. Multiple `dispatch` calls plus a `directive`
|
|
229
|
+
on the return value all land on the same bus and merge identically
|
|
230
|
+
(see [Directives](../concepts/directives.md)).
|
|
231
|
+
|
|
232
|
+
## 4. Optional metadata, briefly
|
|
233
|
+
|
|
234
|
+
Every metadata field on `Tool` is optional. Reach for them only when
|
|
235
|
+
you want the safer default they buy you.
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
isReadOnly: () => true; // safe to cache and parallelize
|
|
239
|
+
validateInput: (input) => ({ valid: typeof input.guests === "number" }); // repair or reject bad args
|
|
240
|
+
checkPermissions: (_, ctx) => ({ allowed: !!ctx.context.userId }); // gate access; handler skipped on deny
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Four more live on the same surface — `isConcurrencySafe`,
|
|
244
|
+
`isDestructive`, `interruptBehavior`, `maxResultSizeChars`. See the
|
|
245
|
+
[Tool reference](../reference/tool.md) for the full list and exact
|
|
246
|
+
contracts.
|
|
247
|
+
|
|
248
|
+
## 5. Run it
|
|
249
|
+
|
|
250
|
+
A user message like
|
|
251
|
+
|
|
252
|
+
> "Book me a room in Lisbon for 2 adults, checking in March 14."
|
|
253
|
+
|
|
254
|
+
now flows through:
|
|
255
|
+
|
|
256
|
+
1. **Pre-extraction.** The router pulls `destination: "Lisbon"`,
|
|
257
|
+
`checkIn: "March 14"`, `guests: 2` out of the message in one shot.
|
|
258
|
+
2. **Step selection.** The `ask` step is satisfied — every `collect`
|
|
259
|
+
field is set — so the engine skips it and enters `confirm`.
|
|
260
|
+
3. **Eligibility.** The AI calls `check_eligibility`. If allowed,
|
|
261
|
+
the tool returns `{ ok: true }` and we move on. If not, the
|
|
262
|
+
dispatched directive jumps to the `Denial` flow and the verbatim
|
|
263
|
+
`reply` becomes the assistant message — no LLM call this turn.
|
|
264
|
+
4. **Booking.** The AI calls `book_hotel`, gets a `bookingId`, and
|
|
265
|
+
composes the confirmation reply.
|
|
266
|
+
5. **Completion.** With every required field present (and a
|
|
267
|
+
`bookingId` in `data`), the flow finishes.
|
|
268
|
+
|
|
269
|
+
## What's next
|
|
270
|
+
|
|
271
|
+
You have an agent that collects data, runs tools, gates access, and
|
|
272
|
+
redirects on failure. The remaining concern is shipping it: swapping
|
|
273
|
+
`MemoryAdapter` for `PrismaAdapter`, streaming responses, and
|
|
274
|
+
dropping the agent behind an HTTP endpoint.
|
|
275
|
+
|
|
276
|
+
**Next:** [Go to production](./05-go-to-production.md)
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Go to production"
|
|
3
|
+
description: "Add durable persistence, streaming responses, and an HTTP endpoint to ship the booking agent."
|
|
4
|
+
type: tutorial
|
|
5
|
+
order: 5
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Go to production
|
|
9
|
+
|
|
10
|
+
The framework stays the same shape from prototype to production; only the adapter and the call site change. This page adds `PrismaAdapter` for durable sessions, `respondStream` for real-time output, and a session-keyed POST endpoint that any chat client can call. Same seven primitives, same booking flow — now with persistence and streaming on top.
|
|
11
|
+
|
|
12
|
+
The booking agent from [04 — Add tools](./04-add-tools.md) runs end to end, but it forgets every conversation the moment the process exits, hands replies back as one final string, and lives in a script. Production has three more requirements: durability, real-time output, and a way for clients to talk to it. This page wires up all three.
|
|
13
|
+
|
|
14
|
+
You will:
|
|
15
|
+
|
|
16
|
+
1. Swap the implicit `MemoryAdapter` for `PrismaAdapter` so sessions survive restarts.
|
|
17
|
+
2. Switch the call site from `agent.respond` to `agent.respondStream` and consume chunks as they arrive.
|
|
18
|
+
3. Wrap the agent in a session-keyed POST endpoint that any chat client can call.
|
|
19
|
+
|
|
20
|
+
By the end you have the same booking agent — same flow, same tools — running behind an HTTP API with persistent state.
|
|
21
|
+
|
|
22
|
+
## 1. Persist sessions with Prisma
|
|
23
|
+
|
|
24
|
+
By default `createAgent` uses `MemoryAdapter`, an in-process map that vanishes with the process. Production needs storage that outlives a deploy. `PrismaAdapter` rides on top of any Prisma-supported database; you own the schema, the adapter does the reads and writes.
|
|
25
|
+
|
|
26
|
+
Add Prisma to the project:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
bun add @prisma/client
|
|
30
|
+
bun add -d prisma
|
|
31
|
+
bunx prisma init
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Open the generated `prisma/schema.prisma` and add the `AgentSession` and `AgentMessage` models. Two columns matter most: `pendingDirective` and `signals`. The agent serializes its [`Directive`](../reference/directive.md) and signal state into them at the end of every turn and reads them back at the start of the next.
|
|
35
|
+
|
|
36
|
+
```prisma
|
|
37
|
+
// prisma/schema.prisma
|
|
38
|
+
generator client {
|
|
39
|
+
provider = "prisma-client-js"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
datasource db {
|
|
43
|
+
provider = "postgresql"
|
|
44
|
+
url = env("DATABASE_URL")
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
model AgentSession {
|
|
48
|
+
id String @id
|
|
49
|
+
userId String?
|
|
50
|
+
agentName String?
|
|
51
|
+
status String @default("active")
|
|
52
|
+
currentFlow String?
|
|
53
|
+
currentStep String?
|
|
54
|
+
collectedData Json?
|
|
55
|
+
pendingDirective Json?
|
|
56
|
+
signals Json?
|
|
57
|
+
messageCount Int @default(0)
|
|
58
|
+
lastMessageAt DateTime?
|
|
59
|
+
completedAt DateTime?
|
|
60
|
+
createdAt DateTime @default(now())
|
|
61
|
+
updatedAt DateTime @updatedAt
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
model AgentMessage {
|
|
65
|
+
id String @id @default(cuid())
|
|
66
|
+
sessionId String
|
|
67
|
+
role String
|
|
68
|
+
content String
|
|
69
|
+
createdAt DateTime @default(now())
|
|
70
|
+
|
|
71
|
+
@@index([sessionId, createdAt])
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Push the schema and generate the client:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
bunx prisma db push
|
|
79
|
+
bunx prisma generate
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Now wire the adapter into the booking agent. The only change from the previous tutorial is the new `persistence` field — every flow, step, tool, and instruction stays exactly the same.
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { PrismaClient } from "@prisma/client";
|
|
86
|
+
import { createAgent, GeminiProvider, PrismaAdapter } from "@falai/agent";
|
|
87
|
+
import { bookingFlow, bookingTools, bookingInstructions, schema } from "./booking";
|
|
88
|
+
|
|
89
|
+
const prisma = new PrismaClient();
|
|
90
|
+
|
|
91
|
+
export const agent = createAgent({
|
|
92
|
+
name: "BookingBot",
|
|
93
|
+
provider: new GeminiProvider({ apiKey: process.env.GEMINI_API_KEY! }),
|
|
94
|
+
schema,
|
|
95
|
+
flows: [bookingFlow],
|
|
96
|
+
tools: bookingTools,
|
|
97
|
+
instructions: bookingInstructions,
|
|
98
|
+
persistence: {
|
|
99
|
+
adapter: new PrismaAdapter({ prisma }),
|
|
100
|
+
userId: "user_123",
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
To resume a conversation by id, hydrate the session from the adapter and pass it through. `agent.session.getOrCreate(sessionId)` loads the stored `SessionState` (collected data, flow position, `pendingDirective`, signals state) — or creates a fresh one with that id if nothing exists yet.
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const session = await agent.session.getOrCreate("user_123:thread_abc");
|
|
109
|
+
|
|
110
|
+
const response = await agent.respond({
|
|
111
|
+
history: [{ role: "user", content: "Hi again" }],
|
|
112
|
+
session,
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Unknown ids start fresh against that id; there is no "not found" error path.
|
|
117
|
+
|
|
118
|
+
For the full schema migration story (renaming `pending_transition` to `pendingDirective`, adding the `signals` column) see [persistence adapters reference](../reference/adapters.md#prismaadapter).
|
|
119
|
+
|
|
120
|
+
## 2. Stream responses
|
|
121
|
+
|
|
122
|
+
`agent.respond` returns one final `AgentResponse` after the LLM and any tools have finished. That works for batch jobs, but a chat UI feels dead until the first character lands. `agent.respondStream` returns an `AsyncGenerator<AgentResponseStreamChunk>` — every chunk has the latest `delta` and `accumulated` text, plus a `done` flag.
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
const stream = agent.respondStream({
|
|
126
|
+
history: [{ role: "user", content: "Book me a hotel in Lisbon for two nights." }],
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
for await (const chunk of stream) {
|
|
130
|
+
if (chunk.delta) {
|
|
131
|
+
process.stdout.write(chunk.delta);
|
|
132
|
+
}
|
|
133
|
+
if (chunk.done) {
|
|
134
|
+
console.log("\n---");
|
|
135
|
+
console.log("Applied instructions:", chunk.appliedInstructions);
|
|
136
|
+
console.log("Triggered signals:", chunk.triggeredSignals);
|
|
137
|
+
console.log("Flow complete:", chunk.isFlowComplete);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Two fields land only on the terminal chunk (`done: true`):
|
|
143
|
+
|
|
144
|
+
- `appliedInstructions` — the [instructions](../reference/instruction.md) whose conditions passed and were rendered into this turn's prompt. Deterministic; derived from rendering, not from LLM self-report.
|
|
145
|
+
- `triggeredSignals` — the signals (if any) that fired during this turn, in fire order.
|
|
146
|
+
|
|
147
|
+
Use them for telemetry, audit logs, or showing the user which guardrails ran. They mirror the same fields on the non-streaming `AgentResponse`, so swapping between APIs does not change observability.
|
|
148
|
+
|
|
149
|
+
To cancel mid-stream — say, the user hits Stop — pass an `AbortSignal`:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
const controller = new AbortController();
|
|
153
|
+
setTimeout(() => controller.abort(), 5000);
|
|
154
|
+
|
|
155
|
+
const stream = agent.respondStream({
|
|
156
|
+
history,
|
|
157
|
+
signal: controller.signal,
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## 3. A session-keyed HTTP endpoint
|
|
162
|
+
|
|
163
|
+
The agent is now durable and streaming. The last piece is exposing it. Any HTTP framework works — Express, Bun.serve, Fastify, Hono. The pattern is the same: accept a `sessionId` and `message`, look up history, stream chunks back to the client. This Bun example is one screenful.
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { agent } from "./agent";
|
|
167
|
+
|
|
168
|
+
Bun.serve({
|
|
169
|
+
port: 3000,
|
|
170
|
+
async fetch(req) {
|
|
171
|
+
if (req.method !== "POST" || new URL(req.url).pathname !== "/chat") {
|
|
172
|
+
return new Response("Not found", { status: 404 });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const { sessionId, message } = await req.json() as {
|
|
176
|
+
sessionId: string;
|
|
177
|
+
message: string;
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const session = await agent.session.getOrCreate(sessionId);
|
|
181
|
+
|
|
182
|
+
const stream = agent.respondStream({
|
|
183
|
+
history: [{ role: "user", content: message }],
|
|
184
|
+
session,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return new Response(
|
|
188
|
+
new ReadableStream({
|
|
189
|
+
async start(controller) {
|
|
190
|
+
for await (const chunk of stream) {
|
|
191
|
+
controller.enqueue(
|
|
192
|
+
new TextEncoder().encode(
|
|
193
|
+
`data: ${JSON.stringify({
|
|
194
|
+
delta: chunk.delta,
|
|
195
|
+
done: chunk.done,
|
|
196
|
+
isFlowComplete: chunk.isFlowComplete,
|
|
197
|
+
})}\n\n`
|
|
198
|
+
)
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
controller.close();
|
|
202
|
+
},
|
|
203
|
+
}),
|
|
204
|
+
{ headers: { "Content-Type": "text/event-stream" } }
|
|
205
|
+
);
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The shape that matters: `sessionId` is the contract between client and server. The same id on every request keeps the user pinned to the same conversation; the adapter loads the right `pendingDirective` and `signals`, the agent picks up exactly where the last turn ended. No per-request setup, no global state.
|
|
211
|
+
|
|
212
|
+
A real chat backend adds auth, rate limits, and persistent message storage — but the core glue is the four lines that build `agent`, the four lines that read `request.json()`, and the loop that pipes stream chunks into Server-Sent Events.
|
|
213
|
+
|
|
214
|
+
That is the full path: a 12-line `createAgent` call in [02 — Your first agent](./02-first-agent.md), data extraction in [03](./03-collect-data.md), tools in [04](./04-add-tools.md), and now durable, streaming, HTTP-served. The framework stays the same shape from prototype to production — only the adapter and the call site change.
|
|
215
|
+
|
|
216
|
+
**Next:** [How-to guides](../guides/conditions.md)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** @intent Minimal agent: one flow, one step, one response.
|
|
2
|
+
* @teaches createAgent, GeminiProvider, Flow, Step, respond
|
|
3
|
+
* @readAfter docs/start/02-first-agent.md */
|
|
4
|
+
import { createAgent, GeminiProvider } from "../src";
|
|
5
|
+
|
|
6
|
+
if (!process.env.GEMINI_API_KEY) throw new Error("Set GEMINI_API_KEY");
|
|
7
|
+
|
|
8
|
+
const agent = createAgent({
|
|
9
|
+
name: "Greeter",
|
|
10
|
+
provider: new GeminiProvider({ apiKey: process.env.GEMINI_API_KEY, model: "gemini-3.1-flash-lite" }),
|
|
11
|
+
schema: { type: "object", properties: { name: { type: "string" } } },
|
|
12
|
+
flows: [{
|
|
13
|
+
title: "Greet",
|
|
14
|
+
requiredFields: ["name"],
|
|
15
|
+
steps: [{ id: "ask_name", prompt: "What's your name?", collect: ["name"] }],
|
|
16
|
+
}],
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const response = await agent.respond({ history: [{ role: "user", content: "Hi, I'm Alice" }] });
|
|
20
|
+
console.log(response.message);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data extraction — schema, collect, skip, requires, requiredFields; pre-extraction in action.
|
|
3
|
+
* Run with the message "I want X for Y people on Z" and watch all three fields populate from one turn.
|
|
4
|
+
* Read after: docs/start/03-collect-data.md
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createAgent, GeminiProvider } from "@falai/agent";
|
|
8
|
+
|
|
9
|
+
// ─── Schema ──────────────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
interface BookingData {
|
|
12
|
+
roomType: "single" | "double" | "suite";
|
|
13
|
+
guests: number;
|
|
14
|
+
checkIn: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const schema = {
|
|
18
|
+
type: "object" as const,
|
|
19
|
+
properties: {
|
|
20
|
+
roomType: {
|
|
21
|
+
type: "string" as const,
|
|
22
|
+
enum: ["single", "double", "suite"],
|
|
23
|
+
description: "Type of room requested",
|
|
24
|
+
},
|
|
25
|
+
guests: {
|
|
26
|
+
type: "number" as const,
|
|
27
|
+
description: "Number of guests",
|
|
28
|
+
},
|
|
29
|
+
checkIn: {
|
|
30
|
+
type: "string" as const,
|
|
31
|
+
description: "Check-in date in YYYY-MM-DD format",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
required: ["roomType", "guests", "checkIn"],
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// ─── Agent ───────────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
const agent = createAgent<Record<string, never>, BookingData>({
|
|
40
|
+
name: "Booking Agent",
|
|
41
|
+
provider: new GeminiProvider({
|
|
42
|
+
apiKey: process.env.GEMINI_API_KEY!,
|
|
43
|
+
model: "gemini-3.1-flash-lite",
|
|
44
|
+
}),
|
|
45
|
+
schema,
|
|
46
|
+
flows: [
|
|
47
|
+
{
|
|
48
|
+
title: "Book a room",
|
|
49
|
+
when: "The user wants to book a hotel room",
|
|
50
|
+
requiredFields: ["roomType", "guests", "checkIn"],
|
|
51
|
+
steps: [
|
|
52
|
+
{
|
|
53
|
+
id: "ask_room",
|
|
54
|
+
prompt: "What type of room would you like? (single, double, or suite)",
|
|
55
|
+
collect: ["roomType"],
|
|
56
|
+
skip: [({ data }) => data.roomType !== undefined],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: "ask_guests",
|
|
60
|
+
prompt: "How many guests will be staying?",
|
|
61
|
+
collect: ["guests"],
|
|
62
|
+
requires: ["roomType"],
|
|
63
|
+
skip: [({ data }) => data.guests !== undefined],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: "ask_checkin",
|
|
67
|
+
prompt: "When would you like to check in?",
|
|
68
|
+
collect: ["checkIn"],
|
|
69
|
+
requires: ["roomType", "guests"],
|
|
70
|
+
skip: [({ data }) => data.checkIn !== undefined],
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// ─── Run ─────────────────────────────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
async function main() {
|
|
80
|
+
// Pre-extraction: all three fields are extracted from a single message.
|
|
81
|
+
const response = await agent.respond({
|
|
82
|
+
history: [{ role: "user", content: "I want a double for 2 people on 2025-03-15" }],
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
console.log(response.message);
|
|
86
|
+
console.log("Collected:", response.session?.data);
|
|
87
|
+
console.log("Complete:", response.isFlowComplete);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
main();
|