@falai/agent 0.6.7 → 0.6.9

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.
Files changed (60) hide show
  1. package/README.md +162 -30
  2. package/dist/cjs/core/Agent.d.ts +18 -0
  3. package/dist/cjs/core/Agent.d.ts.map +1 -1
  4. package/dist/cjs/core/Agent.js +218 -15
  5. package/dist/cjs/core/Agent.js.map +1 -1
  6. package/dist/cjs/core/Route.d.ts +12 -1
  7. package/dist/cjs/core/Route.d.ts.map +1 -1
  8. package/dist/cjs/core/Route.js +38 -1
  9. package/dist/cjs/core/Route.js.map +1 -1
  10. package/dist/cjs/core/RoutingEngine.d.ts.map +1 -1
  11. package/dist/cjs/core/RoutingEngine.js +3 -1
  12. package/dist/cjs/core/RoutingEngine.js.map +1 -1
  13. package/dist/cjs/core/State.js +1 -1
  14. package/dist/cjs/core/State.js.map +1 -1
  15. package/dist/cjs/index.d.ts +2 -2
  16. package/dist/cjs/index.d.ts.map +1 -1
  17. package/dist/cjs/index.js.map +1 -1
  18. package/dist/cjs/types/route.d.ts +52 -1
  19. package/dist/cjs/types/route.d.ts.map +1 -1
  20. package/dist/cjs/types/session.d.ts +17 -1
  21. package/dist/cjs/types/session.d.ts.map +1 -1
  22. package/dist/cjs/types/session.js.map +1 -1
  23. package/dist/core/Agent.d.ts +18 -0
  24. package/dist/core/Agent.d.ts.map +1 -1
  25. package/dist/core/Agent.js +219 -16
  26. package/dist/core/Agent.js.map +1 -1
  27. package/dist/core/Route.d.ts +12 -1
  28. package/dist/core/Route.d.ts.map +1 -1
  29. package/dist/core/Route.js +38 -1
  30. package/dist/core/Route.js.map +1 -1
  31. package/dist/core/RoutingEngine.d.ts.map +1 -1
  32. package/dist/core/RoutingEngine.js +3 -1
  33. package/dist/core/RoutingEngine.js.map +1 -1
  34. package/dist/core/State.js +1 -1
  35. package/dist/core/State.js.map +1 -1
  36. package/dist/index.d.ts +2 -2
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/types/route.d.ts +52 -1
  40. package/dist/types/route.d.ts.map +1 -1
  41. package/dist/types/session.d.ts +17 -1
  42. package/dist/types/session.d.ts.map +1 -1
  43. package/dist/types/session.js.map +1 -1
  44. package/docs/EXAMPLES.md +51 -2
  45. package/docs/ROUTES.md +345 -1
  46. package/docs/STATES.md +97 -7
  47. package/examples/business-onboarding.ts +10 -12
  48. package/examples/company-qna-agent.ts +4 -5
  49. package/examples/healthcare-agent.ts +63 -0
  50. package/examples/persistent-onboarding.ts +6 -8
  51. package/examples/route-transitions.ts +242 -0
  52. package/examples/travel-agent.ts +60 -0
  53. package/package.json +1 -1
  54. package/src/core/Agent.ts +338 -16
  55. package/src/core/Route.ts +53 -1
  56. package/src/core/RoutingEngine.ts +3 -1
  57. package/src/core/State.ts +1 -1
  58. package/src/index.ts +3 -1
  59. package/src/types/route.ts +58 -1
  60. package/src/types/session.ts +20 -2
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  # 🤖 @falai/agent
4
4
 
5
- ### Build intelligent, conversational AI agents with TypeScript
5
+ ### Type-Safe AI Conversational Agents That Actually Work in Production
6
6
 
7
- **StandaloneStrongly-TypedProduction-Ready**
7
+ **Schema-driven data extraction Predictable conversations Enterprise-ready**
8
8
 
