@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/API_REFERENCE.md
CHANGED
|
@@ -48,50 +48,50 @@ Gets allowed domains for a specific route by ID. Returns filtered domains based
|
|
|
48
48
|
|
|
49
49
|
Gets allowed domains for a specific route by title. Returns filtered domains based on route's `domains` property, or all domains if route has no restrictions.
|
|
50
50
|
|
|
51
|
-
##### `
|
|
51
|
+
##### `getData<TData>(routeId?): Partial<TData>`
|
|
52
52
|
|
|
53
|
-
Gets the
|
|
53
|
+
Gets the collected data from current session, optionally for a specific route.
|
|
54
54
|
|
|
55
55
|
```typescript
|
|
56
56
|
// Option 1: Using current session (set with setCurrentSession)
|
|
57
57
|
agent.setCurrentSession(session);
|
|
58
|
-
const
|
|
58
|
+
const data = agent.getData(); // Uses current session
|
|
59
59
|
|
|
60
60
|
// Option 2: Get data for specific route
|
|
61
|
-
const routeData = agent.
|
|
61
|
+
const routeData = agent.getData("onboarding"); // Route-specific data
|
|
62
62
|
|
|
63
63
|
// Option 3: From response (with current session set)
|
|
64
64
|
const response = await agent.respond({ history });
|
|
65
|
-
const
|
|
65
|
+
const data = agent.getData(); // Uses current session
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
**Parameters:**
|
|
69
69
|
|
|
70
70
|
- `routeId` (optional): Route ID to get data for. If not provided, returns current route data.
|
|
71
71
|
|
|
72
|
-
**Returns:** The
|
|
72
|
+
**Returns:** The collected data from the current session
|
|
73
73
|
|
|
74
74
|
**Note:** Returns empty object if no current session is set.
|
|
75
75
|
|
|
76
76
|
##### `setCurrentSession(session): void`
|
|
77
77
|
|
|
78
|
-
Sets the current session for convenience methods. Once set, methods like `
|
|
78
|
+
Sets the current session for convenience methods. Once set, methods like `getData()` don't need the session parameter.
|
|
79
79
|
|
|
80
80
|
```typescript
|
|
81
81
|
// Set current session
|
|
82
82
|
agent.setCurrentSession(session);
|
|
83
83
|
|
|
84
84
|
// Now methods use the current session automatically
|
|
85
|
-
const
|
|
86
|
-
// Get
|
|
87
|
-
const routeData = agent.
|
|
85
|
+
const data = agent.getData();
|
|
86
|
+
// Get collected data for route
|
|
87
|
+
const routeData = agent.getData("onboarding");
|
|
88
88
|
```
|
|
89
89
|
|
|
90
90
|
**Parameters:**
|
|
91
91
|
|
|
92
|
-
- `session`: Session
|
|
92
|
+
- `session`: Session step to use as current session
|
|
93
93
|
|
|
94
|
-
##### `getCurrentSession():
|
|
94
|
+
##### `getCurrentSession(): SessionStep | undefined`
|
|
95
95
|
|
|
96
96
|
Gets the currently set session.
|
|
97
97
|
|
|
@@ -114,12 +114,12 @@ agent.clearCurrentSession();
|
|
|
114
114
|
|
|
115
115
|
##### `respond(input: RespondInput<TContext>): Promise<RespondOutput>`
|
|
116
116
|
|
|
117
|
-
Generates an AI response with session
|
|
117
|
+
Generates an AI response with session step management, data extraction, and intelligent routing.
|
|
118
118
|
|
|
119
119
|
```typescript
|
|
120
120
|
interface RespondInput<TContext> {
|
|
121
121
|
history: Event[];
|
|
122
|
-
session?:
|
|
122
|
+
session?: SessionStep; // NEW: Session step for conversation tracking
|
|
123
123
|
contextOverride?: Partial<TContext>;
|
|
124
124
|
signal?: AbortSignal;
|
|
125
125
|
}
|
|
@@ -127,15 +127,15 @@ interface RespondInput<TContext> {
|
|
|
127
127
|
interface RespondOutput {
|
|
128
128
|
/** The message to send to the user */
|
|
129
129
|
message: string;
|
|
130
|
-
/** Updated session
|
|
131
|
-
session?:
|
|
130
|
+
/** Updated session step (includes collected data, current route/step) */
|
|
131
|
+
session?: SessionStep;
|
|
132
132
|
/** Tool calls executed during response (for debugging) */
|
|
133
133
|
toolCalls?: Array<{
|
|
134
134
|
toolName: string;
|
|
135
135
|
arguments: Record<string, unknown>;
|
|
136
136
|
}>;
|
|
137
137
|
/**
|
|
138
|
-
* NEW: Indicates if the current route has reached
|
|
138
|
+
* NEW: Indicates if the current route has reached END_ROUTE
|
|
139
139
|
* When true, all required data has been collected and the route is complete.
|
|
140
140
|
* Your application should handle this appropriately (e.g., process collected data,
|
|
141
141
|
* show completion UI, start a new route, etc.)
|
|
@@ -146,18 +146,18 @@ interface RespondOutput {
|
|
|
146
146
|
|
|
147
147
|
**Enhanced Response Pipeline:**
|
|
148
148
|
|
|
149
|
-
1. **Tool Execution** - Execute tools if current
|
|
149
|
+
1. **Tool Execution** - Execute tools if current step has `tool`
|
|
150
150
|
2. **Always-On Routing** - Score all routes, respect user intent to change direction
|
|
151
|
-
3. **
|
|
152
|
-
4. **Response Generation** - Build schema with `
|
|
153
|
-
5. **Session Update** - Merge
|
|
151
|
+
3. **Step Traversal** - Use `skipIf` and `requires` to determine next step
|
|
152
|
+
4. **Response Generation** - Build schema with `collect` fields, extract data
|
|
153
|
+
5. **Session Update** - Merge collected data into session step
|
|
154
154
|
|
|
155
|
-
**Session
|
|
155
|
+
**Session Step Management:**
|
|
156
156
|
|
|
157
|
-
- Tracks current route,
|
|
157
|
+
- Tracks current route, step, and collected data across turns
|
|
158
158
|
- Enables "I changed my mind" scenarios with context-aware routing
|
|
159
|
-
- Automatically merges new
|
|
160
|
-
- **Per-route data preservation** -
|
|
159
|
+
- Automatically merges new collected data with existing session data
|
|
160
|
+
- **Per-route data preservation** - Collected data is organized by route ID, allowing users to switch routes without losing progress
|
|
161
161
|
|
|
162
162
|
**Example with Persistence Adapters:**
|
|
163
163
|
|
|
@@ -165,40 +165,40 @@ interface RespondOutput {
|
|
|
165
165
|
import { createSession } from "@falai/agent";
|
|
166
166
|
|
|
167
167
|
// Using built-in persistence adapters
|
|
168
|
-
const { sessionData,
|
|
169
|
-
await persistence.
|
|
168
|
+
const { sessionData, sessionStep } =
|
|
169
|
+
await persistence.createSessionWithStep<FlightData>({
|
|
170
170
|
userId: "user_123",
|
|
171
171
|
agentName: "Travel Agent",
|
|
172
172
|
});
|
|
173
173
|
|
|
174
174
|
// Option 1: Set current session for convenience
|
|
175
|
-
agent.setCurrentSession(
|
|
175
|
+
agent.setCurrentSession(sessionStep);
|
|
176
176
|
|
|
177
177
|
const response = await agent.respond({
|
|
178
178
|
history,
|
|
179
|
-
// session:
|
|
179
|
+
// session: sessionStep, // No longer required!
|
|
180
180
|
});
|
|
181
181
|
|
|
182
182
|
// Use convenience methods without passing session
|
|
183
|
-
const
|
|
183
|
+
const data = agent.getData();
|
|
184
184
|
|
|
185
185
|
// Option 2: Still pass session explicitly if preferred
|
|
186
186
|
const response2 = await agent.respond({
|
|
187
187
|
history,
|
|
188
|
-
session:
|
|
188
|
+
session: sessionStep,
|
|
189
189
|
});
|
|
190
190
|
```
|
|
191
191
|
|
|
192
192
|
**Example with Custom Database (Manual):**
|
|
193
193
|
|
|
194
194
|
```typescript
|
|
195
|
-
import { createSession,
|
|
195
|
+
import { createSession, SessionStep } from "@falai/agent";
|
|
196
196
|
|
|
197
197
|
// Load from your custom database
|
|
198
198
|
const dbSession = await yourDb.sessions.findOne({ id: sessionId });
|
|
199
199
|
|
|
200
|
-
// Restore or create session
|
|
201
|
-
let agentSession:
|
|
200
|
+
// Restore or create session step
|
|
201
|
+
let agentSession: SessionStep<YourDataType>;
|
|
202
202
|
|
|
203
203
|
if (dbSession && dbSession.currentRoute && dbSession.collectedData) {
|
|
204
204
|
// Restore existing session from database
|
|
@@ -209,14 +209,14 @@ if (dbSession && dbSession.currentRoute && dbSession.collectedData) {
|
|
|
209
209
|
dbSession.collectedData?.currentRouteTitle || dbSession.currentRoute,
|
|
210
210
|
enteredAt: new Date(),
|
|
211
211
|
},
|
|
212
|
-
|
|
212
|
+
currentStep: dbSession.currentStep
|
|
213
213
|
? {
|
|
214
|
-
id: dbSession.
|
|
215
|
-
description: dbSession.collectedData?.
|
|
214
|
+
id: dbSession.currentStep,
|
|
215
|
+
description: dbSession.collectedData?.currentStepDescription,
|
|
216
216
|
enteredAt: new Date(),
|
|
217
217
|
}
|
|
218
218
|
: undefined,
|
|
219
|
-
|
|
219
|
+
data: dbSession.collectedData?.data || {},
|
|
220
220
|
routeHistory: dbSession.collectedData?.routeHistory || [],
|
|
221
221
|
metadata: {
|
|
222
222
|
sessionId: dbSession.id,
|
|
@@ -241,12 +241,12 @@ const response = await agent.respond({
|
|
|
241
241
|
await yourDb.sessions.update({
|
|
242
242
|
id: dbSession.id,
|
|
243
243
|
currentRoute: response.session?.currentRoute?.id,
|
|
244
|
-
|
|
244
|
+
currentStep: response.session?.currentStep?.id,
|
|
245
245
|
collectedData: {
|
|
246
|
-
|
|
246
|
+
data: response.session?.data,
|
|
247
247
|
routeHistory: response.session?.routeHistory,
|
|
248
248
|
currentRouteTitle: response.session?.currentRoute?.title,
|
|
249
|
-
|
|
249
|
+
currentStepDescription: response.session?.currentStep?.description,
|
|
250
250
|
metadata: response.session?.metadata,
|
|
251
251
|
},
|
|
252
252
|
lastMessageAt: new Date(),
|
|
@@ -258,13 +258,13 @@ await yourDb.messages.create({
|
|
|
258
258
|
role: "agent",
|
|
259
259
|
content: response.message,
|
|
260
260
|
route: response.session?.currentRoute?.id,
|
|
261
|
-
|
|
261
|
+
step: response.session?.currentStep?.id,
|
|
262
262
|
});
|
|
263
263
|
```
|
|
264
264
|
|
|
265
265
|
**Handling Route Completion:**
|
|
266
266
|
|
|
267
|
-
When a route reaches its
|
|
267
|
+
When a route reaches its END_ROUTE transition (all required data collected), the response includes `isRouteComplete: true`:
|
|
268
268
|
|
|
269
269
|
```typescript
|
|
270
270
|
const response = await agent.respond({
|
|
@@ -277,7 +277,7 @@ if (response.isRouteComplete) {
|
|
|
277
277
|
console.log("✅ Route completed!");
|
|
278
278
|
|
|
279
279
|
// Get all the collected data
|
|
280
|
-
const collectedData = agent.
|
|
280
|
+
const collectedData = agent.getData(response.session!);
|
|
281
281
|
console.log("Collected data:", collectedData);
|
|
282
282
|
|
|
283
283
|
// Handle completion in your application:
|
|
@@ -303,31 +303,31 @@ if (response.isRouteComplete) {
|
|
|
303
303
|
const onboardingRoute = agent.createRoute<OnboardingData>({
|
|
304
304
|
id: "onboarding",
|
|
305
305
|
title: "User Onboarding",
|
|
306
|
-
|
|
306
|
+
schema: ONBOARDING_SCHEMA,
|
|
307
307
|
initialData: existingUserData, // Pre-fill with existing data
|
|
308
308
|
});
|
|
309
309
|
|
|
310
|
-
// Build
|
|
311
|
-
const welcome = onboardingRoute.
|
|
310
|
+
// Build steps with skipIf conditions
|
|
311
|
+
const welcome = onboardingRoute.initialStep.nextStep({
|
|
312
312
|
id: "ask_name",
|
|
313
|
-
|
|
314
|
-
|
|
313
|
+
instructions: "What's your name?",
|
|
314
|
+
collect: ["name"],
|
|
315
315
|
skipIf: (data) => !!data.name, // Skip if name already collected
|
|
316
316
|
});
|
|
317
317
|
|
|
318
|
-
const askEmail = welcome.
|
|
318
|
+
const askEmail = welcome.nextStep({
|
|
319
319
|
id: "ask_email",
|
|
320
|
-
|
|
321
|
-
|
|
320
|
+
instructions: "What's your email?",
|
|
321
|
+
collect: ["email"],
|
|
322
322
|
skipIf: (data) => !!data.email, // Skip if email already collected
|
|
323
323
|
});
|
|
324
324
|
|
|
325
|
-
const complete = askEmail.
|
|
325
|
+
const complete = askEmail.nextStep({
|
|
326
326
|
id: "complete",
|
|
327
|
-
|
|
327
|
+
instructions: "All done! Thank you.",
|
|
328
328
|
});
|
|
329
329
|
|
|
330
|
-
complete.
|
|
330
|
+
complete.nextStep({ step: END_ROUTE });
|
|
331
331
|
|
|
332
332
|
// Option 1: Set current session for convenience
|
|
333
333
|
agent.setCurrentSession(session);
|
|
@@ -336,26 +336,26 @@ const response = await agent.respond({ history });
|
|
|
336
336
|
|
|
337
337
|
if (response.isRouteComplete) {
|
|
338
338
|
// If all data was pre-filled, the route completes immediately!
|
|
339
|
-
// The routing engine recursively skips all
|
|
340
|
-
const data = agent.
|
|
339
|
+
// The routing engine recursively skips all steps and reaches END_ROUTE
|
|
340
|
+
const data = agent.getData(); // No need to pass session!
|
|
341
341
|
await saveUserProfile(data);
|
|
342
342
|
return "Profile updated successfully!";
|
|
343
343
|
}
|
|
344
344
|
|
|
345
345
|
// Get route-specific data if needed
|
|
346
|
-
const onboardingData = agent.
|
|
347
|
-
const bookingData = agent.
|
|
346
|
+
const onboardingData = agent.getDataForRoute("onboarding");
|
|
347
|
+
const bookingData = agent.getDataForRoute("booking");
|
|
348
348
|
|
|
349
349
|
return response.message;
|
|
350
350
|
```
|
|
351
351
|
|
|
352
352
|
**Important Notes:**
|
|
353
353
|
|
|
354
|
-
- `isRouteComplete` is `true` when the route reaches an `
|
|
354
|
+
- `isRouteComplete` is `true` when the route reaches an `END_ROUTE` transition
|
|
355
355
|
- The `message` will be empty (`""`) when `isRouteComplete` is `true`
|
|
356
356
|
- You should check `isRouteComplete` and handle completion appropriately
|
|
357
|
-
- If all
|
|
358
|
-
- Use `agent.
|
|
357
|
+
- If all steps are skipped (due to `skipIf` conditions), the route can complete immediately on entry
|
|
358
|
+
- Use `agent.getData(session)` to retrieve all collected data
|
|
359
359
|
|
|
360
360
|
See also: [Custom Database Integration Example](../examples/custom-database-persistence.ts)
|
|
361
361
|
|
|
@@ -371,15 +371,15 @@ interface StreamChunk {
|
|
|
371
371
|
accumulated: string;
|
|
372
372
|
/** Whether this is the final chunk */
|
|
373
373
|
done: boolean;
|
|
374
|
-
/** Updated session
|
|
375
|
-
session?:
|
|
374
|
+
/** Updated session step (includes collected data, current route/step) */
|
|
375
|
+
session?: SessionStep;
|
|
376
376
|
/** Tool calls requested by the agent (only in final chunk) */
|
|
377
377
|
toolCalls?: Array<{
|
|
378
378
|
toolName: string;
|
|
379
379
|
arguments: Record<string, unknown>;
|
|
380
380
|
}>;
|
|
381
381
|
/**
|
|
382
|
-
* Indicates if the current route has reached
|
|
382
|
+
* Indicates if the current route has reached END_ROUTE (only in final chunk)
|
|
383
383
|
* When true, all required data has been collected and the route is complete.
|
|
384
384
|
*/
|
|
385
385
|
isRouteComplete?: boolean;
|
|
@@ -389,7 +389,7 @@ interface StreamChunk {
|
|
|
389
389
|
**Key Features:**
|
|
390
390
|
|
|
391
391
|
- 🌊 Real-time streaming for better perceived performance
|
|
392
|
-
- 📊 Access to route,
|
|
392
|
+
- 📊 Access to route, step, and tool information in final chunk
|
|
393
393
|
- 🛑 Cancellable with AbortSignal
|
|
394
394
|
- ✅ Supported by all providers (Anthropic, OpenAI, Gemini, OpenRouter)
|
|
395
395
|
|
|
@@ -409,11 +409,11 @@ for await (const chunk of agent.respondStream({ history, session })) {
|
|
|
409
409
|
// Check if route is complete
|
|
410
410
|
if (chunk.isRouteComplete) {
|
|
411
411
|
console.log("🎉 Route completed!");
|
|
412
|
-
const data = agent.
|
|
412
|
+
const data = agent.getData(chunk.session!);
|
|
413
413
|
await handleCompletion(data);
|
|
414
414
|
}
|
|
415
415
|
|
|
416
|
-
// Access session
|
|
416
|
+
// Access session step
|
|
417
417
|
if (chunk.session?.currentRoute) {
|
|
418
418
|
console.log("Route:", chunk.session.currentRoute.title);
|
|
419
419
|
}
|
|
@@ -493,14 +493,14 @@ Dynamic domain registry access.
|
|
|
493
493
|
|
|
494
494
|
### `Route`
|
|
495
495
|
|
|
496
|
-
Represents a conversation flow with
|
|
496
|
+
Represents a conversation flow with steps and transitions.
|
|
497
497
|
|
|
498
498
|
#### Constructor
|
|
499
499
|
|
|
500
500
|
```typescript
|
|
501
501
|
new Route(options: RouteOptions)
|
|
502
502
|
|
|
503
|
-
interface RouteOptions<
|
|
503
|
+
interface RouteOptions<TData = unknown> {
|
|
504
504
|
id?: string; // Optional custom ID (deterministic ID generated from title if not provided)
|
|
505
505
|
title: string; // Route title
|
|
506
506
|
description?: string; // Route description
|
|
@@ -511,36 +511,36 @@ interface RouteOptions<TExtracted = unknown> {
|
|
|
511
511
|
prohibitions?: string[]; // Absolute prohibitions the agent MUST NEVER do in this route
|
|
512
512
|
|
|
513
513
|
// NEW: Schema-first data extraction
|
|
514
|
-
|
|
514
|
+
schema?: {
|
|
515
515
|
type: "object";
|
|
516
516
|
properties: Record<string, any>;
|
|
517
517
|
required?: string[];
|
|
518
518
|
additionalProperties?: boolean;
|
|
519
519
|
};
|
|
520
520
|
|
|
521
|
-
// NEW: Pre-populate
|
|
522
|
-
initialData?: Partial<
|
|
521
|
+
// NEW: Pre-populate collected data when entering route
|
|
522
|
+
initialData?: Partial<TData>;
|
|
523
523
|
|
|
524
|
-
// NEW: Configure the initial
|
|
525
|
-
|
|
526
|
-
id?: string; // Custom ID for the initial
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
skipIf?: (
|
|
530
|
-
|
|
524
|
+
// NEW: Configure the initial step
|
|
525
|
+
initialStep?: {
|
|
526
|
+
id?: string; // Custom ID for the initial step
|
|
527
|
+
instructions?: string; // Description for the initial step
|
|
528
|
+
collect?: string[]; // Fields to collect in the initial step
|
|
529
|
+
skipIf?: (data: Partial<TData>) => boolean; // Skip condition
|
|
530
|
+
requires?: string[]; // Required data prerequisites
|
|
531
531
|
};
|
|
532
532
|
|
|
533
533
|
// NEW: Sequential steps for simple linear flows
|
|
534
|
-
steps?: TransitionSpec<unknown,
|
|
534
|
+
steps?: TransitionSpec<unknown, TData>[];
|
|
535
535
|
}
|
|
536
536
|
```
|
|
537
537
|
|
|
538
538
|
**Note on IDs:** Route IDs are deterministic by default, generated from the title using a hash function. This ensures consistency across server restarts. You can provide a custom ID if you need specific control over the identifier.
|
|
539
539
|
|
|
540
|
-
**Initial
|
|
540
|
+
**Initial Step Configuration:** You can configure the initial step in two ways:
|
|
541
541
|
|
|
542
|
-
1. Using `
|
|
543
|
-
2. Using `route.
|
|
542
|
+
1. Using `initialStep` option when creating the route
|
|
543
|
+
2. Using `route.initialStep.configure()` method after route creation
|
|
544
544
|
|
|
545
545
|
#### Methods
|
|
546
546
|
|
|
@@ -568,7 +568,7 @@ Returns the prohibitions that must never be done in this route.
|
|
|
568
568
|
|
|
569
569
|
Returns a reference to this route.
|
|
570
570
|
|
|
571
|
-
**Note:** Routes no longer have a `
|
|
571
|
+
**Note:** Routes no longer have a `getData()` method. Use `agent.getData()` or `agent.getDataForRoute(routeId)` instead.
|
|
572
572
|
|
|
573
573
|
##### `describe(): string`
|
|
574
574
|
|
|
@@ -592,55 +592,53 @@ Route description (readonly).
|
|
|
592
592
|
|
|
593
593
|
Conditions that trigger this route (readonly).
|
|
594
594
|
|
|
595
|
-
##### `
|
|
595
|
+
##### `initialStep: Step`
|
|
596
596
|
|
|
597
|
-
Starting
|
|
597
|
+
Starting step of the route (readonly).
|
|
598
598
|
|
|
599
599
|
---
|
|
600
600
|
|
|
601
|
-
### `
|
|
601
|
+
### `Step`
|
|
602
602
|
|
|
603
|
-
Represents a
|
|
603
|
+
Represents a step within a conversation route.
|
|
604
604
|
|
|
605
605
|
#### Methods
|
|
606
606
|
|
|
607
|
-
##### `
|
|
607
|
+
##### `nextStep(spec: TransitionSpec): TransitionResult`
|
|
608
608
|
|
|
609
|
-
Creates a transition from this
|
|
609
|
+
Creates a transition from this step and returns a chainable result.
|
|
610
610
|
|
|
611
611
|
```typescript
|
|
612
|
-
interface TransitionSpec<
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
612
|
+
interface TransitionSpec<TData = unknown> {
|
|
613
|
+
instructions?: string; // Transition to a chat interaction
|
|
614
|
+
tool?: ToolRef; // Transition to execute a tool
|
|
615
|
+
step?: StepRef | symbol; // Transition to specific step or END_ROUTE
|
|
616
616
|
|
|
617
|
-
// NEW: Data extraction fields for this
|
|
618
|
-
|
|
617
|
+
// NEW: Data extraction fields for this step
|
|
618
|
+
collect?: string[];
|
|
619
619
|
|
|
620
|
-
// NEW: Code-based condition to skip this
|
|
621
|
-
skipIf?: (
|
|
620
|
+
// NEW: Code-based condition to skip this step
|
|
621
|
+
skipIf?: (data: Partial<TData>) => boolean;
|
|
622
622
|
|
|
623
|
-
// NEW: Prerequisites that must be met to enter this
|
|
624
|
-
|
|
623
|
+
// NEW: Prerequisites that must be met to enter this step
|
|
624
|
+
requires?: string[];
|
|
625
625
|
|
|
626
626
|
// Optional: AI-evaluated text condition for this transition
|
|
627
627
|
condition?: string;
|
|
628
628
|
}
|
|
629
629
|
|
|
630
|
-
interface TransitionResult<
|
|
631
|
-
id: string; //
|
|
630
|
+
interface TransitionResult<TData = unknown> {
|
|
631
|
+
id: string; // Step identifier
|
|
632
632
|
routeId: string; // Route identifier
|
|
633
|
-
|
|
634
|
-
spec: TransitionSpec<TExtracted>
|
|
635
|
-
) => TransitionResult<TExtracted>;
|
|
633
|
+
nextStep: (spec: TransitionSpec<TData>) => TransitionResult<TData>;
|
|
636
634
|
}
|
|
637
635
|
```
|
|
638
636
|
|
|
639
637
|
**Parameters:**
|
|
640
638
|
|
|
641
|
-
- `spec`: The transition specification (see `TransitionSpec` above). Can include an optional `condition` property for AI-evaluated
|
|
639
|
+
- `spec`: The transition specification (see `TransitionSpec` above). Can include an optional `condition` property for AI-evaluated step selection guidance.
|
|
642
640
|
|
|
643
|
-
**Returns:** A `TransitionResult` that includes the target
|
|
641
|
+
**Returns:** A `TransitionResult` that includes the target step's reference (`id`, `routeId`) and a `nextStep` method for chaining additional transitions.
|
|
644
642
|
|
|
645
643
|
**Example:**
|
|
646
644
|
|
|
@@ -655,7 +653,7 @@ interface FlightData {
|
|
|
655
653
|
// Create a data-driven route
|
|
656
654
|
const flightRoute = agent.createRoute<FlightData>({
|
|
657
655
|
title: "Book Flight",
|
|
658
|
-
|
|
656
|
+
schema: {
|
|
659
657
|
type: "object",
|
|
660
658
|
properties: {
|
|
661
659
|
destination: { type: "string" },
|
|
@@ -667,79 +665,79 @@ const flightRoute = agent.createRoute<FlightData>({
|
|
|
667
665
|
});
|
|
668
666
|
|
|
669
667
|
// Approach 1: Step-by-step with data extraction and text conditions
|
|
670
|
-
const askDestination = flightRoute.
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
skipIf: (
|
|
668
|
+
const askDestination = flightRoute.initialStep.nextStep({
|
|
669
|
+
instructions: "Ask where they want to fly",
|
|
670
|
+
collect: ["destination"],
|
|
671
|
+
skipIf: (data) => !!data.destination, // Skip if already have destination
|
|
674
672
|
condition: "Customer hasn't specified destination yet", // AI-evaluated condition
|
|
675
673
|
});
|
|
676
674
|
|
|
677
|
-
const askDates = askDestination.
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
skipIf: (
|
|
681
|
-
|
|
675
|
+
const askDates = askDestination.nextStep({
|
|
676
|
+
instructions: "Ask about travel dates",
|
|
677
|
+
collect: ["departureDate"],
|
|
678
|
+
skipIf: (data) => !!data.departureDate,
|
|
679
|
+
requires: ["destination"], // Must have destination first
|
|
682
680
|
condition: "Destination confirmed, need travel dates",
|
|
683
681
|
});
|
|
684
682
|
|
|
685
|
-
const askPassengers = askDates.
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
skipIf: (
|
|
683
|
+
const askPassengers = askDates.nextStep({
|
|
684
|
+
instructions: "How many passengers?",
|
|
685
|
+
collect: ["passengers"],
|
|
686
|
+
skipIf: (data) => !!data.passengers,
|
|
689
687
|
});
|
|
690
688
|
|
|
691
|
-
// Access
|
|
692
|
-
console.log(askDestination.id); //
|
|
689
|
+
// Access step properties
|
|
690
|
+
console.log(askDestination.id); // Step ID
|
|
693
691
|
console.log(askDestination.routeId); // Route ID
|
|
694
692
|
|
|
695
693
|
// Approach 2: Fluent chaining for linear flows
|
|
696
|
-
flightRoute.
|
|
697
|
-
.
|
|
698
|
-
|
|
699
|
-
|
|
694
|
+
flightRoute.initialStep
|
|
695
|
+
.nextStep({
|
|
696
|
+
instructions: "Extract travel details",
|
|
697
|
+
collect: ["destination", "departureDate", "passengers"],
|
|
700
698
|
})
|
|
701
|
-
.
|
|
702
|
-
|
|
699
|
+
.nextStep({
|
|
700
|
+
instructions: "Present available flights",
|
|
703
701
|
})
|
|
704
|
-
.
|
|
702
|
+
.nextStep({ step: END_ROUTE });
|
|
705
703
|
|
|
706
|
-
// Use with session
|
|
704
|
+
// Use with session step
|
|
707
705
|
let session = createSession<FlightData>();
|
|
708
706
|
const response = await agent.respond({ history, session });
|
|
709
|
-
console.log(response.session?.
|
|
707
|
+
console.log(response.session?.data); // { destination: "Paris", ... }
|
|
710
708
|
```
|
|
711
709
|
|
|
712
710
|
##### `addGuideline(guideline: Guideline): void`
|
|
713
711
|
|
|
714
|
-
Adds a guideline specific to this
|
|
712
|
+
Adds a guideline specific to this step.
|
|
715
713
|
|
|
716
714
|
##### `configure(config): this`
|
|
717
715
|
|
|
718
|
-
Configure the
|
|
716
|
+
Configure the step properties after creation. Useful for overriding initial step configuration. Returns `this` for chaining.
|
|
719
717
|
|
|
720
718
|
```typescript
|
|
721
|
-
// Configure initial
|
|
722
|
-
route.
|
|
719
|
+
// Configure initial step after route creation
|
|
720
|
+
route.initialStep.configure({
|
|
723
721
|
description: "Welcome! Let's get started",
|
|
724
|
-
|
|
725
|
-
skipIf: (
|
|
726
|
-
|
|
722
|
+
collectFields: ["name", "email"],
|
|
723
|
+
skipIf: (data) => !!data.name && !!data.email,
|
|
724
|
+
requires: [],
|
|
727
725
|
});
|
|
728
726
|
|
|
729
|
-
// Or configure any
|
|
730
|
-
const askName = route.
|
|
727
|
+
// Or configure any step
|
|
728
|
+
const askName = route.initialStep.nextStep({ instructions: "Ask for name" });
|
|
731
729
|
askName.configure({
|
|
732
|
-
|
|
730
|
+
collectFields: ["firstName", "lastName"],
|
|
733
731
|
});
|
|
734
732
|
```
|
|
735
733
|
|
|
736
734
|
**Parameters:**
|
|
737
735
|
|
|
738
736
|
- `config`: Configuration object with optional properties:
|
|
739
|
-
- `description?: string` -
|
|
740
|
-
- `
|
|
741
|
-
- `skipIf?: (
|
|
742
|
-
- `
|
|
737
|
+
- `description?: string` - Step description
|
|
738
|
+
- `collectFields?: string[]` - Fields to collect in this step
|
|
739
|
+
- `skipIf?: (data: Partial<TData>) => boolean` - Skip condition function
|
|
740
|
+
- `requires?: string[]` - Required data prerequisites
|
|
743
741
|
|
|
744
742
|
**Returns:** `this` for method chaining
|
|
745
743
|
|
|
@@ -747,15 +745,15 @@ askName.configure({
|
|
|
747
745
|
|
|
748
746
|
##### `id: string`
|
|
749
747
|
|
|
750
|
-
Unique
|
|
748
|
+
Unique step identifier (readonly).
|
|
751
749
|
|
|
752
750
|
##### `routeId: string`
|
|
753
751
|
|
|
754
|
-
ID of the route this
|
|
752
|
+
ID of the route this step belongs to (readonly).
|
|
755
753
|
|
|
756
754
|
##### `description: string`
|
|
757
755
|
|
|
758
|
-
|
|
756
|
+
Step description (readonly).
|
|
759
757
|
|
|
760
758
|
---
|
|
761
759
|
|
|
@@ -1461,7 +1459,7 @@ interface SessionData {
|
|
|
1461
1459
|
agentName?: string;
|
|
1462
1460
|
status: SessionStatus; // "active" | "completed" | "abandoned"
|
|
1463
1461
|
currentRoute?: string;
|
|
1464
|
-
|
|
1462
|
+
currentStep?: string;
|
|
1465
1463
|
collectedData?: Record<string, unknown>;
|
|
1466
1464
|
messageCount: number;
|
|
1467
1465
|
lastMessageAt?: Date;
|
|
@@ -1481,7 +1479,7 @@ interface MessageData {
|
|
|
1481
1479
|
role: MessageRole; // "user" | "agent" | "system"
|
|
1482
1480
|
content: string;
|
|
1483
1481
|
route?: string;
|
|
1484
|
-
|
|
1482
|
+
step?: string;
|
|
1485
1483
|
toolCalls?: Array<{
|
|
1486
1484
|
toolName: string;
|
|
1487
1485
|
arguments: Record<string, unknown>;
|
|
@@ -1747,12 +1745,12 @@ interface ToolResult<TReturn> {
|
|
|
1747
1745
|
|
|
1748
1746
|
## Types
|
|
1749
1747
|
|
|
1750
|
-
### `
|
|
1748
|
+
### `SessionStep<TData>`
|
|
1751
1749
|
|
|
1752
|
-
Tracks the current position in the conversation flow and data
|
|
1750
|
+
Tracks the current position in the conversation flow and data collected during route progression.
|
|
1753
1751
|
|
|
1754
1752
|
```typescript
|
|
1755
|
-
interface
|
|
1753
|
+
interface SessionStep<TData = Record<string, unknown>> {
|
|
1756
1754
|
/** Unique session identifier (useful for persistence) */
|
|
1757
1755
|
id?: string;
|
|
1758
1756
|
|
|
@@ -1763,25 +1761,25 @@ interface SessionState<TExtracted = Record<string, unknown>> {
|
|
|
1763
1761
|
enteredAt: Date;
|
|
1764
1762
|
};
|
|
1765
1763
|
|
|
1766
|
-
/** Current
|
|
1767
|
-
|
|
1764
|
+
/** Current step within the route */
|
|
1765
|
+
currentStep?: {
|
|
1768
1766
|
id: string;
|
|
1769
1767
|
description?: string;
|
|
1770
1768
|
enteredAt: Date;
|
|
1771
1769
|
};
|
|
1772
1770
|
|
|
1773
1771
|
/**
|
|
1774
|
-
* Data
|
|
1775
|
-
* Convenience reference to
|
|
1772
|
+
* Data collected during the current route
|
|
1773
|
+
* Convenience reference to dataByRoute[currentRoute.id]
|
|
1776
1774
|
*/
|
|
1777
|
-
|
|
1775
|
+
data: Partial<TData>;
|
|
1778
1776
|
|
|
1779
1777
|
/**
|
|
1780
|
-
*
|
|
1778
|
+
* Collected data organized by route ID
|
|
1781
1779
|
* Preserves data when switching between routes
|
|
1782
|
-
* Format: { "routeId": { ...
|
|
1780
|
+
* Format: { "routeId": { ...dataData } }
|
|
1783
1781
|
*/
|
|
1784
|
-
|
|
1782
|
+
dataByRoute: Record<string, Partial<unknown>>;
|
|
1785
1783
|
|
|
1786
1784
|
/** History of routes visited in this session */
|
|
1787
1785
|
routeHistory: Array<{
|
|
@@ -1803,9 +1801,9 @@ interface SessionState<TExtracted = Record<string, unknown>> {
|
|
|
1803
1801
|
**Key Features:**
|
|
1804
1802
|
|
|
1805
1803
|
- **`id`** - Optional session identifier that persists across database operations
|
|
1806
|
-
- **`
|
|
1807
|
-
- **`
|
|
1808
|
-
- **`currentRoute`** / **`
|
|
1804
|
+
- **`data`** - Type-safe data collected via `schema` for the **current route**
|
|
1805
|
+
- **`dataByRoute`** - **NEW:** Per-route data map that preserves collected data when switching routes
|
|
1806
|
+
- **`currentRoute`** / **`currentStep`** - Track conversation position
|
|
1809
1807
|
- **`routeHistory`** - Full audit trail of route transitions
|
|
1810
1808
|
- **`metadata`** - Custom data (timestamps, user info, etc.)
|
|
1811
1809
|
|
|
@@ -1813,15 +1811,15 @@ interface SessionState<TExtracted = Record<string, unknown>> {
|
|
|
1813
1811
|
|
|
1814
1812
|
When users switch routes (e.g., "Actually, I want to book a hotel instead"), the framework automatically:
|
|
1815
1813
|
|
|
1816
|
-
- Saves current route's `
|
|
1817
|
-
- Loads the new route's data from `
|
|
1818
|
-
- Keeps `
|
|
1814
|
+
- Saves current route's `data` data to `dataByRoute[routeId]`
|
|
1815
|
+
- Loads the new route's data from `dataByRoute[newRouteId]` (if resuming)
|
|
1816
|
+
- Keeps `data` as a convenient reference to the current route's data
|
|
1819
1817
|
|
|
1820
1818
|
This allows users to:
|
|
1821
1819
|
|
|
1822
1820
|
- Switch routes without losing progress
|
|
1823
1821
|
- Resume incomplete routes where they left off
|
|
1824
|
-
- Access historical data from previous routes via `session.
|
|
1822
|
+
- Access historical data from previous routes via `session.dataByRoute["route_id"]`
|
|
1825
1823
|
|
|
1826
1824
|
**Usage:**
|
|
1827
1825
|
|
|
@@ -1837,17 +1835,17 @@ const session = createSession<FlightData>("session_abc123");
|
|
|
1837
1835
|
// Use in conversation
|
|
1838
1836
|
const response = await agent.respond({ history, session });
|
|
1839
1837
|
|
|
1840
|
-
// Access
|
|
1841
|
-
console.log(response.session?.
|
|
1838
|
+
// Access collected data
|
|
1839
|
+
console.log(response.session?.data.destination); // Type-safe!
|
|
1842
1840
|
```
|
|
1843
1841
|
|
|
1844
1842
|
---
|
|
1845
1843
|
|
|
1846
1844
|
### Session Helper Functions
|
|
1847
1845
|
|
|
1848
|
-
#### `createSession<
|
|
1846
|
+
#### `createSession<TData>(sessionId?, metadata?): SessionStep<TData>`
|
|
1849
1847
|
|
|
1850
|
-
Creates a new session
|
|
1848
|
+
Creates a new session step object.
|
|
1851
1849
|
|
|
1852
1850
|
**Parameters:**
|
|
1853
1851
|
|
|
@@ -1870,12 +1868,12 @@ const session = createSession<OnboardingData>("session_123", {
|
|
|
1870
1868
|
});
|
|
1871
1869
|
```
|
|
1872
1870
|
|
|
1873
|
-
#### `enterRoute<
|
|
1871
|
+
#### `enterRoute<TData>(session, routeId, routeTitle): SessionStep<TData>`
|
|
1874
1872
|
|
|
1875
1873
|
Updates session when entering a new route. Automatically:
|
|
1876
1874
|
|
|
1877
1875
|
- Exits previous route (if exists)
|
|
1878
|
-
- Resets
|
|
1876
|
+
- Resets collected data
|
|
1879
1877
|
- Adds route to history
|
|
1880
1878
|
- Updates timestamps
|
|
1881
1879
|
|
|
@@ -1888,52 +1886,52 @@ let session = createSession<FlightData>();
|
|
|
1888
1886
|
session = enterRoute(session, "book_flight", "Book a Flight");
|
|
1889
1887
|
|
|
1890
1888
|
console.log(session.currentRoute?.title); // "Book a Flight"
|
|
1891
|
-
console.log(session.
|
|
1889
|
+
console.log(session.data); // {} (reset for new route)
|
|
1892
1890
|
```
|
|
1893
1891
|
|
|
1894
|
-
#### `
|
|
1892
|
+
#### `enterStep<TData>(session, stepId, description?): SessionStep<TData>`
|
|
1895
1893
|
|
|
1896
|
-
Updates session when entering a new
|
|
1894
|
+
Updates session when entering a new step within a route.
|
|
1897
1895
|
|
|
1898
1896
|
**Example:**
|
|
1899
1897
|
|
|
1900
1898
|
```typescript
|
|
1901
|
-
session =
|
|
1899
|
+
session = enterStep(session, "ask_destination", "Ask where to fly");
|
|
1902
1900
|
|
|
1903
|
-
console.log(session.
|
|
1904
|
-
console.log(session.
|
|
1901
|
+
console.log(session.currentStep?.id); // "ask_destination"
|
|
1902
|
+
console.log(session.currentStep?.description); // "Ask where to fly"
|
|
1905
1903
|
```
|
|
1906
1904
|
|
|
1907
|
-
#### `
|
|
1905
|
+
#### `mergeData<TData>(session, data): SessionStep<TData>`
|
|
1908
1906
|
|
|
1909
|
-
Merges new
|
|
1907
|
+
Merges new collected data into session. Updates timestamps automatically.
|
|
1910
1908
|
|
|
1911
1909
|
**Example:**
|
|
1912
1910
|
|
|
1913
1911
|
```typescript
|
|
1914
|
-
session =
|
|
1912
|
+
session = mergeData(session, {
|
|
1915
1913
|
destination: "Paris",
|
|
1916
1914
|
departureDate: "2025-06-15",
|
|
1917
1915
|
});
|
|
1918
1916
|
|
|
1919
|
-
console.log(session.
|
|
1917
|
+
console.log(session.data); // { destination: "Paris", departureDate: "2025-06-15" }
|
|
1920
1918
|
```
|
|
1921
1919
|
|
|
1922
|
-
#### `
|
|
1920
|
+
#### `sessionStepToData<TData>(session): object`
|
|
1923
1921
|
|
|
1924
|
-
Converts
|
|
1922
|
+
Converts SessionStep to persistence-friendly format for database storage.
|
|
1925
1923
|
|
|
1926
1924
|
**Returns:**
|
|
1927
1925
|
|
|
1928
1926
|
```typescript
|
|
1929
1927
|
{
|
|
1930
1928
|
currentRoute?: string; // Route ID
|
|
1931
|
-
|
|
1929
|
+
currentStep?: string; // Step ID
|
|
1932
1930
|
collectedData: { // All session data
|
|
1933
|
-
|
|
1931
|
+
data: Partial<TData>;
|
|
1934
1932
|
routeHistory: Array<...>;
|
|
1935
1933
|
currentRouteTitle?: string;
|
|
1936
|
-
|
|
1934
|
+
currentStepDescription?: string;
|
|
1937
1935
|
metadata?: object;
|
|
1938
1936
|
};
|
|
1939
1937
|
}
|
|
@@ -1946,22 +1944,22 @@ const session = createSession<FlightData>("session_123");
|
|
|
1946
1944
|
// ... conversation happens ...
|
|
1947
1945
|
|
|
1948
1946
|
// Save to database
|
|
1949
|
-
const dbData =
|
|
1947
|
+
const dbData = sessionStepToData(session);
|
|
1950
1948
|
await db.sessions.update(session.id!, {
|
|
1951
1949
|
currentRoute: dbData.currentRoute,
|
|
1952
|
-
|
|
1950
|
+
currentStep: dbData.currentStep,
|
|
1953
1951
|
collectedData: dbData.collectedData,
|
|
1954
1952
|
});
|
|
1955
1953
|
```
|
|
1956
1954
|
|
|
1957
|
-
#### `
|
|
1955
|
+
#### `sessionDataToStep<TData>(sessionId, data): SessionStep<TData>`
|
|
1958
1956
|
|
|
1959
|
-
Converts database data back to
|
|
1957
|
+
Converts database data back to SessionStep for resuming conversations.
|
|
1960
1958
|
|
|
1961
1959
|
**Parameters:**
|
|
1962
1960
|
|
|
1963
1961
|
- `sessionId`: The database session ID
|
|
1964
|
-
- `data`: Database session data (currentRoute,
|
|
1962
|
+
- `data`: Database session data (currentRoute, currentStep, collectedData)
|
|
1965
1963
|
|
|
1966
1964
|
**Example:**
|
|
1967
1965
|
|
|
@@ -1969,10 +1967,10 @@ Converts database data back to SessionState for resuming conversations.
|
|
|
1969
1967
|
// Load from database
|
|
1970
1968
|
const dbSession = await db.sessions.findById("session_123");
|
|
1971
1969
|
|
|
1972
|
-
// Restore session
|
|
1973
|
-
const session =
|
|
1970
|
+
// Restore session step
|
|
1971
|
+
const session = sessionDataToStep<FlightData>(dbSession.id, {
|
|
1974
1972
|
currentRoute: dbSession.currentRoute,
|
|
1975
|
-
|
|
1973
|
+
currentStep: dbSession.currentStep,
|
|
1976
1974
|
collectedData: dbSession.collectedData,
|
|
1977
1975
|
});
|
|
1978
1976
|
|
|
@@ -1988,17 +1986,17 @@ let session = createSession<FlightData>(dbSession.id);
|
|
|
1988
1986
|
|
|
1989
1987
|
// CONVERSATION: Extract data
|
|
1990
1988
|
const response1 = await agent.respond({ history: history1, session });
|
|
1991
|
-
session = response1.session!; // {
|
|
1989
|
+
session = response1.session!; // { data: { destination: "Paris" } }
|
|
1992
1990
|
|
|
1993
1991
|
// SAVE: To database
|
|
1994
|
-
const saveData =
|
|
1992
|
+
const saveData = sessionStepToData(session);
|
|
1995
1993
|
await db.sessions.update(session.id!, saveData);
|
|
1996
1994
|
|
|
1997
1995
|
// --- Later (new request) ---
|
|
1998
1996
|
|
|
1999
1997
|
// LOAD: From database
|
|
2000
1998
|
const loaded = await db.sessions.findById("session_123");
|
|
2001
|
-
const restored =
|
|
1999
|
+
const restored = sessionDataToStep<FlightData>(loaded.id, loaded);
|
|
2002
2000
|
|
|
2003
2001
|
// CONTINUE: Conversation
|
|
2004
2002
|
const response2 = await agent.respond({ history: history2, session: restored });
|
|
@@ -2016,8 +2014,8 @@ interface AgentStructuredResponse {
|
|
|
2016
2014
|
message: string;
|
|
2017
2015
|
/** Route chosen by the agent (route title or null if no route) */
|
|
2018
2016
|
route?: string | null;
|
|
2019
|
-
/** Current
|
|
2020
|
-
|
|
2017
|
+
/** Current step within the route (step description or null) */
|
|
2018
|
+
step?: string | null;
|
|
2021
2019
|
/** Tool calls the agent wants to execute */
|
|
2022
2020
|
toolCalls?: Array<{
|
|
2023
2021
|
toolName: string;
|
|
@@ -2047,15 +2045,15 @@ const routeId = generateRouteId("User Onboarding");
|
|
|
2047
2045
|
// Returns: "route_user_onboarding_{hash}"
|
|
2048
2046
|
```
|
|
2049
2047
|
|
|
2050
|
-
#### `
|
|
2048
|
+
#### `generateStepId(routeId: string, description?: string, index?: number): string`
|
|
2051
2049
|
|
|
2052
|
-
Generates a deterministic
|
|
2050
|
+
Generates a deterministic step ID.
|
|
2053
2051
|
|
|
2054
2052
|
```typescript
|
|
2055
|
-
import {
|
|
2053
|
+
import { generateStepId } from "@falai/agent";
|
|
2056
2054
|
|
|
2057
|
-
const
|
|
2058
|
-
// Returns: "
|
|
2055
|
+
const stepId = generateStepId("route_123", "Ask for name");
|
|
2056
|
+
// Returns: "step_ask_for_name_{hash}"
|
|
2059
2057
|
```
|
|
2060
2058
|
|
|
2061
2059
|
#### `generateToolId(name: string): string`
|
|
@@ -2082,27 +2080,27 @@ All IDs are generated deterministically using a hash function of their content (
|
|
|
2082
2080
|
|
|
2083
2081
|
## Constants
|
|
2084
2082
|
|
|
2085
|
-
### `
|
|
2083
|
+
### `END_ROUTE`
|
|
2086
2084
|
|
|
2087
2085
|
Symbol marking the end of a conversation route. Use this when building routes to mark where they should end.
|
|
2088
2086
|
|
|
2089
2087
|
```typescript
|
|
2090
|
-
import {
|
|
2088
|
+
import { END_ROUTE } from "@falai/agent";
|
|
2091
2089
|
|
|
2092
|
-
const thankYou = askEmail.
|
|
2093
|
-
|
|
2090
|
+
const thankYou = askEmail.nextStep({
|
|
2091
|
+
instructions: "Thank you for your information!",
|
|
2094
2092
|
});
|
|
2095
2093
|
|
|
2096
2094
|
// Mark the end of the route
|
|
2097
|
-
thankYou.
|
|
2095
|
+
thankYou.nextStep({ step: END_ROUTE });
|
|
2098
2096
|
```
|
|
2099
2097
|
|
|
2100
|
-
### `
|
|
2098
|
+
### `END_ROUTE_ID`
|
|
2101
2099
|
|
|
2102
|
-
String constant representing
|
|
2100
|
+
String constant representing END_ROUTE for runtime comparisons. When a route completes, `currentStep.id` is set to this value.
|
|
2103
2101
|
|
|
2104
2102
|
```typescript
|
|
2105
|
-
import {
|
|
2103
|
+
import { END_ROUTE_ID } from "@falai/agent";
|
|
2106
2104
|
|
|
2107
2105
|
const response = await agent.respond({ history, session });
|
|
2108
2106
|
|
|
@@ -2111,13 +2109,13 @@ if (response.isRouteComplete) {
|
|
|
2111
2109
|
console.log("Route completed!");
|
|
2112
2110
|
}
|
|
2113
2111
|
|
|
2114
|
-
// Method 2: Using
|
|
2115
|
-
if (response.session?.
|
|
2112
|
+
// Method 2: Using END_ROUTE_ID constant
|
|
2113
|
+
if (response.session?.currentStep?.id === END_ROUTE_ID) {
|
|
2116
2114
|
console.log("Route completed!");
|
|
2117
2115
|
}
|
|
2118
2116
|
```
|
|
2119
2117
|
|
|
2120
|
-
**Note:** Both methods are equivalent. Use `isRouteComplete` for simplicity, or `
|
|
2118
|
+
**Note:** Both methods are equivalent. Use `isRouteComplete` for simplicity, or `END_ROUTE_ID` for consistency with how you build routes.
|
|
2121
2119
|
|
|
2122
2120
|
---
|
|
2123
2121
|
|