@falai/agent 0.9.2 → 1.0.1
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 +281 -42
- package/dist/adapters/MemoryAdapter.d.ts.map +1 -0
- package/dist/adapters/MemoryAdapter.js.map +1 -0
- package/dist/adapters/MongoAdapter.d.ts.map +1 -0
- package/dist/adapters/MongoAdapter.js.map +1 -0
- package/dist/adapters/OpenSearchAdapter.d.ts.map +1 -0
- package/dist/adapters/OpenSearchAdapter.js.map +1 -0
- package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -0
- package/dist/adapters/PostgreSQLAdapter.js.map +1 -0
- package/dist/adapters/PrismaAdapter.d.ts.map +1 -0
- package/dist/{src/adapters → adapters}/PrismaAdapter.js +3 -2
- package/dist/adapters/PrismaAdapter.js.map +1 -0
- package/dist/adapters/RedisAdapter.d.ts.map +1 -0
- package/dist/{src/adapters → adapters}/RedisAdapter.js +3 -3
- package/dist/adapters/RedisAdapter.js.map +1 -0
- package/dist/adapters/SQLiteAdapter.d.ts.map +1 -0
- package/dist/adapters/SQLiteAdapter.js.map +1 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/cjs/adapters/MemoryAdapter.js.map +1 -0
- package/dist/cjs/adapters/MongoAdapter.js.map +1 -0
- package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -0
- package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -0
- package/dist/{src → cjs}/adapters/PrismaAdapter.d.ts.map +1 -1
- package/dist/cjs/{src/adapters → adapters}/PrismaAdapter.js +3 -2
- package/dist/cjs/adapters/PrismaAdapter.js.map +1 -0
- package/dist/cjs/{src/adapters → adapters}/RedisAdapter.js +2 -2
- package/dist/cjs/adapters/RedisAdapter.js.map +1 -0
- package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -0
- package/dist/cjs/adapters/index.js.map +1 -0
- package/dist/cjs/constants/index.js.map +1 -0
- package/dist/cjs/{src/core → core}/Agent.d.ts +16 -1
- package/dist/cjs/core/Agent.d.ts.map +1 -0
- package/dist/cjs/{src/core → core}/Agent.js +63 -2
- package/dist/cjs/core/Agent.js.map +1 -0
- package/dist/cjs/core/BatchExecutor.d.ts +353 -0
- package/dist/cjs/core/BatchExecutor.d.ts.map +1 -0
- package/dist/cjs/core/BatchExecutor.js +850 -0
- package/dist/cjs/core/BatchExecutor.js.map +1 -0
- package/dist/cjs/core/BatchPromptBuilder.d.ts +86 -0
- package/dist/cjs/core/BatchPromptBuilder.d.ts.map +1 -0
- package/dist/cjs/core/BatchPromptBuilder.js +217 -0
- package/dist/cjs/core/BatchPromptBuilder.js.map +1 -0
- package/dist/cjs/core/Events.js.map +1 -0
- package/dist/cjs/core/PersistenceManager.js.map +1 -0
- package/dist/{src → cjs}/core/PromptComposer.d.ts +1 -1
- package/dist/cjs/core/PromptComposer.d.ts.map +1 -0
- package/dist/cjs/{src/core → core}/PromptComposer.js +44 -7
- package/dist/cjs/core/PromptComposer.js.map +1 -0
- package/dist/{src → cjs}/core/ResponseEngine.d.ts.map +1 -1
- package/dist/cjs/core/ResponseEngine.js +211 -0
- package/dist/cjs/core/ResponseEngine.js.map +1 -0
- package/dist/{src → cjs}/core/ResponseModal.d.ts +45 -0
- package/dist/cjs/core/ResponseModal.d.ts.map +1 -0
- package/dist/cjs/{src/core → core}/ResponseModal.js +752 -74
- package/dist/cjs/core/ResponseModal.js.map +1 -0
- package/dist/{src → cjs}/core/ResponsePipeline.d.ts +2 -2
- package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -0
- package/dist/cjs/{src/core → core}/ResponsePipeline.js +13 -6
- package/dist/cjs/core/ResponsePipeline.js.map +1 -0
- package/dist/{src → cjs}/core/Route.d.ts +34 -5
- package/dist/cjs/core/Route.d.ts.map +1 -0
- package/dist/cjs/{src/core → core}/Route.js +196 -19
- package/dist/cjs/core/Route.js.map +1 -0
- package/dist/cjs/{src/core → core}/RoutingEngine.d.ts +30 -5
- package/dist/cjs/core/RoutingEngine.d.ts.map +1 -0
- package/dist/cjs/{src/core → core}/RoutingEngine.js +330 -80
- package/dist/cjs/core/RoutingEngine.js.map +1 -0
- package/dist/cjs/core/SessionManager.js.map +1 -0
- package/dist/{src → cjs}/core/Step.d.ts +31 -10
- package/dist/cjs/core/Step.d.ts.map +1 -0
- package/dist/cjs/{src/core → core}/Step.js +105 -10
- package/dist/cjs/core/Step.js.map +1 -0
- package/dist/cjs/core/ToolManager.js.map +1 -0
- package/dist/{src → cjs}/index.d.ts +4 -1
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/{src/index.js → index.js} +12 -1
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/{src/providers → providers}/AnthropicProvider.js +18 -18
- package/dist/cjs/providers/AnthropicProvider.js.map +1 -0
- package/dist/{src → cjs}/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/cjs/{src/providers → providers}/GeminiProvider.js +123 -51
- package/dist/cjs/providers/GeminiProvider.js.map +1 -0
- package/dist/cjs/{src/providers → providers}/OpenAIProvider.js +19 -19
- package/dist/cjs/providers/OpenAIProvider.js.map +1 -0
- package/dist/cjs/{src/providers → providers}/OpenRouterProvider.js +19 -19
- package/dist/cjs/providers/OpenRouterProvider.js.map +1 -0
- package/dist/cjs/providers/index.js.map +1 -0
- package/dist/cjs/{src/types → types}/agent.d.ts +15 -3
- package/dist/cjs/types/agent.d.ts.map +1 -0
- package/dist/cjs/types/agent.js.map +1 -0
- package/dist/{src → cjs}/types/ai.js.map +1 -1
- package/dist/cjs/types/history.js.map +1 -0
- package/dist/cjs/{src/types → types}/index.d.ts +2 -1
- package/dist/{src → cjs}/types/index.d.ts.map +1 -1
- package/dist/cjs/{src/types → types}/index.js +6 -1
- package/dist/cjs/types/index.js.map +1 -0
- package/dist/cjs/types/persistence.js.map +1 -0
- package/dist/cjs/{src/types → types}/route.d.ts +111 -12
- package/dist/cjs/types/route.d.ts.map +1 -0
- package/dist/cjs/{src/types → types}/route.js.map +1 -1
- package/dist/cjs/types/session.js.map +1 -0
- package/dist/cjs/types/template.d.ts +88 -0
- package/dist/cjs/types/template.d.ts.map +1 -0
- package/dist/cjs/types/tool.js.map +1 -0
- package/dist/cjs/utils/clone.js.map +1 -0
- package/dist/cjs/utils/condition.d.ts +38 -0
- package/dist/cjs/utils/condition.d.ts.map +1 -0
- package/dist/cjs/utils/condition.js +168 -0
- package/dist/cjs/utils/condition.js.map +1 -0
- package/dist/cjs/utils/event.js.map +1 -0
- package/dist/cjs/utils/history.js.map +1 -0
- package/dist/cjs/utils/id.js.map +1 -0
- package/dist/cjs/{src/utils → utils}/index.d.ts +3 -1
- package/dist/cjs/utils/index.d.ts.map +1 -0
- package/dist/cjs/{src/utils → utils}/index.js +12 -1
- package/dist/cjs/utils/index.js.map +1 -0
- package/dist/cjs/utils/json.d.ts +16 -0
- package/dist/cjs/utils/json.d.ts.map +1 -0
- package/dist/cjs/utils/json.js +47 -0
- package/dist/cjs/utils/json.js.map +1 -0
- package/dist/cjs/utils/logger.js.map +1 -0
- package/dist/{src → cjs}/utils/retry.d.ts +0 -3
- package/dist/cjs/utils/retry.d.ts.map +1 -0
- package/dist/cjs/{src/utils → utils}/retry.js +8 -7
- package/dist/cjs/utils/retry.js.map +1 -0
- package/dist/cjs/utils/session.js.map +1 -0
- package/dist/{src → cjs}/utils/template.d.ts +48 -0
- package/dist/cjs/utils/template.d.ts.map +1 -0
- package/dist/cjs/{src/utils → utils}/template.js +100 -0
- package/dist/cjs/utils/template.js.map +1 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/{src/core → core}/Agent.d.ts +16 -1
- package/dist/core/Agent.d.ts.map +1 -0
- package/dist/{src/core → core}/Agent.js +64 -3
- package/dist/core/Agent.js.map +1 -0
- package/dist/core/BatchExecutor.d.ts +353 -0
- package/dist/core/BatchExecutor.d.ts.map +1 -0
- package/dist/core/BatchExecutor.js +845 -0
- package/dist/core/BatchExecutor.js.map +1 -0
- package/dist/core/BatchPromptBuilder.d.ts +86 -0
- package/dist/core/BatchPromptBuilder.d.ts.map +1 -0
- package/dist/core/BatchPromptBuilder.js +213 -0
- package/dist/core/BatchPromptBuilder.js.map +1 -0
- package/dist/core/Events.d.ts.map +1 -0
- package/dist/core/Events.js.map +1 -0
- package/dist/core/PersistenceManager.d.ts.map +1 -0
- package/dist/core/PersistenceManager.js.map +1 -0
- package/dist/{cjs/src/core → core}/PromptComposer.d.ts +1 -1
- package/dist/core/PromptComposer.d.ts.map +1 -0
- package/dist/{src/core → core}/PromptComposer.js +45 -8
- package/dist/core/PromptComposer.js.map +1 -0
- package/dist/core/ResponseEngine.d.ts.map +1 -0
- package/dist/core/ResponseEngine.js +207 -0
- package/dist/core/ResponseEngine.js.map +1 -0
- package/dist/{cjs/src/core → core}/ResponseModal.d.ts +45 -0
- package/dist/core/ResponseModal.d.ts.map +1 -0
- package/dist/{src/core → core}/ResponseModal.js +752 -74
- package/dist/core/ResponseModal.js.map +1 -0
- package/dist/{cjs/src/core → core}/ResponsePipeline.d.ts +2 -2
- package/dist/core/ResponsePipeline.d.ts.map +1 -0
- package/dist/{src/core → core}/ResponsePipeline.js +13 -6
- package/dist/core/ResponsePipeline.js.map +1 -0
- package/dist/{cjs/src/core → core}/Route.d.ts +34 -5
- package/dist/core/Route.d.ts.map +1 -0
- package/dist/{src/core → core}/Route.js +195 -18
- package/dist/core/Route.js.map +1 -0
- package/dist/{src/core → core}/RoutingEngine.d.ts +30 -5
- package/dist/core/RoutingEngine.d.ts.map +1 -0
- package/dist/{src/core → core}/RoutingEngine.js +310 -60
- package/dist/core/RoutingEngine.js.map +1 -0
- package/dist/core/SessionManager.d.ts.map +1 -0
- package/dist/core/SessionManager.js.map +1 -0
- package/dist/{cjs/src/core → core}/Step.d.ts +31 -10
- package/dist/core/Step.d.ts.map +1 -0
- package/dist/{src/core → core}/Step.js +104 -9
- package/dist/core/Step.js.map +1 -0
- package/dist/core/ToolManager.d.ts.map +1 -0
- package/dist/core/ToolManager.js.map +1 -0
- package/dist/{cjs/src/index.d.ts → index.d.ts} +4 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/{src/index.js → index.js} +3 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/AnthropicProvider.d.ts.map +1 -0
- package/dist/{src/providers → providers}/AnthropicProvider.js +17 -17
- package/dist/providers/AnthropicProvider.js.map +1 -0
- package/dist/providers/GeminiProvider.d.ts.map +1 -0
- package/dist/{src/providers → providers}/GeminiProvider.js +123 -51
- package/dist/providers/GeminiProvider.js.map +1 -0
- package/dist/providers/OpenAIProvider.d.ts.map +1 -0
- package/dist/{src/providers → providers}/OpenAIProvider.js +18 -18
- package/dist/providers/OpenAIProvider.js.map +1 -0
- package/dist/providers/OpenRouterProvider.d.ts.map +1 -0
- package/dist/{src/providers → providers}/OpenRouterProvider.js +18 -18
- package/dist/providers/OpenRouterProvider.js.map +1 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/{src/types → types}/agent.d.ts +15 -3
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/ai.d.ts.map +1 -0
- package/dist/types/ai.js.map +1 -0
- package/dist/types/history.d.ts.map +1 -0
- package/dist/types/history.js.map +1 -0
- package/dist/{src/types → types}/index.d.ts +2 -1
- package/dist/types/index.d.ts.map +1 -0
- package/dist/{src/types → types}/index.js +1 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/persistence.d.ts.map +1 -0
- package/dist/types/persistence.js.map +1 -0
- package/dist/{src/types → types}/route.d.ts +111 -12
- package/dist/types/route.d.ts.map +1 -0
- package/dist/{src/types → types}/route.js.map +1 -1
- package/dist/types/routing.d.ts.map +1 -0
- package/dist/{cjs/src/types → types}/routing.js.map +1 -1
- package/dist/types/schema.d.ts.map +1 -0
- package/dist/{cjs/src/types → types}/schema.js.map +1 -1
- package/dist/types/session.d.ts.map +1 -0
- package/dist/{src/types → types}/session.js.map +1 -1
- package/dist/types/template.d.ts +88 -0
- package/dist/types/template.d.ts.map +1 -0
- package/dist/{cjs/src/types → types}/template.js.map +1 -1
- package/dist/types/tool.d.ts.map +1 -0
- package/dist/types/tool.js.map +1 -0
- package/dist/utils/clone.d.ts.map +1 -0
- package/dist/utils/clone.js.map +1 -0
- package/dist/utils/condition.d.ts +38 -0
- package/dist/utils/condition.d.ts.map +1 -0
- package/dist/utils/condition.js +161 -0
- package/dist/utils/condition.js.map +1 -0
- package/dist/utils/event.d.ts.map +1 -0
- package/dist/utils/event.js.map +1 -0
- package/dist/utils/history.d.ts.map +1 -0
- package/dist/utils/history.js.map +1 -0
- package/dist/utils/id.d.ts.map +1 -0
- package/dist/utils/id.js.map +1 -0
- package/dist/{src/utils → utils}/index.d.ts +3 -1
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/{src/utils → utils}/index.js +5 -1
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/json.d.ts +16 -0
- package/dist/utils/json.d.ts.map +1 -0
- package/dist/utils/json.js +43 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/{cjs/src/utils → utils}/retry.d.ts +0 -3
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/{src/utils → utils}/retry.js +5 -4
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/session.d.ts.map +1 -0
- package/dist/utils/session.js.map +1 -0
- package/dist/{cjs/src/utils → utils}/template.d.ts +48 -0
- package/dist/utils/template.d.ts.map +1 -0
- package/dist/{src/utils → utils}/template.js +98 -0
- package/dist/utils/template.js.map +1 -0
- package/docs/README.md +1 -0
- package/docs/api/README.md +237 -12
- package/docs/api/overview.md +206 -3
- package/docs/architecture/data-extraction-flow.md +363 -0
- package/docs/architecture/multi-step-execution.md +243 -0
- package/docs/core/agent/README.md +156 -5
- package/docs/core/agent/rules-and-prohibitions.md +113 -0
- package/docs/core/agent/session-management.md +1 -1
- package/docs/core/ai-integration/prompt-composition.md +135 -0
- package/docs/core/ai-integration/response-processing.md +146 -0
- package/docs/core/conversation-flows/data-collection.md +143 -0
- package/docs/core/conversation-flows/routes.md +2 -2
- package/docs/core/conversation-flows/step-transitions.md +132 -0
- package/docs/core/conversation-flows/steps.md +112 -0
- package/docs/core/error-handling.md +193 -0
- package/docs/core/routing/intelligent-routing.md +118 -0
- package/docs/guides/getting-started/README.md +284 -3
- package/docs/guides/migration/README.md +27 -0
- package/docs/guides/migration/flexible-routing-conditions.md +375 -0
- package/docs/guides/migration/multi-step-execution.md +373 -0
- package/examples/advanced-patterns/knowledge-based-agent.ts +101 -24
- package/examples/advanced-patterns/persistent-onboarding.ts +40 -5
- package/examples/advanced-patterns/route-lifecycle-hooks.ts +82 -12
- package/examples/advanced-patterns/streaming-responses.ts +2 -2
- package/examples/ai-providers/anthropic-integration.ts +4 -4
- package/examples/ai-providers/openai-integration.ts +1 -1
- package/examples/condition-patterns/function-only-conditions.ts +365 -0
- package/examples/condition-patterns/mixed-array-conditions.ts +477 -0
- package/examples/condition-patterns/route-skipif-patterns.ts +468 -0
- package/examples/condition-patterns/step-skipif-patterns.ts +0 -0
- package/examples/condition-patterns/string-only-conditions.ts +296 -0
- package/examples/conversation-flows/completion-transitions.ts +48 -7
- package/examples/core-concepts/basic-agent.ts +54 -33
- package/examples/core-concepts/schema-driven-extraction.ts +33 -9
- package/examples/core-concepts/session-management.ts +51 -16
- package/examples/integrations/database-integration.ts +6 -6
- package/examples/integrations/healthcare-integration.ts +10 -10
- package/examples/integrations/search-integration.ts +8 -8
- package/examples/integrations/server-session-management.ts +8 -8
- package/examples/persistence/database-persistence.ts +15 -15
- package/examples/persistence/memory-sessions.ts +3 -3
- package/examples/persistence/redis-persistence.ts +7 -9
- package/examples/tools/data-enrichment-tools.ts +4 -4
- package/package.json +6 -4
- package/src/adapters/PrismaAdapter.ts +3 -2
- package/src/adapters/RedisAdapter.ts +3 -3
- package/src/core/Agent.ts +78 -2
- package/src/core/BatchExecutor.ts +1166 -0
- package/src/core/BatchPromptBuilder.ts +293 -0
- package/src/core/PromptComposer.ts +53 -16
- package/src/core/ResponseEngine.ts +168 -29
- package/src/core/ResponseModal.ts +954 -74
- package/src/core/ResponsePipeline.ts +17 -9
- package/src/core/Route.ts +223 -22
- package/src/core/RoutingEngine.ts +426 -83
- package/src/core/Step.ts +144 -16
- package/src/index.ts +19 -0
- package/src/providers/AnthropicProvider.ts +17 -17
- package/src/providers/GeminiProvider.ts +129 -60
- package/src/providers/OpenAIProvider.ts +18 -18
- package/src/providers/OpenRouterProvider.ts +18 -18
- package/src/types/agent.ts +15 -3
- package/src/types/index.ts +12 -1
- package/src/types/route.ts +131 -12
- package/src/types/template.ts +70 -2
- package/src/utils/condition.ts +190 -0
- package/src/utils/index.ts +12 -0
- package/src/utils/json.ts +46 -0
- package/src/utils/retry.ts +5 -4
- package/src/utils/template.ts +109 -0
- package/dist/cjs/src/adapters/MemoryAdapter.d.ts.map +0 -1
- package/dist/cjs/src/adapters/MemoryAdapter.js.map +0 -1
- package/dist/cjs/src/adapters/MongoAdapter.d.ts.map +0 -1
- package/dist/cjs/src/adapters/MongoAdapter.js.map +0 -1
- package/dist/cjs/src/adapters/OpenSearchAdapter.d.ts.map +0 -1
- package/dist/cjs/src/adapters/OpenSearchAdapter.js.map +0 -1
- package/dist/cjs/src/adapters/PostgreSQLAdapter.d.ts.map +0 -1
- package/dist/cjs/src/adapters/PostgreSQLAdapter.js.map +0 -1
- package/dist/cjs/src/adapters/PrismaAdapter.d.ts.map +0 -1
- package/dist/cjs/src/adapters/PrismaAdapter.js.map +0 -1
- package/dist/cjs/src/adapters/RedisAdapter.d.ts.map +0 -1
- package/dist/cjs/src/adapters/RedisAdapter.js.map +0 -1
- package/dist/cjs/src/adapters/SQLiteAdapter.d.ts.map +0 -1
- package/dist/cjs/src/adapters/SQLiteAdapter.js.map +0 -1
- package/dist/cjs/src/adapters/index.d.ts.map +0 -1
- package/dist/cjs/src/adapters/index.js.map +0 -1
- package/dist/cjs/src/constants/index.d.ts.map +0 -1
- package/dist/cjs/src/constants/index.js.map +0 -1
- package/dist/cjs/src/core/Agent.d.ts.map +0 -1
- package/dist/cjs/src/core/Agent.js.map +0 -1
- package/dist/cjs/src/core/Events.d.ts.map +0 -1
- package/dist/cjs/src/core/Events.js.map +0 -1
- package/dist/cjs/src/core/PersistenceManager.d.ts.map +0 -1
- package/dist/cjs/src/core/PersistenceManager.js.map +0 -1
- package/dist/cjs/src/core/PromptComposer.d.ts.map +0 -1
- package/dist/cjs/src/core/PromptComposer.js.map +0 -1
- package/dist/cjs/src/core/ResponseEngine.d.ts.map +0 -1
- package/dist/cjs/src/core/ResponseEngine.js +0 -84
- package/dist/cjs/src/core/ResponseEngine.js.map +0 -1
- package/dist/cjs/src/core/ResponseModal.d.ts.map +0 -1
- package/dist/cjs/src/core/ResponseModal.js.map +0 -1
- package/dist/cjs/src/core/ResponsePipeline.d.ts.map +0 -1
- package/dist/cjs/src/core/ResponsePipeline.js.map +0 -1
- package/dist/cjs/src/core/Route.d.ts.map +0 -1
- package/dist/cjs/src/core/Route.js.map +0 -1
- package/dist/cjs/src/core/RoutingEngine.d.ts.map +0 -1
- package/dist/cjs/src/core/RoutingEngine.js.map +0 -1
- package/dist/cjs/src/core/SessionManager.d.ts.map +0 -1
- package/dist/cjs/src/core/SessionManager.js.map +0 -1
- package/dist/cjs/src/core/Step.d.ts.map +0 -1
- package/dist/cjs/src/core/Step.js.map +0 -1
- package/dist/cjs/src/core/ToolManager.d.ts.map +0 -1
- package/dist/cjs/src/core/ToolManager.js.map +0 -1
- package/dist/cjs/src/index.d.ts.map +0 -1
- package/dist/cjs/src/index.js.map +0 -1
- package/dist/cjs/src/providers/AnthropicProvider.d.ts.map +0 -1
- package/dist/cjs/src/providers/AnthropicProvider.js.map +0 -1
- package/dist/cjs/src/providers/GeminiProvider.d.ts.map +0 -1
- package/dist/cjs/src/providers/GeminiProvider.js.map +0 -1
- package/dist/cjs/src/providers/OpenAIProvider.d.ts.map +0 -1
- package/dist/cjs/src/providers/OpenAIProvider.js.map +0 -1
- package/dist/cjs/src/providers/OpenRouterProvider.d.ts.map +0 -1
- package/dist/cjs/src/providers/OpenRouterProvider.js.map +0 -1
- package/dist/cjs/src/providers/index.d.ts.map +0 -1
- package/dist/cjs/src/providers/index.js.map +0 -1
- package/dist/cjs/src/types/agent.d.ts.map +0 -1
- package/dist/cjs/src/types/agent.js.map +0 -1
- package/dist/cjs/src/types/ai.d.ts.map +0 -1
- package/dist/cjs/src/types/ai.js.map +0 -1
- package/dist/cjs/src/types/history.d.ts.map +0 -1
- package/dist/cjs/src/types/history.js.map +0 -1
- package/dist/cjs/src/types/index.d.ts.map +0 -1
- package/dist/cjs/src/types/index.js.map +0 -1
- package/dist/cjs/src/types/persistence.d.ts.map +0 -1
- package/dist/cjs/src/types/persistence.js.map +0 -1
- package/dist/cjs/src/types/route.d.ts.map +0 -1
- package/dist/cjs/src/types/routing.d.ts.map +0 -1
- package/dist/cjs/src/types/schema.d.ts.map +0 -1
- package/dist/cjs/src/types/session.d.ts.map +0 -1
- package/dist/cjs/src/types/session.js.map +0 -1
- package/dist/cjs/src/types/template.d.ts +0 -30
- package/dist/cjs/src/types/template.d.ts.map +0 -1
- package/dist/cjs/src/types/tool.d.ts.map +0 -1
- package/dist/cjs/src/types/tool.js.map +0 -1
- package/dist/cjs/src/utils/clone.d.ts.map +0 -1
- package/dist/cjs/src/utils/clone.js.map +0 -1
- package/dist/cjs/src/utils/event.d.ts.map +0 -1
- package/dist/cjs/src/utils/event.js.map +0 -1
- package/dist/cjs/src/utils/history.d.ts.map +0 -1
- package/dist/cjs/src/utils/history.js.map +0 -1
- package/dist/cjs/src/utils/id.d.ts.map +0 -1
- package/dist/cjs/src/utils/id.js.map +0 -1
- package/dist/cjs/src/utils/index.d.ts.map +0 -1
- package/dist/cjs/src/utils/index.js.map +0 -1
- package/dist/cjs/src/utils/logger.d.ts.map +0 -1
- package/dist/cjs/src/utils/logger.js.map +0 -1
- package/dist/cjs/src/utils/retry.d.ts.map +0 -1
- package/dist/cjs/src/utils/retry.js.map +0 -1
- package/dist/cjs/src/utils/session.d.ts.map +0 -1
- package/dist/cjs/src/utils/session.js.map +0 -1
- package/dist/cjs/src/utils/template.d.ts.map +0 -1
- package/dist/cjs/src/utils/template.js.map +0 -1
- package/dist/src/adapters/MemoryAdapter.js.map +0 -1
- package/dist/src/adapters/MongoAdapter.js.map +0 -1
- package/dist/src/adapters/OpenSearchAdapter.js.map +0 -1
- package/dist/src/adapters/PostgreSQLAdapter.js.map +0 -1
- package/dist/src/adapters/PrismaAdapter.js.map +0 -1
- package/dist/src/adapters/RedisAdapter.js.map +0 -1
- package/dist/src/adapters/SQLiteAdapter.js.map +0 -1
- package/dist/src/adapters/index.js.map +0 -1
- package/dist/src/constants/index.js.map +0 -1
- package/dist/src/core/Agent.d.ts.map +0 -1
- package/dist/src/core/Agent.js.map +0 -1
- package/dist/src/core/Events.js.map +0 -1
- package/dist/src/core/PersistenceManager.js.map +0 -1
- package/dist/src/core/PromptComposer.d.ts.map +0 -1
- package/dist/src/core/PromptComposer.js.map +0 -1
- package/dist/src/core/ResponseEngine.js +0 -80
- package/dist/src/core/ResponseEngine.js.map +0 -1
- package/dist/src/core/ResponseModal.d.ts.map +0 -1
- package/dist/src/core/ResponseModal.js.map +0 -1
- package/dist/src/core/ResponsePipeline.d.ts.map +0 -1
- package/dist/src/core/ResponsePipeline.js.map +0 -1
- package/dist/src/core/Route.d.ts.map +0 -1
- package/dist/src/core/Route.js.map +0 -1
- package/dist/src/core/RoutingEngine.d.ts.map +0 -1
- package/dist/src/core/RoutingEngine.js.map +0 -1
- package/dist/src/core/SessionManager.js.map +0 -1
- package/dist/src/core/Step.d.ts.map +0 -1
- package/dist/src/core/Step.js.map +0 -1
- package/dist/src/core/ToolManager.js.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/providers/AnthropicProvider.js.map +0 -1
- package/dist/src/providers/GeminiProvider.js.map +0 -1
- package/dist/src/providers/OpenAIProvider.js.map +0 -1
- package/dist/src/providers/OpenRouterProvider.js.map +0 -1
- package/dist/src/providers/index.js.map +0 -1
- package/dist/src/types/agent.d.ts.map +0 -1
- package/dist/src/types/agent.js.map +0 -1
- package/dist/src/types/history.js.map +0 -1
- package/dist/src/types/index.js.map +0 -1
- package/dist/src/types/persistence.js.map +0 -1
- package/dist/src/types/route.d.ts.map +0 -1
- package/dist/src/types/template.d.ts +0 -30
- package/dist/src/types/template.d.ts.map +0 -1
- package/dist/src/types/tool.js.map +0 -1
- package/dist/src/utils/clone.js.map +0 -1
- package/dist/src/utils/event.js.map +0 -1
- package/dist/src/utils/history.js.map +0 -1
- package/dist/src/utils/id.js.map +0 -1
- package/dist/src/utils/index.d.ts.map +0 -1
- package/dist/src/utils/index.js.map +0 -1
- package/dist/src/utils/logger.js.map +0 -1
- package/dist/src/utils/retry.d.ts.map +0 -1
- package/dist/src/utils/retry.js.map +0 -1
- package/dist/src/utils/session.js.map +0 -1
- package/dist/src/utils/template.d.ts.map +0 -1
- package/dist/src/utils/template.js.map +0 -1
- /package/dist/{cjs/src/adapters → adapters}/MemoryAdapter.d.ts +0 -0
- /package/dist/{src/adapters → adapters}/MemoryAdapter.js +0 -0
- /package/dist/{cjs/src/adapters → adapters}/MongoAdapter.d.ts +0 -0
- /package/dist/{src/adapters → adapters}/MongoAdapter.js +0 -0
- /package/dist/{cjs/src/adapters → adapters}/OpenSearchAdapter.d.ts +0 -0
- /package/dist/{src/adapters → adapters}/OpenSearchAdapter.js +0 -0
- /package/dist/{cjs/src/adapters → adapters}/PostgreSQLAdapter.d.ts +0 -0
- /package/dist/{src/adapters → adapters}/PostgreSQLAdapter.js +0 -0
- /package/dist/{cjs/src/adapters → adapters}/PrismaAdapter.d.ts +0 -0
- /package/dist/{cjs/src/adapters → adapters}/RedisAdapter.d.ts +0 -0
- /package/dist/{cjs/src/adapters → adapters}/SQLiteAdapter.d.ts +0 -0
- /package/dist/{src/adapters → adapters}/SQLiteAdapter.js +0 -0
- /package/dist/{cjs/src/adapters → adapters}/index.d.ts +0 -0
- /package/dist/{src/adapters → adapters}/index.js +0 -0
- /package/dist/{src → cjs}/adapters/MemoryAdapter.d.ts +0 -0
- /package/dist/{src → cjs}/adapters/MemoryAdapter.d.ts.map +0 -0
- /package/dist/cjs/{src/adapters → adapters}/MemoryAdapter.js +0 -0
- /package/dist/{src → cjs}/adapters/MongoAdapter.d.ts +0 -0
- /package/dist/{src → cjs}/adapters/MongoAdapter.d.ts.map +0 -0
- /package/dist/cjs/{src/adapters → adapters}/MongoAdapter.js +0 -0
- /package/dist/{src → cjs}/adapters/OpenSearchAdapter.d.ts +0 -0
- /package/dist/{src → cjs}/adapters/OpenSearchAdapter.d.ts.map +0 -0
- /package/dist/cjs/{src/adapters → adapters}/OpenSearchAdapter.js +0 -0
- /package/dist/{src → cjs}/adapters/PostgreSQLAdapter.d.ts +0 -0
- /package/dist/{src → cjs}/adapters/PostgreSQLAdapter.d.ts.map +0 -0
- /package/dist/cjs/{src/adapters → adapters}/PostgreSQLAdapter.js +0 -0
- /package/dist/{src → cjs}/adapters/PrismaAdapter.d.ts +0 -0
- /package/dist/{src → cjs}/adapters/RedisAdapter.d.ts +0 -0
- /package/dist/{src → cjs}/adapters/RedisAdapter.d.ts.map +0 -0
- /package/dist/{src → cjs}/adapters/SQLiteAdapter.d.ts +0 -0
- /package/dist/{src → cjs}/adapters/SQLiteAdapter.d.ts.map +0 -0
- /package/dist/cjs/{src/adapters → adapters}/SQLiteAdapter.js +0 -0
- /package/dist/{src → cjs}/adapters/index.d.ts +0 -0
- /package/dist/{src → cjs}/adapters/index.d.ts.map +0 -0
- /package/dist/cjs/{src/adapters → adapters}/index.js +0 -0
- /package/dist/cjs/{src/constants → constants}/index.d.ts +0 -0
- /package/dist/{src → cjs}/constants/index.d.ts.map +0 -0
- /package/dist/cjs/{src/constants → constants}/index.js +0 -0
- /package/dist/cjs/{src/core → core}/Events.d.ts +0 -0
- /package/dist/{src → cjs}/core/Events.d.ts.map +0 -0
- /package/dist/cjs/{src/core → core}/Events.js +0 -0
- /package/dist/cjs/{src/core → core}/PersistenceManager.d.ts +0 -0
- /package/dist/{src → cjs}/core/PersistenceManager.d.ts.map +0 -0
- /package/dist/cjs/{src/core → core}/PersistenceManager.js +0 -0
- /package/dist/cjs/{src/core → core}/ResponseEngine.d.ts +0 -0
- /package/dist/cjs/{src/core → core}/SessionManager.d.ts +0 -0
- /package/dist/{src → cjs}/core/SessionManager.d.ts.map +0 -0
- /package/dist/cjs/{src/core → core}/SessionManager.js +0 -0
- /package/dist/cjs/{src/core → core}/ToolManager.d.ts +0 -0
- /package/dist/{src → cjs}/core/ToolManager.d.ts.map +0 -0
- /package/dist/cjs/{src/core → core}/ToolManager.js +0 -0
- /package/dist/cjs/{src/providers → providers}/AnthropicProvider.d.ts +0 -0
- /package/dist/{src → cjs}/providers/AnthropicProvider.d.ts.map +0 -0
- /package/dist/cjs/{src/providers → providers}/GeminiProvider.d.ts +0 -0
- /package/dist/cjs/{src/providers → providers}/OpenAIProvider.d.ts +0 -0
- /package/dist/{src → cjs}/providers/OpenAIProvider.d.ts.map +0 -0
- /package/dist/cjs/{src/providers → providers}/OpenRouterProvider.d.ts +0 -0
- /package/dist/{src → cjs}/providers/OpenRouterProvider.d.ts.map +0 -0
- /package/dist/cjs/{src/providers → providers}/index.d.ts +0 -0
- /package/dist/{src → cjs}/providers/index.d.ts.map +0 -0
- /package/dist/cjs/{src/providers → providers}/index.js +0 -0
- /package/dist/cjs/{src/types → types}/agent.js +0 -0
- /package/dist/cjs/{src/types → types}/ai.d.ts +0 -0
- /package/dist/{src → cjs}/types/ai.d.ts.map +0 -0
- /package/dist/cjs/{src/types → types}/ai.js +0 -0
- /package/dist/cjs/{src/types → types}/history.d.ts +0 -0
- /package/dist/{src → cjs}/types/history.d.ts.map +0 -0
- /package/dist/cjs/{src/types → types}/history.js +0 -0
- /package/dist/cjs/{src/types → types}/persistence.d.ts +0 -0
- /package/dist/{src → cjs}/types/persistence.d.ts.map +0 -0
- /package/dist/cjs/{src/types → types}/persistence.js +0 -0
- /package/dist/cjs/{src/types → types}/route.js +0 -0
- /package/dist/cjs/{src/types → types}/routing.d.ts +0 -0
- /package/dist/{src → cjs}/types/routing.d.ts.map +0 -0
- /package/dist/cjs/{src/types → types}/routing.js +0 -0
- /package/dist/{src → cjs}/types/routing.js.map +0 -0
- /package/dist/cjs/{src/types → types}/schema.d.ts +0 -0
- /package/dist/{src → cjs}/types/schema.d.ts.map +0 -0
- /package/dist/cjs/{src/types → types}/schema.js +0 -0
- /package/dist/{src → cjs}/types/schema.js.map +0 -0
- /package/dist/cjs/{src/types → types}/session.d.ts +0 -0
- /package/dist/{src → cjs}/types/session.d.ts.map +0 -0
- /package/dist/cjs/{src/types → types}/session.js +0 -0
- /package/dist/cjs/{src/types → types}/template.js +0 -0
- /package/dist/{src → cjs}/types/template.js.map +0 -0
- /package/dist/cjs/{src/types → types}/tool.d.ts +0 -0
- /package/dist/{src → cjs}/types/tool.d.ts.map +0 -0
- /package/dist/cjs/{src/types → types}/tool.js +0 -0
- /package/dist/cjs/{src/utils → utils}/clone.d.ts +0 -0
- /package/dist/{src → cjs}/utils/clone.d.ts.map +0 -0
- /package/dist/cjs/{src/utils → utils}/clone.js +0 -0
- /package/dist/cjs/{src/utils → utils}/event.d.ts +0 -0
- /package/dist/{src → cjs}/utils/event.d.ts.map +0 -0
- /package/dist/cjs/{src/utils → utils}/event.js +0 -0
- /package/dist/cjs/{src/utils → utils}/history.d.ts +0 -0
- /package/dist/{src → cjs}/utils/history.d.ts.map +0 -0
- /package/dist/cjs/{src/utils → utils}/history.js +0 -0
- /package/dist/cjs/{src/utils → utils}/id.d.ts +0 -0
- /package/dist/{src → cjs}/utils/id.d.ts.map +0 -0
- /package/dist/cjs/{src/utils → utils}/id.js +0 -0
- /package/dist/cjs/{src/utils → utils}/logger.d.ts +0 -0
- /package/dist/{src → cjs}/utils/logger.d.ts.map +0 -0
- /package/dist/cjs/{src/utils → utils}/logger.js +0 -0
- /package/dist/cjs/{src/utils → utils}/session.d.ts +0 -0
- /package/dist/{src → cjs}/utils/session.d.ts.map +0 -0
- /package/dist/cjs/{src/utils → utils}/session.js +0 -0
- /package/dist/{src/constants → constants}/index.d.ts +0 -0
- /package/dist/{src/constants → constants}/index.js +0 -0
- /package/dist/{src/core → core}/Events.d.ts +0 -0
- /package/dist/{src/core → core}/Events.js +0 -0
- /package/dist/{src/core → core}/PersistenceManager.d.ts +0 -0
- /package/dist/{src/core → core}/PersistenceManager.js +0 -0
- /package/dist/{src/core → core}/ResponseEngine.d.ts +0 -0
- /package/dist/{src/core → core}/SessionManager.d.ts +0 -0
- /package/dist/{src/core → core}/SessionManager.js +0 -0
- /package/dist/{src/core → core}/ToolManager.d.ts +0 -0
- /package/dist/{src/core → core}/ToolManager.js +0 -0
- /package/dist/{src/providers → providers}/AnthropicProvider.d.ts +0 -0
- /package/dist/{src/providers → providers}/GeminiProvider.d.ts +0 -0
- /package/dist/{src/providers → providers}/OpenAIProvider.d.ts +0 -0
- /package/dist/{src/providers → providers}/OpenRouterProvider.d.ts +0 -0
- /package/dist/{src/providers → providers}/index.d.ts +0 -0
- /package/dist/{src/providers → providers}/index.js +0 -0
- /package/dist/{src/types → types}/agent.js +0 -0
- /package/dist/{src/types → types}/ai.d.ts +0 -0
- /package/dist/{src/types → types}/ai.js +0 -0
- /package/dist/{src/types → types}/history.d.ts +0 -0
- /package/dist/{src/types → types}/history.js +0 -0
- /package/dist/{src/types → types}/persistence.d.ts +0 -0
- /package/dist/{src/types → types}/persistence.js +0 -0
- /package/dist/{src/types → types}/route.js +0 -0
- /package/dist/{src/types → types}/routing.d.ts +0 -0
- /package/dist/{src/types → types}/routing.js +0 -0
- /package/dist/{src/types → types}/schema.d.ts +0 -0
- /package/dist/{src/types → types}/schema.js +0 -0
- /package/dist/{src/types → types}/session.d.ts +0 -0
- /package/dist/{src/types → types}/session.js +0 -0
- /package/dist/{src/types → types}/template.js +0 -0
- /package/dist/{src/types → types}/tool.d.ts +0 -0
- /package/dist/{src/types → types}/tool.js +0 -0
- /package/dist/{src/utils → utils}/clone.d.ts +0 -0
- /package/dist/{src/utils → utils}/clone.js +0 -0
- /package/dist/{src/utils → utils}/event.d.ts +0 -0
- /package/dist/{src/utils → utils}/event.js +0 -0
- /package/dist/{src/utils → utils}/history.d.ts +0 -0
- /package/dist/{src/utils → utils}/history.js +0 -0
- /package/dist/{src/utils → utils}/id.d.ts +0 -0
- /package/dist/{src/utils → utils}/id.js +0 -0
- /package/dist/{src/utils → utils}/logger.d.ts +0 -0
- /package/dist/{src/utils → utils}/logger.js +0 -0
- /package/dist/{src/utils → utils}/session.d.ts +0 -0
- /package/dist/{src/utils → utils}/session.js +0 -0
|
@@ -6,7 +6,10 @@ import { EventKind, MessageRole } from "../types";
|
|
|
6
6
|
import { Step } from "./Step";
|
|
7
7
|
import { ResponseEngine } from "./ResponseEngine";
|
|
8
8
|
import { ResponsePipeline } from "./ResponsePipeline";
|
|
9
|
+
import { BatchExecutor } from "./BatchExecutor";
|
|
10
|
+
import { BatchPromptBuilder } from "./BatchPromptBuilder";
|
|
9
11
|
import { cloneDeep, mergeCollected, enterStep, getLastMessageFromHistory, render, logger, historyToEvents } from "../utils";
|
|
12
|
+
import { createTemplateContext } from "../utils/template";
|
|
10
13
|
import { END_ROUTE_ID } from "../constants";
|
|
11
14
|
/**
|
|
12
15
|
* Error class for response generation failures
|
|
@@ -48,6 +51,10 @@ export class ResponseModal {
|
|
|
48
51
|
// Initialize response pipeline with agent dependencies
|
|
49
52
|
this.responsePipeline = new ResponsePipeline(this.agent.getAgentOptions(), () => this.agent.getRoutes(), // Pass a function to get routes dynamically
|
|
50
53
|
this.agent.getTools(), this.agent.getRoutingEngine(), this.agent.updateContext.bind(this.agent), this.agent.getUpdateDataMethod(), this.agent.updateCollectedData.bind(this.agent), this.getToolManager());
|
|
54
|
+
// Initialize batch executor for multi-step execution
|
|
55
|
+
this.batchExecutor = new BatchExecutor();
|
|
56
|
+
// Initialize batch prompt builder for combined prompts
|
|
57
|
+
this.batchPromptBuilder = new BatchPromptBuilder();
|
|
51
58
|
}
|
|
52
59
|
/**
|
|
53
60
|
* Generate a non-streaming response using unified logic
|
|
@@ -268,6 +275,7 @@ export class ResponseModal {
|
|
|
268
275
|
throw ResponseGenerationError.fromError(error, 'step_preparation', params, { session, effectiveContext });
|
|
269
276
|
}
|
|
270
277
|
// PHASE 2: ROUTING + STEP SELECTION - Determine which route and step to use
|
|
278
|
+
// Also performs pre-extraction and batch determination
|
|
271
279
|
let routingResult;
|
|
272
280
|
try {
|
|
273
281
|
routingResult = await this.handleUnifiedRoutingAndStepSelection({
|
|
@@ -288,6 +296,9 @@ export class ResponseModal {
|
|
|
288
296
|
selectedStep: routingResult.selectedStep,
|
|
289
297
|
responseDirectives: routingResult.responseDirectives,
|
|
290
298
|
isRouteComplete: routingResult.isRouteComplete,
|
|
299
|
+
batchSteps: routingResult.batchSteps,
|
|
300
|
+
batchStoppedReason: routingResult.batchStoppedReason,
|
|
301
|
+
batchStoppedAtStep: routingResult.batchStoppedAtStep,
|
|
291
302
|
};
|
|
292
303
|
}
|
|
293
304
|
catch (error) {
|
|
@@ -313,31 +324,156 @@ export class ResponseModal {
|
|
|
313
324
|
context: params.context,
|
|
314
325
|
signal: params.signal,
|
|
315
326
|
});
|
|
327
|
+
let updatedSession = routingResult.session;
|
|
328
|
+
let isRouteComplete = routingResult.isRouteComplete;
|
|
329
|
+
// PRE-EXTRACTION: If entering a route that collects data, extract data from user message first
|
|
330
|
+
// This allows us to skip steps whose data is already provided
|
|
331
|
+
// Requirement 3.1: Perform Pre_Extraction before determining the Batch
|
|
332
|
+
if (routingResult.selectedRoute && !isRouteComplete) {
|
|
333
|
+
// Always pre-extract when route collects data (not just on new route entry)
|
|
334
|
+
// This ensures batch determination has the most up-to-date data
|
|
335
|
+
if (this.shouldPreExtractData(routingResult.selectedRoute)) {
|
|
336
|
+
logger.debug(`[ResponseModal] Pre-extracting data for route: ${routingResult.selectedRoute.title}`);
|
|
337
|
+
const extractedData = await this.preExtractRouteData({
|
|
338
|
+
route: routingResult.selectedRoute,
|
|
339
|
+
history: params.history,
|
|
340
|
+
context: params.context,
|
|
341
|
+
session: updatedSession,
|
|
342
|
+
signal: params.signal,
|
|
343
|
+
});
|
|
344
|
+
if (extractedData && Object.keys(extractedData).length > 0) {
|
|
345
|
+
logger.debug(`[ResponseModal] Pre-extracted data:`, extractedData);
|
|
346
|
+
// Requirement 3.3: Merge pre-extracted data into session before batch determination
|
|
347
|
+
updatedSession = mergeCollected(updatedSession, extractedData);
|
|
348
|
+
// Also update agent's collected data
|
|
349
|
+
await this.agent.updateCollectedData(extractedData);
|
|
350
|
+
// Re-check route completion after pre-extraction
|
|
351
|
+
const allRequiredFieldsCollected = routingResult.selectedRoute.isComplete(updatedSession.data || {});
|
|
352
|
+
if (allRequiredFieldsCollected) {
|
|
353
|
+
logger.debug(`[ResponseModal] Route ${routingResult.selectedRoute.title} completed after pre-extraction`);
|
|
354
|
+
isRouteComplete = true;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// BATCH DETERMINATION: Use BatchExecutor to determine which steps can execute together
|
|
360
|
+
// Requirement 3.4: Pre-extraction results affect batch determination
|
|
361
|
+
let batchSteps;
|
|
362
|
+
let batchStoppedReason;
|
|
363
|
+
let batchStoppedAtStep;
|
|
364
|
+
if (routingResult.selectedRoute && !isRouteComplete) {
|
|
365
|
+
// Determine current step position for batch determination
|
|
366
|
+
const currentStep = routingResult.selectedStep ||
|
|
367
|
+
(updatedSession.currentStep ? routingResult.selectedRoute.getStep(updatedSession.currentStep.id) : undefined);
|
|
368
|
+
logger.debug(`[ResponseModal] Determining batch starting from step: ${currentStep?.id || 'initial'}`);
|
|
369
|
+
const batchResult = await this.batchExecutor.determineBatch({
|
|
370
|
+
route: routingResult.selectedRoute,
|
|
371
|
+
currentStep,
|
|
372
|
+
sessionData: updatedSession.data || {},
|
|
373
|
+
context: params.context,
|
|
374
|
+
});
|
|
375
|
+
batchSteps = batchResult.steps;
|
|
376
|
+
batchStoppedReason = batchResult.stoppedReason;
|
|
377
|
+
batchStoppedAtStep = batchResult.stoppedAtStep;
|
|
378
|
+
logger.debug(`[ResponseModal] Batch determined: ${batchSteps.length} steps, stopped reason: ${batchStoppedReason}`);
|
|
379
|
+
}
|
|
316
380
|
// Determine next step using pipeline method for consistency
|
|
317
|
-
const stepResult = this.responsePipeline.determineNextStep({
|
|
381
|
+
const stepResult = await this.responsePipeline.determineNextStep({
|
|
318
382
|
selectedRoute: routingResult.selectedRoute,
|
|
319
383
|
selectedStep: routingResult.selectedStep,
|
|
320
|
-
session:
|
|
321
|
-
isRouteComplete
|
|
384
|
+
session: updatedSession, // Use updated session with pre-extracted data
|
|
385
|
+
isRouteComplete, // Use updated completion status
|
|
322
386
|
});
|
|
323
387
|
return {
|
|
324
388
|
selectedRoute: routingResult.selectedRoute,
|
|
325
389
|
selectedStep: stepResult.nextStep, // Use the determined next step
|
|
326
390
|
responseDirectives: routingResult.responseDirectives,
|
|
327
391
|
session: stepResult.session,
|
|
328
|
-
isRouteComplete
|
|
392
|
+
isRouteComplete, // Use updated completion status
|
|
393
|
+
batchSteps,
|
|
394
|
+
batchStoppedReason,
|
|
395
|
+
batchStoppedAtStep,
|
|
329
396
|
};
|
|
330
397
|
}
|
|
331
398
|
catch (error) {
|
|
332
399
|
throw ResponseGenerationError.fromError(error, 'routing_optimization', params);
|
|
333
400
|
}
|
|
334
401
|
}
|
|
402
|
+
/**
|
|
403
|
+
* Check if a route should pre-extract data before determining the initial step
|
|
404
|
+
* @private
|
|
405
|
+
*/
|
|
406
|
+
shouldPreExtractData(route) {
|
|
407
|
+
// Pre-extract if route has declared required or optional fields
|
|
408
|
+
if (route.requiredFields && route.requiredFields.length > 0) {
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
if (route.optionalFields && route.optionalFields.length > 0) {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
// Pre-extract if any step in the route collects data
|
|
415
|
+
const steps = route.getAllSteps();
|
|
416
|
+
const hasDataCollectionSteps = steps.some(step => step.collect && step.collect.length > 0);
|
|
417
|
+
return hasDataCollectionSteps;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Pre-extract data from user message when entering a route
|
|
421
|
+
* This allows skipping steps whose data is already provided
|
|
422
|
+
* @private
|
|
423
|
+
*/
|
|
424
|
+
async preExtractRouteData(params) {
|
|
425
|
+
const { route, history, context, signal } = params;
|
|
426
|
+
// Build a schema for data extraction based on route's fields
|
|
427
|
+
const extractionSchema = this.agent.getSchema();
|
|
428
|
+
if (!extractionSchema) {
|
|
429
|
+
logger.warn(`[ResponseModal] No schema available for pre-extraction`);
|
|
430
|
+
return {};
|
|
431
|
+
}
|
|
432
|
+
// Get last user message
|
|
433
|
+
const lastMessage = getLastMessageFromHistory(history);
|
|
434
|
+
// Build extraction prompt
|
|
435
|
+
const extractionPrompt = [
|
|
436
|
+
`Extract any relevant information from the user's message that matches the following data fields.`,
|
|
437
|
+
`Only extract information that is explicitly stated or clearly implied.`,
|
|
438
|
+
``,
|
|
439
|
+
`User's message: "${lastMessage}"`,
|
|
440
|
+
``,
|
|
441
|
+
`Extract data for these fields if present:`,
|
|
442
|
+
];
|
|
443
|
+
// Add field descriptions
|
|
444
|
+
if (route.requiredFields) {
|
|
445
|
+
extractionPrompt.push(`Required fields: ${route.requiredFields.join(', ')}`);
|
|
446
|
+
}
|
|
447
|
+
if (route.optionalFields) {
|
|
448
|
+
extractionPrompt.push(`Optional fields: ${route.optionalFields.join(', ')}`);
|
|
449
|
+
}
|
|
450
|
+
extractionPrompt.push(``, `Return ONLY the extracted data as JSON. If no data can be extracted, return an empty object {}.`);
|
|
451
|
+
// Call AI to extract data
|
|
452
|
+
const agentOptions = this.agent.getAgentOptions();
|
|
453
|
+
try {
|
|
454
|
+
const result = await agentOptions.provider.generateMessage({
|
|
455
|
+
prompt: extractionPrompt.join('\n'),
|
|
456
|
+
history,
|
|
457
|
+
context,
|
|
458
|
+
signal,
|
|
459
|
+
parameters: {
|
|
460
|
+
jsonSchema: extractionSchema,
|
|
461
|
+
schemaName: 'data_extraction',
|
|
462
|
+
},
|
|
463
|
+
});
|
|
464
|
+
return result.structured || {};
|
|
465
|
+
}
|
|
466
|
+
catch (error) {
|
|
467
|
+
logger.error(`[ResponseModal] Pre-extraction failed:`, error);
|
|
468
|
+
return {};
|
|
469
|
+
}
|
|
470
|
+
}
|
|
335
471
|
/**
|
|
336
472
|
* Unified response generation for non-streaming responses
|
|
337
473
|
* @private
|
|
338
474
|
*/
|
|
339
475
|
async generateUnifiedResponse(responseContext) {
|
|
340
|
-
const { effectiveContext, session: initialSession, history, selectedRoute, selectedStep, responseDirectives, isRouteComplete } = responseContext;
|
|
476
|
+
const { effectiveContext, session: initialSession, history, selectedRoute, selectedStep, responseDirectives, isRouteComplete, batchSteps, batchStoppedReason, } = responseContext;
|
|
341
477
|
let session = initialSession;
|
|
342
478
|
// Get last user message (needed for both route and completion handling)
|
|
343
479
|
// Convert HistoryItem[] to Event[] for internal processing
|
|
@@ -345,35 +481,79 @@ export class ResponseModal {
|
|
|
345
481
|
const lastMessageText = getLastMessageFromHistory(historyEvents);
|
|
346
482
|
let message;
|
|
347
483
|
let toolCalls = undefined;
|
|
484
|
+
let executedSteps;
|
|
485
|
+
let stoppedReason;
|
|
348
486
|
if (selectedRoute && !isRouteComplete) {
|
|
349
|
-
//
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
487
|
+
// Check if we have batch steps to execute
|
|
488
|
+
if (batchSteps && batchSteps.length > 0) {
|
|
489
|
+
// BATCH EXECUTION: Execute multiple steps in a single LLM call
|
|
490
|
+
logger.debug(`[ResponseModal] Executing batch of ${batchSteps.length} steps`);
|
|
491
|
+
const batchResult = await this.executeBatchResponse({
|
|
492
|
+
selectedRoute,
|
|
493
|
+
batchSteps,
|
|
494
|
+
responseDirectives,
|
|
495
|
+
session,
|
|
496
|
+
history,
|
|
497
|
+
context: effectiveContext,
|
|
498
|
+
historyEvents,
|
|
499
|
+
});
|
|
500
|
+
message = batchResult.message;
|
|
501
|
+
toolCalls = batchResult.toolCalls;
|
|
502
|
+
session = batchResult.session;
|
|
503
|
+
executedSteps = batchResult.executedSteps;
|
|
504
|
+
stoppedReason = batchStoppedReason;
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
// SINGLE STEP EXECUTION: Fall back to single-step processing
|
|
508
|
+
// This happens when batch determination returns empty (first step needs input)
|
|
509
|
+
const result = await this.processRouteResponse({
|
|
510
|
+
selectedRoute,
|
|
511
|
+
selectedStep,
|
|
512
|
+
responseDirectives,
|
|
513
|
+
session,
|
|
514
|
+
history,
|
|
515
|
+
context: effectiveContext,
|
|
516
|
+
lastMessageText,
|
|
517
|
+
historyEvents,
|
|
518
|
+
signal: undefined,
|
|
519
|
+
});
|
|
520
|
+
message = result.message;
|
|
521
|
+
toolCalls = result.toolCalls;
|
|
522
|
+
session = result.session;
|
|
523
|
+
// Track executed step for single-step execution
|
|
524
|
+
if (selectedStep) {
|
|
525
|
+
executedSteps = [{
|
|
526
|
+
id: selectedStep.id,
|
|
527
|
+
routeId: selectedRoute.id,
|
|
528
|
+
}];
|
|
529
|
+
}
|
|
530
|
+
stoppedReason = batchStoppedReason || 'needs_input';
|
|
531
|
+
}
|
|
364
532
|
}
|
|
365
533
|
else if (isRouteComplete && selectedRoute) {
|
|
366
534
|
// Handle route completion
|
|
367
|
-
message
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
535
|
+
logger.debug(`[ResponseModal] Generating completion message for route: ${selectedRoute.title}`);
|
|
536
|
+
try {
|
|
537
|
+
message = await this.handleRouteCompletion({
|
|
538
|
+
selectedRoute,
|
|
539
|
+
session,
|
|
540
|
+
context: effectiveContext,
|
|
541
|
+
lastMessageText,
|
|
542
|
+
historyEvents,
|
|
543
|
+
signal: undefined,
|
|
544
|
+
});
|
|
545
|
+
// Set step to END_ROUTE marker
|
|
546
|
+
session = enterStep(session, END_ROUTE_ID, "Route completed");
|
|
547
|
+
stoppedReason = 'route_complete';
|
|
548
|
+
logger.debug(`[ResponseModal] Route ${selectedRoute.title} completed. Entered END_ROUTE step.`);
|
|
549
|
+
}
|
|
550
|
+
catch (error) {
|
|
551
|
+
logger.error(`[ResponseModal] Error generating completion message:`, error);
|
|
552
|
+
// Fallback to simple completion message
|
|
553
|
+
message = `Thank you! I've recorded all the information for your ${selectedRoute.title.toLowerCase()}.`;
|
|
554
|
+
session = enterStep(session, END_ROUTE_ID, "Route completed");
|
|
555
|
+
stoppedReason = 'route_complete';
|
|
556
|
+
}
|
|
377
557
|
}
|
|
378
558
|
else {
|
|
379
559
|
// Fallback: No routes defined, generate a simple response
|
|
@@ -382,37 +562,275 @@ export class ResponseModal {
|
|
|
382
562
|
context: effectiveContext,
|
|
383
563
|
session,
|
|
384
564
|
});
|
|
565
|
+
// For fallback responses, set empty executedSteps and no stoppedReason
|
|
566
|
+
// since there's no route/step execution happening
|
|
567
|
+
executedSteps = [];
|
|
568
|
+
stoppedReason = undefined;
|
|
385
569
|
}
|
|
570
|
+
// Ensure response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
571
|
+
// - executedSteps: array of steps executed (empty array if none)
|
|
572
|
+
// - stoppedReason: why execution stopped (undefined for fallback)
|
|
573
|
+
// - session.currentStep: reflects final step position
|
|
386
574
|
return {
|
|
387
575
|
message,
|
|
388
576
|
session,
|
|
389
577
|
toolCalls,
|
|
390
578
|
isRouteComplete,
|
|
579
|
+
executedSteps: executedSteps || [],
|
|
580
|
+
stoppedReason,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Execute a batch of steps with a single LLM call
|
|
585
|
+
*
|
|
586
|
+
* This method:
|
|
587
|
+
* 1. Executes all prepare hooks for steps in the batch (in order)
|
|
588
|
+
* 2. Builds a combined prompt using BatchPromptBuilder
|
|
589
|
+
* 3. Makes a single LLM call
|
|
590
|
+
* 4. Collects data from the response for all steps
|
|
591
|
+
* 5. Executes all finalize hooks for steps in the batch (in order)
|
|
592
|
+
*
|
|
593
|
+
* @private
|
|
594
|
+
* **Validates: Requirements 1.1, 4.4, 5.1, 5.2**
|
|
595
|
+
*/
|
|
596
|
+
async executeBatchResponse(params) {
|
|
597
|
+
const { selectedRoute, batchSteps, history, context, historyEvents, signal } = params;
|
|
598
|
+
let session = params.session;
|
|
599
|
+
logger.debug(`[ResponseModal] Starting batch execution for ${batchSteps.length} steps`);
|
|
600
|
+
// Create hook executor function
|
|
601
|
+
const executeHook = async (hook, hookContext, data, step) => {
|
|
602
|
+
// Find the route for this step
|
|
603
|
+
const route = selectedRoute;
|
|
604
|
+
// Convert StepOptions to Step if needed for executePrepareFinalize
|
|
605
|
+
const stepInstance = step?.id ? route.getStep(step.id) : undefined;
|
|
606
|
+
await this.executePrepareFinalize(hook, hookContext, data, route, stepInstance);
|
|
607
|
+
};
|
|
608
|
+
// PHASE 1: Execute all prepare hooks (Requirement 5.1)
|
|
609
|
+
logger.debug(`[ResponseModal] Executing prepare hooks for batch`);
|
|
610
|
+
const prepareResult = await this.batchExecutor.executePrepareHooks({
|
|
611
|
+
steps: batchSteps,
|
|
612
|
+
context,
|
|
613
|
+
data: session.data,
|
|
614
|
+
executeHook,
|
|
615
|
+
});
|
|
616
|
+
if (!prepareResult.success) {
|
|
617
|
+
// Prepare hook failed - return error response
|
|
618
|
+
logger.error(`[ResponseModal] Prepare hook failed:`, prepareResult.error);
|
|
619
|
+
throw new ResponseGenerationError(`Prepare hook failed: ${prepareResult.error?.message}`, {
|
|
620
|
+
phase: 'prepare_hooks',
|
|
621
|
+
context: {
|
|
622
|
+
stepId: prepareResult.error?.stepId,
|
|
623
|
+
executedSteps: prepareResult.executedSteps,
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
// PHASE 2: Build combined prompt using BatchPromptBuilder (Requirement 4.4)
|
|
628
|
+
logger.debug(`[ResponseModal] Building batch prompt`);
|
|
629
|
+
const batchPromptResult = await this.batchPromptBuilder.buildBatchPrompt({
|
|
630
|
+
steps: batchSteps,
|
|
631
|
+
route: selectedRoute,
|
|
632
|
+
history: historyEvents,
|
|
633
|
+
context,
|
|
634
|
+
session,
|
|
635
|
+
agentOptions: this.agent.getAgentOptions(),
|
|
636
|
+
});
|
|
637
|
+
logger.debug(`[ResponseModal] Batch prompt built with ${batchPromptResult.stepCount} steps, collecting: ${batchPromptResult.collectFields.join(', ')}`);
|
|
638
|
+
// Build response schema for batch (includes all collect fields)
|
|
639
|
+
const responseSchema = this.buildBatchResponseSchema(batchPromptResult.collectFields);
|
|
640
|
+
// Collect available tools for AI (from all steps in batch)
|
|
641
|
+
const availableTools = this.collectBatchAvailableTools(selectedRoute, batchSteps);
|
|
642
|
+
// PHASE 3: Make single LLM call (Requirement 4.4)
|
|
643
|
+
logger.debug(`[ResponseModal] Making LLM call for batch`);
|
|
644
|
+
const agentOptions = this.agent.getAgentOptions();
|
|
645
|
+
const result = await agentOptions.provider.generateMessage({
|
|
646
|
+
prompt: batchPromptResult.prompt,
|
|
647
|
+
history: historyEvents,
|
|
648
|
+
context,
|
|
649
|
+
tools: availableTools,
|
|
650
|
+
signal,
|
|
651
|
+
parameters: responseSchema ? { jsonSchema: responseSchema, schemaName: "batch_response" } : undefined,
|
|
652
|
+
});
|
|
653
|
+
let message = result.structured?.message || result.message;
|
|
654
|
+
let toolCalls = result.structured?.toolCalls;
|
|
655
|
+
logger.debug(`[ResponseModal] LLM response received for batch`);
|
|
656
|
+
// Execute tools if any
|
|
657
|
+
if (toolCalls && toolCalls.length > 0) {
|
|
658
|
+
const toolResult = await this.executeUnifiedToolLoop({
|
|
659
|
+
toolCalls,
|
|
660
|
+
context,
|
|
661
|
+
session,
|
|
662
|
+
history,
|
|
663
|
+
selectedRoute,
|
|
664
|
+
responsePrompt: batchPromptResult.prompt,
|
|
665
|
+
availableTools,
|
|
666
|
+
responseSchema,
|
|
667
|
+
signal,
|
|
668
|
+
});
|
|
669
|
+
session = toolResult.session;
|
|
670
|
+
toolCalls = toolResult.finalToolCalls;
|
|
671
|
+
if (toolResult.finalMessage) {
|
|
672
|
+
message = toolResult.finalMessage;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
// PHASE 4: Collect data from response for all steps (Requirement 6.1, 6.2, 6.3)
|
|
676
|
+
logger.debug(`[ResponseModal] Collecting batch data`);
|
|
677
|
+
const collectResult = this.batchExecutor.collectBatchData({
|
|
678
|
+
steps: batchSteps,
|
|
679
|
+
llmResponse: result.structured || {},
|
|
680
|
+
session,
|
|
681
|
+
schema: this.agent.getSchema(),
|
|
682
|
+
});
|
|
683
|
+
session = collectResult.session;
|
|
684
|
+
if (collectResult.collectedData && Object.keys(collectResult.collectedData).length > 0) {
|
|
685
|
+
// Update agent's collected data
|
|
686
|
+
await this.agent.updateCollectedData(collectResult.collectedData);
|
|
687
|
+
logger.debug(`[ResponseModal] Batch collected data:`, collectResult.collectedData);
|
|
688
|
+
}
|
|
689
|
+
if (collectResult.validationErrors && collectResult.validationErrors.length > 0) {
|
|
690
|
+
logger.warn(`[ResponseModal] Batch data validation errors:`, collectResult.validationErrors);
|
|
691
|
+
}
|
|
692
|
+
// Update session to final step position
|
|
693
|
+
const lastStep = batchSteps[batchSteps.length - 1];
|
|
694
|
+
if (lastStep?.id) {
|
|
695
|
+
session = enterStep(session, lastStep.id, lastStep.description);
|
|
696
|
+
logger.debug(`[ResponseModal] Updated session to final batch step: ${lastStep.id}`);
|
|
697
|
+
}
|
|
698
|
+
// PHASE 5: Execute all finalize hooks (Requirement 5.2)
|
|
699
|
+
logger.debug(`[ResponseModal] Executing finalize hooks for batch`);
|
|
700
|
+
const finalizeResult = await this.batchExecutor.executeFinalizeHooks({
|
|
701
|
+
steps: batchSteps,
|
|
702
|
+
context,
|
|
703
|
+
data: session.data,
|
|
704
|
+
executeHook,
|
|
705
|
+
});
|
|
706
|
+
if (finalizeResult.errors && finalizeResult.errors.length > 0) {
|
|
707
|
+
// Log finalize errors but don't fail (Requirement 5.5)
|
|
708
|
+
logger.warn(`[ResponseModal] Some finalize hooks failed:`, finalizeResult.errors);
|
|
709
|
+
}
|
|
710
|
+
// Build executed steps list
|
|
711
|
+
const executedSteps = batchSteps
|
|
712
|
+
.filter(step => step.id)
|
|
713
|
+
.map(step => ({
|
|
714
|
+
id: step.id,
|
|
715
|
+
routeId: selectedRoute.id,
|
|
716
|
+
}));
|
|
717
|
+
logger.debug(`[ResponseModal] Batch execution complete. Executed ${executedSteps.length} steps`);
|
|
718
|
+
return {
|
|
719
|
+
message,
|
|
720
|
+
toolCalls,
|
|
721
|
+
session,
|
|
722
|
+
executedSteps,
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Build response schema for batch execution
|
|
727
|
+
* @private
|
|
728
|
+
*/
|
|
729
|
+
buildBatchResponseSchema(collectFields) {
|
|
730
|
+
const properties = {
|
|
731
|
+
message: {
|
|
732
|
+
type: "string",
|
|
733
|
+
description: "Your response to the user",
|
|
734
|
+
},
|
|
735
|
+
};
|
|
736
|
+
const agentSchema = this.agent.getSchema();
|
|
737
|
+
// Add collect fields to schema, using agent schema definitions when available
|
|
738
|
+
for (const field of collectFields) {
|
|
739
|
+
if (agentSchema?.properties && agentSchema.properties[field]) {
|
|
740
|
+
properties[field] = agentSchema.properties[field];
|
|
741
|
+
}
|
|
742
|
+
else {
|
|
743
|
+
// Dynamic fallback when no agent schema is defined
|
|
744
|
+
properties[field] = {
|
|
745
|
+
type: "string",
|
|
746
|
+
description: `Collected value for ${field}`,
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
return {
|
|
751
|
+
type: "object",
|
|
752
|
+
properties,
|
|
753
|
+
required: ["message"],
|
|
754
|
+
additionalProperties: true,
|
|
391
755
|
};
|
|
392
756
|
}
|
|
757
|
+
/**
|
|
758
|
+
* Collect available tools from all steps in the batch
|
|
759
|
+
* @private
|
|
760
|
+
*/
|
|
761
|
+
collectBatchAvailableTools(route, batchSteps) {
|
|
762
|
+
const availableTools = new Map();
|
|
763
|
+
// Add agent-level tools
|
|
764
|
+
this.agent.getTools().forEach((tool) => {
|
|
765
|
+
availableTools.set(tool.id, tool);
|
|
766
|
+
});
|
|
767
|
+
// Add route-level tools
|
|
768
|
+
route.getTools().forEach((tool) => {
|
|
769
|
+
availableTools.set(tool.id, tool);
|
|
770
|
+
});
|
|
771
|
+
// Add step-level tools from all batch steps
|
|
772
|
+
for (const step of batchSteps) {
|
|
773
|
+
if (step.tools) {
|
|
774
|
+
for (const toolRef of step.tools) {
|
|
775
|
+
if (typeof toolRef === "string") {
|
|
776
|
+
// Reference to registered tool - already in availableTools
|
|
777
|
+
}
|
|
778
|
+
else if (typeof toolRef === 'object' && 'id' in toolRef && toolRef.id) {
|
|
779
|
+
// Inline tool definition
|
|
780
|
+
availableTools.set(toolRef.id, toolRef);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
// Convert to the format expected by AI providers
|
|
786
|
+
return Array.from(availableTools.values()).map((tool) => ({
|
|
787
|
+
id: tool.id,
|
|
788
|
+
name: tool.name || tool.id,
|
|
789
|
+
description: tool.description,
|
|
790
|
+
parameters: tool.parameters,
|
|
791
|
+
}));
|
|
792
|
+
}
|
|
393
793
|
/**
|
|
394
794
|
* Unified streaming response generation
|
|
395
795
|
* @private
|
|
396
796
|
*/
|
|
397
797
|
async *generateUnifiedStreamingResponse(responseContext) {
|
|
398
|
-
const { effectiveContext, session: initialSession, history, selectedRoute, selectedStep, responseDirectives, isRouteComplete } = responseContext;
|
|
798
|
+
const { effectiveContext, session: initialSession, history, selectedRoute, selectedStep, responseDirectives, isRouteComplete, batchSteps, batchStoppedReason, } = responseContext;
|
|
399
799
|
const session = initialSession;
|
|
400
800
|
// Get last user message (needed for both route and completion handling)
|
|
401
801
|
// Convert HistoryItem[] to Event[] for internal processing
|
|
402
802
|
const historyEvents = historyToEvents(history);
|
|
403
803
|
const lastMessageText = getLastMessageFromHistory(historyEvents);
|
|
404
804
|
if (selectedRoute && !isRouteComplete) {
|
|
405
|
-
//
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
805
|
+
// Check if we have batch steps to execute
|
|
806
|
+
if (batchSteps && batchSteps.length > 0) {
|
|
807
|
+
// BATCH EXECUTION: Execute multiple steps with streaming
|
|
808
|
+
// Note: For streaming, we still use batch execution but stream the response
|
|
809
|
+
logger.debug(`[ResponseModal] Streaming batch execution for ${batchSteps.length} steps`);
|
|
810
|
+
yield* this.streamBatchResponse({
|
|
811
|
+
selectedRoute,
|
|
812
|
+
batchSteps,
|
|
813
|
+
responseDirectives,
|
|
814
|
+
session,
|
|
815
|
+
history,
|
|
816
|
+
context: effectiveContext,
|
|
817
|
+
historyEvents,
|
|
818
|
+
batchStoppedReason,
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
else {
|
|
822
|
+
// SINGLE STEP EXECUTION: Fall back to single-step streaming
|
|
823
|
+
yield* this.processRouteStreamingResponse({
|
|
824
|
+
selectedRoute,
|
|
825
|
+
selectedStep,
|
|
826
|
+
responseDirectives,
|
|
827
|
+
session,
|
|
828
|
+
history,
|
|
829
|
+
context: effectiveContext,
|
|
830
|
+
lastMessageText,
|
|
831
|
+
historyEvents,
|
|
832
|
+
});
|
|
833
|
+
}
|
|
416
834
|
}
|
|
417
835
|
else if (isRouteComplete && selectedRoute) {
|
|
418
836
|
// Handle route completion streaming
|
|
@@ -433,6 +851,114 @@ export class ResponseModal {
|
|
|
433
851
|
});
|
|
434
852
|
}
|
|
435
853
|
}
|
|
854
|
+
/**
|
|
855
|
+
* Stream a batch response with multiple steps
|
|
856
|
+
*
|
|
857
|
+
* Similar to executeBatchResponse but streams the LLM response.
|
|
858
|
+
*
|
|
859
|
+
* @private
|
|
860
|
+
*/
|
|
861
|
+
async *streamBatchResponse(params) {
|
|
862
|
+
const { selectedRoute, batchSteps, context, historyEvents, batchStoppedReason, signal } = params;
|
|
863
|
+
let session = params.session;
|
|
864
|
+
// Create hook executor function
|
|
865
|
+
const executeHook = async (hook, hookContext, data, step) => {
|
|
866
|
+
const route = selectedRoute;
|
|
867
|
+
const stepInstance = step?.id ? route.getStep(step.id) : undefined;
|
|
868
|
+
await this.executePrepareFinalize(hook, hookContext, data, route, stepInstance);
|
|
869
|
+
};
|
|
870
|
+
// PHASE 1: Execute all prepare hooks
|
|
871
|
+
const prepareResult = await this.batchExecutor.executePrepareHooks({
|
|
872
|
+
steps: batchSteps,
|
|
873
|
+
context,
|
|
874
|
+
data: session.data,
|
|
875
|
+
executeHook,
|
|
876
|
+
});
|
|
877
|
+
if (!prepareResult.success) {
|
|
878
|
+
// Yield error chunk
|
|
879
|
+
yield {
|
|
880
|
+
delta: "",
|
|
881
|
+
accumulated: "",
|
|
882
|
+
done: true,
|
|
883
|
+
session,
|
|
884
|
+
error: new ResponseGenerationError(`Prepare hook failed: ${prepareResult.error?.message}`, { phase: 'prepare_hooks' }),
|
|
885
|
+
};
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
// PHASE 2: Build combined prompt
|
|
889
|
+
const batchPromptResult = await this.batchPromptBuilder.buildBatchPrompt({
|
|
890
|
+
steps: batchSteps,
|
|
891
|
+
route: selectedRoute,
|
|
892
|
+
history: historyEvents,
|
|
893
|
+
context,
|
|
894
|
+
session,
|
|
895
|
+
agentOptions: this.agent.getAgentOptions(),
|
|
896
|
+
});
|
|
897
|
+
const responseSchema = this.buildBatchResponseSchema(batchPromptResult.collectFields);
|
|
898
|
+
const availableTools = this.collectBatchAvailableTools(selectedRoute, batchSteps);
|
|
899
|
+
// PHASE 3: Stream LLM response
|
|
900
|
+
const agentOptions = this.agent.getAgentOptions();
|
|
901
|
+
const stream = agentOptions.provider.generateMessageStream({
|
|
902
|
+
prompt: batchPromptResult.prompt,
|
|
903
|
+
history: historyEvents,
|
|
904
|
+
context,
|
|
905
|
+
tools: availableTools,
|
|
906
|
+
signal,
|
|
907
|
+
parameters: responseSchema ? { jsonSchema: responseSchema, schemaName: "batch_stream_response" } : undefined,
|
|
908
|
+
});
|
|
909
|
+
// Build executed steps list
|
|
910
|
+
const executedSteps = batchSteps
|
|
911
|
+
.filter(step => step.id)
|
|
912
|
+
.map(step => ({
|
|
913
|
+
id: step.id,
|
|
914
|
+
routeId: selectedRoute.id,
|
|
915
|
+
}));
|
|
916
|
+
// Stream chunks
|
|
917
|
+
for await (const chunk of stream) {
|
|
918
|
+
// On final chunk, collect data and execute finalize hooks
|
|
919
|
+
if (chunk.done) {
|
|
920
|
+
// Collect data from response
|
|
921
|
+
if (chunk.structured) {
|
|
922
|
+
const collectResult = this.batchExecutor.collectBatchData({
|
|
923
|
+
steps: batchSteps,
|
|
924
|
+
llmResponse: chunk.structured,
|
|
925
|
+
session,
|
|
926
|
+
schema: this.agent.getSchema(),
|
|
927
|
+
});
|
|
928
|
+
session = collectResult.session;
|
|
929
|
+
if (collectResult.collectedData && Object.keys(collectResult.collectedData).length > 0) {
|
|
930
|
+
await this.agent.updateCollectedData(collectResult.collectedData);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
// Update session to final step position
|
|
934
|
+
const lastStep = batchSteps[batchSteps.length - 1];
|
|
935
|
+
if (lastStep?.id) {
|
|
936
|
+
session = enterStep(session, lastStep.id, lastStep.description);
|
|
937
|
+
}
|
|
938
|
+
// Execute finalize hooks
|
|
939
|
+
await this.batchExecutor.executeFinalizeHooks({
|
|
940
|
+
steps: batchSteps,
|
|
941
|
+
context,
|
|
942
|
+
data: session.data,
|
|
943
|
+
executeHook,
|
|
944
|
+
});
|
|
945
|
+
// Finalize session
|
|
946
|
+
await this.finalizeSession(session, context);
|
|
947
|
+
}
|
|
948
|
+
yield {
|
|
949
|
+
delta: chunk.delta,
|
|
950
|
+
accumulated: chunk.accumulated,
|
|
951
|
+
done: chunk.done,
|
|
952
|
+
session,
|
|
953
|
+
toolCalls: chunk.structured?.toolCalls,
|
|
954
|
+
isRouteComplete: false,
|
|
955
|
+
executedSteps: chunk.done ? executedSteps : undefined,
|
|
956
|
+
stoppedReason: chunk.done ? batchStoppedReason : undefined,
|
|
957
|
+
metadata: chunk.metadata,
|
|
958
|
+
structured: chunk.structured,
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
}
|
|
436
962
|
/**
|
|
437
963
|
* Execute prepare function for current step if available
|
|
438
964
|
* @private
|
|
@@ -478,12 +1004,20 @@ export class ResponseModal {
|
|
|
478
1004
|
nextStep = selectedStep;
|
|
479
1005
|
}
|
|
480
1006
|
else {
|
|
481
|
-
//
|
|
1007
|
+
// Determine current step from session if we're already in this route
|
|
1008
|
+
const isInSameRoute = session.currentRoute?.id === selectedRoute.id;
|
|
1009
|
+
const currentStep = isInSameRoute && session.currentStep
|
|
1010
|
+
? selectedRoute.getStep(session.currentStep.id)
|
|
1011
|
+
: undefined;
|
|
1012
|
+
logger.debug(`[ResponseModal] Step determination: route match=${isInSameRoute}, currentRoute=${session.currentRoute?.id}, selectedRoute=${selectedRoute.id}, currentStep=${currentStep?.id || 'none'}`);
|
|
1013
|
+
// Get candidate steps based on current position in the route
|
|
482
1014
|
const routingEngine = this.agent.getRoutingEngine();
|
|
483
|
-
const candidates = routingEngine.
|
|
1015
|
+
const candidates = await routingEngine.getCandidateStepsWithConditions(selectedRoute, currentStep, // Pass current step instead of undefined to maintain progression
|
|
1016
|
+
createTemplateContext({ data: session.data, session, context }));
|
|
1017
|
+
logger.debug(`[ResponseModal] Found ${candidates.length} candidate steps${currentStep ? ' from current step ' + currentStep.id : ' (new route entry)'}`);
|
|
484
1018
|
if (candidates.length > 0) {
|
|
485
1019
|
nextStep = candidates[0].step;
|
|
486
|
-
logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id} for new route`);
|
|
1020
|
+
logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new route'}`);
|
|
487
1021
|
}
|
|
488
1022
|
else {
|
|
489
1023
|
// Fallback to initial step even if it should be skipped
|
|
@@ -492,16 +1026,42 @@ export class ResponseModal {
|
|
|
492
1026
|
}
|
|
493
1027
|
}
|
|
494
1028
|
// Update session with next step
|
|
495
|
-
|
|
496
|
-
|
|
1029
|
+
// If the next step has requires fields that are missing, stay at the previous step
|
|
1030
|
+
if (nextStep.requires && nextStep.requires.length > 0) {
|
|
1031
|
+
const sessionData = session.data || {};
|
|
1032
|
+
const missingRequires = nextStep.requires.filter(field => sessionData[String(field)] === undefined);
|
|
1033
|
+
if (missingRequires.length > 0) {
|
|
1034
|
+
const warning = `[Agent] Cannot advance to step "${nextStep.description || nextStep.id}": ` +
|
|
1035
|
+
`missing required fields [${missingRequires.join(', ')}]. Staying at current step.`;
|
|
1036
|
+
logger.warn(warning);
|
|
1037
|
+
console.warn(warning);
|
|
1038
|
+
// Stay at the current step - don't enter the next one
|
|
1039
|
+
const currentStepId = session.currentStep?.id;
|
|
1040
|
+
if (currentStepId) {
|
|
1041
|
+
const currentStepInstance = selectedRoute.getStep(currentStepId);
|
|
1042
|
+
if (currentStepInstance) {
|
|
1043
|
+
nextStep = currentStepInstance;
|
|
1044
|
+
logger.debug(`[ResponseModal] Staying at current step: ${nextStep.id} due to missing requires`);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
else {
|
|
1049
|
+
session = enterStep(session, nextStep.id, nextStep.description);
|
|
1050
|
+
logger.debug(`[ResponseModal] Entered step: ${nextStep.id}`);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
else {
|
|
1054
|
+
session = enterStep(session, nextStep.id, nextStep.description);
|
|
1055
|
+
logger.debug(`[ResponseModal] Entered step: ${nextStep.id}`);
|
|
1056
|
+
}
|
|
497
1057
|
// Build response schema for this route (with collect fields from step)
|
|
498
1058
|
const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep, this.agent.getSchema());
|
|
499
1059
|
// Build response prompt
|
|
500
1060
|
const responsePrompt = await this.responseEngine.buildResponsePrompt({
|
|
501
1061
|
route: selectedRoute,
|
|
502
1062
|
currentStep: nextStep,
|
|
503
|
-
rules: selectedRoute.getRules(),
|
|
504
|
-
prohibitions: selectedRoute.getProhibitions(),
|
|
1063
|
+
rules: [...this.agent.getRules(), ...selectedRoute.getRules()],
|
|
1064
|
+
prohibitions: [...this.agent.getProhibitions(), ...selectedRoute.getProhibitions()],
|
|
505
1065
|
directives: responseDirectives,
|
|
506
1066
|
history: historyEvents, // Use Event[] for buildResponsePrompt
|
|
507
1067
|
lastMessage: lastMessageText, // Use string for buildResponsePrompt
|
|
@@ -526,6 +1086,14 @@ export class ResponseModal {
|
|
|
526
1086
|
});
|
|
527
1087
|
let message = result.structured?.message || result.message;
|
|
528
1088
|
let toolCalls = result.structured?.toolCalls;
|
|
1089
|
+
// Debug: Log initial AI response
|
|
1090
|
+
logger.debug(`[ResponseModal] Initial AI response:`, {
|
|
1091
|
+
hasMessage: !!message,
|
|
1092
|
+
messageLength: message?.length || 0,
|
|
1093
|
+
hasToolCalls: !!toolCalls,
|
|
1094
|
+
toolCallsCount: toolCalls?.length || 0,
|
|
1095
|
+
toolNames: toolCalls?.map(tc => tc.toolName) || [],
|
|
1096
|
+
});
|
|
529
1097
|
// Execute tools with unified loop handling
|
|
530
1098
|
const toolResult = await this.executeUnifiedToolLoop({
|
|
531
1099
|
toolCalls,
|
|
@@ -560,11 +1128,17 @@ export class ResponseModal {
|
|
|
560
1128
|
nextStep = selectedStep;
|
|
561
1129
|
}
|
|
562
1130
|
else {
|
|
1131
|
+
// Determine current step from session if we're already in this route
|
|
1132
|
+
const currentStep = session.currentRoute?.id === selectedRoute.id && session.currentStep
|
|
1133
|
+
? selectedRoute.getStep(session.currentStep.id)
|
|
1134
|
+
: undefined;
|
|
1135
|
+
// Get candidate steps based on current position in the route
|
|
563
1136
|
const routingEngine = this.agent.getRoutingEngine();
|
|
564
|
-
const candidates = routingEngine.
|
|
1137
|
+
const candidates = await routingEngine.getCandidateStepsWithConditions(selectedRoute, currentStep, // Pass current step instead of undefined to maintain progression
|
|
1138
|
+
createTemplateContext({ data: session.data, session, context }));
|
|
565
1139
|
if (candidates.length > 0) {
|
|
566
1140
|
nextStep = candidates[0].step;
|
|
567
|
-
logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id} for new route`);
|
|
1141
|
+
logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new route'}`);
|
|
568
1142
|
}
|
|
569
1143
|
else {
|
|
570
1144
|
nextStep = selectedRoute.initialStep;
|
|
@@ -572,15 +1146,40 @@ export class ResponseModal {
|
|
|
572
1146
|
}
|
|
573
1147
|
}
|
|
574
1148
|
// Update session with next step
|
|
575
|
-
|
|
576
|
-
|
|
1149
|
+
// If the next step has requires fields that are missing, stay at the previous step
|
|
1150
|
+
if (nextStep.requires && nextStep.requires.length > 0) {
|
|
1151
|
+
const sessionData = session.data || {};
|
|
1152
|
+
const missingRequires = nextStep.requires.filter(field => sessionData[String(field)] === undefined);
|
|
1153
|
+
if (missingRequires.length > 0) {
|
|
1154
|
+
const warning = `[Agent] Cannot advance to step "${nextStep.description || nextStep.id}": ` +
|
|
1155
|
+
`missing required fields [${missingRequires.join(', ')}]. Staying at current step.`;
|
|
1156
|
+
logger.warn(warning);
|
|
1157
|
+
console.warn(warning);
|
|
1158
|
+
const currentStepId = session.currentStep?.id;
|
|
1159
|
+
if (currentStepId) {
|
|
1160
|
+
const currentStepInstance = selectedRoute.getStep(currentStepId);
|
|
1161
|
+
if (currentStepInstance) {
|
|
1162
|
+
nextStep = currentStepInstance;
|
|
1163
|
+
logger.debug(`[ResponseModal] Staying at current step: ${nextStep.id} due to missing requires`);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
else {
|
|
1168
|
+
session = enterStep(session, nextStep.id, nextStep.description);
|
|
1169
|
+
logger.debug(`[ResponseModal] Entered step: ${nextStep.id}`);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
else {
|
|
1173
|
+
session = enterStep(session, nextStep.id, nextStep.description);
|
|
1174
|
+
logger.debug(`[ResponseModal] Entered step: ${nextStep.id}`);
|
|
1175
|
+
}
|
|
577
1176
|
// Build response schema and prompt (same as non-streaming)
|
|
578
1177
|
const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep, this.agent.getSchema());
|
|
579
1178
|
const responsePrompt = await this.responseEngine.buildResponsePrompt({
|
|
580
1179
|
route: selectedRoute,
|
|
581
1180
|
currentStep: nextStep,
|
|
582
|
-
rules: selectedRoute.getRules(),
|
|
583
|
-
prohibitions: selectedRoute.getProhibitions(),
|
|
1181
|
+
rules: [...this.agent.getRules(), ...selectedRoute.getRules()],
|
|
1182
|
+
prohibitions: [...this.agent.getProhibitions(), ...selectedRoute.getProhibitions()],
|
|
584
1183
|
directives: responseDirectives,
|
|
585
1184
|
history: historyEvents, // Use Event[] for buildResponsePrompt
|
|
586
1185
|
lastMessage: lastMessageText, // Use string for buildResponsePrompt
|
|
@@ -637,6 +1236,10 @@ export class ResponseModal {
|
|
|
637
1236
|
if (chunk.done) {
|
|
638
1237
|
await this.finalizeSession(session, context);
|
|
639
1238
|
}
|
|
1239
|
+
// Response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
1240
|
+
// - executedSteps: single step executed in this response
|
|
1241
|
+
// - stoppedReason: 'needs_input' for single-step execution (waiting for user input)
|
|
1242
|
+
// - session.currentStep: reflects the executed step
|
|
640
1243
|
yield {
|
|
641
1244
|
delta: chunk.delta,
|
|
642
1245
|
accumulated: chunk.accumulated,
|
|
@@ -644,6 +1247,8 @@ export class ResponseModal {
|
|
|
644
1247
|
session,
|
|
645
1248
|
toolCalls,
|
|
646
1249
|
isRouteComplete: false,
|
|
1250
|
+
executedSteps: chunk.done ? [{ id: nextStep.id, routeId: selectedRoute.id }] : undefined,
|
|
1251
|
+
stoppedReason: chunk.done ? 'needs_input' : undefined,
|
|
647
1252
|
metadata: chunk.metadata,
|
|
648
1253
|
structured: chunk.structured,
|
|
649
1254
|
};
|
|
@@ -662,7 +1267,7 @@ export class ResponseModal {
|
|
|
662
1267
|
const historyEvents = historyToEvents(history);
|
|
663
1268
|
// Execute initial dynamic tool calls
|
|
664
1269
|
if (toolCalls && toolCalls.length > 0) {
|
|
665
|
-
logger.debug(`[ResponseModal] Executing ${toolCalls.length} dynamic tool calls
|
|
1270
|
+
logger.debug(`[ResponseModal] Executing ${toolCalls.length} dynamic tool calls:`, toolCalls.map(tc => tc.toolName));
|
|
666
1271
|
for (const toolCall of toolCalls) {
|
|
667
1272
|
const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
|
|
668
1273
|
if (!tool) {
|
|
@@ -732,7 +1337,7 @@ export class ResponseModal {
|
|
|
732
1337
|
let finalMessage;
|
|
733
1338
|
while (hasToolCalls && toolLoopCount < MAX_TOOL_LOOPS) {
|
|
734
1339
|
toolLoopCount++;
|
|
735
|
-
logger.debug(`[ResponseModal] Starting tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS}`);
|
|
1340
|
+
logger.debug(`[ResponseModal] Starting tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS} with ${toolCalls?.length || 0} tool calls`);
|
|
736
1341
|
// Create tool result events with proper Event format structure
|
|
737
1342
|
const toolResultEvents = [];
|
|
738
1343
|
for (const toolCall of toolCalls || []) {
|
|
@@ -761,12 +1366,19 @@ export class ResponseModal {
|
|
|
761
1366
|
// Create updated history with tool results (combine Event arrays)
|
|
762
1367
|
const updatedHistoryEvents = [...historyEvents, ...toolResultEvents];
|
|
763
1368
|
// Make follow-up AI call to see if more tools are needed
|
|
1369
|
+
// After first iteration, don't provide tools to force a text response
|
|
764
1370
|
const agentOptions = this.agent.getAgentOptions();
|
|
1371
|
+
const shouldProvideTools = toolLoopCount === 1;
|
|
1372
|
+
logger.debug(`[ResponseModal] Making follow-up AI call (loop ${toolLoopCount}):`, {
|
|
1373
|
+
providingTools: shouldProvideTools,
|
|
1374
|
+
toolsCount: shouldProvideTools ? availableTools.length : 0,
|
|
1375
|
+
addingTextInstruction: toolLoopCount > 1,
|
|
1376
|
+
});
|
|
765
1377
|
const followUpResult = await agentOptions.provider.generateMessage({
|
|
766
|
-
prompt: responsePrompt,
|
|
1378
|
+
prompt: responsePrompt + (toolLoopCount > 1 ? "\n\nProvide a text response to the user based on the tool results." : ""),
|
|
767
1379
|
history: updatedHistoryEvents, // Use Event[] for AI provider
|
|
768
1380
|
context,
|
|
769
|
-
tools: availableTools,
|
|
1381
|
+
tools: shouldProvideTools ? availableTools : [], // Only provide tools on first iteration
|
|
770
1382
|
parameters: responseSchema ? {
|
|
771
1383
|
jsonSchema: responseSchema,
|
|
772
1384
|
schemaName: "tool_followup",
|
|
@@ -776,6 +1388,13 @@ export class ResponseModal {
|
|
|
776
1388
|
// Check if follow-up call has more tool calls
|
|
777
1389
|
const followUpToolCalls = followUpResult.structured?.toolCalls;
|
|
778
1390
|
hasToolCalls = followUpToolCalls && followUpToolCalls.length > 0;
|
|
1391
|
+
logger.debug(`[ResponseModal] Follow-up AI response (loop ${toolLoopCount}):`, {
|
|
1392
|
+
hasMessage: !!followUpResult.message,
|
|
1393
|
+
messageLength: followUpResult.message?.length || 0,
|
|
1394
|
+
hasToolCalls,
|
|
1395
|
+
toolCallsCount: followUpToolCalls?.length || 0,
|
|
1396
|
+
toolNames: followUpToolCalls?.map(tc => tc.toolName) || [],
|
|
1397
|
+
});
|
|
779
1398
|
if (hasToolCalls) {
|
|
780
1399
|
logger.debug(`[ResponseModal] Follow-up call produced ${followUpToolCalls.length} additional tool calls`);
|
|
781
1400
|
// Execute the follow-up tool calls
|
|
@@ -849,6 +1468,12 @@ export class ResponseModal {
|
|
|
849
1468
|
if (toolLoopCount >= MAX_TOOL_LOOPS) {
|
|
850
1469
|
logger.warn(`[ResponseModal] Tool loop limit reached (${MAX_TOOL_LOOPS}), stopping`);
|
|
851
1470
|
}
|
|
1471
|
+
logger.debug(`[ResponseModal] Tool loop completed:`, {
|
|
1472
|
+
totalIterations: toolLoopCount,
|
|
1473
|
+
hasFinalMessage: !!finalMessage,
|
|
1474
|
+
finalMessageLength: finalMessage?.length || 0,
|
|
1475
|
+
finalToolCallsCount: toolCalls?.length || 0,
|
|
1476
|
+
});
|
|
852
1477
|
return {
|
|
853
1478
|
session,
|
|
854
1479
|
finalToolCalls: toolCalls,
|
|
@@ -870,14 +1495,29 @@ export class ResponseModal {
|
|
|
870
1495
|
const { result, selectedRoute, nextStep, session } = params;
|
|
871
1496
|
let updatedSession = session;
|
|
872
1497
|
// Extract collected data from final response (only for route-based interactions)
|
|
873
|
-
if (selectedRoute && result.structured
|
|
1498
|
+
if (selectedRoute && result.structured) {
|
|
874
1499
|
try {
|
|
875
1500
|
const collectedData = {};
|
|
876
1501
|
// AgentStructuredResponse extends Record<string, unknown>, so we can safely access properties
|
|
877
1502
|
const structuredData = result.structured;
|
|
878
|
-
|
|
1503
|
+
// Collect ALL route fields (required + optional) from structured response
|
|
1504
|
+
const allRouteFields = new Set();
|
|
1505
|
+
// Add route required fields
|
|
1506
|
+
if (selectedRoute.requiredFields) {
|
|
1507
|
+
selectedRoute.requiredFields.forEach(field => allRouteFields.add(String(field)));
|
|
1508
|
+
}
|
|
1509
|
+
// Add route optional fields
|
|
1510
|
+
if (selectedRoute.optionalFields) {
|
|
1511
|
+
selectedRoute.optionalFields.forEach(field => allRouteFields.add(String(field)));
|
|
1512
|
+
}
|
|
1513
|
+
// Also include current step's collect fields (in case they're not in route fields)
|
|
1514
|
+
if (nextStep?.collect) {
|
|
1515
|
+
nextStep.collect.forEach(field => allRouteFields.add(String(field)));
|
|
1516
|
+
}
|
|
1517
|
+
// Extract all available fields from structured response
|
|
1518
|
+
for (const field of allRouteFields) {
|
|
879
1519
|
const fieldKey = String(field);
|
|
880
|
-
if (fieldKey in structuredData) {
|
|
1520
|
+
if (fieldKey in structuredData && structuredData[fieldKey] !== undefined && structuredData[fieldKey] !== null) {
|
|
881
1521
|
collectedData[fieldKey] = structuredData[fieldKey];
|
|
882
1522
|
}
|
|
883
1523
|
}
|
|
@@ -940,34 +1580,60 @@ export class ResponseModal {
|
|
|
940
1580
|
requires: endStepSpec.requires,
|
|
941
1581
|
prompt: endStepSpec.prompt || "Summarize what was accomplished and confirm completion based on the conversation history and collected data",
|
|
942
1582
|
});
|
|
943
|
-
// Build response schema for completion
|
|
944
|
-
const
|
|
945
|
-
|
|
946
|
-
|
|
1583
|
+
// Build response schema for completion (message only, no data collection)
|
|
1584
|
+
const completionSchema = {
|
|
1585
|
+
type: "object",
|
|
1586
|
+
properties: {
|
|
1587
|
+
message: {
|
|
1588
|
+
type: "string",
|
|
1589
|
+
description: "Completion message confirming what was accomplished",
|
|
1590
|
+
},
|
|
1591
|
+
},
|
|
1592
|
+
required: ["message"],
|
|
1593
|
+
additionalProperties: false,
|
|
1594
|
+
};
|
|
1595
|
+
const templateContext = createTemplateContext({ context, session, history: historyEvents });
|
|
1596
|
+
// Build completion response prompt using ResponseEngine
|
|
1597
|
+
// Filter out conditional guidelines - only include always-active ones
|
|
1598
|
+
const alwaysActiveGuidelines = [
|
|
1599
|
+
...this.agent.getGuidelines().filter(g => !g.condition),
|
|
1600
|
+
...selectedRoute.getGuidelines().filter(g => !g.condition),
|
|
1601
|
+
];
|
|
1602
|
+
let completitionPrompt = "Summarize what was accomplished and confirm completion";
|
|
1603
|
+
if (endStepSpec.prompt) {
|
|
1604
|
+
completitionPrompt = await render(endStepSpec.prompt, templateContext);
|
|
1605
|
+
}
|
|
947
1606
|
const completionPrompt = await this.responseEngine.buildResponsePrompt({
|
|
948
1607
|
route: selectedRoute,
|
|
949
1608
|
currentStep: completionStep,
|
|
950
1609
|
rules: selectedRoute.getRules(),
|
|
951
1610
|
prohibitions: selectedRoute.getProhibitions(),
|
|
952
|
-
directives:
|
|
953
|
-
|
|
954
|
-
|
|
1611
|
+
directives: [
|
|
1612
|
+
`Task completed: ${selectedRoute.title}`,
|
|
1613
|
+
`Collected data: ${JSON.stringify(session.data, null, 2)}`,
|
|
1614
|
+
"Do NOT ask for more information - the task is complete",
|
|
1615
|
+
completitionPrompt,
|
|
1616
|
+
],
|
|
1617
|
+
history: historyEvents,
|
|
1618
|
+
lastMessage: lastMessageText,
|
|
955
1619
|
agentOptions: this.agent.getAgentOptions(),
|
|
956
|
-
combinedGuidelines:
|
|
1620
|
+
combinedGuidelines: alwaysActiveGuidelines, // Only non-conditional guidelines
|
|
957
1621
|
combinedTerms: this.mergeTerms(this.agent.getTerms(), selectedRoute.getTerms()),
|
|
958
1622
|
context,
|
|
959
1623
|
session,
|
|
960
|
-
agentSchema:
|
|
1624
|
+
agentSchema: undefined, // No data collection schema for completion
|
|
961
1625
|
});
|
|
962
1626
|
// Generate completion message using AI provider
|
|
963
1627
|
const agentOptions = this.agent.getAgentOptions();
|
|
1628
|
+
logger.debug(`[ResponseModal] Calling AI provider for completion message...`);
|
|
964
1629
|
const completionResult = await agentOptions.provider.generateMessage({
|
|
965
1630
|
prompt: completionPrompt,
|
|
966
|
-
history: historyEvents,
|
|
1631
|
+
history: historyEvents,
|
|
967
1632
|
context,
|
|
968
1633
|
signal,
|
|
969
|
-
parameters: { jsonSchema:
|
|
1634
|
+
parameters: { jsonSchema: completionSchema, schemaName: "completion_message" },
|
|
970
1635
|
});
|
|
1636
|
+
logger.debug(`[ResponseModal] AI provider returned completion result`);
|
|
971
1637
|
const message = completionResult.structured?.message || completionResult.message;
|
|
972
1638
|
logger.debug(`[ResponseModal] Generated completion message for route: ${selectedRoute.title}`);
|
|
973
1639
|
// Check for onComplete transition
|
|
@@ -1010,7 +1676,7 @@ export class ResponseModal {
|
|
|
1010
1676
|
});
|
|
1011
1677
|
// Build response schema for completion
|
|
1012
1678
|
const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep, this.agent.getSchema());
|
|
1013
|
-
const templateContext = { context, session, history: historyEvents }; // Use Event[] for template context
|
|
1679
|
+
const templateContext = createTemplateContext({ context, session, history: historyEvents }); // Use Event[] for template context
|
|
1014
1680
|
// Build completion response prompt
|
|
1015
1681
|
const completionPrompt = await this.responseEngine.buildResponsePrompt({
|
|
1016
1682
|
route: selectedRoute,
|
|
@@ -1068,6 +1734,10 @@ export class ResponseModal {
|
|
|
1068
1734
|
if (chunk.done) {
|
|
1069
1735
|
await this.finalizeSession(session, context);
|
|
1070
1736
|
}
|
|
1737
|
+
// Response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
1738
|
+
// - executedSteps: empty for route completion (no new steps executed)
|
|
1739
|
+
// - stoppedReason: 'route_complete' for completed routes
|
|
1740
|
+
// - session.currentStep: set to END_ROUTE
|
|
1071
1741
|
yield {
|
|
1072
1742
|
delta: chunk.delta,
|
|
1073
1743
|
accumulated: chunk.accumulated,
|
|
@@ -1075,6 +1745,8 @@ export class ResponseModal {
|
|
|
1075
1745
|
session,
|
|
1076
1746
|
toolCalls: undefined,
|
|
1077
1747
|
isRouteComplete: true,
|
|
1748
|
+
executedSteps: chunk.done ? [] : undefined,
|
|
1749
|
+
stoppedReason: chunk.done ? 'route_complete' : undefined,
|
|
1078
1750
|
metadata: chunk.metadata,
|
|
1079
1751
|
structured: chunk.structured,
|
|
1080
1752
|
};
|
|
@@ -1149,6 +1821,10 @@ export class ResponseModal {
|
|
|
1149
1821
|
if (chunk.done) {
|
|
1150
1822
|
await this.finalizeSession(session, context);
|
|
1151
1823
|
}
|
|
1824
|
+
// Response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
1825
|
+
// - executedSteps: empty for fallback (no route/step execution)
|
|
1826
|
+
// - stoppedReason: undefined for fallback (no route context)
|
|
1827
|
+
// - session.currentStep: unchanged (no step progression)
|
|
1152
1828
|
yield {
|
|
1153
1829
|
delta: chunk.delta,
|
|
1154
1830
|
accumulated: chunk.accumulated,
|
|
@@ -1156,6 +1832,8 @@ export class ResponseModal {
|
|
|
1156
1832
|
session,
|
|
1157
1833
|
toolCalls: undefined,
|
|
1158
1834
|
isRouteComplete: false,
|
|
1835
|
+
executedSteps: chunk.done ? [] : undefined,
|
|
1836
|
+
stoppedReason: undefined,
|
|
1159
1837
|
metadata: chunk.metadata,
|
|
1160
1838
|
structured: chunk.structured,
|
|
1161
1839
|
};
|