9
9
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.3+-blue.svg)](https://www.typescriptlang.org/)
10
10
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE)
@@ -17,6 +17,46 @@
17
17
 
18
18
  ---
19
19
 
20
+ ## ⚡ The @falai/agent Difference
21
+
22
+ ### Traditional AI Chat:
23
+ ```typescript
24
+ // User: "I want to book the Grand Hotel for 2 people"
25
+ // AI: "Sure! Which hotel would you like?" // 😠 Asked already!
26
+ // User: "Grand Hotel"
27
+ // AI: "How many guests?" // 😠 You just told me!
28
+ // User: "2 people"
29
+ // AI: "What date?" // Finally...
30
+ ```
31
+
32
+ ### With @falai/agent:
33
+ ```typescript
34
+ // User: "I want to book the Grand Hotel for 2 people"
35
+ // AI: "Sure! For what date would you like to book?" // ✅ Skips known info
36
+ // User: "Next Friday"
37
+ // AI: "Booking confirmed for 2 guests at Grand Hotel on Friday!" // ✅ All data extracted
38
+ ```
39
+
40
+ **No more repetitive questions. No more guessing what the AI will ask next.**
41
+
42
+ Schema-first extraction means the AI automatically captures what you've already said, and only asks for what's missing.
43
+
44
+ ---
45
+
46
+ ## 🤔 Why @falai/agent?
47
+
48
+ After building production AI applications, we found existing solutions either:
49
+
50
+ - **Too unpredictable** - AI decides everything, including which tools to call (unreliable in production)
51
+ - **Too complex** - Heavy Python frameworks with massive dependencies
52
+ - **Too basic** - No structured data extraction or state management
53
+
54
+ @falai/agent gives you **predictable AI** - the creativity of LLMs with the reliability of code.
55
+
56
+ **The key insight:** Let AI do what it's good at (understanding intent, generating responses, extracting data), and let TypeScript handle the rest (state logic, tool execution, validation).
57
+
58
+ ---
59
+
20
60
  ## 🌟 Features
21
61
 
22
62
  <table>
@@ -51,6 +91,7 @@
51
91
  - **Text-Based Conditions** - Human-readable transition conditions for the AI to evaluate
52
92
  - **Code-Based Logic** - Deterministic state progression with `skipIf` and `requiredData`
53
93
  - **Always-On Routing** - Context-aware routing respects user intent changes
94
+ - **Route Transitions** - Automatic transitions between routes with `onComplete` for seamless workflows
54
95
 
55
96
  </td>
56
97
  <td width="50%">
@@ -112,7 +153,50 @@ yarn add @falai/agent
112
153
 
113
154
  ## 🚀 Quick Start
114
155
 
115
- Build a data-driven conversational AI agent in minutes. This example shows how to intelligently gather structured data over multiple turns.
156
+ ### Level 1: Your First Agent (30 seconds)
157
+
158
+ Create a minimal conversational agent:
159
+
160
+ ```typescript
161
+ import { Agent, GeminiProvider } from "@falai/agent";
162
+
163
+ // Create your agent
164
+ const agent = new Agent({
165
+ name: "Assistant",
166
+ description: "A helpful assistant",
167
+ ai: new GeminiProvider({
168
+ apiKey: process.env.GEMINI_API_KEY!,
169
+ model: "models/gemini-2.0-flash-exp",
170
+ }),
171
+ });
172
+
173
+ // Create a simple route
174
+ agent.createRoute({
175
+ title: "General Help",
176
+ description: "Answers user questions",
177
+ conditions: ["User needs help or asks a question"],
178
+ initialState: {
179
+ chatState: "Answer the user's question helpfully",
180
+ },
181
+ });
182
+
183
+ // Start chatting
184
+ const response = await agent.respond({
185
+ history: [
186
+ { source: "customer", name: "Alice", content: "What can you do?" },
187
+ ],
188
+ });
189
+
190
+ console.log(response.message);
191
+ ```
192
+
193
+ **That's it!** You now have a working conversational AI agent.
194
+
195
+ ---
196
+
197
+ ### Level 2: Data Extraction (The Real Power)
198
+
199
+ Now let's build an agent that intelligently gathers structured data:
116
200
 
