@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/src/core/Agent.ts
CHANGED
|
@@ -17,6 +17,8 @@ import type {
|
|
|
17
17
|
AgentResponseStreamChunk,
|
|
18
18
|
AgentResponse,
|
|
19
19
|
StructuredSchema,
|
|
20
|
+
ValidationError,
|
|
21
|
+
ValidationResult,
|
|
20
22
|
} from "../types";
|
|
21
23
|
import { EventKind, MessageRole } from "../types/history";
|
|
22
24
|
import {
|
|
@@ -42,26 +44,48 @@ import { ResponsePipeline } from "./ResponsePipeline";
|
|
|
42
44
|
import { END_ROUTE_ID } from "../constants";
|
|
43
45
|
|
|
44
46
|
/**
|
|
45
|
-
*
|
|
47
|
+
* Error thrown when data validation fails
|
|
46
48
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
class DataValidationError extends Error {
|
|
50
|
+
constructor(public errors: ValidationError[], message?: string) {
|
|
51
|
+
super(message || "Data validation failed");
|
|
52
|
+
this.name = "DataValidationError";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Error thrown when route configuration is invalid
|
|
58
|
+
*/
|
|
59
|
+
class RouteConfigurationError extends Error {
|
|
60
|
+
constructor(public routeTitle: string, public invalidFields: string[], message?: string) {
|
|
61
|
+
super(message || `Route configuration error in '${routeTitle}'`);
|
|
62
|
+
this.name = "RouteConfigurationError";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Main Agent class with generic context and data support
|
|
68
|
+
*/
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
|
+
export class Agent<TContext = any, TData = any> {
|
|
71
|
+
private terms: Term<TContext, TData>[] = [];
|
|
72
|
+
private guidelines: Guideline<TContext, TData>[] = [];
|
|
73
|
+
private tools: Tool<TContext, TData, unknown[], unknown>[] = [];
|
|
74
|
+
private routes: Route<TContext, TData>[] = [];
|
|
53
75
|
private context: TContext | undefined;
|
|
54
|
-
private persistenceManager: PersistenceManager | undefined;
|
|
55
|
-
private routingEngine: RoutingEngine<TContext>;
|
|
56
|
-
private responseEngine: ResponseEngine<TContext>;
|
|
57
|
-
private responsePipeline: ResponsePipeline<TContext>;
|
|
58
|
-
private currentSession?: SessionState
|
|
76
|
+
private persistenceManager: PersistenceManager<TData> | undefined;
|
|
77
|
+
private routingEngine: RoutingEngine<TContext, TData>;
|
|
78
|
+
private responseEngine: ResponseEngine<TContext, TData>;
|
|
79
|
+
private responsePipeline: ResponsePipeline<TContext, TData>;
|
|
80
|
+
private currentSession?: SessionState<TData>;
|
|
59
81
|
private knowledgeBase: Record<string, unknown> = {};
|
|
82
|
+
private schema?: StructuredSchema;
|
|
83
|
+
private collectedData: Partial<TData> = {};
|
|
60
84
|
|
|
61
85
|
/** Public session manager for easy session management */
|
|
62
|
-
public session: SessionManager<
|
|
86
|
+
public session: SessionManager<TData>;
|
|
63
87
|
|
|
64
|
-
constructor(private readonly options: AgentOptions<TContext>) {
|
|
88
|
+
constructor(private readonly options: AgentOptions<TContext, TData>) {
|
|
65
89
|
// Set log level based on debug option
|
|
66
90
|
if (options.debug) {
|
|
67
91
|
logger.setLevel(LoggerLevel.DEBUG);
|
|
@@ -74,40 +98,81 @@ export class Agent<TContext = unknown> {
|
|
|
74
98
|
);
|
|
75
99
|
}
|
|
76
100
|
|
|
101
|
+
// Initialize and validate agent-level schema if provided
|
|
102
|
+
if (options.schema) {
|
|
103
|
+
this.schema = options.schema;
|
|
104
|
+
this.validateSchema(this.schema);
|
|
105
|
+
logger.debug("[Agent] Agent-level schema initialized and validated");
|
|
106
|
+
}
|
|
107
|
+
|
|
77
108
|
// Initialize context if provided
|
|
78
109
|
this.context = options.context;
|
|
79
110
|
|
|
111
|
+
// Initialize collected data with initial data if provided
|
|
112
|
+
if (options.initialData) {
|
|
113
|
+
if (this.schema) {
|
|
114
|
+
const validation = this.validateData(options.initialData);
|
|
115
|
+
if (!validation.valid) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Initial data validation failed: ${validation.errors.map(e => e.message).join(', ')}`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
this.collectedData = { ...options.initialData };
|
|
122
|
+
logger.debug("[Agent] Initial data set:", this.collectedData);
|
|
123
|
+
}
|
|
124
|
+
|
|
80
125
|
// Initialize current session if provided
|
|
81
126
|
this.currentSession = options.session;
|
|
82
127
|
|
|
83
128
|
// Initialize routing and response engines
|
|
84
|
-
this.routingEngine = new RoutingEngine<TContext>({
|
|
129
|
+
this.routingEngine = new RoutingEngine<TContext, TData>({
|
|
85
130
|
maxCandidates: 5,
|
|
86
131
|
allowRouteSwitch: true,
|
|
87
132
|
switchThreshold: 70,
|
|
88
133
|
});
|
|
89
|
-
this.responseEngine = new ResponseEngine<TContext>();
|
|
90
|
-
this.responsePipeline = new ResponsePipeline<TContext>(
|
|
134
|
+
this.responseEngine = new ResponseEngine<TContext, TData>();
|
|
135
|
+
this.responsePipeline = new ResponsePipeline<TContext, TData>(
|
|
91
136
|
options,
|
|
92
137
|
this.routes,
|
|
93
138
|
this.tools,
|
|
94
139
|
this.routingEngine,
|
|
95
140
|
this.updateContext.bind(this),
|
|
96
|
-
this.updateData.bind(this)
|
|
141
|
+
this.updateData.bind(this),
|
|
142
|
+
this.updateCollectedData.bind(this)
|
|
97
143
|
);
|
|
98
144
|
|
|
99
145
|
// Initialize persistence if configured
|
|
100
146
|
if (options.persistence) {
|
|
101
|
-
|
|
147
|
+
try {
|
|
148
|
+
// Validate persistence configuration
|
|
149
|
+
if (!options.persistence.adapter) {
|
|
150
|
+
throw new Error("Persistence adapter is required when persistence is configured");
|
|
151
|
+
}
|
|
102
152
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
153
|
+
if (!options.persistence.adapter.sessionRepository) {
|
|
154
|
+
throw new Error("Persistence adapter must provide a sessionRepository");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!options.persistence.adapter.messageRepository) {
|
|
158
|
+
throw new Error("Persistence adapter must provide a messageRepository");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
this.persistenceManager = new PersistenceManager<TData>(options.persistence);
|
|
162
|
+
|
|
163
|
+
// Initialize the adapter if it has an initialize method
|
|
164
|
+
if (options.persistence.adapter.initialize) {
|
|
165
|
+
options.persistence.adapter.initialize().catch((error) => {
|
|
166
|
+
logger.error(
|
|
167
|
+
"[Agent] Persistence adapter initialization failed:",
|
|
168
|
+
error instanceof Error ? error.message : String(error)
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
} catch (error) {
|
|
173
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
174
|
+
logger.error("[Agent] Failed to initialize persistence:", errorMessage);
|
|
175
|
+
throw new Error(`Failed to initialize persistence: ${errorMessage}`);
|
|
111
176
|
}
|
|
112
177
|
}
|
|
113
178
|
|
|
@@ -132,7 +197,7 @@ export class Agent<TContext = unknown> {
|
|
|
132
197
|
|
|
133
198
|
if (options.routes) {
|
|
134
199
|
options.routes.forEach((routeOptions) => {
|
|
135
|
-
this.createRoute
|
|
200
|
+
this.createRoute(routeOptions);
|
|
136
201
|
});
|
|
137
202
|
}
|
|
138
203
|
|
|
@@ -142,7 +207,7 @@ export class Agent<TContext = unknown> {
|
|
|
142
207
|
}
|
|
143
208
|
|
|
144
209
|
// Initialize session manager
|
|
145
|
-
this.session = new SessionManager(this.persistenceManager);
|
|
210
|
+
this.session = new SessionManager<TData>(this.persistenceManager);
|
|
146
211
|
|
|
147
212
|
// Store sessionId for later use in getOrCreate calls
|
|
148
213
|
if (options.sessionId) {
|
|
@@ -153,6 +218,143 @@ export class Agent<TContext = unknown> {
|
|
|
153
218
|
}
|
|
154
219
|
}
|
|
155
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Validate the agent-level schema structure
|
|
223
|
+
* @private
|
|
224
|
+
*/
|
|
225
|
+
private validateSchema(schema: StructuredSchema): void {
|
|
226
|
+
if (!schema || typeof schema !== 'object') {
|
|
227
|
+
throw new Error(
|
|
228
|
+
"Agent schema must be a valid JSON Schema object. " +
|
|
229
|
+
"Provide a schema with 'type': 'object' and 'properties' to define the data structure."
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (schema.type !== 'object') {
|
|
234
|
+
throw new Error(
|
|
235
|
+
`Agent schema must be of type 'object', but received '${String(schema.type)}'. ` +
|
|
236
|
+
"Agent-level schemas must define object structures for data collection."
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (!schema.properties || typeof schema.properties !== 'object') {
|
|
241
|
+
throw new Error(
|
|
242
|
+
"Agent schema must have a 'properties' field defining the data fields. " +
|
|
243
|
+
"Example: { type: 'object', properties: { name: { type: 'string' }, email: { type: 'string' } } }"
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
logger.debug("[Agent] Schema validation passed");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Validate data against the agent-level schema
|
|
252
|
+
*/
|
|
253
|
+
validateData(data: Partial<TData>): ValidationResult {
|
|
254
|
+
if (!this.schema) {
|
|
255
|
+
// No schema defined, consider all data valid
|
|
256
|
+
return { valid: true, errors: [], warnings: [] };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const errors: ValidationError[] = [];
|
|
260
|
+
const warnings: ValidationError[] = [];
|
|
261
|
+
|
|
262
|
+
// Basic validation - check if provided fields exist in schema
|
|
263
|
+
if (this.schema.properties) {
|
|
264
|
+
for (const [key, value] of Object.entries(data)) {
|
|
265
|
+
if (!(key in this.schema.properties)) {
|
|
266
|
+
errors.push({
|
|
267
|
+
field: key,
|
|
268
|
+
value,
|
|
269
|
+
message: `Field '${key}' is not defined in agent schema`,
|
|
270
|
+
schemaPath: `properties.${key}`
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Check required fields if specified
|
|
277
|
+
if (this.schema.required && Array.isArray(this.schema.required)) {
|
|
278
|
+
for (const requiredField of this.schema.required) {
|
|
279
|
+
if (!(requiredField in data) || data[requiredField as keyof TData] === undefined) {
|
|
280
|
+
warnings.push({
|
|
281
|
+
field: requiredField,
|
|
282
|
+
value: undefined,
|
|
283
|
+
message: `Required field '${requiredField}' is missing`,
|
|
284
|
+
schemaPath: `required`
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
valid: errors.length === 0,
|
|
292
|
+
errors,
|
|
293
|
+
warnings
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Check if a field is valid according to the agent schema
|
|
299
|
+
* @param field - The field key to validate
|
|
300
|
+
* @returns true if field exists in schema or no schema is defined, false otherwise
|
|
301
|
+
*/
|
|
302
|
+
isValidSchemaField(field: keyof TData): boolean {
|
|
303
|
+
if (!this.schema || !this.schema.properties) {
|
|
304
|
+
// No schema defined, consider all fields valid
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return field as string in this.schema.properties;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Get the current collected data
|
|
313
|
+
*/
|
|
314
|
+
getCollectedData(): Partial<TData> {
|
|
315
|
+
return { ...this.collectedData };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Update collected data with validation
|
|
320
|
+
*/
|
|
321
|
+
async updateCollectedData(updates: Partial<TData>): Promise<void> {
|
|
322
|
+
// Validate the updates
|
|
323
|
+
const validation = this.validateData(updates);
|
|
324
|
+
if (!validation.valid) {
|
|
325
|
+
const errorMessages = validation.errors.map(e => e.message).join(', ');
|
|
326
|
+
throw new DataValidationError(validation.errors, `Data validation failed: ${errorMessages}`);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Log warnings if any
|
|
330
|
+
if (validation.warnings.length > 0) {
|
|
331
|
+
const warningMessages = validation.warnings.map(w => w.message).join(', ');
|
|
332
|
+
logger.warn(`[Agent] Data validation warnings: ${warningMessages}`);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Merge updates with current data
|
|
336
|
+
const previousData = { ...this.collectedData };
|
|
337
|
+
this.collectedData = {
|
|
338
|
+
...this.collectedData,
|
|
339
|
+
...updates
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// Trigger agent-level lifecycle hook if configured
|
|
343
|
+
if (this.options.hooks?.onDataUpdate) {
|
|
344
|
+
this.collectedData = await this.options.hooks.onDataUpdate(
|
|
345
|
+
this.collectedData,
|
|
346
|
+
previousData
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Update current session if it exists to keep it in sync
|
|
351
|
+
if (this.currentSession) {
|
|
352
|
+
this.currentSession = mergeCollected(this.currentSession, this.collectedData);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
logger.debug("[Agent] Collected data updated:", updates);
|
|
356
|
+
}
|
|
357
|
+
|
|
156
358
|
/**
|
|
157
359
|
* Get agent name
|
|
158
360
|
*/
|
|
@@ -182,12 +384,41 @@ export class Agent<TContext = unknown> {
|
|
|
182
384
|
}
|
|
183
385
|
|
|
184
386
|
/**
|
|
185
|
-
* Create a new route (journey)
|
|
186
|
-
* @template TData - Type of data collected throughout the route
|
|
387
|
+
* Create a new route (journey) using agent-level data type
|
|
187
388
|
*/
|
|
188
|
-
createRoute
|
|
389
|
+
createRoute(
|
|
189
390
|
options: RouteOptions<TContext, TData>
|
|
190
391
|
): Route<TContext, TData> {
|
|
392
|
+
// Validate that requiredFields exist in agent schema
|
|
393
|
+
if (options.requiredFields && this.schema?.properties) {
|
|
394
|
+
const invalidRequiredFields = options.requiredFields.filter(
|
|
395
|
+
field => !(String(field) in this.schema!.properties!)
|
|
396
|
+
);
|
|
397
|
+
if (invalidRequiredFields.length > 0) {
|
|
398
|
+
throw new RouteConfigurationError(
|
|
399
|
+
options.title,
|
|
400
|
+
invalidRequiredFields.map(f => String(f)),
|
|
401
|
+
`Invalid required fields in route '${options.title}': ${invalidRequiredFields.join(', ')}. ` +
|
|
402
|
+
`Must be valid keys from agent schema. Available fields: ${Object.keys(this.schema.properties).join(', ')}.`
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Validate that optionalFields exist in agent schema
|
|
408
|
+
if (options.optionalFields && this.schema?.properties) {
|
|
409
|
+
const invalidOptionalFields = options.optionalFields.filter(
|
|
410
|
+
field => !(String(field) in this.schema!.properties!)
|
|
411
|
+
);
|
|
412
|
+
if (invalidOptionalFields.length > 0) {
|
|
413
|
+
throw new RouteConfigurationError(
|
|
414
|
+
options.title,
|
|
415
|
+
invalidOptionalFields.map(f => String(f)),
|
|
416
|
+
`Invalid optional fields in route '${options.title}': ${invalidOptionalFields.join(', ')}. ` +
|
|
417
|
+
`Must be valid keys from agent schema. Available fields: ${Object.keys(this.schema.properties).join(', ')}.`
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
191
422
|
const route = new Route<TContext, TData>(options);
|
|
192
423
|
this.routes.push(route);
|
|
193
424
|
return route;
|
|
@@ -196,7 +427,7 @@ export class Agent<TContext = unknown> {
|
|
|
196
427
|
/**
|
|
197
428
|
* Create a domain term for the glossary
|
|
198
429
|
*/
|
|
199
|
-
createTerm(term: Term<TContext>): this {
|
|
430
|
+
createTerm(term: Term<TContext, TData>): this {
|
|
200
431
|
this.terms.push(term);
|
|
201
432
|
return this;
|
|
202
433
|
}
|
|
@@ -204,7 +435,7 @@ export class Agent<TContext = unknown> {
|
|
|
204
435
|
/**
|
|
205
436
|
* Create a behavioral guideline
|
|
206
437
|
*/
|
|
207
|
-
createGuideline(guideline: Guideline<TContext>): this {
|
|
438
|
+
createGuideline(guideline: Guideline<TContext, TData>): this {
|
|
208
439
|
const guidelineWithId = {
|
|
209
440
|
...guideline,
|
|
210
441
|
id: guideline.id || `guideline_${this.guidelines.length}`,
|
|
@@ -217,7 +448,7 @@ export class Agent<TContext = unknown> {
|
|
|
217
448
|
/**
|
|
218
449
|
* Register a tool at the agent level
|
|
219
450
|
*/
|
|
220
|
-
createTool(tool: Tool<TContext, unknown[], unknown
|
|
451
|
+
createTool(tool: Tool<TContext, TData, unknown[], unknown>): this {
|
|
221
452
|
this.tools.push(tool);
|
|
222
453
|
return this;
|
|
223
454
|
}
|
|
@@ -225,7 +456,7 @@ export class Agent<TContext = unknown> {
|
|
|
225
456
|
/**
|
|
226
457
|
* Register multiple tools at the agent level
|
|
227
458
|
*/
|
|
228
|
-
registerTools(tools: Tool<TContext, unknown[], unknown
|
|
459
|
+
registerTools(tools: Tool<TContext, TData, unknown[], unknown>[]): this {
|
|
229
460
|
tools.forEach((tool) => this.createTool(tool));
|
|
230
461
|
return this;
|
|
231
462
|
}
|
|
@@ -267,7 +498,7 @@ export class Agent<TContext = unknown> {
|
|
|
267
498
|
* Triggers both agent-level and route-specific onDataUpdate lifecycle hooks if configured
|
|
268
499
|
* @internal
|
|
269
500
|
*/
|
|
270
|
-
private async updateData
|
|
501
|
+
private async updateData(
|
|
271
502
|
session: SessionState<TData>,
|
|
272
503
|
dataUpdate: Partial<TData>
|
|
273
504
|
): Promise<SessionState<TData>> {
|
|
@@ -297,9 +528,12 @@ export class Agent<TContext = unknown> {
|
|
|
297
528
|
newCollected = (await this.options.hooks.onDataUpdate(
|
|
298
529
|
newCollected,
|
|
299
530
|
previousCollected
|
|
300
|
-
))
|
|
531
|
+
));
|
|
301
532
|
}
|
|
302
533
|
|
|
534
|
+
// Update agent's collected data to stay in sync
|
|
535
|
+
this.collectedData = { ...newCollected };
|
|
536
|
+
|
|
303
537
|
// Return updated session
|
|
304
538
|
return mergeCollected(session, newCollected);
|
|
305
539
|
}
|
|
@@ -316,11 +550,17 @@ export class Agent<TContext = unknown> {
|
|
|
316
550
|
// Otherwise return the stored context
|
|
317
551
|
return this.context;
|
|
318
552
|
}
|
|
553
|
+
/**
|
|
554
|
+
* Get current schema
|
|
555
|
+
*/
|
|
556
|
+
getSchema(): StructuredSchema | undefined {
|
|
557
|
+
return this.schema;
|
|
558
|
+
}
|
|
319
559
|
|
|
320
560
|
/**
|
|
321
561
|
* Generate a response based on history and context as a stream
|
|
322
562
|
*/
|
|
323
|
-
async *respondStream
|
|
563
|
+
async *respondStream(params: {
|
|
324
564
|
history: History;
|
|
325
565
|
step?: StepRef;
|
|
326
566
|
session?: SessionState<TData>;
|
|
@@ -340,6 +580,13 @@ export class Agent<TContext = unknown> {
|
|
|
340
580
|
});
|
|
341
581
|
const { effectiveContext } = responseContext;
|
|
342
582
|
session = responseContext.session;
|
|
583
|
+
|
|
584
|
+
// Merge agent's collected data into session (agent data takes precedence)
|
|
585
|
+
if (Object.keys(this.collectedData).length > 0) {
|
|
586
|
+
session = mergeCollected(session, this.collectedData);
|
|
587
|
+
logger.debug("[Agent] Merged agent collected data into session:", this.collectedData);
|
|
588
|
+
}
|
|
589
|
+
|
|
343
590
|
// Update our stored context if it was modified by beforeRespond hook
|
|
344
591
|
this.context = this.responsePipeline.getStoredContext();
|
|
345
592
|
|
|
@@ -395,7 +642,8 @@ export class Agent<TContext = unknown> {
|
|
|
395
642
|
// Build response schema for this route (with collect fields from step)
|
|
396
643
|
const responseSchema = this.responseEngine.responseSchemaForRoute(
|
|
397
644
|
selectedRoute,
|
|
398
|
-
nextStep
|
|
645
|
+
nextStep,
|
|
646
|
+
this.schema
|
|
399
647
|
);
|
|
400
648
|
|
|
401
649
|
// Check if selected route and next step are defined
|
|
@@ -428,6 +676,7 @@ export class Agent<TContext = unknown> {
|
|
|
428
676
|
),
|
|
429
677
|
context: effectiveContext,
|
|
430
678
|
session,
|
|
679
|
+
agentSchema: this.schema,
|
|
431
680
|
});
|
|
432
681
|
|
|
433
682
|
// Collect available tools for AI
|
|
@@ -475,11 +724,12 @@ export class Agent<TContext = unknown> {
|
|
|
475
724
|
continue;
|
|
476
725
|
}
|
|
477
726
|
|
|
478
|
-
const toolExecutor = new ToolExecutor<TContext,
|
|
727
|
+
const toolExecutor = new ToolExecutor<TContext, TData>();
|
|
479
728
|
const result = await toolExecutor.executeTool({
|
|
480
729
|
tool: tool,
|
|
481
730
|
context: effectiveContext,
|
|
482
731
|
updateContext: this.updateContext.bind(this),
|
|
732
|
+
updateData: this.updateCollectedData.bind(this),
|
|
483
733
|
history,
|
|
484
734
|
data: session.data,
|
|
485
735
|
toolArguments: toolCall.arguments,
|
|
@@ -494,7 +744,7 @@ export class Agent<TContext = unknown> {
|
|
|
494
744
|
|
|
495
745
|
// Update collected data with tool results
|
|
496
746
|
if (result.dataUpdate) {
|
|
497
|
-
session = await this.updateData(session, result.dataUpdate);
|
|
747
|
+
session = await this.updateData(session, result.dataUpdate as Partial<TData>);
|
|
498
748
|
logger.debug(
|
|
499
749
|
`[Agent] Tool updated collected data:`,
|
|
500
750
|
result.dataUpdate
|
|
@@ -577,8 +827,7 @@ export class Agent<TContext = unknown> {
|
|
|
577
827
|
|
|
578
828
|
if (hasToolCalls) {
|
|
579
829
|
logger.debug(
|
|
580
|
-
`[Agent] Follow-up streaming call produced ${
|
|
581
|
-
followUpToolCalls!.length
|
|
830
|
+
`[Agent] Follow-up streaming call produced ${followUpToolCalls!.length
|
|
582
831
|
} additional tool calls`
|
|
583
832
|
);
|
|
584
833
|
|
|
@@ -595,11 +844,12 @@ export class Agent<TContext = unknown> {
|
|
|
595
844
|
continue;
|
|
596
845
|
}
|
|
597
846
|
|
|
598
|
-
const toolExecutor = new ToolExecutor<TContext,
|
|
847
|
+
const toolExecutor = new ToolExecutor<TContext, TData>();
|
|
599
848
|
const result = await toolExecutor.executeTool({
|
|
600
849
|
tool: tool,
|
|
601
850
|
context: effectiveContext,
|
|
602
851
|
updateContext: this.updateContext.bind(this),
|
|
852
|
+
updateData: this.updateCollectedData.bind(this),
|
|
603
853
|
history: updatedHistory,
|
|
604
854
|
data: session.data,
|
|
605
855
|
toolArguments: toolCall.arguments,
|
|
@@ -613,7 +863,7 @@ export class Agent<TContext = unknown> {
|
|
|
613
863
|
}
|
|
614
864
|
|
|
615
865
|
if (result.dataUpdate) {
|
|
616
|
-
session = await this.updateData(session, result.dataUpdate);
|
|
866
|
+
session = await this.updateData(session, result.dataUpdate as Partial<TData>);
|
|
617
867
|
logger.debug(
|
|
618
868
|
`[Agent] Streaming follow-up tool updated collected data:`,
|
|
619
869
|
result.dataUpdate
|
|
@@ -651,14 +901,19 @@ export class Agent<TContext = unknown> {
|
|
|
651
901
|
Record<string, unknown>;
|
|
652
902
|
|
|
653
903
|
for (const field of nextStep.collect) {
|
|
654
|
-
|
|
655
|
-
|
|
904
|
+
const fieldKey = String(field);
|
|
905
|
+
if (fieldKey in structuredData) {
|
|
906
|
+
collectedData[fieldKey] = structuredData[fieldKey];
|
|
656
907
|
}
|
|
657
908
|
}
|
|
658
909
|
|
|
659
|
-
// Merge collected data into session
|
|
910
|
+
// Merge collected data into session using agent-level data validation
|
|
660
911
|
if (Object.keys(collectedData).length > 0) {
|
|
661
|
-
|
|
912
|
+
// Update agent-level collected data with validation
|
|
913
|
+
await this.updateCollectedData(collectedData as Partial<TData>);
|
|
914
|
+
|
|
915
|
+
// Update session with validated data
|
|
916
|
+
session = await this.updateData(session, collectedData as Partial<TData>);
|
|
662
917
|
logger.debug(`[Agent] Collected data:`, collectedData);
|
|
663
918
|
}
|
|
664
919
|
}
|
|
@@ -735,7 +990,7 @@ export class Agent<TContext = unknown> {
|
|
|
735
990
|
const endStepSpec = selectedRoute.endStepSpec;
|
|
736
991
|
|
|
737
992
|
// Create a temporary step for completion message generation using endStep configuration
|
|
738
|
-
const completionStep = new Step<TContext,
|
|
993
|
+
const completionStep = new Step<TContext, TData>(selectedRoute.id, {
|
|
739
994
|
description: endStepSpec.description,
|
|
740
995
|
id: endStepSpec.id || END_ROUTE_ID,
|
|
741
996
|
collect: endStepSpec.collect,
|
|
@@ -748,7 +1003,8 @@ export class Agent<TContext = unknown> {
|
|
|
748
1003
|
// Build response schema for completion
|
|
749
1004
|
const responseSchema = this.responseEngine.responseSchemaForRoute(
|
|
750
1005
|
selectedRoute,
|
|
751
|
-
completionStep
|
|
1006
|
+
completionStep,
|
|
1007
|
+
this.schema
|
|
752
1008
|
);
|
|
753
1009
|
const templateContext = {
|
|
754
1010
|
context: effectiveContext,
|
|
@@ -777,6 +1033,7 @@ export class Agent<TContext = unknown> {
|
|
|
777
1033
|
),
|
|
778
1034
|
context: effectiveContext,
|
|
779
1035
|
session,
|
|
1036
|
+
agentSchema: this.schema,
|
|
780
1037
|
});
|
|
781
1038
|
|
|
782
1039
|
// Stream completion message using AI provider
|
|
@@ -909,7 +1166,7 @@ export class Agent<TContext = unknown> {
|
|
|
909
1166
|
/**
|
|
910
1167
|
* Generate a response based on history and context
|
|
911
1168
|
*/
|
|
912
|
-
async respond
|
|
1169
|
+
async respond(params: {
|
|
913
1170
|
history: History;
|
|
914
1171
|
step?: StepRef;
|
|
915
1172
|
session?: SessionState<TData>;
|
|
@@ -941,6 +1198,12 @@ export class Agent<TContext = unknown> {
|
|
|
941
1198
|
cloneDeep(this.currentSession) ||
|
|
942
1199
|
(await this.session.getOrCreate());
|
|
943
1200
|
|
|
1201
|
+
// Merge agent's collected data into session (agent data takes precedence)
|
|
1202
|
+
if (Object.keys(this.collectedData).length > 0) {
|
|
1203
|
+
session = mergeCollected(session, this.collectedData);
|
|
1204
|
+
logger.debug("[Agent] Merged agent collected data into session:", this.collectedData);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
944
1207
|
// PHASE 1: PREPARE - Execute prepare function if current step has one
|
|
945
1208
|
if (session.currentRoute && session.currentStep) {
|
|
946
1209
|
const currentRoute = this.routes.find(
|
|
@@ -962,9 +1225,9 @@ export class Agent<TContext = unknown> {
|
|
|
962
1225
|
}
|
|
963
1226
|
|
|
964
1227
|
// PHASE 2: ROUTING + STEP SELECTION - Determine which route and step to use (combined)
|
|
965
|
-
let selectedRoute: Route<TContext,
|
|
1228
|
+
let selectedRoute: Route<TContext, TData> | undefined;
|
|
966
1229
|
let responseDirectives: string[] | undefined;
|
|
967
|
-
let selectedStep: Step<TContext,
|
|
1230
|
+
let selectedStep: Step<TContext, TData> | undefined;
|
|
968
1231
|
let isRouteComplete = false;
|
|
969
1232
|
|
|
970
1233
|
// Check for pending transition from previous route completion
|
|
@@ -1034,9 +1297,14 @@ export class Agent<TContext = unknown> {
|
|
|
1034
1297
|
| Array<{ toolName: string; arguments: Record<string, unknown> }>
|
|
1035
1298
|
| undefined = undefined;
|
|
1036
1299
|
let responsePrompt: string;
|
|
1037
|
-
let availableTools:
|
|
1300
|
+
let availableTools: Array<{
|
|
1301
|
+
id: string;
|
|
1302
|
+
name: string;
|
|
1303
|
+
description?: string;
|
|
1304
|
+
parameters?: unknown;
|
|
1305
|
+
}> = [];
|
|
1038
1306
|
let responseSchema: StructuredSchema | undefined;
|
|
1039
|
-
let nextStep: Step<TContext,
|
|
1307
|
+
let nextStep: Step<TContext, TData> | undefined;
|
|
1040
1308
|
|
|
1041
1309
|
// Get last user message (needed for both route and completion handling)
|
|
1042
1310
|
const lastUserMessage = getLastMessageFromHistory(history);
|
|
@@ -1077,7 +1345,8 @@ export class Agent<TContext = unknown> {
|
|
|
1077
1345
|
// Build response schema for this route (with collect fields from step)
|
|
1078
1346
|
responseSchema = this.responseEngine.responseSchemaForRoute(
|
|
1079
1347
|
selectedRoute,
|
|
1080
|
-
nextStep
|
|
1348
|
+
nextStep,
|
|
1349
|
+
this.schema
|
|
1081
1350
|
);
|
|
1082
1351
|
|
|
1083
1352
|
// Build response prompt
|
|
@@ -1101,13 +1370,14 @@ export class Agent<TContext = unknown> {
|
|
|
1101
1370
|
),
|
|
1102
1371
|
context: effectiveContext,
|
|
1103
1372
|
session,
|
|
1373
|
+
agentSchema: this.schema,
|
|
1104
1374
|
});
|
|
1105
1375
|
|
|
1106
1376
|
// Collect available tools for AI
|
|
1107
1377
|
availableTools = this.collectAvailableTools(
|
|
1108
1378
|
selectedRoute,
|
|
1109
1379
|
nextStep
|
|
1110
|
-
)
|
|
1380
|
+
);
|
|
1111
1381
|
} else {
|
|
1112
1382
|
// No route selected - generate basic response without route context
|
|
1113
1383
|
logger.debug(`[Agent] No route selected, generating basic response`);
|
|
@@ -1123,7 +1393,7 @@ export class Agent<TContext = unknown> {
|
|
|
1123
1393
|
});
|
|
1124
1394
|
|
|
1125
1395
|
// Use agent-level tools only
|
|
1126
|
-
availableTools =
|
|
1396
|
+
availableTools = this.collectAvailableTools();
|
|
1127
1397
|
responseSchema = undefined;
|
|
1128
1398
|
}
|
|
1129
1399
|
|
|
@@ -1136,9 +1406,9 @@ export class Agent<TContext = unknown> {
|
|
|
1136
1406
|
signal,
|
|
1137
1407
|
parameters: responseSchema
|
|
1138
1408
|
? {
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1409
|
+
jsonSchema: responseSchema,
|
|
1410
|
+
schemaName: "response_output",
|
|
1411
|
+
}
|
|
1142
1412
|
: undefined,
|
|
1143
1413
|
});
|
|
1144
1414
|
|
|
@@ -1161,11 +1431,12 @@ export class Agent<TContext = unknown> {
|
|
|
1161
1431
|
continue;
|
|
1162
1432
|
}
|
|
1163
1433
|
|
|
1164
|
-
const toolExecutor = new ToolExecutor<TContext,
|
|
1434
|
+
const toolExecutor = new ToolExecutor<TContext, TData>();
|
|
1165
1435
|
const toolResult = await toolExecutor.executeTool({
|
|
1166
1436
|
tool: tool,
|
|
1167
1437
|
context: effectiveContext,
|
|
1168
1438
|
updateContext: this.updateContext.bind(this),
|
|
1439
|
+
updateData: this.updateCollectedData.bind(this),
|
|
1169
1440
|
history,
|
|
1170
1441
|
data: session.data,
|
|
1171
1442
|
toolArguments: toolCall.arguments,
|
|
@@ -1180,7 +1451,7 @@ export class Agent<TContext = unknown> {
|
|
|
1180
1451
|
|
|
1181
1452
|
// Update collected data with tool results
|
|
1182
1453
|
if (toolResult.dataUpdate) {
|
|
1183
|
-
session = await this.updateData(session, toolResult.dataUpdate);
|
|
1454
|
+
session = await this.updateData(session, toolResult.dataUpdate as Partial<TData>);
|
|
1184
1455
|
logger.debug(
|
|
1185
1456
|
`[Agent] Tool updated collected data:`,
|
|
1186
1457
|
toolResult.dataUpdate
|
|
@@ -1251,8 +1522,7 @@ export class Agent<TContext = unknown> {
|
|
|
1251
1522
|
|
|
1252
1523
|
if (hasToolCalls) {
|
|
1253
1524
|
logger.debug(
|
|
1254
|
-
`[Agent] Follow-up call produced ${
|
|
1255
|
-
followUpToolCalls!.length
|
|
1525
|
+
`[Agent] Follow-up call produced ${followUpToolCalls!.length
|
|
1256
1526
|
} additional tool calls`
|
|
1257
1527
|
);
|
|
1258
1528
|
|
|
@@ -1266,11 +1536,12 @@ export class Agent<TContext = unknown> {
|
|
|
1266
1536
|
continue;
|
|
1267
1537
|
}
|
|
1268
1538
|
|
|
1269
|
-
const toolExecutor = new ToolExecutor<TContext,
|
|
1539
|
+
const toolExecutor = new ToolExecutor<TContext, TData>();
|
|
1270
1540
|
const toolResult = await toolExecutor.executeTool({
|
|
1271
1541
|
tool: tool,
|
|
1272
1542
|
context: effectiveContext,
|
|
1273
1543
|
updateContext: this.updateContext.bind(this),
|
|
1544
|
+
updateData: this.updateCollectedData.bind(this),
|
|
1274
1545
|
history: updatedHistory,
|
|
1275
1546
|
data: session.data,
|
|
1276
1547
|
toolArguments: toolCall.arguments,
|
|
@@ -1284,7 +1555,7 @@ export class Agent<TContext = unknown> {
|
|
|
1284
1555
|
}
|
|
1285
1556
|
|
|
1286
1557
|
if (toolResult.dataUpdate) {
|
|
1287
|
-
session = await this.updateData(session, toolResult.dataUpdate);
|
|
1558
|
+
session = await this.updateData(session, toolResult.dataUpdate as Partial<TData>);
|
|
1288
1559
|
logger.debug(
|
|
1289
1560
|
`[Agent] Follow-up tool updated collected data:`,
|
|
1290
1561
|
toolResult.dataUpdate
|
|
@@ -1323,14 +1594,19 @@ export class Agent<TContext = unknown> {
|
|
|
1323
1594
|
Record<string, unknown>;
|
|
1324
1595
|
|
|
1325
1596
|
for (const field of nextStep.collect) {
|
|
1326
|
-
|
|
1327
|
-
|
|
1597
|
+
const fieldKey = String(field);
|
|
1598
|
+
if (fieldKey in structuredData) {
|
|
1599
|
+
collectedData[fieldKey] = structuredData[fieldKey];
|
|
1328
1600
|
}
|
|
1329
1601
|
}
|
|
1330
1602
|
|
|
1331
|
-
// Merge collected data into session
|
|
1603
|
+
// Merge collected data into session using agent-level data validation
|
|
1332
1604
|
if (Object.keys(collectedData).length > 0) {
|
|
1333
|
-
|
|
1605
|
+
// Update agent-level collected data with validation
|
|
1606
|
+
await this.updateCollectedData(collectedData as Partial<TData>);
|
|
1607
|
+
|
|
1608
|
+
// Update session with validated data
|
|
1609
|
+
session = await this.updateData(session, collectedData as Partial<TData>);
|
|
1334
1610
|
logger.debug(`[Agent] Collected data:`, collectedData);
|
|
1335
1611
|
}
|
|
1336
1612
|
}
|
|
@@ -1355,7 +1631,7 @@ export class Agent<TContext = unknown> {
|
|
|
1355
1631
|
const endStepSpec = selectedRoute!.endStepSpec;
|
|
1356
1632
|
|
|
1357
1633
|
// Create a temporary step for completion message generation using endStep configuration
|
|
1358
|
-
const completionStep = new Step<TContext,
|
|
1634
|
+
const completionStep = new Step<TContext, TData>(selectedRoute!.id, {
|
|
1359
1635
|
description: endStepSpec.description,
|
|
1360
1636
|
id: endStepSpec.id || END_ROUTE_ID,
|
|
1361
1637
|
collect: endStepSpec.collect,
|
|
@@ -1365,19 +1641,21 @@ export class Agent<TContext = unknown> {
|
|
|
1365
1641
|
"Summarize what was accomplished and confirm completion based on the conversation history and collected data",
|
|
1366
1642
|
});
|
|
1367
1643
|
|
|
1644
|
+
if (!selectedRoute) {
|
|
1645
|
+
throw new Error("Selected route is not defined");
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1368
1648
|
// Build response schema for completion
|
|
1369
1649
|
const responseSchema = this.responseEngine.responseSchemaForRoute(
|
|
1370
|
-
selectedRoute
|
|
1371
|
-
completionStep
|
|
1650
|
+
selectedRoute,
|
|
1651
|
+
completionStep,
|
|
1652
|
+
this.schema
|
|
1372
1653
|
);
|
|
1373
1654
|
const templateContext = {
|
|
1374
1655
|
context: effectiveContext,
|
|
1375
1656
|
session,
|
|
1376
1657
|
history,
|
|
1377
1658
|
};
|
|
1378
|
-
if (!selectedRoute) {
|
|
1379
|
-
throw new Error("Selected route is not defined");
|
|
1380
|
-
}
|
|
1381
1659
|
|
|
1382
1660
|
// Build completion response prompt
|
|
1383
1661
|
const completionPrompt = await this.responseEngine.buildResponsePrompt({
|
|
@@ -1400,6 +1678,7 @@ export class Agent<TContext = unknown> {
|
|
|
1400
1678
|
),
|
|
1401
1679
|
context: effectiveContext,
|
|
1402
1680
|
session,
|
|
1681
|
+
agentSchema: this.schema,
|
|
1403
1682
|
});
|
|
1404
1683
|
|
|
1405
1684
|
// Generate completion message using AI provider
|
|
@@ -1545,21 +1824,21 @@ export class Agent<TContext = unknown> {
|
|
|
1545
1824
|
/**
|
|
1546
1825
|
* Get all routes
|
|
1547
1826
|
*/
|
|
1548
|
-
getRoutes(): Route<TContext,
|
|
1827
|
+
getRoutes(): Route<TContext, TData>[] {
|
|
1549
1828
|
return [...this.routes];
|
|
1550
1829
|
}
|
|
1551
1830
|
|
|
1552
1831
|
/**
|
|
1553
1832
|
* Get all terms
|
|
1554
1833
|
*/
|
|
1555
|
-
getTerms(): Term<TContext>[] {
|
|
1834
|
+
getTerms(): Term<TContext, TData>[] {
|
|
1556
1835
|
return [...this.terms];
|
|
1557
1836
|
}
|
|
1558
1837
|
|
|
1559
1838
|
/**
|
|
1560
1839
|
* Get all tools
|
|
1561
1840
|
*/
|
|
1562
|
-
getTools(): Tool<TContext, unknown[], unknown
|
|
1841
|
+
getTools(): Tool<TContext, TData, unknown[], unknown>[] {
|
|
1563
1842
|
return [...this.tools];
|
|
1564
1843
|
}
|
|
1565
1844
|
|
|
@@ -1570,8 +1849,8 @@ export class Agent<TContext = unknown> {
|
|
|
1570
1849
|
*/
|
|
1571
1850
|
private findAvailableTool(
|
|
1572
1851
|
toolName: string,
|
|
1573
|
-
route?: Route<TContext,
|
|
1574
|
-
): Tool<TContext, unknown[], unknown
|
|
1852
|
+
route?: Route<TContext, TData>
|
|
1853
|
+
): Tool<TContext, TData, unknown[], unknown> | undefined {
|
|
1575
1854
|
// Check route-level tools first (if route provided)
|
|
1576
1855
|
if (route) {
|
|
1577
1856
|
const routeTool = route
|
|
@@ -1591,8 +1870,8 @@ export class Agent<TContext = unknown> {
|
|
|
1591
1870
|
* @private
|
|
1592
1871
|
*/
|
|
1593
1872
|
private collectAvailableTools(
|
|
1594
|
-
route?: Route<TContext,
|
|
1595
|
-
step?: Step<TContext,
|
|
1873
|
+
route?: Route<TContext, TData>,
|
|
1874
|
+
step?: Step<TContext, TData>
|
|
1596
1875
|
): Array<{
|
|
1597
1876
|
id: string;
|
|
1598
1877
|
name: string;
|
|
@@ -1601,7 +1880,7 @@ export class Agent<TContext = unknown> {
|
|
|
1601
1880
|
}> {
|
|
1602
1881
|
const availableTools = new Map<
|
|
1603
1882
|
string,
|
|
1604
|
-
Tool<TContext, unknown[], unknown
|
|
1883
|
+
Tool<TContext, TData, unknown[], unknown>
|
|
1605
1884
|
>();
|
|
1606
1885
|
|
|
1607
1886
|
// Add agent-level tools
|
|
@@ -1619,7 +1898,7 @@ export class Agent<TContext = unknown> {
|
|
|
1619
1898
|
// Filter by step-level allowed tools if specified
|
|
1620
1899
|
if (step?.tools) {
|
|
1621
1900
|
const allowedToolIds = new Set<string>();
|
|
1622
|
-
const stepTools: Tool<TContext, unknown[], unknown
|
|
1901
|
+
const stepTools: Tool<TContext, TData, unknown[], unknown>[] = [];
|
|
1623
1902
|
|
|
1624
1903
|
for (const toolRef of step.tools) {
|
|
1625
1904
|
if (typeof toolRef === "string") {
|
|
@@ -1638,7 +1917,7 @@ export class Agent<TContext = unknown> {
|
|
|
1638
1917
|
if (allowedToolIds.size > 0) {
|
|
1639
1918
|
const filteredTools = new Map<
|
|
1640
1919
|
string,
|
|
1641
|
-
Tool<TContext, unknown[], unknown
|
|
1920
|
+
Tool<TContext, TData, unknown[], unknown>
|
|
1642
1921
|
>();
|
|
1643
1922
|
for (const toolId of allowedToolIds) {
|
|
1644
1923
|
const tool = availableTools.get(toolId);
|
|
@@ -1673,13 +1952,13 @@ export class Agent<TContext = unknown> {
|
|
|
1673
1952
|
private async executePrepareFinalize(
|
|
1674
1953
|
prepareOrFinalize:
|
|
1675
1954
|
| string
|
|
1676
|
-
| Tool<TContext, unknown[], unknown
|
|
1677
|
-
| ((context: TContext, data?: Partial<
|
|
1955
|
+
| Tool<TContext, TData, unknown[], unknown>
|
|
1956
|
+
| ((context: TContext, data?: Partial<TData>) => void | Promise<void>)
|
|
1678
1957
|
| undefined,
|
|
1679
1958
|
context: TContext,
|
|
1680
|
-
data?: Partial<
|
|
1681
|
-
route?: Route<TContext,
|
|
1682
|
-
step?: Step<TContext,
|
|
1959
|
+
data?: Partial<TData>,
|
|
1960
|
+
route?: Route<TContext, TData>,
|
|
1961
|
+
step?: Step<TContext, TData>
|
|
1683
1962
|
): Promise<void> {
|
|
1684
1963
|
if (!prepareOrFinalize) return;
|
|
1685
1964
|
|
|
@@ -1688,13 +1967,13 @@ export class Agent<TContext = unknown> {
|
|
|
1688
1967
|
await prepareOrFinalize(context, data);
|
|
1689
1968
|
} else {
|
|
1690
1969
|
// It's a tool reference - find and execute the tool
|
|
1691
|
-
let tool: Tool<TContext, unknown[], unknown
|
|
1970
|
+
let tool: Tool<TContext, TData, unknown[], unknown> | undefined;
|
|
1692
1971
|
|
|
1693
1972
|
if (typeof prepareOrFinalize === "string") {
|
|
1694
1973
|
// Tool ID - find it in available tools
|
|
1695
1974
|
const availableTools = new Map<
|
|
1696
1975
|
string,
|
|
1697
|
-
Tool<TContext, unknown[], unknown
|
|
1976
|
+
Tool<TContext, TData, unknown[], unknown>
|
|
1698
1977
|
>();
|
|
1699
1978
|
|
|
1700
1979
|
// Add agent-level tools
|
|
@@ -1727,11 +2006,12 @@ export class Agent<TContext = unknown> {
|
|
|
1727
2006
|
}
|
|
1728
2007
|
|
|
1729
2008
|
if (tool) {
|
|
1730
|
-
const toolExecutor = new ToolExecutor<TContext,
|
|
2009
|
+
const toolExecutor = new ToolExecutor<TContext, TData>();
|
|
1731
2010
|
const result = await toolExecutor.executeTool({
|
|
1732
2011
|
tool,
|
|
1733
2012
|
context,
|
|
1734
2013
|
updateContext: this.updateContext.bind(this),
|
|
2014
|
+
updateData: this.updateCollectedData.bind(this),
|
|
1735
2015
|
history: [], // Empty history for prepare/finalize
|
|
1736
2016
|
data,
|
|
1737
2017
|
});
|
|
@@ -1744,10 +2024,9 @@ export class Agent<TContext = unknown> {
|
|
|
1744
2024
|
}
|
|
1745
2025
|
} else {
|
|
1746
2026
|
logger.warn(
|
|
1747
|
-
`[Agent] Tool not found for prepare/finalize: ${
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
: "inline tool"
|
|
2027
|
+
`[Agent] Tool not found for prepare/finalize: ${typeof prepareOrFinalize === "string"
|
|
2028
|
+
? prepareOrFinalize
|
|
2029
|
+
: "inline tool"
|
|
1751
2030
|
}`
|
|
1752
2031
|
);
|
|
1753
2032
|
}
|
|
@@ -1757,7 +2036,7 @@ export class Agent<TContext = unknown> {
|
|
|
1757
2036
|
/**
|
|
1758
2037
|
* Get all guidelines
|
|
1759
2038
|
*/
|
|
1760
|
-
getGuidelines(): Guideline<TContext>[] {
|
|
2039
|
+
getGuidelines(): Guideline<TContext, TData>[] {
|
|
1761
2040
|
return [...this.guidelines];
|
|
1762
2041
|
}
|
|
1763
2042
|
|
|
@@ -1773,10 +2052,10 @@ export class Agent<TContext = unknown> {
|
|
|
1773
2052
|
* @private
|
|
1774
2053
|
*/
|
|
1775
2054
|
private mergeTerms(
|
|
1776
|
-
agentTerms: Term<TContext>[],
|
|
1777
|
-
routeTerms: Term<TContext>[]
|
|
1778
|
-
): Term<TContext>[] {
|
|
1779
|
-
const merged = new Map<string, Term<TContext>>();
|
|
2055
|
+
agentTerms: Term<TContext, TData>[],
|
|
2056
|
+
routeTerms: Term<TContext, TData>[]
|
|
2057
|
+
): Term<TContext, TData>[] {
|
|
2058
|
+
const merged = new Map<string, Term<TContext, TData>>();
|
|
1780
2059
|
|
|
1781
2060
|
// Add agent terms first
|
|
1782
2061
|
agentTerms.forEach((term) => {
|
|
@@ -1798,7 +2077,7 @@ export class Agent<TContext = unknown> {
|
|
|
1798
2077
|
/**
|
|
1799
2078
|
* Get the persistence manager (if configured)
|
|
1800
2079
|
*/
|
|
1801
|
-
getPersistenceManager(): PersistenceManager | undefined {
|
|
2080
|
+
getPersistenceManager(): PersistenceManager<TData> | undefined {
|
|
1802
2081
|
return this.persistenceManager;
|
|
1803
2082
|
}
|
|
1804
2083
|
|
|
@@ -1832,21 +2111,20 @@ export class Agent<TContext = unknown> {
|
|
|
1832
2111
|
}
|
|
1833
2112
|
|
|
1834
2113
|
/**
|
|
1835
|
-
* Get collected data from current session
|
|
2114
|
+
* Get collected data from current session or agent-level collected data
|
|
1836
2115
|
* @param routeId - Optional route ID to get data for (uses current route if not provided)
|
|
1837
|
-
* @returns The collected data from the current session
|
|
2116
|
+
* @returns The collected data from the current session or agent-level data
|
|
1838
2117
|
*/
|
|
1839
|
-
getData
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
return (
|
|
1845
|
-
(this.currentSession.dataByRoute?.[routeId] as Partial<TData>) ||
|
|
1846
|
-
({} as Partial<TData>)
|
|
1847
|
-
);
|
|
2118
|
+
getData(): Partial<TData> {
|
|
2119
|
+
// If we have a current session, use session data
|
|
2120
|
+
if (this.currentSession) {
|
|
2121
|
+
// With agent-level data, all routes share the same data structure
|
|
2122
|
+
// No need for route-specific data access
|
|
2123
|
+
return (this.currentSession.data) || {};
|
|
1848
2124
|
}
|
|
1849
|
-
|
|
2125
|
+
|
|
2126
|
+
// Otherwise, return agent-level collected data
|
|
2127
|
+
return this.getCollectedData();
|
|
1850
2128
|
}
|
|
1851
2129
|
|
|
1852
2130
|
/**
|
|
@@ -1868,10 +2146,10 @@ export class Agent<TContext = unknown> {
|
|
|
1868
2146
|
*/
|
|
1869
2147
|
async nextStepRoute(
|
|
1870
2148
|
routeIdOrTitle: string,
|
|
1871
|
-
session?: SessionState
|
|
1872
|
-
condition?: Template<TContext,
|
|
2149
|
+
session?: SessionState<TData>,
|
|
2150
|
+
condition?: Template<TContext, TData>,
|
|
1873
2151
|
history?: Event[]
|
|
1874
|
-
): Promise<SessionState
|
|
2152
|
+
): Promise<SessionState<TData>> {
|
|
1875
2153
|
const targetSession = session || this.currentSession;
|
|
1876
2154
|
|
|
1877
2155
|
if (!targetSession) {
|
|
@@ -1900,12 +2178,12 @@ export class Agent<TContext = unknown> {
|
|
|
1900
2178
|
};
|
|
1901
2179
|
const renderedCondition = await render(condition, templateContext);
|
|
1902
2180
|
|
|
1903
|
-
const updatedSession: SessionState = {
|
|
2181
|
+
const updatedSession: SessionState<TData> = {
|
|
1904
2182
|
...targetSession,
|
|
1905
2183
|
pendingTransition: {
|
|
1906
2184
|
targetRouteId: targetRoute.id,
|
|
1907
2185
|
condition: renderedCondition,
|
|
1908
|
-
reason: "
|
|
2186
|
+
reason: "route_complete",
|
|
1909
2187
|
},
|
|
1910
2188
|
};
|
|
1911
2189
|
|
|
@@ -1915,7 +2193,7 @@ export class Agent<TContext = unknown> {
|
|
|
1915
2193
|
}
|
|
1916
2194
|
|
|
1917
2195
|
logger.debug(
|
|
1918
|
-
`[Agent] Set pending
|
|
2196
|
+
`[Agent] Set pending transition to route: ${targetRoute.title}`
|
|
1919
2197
|
);
|
|
1920
2198
|
|
|
1921
2199
|
return updatedSession;
|
|
@@ -1925,7 +2203,7 @@ export class Agent<TContext = unknown> {
|
|
|
1925
2203
|
* Simplified respond method using SessionManager
|
|
1926
2204
|
* Automatically manages conversation history through the session
|
|
1927
2205
|
*/
|
|
1928
|
-
async chat
|
|
2206
|
+
async chat(
|
|
1929
2207
|
message?: string,
|
|
1930
2208
|
options?: {
|
|
1931
2209
|
history?: History; // Optional: override session history for this response
|
|
@@ -1947,7 +2225,15 @@ export class Agent<TContext = unknown> {
|
|
|
1947
2225
|
}
|
|
1948
2226
|
|
|
1949
2227
|
// Get or create session
|
|
1950
|
-
|
|
2228
|
+
let session = await this.session.getOrCreate();
|
|
2229
|
+
|
|
2230
|
+
// Merge agent's collected data into session (agent data takes precedence)
|
|
2231
|
+
if (Object.keys(this.collectedData).length > 0) {
|
|
2232
|
+
session = mergeCollected(session, this.collectedData);
|
|
2233
|
+
// Update the session manager with the merged data
|
|
2234
|
+
await this.session.setData(this.collectedData);
|
|
2235
|
+
logger.debug("[Agent] Merged agent collected data into chat session:", this.collectedData);
|
|
2236
|
+
}
|
|
1951
2237
|
|
|
1952
2238
|
// Use existing respond method with session-managed history
|
|
1953
2239
|
const result = await this.respond({
|
|
@@ -1962,6 +2248,10 @@ export class Agent<TContext = unknown> {
|
|
|
1962
2248
|
await this.session.addMessage("assistant", result.message);
|
|
1963
2249
|
}
|
|
1964
2250
|
|
|
1965
|
-
|
|
2251
|
+
// Ensure the result includes the current session
|
|
2252
|
+
return {
|
|
2253
|
+
...result,
|
|
2254
|
+
session: result.session || this.session.current,
|
|
2255
|
+
};
|
|
1966
2256
|
}
|
|
1967
2257
|
}
|