@falai/agent 0.9.0-alpha-1 → 0.9.0-alpha-2
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 +34 -22
- package/dist/cjs/src/core/Agent.d.ts +52 -24
- package/dist/cjs/src/core/Agent.d.ts.map +1 -1
- package/dist/cjs/src/core/Agent.js +266 -39
- package/dist/cjs/src/core/Agent.js.map +1 -1
- package/dist/cjs/src/core/PersistenceManager.d.ts.map +1 -1
- package/dist/cjs/src/core/PersistenceManager.js +48 -25
- package/dist/cjs/src/core/PersistenceManager.js.map +1 -1
- package/dist/cjs/src/core/PromptComposer.d.ts +1 -1
- package/dist/cjs/src/core/PromptComposer.d.ts.map +1 -1
- package/dist/cjs/src/core/PromptComposer.js.map +1 -1
- package/dist/cjs/src/core/ResponseEngine.d.ts +13 -12
- package/dist/cjs/src/core/ResponseEngine.d.ts.map +1 -1
- package/dist/cjs/src/core/ResponseEngine.js +4 -4
- package/dist/cjs/src/core/ResponseEngine.js.map +1 -1
- package/dist/cjs/src/core/ResponsePipeline.d.ts +66 -38
- package/dist/cjs/src/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/cjs/src/core/ResponsePipeline.js +71 -3
- package/dist/cjs/src/core/ResponsePipeline.js.map +1 -1
- package/dist/cjs/src/core/Route.d.ts +24 -5
- package/dist/cjs/src/core/Route.d.ts.map +1 -1
- package/dist/cjs/src/core/Route.js +45 -1
- package/dist/cjs/src/core/Route.js.map +1 -1
- package/dist/cjs/src/core/RoutingEngine.d.ts +31 -6
- package/dist/cjs/src/core/RoutingEngine.d.ts.map +1 -1
- package/dist/cjs/src/core/RoutingEngine.js +113 -9
- package/dist/cjs/src/core/RoutingEngine.js.map +1 -1
- package/dist/cjs/src/core/SessionManager.d.ts +14 -4
- package/dist/cjs/src/core/SessionManager.d.ts.map +1 -1
- package/dist/cjs/src/core/SessionManager.js +25 -5
- package/dist/cjs/src/core/SessionManager.js.map +1 -1
- package/dist/cjs/src/core/Step.d.ts +10 -10
- package/dist/cjs/src/core/Step.d.ts.map +1 -1
- package/dist/cjs/src/core/Step.js.map +1 -1
- package/dist/cjs/src/core/ToolExecutor.d.ts +4 -2
- package/dist/cjs/src/core/ToolExecutor.d.ts.map +1 -1
- package/dist/cjs/src/core/ToolExecutor.js +13 -3
- package/dist/cjs/src/core/ToolExecutor.js.map +1 -1
- package/dist/cjs/src/types/agent.d.ts +41 -21
- package/dist/cjs/src/types/agent.d.ts.map +1 -1
- package/dist/cjs/src/types/agent.js.map +1 -1
- package/dist/cjs/src/types/index.d.ts +1 -1
- package/dist/cjs/src/types/index.d.ts.map +1 -1
- package/dist/cjs/src/types/index.js.map +1 -1
- package/dist/cjs/src/types/persistence.d.ts +0 -1
- package/dist/cjs/src/types/persistence.d.ts.map +1 -1
- package/dist/cjs/src/types/route.d.ts +22 -16
- package/dist/cjs/src/types/route.d.ts.map +1 -1
- package/dist/cjs/src/types/session.d.ts +6 -11
- package/dist/cjs/src/types/session.d.ts.map +1 -1
- package/dist/cjs/src/types/tool.d.ts +12 -6
- package/dist/cjs/src/types/tool.d.ts.map +1 -1
- package/dist/cjs/src/utils/session.d.ts +2 -2
- package/dist/cjs/src/utils/session.d.ts.map +1 -1
- package/dist/cjs/src/utils/session.js +6 -26
- package/dist/cjs/src/utils/session.js.map +1 -1
- package/dist/src/core/Agent.d.ts +52 -24
- package/dist/src/core/Agent.d.ts.map +1 -1
- package/dist/src/core/Agent.js +266 -39
- package/dist/src/core/Agent.js.map +1 -1
- package/dist/src/core/PersistenceManager.d.ts.map +1 -1
- package/dist/src/core/PersistenceManager.js +48 -25
- package/dist/src/core/PersistenceManager.js.map +1 -1
- package/dist/src/core/PromptComposer.d.ts +1 -1
- package/dist/src/core/PromptComposer.d.ts.map +1 -1
- package/dist/src/core/PromptComposer.js.map +1 -1
- package/dist/src/core/ResponseEngine.d.ts +13 -12
- package/dist/src/core/ResponseEngine.d.ts.map +1 -1
- package/dist/src/core/ResponseEngine.js +4 -4
- package/dist/src/core/ResponseEngine.js.map +1 -1
- package/dist/src/core/ResponsePipeline.d.ts +66 -38
- package/dist/src/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/src/core/ResponsePipeline.js +71 -3
- package/dist/src/core/ResponsePipeline.js.map +1 -1
- package/dist/src/core/Route.d.ts +24 -5
- package/dist/src/core/Route.d.ts.map +1 -1
- package/dist/src/core/Route.js +45 -1
- package/dist/src/core/Route.js.map +1 -1
- package/dist/src/core/RoutingEngine.d.ts +31 -6
- package/dist/src/core/RoutingEngine.d.ts.map +1 -1
- package/dist/src/core/RoutingEngine.js +113 -9
- package/dist/src/core/RoutingEngine.js.map +1 -1
- package/dist/src/core/SessionManager.d.ts +14 -4
- package/dist/src/core/SessionManager.d.ts.map +1 -1
- package/dist/src/core/SessionManager.js +25 -5
- package/dist/src/core/SessionManager.js.map +1 -1
- package/dist/src/core/Step.d.ts +10 -10
- package/dist/src/core/Step.d.ts.map +1 -1
- package/dist/src/core/Step.js.map +1 -1
- package/dist/src/core/ToolExecutor.d.ts +4 -2
- package/dist/src/core/ToolExecutor.d.ts.map +1 -1
- package/dist/src/core/ToolExecutor.js +13 -3
- package/dist/src/core/ToolExecutor.js.map +1 -1
- package/dist/src/types/agent.d.ts +41 -21
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/agent.js.map +1 -1
- package/dist/src/types/index.d.ts +1 -1
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/types/persistence.d.ts +0 -1
- package/dist/src/types/persistence.d.ts.map +1 -1
- package/dist/src/types/route.d.ts +22 -16
- package/dist/src/types/route.d.ts.map +1 -1
- package/dist/src/types/session.d.ts +6 -11
- package/dist/src/types/session.d.ts.map +1 -1
- package/dist/src/types/tool.d.ts +12 -6
- package/dist/src/types/tool.d.ts.map +1 -1
- package/dist/src/utils/session.d.ts +2 -2
- package/dist/src/utils/session.d.ts.map +1 -1
- package/dist/src/utils/session.js +6 -26
- package/dist/src/utils/session.js.map +1 -1
- package/docs/README.md +3 -3
- package/docs/api/README.md +35 -4
- package/docs/api/overview.md +166 -12
- package/docs/core/agent/README.md +162 -17
- package/docs/core/agent/context-management.md +39 -15
- package/docs/core/agent/session-management.md +49 -16
- package/docs/core/ai-integration/prompt-composition.md +38 -14
- package/docs/core/ai-integration/response-processing.md +28 -17
- package/docs/core/conversation-flows/data-collection.md +103 -25
- package/docs/core/conversation-flows/route-dsl.md +45 -22
- package/docs/core/conversation-flows/routes.md +74 -18
- package/docs/core/conversation-flows/step-transitions.md +3 -3
- package/docs/core/conversation-flows/steps.md +39 -15
- package/docs/core/routing/intelligent-routing.md +18 -9
- package/docs/core/tools/tool-definition.md +8 -8
- package/docs/core/tools/tool-execution.md +26 -26
- package/docs/core/tools/tool-scoping.md +5 -5
- package/docs/guides/getting-started/README.md +54 -32
- package/examples/advanced-patterns/knowledge-based-agent.ts +37 -28
- package/examples/advanced-patterns/persistent-onboarding.ts +70 -41
- package/examples/advanced-patterns/route-lifecycle-hooks.ts +28 -2
- package/examples/advanced-patterns/streaming-responses.ts +28 -23
- package/examples/ai-providers/anthropic-integration.ts +40 -33
- package/examples/ai-providers/openai-integration.ts +25 -25
- package/examples/conversation-flows/completion-transitions.ts +36 -32
- package/examples/core-concepts/basic-agent.ts +76 -78
- package/examples/core-concepts/schema-driven-extraction.ts +20 -16
- package/examples/core-concepts/session-management.ts +65 -53
- package/examples/integrations/database-integration.ts +49 -34
- package/examples/integrations/healthcare-integration.ts +96 -91
- package/examples/integrations/search-integration.ts +79 -82
- package/examples/integrations/server-session-management.ts +25 -17
- package/examples/persistence/database-persistence.ts +61 -45
- package/examples/persistence/memory-sessions.ts +52 -63
- package/examples/persistence/redis-persistence.ts +81 -95
- package/examples/tools/basic-tools.ts +73 -62
- package/examples/tools/data-enrichment-tools.ts +52 -44
- package/package.json +1 -1
- package/src/core/Agent.ts +418 -128
- package/src/core/PersistenceManager.ts +51 -27
- package/src/core/PromptComposer.ts +1 -1
- package/src/core/ResponseEngine.ts +21 -19
- package/src/core/ResponsePipeline.ts +174 -59
- package/src/core/Route.ts +58 -6
- package/src/core/RoutingEngine.ts +174 -27
- package/src/core/SessionManager.ts +32 -8
- package/src/core/Step.ts +20 -12
- package/src/core/ToolExecutor.ts +19 -5
- package/src/types/agent.ts +46 -23
- package/src/types/index.ts +2 -0
- package/src/types/persistence.ts +0 -1
- package/src/types/route.ts +22 -16
- package/src/types/session.ts +6 -12
- package/src/types/tool.ts +15 -9
- package/src/utils/session.ts +6 -31
|
@@ -8,28 +8,45 @@ The `@falai/agent` framework provides **automatic session management** through t
|
|
|
8
8
|
|
|
9
9
|
## 🎯 Automatic Session Management
|
|
10
10
|
|
|
11
|
-
The `SessionManager` automatically tracks
|
|
11
|
+
The `SessionManager` automatically tracks four key aspects of a conversation:
|
|
12
12
|
|
|
13
13
|
1. **Current Route** - Which conversation flow the user is in
|
|
14
14
|
2. **Current Step** - Where in the flow they currently are
|
|
15
|
-
3. **
|
|
15
|
+
3. **Agent-Level Data** - Centralized structured data collected across all routes
|
|
16
16
|
4. **Conversation History** - Complete message history within the session
|
|
17
17
|
|
|
18
18
|
```typescript
|
|
19
|
-
// Define your data extraction type
|
|
20
|
-
interface
|
|
19
|
+
// Define your agent-level data extraction type
|
|
20
|
+
interface TravelData {
|
|
21
21
|
destination: string;
|
|
22
22
|
departureDate: string;
|
|
23
23
|
passengers: number;
|
|
24
24
|
cabinClass: "economy" | "business" | "first";
|
|
25
|
+
hotelPreference?: string;
|
|
26
|
+
budgetRange?: string;
|
|
27
|
+
specialRequests?: string;
|
|
25
28
|
}
|
|
26
29
|
|
|
27
|
-
// Agent with automatic session management
|
|
28
|
-
const agent = new Agent({
|
|
30
|
+
// Agent with automatic session management and agent-level schema
|
|
31
|
+
const agent = new Agent<{}, TravelData>({
|
|
29
32
|
name: "Travel Agent",
|
|
30
33
|
provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
|
|
31
34
|
persistence: { adapter: new PrismaAdapter({ prisma }) },
|
|
32
|
-
sessionId: "user-123" // Automatically loads or creates session
|
|
35
|
+
sessionId: "user-123", // Automatically loads or creates session
|
|
36
|
+
|
|
37
|
+
// Agent-level schema for all data collection
|
|
38
|
+
schema: {
|
|
39
|
+
type: "object",
|
|
40
|
+
properties: {
|
|
41
|
+
destination: { type: "string" },
|
|
42
|
+
departureDate: { type: "string", format: "date" },
|
|
43
|
+
passengers: { type: "number", minimum: 1, maximum: 9 },
|
|
44
|
+
cabinClass: { type: "string", enum: ["economy", "business", "first"] },
|
|
45
|
+
hotelPreference: { type: "string" },
|
|
46
|
+
budgetRange: { type: "string" },
|
|
47
|
+
specialRequests: { type: "string" }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
33
50
|
});
|
|
34
51
|
|
|
35
52
|
// Simple conversation - session managed automatically
|
|
@@ -37,7 +54,7 @@ const response = await agent.respond("I want to book a flight to Paris");
|
|
|
37
54
|
|
|
38
55
|
// Access session information
|
|
39
56
|
console.log(agent.session.id); // "user-123"
|
|
40
|
-
console.log(agent.session.getData<
|
|
57
|
+
console.log(agent.session.getData<TravelData>()); // { destination: "Paris", ... }
|
|
41
58
|
console.log(agent.session.getHistory()); // Conversation history
|
|
42
59
|
```
|
|
43
60
|
|
|
@@ -64,12 +81,13 @@ const sessionManager = agent.session;
|
|
|
64
81
|
await sessionManager.getOrCreate("user-123");
|
|
65
82
|
await sessionManager.getOrCreate(); // Auto-generates ID
|
|
66
83
|
|
|
67
|
-
//
|
|
68
|
-
const data = sessionManager.getData<
|
|
84
|
+
// Agent-level data management
|
|
85
|
+
const data = sessionManager.getData<TravelData>();
|
|
69
86
|
await sessionManager.setData({
|
|
70
87
|
destination: "Paris",
|
|
71
88
|
departureDate: "2025-10-15",
|
|
72
89
|
passengers: 2,
|
|
90
|
+
cabinClass: "economy"
|
|
73
91
|
});
|
|
74
92
|
|
|
75
93
|
// History management
|
|
@@ -128,19 +146,25 @@ const agent = new Agent({
|
|
|
128
146
|
await saveUserData(newContext.userId, newContext);
|
|
129
147
|
},
|
|
130
148
|
|
|
131
|
-
//
|
|
149
|
+
// Agent-level data validation and enrichment
|
|
132
150
|
onDataUpdate: async (data, previousData) => {
|
|
133
151
|
// Normalize passenger count
|
|
134
152
|
if (data.passengers < 1) data.passengers = 1;
|
|
135
153
|
if (data.passengers > 9) data.passengers = 9;
|
|
136
154
|
|
|
137
|
-
// Enrich with computed fields
|
|
138
|
-
if (data.destination) {
|
|
155
|
+
// Enrich with computed fields using agent-level data
|
|
156
|
+
if (data.destination && !data.destinationCode) {
|
|
139
157
|
data.destinationCode = await lookupAirportCode(data.destination);
|
|
140
158
|
}
|
|
141
159
|
|
|
142
|
-
// Auto-
|
|
143
|
-
if (
|
|
160
|
+
// Auto-set budget range based on cabin class
|
|
161
|
+
if (data.cabinClass && !data.budgetRange) {
|
|
162
|
+
data.budgetRange = data.cabinClass === 'first' ? 'premium' :
|
|
163
|
+
data.cabinClass === 'business' ? 'high' : 'standard';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Auto-trigger actions when we have complete booking data
|
|
167
|
+
if (data.destination && data.departureDate && data.passengers) {
|
|
144
168
|
data.shouldSearchFlights = true;
|
|
145
169
|
}
|
|
146
170
|
|
|
@@ -6,22 +6,28 @@ The `@falai/agent` framework provides **automatic session management** through t
|
|
|
6
6
|
|
|
7
7
|
## Core Design Principles
|
|
8
8
|
|
|
9
|
-
### 1. 🎯 Schema-First Data Extraction
|
|
9
|
+
### 1. 🎯 Agent-Level Schema-First Data Extraction
|
|
10
10
|
|
|
11
|
-
Define what data to collect upfront using JSON Schema, then extract it reliably:
|
|
11
|
+
Define what data to collect upfront using JSON Schema at the agent level, then extract it reliably across all routes:
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
|
-
// Define your data contract
|
|
15
|
-
interface
|
|
14
|
+
// Define your agent-level data contract
|
|
15
|
+
interface TravelData {
|
|
16
16
|
destination: string;
|
|
17
17
|
departureDate: string;
|
|
18
18
|
passengers: number;
|
|
19
19
|
cabinClass: "economy" | "business" | "first";
|
|
20
|
+
hotelPreference?: string;
|
|
21
|
+
budgetRange?: string;
|
|
22
|
+
specialRequests?: string;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
// Agent with centralized schema
|
|
26
|
+
const agent = new Agent<{}, TravelData>({
|
|
27
|
+
name: "Travel Agent",
|
|
28
|
+
provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
|
|
29
|
+
|
|
30
|
+
// Agent-level schema defines all possible data fields
|
|
25
31
|
schema: {
|
|
26
32
|
type: "object",
|
|
27
33
|
properties: {
|
|
@@ -33,40 +39,67 @@ const route = agent.createRoute<FlightData>({
|
|
|
33
39
|
enum: ["economy", "business", "first"],
|
|
34
40
|
default: "economy",
|
|
35
41
|
},
|
|
42
|
+
hotelPreference: { type: "string" },
|
|
43
|
+
budgetRange: { type: "string" },
|
|
44
|
+
specialRequests: { type: "string" }
|
|
36
45
|
},
|
|
37
46
|
required: ["destination", "departureDate", "passengers"],
|
|
38
|
-
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Routes specify required fields instead of schemas
|
|
51
|
+
const flightRoute = agent.createRoute({
|
|
52
|
+
title: "Book Flight",
|
|
53
|
+
description: "Help user book a flight",
|
|
54
|
+
requiredFields: ["destination", "departureDate", "passengers", "cabinClass"],
|
|
55
|
+
optionalFields: ["specialRequests"]
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const hotelRoute = agent.createRoute({
|
|
59
|
+
title: "Book Hotel",
|
|
60
|
+
description: "Help user book accommodation",
|
|
61
|
+
requiredFields: ["destination", "departureDate", "hotelPreference"],
|
|
62
|
+
optionalFields: ["budgetRange", "specialRequests"]
|
|
39
63
|
});
|
|
40
64
|
```
|
|
41
65
|
|
|
42
|
-
**Why?**
|
|
66
|
+
**Why?** Agent-level schema-first extraction provides:
|
|
43
67
|
|
|
44
|
-
- **Type Safety** - Full TypeScript types from definition to extraction
|
|
68
|
+
- **Type Safety** - Full TypeScript types from definition to extraction across all routes
|
|
45
69
|
- **Reliability** - Provider-enforced schemas, not prompt-based parsing
|
|
46
|
-
- **Predictability** - Same data structure every time
|
|
70
|
+
- **Predictability** - Same data structure every time, shared across routes
|
|
47
71
|
- **Efficiency** - Extract multiple fields in one LLM call
|
|
72
|
+
- **Cross-Route Data Sharing** - Data collected by any route is available to all routes
|
|
73
|
+
- **Route Completion** - Routes complete when their required fields are satisfied
|
|
48
74
|
|
|
49
75
|
### 2. 🤖 Automatic Session Management
|
|
50
76
|
|
|
51
77
|
Sessions are automatically managed through the `SessionManager` class integrated into every `Agent`:
|
|
52
78
|
|
|
53
79
|
```typescript
|
|
54
|
-
// Server-side: Agent with automatic session management
|
|
55
|
-
const agent = new Agent({
|
|
80
|
+
// Server-side: Agent with automatic session management and agent-level data
|
|
81
|
+
const agent = new Agent<{}, TravelData>({
|
|
56
82
|
name: "Travel Agent",
|
|
57
83
|
provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
|
|
58
84
|
persistence: { adapter: new PrismaAdapter({ prisma }) },
|
|
59
|
-
sessionId: "user-123" // Automatically loads or creates this session
|
|
85
|
+
sessionId: "user-123", // Automatically loads or creates this session
|
|
86
|
+
|
|
87
|
+
// Agent-level schema
|
|
88
|
+
schema: { /* comprehensive travel data schema */ }
|
|
60
89
|
});
|
|
61
90
|
|
|
62
91
|
// Simple conversation - no manual session management
|
|
63
92
|
const response1 = await agent.respond("I want to book a flight to Paris");
|
|
64
93
|
console.log(agent.session.id); // Session ID
|
|
65
|
-
console.log(agent.session.getData()); //
|
|
94
|
+
console.log(agent.session.getData<TravelData>()); // Agent-level collected data
|
|
66
95
|
|
|
67
96
|
// Continue conversation - session automatically maintained
|
|
68
97
|
const response2 = await agent.respond("Make that Tokyo instead");
|
|
69
|
-
// Session automatically updated with new data
|
|
98
|
+
// Session automatically updated with new data in agent-level structure
|
|
99
|
+
|
|
100
|
+
// Switch to hotel booking - data is shared
|
|
101
|
+
const response3 = await agent.respond("Also book me a hotel in Tokyo");
|
|
102
|
+
// Hotel route can access destination data collected by flight route
|
|
70
103
|
```
|
|
71
104
|
|
|
72
105
|
**SessionManager API:**
|
|
@@ -103,35 +103,59 @@ Assistant: Great! Let me check flights for next week. Could you tell me which ai
|
|
|
103
103
|
Current session information including:
|
|
104
104
|
|
|
105
105
|
- Active route and step
|
|
106
|
-
-
|
|
106
|
+
- Agent-level collected data (with privacy filtering)
|
|
107
107
|
- Route progress and completion status
|
|
108
|
+
- Cross-route data availability
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
Current Session:
|
|
112
|
+
- Route: Flight Booking (2/3 required fields collected)
|
|
113
|
+
- Step: ask_passengers
|
|
114
|
+
- Agent Data: { destination: "Paris", departureDate: "2025-01-15" }
|
|
115
|
+
- Missing Required: passengers
|
|
116
|
+
- Available from other routes: { hotelPreference: "luxury" }
|
|
117
|
+
```
|
|
108
118
|
|
|
109
119
|
## Dynamic Schema Generation
|
|
110
120
|
|
|
111
|
-
For data collection steps, the prompt includes JSON schemas:
|
|
121
|
+
For data collection steps, the prompt includes agent-level JSON schemas:
|
|
112
122
|
|
|
113
123
|
```typescript
|
|
114
|
-
//
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
+
// Agent-level schema
|
|
125
|
+
const agent = new Agent<{}, TravelData>({
|
|
126
|
+
schema: {
|
|
127
|
+
type: "object",
|
|
128
|
+
properties: {
|
|
129
|
+
destination: { type: "string" },
|
|
130
|
+
departureDate: { type: "string", format: "date" },
|
|
131
|
+
passengers: { type: "number", minimum: 1 },
|
|
132
|
+
hotelPreference: { type: "string" },
|
|
133
|
+
budgetRange: { type: "string" }
|
|
134
|
+
},
|
|
135
|
+
required: ["destination", "departureDate"]
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Route specifies which fields to collect
|
|
140
|
+
const flightRoute = agent.createRoute({
|
|
141
|
+
title: "Flight Booking",
|
|
142
|
+
requiredFields: ["destination", "departureDate", "passengers"],
|
|
143
|
+
optionalFields: ["budgetRange"]
|
|
144
|
+
});
|
|
124
145
|
```
|
|
125
146
|
|
|
126
147
|
Generates:
|
|
127
148
|
|
|
128
149
|
```
|
|
129
|
-
Extract the following information from the user's response:
|
|
150
|
+
Extract the following information from the user's response based on the agent schema:
|
|
130
151
|
- destination: string - Where the user wants to fly
|
|
131
152
|
- departureDate: string (date format) - When they want to depart
|
|
132
153
|
- passengers: number (minimum 1) - How many people are traveling
|
|
154
|
+
- budgetRange: string (optional) - Budget preference for the trip
|
|
133
155
|
|
|
134
|
-
Return extracted data as valid JSON matching
|
|
156
|
+
Return extracted data as valid JSON matching the agent schema.
|
|
157
|
+
Current route requires: destination, departureDate, passengers
|
|
158
|
+
Route completion: 2/3 required fields collected
|
|
135
159
|
```
|
|
136
160
|
|
|
137
161
|
## Tool Integration
|
|
@@ -20,26 +20,33 @@ AI responses are parsed to extract:
|
|
|
20
20
|
3. **Tool Calls** - Instructions to execute tools
|
|
21
21
|
4. **Routing Decisions** - Route or step transitions
|
|
22
22
|
|
|
23
|
-
## Schema-Driven Extraction
|
|
23
|
+
## Agent-Level Schema-Driven Extraction
|
|
24
24
|
|
|
25
|
-
When steps specify `collect` fields, the AI response is validated against JSON
|
|
25
|
+
When steps specify `collect` fields, the AI response is validated against the agent-level JSON schema:
|
|
26
26
|
|
|
27
27
|
```typescript
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
collect: ["name", "email"],
|
|
28
|
+
// Agent defines comprehensive schema
|
|
29
|
+
const agent = new Agent<{}, UserData>({
|
|
31
30
|
schema: {
|
|
32
31
|
type: "object",
|
|
33
32
|
properties: {
|
|
34
33
|
name: { type: "string" },
|
|
35
34
|
email: { type: "string", format: "email" },
|
|
35
|
+
phone: { type: "string" },
|
|
36
|
+
preferences: { type: "object" }
|
|
36
37
|
},
|
|
37
|
-
required: ["name", "email"]
|
|
38
|
-
}
|
|
38
|
+
required: ["name", "email"]
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Steps collect into agent schema
|
|
43
|
+
const step = route.initialStep.nextStep({
|
|
44
|
+
prompt: "What's your name and email?",
|
|
45
|
+
collect: ["name", "email"], // Maps to agent schema fields
|
|
39
46
|
});
|
|
40
47
|
```
|
|
41
48
|
|
|
42
|
-
The AI receives instructions to return structured data
|
|
49
|
+
The AI receives instructions to return structured data that matches the agent-level schema, enabling cross-route data sharing.
|
|
43
50
|
|
|
44
51
|
## Tool Execution Pipeline
|
|
45
52
|
|
|
@@ -65,26 +72,30 @@ When tools are called, the response engine:
|
|
|
65
72
|
|
|
66
73
|
## Data Validation
|
|
67
74
|
|
|
68
|
-
Extracted data is validated against
|
|
75
|
+
Extracted data is validated against the agent-level schema:
|
|
69
76
|
|
|
70
|
-
- **Type checking** - Ensures correct data types
|
|
71
|
-
- **Required fields** - Validates mandatory data presence
|
|
72
|
-
- **Format validation** - Email, dates, custom formats
|
|
73
|
-
- **Business rules** - Custom validation logic
|
|
77
|
+
- **Type checking** - Ensures correct data types against agent schema
|
|
78
|
+
- **Required fields** - Validates mandatory data presence for route completion
|
|
79
|
+
- **Format validation** - Email, dates, custom formats from agent schema
|
|
80
|
+
- **Business rules** - Custom validation logic in agent-level hooks
|
|
81
|
+
- **Cross-route consistency** - Ensures data consistency across all routes
|
|
74
82
|
|
|
75
83
|
## Context Updates
|
|
76
84
|
|
|
77
85
|
Response processing updates multiple context layers:
|
|
78
86
|
|
|
79
|
-
###
|
|
87
|
+
### Agent-Level Data
|
|
80
88
|
|
|
81
89
|
```typescript
|
|
82
|
-
// Collected data merged into
|
|
83
|
-
|
|
84
|
-
...
|
|
90
|
+
// Collected data merged into agent-level data structure
|
|
91
|
+
agent.collectedData = {
|
|
92
|
+
...agent.collectedData,
|
|
85
93
|
...extractedData,
|
|
86
94
|
...toolResults,
|
|
87
95
|
};
|
|
96
|
+
|
|
97
|
+
// Session references agent data
|
|
98
|
+
session.data = agent.collectedData;
|
|
88
99
|
```
|
|
89
100
|
|
|
90
101
|
### Route Context
|
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
# Schema-Driven Data Collection
|
|
1
|
+
# Agent-Level Schema-Driven Data Collection
|
|
2
2
|
|
|
3
|
-
@falai/agent implements a powerful schema-first approach to data collection, enabling type-safe, structured information extraction from natural conversations. Unlike traditional
|
|
3
|
+
@falai/agent implements a powerful agent-level schema-first approach to data collection, enabling type-safe, structured information extraction from natural conversations across all routes. Unlike traditional route-specific data collection, this system centralizes data schemas at the agent level while allowing routes to specify completion requirements.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
The data collection system provides:
|
|
7
|
+
The agent-level data collection system provides:
|
|
8
8
|
|
|
9
|
-
- **JSON Schema
|
|
9
|
+
- **Centralized JSON Schema**: Define comprehensive data structures at the agent level
|
|
10
|
+
- **Cross-Route Data Sharing**: Data collected by any route is available to all routes
|
|
11
|
+
- **Route Completion Logic**: Routes complete when their required fields are satisfied
|
|
10
12
|
- **Type-Safe Extraction**: Automatic mapping from AI responses to typed data
|
|
11
13
|
- **Natural Conversations**: AI handles information gathering conversationally
|
|
12
|
-
- **Validation & Enrichment**:
|
|
13
|
-
- **Session Persistence**: Data survives across conversation turns
|
|
14
|
+
- **Validation & Enrichment**: Agent-level lifecycle hooks for data processing
|
|
15
|
+
- **Session Persistence**: Data survives across conversation turns and route transitions
|
|
14
16
|
|
|
15
|
-
## Schema Definition
|
|
17
|
+
## Agent-Level Schema Definition
|
|
16
18
|
|
|
17
|
-
###
|
|
19
|
+
### Centralized Schema
|
|
18
20
|
|
|
19
21
|
```typescript
|
|
20
22
|
interface UserProfile {
|
|
@@ -26,10 +28,19 @@ interface UserProfile {
|
|
|
26
28
|
notifications: boolean;
|
|
27
29
|
theme: "light" | "dark";
|
|
28
30
|
};
|
|
31
|
+
// Additional fields for other routes
|
|
32
|
+
supportTicketId?: string;
|
|
33
|
+
issueType?: string;
|
|
34
|
+
feedbackRating?: number;
|
|
35
|
+
subscriptionTier?: "free" | "premium" | "enterprise";
|
|
29
36
|
}
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
// Define schema at agent level
|
|
39
|
+
const agent = new Agent<{}, UserProfile>({
|
|
40
|
+
name: "User Management Agent",
|
|
41
|
+
provider: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
|
|
42
|
+
|
|
43
|
+
// Comprehensive agent-level schema
|
|
33
44
|
schema: {
|
|
34
45
|
type: "object",
|
|
35
46
|
properties: {
|
|
@@ -63,9 +74,32 @@ const userProfileRoute = agent.createRoute<UserProfile>({
|
|
|
63
74
|
},
|
|
64
75
|
},
|
|
65
76
|
},
|
|
77
|
+
supportTicketId: { type: "string" },
|
|
78
|
+
issueType: { type: "string" },
|
|
79
|
+
feedbackRating: { type: "number", minimum: 1, maximum: 5 },
|
|
80
|
+
subscriptionTier: { type: "string", enum: ["free", "premium", "enterprise"] }
|
|
66
81
|
},
|
|
67
82
|
required: ["name", "email"],
|
|
68
|
-
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Routes specify required fields instead of schemas
|
|
87
|
+
const profileRoute = agent.createRoute({
|
|
88
|
+
title: "User Profile Collection",
|
|
89
|
+
requiredFields: ["name", "email", "age"],
|
|
90
|
+
optionalFields: ["interests", "preferences"]
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const supportRoute = agent.createRoute({
|
|
94
|
+
title: "Support Ticket",
|
|
95
|
+
requiredFields: ["name", "email", "issueType"],
|
|
96
|
+
optionalFields: ["supportTicketId"]
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const feedbackRoute = agent.createRoute({
|
|
100
|
+
title: "Feedback Collection",
|
|
101
|
+
requiredFields: ["name", "email", "feedbackRating"],
|
|
102
|
+
optionalFields: ["subscriptionTier"]
|
|
69
103
|
});
|
|
70
104
|
```
|
|
71
105
|
|
|
@@ -128,24 +162,33 @@ const complexSchema = {
|
|
|
128
162
|
|
|
129
163
|
## Step-Level Data Collection
|
|
130
164
|
|
|
131
|
-
### Basic Collection
|
|
165
|
+
### Basic Collection with Agent-Level Data
|
|
132
166
|
|
|
133
167
|
```typescript
|
|
134
168
|
const profileRoute = agent
|
|
135
169
|
.createRoute({
|
|
136
170
|
title: "Profile Collection",
|
|
137
|
-
|
|
171
|
+
requiredFields: ["name", "email", "age"], // Required for route completion
|
|
172
|
+
optionalFields: ["interests"], // Optional but helpful
|
|
138
173
|
initialStep: {
|
|
139
174
|
prompt:
|
|
140
175
|
"Hi! I'm collecting some information to personalize your experience. What's your name?",
|
|
141
|
-
collect: ["name"], // Maps to schema field
|
|
176
|
+
collect: ["name"], // Maps to agent schema field
|
|
142
177
|
},
|
|
143
178
|
})
|
|
144
179
|
.nextStep({
|
|
145
180
|
prompt: "Thanks {{name}}! What's your email address?",
|
|
146
181
|
collect: ["email"],
|
|
147
182
|
requires: ["name"], // Must have name before collecting email
|
|
183
|
+
})
|
|
184
|
+
.nextStep({
|
|
185
|
+
prompt: "What's your age?",
|
|
186
|
+
collect: ["age"],
|
|
187
|
+
requires: ["name", "email"],
|
|
148
188
|
});
|
|
189
|
+
|
|
190
|
+
// Route completes when all required fields are collected
|
|
191
|
+
// Data is available to all other routes
|
|
149
192
|
```
|
|
150
193
|
|
|
151
194
|
### Multi-Field Collection
|
|
@@ -160,12 +203,12 @@ const comprehensiveStep = {
|
|
|
160
203
|
- Your preferred theme (light/dark)
|
|
161
204
|
`,
|
|
162
205
|
collect: [
|
|
163
|
-
"age", // Single field
|
|
164
|
-
"interests", // Array field
|
|
206
|
+
"age", // Single field from agent schema
|
|
207
|
+
"interests", // Array field from agent schema
|
|
165
208
|
"preferences.notifications", // Nested field (dot notation)
|
|
166
209
|
"preferences.theme", // Another nested field
|
|
167
210
|
],
|
|
168
|
-
requires: ["name", "email"],
|
|
211
|
+
requires: ["name", "email"], // Prerequisites from agent data
|
|
169
212
|
};
|
|
170
213
|
```
|
|
171
214
|
|
|
@@ -175,34 +218,69 @@ const comprehensiveStep = {
|
|
|
175
218
|
const conditionalCollection = {
|
|
176
219
|
prompt: "Would you like to set up notifications? (yes/no)",
|
|
177
220
|
collect: ["preferences.notifications"],
|
|
178
|
-
skipIf: (data) => data.preferences?.notifications !== undefined,
|
|
179
|
-
requires: ["name", "email"],
|
|
221
|
+
skipIf: (data) => data.preferences?.notifications !== undefined, // Skip if already collected
|
|
222
|
+
requires: ["name", "email"], // Prerequisites from agent data
|
|
180
223
|
};
|
|
181
224
|
```
|
|
182
225
|
|
|
226
|
+
### Cross-Route Data Sharing
|
|
227
|
+
|
|
228
|
+
With agent-level data collection, routes can share data seamlessly:
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
// User starts with profile collection
|
|
232
|
+
const response1 = await agent.respond("Hi, I'm John Doe, email john@example.com");
|
|
233
|
+
// Agent data: { name: "John Doe", email: "john@example.com" }
|
|
234
|
+
|
|
235
|
+
// User switches to support - data is already available
|
|
236
|
+
const response2 = await agent.respond("Actually, I need help with a technical issue");
|
|
237
|
+
// Support route can access name and email, only needs to collect issue details
|
|
238
|
+
// Support route: 2/3 required fields already satisfied
|
|
239
|
+
|
|
240
|
+
// User provides issue details
|
|
241
|
+
const response3 = await agent.respond("My account won't sync properly");
|
|
242
|
+
// Support route completes: { name: "John Doe", email: "john@example.com", issueType: "technical" }
|
|
243
|
+
|
|
244
|
+
// Later, user wants to give feedback
|
|
245
|
+
const response4 = await agent.respond("I want to rate my support experience - 5 stars");
|
|
246
|
+
// Feedback route completes immediately: already has name, email, and now rating
|
|
247
|
+
```
|
|
248
|
+
|
|
183
249
|
## Data Validation & Processing
|
|
184
250
|
|
|
185
|
-
### Lifecycle Hooks
|
|
251
|
+
### Agent-Level Lifecycle Hooks
|
|
186
252
|
|
|
187
253
|
```typescript
|
|
188
|
-
const
|
|
189
|
-
|
|
254
|
+
const agent = new Agent<{}, UserProfile>({
|
|
255
|
+
name: "User Management Agent",
|
|
256
|
+
schema: { /* agent schema */ },
|
|
190
257
|
|
|
191
|
-
// Agent-level data validation
|
|
258
|
+
// Agent-level data validation (applies to all routes)
|
|
192
259
|
hooks: {
|
|
193
260
|
onDataUpdate: (newData, previousData) => {
|
|
194
|
-
// Cross-field validation
|
|
261
|
+
// Cross-field validation using complete agent data
|
|
195
262
|
if (newData.email && newData.confirmEmail) {
|
|
196
263
|
if (newData.email !== newData.confirmEmail) {
|
|
197
264
|
throw new Error("Email addresses don't match");
|
|
198
265
|
}
|
|
199
266
|
}
|
|
200
267
|
|
|
201
|
-
// Data enrichment
|
|
268
|
+
// Data enrichment based on agent-level data
|
|
202
269
|
if (newData.name && !newData.displayName) {
|
|
203
270
|
newData.displayName = newData.name.split(" ")[0]; // First name only
|
|
204
271
|
}
|
|
205
272
|
|
|
273
|
+
// Auto-set subscription tier based on email domain
|
|
274
|
+
if (newData.email && !newData.subscriptionTier) {
|
|
275
|
+
newData.subscriptionTier = newData.email.includes('@enterprise.com') ? 'enterprise' : 'free';
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Validate against agent schema
|
|
279
|
+
const validation = agent.validateData(newData);
|
|
280
|
+
if (!validation.valid) {
|
|
281
|
+
throw new Error(`Data validation failed: ${validation.errors.map(e => e.message).join(', ')}`);
|
|
282
|
+
}
|
|
283
|
+
|
|
206
284
|
return newData;
|
|
207
285
|
},
|
|
208
286
|
},
|