@falai/agent 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -74
- package/dist/cjs/core/Agent.d.ts +22 -29
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +464 -291
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/Events.d.ts +10 -1
- package/dist/cjs/core/Events.d.ts.map +1 -1
- package/dist/cjs/core/Events.js +3 -2
- package/dist/cjs/core/Events.js.map +1 -1
- package/dist/cjs/core/PersistenceManager.d.ts +19 -0
- package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
- package/dist/cjs/core/PersistenceManager.js +57 -0
- package/dist/cjs/core/PersistenceManager.js.map +1 -1
- package/dist/cjs/core/PromptComposer.d.ts +24 -0
- package/dist/cjs/core/PromptComposer.d.ts.map +1 -0
- package/dist/cjs/core/PromptComposer.js +127 -0
- package/dist/cjs/core/PromptComposer.js.map +1 -0
- package/dist/cjs/core/ResponseEngine.d.ts +19 -0
- package/dist/cjs/core/ResponseEngine.d.ts.map +1 -0
- package/dist/cjs/core/ResponseEngine.js +51 -0
- package/dist/cjs/core/ResponseEngine.js.map +1 -0
- package/dist/cjs/core/Route.d.ts +18 -12
- package/dist/cjs/core/Route.d.ts.map +1 -1
- package/dist/cjs/core/Route.js +15 -9
- package/dist/cjs/core/Route.js.map +1 -1
- package/dist/cjs/core/RoutingEngine.d.ts +38 -0
- package/dist/cjs/core/RoutingEngine.d.ts.map +1 -0
- package/dist/cjs/core/RoutingEngine.js +110 -0
- package/dist/cjs/core/RoutingEngine.js.map +1 -0
- package/dist/cjs/core/State.d.ts +15 -4
- package/dist/cjs/core/State.d.ts.map +1 -1
- package/dist/cjs/core/State.js +21 -2
- package/dist/cjs/core/State.js.map +1 -1
- package/dist/cjs/core/ToolExecutor.d.ts +29 -0
- package/dist/cjs/core/ToolExecutor.d.ts.map +1 -0
- package/dist/cjs/core/ToolExecutor.js +73 -0
- package/dist/cjs/core/ToolExecutor.js.map +1 -0
- package/dist/cjs/core/Transition.d.ts +5 -5
- package/dist/cjs/core/Transition.d.ts.map +1 -1
- package/dist/cjs/core/Transition.js.map +1 -1
- package/dist/cjs/index.d.ts +6 -8
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +8 -10
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.js +10 -13
- package/dist/cjs/providers/AnthropicProvider.js.map +1 -1
- package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/cjs/providers/GeminiProvider.js +12 -8
- package/dist/cjs/providers/GeminiProvider.js.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.js +10 -53
- package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.js +10 -53
- package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +13 -12
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/ai.d.ts +8 -2
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/cjs/types/history.d.ts +8 -0
- package/dist/cjs/types/history.d.ts.map +1 -1
- package/dist/cjs/types/index.d.ts +0 -3
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js +1 -3
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/route.d.ts +39 -4
- package/dist/cjs/types/route.d.ts.map +1 -1
- package/dist/cjs/types/routing.d.ts +16 -0
- package/dist/cjs/types/routing.d.ts.map +1 -0
- package/dist/cjs/types/routing.js +3 -0
- package/dist/cjs/types/routing.js.map +1 -0
- package/dist/cjs/types/schema.d.ts +22 -0
- package/dist/cjs/types/schema.d.ts.map +1 -0
- package/dist/cjs/types/schema.js +3 -0
- package/dist/cjs/types/schema.js.map +1 -0
- package/dist/cjs/types/session.d.ts +72 -0
- package/dist/cjs/types/session.d.ts.map +1 -0
- package/dist/cjs/types/session.js +140 -0
- package/dist/cjs/types/session.js.map +1 -0
- package/dist/cjs/types/tool.d.ts +11 -5
- package/dist/cjs/types/tool.d.ts.map +1 -1
- package/dist/cjs/utils/id.d.ts +0 -5
- package/dist/cjs/utils/id.d.ts.map +1 -1
- package/dist/cjs/utils/id.js +0 -10
- package/dist/cjs/utils/id.js.map +1 -1
- package/dist/cjs/utils/schema.d.ts +17 -0
- package/dist/cjs/utils/schema.d.ts.map +1 -0
- package/dist/cjs/utils/schema.js +32 -0
- package/dist/cjs/utils/schema.js.map +1 -0
- package/dist/core/Agent.d.ts +22 -29
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +464 -291
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/Events.d.ts +10 -1
- package/dist/core/Events.d.ts.map +1 -1
- package/dist/core/Events.js +3 -2
- package/dist/core/Events.js.map +1 -1
- package/dist/core/PersistenceManager.d.ts +19 -0
- package/dist/core/PersistenceManager.d.ts.map +1 -1
- package/dist/core/PersistenceManager.js +57 -0
- package/dist/core/PersistenceManager.js.map +1 -1
- package/dist/core/PromptComposer.d.ts +24 -0
- package/dist/core/PromptComposer.d.ts.map +1 -0
- package/dist/core/PromptComposer.js +123 -0
- package/dist/core/PromptComposer.js.map +1 -0
- package/dist/core/ResponseEngine.d.ts +19 -0
- package/dist/core/ResponseEngine.d.ts.map +1 -0
- package/dist/core/ResponseEngine.js +47 -0
- package/dist/core/ResponseEngine.js.map +1 -0
- package/dist/core/Route.d.ts +18 -12
- package/dist/core/Route.d.ts.map +1 -1
- package/dist/core/Route.js +15 -9
- package/dist/core/Route.js.map +1 -1
- package/dist/core/RoutingEngine.d.ts +38 -0
- package/dist/core/RoutingEngine.d.ts.map +1 -0
- package/dist/core/RoutingEngine.js +106 -0
- package/dist/core/RoutingEngine.js.map +1 -0
- package/dist/core/State.d.ts +15 -4
- package/dist/core/State.d.ts.map +1 -1
- package/dist/core/State.js +21 -2
- package/dist/core/State.js.map +1 -1
- package/dist/core/ToolExecutor.d.ts +29 -0
- package/dist/core/ToolExecutor.d.ts.map +1 -0
- package/dist/core/ToolExecutor.js +69 -0
- package/dist/core/ToolExecutor.js.map +1 -0
- package/dist/core/Transition.d.ts +5 -5
- package/dist/core/Transition.d.ts.map +1 -1
- package/dist/core/Transition.js.map +1 -1
- package/dist/index.d.ts +6 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/providers/AnthropicProvider.d.ts.map +1 -1
- package/dist/providers/AnthropicProvider.js +10 -13
- package/dist/providers/AnthropicProvider.js.map +1 -1
- package/dist/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/providers/GeminiProvider.js +12 -8
- package/dist/providers/GeminiProvider.js.map +1 -1
- package/dist/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/OpenAIProvider.js +10 -53
- package/dist/providers/OpenAIProvider.js.map +1 -1
- package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/providers/OpenRouterProvider.js +10 -53
- package/dist/providers/OpenRouterProvider.js.map +1 -1
- package/dist/types/agent.d.ts +13 -12
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/ai.d.ts +8 -2
- package/dist/types/ai.d.ts.map +1 -1
- package/dist/types/history.d.ts +8 -0
- package/dist/types/history.d.ts.map +1 -1
- package/dist/types/index.d.ts +0 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +0 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/route.d.ts +39 -4
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/routing.d.ts +16 -0
- package/dist/types/routing.d.ts.map +1 -0
- package/dist/types/routing.js +2 -0
- package/dist/types/routing.js.map +1 -0
- package/dist/types/schema.d.ts +22 -0
- package/dist/types/schema.d.ts.map +1 -0
- package/dist/types/schema.js +2 -0
- package/dist/types/schema.js.map +1 -0
- package/dist/types/session.d.ts +72 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +132 -0
- package/dist/types/session.js.map +1 -0
- package/dist/types/tool.d.ts +11 -5
- package/dist/types/tool.d.ts.map +1 -1
- package/dist/utils/id.d.ts +0 -5
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +0 -9
- package/dist/utils/id.js.map +1 -1
- package/dist/utils/schema.d.ts +17 -0
- package/dist/utils/schema.d.ts.map +1 -0
- package/dist/utils/schema.js +27 -0
- package/dist/utils/schema.js.map +1 -0
- package/docs/ADAPTERS.md +83 -3
- package/docs/API_REFERENCE.md +95 -104
- package/docs/ARCHITECTURE.md +284 -286
- package/docs/CONSTRUCTOR_OPTIONS.md +192 -135
- package/docs/CONTEXT_MANAGEMENT.md +311 -28
- package/docs/CONTRIBUTING.md +1 -1
- package/docs/DOMAINS.md +61 -0
- package/docs/GETTING_STARTED.md +177 -88
- package/docs/PERSISTENCE.md +170 -23
- package/docs/README.md +7 -10
- package/examples/business-onboarding.ts +21 -9
- package/examples/company-qna-agent.ts +508 -0
- package/examples/declarative-agent.ts +143 -26
- package/examples/domain-scoping.ts +31 -10
- package/examples/extracted-data-modification.ts +415 -0
- package/examples/healthcare-agent.ts +194 -90
- package/examples/openai-agent.ts +67 -25
- package/examples/opensearch-persistence.ts +455 -151
- package/examples/persistent-onboarding.ts +162 -96
- package/examples/prisma-persistence.ts +371 -125
- package/examples/redis-persistence.ts +393 -23
- package/examples/rules-prohibitions.ts +32 -11
- package/examples/streaming-agent.ts +61 -13
- package/examples/travel-agent.ts +266 -133
- package/package.json +1 -1
- package/src/core/Agent.ts +674 -356
- package/src/core/Events.ts +12 -2
- package/src/core/PersistenceManager.ts +83 -0
- package/src/core/PromptComposer.ts +143 -0
- package/src/core/ResponseEngine.ts +82 -0
- package/src/core/Route.ts +32 -17
- package/src/core/RoutingEngine.ts +165 -0
- package/src/core/State.ts +55 -15
- package/src/core/ToolExecutor.ts +117 -0
- package/src/core/Transition.ts +5 -5
- package/src/index.ts +12 -21
- package/src/providers/AnthropicProvider.ts +10 -13
- package/src/providers/GeminiProvider.ts +12 -8
- package/src/providers/OpenAIProvider.ts +10 -56
- package/src/providers/OpenRouterProvider.ts +10 -56
- package/src/types/agent.ts +16 -13
- package/src/types/ai.ts +6 -2
- package/src/types/history.ts +8 -0
- package/src/types/index.ts +0 -11
- package/src/types/route.ts +41 -5
- package/src/types/routing.ts +18 -0
- package/src/types/schema.ts +23 -0
- package/src/types/session.ts +207 -0
- package/src/types/tool.ts +29 -7
- package/src/utils/id.ts +0 -10
- package/src/utils/schema.ts +32 -0
- package/dist/cjs/core/ConditionEvaluator.d.ts +0 -72
- package/dist/cjs/core/ConditionEvaluator.d.ts.map +0 -1
- package/dist/cjs/core/ConditionEvaluator.js +0 -272
- package/dist/cjs/core/ConditionEvaluator.js.map +0 -1
- package/dist/cjs/core/Observation.d.ts +0 -24
- package/dist/cjs/core/Observation.d.ts.map +0 -1
- package/dist/cjs/core/Observation.js +0 -39
- package/dist/cjs/core/Observation.js.map +0 -1
- package/dist/cjs/core/PreparationEngine.d.ts +0 -116
- package/dist/cjs/core/PreparationEngine.d.ts.map +0 -1
- package/dist/cjs/core/PreparationEngine.js +0 -353
- package/dist/cjs/core/PreparationEngine.js.map +0 -1
- package/dist/cjs/core/PromptBuilder.d.ts +0 -136
- package/dist/cjs/core/PromptBuilder.d.ts.map +0 -1
- package/dist/cjs/core/PromptBuilder.js +0 -421
- package/dist/cjs/core/PromptBuilder.js.map +0 -1
- package/dist/cjs/types/observation.d.ts +0 -27
- package/dist/cjs/types/observation.d.ts.map +0 -1
- package/dist/cjs/types/observation.js +0 -6
- package/dist/cjs/types/observation.js.map +0 -1
- package/dist/cjs/types/prompt.d.ts +0 -46
- package/dist/cjs/types/prompt.d.ts.map +0 -1
- package/dist/cjs/types/prompt.js +0 -19
- package/dist/cjs/types/prompt.js.map +0 -1
- package/dist/core/ConditionEvaluator.d.ts +0 -72
- package/dist/core/ConditionEvaluator.d.ts.map +0 -1
- package/dist/core/ConditionEvaluator.js +0 -268
- package/dist/core/ConditionEvaluator.js.map +0 -1
- package/dist/core/Observation.d.ts +0 -24
- package/dist/core/Observation.d.ts.map +0 -1
- package/dist/core/Observation.js +0 -35
- package/dist/core/Observation.js.map +0 -1
- package/dist/core/PreparationEngine.d.ts +0 -116
- package/dist/core/PreparationEngine.d.ts.map +0 -1
- package/dist/core/PreparationEngine.js +0 -349
- package/dist/core/PreparationEngine.js.map +0 -1
- package/dist/core/PromptBuilder.d.ts +0 -136
- package/dist/core/PromptBuilder.d.ts.map +0 -1
- package/dist/core/PromptBuilder.js +0 -417
- package/dist/core/PromptBuilder.js.map +0 -1
- package/dist/types/observation.d.ts +0 -27
- package/dist/types/observation.d.ts.map +0 -1
- package/dist/types/observation.js +0 -5
- package/dist/types/observation.js.map +0 -1
- package/dist/types/prompt.d.ts +0 -46
- package/dist/types/prompt.d.ts.map +0 -1
- package/dist/types/prompt.js +0 -16
- package/dist/types/prompt.js.map +0 -1
- package/docs/STRUCTURE.md +0 -58
- package/src/core/ConditionEvaluator.ts +0 -381
- package/src/core/Observation.ts +0 -47
- package/src/core/PreparationEngine.ts +0 -561
- package/src/core/PromptBuilder.ts +0 -617
- package/src/types/observation.ts +0 -29
- package/src/types/prompt.ts +0 -49
|
@@ -1,57 +1,340 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Session State & Data Management
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
The `@falai/agent` framework provides
|
|
5
|
+
The `@falai/agent` framework provides **session state management** for tracking conversation progress, extracted data, and user intent across multiple turns. This enables sophisticated data-driven conversations with intelligent state progression.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## 🎯 Session State: The Foundation
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Session state tracks three key aspects of a conversation:
|
|
12
|
+
|
|
13
|
+
1. **Current Route** - Which conversation flow the user is in
|
|
14
|
+
2. **Current State** - Where in the flow they currently are
|
|
15
|
+
3. **Extracted Data** - Structured data collected so far
|
|
12
16
|
|
|
13
17
|
```typescript
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
import { createSession, SessionState } from "@falai/agent";
|
|
19
|
+
|
|
20
|
+
// Define your data extraction type
|
|
21
|
+
interface FlightData {
|
|
22
|
+
destination: string;
|
|
23
|
+
departureDate: string;
|
|
24
|
+
passengers: number;
|
|
25
|
+
cabinClass: "economy" | "business" | "first";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Initialize session state
|
|
29
|
+
let session = createSession<FlightData>();
|
|
30
|
+
|
|
31
|
+
// Session starts empty
|
|
32
|
+
console.log(session.currentRoute); // undefined
|
|
33
|
+
console.log(session.currentState); // undefined
|
|
34
|
+
console.log(session.extracted); // {}
|
|
35
|
+
|
|
36
|
+
// Use in conversation
|
|
37
|
+
const response = await agent.respond({ history, session });
|
|
38
|
+
|
|
39
|
+
// Session updated with progress and extracted data
|
|
40
|
+
console.log(response.session?.currentRoute?.title); // "Book Flight"
|
|
41
|
+
console.log(response.session?.currentState?.id); // "ask_destination"
|
|
42
|
+
console.log(response.session?.extracted); // { destination: "Paris", ... }
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Benefits of Session State:**
|
|
46
|
+
|
|
47
|
+
- **Always-On Routing** - Users can change their mind mid-conversation
|
|
48
|
+
- **Data Persistence** - Extracted data survives across turns
|
|
49
|
+
- **Context Awareness** - Router sees current progress and extracted data
|
|
50
|
+
- **State Recovery** - Resume conversations from any point
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 🔄 Session State Helpers
|
|
55
|
+
|
|
56
|
+
### Creating and Managing Sessions
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import {
|
|
60
|
+
createSession,
|
|
61
|
+
enterRoute,
|
|
62
|
+
enterState,
|
|
63
|
+
mergeExtracted,
|
|
64
|
+
type SessionState,
|
|
65
|
+
} from "@falai/agent";
|
|
66
|
+
|
|
67
|
+
// Create a new session
|
|
68
|
+
let session = createSession<FlightData>();
|
|
69
|
+
|
|
70
|
+
// Enter a route (when routing decides to switch)
|
|
71
|
+
session = enterRoute(session, "book_flight", "Book Flight");
|
|
72
|
+
|
|
73
|
+
// Enter a state (when progressing through the flow)
|
|
74
|
+
session = enterState(session, "ask_destination", "Ask where they want to fly");
|
|
75
|
+
|
|
76
|
+
// Merge extracted data (when AI extracts new information)
|
|
77
|
+
session = mergeExtracted(session, {
|
|
78
|
+
destination: "Paris",
|
|
79
|
+
departureDate: "2025-10-15",
|
|
80
|
+
passengers: 2,
|
|
19
81
|
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Session State Structure
|
|
20
85
|
|
|
21
|
-
|
|
86
|
+
```typescript
|
|
87
|
+
interface SessionState<TExtracted = unknown> {
|
|
88
|
+
currentRoute?: {
|
|
89
|
+
id: string;
|
|
90
|
+
title: string;
|
|
91
|
+
enteredAt: Date;
|
|
92
|
+
};
|
|
93
|
+
currentState?: {
|
|
94
|
+
id: string;
|
|
95
|
+
description?: string;
|
|
96
|
+
enteredAt: Date;
|
|
97
|
+
};
|
|
98
|
+
extracted: Partial<TExtracted>; // Data collected so far
|
|
99
|
+
routeHistory: Array<{
|
|
100
|
+
routeId: string;
|
|
101
|
+
routeTitle: string;
|
|
102
|
+
enteredAt: Date;
|
|
103
|
+
exitedAt?: Date;
|
|
104
|
+
}>;
|
|
105
|
+
metadata?: Record<string, unknown>;
|
|
106
|
+
}
|
|
22
107
|
```
|
|
23
108
|
|
|
24
|
-
|
|
109
|
+
## 🔄 Enhanced Lifecycle Hooks
|
|
25
110
|
|
|
26
|
-
###
|
|
111
|
+
### Context Hooks (Traditional Context Management)
|
|
27
112
|
|
|
28
113
|
```typescript
|
|
29
|
-
// ❌ PROBLEM: Context updates don't persist
|
|
30
114
|
const agent = new Agent({
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
115
|
+
// ... other options
|
|
116
|
+
hooks: {
|
|
117
|
+
// Refresh context before each response
|
|
118
|
+
beforeRespond: async (currentContext) => {
|
|
119
|
+
const freshData = await loadUserData(currentContext.userId);
|
|
120
|
+
return { ...currentContext, ...freshData };
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// Persist context updates
|
|
124
|
+
onContextUpdate: async (newContext, previousContext) => {
|
|
125
|
+
await saveUserData(newContext.userId, newContext);
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
// NEW: Validate and enrich extracted data
|
|
129
|
+
onExtractedUpdate: async (extracted, previousExtracted) => {
|
|
130
|
+
// Normalize passenger count
|
|
131
|
+
if (extracted.passengers < 1) extracted.passengers = 1;
|
|
132
|
+
if (extracted.passengers > 9) extracted.passengers = 9;
|
|
133
|
+
|
|
134
|
+
// Enrich with computed fields
|
|
135
|
+
if (extracted.destination) {
|
|
136
|
+
extracted.destinationCode = await lookupAirportCode(
|
|
137
|
+
extracted.destination
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Auto-trigger actions
|
|
142
|
+
if (hasAllRequiredData(extracted)) {
|
|
143
|
+
extracted.shouldSearchFlights = true;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return extracted;
|
|
147
|
+
},
|
|
148
|
+
},
|
|
34
149
|
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Context Provider Pattern
|
|
35
153
|
|
|
36
|
-
|
|
37
|
-
await agent.respond({ history: [message1] });
|
|
38
|
-
// Tool modifies context in memory...
|
|
154
|
+
For always-fresh context from external sources:
|
|
39
155
|
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
156
|
+
```typescript
|
|
157
|
+
const agent = new Agent({
|
|
158
|
+
// ... other options
|
|
159
|
+
contextProvider: async () => {
|
|
160
|
+
// Load fresh context for each response
|
|
161
|
+
return await loadFullContextFromDatabase();
|
|
162
|
+
},
|
|
163
|
+
});
|
|
44
164
|
```
|
|
45
165
|
|
|
46
|
-
|
|
166
|
+
## 📊 Data Extraction Pipeline
|
|
47
167
|
|
|
48
|
-
|
|
168
|
+
Schema-first data extraction with intelligent state progression:
|
|
49
169
|
|
|
50
|
-
|
|
170
|
+
### 1. Define Your Data Schema
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
interface FlightData {
|
|
174
|
+
destination: string;
|
|
175
|
+
destinationCode?: string; // Enriched by tools
|
|
176
|
+
departureDate: string;
|
|
177
|
+
departureDateParsed?: string; // Enriched by tools
|
|
178
|
+
passengers: number;
|
|
179
|
+
cabinClass: "economy" | "business" | "first";
|
|
180
|
+
shouldSearchFlights?: boolean; // Action flag
|
|
181
|
+
}
|
|
51
182
|
|
|
52
|
-
|
|
183
|
+
const route = agent.createRoute<FlightData>({
|
|
184
|
+
title: "Book Flight",
|
|
185
|
+
gatherSchema: {
|
|
186
|
+
type: "object",
|
|
187
|
+
properties: {
|
|
188
|
+
destination: { type: "string" },
|
|
189
|
+
departureDate: { type: "string" },
|
|
190
|
+
passengers: { type: "number", minimum: 1, maximum: 9 },
|
|
191
|
+
cabinClass: {
|
|
192
|
+
type: "string",
|
|
193
|
+
enum: ["economy", "business", "first"],
|
|
194
|
+
default: "economy",
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
required: ["destination", "departureDate", "passengers"],
|
|
198
|
+
},
|
|
199
|
+
initialData: {
|
|
200
|
+
cabinClass: "economy", // Pre-populate defaults
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### 2. Create Smart State Machines
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
// State with code-based logic (no fuzzy LLM conditions!)
|
|
209
|
+
const askDestination = route.initialState.transitionTo({
|
|
210
|
+
chatState: "Ask where they want to fly",
|
|
211
|
+
gather: ["destination"],
|
|
212
|
+
skipIf: (extracted) => !!extracted.destination, // Skip if already have destination
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const enrichDestination = askDestination.transitionTo({
|
|
216
|
+
toolState: lookupAirportCode, // Tool executes automatically
|
|
217
|
+
requiredData: ["destination"], // Prerequisites
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const askDates = enrichDestination.transitionTo({
|
|
221
|
+
chatState: "Ask about travel dates",
|
|
222
|
+
gather: ["departureDate"],
|
|
223
|
+
skipIf: (extracted) => !!extracted.departureDate,
|
|
224
|
+
requiredData: ["destination"], // Must have destination first
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const validateDate = askDates.transitionTo({
|
|
228
|
+
toolState: parseAndValidateDate,
|
|
229
|
+
requiredData: ["departureDate"],
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const askPassengers = validateDate.transitionTo({
|
|
233
|
+
chatState: "How many passengers?",
|
|
234
|
+
gather: ["passengers"],
|
|
235
|
+
skipIf: (extracted) => !!extracted.passengers,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const searchFlights = askPassengers.transitionTo({
|
|
239
|
+
toolState: searchFlightAPI,
|
|
240
|
+
// Triggered when shouldSearchFlights flag is set by hook
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### 3. Tools Access Extracted Data
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
const searchFlights = defineTool<Context, [], void, FlightData>(
|
|
248
|
+
"search_flights",
|
|
249
|
+
async ({ context, extracted }) => {
|
|
250
|
+
// Access extracted data directly (no LLM extraction needed!)
|
|
251
|
+
if (!extracted.destination || !extracted.departureDate) {
|
|
252
|
+
return { data: undefined };
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const flights = await searchFlightAPI(
|
|
256
|
+
extracted.destination,
|
|
257
|
+
extracted.departureDate
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
data: undefined,
|
|
262
|
+
contextUpdate: { availableFlights: flights },
|
|
263
|
+
extractedUpdate: {
|
|
264
|
+
shouldSearchFlights: false, // Clear the flag
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### 4. Lifecycle Hooks for Validation & Enrichment
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
const agent = new Agent({
|
|
275
|
+
// ... other options
|
|
276
|
+
hooks: {
|
|
277
|
+
onExtractedUpdate: async (extracted, previous) => {
|
|
278
|
+
// Normalize data
|
|
279
|
+
if (extracted.passengers < 1) extracted.passengers = 1;
|
|
280
|
+
if (extracted.passengers > 9) extracted.passengers = 9;
|
|
281
|
+
|
|
282
|
+
// Enrich data
|
|
283
|
+
if (extracted.destination && !extracted.destinationCode) {
|
|
284
|
+
extracted.destinationCode = await lookupAirportCode(
|
|
285
|
+
extracted.destination
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Auto-trigger actions
|
|
290
|
+
if (hasAllRequiredData(extracted) && !extracted.shouldSearchFlights) {
|
|
291
|
+
extracted.shouldSearchFlights = true;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return extracted;
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## 🎯 Always-On Routing with Context
|
|
301
|
+
|
|
302
|
+
Routing happens every turn with full session context:
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
// User starts booking a flight
|
|
306
|
+
const response1 = await agent.respond({
|
|
307
|
+
history: [
|
|
308
|
+
createMessageEvent(
|
|
309
|
+
EventSource.CUSTOMER,
|
|
310
|
+
"User",
|
|
311
|
+
"I want to fly to Paris tomorrow with 2 people"
|
|
312
|
+
),
|
|
313
|
+
],
|
|
314
|
+
session,
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// User changes mind mid-conversation
|
|
318
|
+
const response2 = await agent.respond({
|
|
319
|
+
history: [
|
|
320
|
+
...previousHistory,
|
|
321
|
+
createMessageEvent(
|
|
322
|
+
EventSource.CUSTOMER,
|
|
323
|
+
"User",
|
|
324
|
+
"Actually, make that Tokyo instead"
|
|
325
|
+
),
|
|
326
|
+
],
|
|
327
|
+
session: response1.session, // Router sees context and switches appropriately
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// Router understands:
|
|
331
|
+
// - Current route: "Book Flight"
|
|
332
|
+
// - Current state: "ask_passengers"
|
|
333
|
+
// - Extracted data: { destination: "Paris", departureDate: "tomorrow", passengers: 2 }
|
|
334
|
+
// - User intent: "Tokyo instead" → switches to new destination
|
|
335
|
+
```
|
|
53
336
|
|
|
54
|
-
|
|
337
|
+
## 📋 Multi-Turn Conversation Patterns
|
|
55
338
|
|
|
56
339
|
```typescript
|
|
57
340
|
import { Agent, type ContextLifecycleHooks } from "@falai/agent";
|
package/docs/CONTRIBUTING.md
CHANGED
package/docs/DOMAINS.md
CHANGED
|
@@ -662,6 +662,67 @@ route.initialState.transitionTo({
|
|
|
662
662
|
});
|
|
663
663
|
```
|
|
664
664
|
|
|
665
|
+
## How Enforcement Works (Under the Hood)
|
|
666
|
+
|
|
667
|
+
For developers who want to understand the implementation:
|
|
668
|
+
|
|
669
|
+
### Automatic Tool Tagging
|
|
670
|
+
|
|
671
|
+
When you register tools via `agent.addDomain()`, each tool is automatically tagged with its domain name:
|
|
672
|
+
|
|
673
|
+
```typescript
|
|
674
|
+
// When you do this:
|
|
675
|
+
agent.addDomain("payment", {
|
|
676
|
+
processPayment: defineTool(/* ... */),
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
// The framework automatically adds:
|
|
680
|
+
// processPayment.domainName = "payment"
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
### Runtime Enforcement
|
|
684
|
+
|
|
685
|
+
When a tool tries to execute, `ToolExecutor` checks:
|
|
686
|
+
|
|
687
|
+
1. **Get allowed domains** from the current route
|
|
688
|
+
2. **Check tool's domain** against the allowed list
|
|
689
|
+
3. **Block execution** if domain not allowed
|
|
690
|
+
4. **Throw security error** with clear message
|
|
691
|
+
|
|
692
|
+
```typescript
|
|
693
|
+
// ToolExecutor enforcement code:
|
|
694
|
+
if (allowedDomains !== undefined && tool.domainName) {
|
|
695
|
+
if (!allowedDomains.includes(tool.domainName)) {
|
|
696
|
+
throw new Error(
|
|
697
|
+
`Domain security violation: Tool "${tool.name}" belongs to domain "${tool.domainName}" ` +
|
|
698
|
+
`which is not allowed in this route. Allowed domains: [${allowedDomains.join(
|
|
699
|
+
", "
|
|
700
|
+
)}]`
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
### What Gets Enforced
|
|
707
|
+
|
|
708
|
+
✅ **Tools in state machine transitions** (`toolState`)
|
|
709
|
+
✅ **Multiple domain access** (route can allow several domains)
|
|
710
|
+
✅ **Empty array enforcement** (`domains: []` blocks all tools)
|
|
711
|
+
✅ **Undefined = all allowed** (backward compatible)
|
|
712
|
+
|
|
713
|
+
### Type Safety
|
|
714
|
+
|
|
715
|
+
The domain system is fully type-safe:
|
|
716
|
+
|
|
717
|
+
```typescript
|
|
718
|
+
interface ToolRef {
|
|
719
|
+
id: string;
|
|
720
|
+
name: string;
|
|
721
|
+
handler: Function;
|
|
722
|
+
domainName?: string; // Added by addDomain()
|
|
723
|
+
}
|
|
724
|
+
```
|
|
725
|
+
|
|
665
726
|
## See Also
|
|
666
727
|
|
|
667
728
|
- [Architecture Guide](./ARCHITECTURE.md) - Core design principles
|