@falai/agent 0.6.9 → 0.7.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 +62 -59
- 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.js +7 -7
- package/dist/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/adapters/PostgreSQLAdapter.js +9 -9
- package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/adapters/PrismaAdapter.js +3 -3
- 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 +3 -3
- package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/adapters/SQLiteAdapter.js +11 -11
- package/dist/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.d.ts.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.js +7 -7
- package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.js +9 -9
- package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/cjs/adapters/PrismaAdapter.js +3 -3
- 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 +3 -3
- package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.js +11 -11
- package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/cjs/adapters/index.d.ts +1 -1
- package/dist/cjs/adapters/index.d.ts.map +1 -1
- package/dist/cjs/constants/index.d.ts +4 -4
- package/dist/cjs/constants/index.js +5 -5
- package/dist/cjs/core/Agent.d.ts +22 -22
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +160 -152
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/Events.d.ts +6 -6
- package/dist/cjs/core/Events.d.ts.map +1 -1
- package/dist/cjs/core/PersistenceManager.d.ts +13 -13
- package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
- package/dist/cjs/core/PersistenceManager.js +24 -24
- package/dist/cjs/core/PersistenceManager.js.map +1 -1
- package/dist/cjs/core/ResponseEngine.d.ts +3 -8
- package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
- package/dist/cjs/core/ResponseEngine.js +8 -8
- package/dist/cjs/core/ResponseEngine.js.map +1 -1
- package/dist/cjs/core/Route.d.ts +17 -17
- package/dist/cjs/core/Route.d.ts.map +1 -1
- package/dist/cjs/core/Route.js +33 -33
- package/dist/cjs/core/Route.js.map +1 -1
- package/dist/cjs/core/RoutingEngine.d.ts +30 -30
- package/dist/cjs/core/RoutingEngine.d.ts.map +1 -1
- package/dist/cjs/core/RoutingEngine.js +192 -192
- package/dist/cjs/core/RoutingEngine.js.map +1 -1
- package/dist/cjs/core/Step.d.ts +72 -0
- package/dist/cjs/core/Step.d.ts.map +1 -0
- package/dist/cjs/core/Step.js +150 -0
- package/dist/cjs/core/Step.js.map +1 -0
- package/dist/cjs/core/ToolExecutor.d.ts +5 -5
- package/dist/cjs/core/ToolExecutor.d.ts.map +1 -1
- package/dist/cjs/core/ToolExecutor.js +8 -8
- package/dist/cjs/core/ToolExecutor.js.map +1 -1
- package/dist/cjs/core/Transition.d.ts +14 -14
- package/dist/cjs/core/Transition.d.ts.map +1 -1
- package/dist/cjs/core/Transition.js +48 -19
- package/dist/cjs/core/Transition.js.map +1 -1
- package/dist/cjs/index.d.ts +7 -7
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +8 -8
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +8 -8
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/ai.d.ts +2 -2
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/cjs/types/history.d.ts +3 -3
- package/dist/cjs/types/history.d.ts.map +1 -1
- package/dist/cjs/types/index.d.ts +1 -1
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/persistence.d.ts +5 -5
- package/dist/cjs/types/persistence.d.ts.map +1 -1
- package/dist/cjs/types/route.d.ts +57 -52
- package/dist/cjs/types/route.d.ts.map +1 -1
- package/dist/cjs/types/session.d.ts +27 -27
- package/dist/cjs/types/session.d.ts.map +1 -1
- package/dist/cjs/types/session.js +48 -50
- package/dist/cjs/types/session.js.map +1 -1
- package/dist/cjs/types/tool.d.ts +13 -13
- package/dist/cjs/types/tool.d.ts.map +1 -1
- package/dist/cjs/utils/id.d.ts +8 -3
- package/dist/cjs/utils/id.d.ts.map +1 -1
- package/dist/cjs/utils/id.js +16 -7
- package/dist/cjs/utils/id.js.map +1 -1
- package/dist/constants/index.d.ts +4 -4
- package/dist/constants/index.js +4 -4
- package/dist/core/Agent.d.ts +22 -22
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +162 -154
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/Events.d.ts +6 -6
- package/dist/core/Events.d.ts.map +1 -1
- package/dist/core/PersistenceManager.d.ts +13 -13
- package/dist/core/PersistenceManager.d.ts.map +1 -1
- package/dist/core/PersistenceManager.js +25 -25
- package/dist/core/PersistenceManager.js.map +1 -1
- package/dist/core/ResponseEngine.d.ts +3 -8
- package/dist/core/ResponseEngine.d.ts.map +1 -1
- package/dist/core/ResponseEngine.js +8 -8
- package/dist/core/ResponseEngine.js.map +1 -1
- package/dist/core/Route.d.ts +17 -17
- package/dist/core/Route.d.ts.map +1 -1
- package/dist/core/Route.js +33 -33
- package/dist/core/Route.js.map +1 -1
- package/dist/core/RoutingEngine.d.ts +30 -30
- package/dist/core/RoutingEngine.d.ts.map +1 -1
- package/dist/core/RoutingEngine.js +193 -193
- package/dist/core/RoutingEngine.js.map +1 -1
- package/dist/core/Step.d.ts +72 -0
- package/dist/core/Step.d.ts.map +1 -0
- package/dist/core/Step.js +146 -0
- package/dist/core/Step.js.map +1 -0
- package/dist/core/ToolExecutor.d.ts +5 -5
- package/dist/core/ToolExecutor.d.ts.map +1 -1
- package/dist/core/ToolExecutor.js +8 -8
- package/dist/core/ToolExecutor.js.map +1 -1
- package/dist/core/Transition.d.ts +14 -14
- package/dist/core/Transition.d.ts.map +1 -1
- package/dist/core/Transition.js +48 -19
- package/dist/core/Transition.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/types/agent.d.ts +8 -8
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/ai.d.ts +2 -2
- package/dist/types/ai.d.ts.map +1 -1
- package/dist/types/history.d.ts +3 -3
- package/dist/types/history.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/persistence.d.ts +5 -5
- package/dist/types/persistence.d.ts.map +1 -1
- package/dist/types/route.d.ts +57 -52
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/session.d.ts +27 -27
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js +44 -46
- package/dist/types/session.js.map +1 -1
- package/dist/types/tool.d.ts +13 -13
- package/dist/types/tool.d.ts.map +1 -1
- package/dist/utils/id.d.ts +8 -3
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +14 -6
- package/dist/utils/id.js.map +1 -1
- package/docs/ADAPTERS.md +21 -21
- package/docs/AGENT.md +57 -55
- package/docs/API_REFERENCE.md +218 -220
- package/docs/ARCHITECTURE.md +99 -104
- package/docs/CONTEXT_MANAGEMENT.md +81 -88
- package/docs/DOCS.md +18 -18
- package/docs/DOMAINS.md +16 -16
- package/docs/EXAMPLES.md +43 -43
- package/docs/GETTING_STARTED.md +60 -63
- package/docs/PERSISTENCE.md +66 -70
- package/docs/PROVIDERS.md +2 -2
- package/docs/README.md +6 -6
- package/docs/ROUTES.md +218 -220
- package/docs/STEPS.md +883 -0
- package/examples/business-onboarding.ts +84 -81
- package/examples/company-qna-agent.ts +68 -67
- package/examples/custom-database-persistence.ts +87 -89
- package/examples/declarative-agent.ts +32 -32
- package/examples/domain-scoping.ts +18 -18
- package/examples/extracted-data-modification.ts +92 -97
- package/examples/healthcare-agent.ts +89 -91
- package/examples/openai-agent.ts +29 -32
- package/examples/opensearch-persistence.ts +43 -45
- package/examples/persistent-onboarding.ts +65 -66
- package/examples/prisma-persistence.ts +108 -112
- package/examples/prisma-schema.example.prisma +3 -3
- package/examples/redis-persistence.ts +67 -73
- package/examples/route-transitions.ts +71 -47
- package/examples/rules-prohibitions.ts +28 -28
- package/examples/streaming-agent.ts +24 -24
- package/examples/travel-agent.ts +94 -109
- package/package.json +1 -1
- package/src/adapters/MemoryAdapter.ts +3 -3
- package/src/adapters/MongoAdapter.ts +3 -3
- package/src/adapters/OpenSearchAdapter.ts +8 -8
- package/src/adapters/PostgreSQLAdapter.ts +10 -10
- package/src/adapters/PrismaAdapter.ts +4 -4
- package/src/adapters/RedisAdapter.ts +3 -3
- package/src/adapters/SQLiteAdapter.ts +15 -15
- package/src/adapters/index.ts +1 -1
- package/src/constants/index.ts +4 -4
- package/src/core/Agent.ts +210 -206
- package/src/core/Events.ts +12 -12
- package/src/core/PersistenceManager.ts +32 -36
- package/src/core/ResponseEngine.ts +11 -17
- package/src/core/Route.ts +55 -49
- package/src/core/RoutingEngine.ts +244 -252
- package/src/core/Step.ts +197 -0
- package/src/core/ToolExecutor.ts +11 -11
- package/src/core/Transition.ts +72 -26
- package/src/index.ts +8 -8
- package/src/types/agent.ts +8 -8
- package/src/types/ai.ts +2 -2
- package/src/types/history.ts +3 -3
- package/src/types/index.ts +1 -1
- package/src/types/persistence.ts +6 -6
- package/src/types/route.ts +77 -61
- package/src/types/session.ts +75 -78
- package/src/types/tool.ts +17 -17
- package/src/utils/id.ts +15 -6
- package/dist/cjs/core/State.d.ts +0 -72
- package/dist/cjs/core/State.d.ts.map +0 -1
- package/dist/cjs/core/State.js +0 -148
- package/dist/cjs/core/State.js.map +0 -1
- package/dist/core/State.d.ts +0 -72
- package/dist/core/State.d.ts.map +0 -1
- package/dist/core/State.js +0 -144
- package/dist/core/State.js.map +0 -1
- package/docs/STATES.md +0 -888
- package/src/core/State.ts +0 -212
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
`@falai/agent` is built on a **schema-first, data-driven architecture** that prioritizes type safety, structured data extraction, and code-based
|
|
5
|
+
`@falai/agent` is built on a **schema-first, data-driven architecture** that prioritizes type safety, structured data extraction, and code-based step management over fuzzy LLM conditions. This creates predictable, maintainable, and efficient conversational AI agents.
|
|
6
6
|
|
|
7
7
|
## Core Design Principles
|
|
8
8
|
|
|
@@ -22,7 +22,7 @@ interface FlightData {
|
|
|
22
22
|
const route = agent.createRoute<FlightData>({
|
|
23
23
|
title: "Book Flight",
|
|
24
24
|
description: "Help user book a flight",
|
|
25
|
-
|
|
25
|
+
schema: {
|
|
26
26
|
type: "object",
|
|
27
27
|
properties: {
|
|
28
28
|
destination: { type: "string" },
|
|
@@ -46,17 +46,12 @@ const route = agent.createRoute<FlightData>({
|
|
|
46
46
|
- **Predictability** - Same data structure every time
|
|
47
47
|
- **Efficiency** - Extract multiple fields in one LLM call
|
|
48
48
|
|
|
49
|
-
### 2. 📊 Session
|
|
49
|
+
### 2. 📊 Session Step Management
|
|
50
50
|
|
|
51
|
-
Track conversation progress and
|
|
51
|
+
Track conversation progress and collected data across turns:
|
|
52
52
|
|
|
53
53
|
```typescript
|
|
54
|
-
import {
|
|
55
|
-
createSession,
|
|
56
|
-
enterRoute,
|
|
57
|
-
enterState,
|
|
58
|
-
mergeExtracted,
|
|
59
|
-
} from "@falai/agent";
|
|
54
|
+
import { createSession, enterRoute, enterStep, mergeData } from "@falai/agent";
|
|
60
55
|
|
|
61
56
|
// Create session with optional metadata including session ID
|
|
62
57
|
let session = createSession<FlightData>(sessionId, {
|
|
@@ -66,11 +61,11 @@ let session = createSession<FlightData>(sessionId, {
|
|
|
66
61
|
|
|
67
62
|
// Turn 1 - Extract data
|
|
68
63
|
const response1 = await agent.respond({ history, session });
|
|
69
|
-
session = response1.session!; // Updated with
|
|
64
|
+
session = response1.session!; // Updated with collected data
|
|
70
65
|
|
|
71
66
|
// Turn 2 - User changes mind (always-on routing)
|
|
72
67
|
const response2 = await agent.respond({ history, session: response1.session });
|
|
73
|
-
session = response2.session!; // Route/
|
|
68
|
+
session = response2.session!; // Route/step updated if user changed direction
|
|
74
69
|
|
|
75
70
|
// Access session metadata
|
|
76
71
|
console.log(session.metadata?.sessionId); // "unique-session-123"
|
|
@@ -81,69 +76,69 @@ console.log(session.metadata?.sessionId); // "unique-session-123"
|
|
|
81
76
|
When using persistence adapters, set the session ID from the database:
|
|
82
77
|
|
|
83
78
|
```typescript
|
|
84
|
-
// Create database session and in-memory session
|
|
85
|
-
const { sessionData,
|
|
86
|
-
await persistence.
|
|
79
|
+
// Create database session and in-memory session step
|
|
80
|
+
const { sessionData, sessionStep } =
|
|
81
|
+
await persistence.createSessionWithStep<FlightData>({
|
|
87
82
|
userId: "user_123",
|
|
88
83
|
agentName: "Travel Agent",
|
|
89
84
|
});
|
|
90
85
|
|
|
91
|
-
//
|
|
92
|
-
console.log(
|
|
86
|
+
// sessionStep.metadata.sessionId is automatically set to sessionData.id
|
|
87
|
+
console.log(sessionStep.metadata?.sessionId); // "cuid_from_database"
|
|
93
88
|
|
|
94
89
|
// Use it in conversation
|
|
95
90
|
const response = await agent.respond({
|
|
96
91
|
history,
|
|
97
|
-
session:
|
|
92
|
+
session: sessionStep, // Auto-saves to database!
|
|
98
93
|
});
|
|
99
94
|
```
|
|
100
95
|
|
|
101
|
-
**Why?** Session
|
|
96
|
+
**Why?** Session step enables:
|
|
102
97
|
|
|
103
98
|
- **Always-on Routing** - Users can change their mind mid-conversation
|
|
104
|
-
- **Context Awareness** - Router sees current progress and
|
|
105
|
-
- **Data Persistence** -
|
|
106
|
-
- **
|
|
99
|
+
- **Context Awareness** - Router sees current progress and collected data
|
|
100
|
+
- **Data Persistence** - Collected data survives across turns
|
|
101
|
+
- **Step Recovery** - Resume conversations from any point
|
|
107
102
|
- **Session Tracking** - Track conversations via session ID in database
|
|
108
103
|
|
|
109
|
-
### 3. 🔧 Code-Based
|
|
104
|
+
### 3. 🔧 Code-Based Step Logic + AI-Driven Transitions
|
|
110
105
|
|
|
111
|
-
Use TypeScript functions for deterministic flow control AND text conditions for AI-driven
|
|
106
|
+
Use TypeScript functions for deterministic flow control AND text conditions for AI-driven step selection:
|
|
112
107
|
|
|
113
108
|
```typescript
|
|
114
|
-
//
|
|
115
|
-
const askDestination = route.
|
|
116
|
-
id: "ask_destination", // Optional: custom
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
skipIf: (
|
|
109
|
+
// Step with smart bypassing based on collected data
|
|
110
|
+
const askDestination = route.initialStep.nextStep({
|
|
111
|
+
id: "ask_destination", // Optional: custom step ID
|
|
112
|
+
instructions: "Ask where they want to fly",
|
|
113
|
+
collect: ["destination"],
|
|
114
|
+
skipIf: (data) => !!data.destination, // Code-based condition!
|
|
120
115
|
condition: "Customer hasn't specified destination yet", // Text condition for AI
|
|
121
116
|
});
|
|
122
117
|
|
|
123
|
-
const askDate = askDestination.
|
|
124
|
-
id: "ask_date", // Optional: custom
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
skipIf: (
|
|
128
|
-
|
|
118
|
+
const askDate = askDestination.nextStep({
|
|
119
|
+
id: "ask_date", // Optional: custom step ID for easier tracking
|
|
120
|
+
instructions: "Ask about travel dates",
|
|
121
|
+
collect: ["departureDate"],
|
|
122
|
+
skipIf: (data) => !!data.departureDate,
|
|
123
|
+
requires: ["destination"], // Prerequisites
|
|
129
124
|
condition: "Destination confirmed, need travel dates now",
|
|
130
125
|
});
|
|
131
126
|
});
|
|
132
127
|
```
|
|
133
128
|
|
|
134
|
-
**Custom
|
|
129
|
+
**Custom Step IDs:**
|
|
135
130
|
|
|
136
|
-
You can optionally provide custom IDs for
|
|
131
|
+
You can optionally provide custom IDs for steps to make them easier to track and reference:
|
|
137
132
|
|
|
138
133
|
```typescript
|
|
139
|
-
const confirmBooking = askDate.
|
|
134
|
+
const confirmBooking = askDate.nextStep({
|
|
140
135
|
id: "confirm_booking", // ✅ Custom ID instead of auto-generated
|
|
141
|
-
|
|
142
|
-
|
|
136
|
+
instructions: "Confirm all booking details",
|
|
137
|
+
requires: ["destination", "departureDate", "passengers"],
|
|
143
138
|
});
|
|
144
139
|
```
|
|
145
140
|
|
|
146
|
-
If you don't provide an ID, one is automatically generated from the route ID and
|
|
141
|
+
If you don't provide an ID, one is automatically generated from the route ID and step description.
|
|
147
142
|
|
|
148
143
|
**Why?** Code-based logic provides:
|
|
149
144
|
|
|
@@ -151,46 +146,46 @@ If you don't provide an ID, one is automatically generated from the route ID and
|
|
|
151
146
|
- **Performance** - No extra LLM calls for condition checking
|
|
152
147
|
- **Debugging** - Clear logic flow you can trace
|
|
153
148
|
- **Type Safety** - Full TypeScript support for data validation
|
|
154
|
-
- **Custom IDs** - Easier tracking and debugging with meaningful
|
|
149
|
+
- **Custom IDs** - Easier tracking and debugging with meaningful step identifiers
|
|
155
150
|
|
|
156
|
-
**How
|
|
151
|
+
**How Step Transitions Work:**
|
|
157
152
|
|
|
158
|
-
1. **Code filters first**: `skipIf` and `
|
|
159
|
-
2. **AI selects best
|
|
160
|
-
3. **Combined decision**: Single AI call handles both route selection AND
|
|
161
|
-
4. **Completion detection**: When all
|
|
153
|
+
1. **Code filters first**: `skipIf` and `requires` filter out invalid steps deterministically
|
|
154
|
+
2. **AI selects best step**: From valid candidates, AI evaluates text conditions to choose optimal step
|
|
155
|
+
3. **Combined decision**: Single AI call handles both route selection AND step selection (no extra calls!)
|
|
156
|
+
4. **Completion detection**: When all steps are skipped and `END_ROUTE` is reached, route is marked complete
|
|
162
157
|
|
|
163
158
|
```typescript
|
|
164
159
|
// The AI sees:
|
|
165
|
-
// "Available
|
|
160
|
+
// "Available steps: askDate, confirmBooking
|
|
166
161
|
// - askDate: Destination confirmed, need travel dates now
|
|
167
162
|
// - confirmBooking: All required info collected, ready to book
|
|
168
|
-
// Current
|
|
163
|
+
// Current data: {destination: 'Paris', departureDate: '2025-01-15'}
|
|
169
164
|
//
|
|
170
165
|
// → AI selects 'confirmBooking' based on context"
|
|
171
166
|
```
|
|
172
167
|
|
|
173
168
|
### 4. 🛠️ Tools with Data Access
|
|
174
169
|
|
|
175
|
-
Tools execute with full context including
|
|
170
|
+
Tools execute with full context including collected data:
|
|
176
171
|
|
|
177
172
|
```typescript
|
|
178
173
|
const searchFlights = defineTool<Context, [], void, FlightData>(
|
|
179
174
|
"search_flights",
|
|
180
175
|
async (toolContext) => {
|
|
181
|
-
const {
|
|
176
|
+
const { data, context, history } = toolContext;
|
|
182
177
|
|
|
183
|
-
// Access
|
|
184
|
-
if (!
|
|
178
|
+
// Access collected data directly
|
|
179
|
+
if (!data.destination || !data.departureDate) {
|
|
185
180
|
return { data: undefined };
|
|
186
181
|
}
|
|
187
182
|
|
|
188
|
-
// Enrich
|
|
183
|
+
// Enrich collected data
|
|
189
184
|
return {
|
|
190
185
|
data: undefined,
|
|
191
|
-
|
|
192
|
-
destinationCode: await lookupAirportCode(
|
|
193
|
-
departureDateParsed: parseDate(
|
|
186
|
+
dataUpdate: {
|
|
187
|
+
destinationCode: await lookupAirportCode(data.destination),
|
|
188
|
+
departureDateParsed: parseDate(data.departureDate),
|
|
194
189
|
},
|
|
195
190
|
};
|
|
196
191
|
}
|
|
@@ -199,9 +194,9 @@ const searchFlights = defineTool<Context, [], void, FlightData>(
|
|
|
199
194
|
|
|
200
195
|
**Why?** Tools with data access enable:
|
|
201
196
|
|
|
202
|
-
- **Data Enrichment** - Tools can validate and enhance
|
|
203
|
-
- **Computed Fields** - Calculate derived values from
|
|
204
|
-
- **Conditional Execution** - Tools decide what to do based on data
|
|
197
|
+
- **Data Enrichment** - Tools can validate and enhance collected data
|
|
198
|
+
- **Computed Fields** - Calculate derived values from collected data
|
|
199
|
+
- **Conditional Execution** - Tools decide what to do based on data step
|
|
205
200
|
- **Action Flags** - Tools can set flags for subsequent operations
|
|
206
201
|
|
|
207
202
|
### 5. 🎭 Always-On Routing
|
|
@@ -248,23 +243,23 @@ Clean separation of concerns in every response:
|
|
|
248
243
|
|
|
249
244
|
**Phase 1: Preparation**
|
|
250
245
|
|
|
251
|
-
- Execute tools if current
|
|
246
|
+
- Execute tools if current step has `tool`
|
|
252
247
|
- Update context with tool results
|
|
253
|
-
- Enrich
|
|
248
|
+
- Enrich collected data if tools return `dataUpdate`
|
|
254
249
|
|
|
255
250
|
**Phase 2: Routing**
|
|
256
251
|
|
|
257
252
|
- Build dynamic routing schema (scores for all routes 0-100)
|
|
258
253
|
- Include session context in routing prompt
|
|
259
|
-
- AI selects best route based on current
|
|
254
|
+
- AI selects best route based on current step
|
|
260
255
|
- Update session if route changed
|
|
261
256
|
|
|
262
257
|
**Phase 3: Response**
|
|
263
258
|
|
|
264
|
-
- Determine next
|
|
265
|
-
- Build response schema including current
|
|
259
|
+
- Determine next step using `skipIf` and `requires`
|
|
260
|
+
- Build response schema including current step's `collect` fields
|
|
266
261
|
- Generate message with schema-enforced data extraction
|
|
267
|
-
- Update session with newly
|
|
262
|
+
- Update session with newly collected data
|
|
268
263
|
|
|
269
264
|
**Why?** This architecture enables:
|
|
270
265
|
|
|
@@ -291,17 +286,17 @@ const agent = new Agent({
|
|
|
291
286
|
await saveContext(newCtx);
|
|
292
287
|
},
|
|
293
288
|
|
|
294
|
-
// Validate and enrich
|
|
295
|
-
|
|
289
|
+
// Validate and enrich collected data
|
|
290
|
+
onDataUpdate: async (data, previous) => {
|
|
296
291
|
// Normalize data
|
|
297
|
-
if (
|
|
292
|
+
if (data.passengers < 1) data.passengers = 1;
|
|
298
293
|
|
|
299
294
|
// Auto-trigger actions
|
|
300
|
-
if (
|
|
301
|
-
|
|
295
|
+
if (hasAllRequires(data)) {
|
|
296
|
+
data.shouldSearchFlights = true;
|
|
302
297
|
}
|
|
303
298
|
|
|
304
|
-
return
|
|
299
|
+
return data;
|
|
305
300
|
},
|
|
306
301
|
},
|
|
307
302
|
});
|
|
@@ -309,18 +304,18 @@ const agent = new Agent({
|
|
|
309
304
|
|
|
310
305
|
**Why?** Lifecycle hooks provide:
|
|
311
306
|
|
|
312
|
-
- **Data Validation** - Ensure
|
|
307
|
+
- **Data Validation** - Ensure collected data meets business rules
|
|
313
308
|
- **Enrichment** - Add computed fields or normalize values
|
|
314
|
-
- **Persistence** - Save/restore conversation
|
|
309
|
+
- **Persistence** - Save/restore conversation step
|
|
315
310
|
- **Integration** - Connect with external systems
|
|
316
311
|
|
|
317
312
|
## Comparison with Other Approaches
|
|
318
313
|
|
|
319
|
-
### @falai/agent vs Traditional
|
|
314
|
+
### @falai/agent vs Traditional Step Machines
|
|
320
315
|
|
|
321
|
-
| Aspect | @falai/agent (Data-Driven) | Traditional
|
|
316
|
+
| Aspect | @falai/agent (Data-Driven) | Traditional Step Machines |
|
|
322
317
|
| ------------------- | -------------------------- | ------------------------------------- |
|
|
323
|
-
| **
|
|
318
|
+
| **Step Logic** | Code-based (`skipIf`) | Manual condition checking |
|
|
324
319
|
| **Data Collection** | Schema-driven extraction | Manual parsing |
|
|
325
320
|
| **Type Safety** | Full TypeScript | Often runtime validation |
|
|
326
321
|
| **LLM Calls/Turn** | 1-2 (routing + response) | 3-5 (conditions + routing + response) |
|
|
@@ -331,8 +326,8 @@ const agent = new Agent({
|
|
|
331
326
|
|
|
332
327
|
| Aspect | @falai/agent | OpenAI Functions |
|
|
333
328
|
| ------------------ | ------------------------ | ----------------------------- |
|
|
334
|
-
| **Tool Execution** | Automatic (
|
|
335
|
-
| **Flow Control** | Code-based
|
|
329
|
+
| **Tool Execution** | Automatic (step-driven) | AI-decided |
|
|
330
|
+
| **Flow Control** | Code-based step logic | AI inference |
|
|
336
331
|
| **Determinism** | High - code-driven flow | Low - AI may vary |
|
|
337
332
|
| **Data Handling** | Structured schemas | Unstructured function results |
|
|
338
333
|
| **Type Safety** | Full TypeScript | Runtime type checking |
|
|
@@ -352,14 +347,14 @@ const agent = new Agent({
|
|
|
352
347
|
|
|
353
348
|
- **Open-Ended Chat** - General conversation without clear goals
|
|
354
349
|
- **Creative Tasks** - Brainstorming, writing, ideation
|
|
355
|
-
- **Simple Q&A** -
|
|
350
|
+
- **Simple Q&A** - Stepless question-answering (use stepless routes!)
|
|
356
351
|
- **Rapid Prototyping** - When you need maximum flexibility
|
|
357
352
|
|
|
358
353
|
## Architecture Patterns
|
|
359
354
|
|
|
360
|
-
###
|
|
355
|
+
### Stepful Routes (Data Collection)
|
|
361
356
|
|
|
362
|
-
For structured data
|
|
357
|
+
For structured data collecting with step management:
|
|
363
358
|
|
|
364
359
|
```typescript
|
|
365
360
|
interface BookingData {
|
|
@@ -370,41 +365,41 @@ interface BookingData {
|
|
|
370
365
|
|
|
371
366
|
const bookingRoute = agent.createRoute<BookingData>({
|
|
372
367
|
title: "Flight Booking",
|
|
373
|
-
|
|
368
|
+
schema: {
|
|
374
369
|
/* schema for all fields */
|
|
375
370
|
},
|
|
376
371
|
});
|
|
377
372
|
|
|
378
|
-
bookingRoute.
|
|
379
|
-
.
|
|
380
|
-
|
|
381
|
-
|
|
373
|
+
bookingRoute.initialStep
|
|
374
|
+
.nextStep({
|
|
375
|
+
instructions: "Ask destination",
|
|
376
|
+
collect: ["destination"],
|
|
382
377
|
skipIf: (data) => !!data.destination,
|
|
383
378
|
})
|
|
384
|
-
.
|
|
385
|
-
|
|
386
|
-
|
|
379
|
+
.nextStep({
|
|
380
|
+
tool: enrichDestination, // Validates and enriches
|
|
381
|
+
requires: ["destination"],
|
|
387
382
|
})
|
|
388
|
-
.
|
|
389
|
-
|
|
390
|
-
|
|
383
|
+
.nextStep({
|
|
384
|
+
instructions: "Ask dates",
|
|
385
|
+
collect: ["dates"],
|
|
391
386
|
skipIf: (data) => !!data.dates,
|
|
392
387
|
});
|
|
393
388
|
```
|
|
394
389
|
|
|
395
|
-
###
|
|
390
|
+
### Stepless Routes (Q&A)
|
|
396
391
|
|
|
397
|
-
For simple question-answering without
|
|
392
|
+
For simple question-answering without step:
|
|
398
393
|
|
|
399
394
|
```typescript
|
|
400
395
|
const qnaRoute = agent.createRoute({
|
|
401
396
|
title: "Company Q&A",
|
|
402
397
|
conditions: ["User asks about company"],
|
|
403
|
-
// NO
|
|
398
|
+
// NO schema - stepless!
|
|
404
399
|
});
|
|
405
400
|
|
|
406
|
-
// Just use initial
|
|
407
|
-
qnaRoute.
|
|
401
|
+
// Just use initial step
|
|
402
|
+
qnaRoute.initialStep.instructions = "Answer from knowledge base";
|
|
408
403
|
```
|
|
409
404
|
|
|
410
405
|
### Mixed Architecture
|
|
@@ -412,7 +407,7 @@ qnaRoute.initialState.chatState = "Answer from knowledge base";
|
|
|
412
407
|
Combine both patterns in one agent:
|
|
413
408
|
|
|
414
409
|
```typescript
|
|
415
|
-
// Q&A routes (
|
|
410
|
+
// Q&A routes (stepless)
|
|
416
411
|
const companyInfoRoute = agent.createRoute({
|
|
417
412
|
/* no schema */
|
|
418
413
|
});
|
|
@@ -420,7 +415,7 @@ const productInfoRoute = agent.createRoute({
|
|
|
420
415
|
/* no schema */
|
|
421
416
|
});
|
|
422
417
|
|
|
423
|
-
// Booking routes (
|
|
418
|
+
// Booking routes (stepful)
|
|
424
419
|
const bookingRoute = agent.createRoute<BookingData>({
|
|
425
420
|
/* with schema */
|
|
426
421
|
});
|
|
@@ -434,15 +429,15 @@ const supportRoute = agent.createRoute<SupportData>({
|
|
|
434
429
|
This framework draws inspiration from:
|
|
435
430
|
|
|
436
431
|
1. **Schema-First APIs** - JSON Schema for data contracts
|
|
437
|
-
2. **
|
|
432
|
+
2. **Step Machines** - Explicit step modeling for predictability
|
|
438
433
|
3. **TypeScript** - Full type safety throughout
|
|
439
|
-
4. **Functional Programming** - Pure functions for
|
|
434
|
+
4. **Functional Programming** - Pure functions for step logic
|
|
440
435
|
5. **React Hooks** - Lifecycle patterns for extensibility
|
|
441
436
|
|
|
442
437
|
## Further Reading
|
|
443
438
|
|
|
444
439
|
- [Getting Started Guide](./GETTING_STARTED.md) - Build your first agent
|
|
445
|
-
- [Session
|
|
440
|
+
- [Session Step Guide](./CONTEXT_MANAGEMENT.md) - Session management patterns
|
|
446
441
|
- [API Reference](./API_REFERENCE.md) - Complete API documentation
|
|
447
442
|
- [Examples](../examples/) - Real-world implementations
|
|
448
443
|
|