@falai/agent 0.6.9 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -59
- package/dist/adapters/MemoryAdapter.js +2 -2
- package/dist/adapters/MemoryAdapter.js.map +1 -1
- package/dist/adapters/MongoAdapter.js +2 -2
- package/dist/adapters/MongoAdapter.js.map +1 -1
- package/dist/adapters/OpenSearchAdapter.js +7 -7
- package/dist/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/adapters/PostgreSQLAdapter.js +9 -9
- package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/adapters/PrismaAdapter.js +3 -3
- package/dist/adapters/PrismaAdapter.js.map +1 -1
- package/dist/adapters/RedisAdapter.js +2 -2
- package/dist/adapters/RedisAdapter.js.map +1 -1
- package/dist/adapters/SQLiteAdapter.d.ts +3 -3
- package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/adapters/SQLiteAdapter.js +11 -11
- package/dist/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/cjs/adapters/MemoryAdapter.js +2 -2
- package/dist/cjs/adapters/MemoryAdapter.js.map +1 -1
- package/dist/cjs/adapters/MongoAdapter.js +2 -2
- package/dist/cjs/adapters/MongoAdapter.js.map +1 -1
- package/dist/cjs/adapters/OpenSearchAdapter.js +7 -7
- package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.js +9 -9
- package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/cjs/adapters/PrismaAdapter.js +3 -3
- package/dist/cjs/adapters/PrismaAdapter.js.map +1 -1
- package/dist/cjs/adapters/RedisAdapter.js +2 -2
- package/dist/cjs/adapters/RedisAdapter.js.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.d.ts +3 -3
- package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.js +11 -11
- package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/cjs/adapters/index.d.ts +1 -1
- package/dist/cjs/adapters/index.d.ts.map +1 -1
- package/dist/cjs/constants/index.d.ts +4 -4
- package/dist/cjs/constants/index.js +5 -5
- package/dist/cjs/core/Agent.d.ts +22 -22
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +160 -152
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/Events.d.ts +6 -6
- package/dist/cjs/core/Events.d.ts.map +1 -1
- package/dist/cjs/core/PersistenceManager.d.ts +13 -13
- package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
- package/dist/cjs/core/PersistenceManager.js +24 -24
- package/dist/cjs/core/PersistenceManager.js.map +1 -1
- package/dist/cjs/core/ResponseEngine.d.ts +3 -8
- package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
- package/dist/cjs/core/ResponseEngine.js +8 -8
- package/dist/cjs/core/ResponseEngine.js.map +1 -1
- package/dist/cjs/core/Route.d.ts +17 -17
- package/dist/cjs/core/Route.d.ts.map +1 -1
- package/dist/cjs/core/Route.js +33 -33
- package/dist/cjs/core/Route.js.map +1 -1
- package/dist/cjs/core/RoutingEngine.d.ts +30 -30
- package/dist/cjs/core/RoutingEngine.d.ts.map +1 -1
- package/dist/cjs/core/RoutingEngine.js +192 -192
- package/dist/cjs/core/RoutingEngine.js.map +1 -1
- package/dist/cjs/core/Step.d.ts +72 -0
- package/dist/cjs/core/Step.d.ts.map +1 -0
- package/dist/cjs/core/Step.js +150 -0
- package/dist/cjs/core/Step.js.map +1 -0
- package/dist/cjs/core/ToolExecutor.d.ts +5 -5
- package/dist/cjs/core/ToolExecutor.d.ts.map +1 -1
- package/dist/cjs/core/ToolExecutor.js +8 -8
- package/dist/cjs/core/ToolExecutor.js.map +1 -1
- package/dist/cjs/core/Transition.d.ts +14 -14
- package/dist/cjs/core/Transition.d.ts.map +1 -1
- package/dist/cjs/core/Transition.js +48 -19
- package/dist/cjs/core/Transition.js.map +1 -1
- package/dist/cjs/index.d.ts +7 -7
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +8 -8
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +8 -8
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/ai.d.ts +2 -2
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/cjs/types/history.d.ts +3 -3
- package/dist/cjs/types/history.d.ts.map +1 -1
- package/dist/cjs/types/index.d.ts +1 -1
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/persistence.d.ts +5 -5
- package/dist/cjs/types/persistence.d.ts.map +1 -1
- package/dist/cjs/types/route.d.ts +57 -52
- package/dist/cjs/types/route.d.ts.map +1 -1
- package/dist/cjs/types/session.d.ts +27 -27
- package/dist/cjs/types/session.d.ts.map +1 -1
- package/dist/cjs/types/session.js +48 -50
- package/dist/cjs/types/session.js.map +1 -1
- package/dist/cjs/types/tool.d.ts +13 -13
- package/dist/cjs/types/tool.d.ts.map +1 -1
- package/dist/cjs/utils/id.d.ts +8 -3
- package/dist/cjs/utils/id.d.ts.map +1 -1
- package/dist/cjs/utils/id.js +16 -7
- package/dist/cjs/utils/id.js.map +1 -1
- package/dist/constants/index.d.ts +4 -4
- package/dist/constants/index.js +4 -4
- package/dist/core/Agent.d.ts +22 -22
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +162 -154
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/Events.d.ts +6 -6
- package/dist/core/Events.d.ts.map +1 -1
- package/dist/core/PersistenceManager.d.ts +13 -13
- package/dist/core/PersistenceManager.d.ts.map +1 -1
- package/dist/core/PersistenceManager.js +25 -25
- package/dist/core/PersistenceManager.js.map +1 -1
- package/dist/core/ResponseEngine.d.ts +3 -8
- package/dist/core/ResponseEngine.d.ts.map +1 -1
- package/dist/core/ResponseEngine.js +8 -8
- package/dist/core/ResponseEngine.js.map +1 -1
- package/dist/core/Route.d.ts +17 -17
- package/dist/core/Route.d.ts.map +1 -1
- package/dist/core/Route.js +33 -33
- package/dist/core/Route.js.map +1 -1
- package/dist/core/RoutingEngine.d.ts +30 -30
- package/dist/core/RoutingEngine.d.ts.map +1 -1
- package/dist/core/RoutingEngine.js +193 -193
- package/dist/core/RoutingEngine.js.map +1 -1
- package/dist/core/Step.d.ts +72 -0
- package/dist/core/Step.d.ts.map +1 -0
- package/dist/core/Step.js +146 -0
- package/dist/core/Step.js.map +1 -0
- package/dist/core/ToolExecutor.d.ts +5 -5
- package/dist/core/ToolExecutor.d.ts.map +1 -1
- package/dist/core/ToolExecutor.js +8 -8
- package/dist/core/ToolExecutor.js.map +1 -1
- package/dist/core/Transition.d.ts +14 -14
- package/dist/core/Transition.d.ts.map +1 -1
- package/dist/core/Transition.js +48 -19
- package/dist/core/Transition.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/types/agent.d.ts +8 -8
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/ai.d.ts +2 -2
- package/dist/types/ai.d.ts.map +1 -1
- package/dist/types/history.d.ts +3 -3
- package/dist/types/history.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/persistence.d.ts +5 -5
- package/dist/types/persistence.d.ts.map +1 -1
- package/dist/types/route.d.ts +57 -52
- package/dist/types/route.d.ts.map +1 -1
- package/dist/types/session.d.ts +27 -27
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js +44 -46
- package/dist/types/session.js.map +1 -1
- package/dist/types/tool.d.ts +13 -13
- package/dist/types/tool.d.ts.map +1 -1
- package/dist/utils/id.d.ts +8 -3
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +14 -6
- package/dist/utils/id.js.map +1 -1
- package/docs/ADAPTERS.md +21 -21
- package/docs/AGENT.md +57 -55
- package/docs/API_REFERENCE.md +218 -220
- package/docs/ARCHITECTURE.md +99 -104
- package/docs/CONTEXT_MANAGEMENT.md +81 -88
- package/docs/DOCS.md +18 -18
- package/docs/DOMAINS.md +16 -16
- package/docs/EXAMPLES.md +43 -43
- package/docs/GETTING_STARTED.md +60 -63
- package/docs/PERSISTENCE.md +66 -70
- package/docs/PROVIDERS.md +2 -2
- package/docs/README.md +6 -6
- package/docs/ROUTES.md +218 -220
- package/docs/STEPS.md +883 -0
- package/examples/business-onboarding.ts +84 -81
- package/examples/company-qna-agent.ts +68 -67
- package/examples/custom-database-persistence.ts +87 -89
- package/examples/declarative-agent.ts +32 -32
- package/examples/domain-scoping.ts +18 -18
- package/examples/extracted-data-modification.ts +92 -97
- package/examples/healthcare-agent.ts +89 -91
- package/examples/openai-agent.ts +29 -32
- package/examples/opensearch-persistence.ts +43 -45
- package/examples/persistent-onboarding.ts +65 -66
- package/examples/prisma-persistence.ts +108 -112
- package/examples/prisma-schema.example.prisma +3 -3
- package/examples/redis-persistence.ts +67 -73
- package/examples/route-transitions.ts +71 -47
- package/examples/rules-prohibitions.ts +28 -28
- package/examples/streaming-agent.ts +24 -24
- package/examples/travel-agent.ts +94 -109
- package/package.json +1 -1
- package/src/adapters/MemoryAdapter.ts +3 -3
- package/src/adapters/MongoAdapter.ts +3 -3
- package/src/adapters/OpenSearchAdapter.ts +8 -8
- package/src/adapters/PostgreSQLAdapter.ts +10 -10
- package/src/adapters/PrismaAdapter.ts +4 -4
- package/src/adapters/RedisAdapter.ts +3 -3
- package/src/adapters/SQLiteAdapter.ts +15 -15
- package/src/adapters/index.ts +1 -1
- package/src/constants/index.ts +4 -4
- package/src/core/Agent.ts +210 -206
- package/src/core/Events.ts +12 -12
- package/src/core/PersistenceManager.ts +32 -36
- package/src/core/ResponseEngine.ts +11 -17
- package/src/core/Route.ts +55 -49
- package/src/core/RoutingEngine.ts +244 -252
- package/src/core/Step.ts +197 -0
- package/src/core/ToolExecutor.ts +11 -11
- package/src/core/Transition.ts +72 -26
- package/src/index.ts +8 -8
- package/src/types/agent.ts +8 -8
- package/src/types/ai.ts +2 -2
- package/src/types/history.ts +3 -3
- package/src/types/index.ts +1 -1
- package/src/types/persistence.ts +6 -6
- package/src/types/route.ts +77 -61
- package/src/types/session.ts +75 -78
- package/src/types/tool.ts +17 -17
- package/src/utils/id.ts +15 -6
- package/dist/cjs/core/State.d.ts +0 -72
- package/dist/cjs/core/State.d.ts.map +0 -1
- package/dist/cjs/core/State.js +0 -148
- package/dist/cjs/core/State.js.map +0 -1
- package/dist/core/State.d.ts +0 -72
- package/dist/core/State.d.ts.map +0 -1
- package/dist/core/State.js +0 -144
- package/dist/core/State.js.map +0 -1
- package/docs/STATES.md +0 -888
- package/src/core/State.ts +0 -212
package/src/core/Agent.ts
CHANGED
|
@@ -3,24 +3,30 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { AgentOptions, Term, Guideline, Capability } from "../types/agent";
|
|
6
|
-
import type { Event,
|
|
6
|
+
import type { Event, StepRef } from "../types/index";
|
|
7
7
|
import type { RouteOptions } from "../types/route";
|
|
8
8
|
|
|
9
|
-
import type {
|
|
9
|
+
import type { SessionStep } from "../types/session";
|
|
10
10
|
import type { AgentStructuredResponse } from "../types/ai";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
createSession,
|
|
13
|
+
enterRoute,
|
|
14
|
+
enterStep,
|
|
15
|
+
mergeCollected,
|
|
16
|
+
} from "../types/session";
|
|
12
17
|
import { PromptComposer } from "./PromptComposer";
|
|
13
18
|
import { logger, LoggerLevel } from "../utils/logger";
|
|
14
19
|
|
|
15
20
|
import { Route } from "./Route";
|
|
16
|
-
import {
|
|
21
|
+
import { Step } from "./Step";
|
|
17
22
|
import { DomainRegistry } from "./DomainRegistry";
|
|
18
23
|
import { PersistenceManager } from "./PersistenceManager";
|
|
19
24
|
import { RoutingEngine } from "./RoutingEngine";
|
|
20
25
|
import { ResponseEngine } from "./ResponseEngine";
|
|
21
26
|
import { ToolExecutor } from "./ToolExecutor";
|
|
22
27
|
import { getLastMessageFromHistory } from "../utils/event";
|
|
23
|
-
import {
|
|
28
|
+
import { END_ROUTE_ID } from "../constants";
|
|
29
|
+
import { ToolRef } from "../types";
|
|
24
30
|
|
|
25
31
|
/**
|
|
26
32
|
* Main Agent class with generic context support
|
|
@@ -36,7 +42,7 @@ export class Agent<TContext = unknown> {
|
|
|
36
42
|
private persistenceManager: PersistenceManager | undefined;
|
|
37
43
|
private routingEngine: RoutingEngine<TContext>;
|
|
38
44
|
private responseEngine: ResponseEngine<TContext>;
|
|
39
|
-
private currentSession?:
|
|
45
|
+
private currentSession?: SessionStep;
|
|
40
46
|
|
|
41
47
|
/**
|
|
42
48
|
* Dynamic domain property - populated via addDomain
|
|
@@ -132,12 +138,12 @@ export class Agent<TContext = unknown> {
|
|
|
132
138
|
|
|
133
139
|
/**
|
|
134
140
|
* Create a new route (journey)
|
|
135
|
-
* @template
|
|
141
|
+
* @template TData - Type of data collected throughout the route
|
|
136
142
|
*/
|
|
137
|
-
createRoute<
|
|
138
|
-
options: RouteOptions<
|
|
139
|
-
): Route<TContext,
|
|
140
|
-
const route = new Route<TContext,
|
|
143
|
+
createRoute<TData = unknown>(
|
|
144
|
+
options: RouteOptions<TContext, TData>
|
|
145
|
+
): Route<TContext, TData> {
|
|
146
|
+
const route = new Route<TContext, TData>(options);
|
|
141
147
|
this.routes.push(route);
|
|
142
148
|
return route;
|
|
143
149
|
}
|
|
@@ -225,32 +231,32 @@ export class Agent<TContext = unknown> {
|
|
|
225
231
|
}
|
|
226
232
|
|
|
227
233
|
/**
|
|
228
|
-
* Update
|
|
229
|
-
* Triggers the
|
|
234
|
+
* Update collected data in session with lifecycle hook support
|
|
235
|
+
* Triggers the onDataUpdate lifecycle hook if configured
|
|
230
236
|
* @internal
|
|
231
237
|
*/
|
|
232
|
-
private async
|
|
233
|
-
session:
|
|
234
|
-
|
|
235
|
-
): Promise<
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
// Merge new
|
|
239
|
-
let
|
|
240
|
-
...session.
|
|
241
|
-
...
|
|
238
|
+
private async updateData<TData = unknown>(
|
|
239
|
+
session: SessionStep<TData>,
|
|
240
|
+
collectedUpdate: Partial<TData>
|
|
241
|
+
): Promise<SessionStep<TData>> {
|
|
242
|
+
const previousCollected = { ...session.data };
|
|
243
|
+
|
|
244
|
+
// Merge new collected data
|
|
245
|
+
let newCollected = {
|
|
246
|
+
...session.data,
|
|
247
|
+
...collectedUpdate,
|
|
242
248
|
};
|
|
243
249
|
|
|
244
250
|
// Trigger lifecycle hook if configured
|
|
245
|
-
if (this.options.hooks?.
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
)) as Partial<
|
|
251
|
+
if (this.options.hooks?.onDataUpdate) {
|
|
252
|
+
newCollected = (await this.options.hooks.onDataUpdate(
|
|
253
|
+
newCollected,
|
|
254
|
+
previousCollected
|
|
255
|
+
)) as Partial<TData>;
|
|
250
256
|
}
|
|
251
257
|
|
|
252
258
|
// Return updated session
|
|
253
|
-
return
|
|
259
|
+
return mergeCollected(session, newCollected);
|
|
254
260
|
}
|
|
255
261
|
|
|
256
262
|
/**
|
|
@@ -272,15 +278,15 @@ export class Agent<TContext = unknown> {
|
|
|
272
278
|
*/
|
|
273
279
|
async *respondStream(params: {
|
|
274
280
|
history: Event[];
|
|
275
|
-
|
|
276
|
-
session?:
|
|
281
|
+
step?: StepRef;
|
|
282
|
+
session?: SessionStep;
|
|
277
283
|
contextOverride?: Partial<TContext>;
|
|
278
284
|
signal?: AbortSignal;
|
|
279
285
|
}): AsyncGenerator<{
|
|
280
286
|
delta: string;
|
|
281
287
|
accumulated: string;
|
|
282
288
|
done: boolean;
|
|
283
|
-
session?:
|
|
289
|
+
session?: SessionStep;
|
|
284
290
|
toolCalls?: Array<{ toolName: string; arguments: Record<string, unknown> }>;
|
|
285
291
|
isRouteComplete?: boolean;
|
|
286
292
|
}> {
|
|
@@ -305,27 +311,27 @@ export class Agent<TContext = unknown> {
|
|
|
305
311
|
// Initialize or get session (use current session if available)
|
|
306
312
|
let session = params.session || this.currentSession || createSession();
|
|
307
313
|
|
|
308
|
-
// PHASE 1: TOOL EXECUTION - Execute tools if current
|
|
309
|
-
if (session.currentRoute && session.
|
|
314
|
+
// PHASE 1: TOOL EXECUTION - Execute tools if current step has tool
|
|
315
|
+
if (session.currentRoute && session.currentStep) {
|
|
310
316
|
const currentRoute = this.routes.find(
|
|
311
317
|
(r) => r.id === session.currentRoute?.id
|
|
312
318
|
);
|
|
313
319
|
if (currentRoute) {
|
|
314
|
-
const
|
|
315
|
-
if (
|
|
316
|
-
const transitions =
|
|
317
|
-
const toolTransition = transitions.find((t) => t.spec.
|
|
320
|
+
const currentStep = currentRoute.getStep(session.currentStep.id);
|
|
321
|
+
if (currentStep) {
|
|
322
|
+
const transitions = currentStep.getTransitions();
|
|
323
|
+
const toolTransition = transitions.find((t) => t.spec.tool);
|
|
318
324
|
|
|
319
|
-
if (toolTransition?.spec.
|
|
325
|
+
if (toolTransition?.spec.tool) {
|
|
320
326
|
const toolExecutor = new ToolExecutor<TContext, unknown>();
|
|
321
327
|
// Get allowed domains from current route for security enforcement
|
|
322
328
|
const allowedDomains = currentRoute.getDomains();
|
|
323
329
|
const result = await toolExecutor.executeTool(
|
|
324
|
-
toolTransition.spec.
|
|
330
|
+
toolTransition.spec.tool as ToolRef<TContext, unknown[], unknown>,
|
|
325
331
|
effectiveContext,
|
|
326
332
|
this.updateContext.bind(this),
|
|
327
333
|
history,
|
|
328
|
-
session.
|
|
334
|
+
session.data,
|
|
329
335
|
allowedDomains
|
|
330
336
|
);
|
|
331
337
|
|
|
@@ -336,15 +342,12 @@ export class Agent<TContext = unknown> {
|
|
|
336
342
|
);
|
|
337
343
|
}
|
|
338
344
|
|
|
339
|
-
// Update
|
|
340
|
-
if (result.
|
|
341
|
-
session = await this.
|
|
342
|
-
session,
|
|
343
|
-
result.extractedUpdate
|
|
344
|
-
);
|
|
345
|
+
// Update collected data with tool results
|
|
346
|
+
if (result.collectedUpdate) {
|
|
347
|
+
session = await this.updateData(session, result.collectedUpdate);
|
|
345
348
|
logger.debug(
|
|
346
|
-
`[Agent] Tool updated
|
|
347
|
-
result.
|
|
349
|
+
`[Agent] Tool updated collected data:`,
|
|
350
|
+
result.collectedUpdate
|
|
348
351
|
);
|
|
349
352
|
}
|
|
350
353
|
|
|
@@ -356,10 +359,10 @@ export class Agent<TContext = unknown> {
|
|
|
356
359
|
}
|
|
357
360
|
}
|
|
358
361
|
|
|
359
|
-
// PHASE 2: ROUTING +
|
|
362
|
+
// PHASE 2: ROUTING + STEP SELECTION - Determine which route and step to use (combined)
|
|
360
363
|
let selectedRoute: Route<TContext> | undefined;
|
|
361
364
|
let responseDirectives: string[] | undefined;
|
|
362
|
-
let
|
|
365
|
+
let selectedStep: Step<TContext> | undefined;
|
|
363
366
|
let isRouteComplete = false;
|
|
364
367
|
|
|
365
368
|
// Check for pending transition from previous route completion
|
|
@@ -381,7 +384,7 @@ export class Agent<TContext = unknown> {
|
|
|
381
384
|
|
|
382
385
|
// Merge initial data if available
|
|
383
386
|
if (targetRoute.initialData) {
|
|
384
|
-
session =
|
|
387
|
+
session = mergeCollected(session, targetRoute.initialData);
|
|
385
388
|
}
|
|
386
389
|
|
|
387
390
|
selectedRoute = targetRoute;
|
|
@@ -399,7 +402,7 @@ export class Agent<TContext = unknown> {
|
|
|
399
402
|
|
|
400
403
|
// If no pending transition or transition handled, do normal routing
|
|
401
404
|
if (this.routes.length > 0 && !selectedRoute) {
|
|
402
|
-
const orchestration = await this.routingEngine.
|
|
405
|
+
const orchestration = await this.routingEngine.decideRouteAndStep({
|
|
403
406
|
routes: this.routes,
|
|
404
407
|
session,
|
|
405
408
|
history,
|
|
@@ -415,7 +418,7 @@ export class Agent<TContext = unknown> {
|
|
|
415
418
|
});
|
|
416
419
|
|
|
417
420
|
selectedRoute = orchestration.selectedRoute;
|
|
418
|
-
|
|
421
|
+
selectedStep = orchestration.selectedStep;
|
|
419
422
|
responseDirectives = orchestration.responseDirectives;
|
|
420
423
|
session = orchestration.session;
|
|
421
424
|
isRouteComplete = orchestration.isRouteComplete || false;
|
|
@@ -423,57 +426,57 @@ export class Agent<TContext = unknown> {
|
|
|
423
426
|
// Log if route is complete
|
|
424
427
|
if (isRouteComplete) {
|
|
425
428
|
logger.debug(
|
|
426
|
-
`[Agent] Route complete: all required data collected,
|
|
429
|
+
`[Agent] Route complete: all required data collected, END_ROUTE reached`
|
|
427
430
|
);
|
|
428
431
|
}
|
|
429
432
|
}
|
|
430
433
|
|
|
431
|
-
// PHASE 3: DETERMINE NEXT
|
|
434
|
+
// PHASE 3: DETERMINE NEXT STEP - Use step from combined decision or get initial step
|
|
432
435
|
if (selectedRoute && !isRouteComplete) {
|
|
433
|
-
let
|
|
436
|
+
let nextStep: Step<TContext>;
|
|
434
437
|
|
|
435
|
-
// If we have a selected
|
|
436
|
-
if (
|
|
437
|
-
|
|
438
|
+
// If we have a selected step from the combined routing decision, use it
|
|
439
|
+
if (selectedStep) {
|
|
440
|
+
nextStep = selectedStep;
|
|
438
441
|
} else {
|
|
439
|
-
// New route or no
|
|
440
|
-
const candidates = this.routingEngine.
|
|
442
|
+
// New route or no step selected - get initial step or first valid step
|
|
443
|
+
const candidates = this.routingEngine.getCandidateSteps(
|
|
441
444
|
selectedRoute,
|
|
442
445
|
undefined,
|
|
443
|
-
session.
|
|
446
|
+
session.data || {}
|
|
444
447
|
);
|
|
445
448
|
if (candidates.length > 0) {
|
|
446
|
-
|
|
449
|
+
nextStep = candidates[0].step;
|
|
447
450
|
logger.debug(
|
|
448
|
-
`[Agent] Using first valid
|
|
451
|
+
`[Agent] Using first valid step: ${nextStep.id} for new route`
|
|
449
452
|
);
|
|
450
453
|
} else {
|
|
451
|
-
// Fallback to initial
|
|
452
|
-
|
|
454
|
+
// Fallback to initial step even if it should be skipped
|
|
455
|
+
nextStep = selectedRoute.initialStep;
|
|
453
456
|
logger.warn(
|
|
454
|
-
`[Agent] No valid
|
|
457
|
+
`[Agent] No valid steps found, using initial step: ${nextStep.id}`
|
|
455
458
|
);
|
|
456
459
|
}
|
|
457
460
|
}
|
|
458
461
|
|
|
459
|
-
// Update session with next
|
|
460
|
-
session =
|
|
461
|
-
logger.debug(`[Agent] Entered
|
|
462
|
+
// Update session with next step
|
|
463
|
+
session = enterStep(session, nextStep.id, nextStep.description);
|
|
464
|
+
logger.debug(`[Agent] Entered step: ${nextStep.id}`);
|
|
462
465
|
|
|
463
|
-
// PHASE 4: RESPONSE GENERATION - Stream message using selected route and
|
|
466
|
+
// PHASE 4: RESPONSE GENERATION - Stream message using selected route and step
|
|
464
467
|
// Get last user message
|
|
465
468
|
const lastUserMessage = getLastMessageFromHistory(history);
|
|
466
469
|
|
|
467
|
-
// Build response schema for this route (with
|
|
470
|
+
// Build response schema for this route (with collect fields from step)
|
|
468
471
|
const responseSchema = this.responseEngine.responseSchemaForRoute(
|
|
469
472
|
selectedRoute,
|
|
470
|
-
|
|
473
|
+
nextStep
|
|
471
474
|
);
|
|
472
475
|
|
|
473
476
|
// Build response prompt
|
|
474
477
|
const responsePrompt = this.responseEngine.buildResponsePrompt(
|
|
475
478
|
selectedRoute,
|
|
476
|
-
|
|
479
|
+
nextStep,
|
|
477
480
|
selectedRoute.getRules(),
|
|
478
481
|
selectedRoute.getProhibitions(),
|
|
479
482
|
responseDirectives,
|
|
@@ -505,23 +508,23 @@ export class Agent<TContext = unknown> {
|
|
|
505
508
|
| Array<{ toolName: string; arguments: Record<string, unknown> }>
|
|
506
509
|
| undefined = undefined;
|
|
507
510
|
|
|
508
|
-
// Extract
|
|
509
|
-
if (chunk.done && chunk.structured &&
|
|
510
|
-
const
|
|
511
|
-
// The structured response includes both base fields and
|
|
511
|
+
// Extract collected data on final chunk
|
|
512
|
+
if (chunk.done && chunk.structured && nextStep.collectFields) {
|
|
513
|
+
const collectedData: Record<string, unknown> = {};
|
|
514
|
+
// The structured response includes both base fields and collected extraction fields
|
|
512
515
|
const structuredData = chunk.structured as AgentStructuredResponse &
|
|
513
516
|
Record<string, unknown>;
|
|
514
517
|
|
|
515
|
-
for (const field of
|
|
518
|
+
for (const field of nextStep.collectFields) {
|
|
516
519
|
if (field in structuredData) {
|
|
517
|
-
|
|
520
|
+
collectedData[field] = structuredData[field];
|
|
518
521
|
}
|
|
519
522
|
}
|
|
520
523
|
|
|
521
|
-
// Merge
|
|
522
|
-
if (Object.keys(
|
|
523
|
-
session = await this.
|
|
524
|
-
logger.debug(`[Agent]
|
|
524
|
+
// Merge collected data into session
|
|
525
|
+
if (Object.keys(collectedData).length > 0) {
|
|
526
|
+
session = await this.updateData(session, collectedData);
|
|
527
|
+
logger.debug(`[Agent] Collected data:`, collectedData);
|
|
525
528
|
}
|
|
526
529
|
}
|
|
527
530
|
|
|
@@ -538,16 +541,16 @@ export class Agent<TContext = unknown> {
|
|
|
538
541
|
);
|
|
539
542
|
}
|
|
540
543
|
|
|
541
|
-
// Auto-save session
|
|
544
|
+
// Auto-save session step on final chunk
|
|
542
545
|
if (
|
|
543
546
|
chunk.done &&
|
|
544
547
|
this.persistenceManager &&
|
|
545
548
|
session.id &&
|
|
546
549
|
this.options.persistence?.autoSave !== false
|
|
547
550
|
) {
|
|
548
|
-
await this.persistenceManager.
|
|
551
|
+
await this.persistenceManager.saveSessionStep(session.id, session);
|
|
549
552
|
logger.debug(
|
|
550
|
-
`[Agent] Auto-saved session
|
|
553
|
+
`[Agent] Auto-saved session step to persistence: ${session.id}`
|
|
551
554
|
);
|
|
552
555
|
}
|
|
553
556
|
|
|
@@ -569,30 +572,32 @@ export class Agent<TContext = unknown> {
|
|
|
569
572
|
// Route is complete - generate completion message then check for onComplete transition
|
|
570
573
|
const lastUserMessage = getLastMessageFromHistory(history);
|
|
571
574
|
|
|
572
|
-
// Get
|
|
573
|
-
const
|
|
575
|
+
// Get endStep spec from route
|
|
576
|
+
const endStepSpec = selectedRoute.endStepSpec;
|
|
574
577
|
|
|
575
|
-
// Create a temporary
|
|
576
|
-
const
|
|
578
|
+
// Create a temporary step for completion message generation using endStep configuration
|
|
579
|
+
const completionStep = new Step<TContext>(
|
|
577
580
|
selectedRoute.id,
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
+
endStepSpec.instructions ||
|
|
582
|
+
"Summarize what was accomplished and confirm completion",
|
|
583
|
+
endStepSpec.id || END_ROUTE_ID,
|
|
584
|
+
endStepSpec.collect,
|
|
581
585
|
undefined,
|
|
582
|
-
|
|
583
|
-
|
|
586
|
+
endStepSpec.requires,
|
|
587
|
+
endStepSpec.instructions ||
|
|
588
|
+
"Summarize what was accomplished and confirm completion based on the conversation history and collected data"
|
|
584
589
|
);
|
|
585
590
|
|
|
586
591
|
// Build response schema for completion
|
|
587
592
|
const responseSchema = this.responseEngine.responseSchemaForRoute(
|
|
588
593
|
selectedRoute,
|
|
589
|
-
|
|
594
|
+
completionStep
|
|
590
595
|
);
|
|
591
596
|
|
|
592
597
|
// Build completion response prompt
|
|
593
598
|
const completionPrompt = this.responseEngine.buildResponsePrompt(
|
|
594
599
|
selectedRoute,
|
|
595
|
-
|
|
600
|
+
completionStep,
|
|
596
601
|
selectedRoute.getRules(),
|
|
597
602
|
selectedRoute.getProhibitions(),
|
|
598
603
|
undefined, // No directives for completion
|
|
@@ -624,7 +629,7 @@ export class Agent<TContext = unknown> {
|
|
|
624
629
|
|
|
625
630
|
// Check for onComplete transition
|
|
626
631
|
const transitionConfig = await selectedRoute.evaluateOnComplete(
|
|
627
|
-
{
|
|
632
|
+
{ data: session.data },
|
|
628
633
|
effectiveContext
|
|
629
634
|
);
|
|
630
635
|
|
|
@@ -632,8 +637,8 @@ export class Agent<TContext = unknown> {
|
|
|
632
637
|
// Find target route by ID or title
|
|
633
638
|
const targetRoute = this.routes.find(
|
|
634
639
|
(r) =>
|
|
635
|
-
r.id === transitionConfig.
|
|
636
|
-
r.title === transitionConfig.
|
|
640
|
+
r.id === transitionConfig.nextStep ||
|
|
641
|
+
r.title === transitionConfig.nextStep
|
|
637
642
|
);
|
|
638
643
|
|
|
639
644
|
if (targetRoute) {
|
|
@@ -651,15 +656,15 @@ export class Agent<TContext = unknown> {
|
|
|
651
656
|
);
|
|
652
657
|
} else {
|
|
653
658
|
logger.warn(
|
|
654
|
-
`[Agent] Route ${selectedRoute.title} completed but target route not found: ${transitionConfig.
|
|
659
|
+
`[Agent] Route ${selectedRoute.title} completed but target route not found: ${transitionConfig.nextStep}`
|
|
655
660
|
);
|
|
656
661
|
}
|
|
657
662
|
}
|
|
658
663
|
|
|
659
|
-
// Set
|
|
660
|
-
session =
|
|
664
|
+
// Set step to END_ROUTE marker
|
|
665
|
+
session = enterStep(session, END_ROUTE_ID, "Route completed");
|
|
661
666
|
logger.debug(
|
|
662
|
-
`[Agent] Route ${selectedRoute.title} completed. Entered
|
|
667
|
+
`[Agent] Route ${selectedRoute.title} completed. Entered END_ROUTE step.`
|
|
663
668
|
);
|
|
664
669
|
|
|
665
670
|
// Stream completion chunks
|
|
@@ -734,13 +739,13 @@ export class Agent<TContext = unknown> {
|
|
|
734
739
|
*/
|
|
735
740
|
async respond(params: {
|
|
736
741
|
history: Event[];
|
|
737
|
-
|
|
738
|
-
session?:
|
|
742
|
+
step?: StepRef;
|
|
743
|
+
session?: SessionStep;
|
|
739
744
|
contextOverride?: Partial<TContext>;
|
|
740
745
|
signal?: AbortSignal;
|
|
741
746
|
}): Promise<{
|
|
742
747
|
message: string;
|
|
743
|
-
session?:
|
|
748
|
+
session?: SessionStep;
|
|
744
749
|
toolCalls?: Array<{ toolName: string; arguments: Record<string, unknown> }>;
|
|
745
750
|
isRouteComplete?: boolean;
|
|
746
751
|
}> {
|
|
@@ -766,27 +771,27 @@ export class Agent<TContext = unknown> {
|
|
|
766
771
|
let session =
|
|
767
772
|
params.session || this.currentSession || createSession<TContext>();
|
|
768
773
|
|
|
769
|
-
// PHASE 1: TOOL EXECUTION - Execute tools if current
|
|
770
|
-
if (session.currentRoute && session.
|
|
774
|
+
// PHASE 1: TOOL EXECUTION - Execute tools if current step has tool
|
|
775
|
+
if (session.currentRoute && session.currentStep) {
|
|
771
776
|
const currentRoute = this.routes.find(
|
|
772
777
|
(r) => r.id === session.currentRoute?.id
|
|
773
778
|
);
|
|
774
779
|
if (currentRoute) {
|
|
775
|
-
const
|
|
776
|
-
if (
|
|
777
|
-
const transitions =
|
|
778
|
-
const toolTransition = transitions.find((t) => t.spec.
|
|
780
|
+
const currentStep = currentRoute.getStep(session.currentStep.id);
|
|
781
|
+
if (currentStep) {
|
|
782
|
+
const transitions = currentStep.getTransitions();
|
|
783
|
+
const toolTransition = transitions.find((t) => t.spec.tool);
|
|
779
784
|
|
|
780
|
-
if (toolTransition?.spec.
|
|
785
|
+
if (toolTransition?.spec.tool) {
|
|
781
786
|
const toolExecutor = new ToolExecutor<TContext, unknown>();
|
|
782
787
|
// Get allowed domains from current route for security enforcement
|
|
783
788
|
const allowedDomains = currentRoute.getDomains();
|
|
784
789
|
const result = await toolExecutor.executeTool(
|
|
785
|
-
toolTransition.spec.
|
|
790
|
+
toolTransition.spec.tool as ToolRef<TContext, unknown[], unknown>,
|
|
786
791
|
effectiveContext,
|
|
787
792
|
this.updateContext.bind(this),
|
|
788
793
|
history,
|
|
789
|
-
session.
|
|
794
|
+
session.data,
|
|
790
795
|
allowedDomains
|
|
791
796
|
);
|
|
792
797
|
|
|
@@ -797,15 +802,12 @@ export class Agent<TContext = unknown> {
|
|
|
797
802
|
);
|
|
798
803
|
}
|
|
799
804
|
|
|
800
|
-
// Update
|
|
801
|
-
if (result.
|
|
802
|
-
session = await this.
|
|
803
|
-
session,
|
|
804
|
-
result.extractedUpdate
|
|
805
|
-
);
|
|
805
|
+
// Update collected data with tool results
|
|
806
|
+
if (result.collectedUpdate) {
|
|
807
|
+
session = await this.updateData(session, result.collectedUpdate);
|
|
806
808
|
logger.debug(
|
|
807
|
-
`[Agent] Tool updated
|
|
808
|
-
result.
|
|
809
|
+
`[Agent] Tool updated collected data:`,
|
|
810
|
+
result.collectedUpdate
|
|
809
811
|
);
|
|
810
812
|
}
|
|
811
813
|
|
|
@@ -817,10 +819,10 @@ export class Agent<TContext = unknown> {
|
|
|
817
819
|
}
|
|
818
820
|
}
|
|
819
821
|
|
|
820
|
-
// PHASE 2: ROUTING +
|
|
822
|
+
// PHASE 2: ROUTING + STEP SELECTION - Determine which route and step to use (combined)
|
|
821
823
|
let selectedRoute: Route<TContext> | undefined;
|
|
822
824
|
let responseDirectives: string[] | undefined;
|
|
823
|
-
let
|
|
825
|
+
let selectedStep: Step<TContext> | undefined;
|
|
824
826
|
let isRouteComplete = false;
|
|
825
827
|
|
|
826
828
|
// Check for pending transition from previous route completion
|
|
@@ -842,7 +844,7 @@ export class Agent<TContext = unknown> {
|
|
|
842
844
|
|
|
843
845
|
// Merge initial data if available
|
|
844
846
|
if (targetRoute.initialData) {
|
|
845
|
-
session =
|
|
847
|
+
session = mergeCollected(session, targetRoute.initialData);
|
|
846
848
|
}
|
|
847
849
|
|
|
848
850
|
selectedRoute = targetRoute;
|
|
@@ -860,7 +862,7 @@ export class Agent<TContext = unknown> {
|
|
|
860
862
|
|
|
861
863
|
// If no pending transition or transition handled, do normal routing
|
|
862
864
|
if (this.routes.length > 0 && !selectedRoute) {
|
|
863
|
-
const orchestration = await this.routingEngine.
|
|
865
|
+
const orchestration = await this.routingEngine.decideRouteAndStep({
|
|
864
866
|
routes: this.routes,
|
|
865
867
|
session,
|
|
866
868
|
history,
|
|
@@ -876,7 +878,7 @@ export class Agent<TContext = unknown> {
|
|
|
876
878
|
});
|
|
877
879
|
|
|
878
880
|
selectedRoute = orchestration.selectedRoute;
|
|
879
|
-
|
|
881
|
+
selectedStep = orchestration.selectedStep;
|
|
880
882
|
responseDirectives = orchestration.responseDirectives;
|
|
881
883
|
session = orchestration.session;
|
|
882
884
|
isRouteComplete = orchestration.isRouteComplete || false;
|
|
@@ -884,62 +886,62 @@ export class Agent<TContext = unknown> {
|
|
|
884
886
|
// Log if route is complete
|
|
885
887
|
if (isRouteComplete) {
|
|
886
888
|
logger.debug(
|
|
887
|
-
`[Agent] Route complete: all required data collected,
|
|
889
|
+
`[Agent] Route complete: all required data collected, END_ROUTE reached`
|
|
888
890
|
);
|
|
889
891
|
}
|
|
890
892
|
}
|
|
891
893
|
|
|
892
|
-
// PHASE 3: DETERMINE NEXT
|
|
894
|
+
// PHASE 3: DETERMINE NEXT STEP - Use step from combined decision or get initial step
|
|
893
895
|
let message: string;
|
|
894
896
|
const toolCalls:
|
|
895
897
|
| Array<{ toolName: string; arguments: Record<string, unknown> }>
|
|
896
898
|
| undefined = undefined;
|
|
897
899
|
|
|
898
900
|
if (selectedRoute && !isRouteComplete) {
|
|
899
|
-
let
|
|
901
|
+
let nextStep: Step<TContext>;
|
|
900
902
|
|
|
901
|
-
// If we have a selected
|
|
902
|
-
if (
|
|
903
|
-
|
|
903
|
+
// If we have a selected step from the combined routing decision, use it
|
|
904
|
+
if (selectedStep) {
|
|
905
|
+
nextStep = selectedStep;
|
|
904
906
|
} else {
|
|
905
|
-
// New route or no
|
|
906
|
-
const candidates = this.routingEngine.
|
|
907
|
+
// New route or no step selected - get initial step or first valid step
|
|
908
|
+
const candidates = this.routingEngine.getCandidateSteps(
|
|
907
909
|
selectedRoute,
|
|
908
910
|
undefined,
|
|
909
|
-
session.
|
|
911
|
+
session.data || {}
|
|
910
912
|
);
|
|
911
913
|
if (candidates.length > 0) {
|
|
912
|
-
|
|
914
|
+
nextStep = candidates[0].step;
|
|
913
915
|
logger.debug(
|
|
914
|
-
`[Agent] Using first valid
|
|
916
|
+
`[Agent] Using first valid step: ${nextStep.id} for new route`
|
|
915
917
|
);
|
|
916
918
|
} else {
|
|
917
|
-
// Fallback to initial
|
|
918
|
-
|
|
919
|
+
// Fallback to initial step even if it should be skipped
|
|
920
|
+
nextStep = selectedRoute.initialStep;
|
|
919
921
|
logger.warn(
|
|
920
|
-
`[Agent] No valid
|
|
922
|
+
`[Agent] No valid steps found, using initial step: ${nextStep.id}`
|
|
921
923
|
);
|
|
922
924
|
}
|
|
923
925
|
}
|
|
924
926
|
|
|
925
|
-
// Update session with next
|
|
926
|
-
session =
|
|
927
|
-
logger.debug(`[Agent] Entered
|
|
927
|
+
// Update session with next step
|
|
928
|
+
session = enterStep(session, nextStep.id, nextStep.description);
|
|
929
|
+
logger.debug(`[Agent] Entered step: ${nextStep.id}`);
|
|
928
930
|
|
|
929
|
-
// PHASE 4: RESPONSE GENERATION - Generate message using selected route and
|
|
931
|
+
// PHASE 4: RESPONSE GENERATION - Generate message using selected route and step
|
|
930
932
|
// Get last user message
|
|
931
933
|
const lastUserMessage = getLastMessageFromHistory(history);
|
|
932
934
|
|
|
933
|
-
// Build response schema for this route (with
|
|
935
|
+
// Build response schema for this route (with collect fields from step)
|
|
934
936
|
const responseSchema = this.responseEngine.responseSchemaForRoute(
|
|
935
937
|
selectedRoute,
|
|
936
|
-
|
|
938
|
+
nextStep
|
|
937
939
|
);
|
|
938
940
|
|
|
939
941
|
// Build response prompt
|
|
940
942
|
const responsePrompt = this.responseEngine.buildResponsePrompt(
|
|
941
943
|
selectedRoute,
|
|
942
|
-
|
|
944
|
+
nextStep,
|
|
943
945
|
selectedRoute.getRules(),
|
|
944
946
|
selectedRoute.getProhibitions(),
|
|
945
947
|
responseDirectives,
|
|
@@ -967,23 +969,23 @@ export class Agent<TContext = unknown> {
|
|
|
967
969
|
|
|
968
970
|
message = result.structured?.message || result.message;
|
|
969
971
|
|
|
970
|
-
// Extract
|
|
971
|
-
if (result.structured &&
|
|
972
|
-
const
|
|
973
|
-
// The structured response includes both base fields and
|
|
972
|
+
// Extract collected data from response
|
|
973
|
+
if (result.structured && nextStep.collectFields) {
|
|
974
|
+
const collectedData: Record<string, unknown> = {};
|
|
975
|
+
// The structured response includes both base fields and collected extraction fields
|
|
974
976
|
const structuredData = result.structured as AgentStructuredResponse &
|
|
975
977
|
Record<string, unknown>;
|
|
976
978
|
|
|
977
|
-
for (const field of
|
|
979
|
+
for (const field of nextStep.collectFields) {
|
|
978
980
|
if (field in structuredData) {
|
|
979
|
-
|
|
981
|
+
collectedData[field] = structuredData[field];
|
|
980
982
|
}
|
|
981
983
|
}
|
|
982
984
|
|
|
983
|
-
// Merge
|
|
984
|
-
if (Object.keys(
|
|
985
|
-
session = await this.
|
|
986
|
-
logger.debug(`[Agent]
|
|
985
|
+
// Merge collected data into session
|
|
986
|
+
if (Object.keys(collectedData).length > 0) {
|
|
987
|
+
session = await this.updateData(session, collectedData);
|
|
988
|
+
logger.debug(`[Agent] Collected data:`, collectedData);
|
|
987
989
|
}
|
|
988
990
|
}
|
|
989
991
|
|
|
@@ -1002,30 +1004,32 @@ export class Agent<TContext = unknown> {
|
|
|
1002
1004
|
// Route is complete - generate completion message then check for onComplete transition
|
|
1003
1005
|
const lastUserMessage = getLastMessageFromHistory(history);
|
|
1004
1006
|
|
|
1005
|
-
// Get
|
|
1006
|
-
const
|
|
1007
|
+
// Get endStep spec from route
|
|
1008
|
+
const endStepSpec = selectedRoute.endStepSpec;
|
|
1007
1009
|
|
|
1008
|
-
// Create a temporary
|
|
1009
|
-
const
|
|
1010
|
+
// Create a temporary step for completion message generation using endStep configuration
|
|
1011
|
+
const completionStep = new Step<TContext>(
|
|
1010
1012
|
selectedRoute.id,
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1013
|
+
endStepSpec.instructions ||
|
|
1014
|
+
"Summarize what was accomplished and confirm completion",
|
|
1015
|
+
endStepSpec.id || END_ROUTE_ID,
|
|
1016
|
+
endStepSpec.collect,
|
|
1014
1017
|
undefined,
|
|
1015
|
-
|
|
1016
|
-
|
|
1018
|
+
endStepSpec.requires,
|
|
1019
|
+
endStepSpec.instructions ||
|
|
1020
|
+
"Summarize what was accomplished and confirm completion based on the conversation history and collected data"
|
|
1017
1021
|
);
|
|
1018
1022
|
|
|
1019
1023
|
// Build response schema for completion
|
|
1020
1024
|
const responseSchema = this.responseEngine.responseSchemaForRoute(
|
|
1021
1025
|
selectedRoute,
|
|
1022
|
-
|
|
1026
|
+
completionStep
|
|
1023
1027
|
);
|
|
1024
1028
|
|
|
1025
1029
|
// Build completion response prompt
|
|
1026
1030
|
const completionPrompt = this.responseEngine.buildResponsePrompt(
|
|
1027
1031
|
selectedRoute,
|
|
1028
|
-
|
|
1032
|
+
completionStep,
|
|
1029
1033
|
selectedRoute.getRules(),
|
|
1030
1034
|
selectedRoute.getProhibitions(),
|
|
1031
1035
|
undefined, // No directives for completion
|
|
@@ -1051,14 +1055,15 @@ export class Agent<TContext = unknown> {
|
|
|
1051
1055
|
},
|
|
1052
1056
|
});
|
|
1053
1057
|
|
|
1054
|
-
message =
|
|
1058
|
+
message =
|
|
1059
|
+
completionResult.structured?.message || completionResult.message;
|
|
1055
1060
|
logger.debug(
|
|
1056
1061
|
`[Agent] Generated completion message for route: ${selectedRoute.title}`
|
|
1057
1062
|
);
|
|
1058
1063
|
|
|
1059
1064
|
// Check for onComplete transition
|
|
1060
1065
|
const transitionConfig = await selectedRoute.evaluateOnComplete(
|
|
1061
|
-
{
|
|
1066
|
+
{ data: session.data },
|
|
1062
1067
|
effectiveContext
|
|
1063
1068
|
);
|
|
1064
1069
|
|
|
@@ -1066,8 +1071,8 @@ export class Agent<TContext = unknown> {
|
|
|
1066
1071
|
// Find target route by ID or title
|
|
1067
1072
|
const targetRoute = this.routes.find(
|
|
1068
1073
|
(r) =>
|
|
1069
|
-
r.id === transitionConfig.
|
|
1070
|
-
r.title === transitionConfig.
|
|
1074
|
+
r.id === transitionConfig.nextStep ||
|
|
1075
|
+
r.title === transitionConfig.nextStep
|
|
1071
1076
|
);
|
|
1072
1077
|
|
|
1073
1078
|
if (targetRoute) {
|
|
@@ -1085,15 +1090,15 @@ export class Agent<TContext = unknown> {
|
|
|
1085
1090
|
);
|
|
1086
1091
|
} else {
|
|
1087
1092
|
logger.warn(
|
|
1088
|
-
`[Agent] Route ${selectedRoute.title} completed but target route not found: ${transitionConfig.
|
|
1093
|
+
`[Agent] Route ${selectedRoute.title} completed but target route not found: ${transitionConfig.nextStep}`
|
|
1089
1094
|
);
|
|
1090
1095
|
}
|
|
1091
1096
|
}
|
|
1092
1097
|
|
|
1093
|
-
// Set
|
|
1094
|
-
session =
|
|
1098
|
+
// Set step to END_ROUTE marker
|
|
1099
|
+
session = enterStep(session, END_ROUTE_ID, "Route completed");
|
|
1095
1100
|
logger.debug(
|
|
1096
|
-
`[Agent] Route ${selectedRoute.title} completed. Entered
|
|
1101
|
+
`[Agent] Route ${selectedRoute.title} completed. Entered END_ROUTE step.`
|
|
1097
1102
|
);
|
|
1098
1103
|
} else {
|
|
1099
1104
|
// Fallback: No routes defined, generate a simple response
|
|
@@ -1131,15 +1136,15 @@ export class Agent<TContext = unknown> {
|
|
|
1131
1136
|
message = result.structured?.message || result.message;
|
|
1132
1137
|
}
|
|
1133
1138
|
|
|
1134
|
-
// Auto-save session
|
|
1139
|
+
// Auto-save session step to persistence if configured
|
|
1135
1140
|
if (
|
|
1136
1141
|
this.persistenceManager &&
|
|
1137
1142
|
session.id &&
|
|
1138
1143
|
this.options.persistence?.autoSave !== false
|
|
1139
1144
|
) {
|
|
1140
|
-
await this.persistenceManager.
|
|
1145
|
+
await this.persistenceManager.saveSessionStep(session.id, session);
|
|
1141
1146
|
logger.debug(
|
|
1142
|
-
`[Agent] Auto-saved session
|
|
1147
|
+
`[Agent] Auto-saved session step to persistence: ${session.id}`
|
|
1143
1148
|
);
|
|
1144
1149
|
}
|
|
1145
1150
|
|
|
@@ -1150,9 +1155,9 @@ export class Agent<TContext = unknown> {
|
|
|
1150
1155
|
|
|
1151
1156
|
return {
|
|
1152
1157
|
message,
|
|
1153
|
-
session, // Return updated session with route/
|
|
1158
|
+
session, // Return updated session with route/step info
|
|
1154
1159
|
toolCalls,
|
|
1155
|
-
isRouteComplete, // Indicates if the route has reached
|
|
1160
|
+
isRouteComplete, // Indicates if the route has reached END_ROUTE with all data collected
|
|
1156
1161
|
};
|
|
1157
1162
|
}
|
|
1158
1163
|
|
|
@@ -1243,16 +1248,16 @@ export class Agent<TContext = unknown> {
|
|
|
1243
1248
|
|
|
1244
1249
|
/**
|
|
1245
1250
|
* Set the current session for convenience methods
|
|
1246
|
-
* @param session - Session
|
|
1251
|
+
* @param session - Session step to use for subsequent calls
|
|
1247
1252
|
*/
|
|
1248
|
-
setCurrentSession(session:
|
|
1253
|
+
setCurrentSession(session: SessionStep): void {
|
|
1249
1254
|
this.currentSession = session;
|
|
1250
1255
|
}
|
|
1251
1256
|
|
|
1252
1257
|
/**
|
|
1253
1258
|
* Get the current session (if set)
|
|
1254
1259
|
*/
|
|
1255
|
-
getCurrentSession():
|
|
1260
|
+
getCurrentSession(): SessionStep | undefined {
|
|
1256
1261
|
return this.currentSession;
|
|
1257
1262
|
}
|
|
1258
1263
|
|
|
@@ -1264,24 +1269,21 @@ export class Agent<TContext = unknown> {
|
|
|
1264
1269
|
}
|
|
1265
1270
|
|
|
1266
1271
|
/**
|
|
1267
|
-
* Get
|
|
1272
|
+
* Get collected data from current session
|
|
1268
1273
|
* @param routeId - Optional route ID to get data for (uses current route if not provided)
|
|
1269
|
-
* @returns The
|
|
1274
|
+
* @returns The collected data from the current session
|
|
1270
1275
|
*/
|
|
1271
|
-
|
|
1272
|
-
routeId?: string
|
|
1273
|
-
): Partial<TExtracted> {
|
|
1276
|
+
getData<TData = unknown>(routeId?: string): Partial<TData> {
|
|
1274
1277
|
if (!this.currentSession) {
|
|
1275
|
-
return {} as Partial<
|
|
1278
|
+
return {} as Partial<TData>;
|
|
1276
1279
|
}
|
|
1277
1280
|
if (routeId) {
|
|
1278
1281
|
return (
|
|
1279
|
-
(this.currentSession.
|
|
1280
|
-
|
|
1281
|
-
] as Partial<TExtracted>) || ({} as Partial<TExtracted>)
|
|
1282
|
+
(this.currentSession.dataByRoute?.[routeId] as Partial<TData>) ||
|
|
1283
|
+
({} as Partial<TData>)
|
|
1282
1284
|
);
|
|
1283
1285
|
}
|
|
1284
|
-
return (this.currentSession.
|
|
1286
|
+
return (this.currentSession.data as Partial<TData>) || {};
|
|
1285
1287
|
}
|
|
1286
1288
|
|
|
1287
1289
|
/**
|
|
@@ -1289,23 +1291,23 @@ export class Agent<TContext = unknown> {
|
|
|
1289
1291
|
* Sets a pending transition that will be executed on the next respond() call
|
|
1290
1292
|
*
|
|
1291
1293
|
* @param routeIdOrTitle - Route ID or title to transition to
|
|
1292
|
-
* @param session - Session
|
|
1294
|
+
* @param session - Session step to update (uses current session if not provided)
|
|
1293
1295
|
* @param condition - Optional AI-evaluated condition for the transition
|
|
1294
1296
|
* @returns Updated session with pending transition
|
|
1295
1297
|
*
|
|
1296
1298
|
* @example
|
|
1297
1299
|
* // After route completes
|
|
1298
1300
|
* if (response.isRouteComplete && response.session) {
|
|
1299
|
-
* const updatedSession = agent.
|
|
1301
|
+
* const updatedSession = agent.nextStepRoute("feedback-collection", response.session);
|
|
1300
1302
|
* // Next respond() call will automatically transition to feedback route
|
|
1301
1303
|
* const nextResponse = await agent.respond({ history, session: updatedSession });
|
|
1302
1304
|
* }
|
|
1303
1305
|
*/
|
|
1304
|
-
|
|
1306
|
+
nextStepRoute(
|
|
1305
1307
|
routeIdOrTitle: string,
|
|
1306
|
-
session?:
|
|
1308
|
+
session?: SessionStep,
|
|
1307
1309
|
condition?: string
|
|
1308
|
-
):
|
|
1310
|
+
): SessionStep {
|
|
1309
1311
|
const targetSession = session || this.currentSession;
|
|
1310
1312
|
|
|
1311
1313
|
if (!targetSession) {
|
|
@@ -1321,11 +1323,13 @@ export class Agent<TContext = unknown> {
|
|
|
1321
1323
|
|
|
1322
1324
|
if (!targetRoute) {
|
|
1323
1325
|
throw new Error(
|
|
1324
|
-
`Route not found: ${routeIdOrTitle}. Available routes: ${this.routes
|
|
1326
|
+
`Route not found: ${routeIdOrTitle}. Available routes: ${this.routes
|
|
1327
|
+
.map((r) => r.title)
|
|
1328
|
+
.join(", ")}`
|
|
1325
1329
|
);
|
|
1326
1330
|
}
|
|
1327
1331
|
|
|
1328
|
-
const updatedSession:
|
|
1332
|
+
const updatedSession: SessionStep = {
|
|
1329
1333
|
...targetSession,
|
|
1330
1334
|
pendingTransition: {
|
|
1331
1335
|
targetRouteId: targetRoute.id,
|