@falai/agent 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -74
- package/dist/cjs/core/Agent.d.ts +22 -29
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +464 -291
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/Events.d.ts +10 -1
- package/dist/cjs/core/Events.d.ts.map +1 -1
- package/dist/cjs/core/Events.js +3 -2
- package/dist/cjs/core/Events.js.map +1 -1
- package/dist/cjs/core/PersistenceManager.d.ts +19 -0
- package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
- package/dist/cjs/core/PersistenceManager.js +57 -0
- package/dist/cjs/core/PersistenceManager.js.map +1 -1
- package/dist/cjs/core/PromptComposer.d.ts +24 -0
- package/dist/cjs/core/PromptComposer.d.ts.map +1 -0
- package/dist/cjs/core/PromptComposer.js +127 -0
- package/dist/cjs/core/PromptComposer.js.map +1 -0
- package/dist/cjs/core/ResponseEngine.d.ts +19 -0
- package/dist/cjs/core/ResponseEngine.d.ts.map +1 -0
- package/dist/cjs/core/ResponseEngine.js +51 -0
- package/dist/cjs/core/ResponseEngine.js.map +1 -0
- package/dist/cjs/core/Route.d.ts +18 -12
- package/dist/cjs/core/Route.d.ts.map +1 -1
- package/dist/cjs/core/Route.js +15 -9
- package/dist/cjs/core/Route.js.map +1 -1
- package/dist/cjs/core/RoutingEngine.d.ts +38 -0
- package/dist/cjs/core/RoutingEngine.d.ts.map +1 -0
- package/dist/cjs/core/RoutingEngine.js +110 -0
- package/dist/cjs/core/RoutingEngine.js.map +1 -0
- package/dist/cjs/core/State.d.ts +15 -4
- package/dist/cjs/core/State.d.ts.map +1 -1
- package/dist/cjs/core/State.js +21 -2
- package/dist/cjs/core/State.js.map +1 -1
- package/dist/cjs/core/ToolExecutor.d.ts +29 -0
- package/dist/cjs/core/ToolExecutor.d.ts.map +1 -0
- package/dist/cjs/core/ToolExecutor.js +73 -0
- package/dist/cjs/core/ToolExecutor.js.map +1 -0
- package/dist/cjs/core/Transition.d.ts +5 -5
- package/dist/cjs/core/Transition.d.ts.map +1 -1
- package/dist/cjs/core/Transition.js.map +1 -1
- package/dist/cjs/index.d.ts +6 -8
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +8 -10
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.js +10 -13
- package/dist/cjs/providers/AnthropicProvider.js.map +1 -1
- package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/cjs/providers/GeminiProvider.js +12 -8
- package/dist/cjs/providers/GeminiProvider.js.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.js +10 -53
- package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.js +10 -53
- package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +13 -12
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/ai.d.ts +8 -2
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/cjs/types/history.d.ts +8 -0
- package/dist/cjs/types/history.d.ts.map +1 -1
- package/dist/cjs/types/index.d.ts +0 -3
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js +1 -3
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/route.d.ts +39 -4
- package/dist/cjs/types/route.d.ts.map +1 -1
- package/dist/cjs/types/routing.d.ts +16 -0
- package/dist/cjs/types/routing.d.ts.map +1 -0
- package/dist/cjs/types/routing.js +3 -0
- package/dist/cjs/types/routing.js.map +1 -0
- package/dist/cjs/types/schema.d.ts +22 -0
- package/dist/cjs/types/schema.d.ts.map +1 -0
- package/dist/cjs/types/schema.js +3 -0
- package/dist/cjs/types/schema.js.map +1 -0
- package/dist/cjs/types/session.d.ts +72 -0
- package/dist/cjs/types/session.d.ts.map +1 -0
- package/dist/cjs/types/session.js +140 -0
- package/dist/cjs/types/session.js.map +1 -0
- package/dist/cjs/types/tool.d.ts +11 -5
- package/dist/cjs/types/tool.d.ts.map +1 -1
- package/dist/cjs/utils/id.d.ts +0 -5
- package/dist/cjs/utils/id.d.ts.map +1 -1
- package/dist/cjs/utils/id.js +0 -10
- package/dist/cjs/utils/id.js.map +1 -1
- package/dist/cjs/utils/schema.d.ts +17 -0
- package/dist/cjs/utils/schema.d.ts.map +1 -0
- package/dist/cjs/utils/schema.js +32 -0
- package/dist/cjs/utils/schema.js.map +1 -0
- package/dist/core/Agent.d.ts +22 -29
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +464 -291
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/Events.d.ts +10 -1
- package/dist/core/Events.d.ts.map +1 -1
- package/dist/core/Events.js +3 -2
- package/dist/core/Events.js.map +1 -1
- package/dist/core/PersistenceManager.d.ts +19 -0
- package/dist/core/PersistenceManager.d.ts.map +1 -1
- package/dist/core/PersistenceManager.js +57 -0
- package/dist/core/PersistenceManager.js.map +1 -1
- package/dist/core/PromptComposer.d.ts +24 -0
- package/dist/core/PromptComposer.d.ts.map +1 -0
- package/dist/core/PromptComposer.js +123 -0
- package/dist/core/PromptComposer.js.map +1 -0
- package/dist/core/ResponseEngine.d.ts +19 -0
- package/dist/core/ResponseEngine.d.ts.map +1 -0
- package/dist/core/ResponseEngine.js +47 -0
- package/dist/core/ResponseEngine.js.map +1 -0
- package/dist/core/Route.d.ts +18 -12
- package/dist/core/Route.d.ts.map +1 -1
- package/dist/core/Route.js +15 -9
- package/dist/core/Route.js.map +1 -1
- package/dist/core/RoutingEngine.d.ts +38 -0
- package/dist/core/RoutingEngine.d.ts.map +1 -0
- package/dist/core/RoutingEngine.js +106 -0
- package/dist/core/RoutingEngine.js.map +1 -0
- package/dist/core/State.d.ts +15 -4
- package/dist/core/State.d.ts.map +1 -1
- package/dist/core/State.js +21 -2
- package/dist/core/State.js.map +1 -1
- package/dist/core/ToolExecutor.d.ts +29 -0
- package/dist/core/ToolExecutor.d.ts.map +1 -0
- package/dist/core/ToolExecutor.js +69 -0
- package/dist/core/ToolExecutor.js.map +1 -0
- package/dist/core/Transition.d.ts +5 -5
- package/dist/core/Transition.d.ts.map +1 -1
- package/dist/core/Transition.js.map +1 -1
- package/dist/index.d.ts +6 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/providers/AnthropicProvider.d.ts.map +1 -1
- package/dist/providers/AnthropicProvider.js +10 -13
- package/dist/providers/AnthropicProvider.js.map +1 -1
- package/dist/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/providers/GeminiProvider.js +12 -8
- package/dist/providers/GeminiProvider.js.map +1 -1
- package/dist/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/OpenAIProvider.js +10 -53
- package/dist/providers/OpenAIProvider.js.map +1 -1
- package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/providers/OpenRouterProvider.js +10 -53
- package/dist/providers/OpenRouterProvider.js.map +1 -1
- package/dist/types/agent.d.ts +13 -12
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/ai.d.ts +8 -2
- package/dist/types/ai.d.ts.map +1 -1
- package/dist/types/history.d.ts +8 -0
- package/dist/types/history.d.ts.map +1 -1
- package/dist/types/index.d.ts +0 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +0 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/route.d.ts +39 -4
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/routing.d.ts +16 -0
- package/dist/types/routing.d.ts.map +1 -0
- package/dist/types/routing.js +2 -0
- package/dist/types/routing.js.map +1 -0
- package/dist/types/schema.d.ts +22 -0
- package/dist/types/schema.d.ts.map +1 -0
- package/dist/types/schema.js +2 -0
- package/dist/types/schema.js.map +1 -0
- package/dist/types/session.d.ts +72 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +132 -0
- package/dist/types/session.js.map +1 -0
- package/dist/types/tool.d.ts +11 -5
- package/dist/types/tool.d.ts.map +1 -1
- package/dist/utils/id.d.ts +0 -5
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +0 -9
- package/dist/utils/id.js.map +1 -1
- package/dist/utils/schema.d.ts +17 -0
- package/dist/utils/schema.d.ts.map +1 -0
- package/dist/utils/schema.js +27 -0
- package/dist/utils/schema.js.map +1 -0
- package/docs/ADAPTERS.md +83 -3
- package/docs/API_REFERENCE.md +95 -104
- package/docs/ARCHITECTURE.md +284 -286
- package/docs/CONSTRUCTOR_OPTIONS.md +192 -135
- package/docs/CONTEXT_MANAGEMENT.md +311 -28
- package/docs/CONTRIBUTING.md +1 -1
- package/docs/DOMAINS.md +61 -0
- package/docs/GETTING_STARTED.md +177 -88
- package/docs/PERSISTENCE.md +170 -23
- package/docs/README.md +7 -10
- package/examples/business-onboarding.ts +21 -9
- package/examples/company-qna-agent.ts +508 -0
- package/examples/declarative-agent.ts +143 -26
- package/examples/domain-scoping.ts +31 -10
- package/examples/extracted-data-modification.ts +415 -0
- package/examples/healthcare-agent.ts +194 -90
- package/examples/openai-agent.ts +67 -25
- package/examples/opensearch-persistence.ts +455 -151
- package/examples/persistent-onboarding.ts +162 -96
- package/examples/prisma-persistence.ts +371 -125
- package/examples/redis-persistence.ts +393 -23
- package/examples/rules-prohibitions.ts +32 -11
- package/examples/streaming-agent.ts +61 -13
- package/examples/travel-agent.ts +266 -133
- package/package.json +1 -1
- package/src/core/Agent.ts +674 -356
- package/src/core/Events.ts +12 -2
- package/src/core/PersistenceManager.ts +83 -0
- package/src/core/PromptComposer.ts +143 -0
- package/src/core/ResponseEngine.ts +82 -0
- package/src/core/Route.ts +32 -17
- package/src/core/RoutingEngine.ts +165 -0
- package/src/core/State.ts +55 -15
- package/src/core/ToolExecutor.ts +117 -0
- package/src/core/Transition.ts +5 -5
- package/src/index.ts +12 -21
- package/src/providers/AnthropicProvider.ts +10 -13
- package/src/providers/GeminiProvider.ts +12 -8
- package/src/providers/OpenAIProvider.ts +10 -56
- package/src/providers/OpenRouterProvider.ts +10 -56
- package/src/types/agent.ts +16 -13
- package/src/types/ai.ts +6 -2
- package/src/types/history.ts +8 -0
- package/src/types/index.ts +0 -11
- package/src/types/route.ts +41 -5
- package/src/types/routing.ts +18 -0
- package/src/types/schema.ts +23 -0
- package/src/types/session.ts +207 -0
- package/src/types/tool.ts +29 -7
- package/src/utils/id.ts +0 -10
- package/src/utils/schema.ts +32 -0
- package/dist/cjs/core/ConditionEvaluator.d.ts +0 -72
- package/dist/cjs/core/ConditionEvaluator.d.ts.map +0 -1
- package/dist/cjs/core/ConditionEvaluator.js +0 -272
- package/dist/cjs/core/ConditionEvaluator.js.map +0 -1
- package/dist/cjs/core/Observation.d.ts +0 -24
- package/dist/cjs/core/Observation.d.ts.map +0 -1
- package/dist/cjs/core/Observation.js +0 -39
- package/dist/cjs/core/Observation.js.map +0 -1
- package/dist/cjs/core/PreparationEngine.d.ts +0 -116
- package/dist/cjs/core/PreparationEngine.d.ts.map +0 -1
- package/dist/cjs/core/PreparationEngine.js +0 -353
- package/dist/cjs/core/PreparationEngine.js.map +0 -1
- package/dist/cjs/core/PromptBuilder.d.ts +0 -136
- package/dist/cjs/core/PromptBuilder.d.ts.map +0 -1
- package/dist/cjs/core/PromptBuilder.js +0 -421
- package/dist/cjs/core/PromptBuilder.js.map +0 -1
- package/dist/cjs/types/observation.d.ts +0 -27
- package/dist/cjs/types/observation.d.ts.map +0 -1
- package/dist/cjs/types/observation.js +0 -6
- package/dist/cjs/types/observation.js.map +0 -1
- package/dist/cjs/types/prompt.d.ts +0 -46
- package/dist/cjs/types/prompt.d.ts.map +0 -1
- package/dist/cjs/types/prompt.js +0 -19
- package/dist/cjs/types/prompt.js.map +0 -1
- package/dist/core/ConditionEvaluator.d.ts +0 -72
- package/dist/core/ConditionEvaluator.d.ts.map +0 -1
- package/dist/core/ConditionEvaluator.js +0 -268
- package/dist/core/ConditionEvaluator.js.map +0 -1
- package/dist/core/Observation.d.ts +0 -24
- package/dist/core/Observation.d.ts.map +0 -1
- package/dist/core/Observation.js +0 -35
- package/dist/core/Observation.js.map +0 -1
- package/dist/core/PreparationEngine.d.ts +0 -116
- package/dist/core/PreparationEngine.d.ts.map +0 -1
- package/dist/core/PreparationEngine.js +0 -349
- package/dist/core/PreparationEngine.js.map +0 -1
- package/dist/core/PromptBuilder.d.ts +0 -136
- package/dist/core/PromptBuilder.d.ts.map +0 -1
- package/dist/core/PromptBuilder.js +0 -417
- package/dist/core/PromptBuilder.js.map +0 -1
- package/dist/types/observation.d.ts +0 -27
- package/dist/types/observation.d.ts.map +0 -1
- package/dist/types/observation.js +0 -5
- package/dist/types/observation.js.map +0 -1
- package/dist/types/prompt.d.ts +0 -46
- package/dist/types/prompt.d.ts.map +0 -1
- package/dist/types/prompt.js +0 -16
- package/dist/types/prompt.js.map +0 -1
- package/docs/STRUCTURE.md +0 -58
- package/src/core/ConditionEvaluator.ts +0 -381
- package/src/core/Observation.ts +0 -47
- package/src/core/PreparationEngine.ts +0 -561
- package/src/core/PromptBuilder.ts +0 -617
- package/src/types/observation.ts +0 -29
- package/src/types/prompt.ts +0 -49
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -2,384 +2,382 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
`@falai/agent` is built on a **
|
|
5
|
+
`@falai/agent` is built on a **schema-first, data-driven architecture** that prioritizes type safety, structured data extraction, and code-based state management over fuzzy LLM conditions. This creates predictable, maintainable, and efficient conversational AI agents.
|
|
6
6
|
|
|
7
7
|
## Core Design Principles
|
|
8
8
|
|
|
9
|
-
### 1. 🎯
|
|
9
|
+
### 1. 🎯 Schema-First Data Extraction
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Define what data to collect upfront using JSON Schema, then extract it reliably:
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
// Define your data contract
|
|
15
|
+
interface FlightData {
|
|
16
|
+
destination: string;
|
|
17
|
+
departureDate: string;
|
|
18
|
+
passengers: number;
|
|
19
|
+
cabinClass: "economy" | "business" | "first";
|
|
20
|
+
}
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
const route = agent.createRoute<FlightData>({
|
|
23
|
+
title: "Book Flight",
|
|
24
|
+
description: "Help user book a flight",
|
|
25
|
+
gatherSchema: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
destination: { type: "string" },
|
|
29
|
+
departureDate: { type: "string" },
|
|
30
|
+
passengers: { type: "number", minimum: 1, maximum: 9 },
|
|
31
|
+
cabinClass: {
|
|
32
|
+
type: "string",
|
|
33
|
+
enum: ["economy", "business", "first"],
|
|
34
|
+
default: "economy",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
required: ["destination", "departureDate", "passengers"],
|
|
38
|
+
},
|
|
39
|
+
});
|
|
27
40
|
```
|
|
28
41
|
|
|
29
|
-
**Why?**
|
|
42
|
+
**Why?** Schema-first extraction provides:
|
|
30
43
|
|
|
31
|
-
- **
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
34
|
-
- **
|
|
44
|
+
- **Type Safety** - Full TypeScript types from definition to extraction
|
|
45
|
+
- **Reliability** - Provider-enforced schemas, not prompt-based parsing
|
|
46
|
+
- **Predictability** - Same data structure every time
|
|
47
|
+
- **Efficiency** - Extract multiple fields in one LLM call
|
|
35
48
|
|
|
36
|
-
### 2.
|
|
49
|
+
### 2. 📊 Session State Management
|
|
37
50
|
|
|
38
|
-
|
|
51
|
+
Track conversation progress and extracted data across turns:
|
|
39
52
|
|
|
40
53
|
```typescript
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
});
|
|
54
|
+
import {
|
|
55
|
+
createSession,
|
|
56
|
+
enterRoute,
|
|
57
|
+
enterState,
|
|
58
|
+
mergeExtracted,
|
|
59
|
+
} from "@falai/agent";
|
|
60
|
+
|
|
61
|
+
let session = createSession<FlightData>();
|
|
62
|
+
|
|
63
|
+
// Turn 1 - Extract data
|
|
64
|
+
const response1 = await agent.respond({ history, session });
|
|
65
|
+
session = response1.session!; // Updated with extracted data
|
|
66
|
+
|
|
67
|
+
// Turn 2 - User changes mind (always-on routing)
|
|
68
|
+
const response2 = await agent.respond({ history, session: response1.session });
|
|
69
|
+
session = response2.session!; // Route/state updated if user changed direction
|
|
56
70
|
```
|
|
57
71
|
|
|
58
|
-
**Why?**
|
|
59
|
-
|
|
60
|
-
- **Reliability** - Tools always execute when they should
|
|
61
|
-
- **Security** - You control tool execution, not the AI
|
|
62
|
-
- **Determinism** - Same conversation always triggers same tools
|
|
63
|
-
- **Separation of Concerns** - AI generates messages, engine executes tools
|
|
72
|
+
**Why?** Session state enables:
|
|
64
73
|
|
|
65
|
-
|
|
74
|
+
- **Always-on Routing** - Users can change their mind mid-conversation
|
|
75
|
+
- **Context Awareness** - Router sees current progress and extracted data
|
|
76
|
+
- **Data Persistence** - Extracted data survives across turns
|
|
77
|
+
- **State Recovery** - Resume conversations from any point
|
|
66
78
|
|
|
67
|
-
|
|
79
|
+
### 3. 🔧 Code-Based State Logic
|
|
68
80
|
|
|
69
|
-
|
|
70
|
-
- Controls conversation flow
|
|
71
|
-
- Makes routing decisions
|
|
72
|
-
- Manages state transitions
|
|
81
|
+
Use TypeScript functions instead of LLM conditions for deterministic flow:
|
|
73
82
|
|
|
74
83
|
```typescript
|
|
75
|
-
//
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
// State with smart bypassing based on extracted data
|
|
85
|
+
const askDestination = route.initialState.transitionTo({
|
|
86
|
+
chatState: "Ask where they want to fly",
|
|
87
|
+
gather: ["destination"],
|
|
88
|
+
skipIf: (extracted) => !!extracted.destination, // Code-based condition!
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const askDate = askDestination.transitionTo({
|
|
92
|
+
chatState: "Ask about travel dates",
|
|
93
|
+
gather: ["departureDate"],
|
|
94
|
+
skipIf: (extracted) => !!extracted.departureDate,
|
|
95
|
+
requiredData: ["destination"], // Prerequisites
|
|
96
|
+
});
|
|
88
97
|
```
|
|
89
98
|
|
|
90
|
-
**Why?**
|
|
99
|
+
**Why?** Code-based logic provides:
|
|
91
100
|
|
|
92
|
-
- **
|
|
93
|
-
- **
|
|
94
|
-
- **
|
|
95
|
-
- **
|
|
101
|
+
- **Predictability** - No fuzzy LLM interpretation of conditions
|
|
102
|
+
- **Performance** - No extra LLM calls for condition checking
|
|
103
|
+
- **Debugging** - Clear logic flow you can trace
|
|
104
|
+
- **Type Safety** - Full TypeScript support for data validation
|
|
96
105
|
|
|
97
|
-
### 4.
|
|
106
|
+
### 4. 🛠️ Tools with Data Access
|
|
98
107
|
|
|
99
|
-
|
|
108
|
+
Tools execute with full context including extracted data:
|
|
100
109
|
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
│ 4. Execute state machine transitions │
|
|
123
|
-
│ - If state has toolState → execute it │
|
|
124
|
-
│ - Update context with results │
|
|
125
|
-
└─────────────────┬───────────────────────────────┘
|
|
126
|
-
│
|
|
127
|
-
▼
|
|
128
|
-
┌─────────┴─────────┐
|
|
129
|
-
│ Tools executed? │
|
|
130
|
-
└─────────┬─────────┘
|
|
131
|
-
│
|
|
132
|
-
┌─────────┴─────────┐
|
|
133
|
-
│ Yes │ No │
|
|
134
|
-
▼ ▼
|
|
135
|
-
┌─────────┐ ┌────────────┐
|
|
136
|
-
│ Loop │ │ Generate │
|
|
137
|
-
│ again │ │ message │
|
|
138
|
-
└─────────┘ └────────────┘
|
|
110
|
+
```typescript
|
|
111
|
+
const searchFlights = defineTool<Context, [], void, FlightData>(
|
|
112
|
+
"search_flights",
|
|
113
|
+
async (toolContext) => {
|
|
114
|
+
const { extracted, context, history } = toolContext;
|
|
115
|
+
|
|
116
|
+
// Access extracted data directly
|
|
117
|
+
if (!extracted.destination || !extracted.departureDate) {
|
|
118
|
+
return { data: undefined };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Enrich extracted data
|
|
122
|
+
return {
|
|
123
|
+
data: undefined,
|
|
124
|
+
extractedUpdate: {
|
|
125
|
+
destinationCode: await lookupAirportCode(extracted.destination),
|
|
126
|
+
departureDateParsed: parseDate(extracted.departureDate),
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
);
|
|
139
131
|
```
|
|
140
132
|
|
|
141
|
-
**Why?**
|
|
133
|
+
**Why?** Tools with data access enable:
|
|
142
134
|
|
|
143
|
-
- **
|
|
144
|
-
- **
|
|
145
|
-
- **
|
|
146
|
-
- **
|
|
135
|
+
- **Data Enrichment** - Tools can validate and enhance extracted data
|
|
136
|
+
- **Computed Fields** - Calculate derived values from extracted data
|
|
137
|
+
- **Conditional Execution** - Tools decide what to do based on data state
|
|
138
|
+
- **Action Flags** - Tools can set flags for subsequent operations
|
|
147
139
|
|
|
148
|
-
### 5.
|
|
140
|
+
### 5. 🎭 Always-On Routing
|
|
149
141
|
|
|
150
|
-
|
|
142
|
+
Routing happens every turn, allowing users to change direction:
|
|
151
143
|
|
|
152
144
|
```typescript
|
|
153
|
-
//
|
|
154
|
-
agent.
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
/* ... */
|
|
160
|
-
},
|
|
145
|
+
// User starts booking a flight
|
|
146
|
+
const response1 = await agent.respond({
|
|
147
|
+
history: [
|
|
148
|
+
createMessageEvent(EventSource.CUSTOMER, "User", "I want to fly to Paris"),
|
|
149
|
+
],
|
|
150
|
+
session,
|
|
161
151
|
});
|
|
162
152
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
153
|
+
// User changes mind mid-conversation
|
|
154
|
+
const response2 = await agent.respond({
|
|
155
|
+
history: [
|
|
156
|
+
...previousHistory,
|
|
157
|
+
createMessageEvent(
|
|
158
|
+
EventSource.CUSTOMER,
|
|
159
|
+
"User",
|
|
160
|
+
"Actually, make that Tokyo instead"
|
|
161
|
+
),
|
|
162
|
+
],
|
|
163
|
+
session: response1.session, // Router sees context and switches appropriately
|
|
170
164
|
});
|
|
165
|
+
```
|
|
171
166
|
|
|
172
|
-
|
|
173
|
-
const checkoutRoute = agent.createRoute({
|
|
174
|
-
title: "Checkout",
|
|
175
|
-
domains: ["payment"], // SECURITY: Only payment tools can execute in this route
|
|
176
|
-
});
|
|
167
|
+
**Why?** Always-on routing provides:
|
|
177
168
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
169
|
+
- **User Control** - Users can change their mind naturally
|
|
170
|
+
- **Context Awareness** - Router considers current progress
|
|
171
|
+
- **Graceful Transitions** - Smooth handling of intent changes
|
|
172
|
+
- **No Dead Ends** - Always a valid next step
|
|
173
|
+
|
|
174
|
+
### 6. 🔄 Three-Phase Pipeline
|
|
175
|
+
|
|
176
|
+
Clean separation of concerns in every response:
|
|
182
177
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
// No domains = ALL tools available (default behavior)
|
|
186
|
-
});
|
|
178
|
+
```
|
|
179
|
+
1. PREPARATION → 2. ROUTING → 3. RESPONSE
|
|
187
180
|
```
|
|
188
181
|
|
|
189
|
-
**
|
|
182
|
+
**Phase 1: Preparation**
|
|
190
183
|
|
|
191
|
-
-
|
|
192
|
-
-
|
|
193
|
-
-
|
|
194
|
-
- ❌ Domains don't affect what AI says, only what tools can run
|
|
184
|
+
- Execute tools if current state has `toolState`
|
|
185
|
+
- Update context with tool results
|
|
186
|
+
- Enrich extracted data if tools return `extractedUpdate`
|
|
195
187
|
|
|
196
|
-
**
|
|
188
|
+
**Phase 2: Routing**
|
|
197
189
|
|
|
198
|
-
-
|
|
199
|
-
-
|
|
200
|
-
-
|
|
201
|
-
-
|
|
202
|
-
- **Scalability** - Add new domains without affecting existing ones
|
|
190
|
+
- Build dynamic routing schema (scores for all routes 0-100)
|
|
191
|
+
- Include session context in routing prompt
|
|
192
|
+
- AI selects best route based on current state
|
|
193
|
+
- Update session if route changed
|
|
203
194
|
|
|
204
|
-
**
|
|
195
|
+
**Phase 3: Response**
|
|
205
196
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
title: "General Chat",
|
|
211
|
-
domains: ["chat", "user"], // Can't execute payment tools
|
|
212
|
-
});
|
|
197
|
+
- Determine next state using `skipIf` and `requiredData`
|
|
198
|
+
- Build response schema including current state's `gather` fields
|
|
199
|
+
- Generate message with schema-enforced data extraction
|
|
200
|
+
- Update session with newly extracted data
|
|
213
201
|
|
|
214
|
-
|
|
215
|
-
title: "Checkout",
|
|
216
|
-
domains: ["payment"], // Can execute payment, but not unrelated tools
|
|
217
|
-
});
|
|
218
|
-
```
|
|
202
|
+
**Why?** This architecture enables:
|
|
219
203
|
|
|
220
|
-
|
|
204
|
+
- **Efficiency** - 1-2 LLM calls per turn vs 3-5 in condition-heavy approaches
|
|
205
|
+
- **Reliability** - Tools execute before AI sees the conversation
|
|
206
|
+
- **Flexibility** - Always-on routing handles any user direction
|
|
207
|
+
- **Type Safety** - Schemas ensure consistent data structures
|
|
221
208
|
|
|
222
|
-
|
|
209
|
+
### 7. 📦 Enhanced Lifecycle Hooks
|
|
223
210
|
|
|
224
|
-
|
|
225
|
-
interface MyContext {
|
|
226
|
-
userId: string;
|
|
227
|
-
plan: "free" | "pro" | "enterprise";
|
|
228
|
-
remainingCredits: number;
|
|
229
|
-
}
|
|
211
|
+
Hooks for validation, enrichment, and persistence:
|
|
230
212
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
context: {
|
|
235
|
-
userId: "user123",
|
|
236
|
-
plan: "pro",
|
|
237
|
-
remainingCredits: 100,
|
|
238
|
-
},
|
|
213
|
+
```typescript
|
|
214
|
+
const agent = new Agent({
|
|
215
|
+
// ... other options
|
|
239
216
|
hooks: {
|
|
240
217
|
// Refresh context before each response
|
|
241
218
|
beforeRespond: async (ctx) => {
|
|
242
|
-
|
|
243
|
-
return { ...ctx, remainingCredits: freshData.credits };
|
|
219
|
+
return await loadFreshContext(ctx.userId);
|
|
244
220
|
},
|
|
245
221
|
|
|
246
222
|
// Persist context updates
|
|
247
223
|
onContextUpdate: async (newCtx, oldCtx) => {
|
|
248
|
-
await
|
|
249
|
-
|
|
250
|
-
|
|
224
|
+
await saveContext(newCtx);
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
// Validate and enrich extracted data
|
|
228
|
+
onExtractedUpdate: async (extracted, previous) => {
|
|
229
|
+
// Normalize data
|
|
230
|
+
if (extracted.passengers < 1) extracted.passengers = 1;
|
|
231
|
+
|
|
232
|
+
// Auto-trigger actions
|
|
233
|
+
if (hasAllRequiredData(extracted)) {
|
|
234
|
+
extracted.shouldSearchFlights = true;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return extracted;
|
|
251
238
|
},
|
|
252
239
|
},
|
|
253
240
|
});
|
|
241
|
+
```
|
|
254
242
|
|
|
255
|
-
|
|
256
|
-
agent.createGuideline({
|
|
257
|
-
condition: "User requests a feature",
|
|
258
|
-
action:
|
|
259
|
-
"If context.plan is 'free', explain upgrade benefits. Otherwise provide the feature.",
|
|
260
|
-
});
|
|
243
|
+
**Why?** Lifecycle hooks provide:
|
|
261
244
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
return {
|
|
267
|
-
data: true,
|
|
268
|
-
contextUpdate: {
|
|
269
|
-
remainingCredits: toolContext.context.remainingCredits - 1,
|
|
270
|
-
},
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
);
|
|
274
|
-
```
|
|
245
|
+
- **Data Validation** - Ensure extracted data meets business rules
|
|
246
|
+
- **Enrichment** - Add computed fields or normalize values
|
|
247
|
+
- **Persistence** - Save/restore conversation state
|
|
248
|
+
- **Integration** - Connect with external systems
|
|
275
249
|
|
|
276
|
-
|
|
250
|
+
## Comparison with Other Approaches
|
|
277
251
|
|
|
278
|
-
|
|
279
|
-
- **State persistence** - Context survives across conversations
|
|
280
|
-
- **Dynamic guidelines** - Rules that depend on user state
|
|
281
|
-
- **Tool integration** - Tools update context for next iteration
|
|
252
|
+
### @falai/agent vs Traditional State Machines
|
|
282
253
|
|
|
283
|
-
|
|
254
|
+
| Aspect | @falai/agent (Data-Driven) | Traditional State Machines |
|
|
255
|
+
| ------------------- | -------------------------- | ------------------------------------- |
|
|
256
|
+
| **State Logic** | Code-based (`skipIf`) | Manual condition checking |
|
|
257
|
+
| **Data Collection** | Schema-driven extraction | Manual parsing |
|
|
258
|
+
| **Type Safety** | Full TypeScript | Often runtime validation |
|
|
259
|
+
| **LLM Calls/Turn** | 1-2 (routing + response) | 3-5 (conditions + routing + response) |
|
|
260
|
+
| **Validation** | Code + schemas | Manual implementation |
|
|
261
|
+
| **Routing** | Always-on, context-aware | Route-only, rigid |
|
|
284
262
|
|
|
285
|
-
|
|
263
|
+
### @falai/agent vs OpenAI Function Calling
|
|
286
264
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
{
|
|
296
|
-
name: "SLA",
|
|
297
|
-
description: "Service Level Agreement - 24hr response time",
|
|
298
|
-
},
|
|
299
|
-
],
|
|
300
|
-
guidelines: [
|
|
301
|
-
{
|
|
302
|
-
condition: "Customer is frustrated",
|
|
303
|
-
action: "Apologize sincerely and escalate to human if needed",
|
|
304
|
-
},
|
|
305
|
-
],
|
|
306
|
-
routes: [
|
|
307
|
-
{
|
|
308
|
-
title: "Refund Request",
|
|
309
|
-
conditions: ["Customer wants a refund"],
|
|
310
|
-
rules: ["Always check order date before processing"],
|
|
311
|
-
prohibitions: ["Never process refunds over $1000 without approval"],
|
|
312
|
-
},
|
|
313
|
-
],
|
|
314
|
-
});
|
|
265
|
+
| Aspect | @falai/agent | OpenAI Functions |
|
|
266
|
+
| ------------------ | ------------------------ | ----------------------------- |
|
|
267
|
+
| **Tool Execution** | Automatic (state-driven) | AI-decided |
|
|
268
|
+
| **Flow Control** | Code-based state logic | AI inference |
|
|
269
|
+
| **Determinism** | High - code-driven flow | Low - AI may vary |
|
|
270
|
+
| **Data Handling** | Structured schemas | Unstructured function results |
|
|
271
|
+
| **Type Safety** | Full TypeScript | Runtime type checking |
|
|
272
|
+
| **Use Case** | Structured conversations | Flexible, open-ended tasks |
|
|
315
273
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
274
|
+
## When to Use @falai/agent
|
|
275
|
+
|
|
276
|
+
✅ **Great for:**
|
|
277
|
+
|
|
278
|
+
- **Data Collection Flows** - Booking, onboarding, forms, surveys
|
|
279
|
+
- **Multi-Step Processes** - Complex workflows with clear progression
|
|
280
|
+
- **Type-Safe Applications** - When data structure matters
|
|
281
|
+
- **Predictable Conversations** - Structured, goal-oriented interactions
|
|
282
|
+
- **Session-Based Apps** - Conversations that span multiple turns
|
|
283
|
+
|
|
284
|
+
❌ **Not ideal for:**
|
|
285
|
+
|
|
286
|
+
- **Open-Ended Chat** - General conversation without clear goals
|
|
287
|
+
- **Creative Tasks** - Brainstorming, writing, ideation
|
|
288
|
+
- **Simple Q&A** - Stateless question-answering (use stateless routes!)
|
|
289
|
+
- **Rapid Prototyping** - When you need maximum flexibility
|
|
290
|
+
|
|
291
|
+
## Architecture Patterns
|
|
292
|
+
|
|
293
|
+
### Stateful Routes (Data Collection)
|
|
294
|
+
|
|
295
|
+
For structured data gathering with state management:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
interface BookingData {
|
|
299
|
+
destination: string;
|
|
300
|
+
dates: string;
|
|
301
|
+
passengers: number;
|
|
325
302
|
}
|
|
326
|
-
```
|
|
327
303
|
|
|
328
|
-
|
|
304
|
+
const bookingRoute = agent.createRoute<BookingData>({
|
|
305
|
+
title: "Flight Booking",
|
|
306
|
+
gatherSchema: {
|
|
307
|
+
/* schema for all fields */
|
|
308
|
+
},
|
|
309
|
+
});
|
|
329
310
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
311
|
+
bookingRoute.initialState
|
|
312
|
+
.transitionTo({
|
|
313
|
+
chatState: "Ask destination",
|
|
314
|
+
gather: ["destination"],
|
|
315
|
+
skipIf: (data) => !!data.destination,
|
|
316
|
+
})
|
|
317
|
+
.transitionTo({
|
|
318
|
+
toolState: enrichDestination, // Validates and enriches
|
|
319
|
+
requiredData: ["destination"],
|
|
320
|
+
})
|
|
321
|
+
.transitionTo({
|
|
322
|
+
chatState: "Ask dates",
|
|
323
|
+
gather: ["dates"],
|
|
324
|
+
skipIf: (data) => !!data.dates,
|
|
325
|
+
});
|
|
326
|
+
```
|
|
334
327
|
|
|
335
|
-
|
|
328
|
+
### Stateless Routes (Q&A)
|
|
336
329
|
|
|
337
|
-
|
|
330
|
+
For simple question-answering without state:
|
|
338
331
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
| **Cost** | Lower - tools not in prompts | Higher - full tool specs in prompt |
|
|
346
|
-
| **Use Case** | Structured conversations | Flexible, open-ended tasks |
|
|
332
|
+
```typescript
|
|
333
|
+
const qnaRoute = agent.createRoute({
|
|
334
|
+
title: "Company Q&A",
|
|
335
|
+
conditions: ["User asks about company"],
|
|
336
|
+
// NO gatherSchema - stateless!
|
|
337
|
+
});
|
|
347
338
|
|
|
348
|
-
|
|
339
|
+
// Just use initial state
|
|
340
|
+
qnaRoute.initialState.chatState = "Answer from knowledge base";
|
|
341
|
+
```
|
|
349
342
|
|
|
350
|
-
|
|
343
|
+
### Mixed Architecture
|
|
351
344
|
|
|
352
|
-
|
|
353
|
-
- Onboarding flows
|
|
354
|
-
- Multi-step processes
|
|
355
|
-
- Compliance-sensitive applications
|
|
356
|
-
- Predictable conversation paths
|
|
357
|
-
- Tool-heavy applications
|
|
345
|
+
Combine both patterns in one agent:
|
|
358
346
|
|
|
359
|
-
|
|
347
|
+
```typescript
|
|
348
|
+
// Q&A routes (stateless)
|
|
349
|
+
const companyInfoRoute = agent.createRoute({
|
|
350
|
+
/* no schema */
|
|
351
|
+
});
|
|
352
|
+
const productInfoRoute = agent.createRoute({
|
|
353
|
+
/* no schema */
|
|
354
|
+
});
|
|
360
355
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
356
|
+
// Booking routes (stateful)
|
|
357
|
+
const bookingRoute = agent.createRoute<BookingData>({
|
|
358
|
+
/* with schema */
|
|
359
|
+
});
|
|
360
|
+
const supportRoute = agent.createRoute<SupportData>({
|
|
361
|
+
/* with schema */
|
|
362
|
+
});
|
|
363
|
+
```
|
|
365
364
|
|
|
366
365
|
## Design Influences
|
|
367
366
|
|
|
368
367
|
This framework draws inspiration from:
|
|
369
368
|
|
|
370
|
-
1. **
|
|
369
|
+
1. **Schema-First APIs** - JSON Schema for data contracts
|
|
371
370
|
2. **State Machines** - Explicit state modeling for predictability
|
|
372
|
-
3. **
|
|
373
|
-
4. **
|
|
374
|
-
5. **React Hooks** - Lifecycle
|
|
371
|
+
3. **TypeScript** - Full type safety throughout
|
|
372
|
+
4. **Functional Programming** - Pure functions for state logic
|
|
373
|
+
5. **React Hooks** - Lifecycle patterns for extensibility
|
|
375
374
|
|
|
376
375
|
## Further Reading
|
|
377
376
|
|
|
378
377
|
- [Getting Started Guide](./GETTING_STARTED.md) - Build your first agent
|
|
378
|
+
- [Session State Guide](./CONTEXT_MANAGEMENT.md) - Session management patterns
|
|
379
379
|
- [API Reference](./API_REFERENCE.md) - Complete API documentation
|
|
380
|
-
- [
|
|
381
|
-
- [Provider Docs](./PROVIDERS.md) - AI provider configuration
|
|
382
|
-
- [Examples](/examples) - Real-world agent implementations
|
|
380
|
+
- [Examples](../examples/) - Real-world implementations
|
|
383
381
|
|
|
384
382
|
---
|
|
385
383
|
|