@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
package/dist/src/core/Agent.js
CHANGED
|
@@ -13,17 +13,39 @@ import { ToolExecutor } from "./ToolExecutor";
|
|
|
13
13
|
import { ResponsePipeline } from "./ResponsePipeline";
|
|
14
14
|
import { END_ROUTE_ID } from "../constants";
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* Error thrown when data validation fails
|
|
17
17
|
*/
|
|
18
|
+
class DataValidationError extends Error {
|
|
19
|
+
constructor(errors, message) {
|
|
20
|
+
super(message || "Data validation failed");
|
|
21
|
+
this.errors = errors;
|
|
22
|
+
this.name = "DataValidationError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Error thrown when route configuration is invalid
|
|
27
|
+
*/
|
|
28
|
+
class RouteConfigurationError extends Error {
|
|
29
|
+
constructor(routeTitle, invalidFields, message) {
|
|
30
|
+
super(message || `Route configuration error in '${routeTitle}'`);
|
|
31
|
+
this.routeTitle = routeTitle;
|
|
32
|
+
this.invalidFields = invalidFields;
|
|
33
|
+
this.name = "RouteConfigurationError";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Main Agent class with generic context and data support
|
|
38
|
+
*/
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
40
|
export class Agent {
|
|
19
41
|
constructor(options) {
|
|
20
42
|
this.options = options;
|
|
21
43
|
this.terms = [];
|
|
22
44
|
this.guidelines = [];
|
|
23
45
|
this.tools = [];
|
|
24
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
46
|
this.routes = [];
|
|
26
47
|
this.knowledgeBase = {};
|
|
48
|
+
this.collectedData = {};
|
|
27
49
|
// Set log level based on debug option
|
|
28
50
|
if (options.debug) {
|
|
29
51
|
logger.setLevel(LoggerLevel.DEBUG);
|
|
@@ -32,8 +54,25 @@ export class Agent {
|
|
|
32
54
|
if (options.context !== undefined && options.contextProvider) {
|
|
33
55
|
throw new Error("Cannot provide both 'context' and 'contextProvider'. Choose one.");
|
|
34
56
|
}
|
|
57
|
+
// Initialize and validate agent-level schema if provided
|
|
58
|
+
if (options.schema) {
|
|
59
|
+
this.schema = options.schema;
|
|
60
|
+
this.validateSchema(this.schema);
|
|
61
|
+
logger.debug("[Agent] Agent-level schema initialized and validated");
|
|
62
|
+
}
|
|
35
63
|
// Initialize context if provided
|
|
36
64
|
this.context = options.context;
|
|
65
|
+
// Initialize collected data with initial data if provided
|
|
66
|
+
if (options.initialData) {
|
|
67
|
+
if (this.schema) {
|
|
68
|
+
const validation = this.validateData(options.initialData);
|
|
69
|
+
if (!validation.valid) {
|
|
70
|
+
throw new Error(`Initial data validation failed: ${validation.errors.map(e => e.message).join(', ')}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
this.collectedData = { ...options.initialData };
|
|
74
|
+
logger.debug("[Agent] Initial data set:", this.collectedData);
|
|
75
|
+
}
|
|
37
76
|
// Initialize current session if provided
|
|
38
77
|
this.currentSession = options.session;
|
|
39
78
|
// Initialize routing and response engines
|
|
@@ -43,15 +82,32 @@ export class Agent {
|
|
|
43
82
|
switchThreshold: 70,
|
|
44
83
|
});
|
|
45
84
|
this.responseEngine = new ResponseEngine();
|
|
46
|
-
this.responsePipeline = new ResponsePipeline(options, this.routes, this.tools, this.routingEngine, this.updateContext.bind(this), this.updateData.bind(this));
|
|
85
|
+
this.responsePipeline = new ResponsePipeline(options, this.routes, this.tools, this.routingEngine, this.updateContext.bind(this), this.updateData.bind(this), this.updateCollectedData.bind(this));
|
|
47
86
|
// Initialize persistence if configured
|
|
48
87
|
if (options.persistence) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
88
|
+
try {
|
|
89
|
+
// Validate persistence configuration
|
|
90
|
+
if (!options.persistence.adapter) {
|
|
91
|
+
throw new Error("Persistence adapter is required when persistence is configured");
|
|
92
|
+
}
|
|
93
|
+
if (!options.persistence.adapter.sessionRepository) {
|
|
94
|
+
throw new Error("Persistence adapter must provide a sessionRepository");
|
|
95
|
+
}
|
|
96
|
+
if (!options.persistence.adapter.messageRepository) {
|
|
97
|
+
throw new Error("Persistence adapter must provide a messageRepository");
|
|
98
|
+
}
|
|
99
|
+
this.persistenceManager = new PersistenceManager(options.persistence);
|
|
100
|
+
// Initialize the adapter if it has an initialize method
|
|
101
|
+
if (options.persistence.adapter.initialize) {
|
|
102
|
+
options.persistence.adapter.initialize().catch((error) => {
|
|
103
|
+
logger.error("[Agent] Persistence adapter initialization failed:", error instanceof Error ? error.message : String(error));
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
109
|
+
logger.error("[Agent] Failed to initialize persistence:", errorMessage);
|
|
110
|
+
throw new Error(`Failed to initialize persistence: ${errorMessage}`);
|
|
55
111
|
}
|
|
56
112
|
}
|
|
57
113
|
// Initialize from options - use create methods for consistency
|
|
@@ -89,6 +145,116 @@ export class Agent {
|
|
|
89
145
|
});
|
|
90
146
|
}
|
|
91
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Validate the agent-level schema structure
|
|
150
|
+
* @private
|
|
151
|
+
*/
|
|
152
|
+
validateSchema(schema) {
|
|
153
|
+
if (!schema || typeof schema !== 'object') {
|
|
154
|
+
throw new Error("Agent schema must be a valid JSON Schema object. " +
|
|
155
|
+
"Provide a schema with 'type': 'object' and 'properties' to define the data structure.");
|
|
156
|
+
}
|
|
157
|
+
if (schema.type !== 'object') {
|
|
158
|
+
throw new Error(`Agent schema must be of type 'object', but received '${String(schema.type)}'. ` +
|
|
159
|
+
"Agent-level schemas must define object structures for data collection.");
|
|
160
|
+
}
|
|
161
|
+
if (!schema.properties || typeof schema.properties !== 'object') {
|
|
162
|
+
throw new Error("Agent schema must have a 'properties' field defining the data fields. " +
|
|
163
|
+
"Example: { type: 'object', properties: { name: { type: 'string' }, email: { type: 'string' } } }");
|
|
164
|
+
}
|
|
165
|
+
logger.debug("[Agent] Schema validation passed");
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Validate data against the agent-level schema
|
|
169
|
+
*/
|
|
170
|
+
validateData(data) {
|
|
171
|
+
if (!this.schema) {
|
|
172
|
+
// No schema defined, consider all data valid
|
|
173
|
+
return { valid: true, errors: [], warnings: [] };
|
|
174
|
+
}
|
|
175
|
+
const errors = [];
|
|
176
|
+
const warnings = [];
|
|
177
|
+
// Basic validation - check if provided fields exist in schema
|
|
178
|
+
if (this.schema.properties) {
|
|
179
|
+
for (const [key, value] of Object.entries(data)) {
|
|
180
|
+
if (!(key in this.schema.properties)) {
|
|
181
|
+
errors.push({
|
|
182
|
+
field: key,
|
|
183
|
+
value,
|
|
184
|
+
message: `Field '${key}' is not defined in agent schema`,
|
|
185
|
+
schemaPath: `properties.${key}`
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Check required fields if specified
|
|
191
|
+
if (this.schema.required && Array.isArray(this.schema.required)) {
|
|
192
|
+
for (const requiredField of this.schema.required) {
|
|
193
|
+
if (!(requiredField in data) || data[requiredField] === undefined) {
|
|
194
|
+
warnings.push({
|
|
195
|
+
field: requiredField,
|
|
196
|
+
value: undefined,
|
|
197
|
+
message: `Required field '${requiredField}' is missing`,
|
|
198
|
+
schemaPath: `required`
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
valid: errors.length === 0,
|
|
205
|
+
errors,
|
|
206
|
+
warnings
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Check if a field is valid according to the agent schema
|
|
211
|
+
* @param field - The field key to validate
|
|
212
|
+
* @returns true if field exists in schema or no schema is defined, false otherwise
|
|
213
|
+
*/
|
|
214
|
+
isValidSchemaField(field) {
|
|
215
|
+
if (!this.schema || !this.schema.properties) {
|
|
216
|
+
// No schema defined, consider all fields valid
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
return field in this.schema.properties;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Get the current collected data
|
|
223
|
+
*/
|
|
224
|
+
getCollectedData() {
|
|
225
|
+
return { ...this.collectedData };
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Update collected data with validation
|
|
229
|
+
*/
|
|
230
|
+
async updateCollectedData(updates) {
|
|
231
|
+
// Validate the updates
|
|
232
|
+
const validation = this.validateData(updates);
|
|
233
|
+
if (!validation.valid) {
|
|
234
|
+
const errorMessages = validation.errors.map(e => e.message).join(', ');
|
|
235
|
+
throw new DataValidationError(validation.errors, `Data validation failed: ${errorMessages}`);
|
|
236
|
+
}
|
|
237
|
+
// Log warnings if any
|
|
238
|
+
if (validation.warnings.length > 0) {
|
|
239
|
+
const warningMessages = validation.warnings.map(w => w.message).join(', ');
|
|
240
|
+
logger.warn(`[Agent] Data validation warnings: ${warningMessages}`);
|
|
241
|
+
}
|
|
242
|
+
// Merge updates with current data
|
|
243
|
+
const previousData = { ...this.collectedData };
|
|
244
|
+
this.collectedData = {
|
|
245
|
+
...this.collectedData,
|
|
246
|
+
...updates
|
|
247
|
+
};
|
|
248
|
+
// Trigger agent-level lifecycle hook if configured
|
|
249
|
+
if (this.options.hooks?.onDataUpdate) {
|
|
250
|
+
this.collectedData = await this.options.hooks.onDataUpdate(this.collectedData, previousData);
|
|
251
|
+
}
|
|
252
|
+
// Update current session if it exists to keep it in sync
|
|
253
|
+
if (this.currentSession) {
|
|
254
|
+
this.currentSession = mergeCollected(this.currentSession, this.collectedData);
|
|
255
|
+
}
|
|
256
|
+
logger.debug("[Agent] Collected data updated:", updates);
|
|
257
|
+
}
|
|
92
258
|
/**
|
|
93
259
|
* Get agent name
|
|
94
260
|
*/
|
|
@@ -114,10 +280,25 @@ export class Agent {
|
|
|
114
280
|
return this.options.identity;
|
|
115
281
|
}
|
|
116
282
|
/**
|
|
117
|
-
* Create a new route (journey)
|
|
118
|
-
* @template TData - Type of data collected throughout the route
|
|
283
|
+
* Create a new route (journey) using agent-level data type
|
|
119
284
|
*/
|
|
120
285
|
createRoute(options) {
|
|
286
|
+
// Validate that requiredFields exist in agent schema
|
|
287
|
+
if (options.requiredFields && this.schema?.properties) {
|
|
288
|
+
const invalidRequiredFields = options.requiredFields.filter(field => !(String(field) in this.schema.properties));
|
|
289
|
+
if (invalidRequiredFields.length > 0) {
|
|
290
|
+
throw new RouteConfigurationError(options.title, invalidRequiredFields.map(f => String(f)), `Invalid required fields in route '${options.title}': ${invalidRequiredFields.join(', ')}. ` +
|
|
291
|
+
`Must be valid keys from agent schema. Available fields: ${Object.keys(this.schema.properties).join(', ')}.`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Validate that optionalFields exist in agent schema
|
|
295
|
+
if (options.optionalFields && this.schema?.properties) {
|
|
296
|
+
const invalidOptionalFields = options.optionalFields.filter(field => !(String(field) in this.schema.properties));
|
|
297
|
+
if (invalidOptionalFields.length > 0) {
|
|
298
|
+
throw new RouteConfigurationError(options.title, invalidOptionalFields.map(f => String(f)), `Invalid optional fields in route '${options.title}': ${invalidOptionalFields.join(', ')}. ` +
|
|
299
|
+
`Must be valid keys from agent schema. Available fields: ${Object.keys(this.schema.properties).join(', ')}.`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
121
302
|
const route = new Route(options);
|
|
122
303
|
this.routes.push(route);
|
|
123
304
|
return route;
|
|
@@ -202,6 +383,8 @@ export class Agent {
|
|
|
202
383
|
if (this.options.hooks?.onDataUpdate) {
|
|
203
384
|
newCollected = (await this.options.hooks.onDataUpdate(newCollected, previousCollected));
|
|
204
385
|
}
|
|
386
|
+
// Update agent's collected data to stay in sync
|
|
387
|
+
this.collectedData = { ...newCollected };
|
|
205
388
|
// Return updated session
|
|
206
389
|
return mergeCollected(session, newCollected);
|
|
207
390
|
}
|
|
@@ -216,6 +399,12 @@ export class Agent {
|
|
|
216
399
|
// Otherwise return the stored context
|
|
217
400
|
return this.context;
|
|
218
401
|
}
|
|
402
|
+
/**
|
|
403
|
+
* Get current schema
|
|
404
|
+
*/
|
|
405
|
+
getSchema() {
|
|
406
|
+
return this.schema;
|
|
407
|
+
}
|
|
219
408
|
/**
|
|
220
409
|
* Generate a response based on history and context as a stream
|
|
221
410
|
*/
|
|
@@ -232,6 +421,11 @@ export class Agent {
|
|
|
232
421
|
});
|
|
233
422
|
const { effectiveContext } = responseContext;
|
|
234
423
|
session = responseContext.session;
|
|
424
|
+
// Merge agent's collected data into session (agent data takes precedence)
|
|
425
|
+
if (Object.keys(this.collectedData).length > 0) {
|
|
426
|
+
session = mergeCollected(session, this.collectedData);
|
|
427
|
+
logger.debug("[Agent] Merged agent collected data into session:", this.collectedData);
|
|
428
|
+
}
|
|
235
429
|
// Update our stored context if it was modified by beforeRespond hook
|
|
236
430
|
this.context = this.responsePipeline.getStoredContext();
|
|
237
431
|
// PHASE 1: PREPARE - Execute prepare function if current step has one
|
|
@@ -271,7 +465,7 @@ export class Agent {
|
|
|
271
465
|
// Get last user message
|
|
272
466
|
const lastUserMessage = getLastMessageFromHistory(history);
|
|
273
467
|
// Build response schema for this route (with collect fields from step)
|
|
274
|
-
const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep);
|
|
468
|
+
const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep, this.schema);
|
|
275
469
|
// Check if selected route and next step are defined
|
|
276
470
|
if (!selectedRoute || !nextStep) {
|
|
277
471
|
logger.error("[Agent] Selected route or next step is not defined", {
|
|
@@ -298,6 +492,7 @@ export class Agent {
|
|
|
298
492
|
combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
|
|
299
493
|
context: effectiveContext,
|
|
300
494
|
session,
|
|
495
|
+
agentSchema: this.schema,
|
|
301
496
|
});
|
|
302
497
|
// Collect available tools for AI
|
|
303
498
|
const availableTools = this.collectAvailableTools(selectedRoute, nextStep);
|
|
@@ -333,6 +528,7 @@ export class Agent {
|
|
|
333
528
|
tool: tool,
|
|
334
529
|
context: effectiveContext,
|
|
335
530
|
updateContext: this.updateContext.bind(this),
|
|
531
|
+
updateData: this.updateCollectedData.bind(this),
|
|
336
532
|
history,
|
|
337
533
|
data: session.data,
|
|
338
534
|
toolArguments: toolCall.arguments,
|
|
@@ -416,6 +612,7 @@ export class Agent {
|
|
|
416
612
|
tool: tool,
|
|
417
613
|
context: effectiveContext,
|
|
418
614
|
updateContext: this.updateContext.bind(this),
|
|
615
|
+
updateData: this.updateCollectedData.bind(this),
|
|
419
616
|
history: updatedHistory,
|
|
420
617
|
data: session.data,
|
|
421
618
|
toolArguments: toolCall.arguments,
|
|
@@ -449,12 +646,16 @@ export class Agent {
|
|
|
449
646
|
// The structured response includes both base fields and collected extraction fields
|
|
450
647
|
const structuredData = chunk.structured;
|
|
451
648
|
for (const field of nextStep.collect) {
|
|
452
|
-
|
|
453
|
-
|
|
649
|
+
const fieldKey = String(field);
|
|
650
|
+
if (fieldKey in structuredData) {
|
|
651
|
+
collectedData[fieldKey] = structuredData[fieldKey];
|
|
454
652
|
}
|
|
455
653
|
}
|
|
456
|
-
// Merge collected data into session
|
|
654
|
+
// Merge collected data into session using agent-level data validation
|
|
457
655
|
if (Object.keys(collectedData).length > 0) {
|
|
656
|
+
// Update agent-level collected data with validation
|
|
657
|
+
await this.updateCollectedData(collectedData);
|
|
658
|
+
// Update session with validated data
|
|
458
659
|
session = await this.updateData(session, collectedData);
|
|
459
660
|
logger.debug(`[Agent] Collected data:`, collectedData);
|
|
460
661
|
}
|
|
@@ -517,7 +718,7 @@ export class Agent {
|
|
|
517
718
|
"Summarize what was accomplished and confirm completion based on the conversation history and collected data",
|
|
518
719
|
});
|
|
519
720
|
// Build response schema for completion
|
|
520
|
-
const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep);
|
|
721
|
+
const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep, this.schema);
|
|
521
722
|
const templateContext = {
|
|
522
723
|
context: effectiveContext,
|
|
523
724
|
session,
|
|
@@ -541,6 +742,7 @@ export class Agent {
|
|
|
541
742
|
combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
|
|
542
743
|
context: effectiveContext,
|
|
543
744
|
session,
|
|
745
|
+
agentSchema: this.schema,
|
|
544
746
|
});
|
|
545
747
|
// Stream completion message using AI provider
|
|
546
748
|
const stream = this.options.provider.generateMessageStream({
|
|
@@ -666,6 +868,11 @@ export class Agent {
|
|
|
666
868
|
let session = cloneDeep(params.session) ||
|
|
667
869
|
cloneDeep(this.currentSession) ||
|
|
668
870
|
(await this.session.getOrCreate());
|
|
871
|
+
// Merge agent's collected data into session (agent data takes precedence)
|
|
872
|
+
if (Object.keys(this.collectedData).length > 0) {
|
|
873
|
+
session = mergeCollected(session, this.collectedData);
|
|
874
|
+
logger.debug("[Agent] Merged agent collected data into session:", this.collectedData);
|
|
875
|
+
}
|
|
669
876
|
// PHASE 1: PREPARE - Execute prepare function if current step has one
|
|
670
877
|
if (session.currentRoute && session.currentStep) {
|
|
671
878
|
const currentRoute = this.routes.find((r) => r.id === session.currentRoute?.id);
|
|
@@ -763,7 +970,7 @@ export class Agent {
|
|
|
763
970
|
// Get last user message
|
|
764
971
|
const lastUserMessage = getLastMessageFromHistory(history);
|
|
765
972
|
// Build response schema for this route (with collect fields from step)
|
|
766
|
-
responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep);
|
|
973
|
+
responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep, this.schema);
|
|
767
974
|
// Build response prompt
|
|
768
975
|
responsePrompt = await this.responseEngine.buildResponsePrompt({
|
|
769
976
|
route: selectedRoute,
|
|
@@ -782,6 +989,7 @@ export class Agent {
|
|
|
782
989
|
combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
|
|
783
990
|
context: effectiveContext,
|
|
784
991
|
session,
|
|
992
|
+
agentSchema: this.schema,
|
|
785
993
|
});
|
|
786
994
|
// Collect available tools for AI
|
|
787
995
|
availableTools = this.collectAvailableTools(selectedRoute, nextStep);
|
|
@@ -799,7 +1007,7 @@ export class Agent {
|
|
|
799
1007
|
session,
|
|
800
1008
|
});
|
|
801
1009
|
// Use agent-level tools only
|
|
802
|
-
availableTools =
|
|
1010
|
+
availableTools = this.collectAvailableTools();
|
|
803
1011
|
responseSchema = undefined;
|
|
804
1012
|
}
|
|
805
1013
|
// Generate message using AI provider (common for both route and no-route cases)
|
|
@@ -834,6 +1042,7 @@ export class Agent {
|
|
|
834
1042
|
tool: tool,
|
|
835
1043
|
context: effectiveContext,
|
|
836
1044
|
updateContext: this.updateContext.bind(this),
|
|
1045
|
+
updateData: this.updateCollectedData.bind(this),
|
|
837
1046
|
history,
|
|
838
1047
|
data: session.data,
|
|
839
1048
|
toolArguments: toolCall.arguments,
|
|
@@ -912,6 +1121,7 @@ export class Agent {
|
|
|
912
1121
|
tool: tool,
|
|
913
1122
|
context: effectiveContext,
|
|
914
1123
|
updateContext: this.updateContext.bind(this),
|
|
1124
|
+
updateData: this.updateCollectedData.bind(this),
|
|
915
1125
|
history: updatedHistory,
|
|
916
1126
|
data: session.data,
|
|
917
1127
|
toolArguments: toolCall.arguments,
|
|
@@ -946,12 +1156,16 @@ export class Agent {
|
|
|
946
1156
|
// The structured response includes both base fields and collected extraction fields
|
|
947
1157
|
const structuredData = result.structured;
|
|
948
1158
|
for (const field of nextStep.collect) {
|
|
949
|
-
|
|
950
|
-
|
|
1159
|
+
const fieldKey = String(field);
|
|
1160
|
+
if (fieldKey in structuredData) {
|
|
1161
|
+
collectedData[fieldKey] = structuredData[fieldKey];
|
|
951
1162
|
}
|
|
952
1163
|
}
|
|
953
|
-
// Merge collected data into session
|
|
1164
|
+
// Merge collected data into session using agent-level data validation
|
|
954
1165
|
if (Object.keys(collectedData).length > 0) {
|
|
1166
|
+
// Update agent-level collected data with validation
|
|
1167
|
+
await this.updateCollectedData(collectedData);
|
|
1168
|
+
// Update session with validated data
|
|
955
1169
|
session = await this.updateData(session, collectedData);
|
|
956
1170
|
logger.debug(`[Agent] Collected data:`, collectedData);
|
|
957
1171
|
}
|
|
@@ -977,16 +1191,16 @@ export class Agent {
|
|
|
977
1191
|
prompt: endStepSpec.prompt ||
|
|
978
1192
|
"Summarize what was accomplished and confirm completion based on the conversation history and collected data",
|
|
979
1193
|
});
|
|
1194
|
+
if (!selectedRoute) {
|
|
1195
|
+
throw new Error("Selected route is not defined");
|
|
1196
|
+
}
|
|
980
1197
|
// Build response schema for completion
|
|
981
|
-
const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep);
|
|
1198
|
+
const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep, this.schema);
|
|
982
1199
|
const templateContext = {
|
|
983
1200
|
context: effectiveContext,
|
|
984
1201
|
session,
|
|
985
1202
|
history,
|
|
986
1203
|
};
|
|
987
|
-
if (!selectedRoute) {
|
|
988
|
-
throw new Error("Selected route is not defined");
|
|
989
|
-
}
|
|
990
1204
|
// Build completion response prompt
|
|
991
1205
|
const completionPrompt = await this.responseEngine.buildResponsePrompt({
|
|
992
1206
|
route: selectedRoute,
|
|
@@ -1005,6 +1219,7 @@ export class Agent {
|
|
|
1005
1219
|
combinedTerms: this.mergeTerms(this.getTerms(), selectedRoute.getTerms()),
|
|
1006
1220
|
context: effectiveContext,
|
|
1007
1221
|
session,
|
|
1222
|
+
agentSchema: this.schema,
|
|
1008
1223
|
});
|
|
1009
1224
|
// Generate completion message using AI provider
|
|
1010
1225
|
const completionResult = await this.options.provider.generateMessage({
|
|
@@ -1250,6 +1465,7 @@ export class Agent {
|
|
|
1250
1465
|
tool,
|
|
1251
1466
|
context,
|
|
1252
1467
|
updateContext: this.updateContext.bind(this),
|
|
1468
|
+
updateData: this.updateCollectedData.bind(this),
|
|
1253
1469
|
history: [], // Empty history for prepare/finalize
|
|
1254
1470
|
data,
|
|
1255
1471
|
});
|
|
@@ -1327,19 +1543,19 @@ export class Agent {
|
|
|
1327
1543
|
this.currentSession = undefined;
|
|
1328
1544
|
}
|
|
1329
1545
|
/**
|
|
1330
|
-
* Get collected data from current session
|
|
1546
|
+
* Get collected data from current session or agent-level collected data
|
|
1331
1547
|
* @param routeId - Optional route ID to get data for (uses current route if not provided)
|
|
1332
|
-
* @returns The collected data from the current session
|
|
1548
|
+
* @returns The collected data from the current session or agent-level data
|
|
1333
1549
|
*/
|
|
1334
|
-
getData(
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
return (this.currentSession.
|
|
1340
|
-
{});
|
|
1550
|
+
getData() {
|
|
1551
|
+
// If we have a current session, use session data
|
|
1552
|
+
if (this.currentSession) {
|
|
1553
|
+
// With agent-level data, all routes share the same data structure
|
|
1554
|
+
// No need for route-specific data access
|
|
1555
|
+
return (this.currentSession.data) || {};
|
|
1341
1556
|
}
|
|
1342
|
-
return
|
|
1557
|
+
// Otherwise, return agent-level collected data
|
|
1558
|
+
return this.getCollectedData();
|
|
1343
1559
|
}
|
|
1344
1560
|
/**
|
|
1345
1561
|
* Manually transition to a different route
|
|
@@ -1382,14 +1598,14 @@ export class Agent {
|
|
|
1382
1598
|
pendingTransition: {
|
|
1383
1599
|
targetRouteId: targetRoute.id,
|
|
1384
1600
|
condition: renderedCondition,
|
|
1385
|
-
reason: "
|
|
1601
|
+
reason: "route_complete",
|
|
1386
1602
|
},
|
|
1387
1603
|
};
|
|
1388
1604
|
// Update current session if using it
|
|
1389
1605
|
if (!session && this.currentSession) {
|
|
1390
1606
|
this.currentSession = updatedSession;
|
|
1391
1607
|
}
|
|
1392
|
-
logger.debug(`[Agent] Set pending
|
|
1608
|
+
logger.debug(`[Agent] Set pending transition to route: ${targetRoute.title}`);
|
|
1393
1609
|
return updatedSession;
|
|
1394
1610
|
}
|
|
1395
1611
|
/**
|
|
@@ -1411,7 +1627,14 @@ export class Agent {
|
|
|
1411
1627
|
history = this.session.getHistory();
|
|
1412
1628
|
}
|
|
1413
1629
|
// Get or create session
|
|
1414
|
-
|
|
1630
|
+
let session = await this.session.getOrCreate();
|
|
1631
|
+
// Merge agent's collected data into session (agent data takes precedence)
|
|
1632
|
+
if (Object.keys(this.collectedData).length > 0) {
|
|
1633
|
+
session = mergeCollected(session, this.collectedData);
|
|
1634
|
+
// Update the session manager with the merged data
|
|
1635
|
+
await this.session.setData(this.collectedData);
|
|
1636
|
+
logger.debug("[Agent] Merged agent collected data into chat session:", this.collectedData);
|
|
1637
|
+
}
|
|
1415
1638
|
// Use existing respond method with session-managed history
|
|
1416
1639
|
const result = await this.respond({
|
|
1417
1640
|
history,
|
|
@@ -1423,7 +1646,11 @@ export class Agent {
|
|
|
1423
1646
|
if (!options?.history) {
|
|
1424
1647
|
await this.session.addMessage("assistant", result.message);
|
|
1425
1648
|
}
|
|
1426
|
-
|
|
1649
|
+
// Ensure the result includes the current session
|
|
1650
|
+
return {
|
|
1651
|
+
...result,
|
|
1652
|
+
session: result.session || this.session.current,
|
|
1653
|
+
};
|
|
1427
1654
|
}
|
|
1428
1655
|
}
|
|
1429
1656
|
//# sourceMappingURL=Agent.js.map
|