117
201
  ```typescript
118
202
  import {
@@ -168,6 +252,9 @@ const bookingRoute = agent.createRoute<HotelBookingData>({
168
252
  },
169
253
  required: ["hotelName", "date", "guests"],
170
254
  },
255
+ endState: {
256
+ chatState: "Confirm the booking details warmly and thank the user",
257
+ },
171
258
  });
172
259
 
173
260
  // 5️⃣ Build the flow to gather data step-by-step
@@ -243,7 +330,7 @@ for await (const chunk of agent.respondStream({ history })) {
243
330
  ```typescript
244
331
  let session = createSession<MyData>();
245
332
  const response = await agent.respond({ history, session });
246
- session = response.session!; // Tracks progress across turns
333
+ session = response.session!; // Tracks progress across turns, you can use it to save the current state in your database
247
334
  ```
248
335
 
249
336
  **Database persistence** with any adapter:
@@ -282,45 +369,78 @@ const agent = new Agent({
282
369
 
283
370
  ---
284
371
 
285
- ## 🎯 Examples
372
+ ## 🎯 Examples - Pick Your Use Case
286
373
 
287
- **Core Examples:**
374
+ ### 🤖 Conversational Flows
375
+ Build intelligent data-gathering conversations:
288
376
 
289
- - 🏢 **[Business Onboarding](./examples/business-onboarding.ts)** - Complex multi-step flow with branching
290
- - ✈️ **[Travel Agent](./examples/travel-agent.ts)** - Multi-route booking system with session state
291
- - 🏥 **[Healthcare Assistant](./examples/healthcare-agent.ts)** - Appointment scheduling & lab results
292
- - 📋 **[Declarative Agent](./examples/declarative-agent.ts)** - Full constructor-based configuration
293
- - **[Streaming Responses](./examples/streaming-agent.ts)** - Real-time response streaming
377
+ - 🏢 **[Business Onboarding](./examples/business-onboarding.ts)** - Multi-step company setup with conditional branching
378
+ - ✈️ **[Travel Agent](./examples/travel-agent.ts)** - Flight & hotel booking with session state
379
+ - 🏥 **[Healthcare Assistant](./examples/healthcare-agent.ts)** - Appointment scheduling & lab result delivery
380
+
381
+ ### 🏢 Production Patterns
382
+ Enterprise-ready features:
294
383
 
295
- **Persistence & Advanced:**
384
+ - 💾 **[Prisma Persistence](./examples/prisma-persistence.ts)** - Auto-save sessions with Prisma ORM
385
+ - ⚡ **[Redis Persistence](./examples/redis-persistence.ts)** - High-performance in-memory sessions
386
+ - 🔐 **[Domain Scoping](./examples/domain-scoping.ts)** - Tool security & access control
296
387
 
297
- - 💾 **[Prisma Persistence](./examples/prisma-persistence.ts)** - Auto-save with Prisma ORM
298
- - ⚡ **[Redis Persistence](./examples/redis-persistence.ts)** - Fast in-memory sessions
299
- - 🔐 **[Domain Scoping](./examples/domain-scoping.ts)** - Tool security per route
388
+ ### Advanced Techniques
389
+ Power-user features:
390
+
391
+ - 📋 **[Declarative Agent](./examples/declarative-agent.ts)** - Full constructor-based configuration
392
+ - ⚡ **[Streaming Responses](./examples/streaming-agent.ts)** - Real-time response streaming
300
393
  - 📜 **[Rules & Prohibitions](./examples/rules-prohibitions.ts)** - Fine-grained behavior control
301
394
 
302
- 📖 **[See all examples with descriptions →](./docs/EXAMPLES.md)**
395
+ 📖 **[See all examples with detailed explanations →](./docs/EXAMPLES.md)**
303
396
 
304
397
  ---
305
398
 
306
399
  ## 🏗️ How It Works
307
400
 
308
- `@falai/agent` uses a **state machine-driven architecture** where conversations flow through explicit states:
401
+ `@falai/agent` uses a **schema-first, state machine-driven architecture**:
309
402
 
310
- 1. **Router** - AI selects the best route based on conversation context
311
- 2. **State Machine** - Routes define explicit states and transitions
312
- 3. **Data Extraction** - JSON Schema defines data to extract during conversation
313
- 4. **Tool Execution** - Tools run automatically when state conditions match
314
- 5. **Message Generation** - AI generates natural responses based on current state
403
+ ```
404
+ User Message
405
+
406
+ ┌─────────────────────────────────────────┐
407
+ │ 1. PREPARATION (Tools) │
408
+ │ • Execute tools for current state │
409
+ │ • Update context with results │
410
+ │ • Enrich extracted data │
411
+ └─────────────────────────────────────────┘
412
+
413
+ ┌─────────────────────────────────────────┐
414
+ │ 2. ROUTING (AI-Driven) │
415
+ │ • Evaluate all routes │
416
+ │ • Consider session context │
417
+ │ • Select best route (0-100 score) │
418
+ └─────────────────────────────────────────┘
419
+
420
+ ┌─────────────────────────────────────────┐
421
+ │ 3. STATE SELECTION (Code + AI) │
422
+ │ • Filter states with skipIf (code) │
423
+ │ • AI picks best from valid states │
424
+ │ • Update session state │
425
+ └─────────────────────────────────────────┘
426
+
427
+ ┌─────────────────────────────────────────┐
428
+ │ 4. RESPONSE (AI + Schema) │
429
+ │ • Extract data via JSON Schema │
430
+ │ • Generate natural message │
431
+ │ • Update session with new data │
432
+ └─────────────────────────────────────────┘
433
+
434
+ Response with Structured Data
435
+ ```
315
436
 
316
- **Behind the scenes:**
437
+ ### Key Principles:
317
438
 
318
- - The AI only generates messages and extracts data - it never decides which tools to call
319
- - Tools execute deterministically based on state transitions and code-based conditions
320
- - Session state tracks progress and extracted data across conversation turns
321
- - Always-on routing lets users change direction mid-conversation
439
+ **AI decides:** Route selection, state selection (from valid options), message generation, data extraction
440
+ **Code decides:** Tool execution, state filtering (`skipIf`), data validation, flow control
441
+ **Result:** Predictable, testable agents with natural conversations
322
442
 
323
- This creates **predictable, testable agents** perfect for production use cases.
443
+ **This architecture delivers 1-2 LLM calls per turn** (vs 3-5 in traditional approaches) while maintaining complete type safety.
324
444
 
325
445
  📖 **[Read the full architecture guide →](./docs/ARCHITECTURE.md)**
326
446
 
@@ -349,10 +469,22 @@ MIT © 2025
349
469
 
350
470
  <div align="center">
351
471
 
352
- **Made with ❤️ for the community**
472
+ ## 🚀 Ready to Build?
473
+
474
+ **Choose your path:**
475
+
476
+ 👶 **New to AI agents?** → [5-minute tutorial](./docs/GETTING_STARTED.md)
477
+ 🏗️ **Building production app?** → [Architecture guide](./docs/ARCHITECTURE.md)
478
+ 💡 **Have questions?** → [Open a discussion](https://github.com/falai-dev/agent/discussions)
479
+
480
+ ---
481
+
482
+ ### ⭐ Star us on [GitHub](https://github.com/falai-dev/agent)
483
+
484
+ **Help us reach more developers building production AI!**
353
485
 
354
486
  [Report Bug](https://github.com/falai-dev/agent/issues) • [Request Feature](https://github.com/falai-dev/agent/issues) • [Contribute](https://github.com/falai-dev/agent/pulls)
355
487
 
356
- Star us on [GitHub](https://github.com/falai-dev/agent) if this helped you build amazing agents!
488
+ **Made with ❤️ for the community**
357
489
 
358
490
  </div>
@@ -175,5 +175,23 @@ export declare class Agent<TContext = unknown> {
175
175
  * @returns The extracted data from the current session
176
176
  */
177
177
  getExtractedData<TExtracted = unknown>(routeId?: string): Partial<TExtracted>;
178
+ /**
179
+ * Manually transition to a different route
180
+ * Sets a pending transition that will be executed on the next respond() call
181
+ *
182
+ * @param routeIdOrTitle - Route ID or title to transition to
183
+ * @param session - Session state to update (uses current session if not provided)
184
+ * @param condition - Optional AI-evaluated condition for the transition
185
+ * @returns Updated session with pending transition
186
+ *
187
+ * @example
188
+ * // After route completes
189
+ * if (response.isRouteComplete && response.session) {
190
+ * const updatedSession = agent.transitionToRoute("feedback-collection", response.session);
191
+ * // Next respond() call will automatically transition to feedback route
192
+ * const nextResponse = await agent.respond({ history, session: updatedSession });
193
+ * }
194
+ */
195
+ transitionToRoute(routeIdOrTitle: string, session?: SessionState, condition?: string): SessionState;
178
196
  }
179
197
  //# sourceMappingURL=Agent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Agent.d.ts","sourceRoot":"","sources":["../../../src/core/Agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Agent.d.ts","sourceRoot":"","sources":["../../../src/core/Agent.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ const session_1 = require("../types/session");
8
8
  const PromptComposer_1 = require("./PromptComposer");
9
9
  const logger_1 = require("../utils/logger");
10
10
  const Route_1 = require("./Route");
11
+ const State_1 = require("./State");
11
12
  const DomainRegistry_1 = require("./DomainRegistry");
12
13
  const PersistenceManager_1 = require("./PersistenceManager");
13
14
  const RoutingEngine_1 = require("./RoutingEngine");
@@ -190,8 +191,7 @@ class Agent {
190
191
  };
191
192
  // Trigger lifecycle hook if configured
192
193
  if (this.options.hooks?.onExtractedUpdate) {
193
- const updatedExtracted = (await this.options.hooks.onExtractedUpdate(newExtracted, previousExtracted));
194
- newExtracted = updatedExtracted;
194
+ newExtracted = (await this.options.hooks.onExtractedUpdate(newExtracted, previousExtracted));
195
195
  }
196
196
  // Return updated session
197
197
  return (0, session_1.mergeExtracted)(session, newExtracted);
@@ -260,7 +260,34 @@ class Agent {
260
260
  let responseDirectives;
261
261
  let selectedState;
262
262
  let isRouteComplete = false;
263
- if (this.routes.length > 0) {
263
+ // Check for pending transition from previous route completion
264
+ if (session.pendingTransition) {
265
+ const targetRoute = this.routes.find((r) => r.id === session.pendingTransition?.targetRouteId);
266
+ if (targetRoute) {
267
+ logger_1.logger.debug(`[Agent] Auto-transitioning from pending transition to route: ${targetRoute.title}`);
268
+ // Clear pending transition and enter new route
269
+ session = {
270
+ ...session,
271
+ pendingTransition: undefined,
272
+ };
273
+ session = (0, session_1.enterRoute)(session, targetRoute.id, targetRoute.title);
274
+ // Merge initial data if available
275
+ if (targetRoute.initialData) {
276
+ session = (0, session_1.mergeExtracted)(session, targetRoute.initialData);
277
+ }
278
+ selectedRoute = targetRoute;
279
+ }
280
+ else {
281
+ logger_1.logger.warn(`[Agent] Pending transition target route not found: ${session.pendingTransition.targetRouteId}`);
282
+ // Clear invalid transition
283
+ session = {
284
+ ...session,
285
+ pendingTransition: undefined,
286
+ };
287
+ }
288
+ }
289
+ // If no pending transition or transition handled, do normal routing
290
+ if (this.routes.length > 0 && !selectedRoute) {
264
291
  const orchestration = await this.routingEngine.decideRouteAndState({
265
292
  routes: this.routes,
266
293
  session,
@@ -381,17 +408,74 @@ class Agent {
381
408
  }
382
409
  }
383
410
  else if (isRouteComplete && selectedRoute) {
384
- // Route is complete - set state to END_STATE marker and yield completion signal
411
+ // Route is complete - generate completion message then check for onComplete transition
412
+ const lastUserMessage = (0, event_1.getLastMessageFromHistory)(history);
413
+ // Get endState spec from route
414
+ const endStateSpec = selectedRoute.endStateSpec;
415
+ // Create a temporary state for completion message generation using endState configuration
416
+ const completionState = new State_1.State(selectedRoute.id, endStateSpec.chatState || "Summarize what was accomplished and confirm completion", endStateSpec.id || constants_1.END_STATE_ID, endStateSpec.gather, undefined, endStateSpec.requiredData, endStateSpec.chatState || "Summarize what was accomplished and confirm completion based on the conversation history and collected data");
417
+ // Build response schema for completion
418
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionState);
419
+ // Build completion response prompt
420
+ const completionPrompt = this.responseEngine.buildResponsePrompt(selectedRoute, completionState, selectedRoute.getRules(), selectedRoute.getProhibitions(), undefined, // No directives for completion
421
+ history, lastUserMessage, {
422
+ name: this.options.name,
423
+ goal: this.options.goal,
424
+ description: this.options.description,
425
+ personality: this.options.personality,
426
+ });
427
+ // Stream completion message using AI provider
428
+ const stream = this.options.ai.generateMessageStream({
429
+ prompt: completionPrompt,
430
+ history,
431
+ context: effectiveContext,
432
+ signal,
433
+ parameters: {
434
+ jsonSchema: responseSchema,
435
+ schemaName: "completion_message_stream",
436
+ },
437
+ });
438
+ logger_1.logger.debug(`[Agent] Streaming completion message for route: ${selectedRoute.title}`);
439
+ // Check for onComplete transition
440
+ const transitionConfig = await selectedRoute.evaluateOnComplete({ extracted: session.extracted }, effectiveContext);
441
+ if (transitionConfig) {
442
+ // Find target route by ID or title
443
+ const targetRoute = this.routes.find((r) => r.id === transitionConfig.transitionTo ||
444
+ r.title === transitionConfig.transitionTo);
445
+ if (targetRoute) {
446
+ // Set pending transition in session
447
+ session = {
448
+ ...session,
449
+ pendingTransition: {
450
+ targetRouteId: targetRoute.id,
451
+ condition: transitionConfig.condition,
452
+ reason: "route_complete",
453
+ },
454
+ };
455
+ logger_1.logger.debug(`[Agent] Route ${selectedRoute.title} completed with pending transition to: ${targetRoute.title}`);
456
+ }
457
+ else {
458
+ logger_1.logger.warn(`[Agent] Route ${selectedRoute.title} completed but target route not found: ${transitionConfig.transitionTo}`);
459
+ }
460
+ }
461
+ // Set state to END_STATE marker
385
462
  session = (0, session_1.enterState)(session, constants_1.END_STATE_ID, "Route completed");
386
463
  logger_1.logger.debug(`[Agent] Route ${selectedRoute.title} completed. Entered END_STATE state.`);
387
- yield {
388
- delta: "",
389
- accumulated: "",
390
- done: true,
391
- session,
392
- toolCalls: undefined,
393
- isRouteComplete: true,
394
- };
464
+ // Stream completion chunks
465
+ for await (const chunk of stream) {
466
+ // Update current session if we have one
467
+ if (chunk.done && this.currentSession) {
468
+ this.currentSession = session;
469
+ }
470
+ yield {
471
+ delta: chunk.delta,
472
+ accumulated: chunk.accumulated,
473
+ done: chunk.done,
474
+ session,
475
+ toolCalls: undefined,
476
+ isRouteComplete: true,
477
+ };
478
+ }
395
479
  }
396
480
  else {
397
481
  // Fallback: No routes defined, stream a simple response
@@ -492,7 +576,34 @@ class Agent {
492
576
  let responseDirectives;
493
577
  let selectedState;
494
578
  let isRouteComplete = false;
495
- if (this.routes.length > 0) {
579
+ // Check for pending transition from previous route completion
580
+ if (session.pendingTransition) {
581
+ const targetRoute = this.routes.find((r) => r.id === session.pendingTransition?.targetRouteId);
582
+ if (targetRoute) {
583
+ logger_1.logger.debug(`[Agent] Auto-transitioning from pending transition to route: ${targetRoute.title}`);
584
+ // Clear pending transition and enter new route
585
+ session = {
586
+ ...session,
587
+ pendingTransition: undefined,
588
+ };
589
+ session = (0, session_1.enterRoute)(session, targetRoute.id, targetRoute.title);
590
+ // Merge initial data if available
591
+ if (targetRoute.initialData) {
592
+ session = (0, session_1.mergeExtracted)(session, targetRoute.initialData);
593
+ }
594
+ selectedRoute = targetRoute;
595
+ }
596
+ else {
597
+ logger_1.logger.warn(`[Agent] Pending transition target route not found: ${session.pendingTransition.targetRouteId}`);
598
+ // Clear invalid transition
599
+ session = {
600
+ ...session,
601
+ pendingTransition: undefined,
602
+ };
603
+ }
604
+ }
605
+ // If no pending transition or transition handled, do normal routing
606
+ if (this.routes.length > 0 && !selectedRoute) {
496
607
  const orchestration = await this.routingEngine.decideRouteAndState({
497
608
  routes: this.routes,
498
609
  session,
@@ -591,9 +702,59 @@ class Agent {
591
702
  }
592
703
  }
593
704
  else if (isRouteComplete && selectedRoute) {
594
- // Route is complete - set state to END_STATE marker and return completion signal
705
+ // Route is complete - generate completion message then check for onComplete transition
706
+ const lastUserMessage = (0, event_1.getLastMessageFromHistory)(history);
707
+ // Get endState spec from route
708
+ const endStateSpec = selectedRoute.endStateSpec;
709
+ // Create a temporary state for completion message generation using endState configuration
710
+ const completionState = new State_1.State(selectedRoute.id, endStateSpec.chatState || "Summarize what was accomplished and confirm completion", endStateSpec.id || constants_1.END_STATE_ID, endStateSpec.gather, undefined, endStateSpec.requiredData, endStateSpec.chatState || "Summarize what was accomplished and confirm completion based on the conversation history and collected data");
711
+ // Build response schema for completion
712
+ const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionState);
713
+ // Build completion response prompt
714
+ const completionPrompt = this.responseEngine.buildResponsePrompt(selectedRoute, completionState, selectedRoute.getRules(), selectedRoute.getProhibitions(), undefined, // No directives for completion
715
+ history, lastUserMessage, {
716
+ name: this.options.name,
717
+ goal: this.options.goal,
718
+ description: this.options.description,
719
+ personality: this.options.personality,
720
+ });
721
+ // Generate completion message using AI provider
722
+ const completionResult = await this.options.ai.generateMessage({
723
+ prompt: completionPrompt,
724
+ history,
725
+ context: effectiveContext,
726
+ signal,
727
+ parameters: {
728
+ jsonSchema: responseSchema,
729
+ schemaName: "completion_message",
730
+ },
731
+ });
732
+ message = completionResult.structured?.message || completionResult.message;
733
+ logger_1.logger.debug(`[Agent] Generated completion message for route: ${selectedRoute.title}`);
734
+ // Check for onComplete transition
735
+ const transitionConfig = await selectedRoute.evaluateOnComplete({ extracted: session.extracted }, effectiveContext);
736
+ if (transitionConfig) {
737
+ // Find target route by ID or title
738
+ const targetRoute = this.routes.find((r) => r.id === transitionConfig.transitionTo ||
739
+ r.title === transitionConfig.transitionTo);
740
+ if (targetRoute) {
741
+ // Set pending transition in session
742
+ session = {
743
+ ...session,
744
+ pendingTransition: {
745
+ targetRouteId: targetRoute.id,
746
+ condition: transitionConfig.condition,
747
+ reason: "route_complete",
748
+ },
749
+ };
750
+ logger_1.logger.debug(`[Agent] Route ${selectedRoute.title} completed with pending transition to: ${targetRoute.title}`);
751
+ }
752
+ else {
753
+ logger_1.logger.warn(`[Agent] Route ${selectedRoute.title} completed but target route not found: ${transitionConfig.transitionTo}`);
754
+ }
755
+ }
756
+ // Set state to END_STATE marker
595
757
  session = (0, session_1.enterState)(session, constants_1.END_STATE_ID, "Route completed");
596
- message = "";
597
758
  logger_1.logger.debug(`[Agent] Route ${selectedRoute.title} completed. Entered END_STATE state.`);
598
759
  }
599
760
  else {
@@ -750,6 +911,48 @@ class Agent {
750
911
  }
751
912
  return this.currentSession.extracted || {};
752
913
  }
914
+ /**
915
+ * Manually transition to a different route
916
+ * Sets a pending transition that will be executed on the next respond() call
917
+ *
918
+ * @param routeIdOrTitle - Route ID or title to transition to
919
+ * @param session - Session state to update (uses current session if not provided)
920
+ * @param condition - Optional AI-evaluated condition for the transition
921
+ * @returns Updated session with pending transition
922
+ *
923
+ * @example
924
+ * // After route completes
925
+ * if (response.isRouteComplete && response.session) {
926
+ * const updatedSession = agent.transitionToRoute("feedback-collection", response.session);
927
+ * // Next respond() call will automatically transition to feedback route
928
+ * const nextResponse = await agent.respond({ history, session: updatedSession });
929
+ * }
930
+ */
931
+ transitionToRoute(routeIdOrTitle, session, condition) {
932
+ const targetSession = session || this.currentSession;
933
+ if (!targetSession) {
934
+ throw new Error("No session provided and no current session available. Please provide a session to transition.");
935
+ }
936
+ // Find target route by ID or title
937
+ const targetRoute = this.routes.find((r) => r.id === routeIdOrTitle || r.title === routeIdOrTitle);
938
+ if (!targetRoute) {
939
+ throw new Error(`Route not found: ${routeIdOrTitle}. Available routes: ${this.routes.map((r) => r.title).join(", ")}`);
940
+ }
941
+ const updatedSession = {
942
+ ...targetSession,
943
+ pendingTransition: {
944
+ targetRouteId: targetRoute.id,
945
+ condition,
946
+ reason: "manual",
947
+ },
948
+ };
949
+ // Update current session if using it
950
+ if (!session && this.currentSession) {
951
+ this.currentSession = updatedSession;
952
+ }
953
+ logger_1.logger.debug(`[Agent] Set pending manual transition to route: ${targetRoute.title}`);
954
+ return updatedSession;
955
+ }
753
956
  }
754
957
  exports.Agent = Agent;
755
958
  //# sourceMappingURL=Agent.js.map