@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
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
ToolEventData,
|
|
16
16
|
AgentStructuredResponse,
|
|
17
17
|
Term,
|
|
18
|
+
StoppedReason,
|
|
18
19
|
} from "../types";
|
|
19
20
|
import { EventKind, MessageRole } from "../types";
|
|
20
21
|
import type { Agent } from "./Agent";
|
|
@@ -22,9 +23,13 @@ import type { Route } from "./Route";
|
|
|
22
23
|
import { Step } from "./Step";
|
|
23
24
|
import { ResponseEngine } from "./ResponseEngine";
|
|
24
25
|
import { ResponsePipeline } from "./ResponsePipeline";
|
|
26
|
+
import { BatchExecutor, type HookFunction } from "./BatchExecutor";
|
|
27
|
+
import { BatchPromptBuilder } from "./BatchPromptBuilder";
|
|
25
28
|
import { cloneDeep, mergeCollected, enterStep, getLastMessageFromHistory, render, logger, historyToEvents } from "../utils";
|
|
29
|
+
import { createTemplateContext } from "../utils/template";
|
|
26
30
|
import type { ToolManager } from "./ToolManager";
|
|
27
31
|
import { END_ROUTE_ID } from "../constants";
|
|
32
|
+
import type { StepOptions } from "../types/route";
|
|
28
33
|
|
|
29
34
|
/**
|
|
30
35
|
* Configuration options for ResponseModal
|
|
@@ -129,6 +134,12 @@ interface ResponseContext<TContext = unknown, TData = unknown> {
|
|
|
129
134
|
selectedStep?: Step<TContext, TData>;
|
|
130
135
|
responseDirectives?: string[];
|
|
131
136
|
isRouteComplete: boolean;
|
|
137
|
+
/** Batch of steps to execute (for multi-step execution) */
|
|
138
|
+
batchSteps?: StepOptions<TContext, TData>[];
|
|
139
|
+
/** Reason why batch determination stopped */
|
|
140
|
+
batchStoppedReason?: StoppedReason;
|
|
141
|
+
/** Step that caused batch to stop (if applicable) */
|
|
142
|
+
batchStoppedAtStep?: StepOptions<TContext, TData>;
|
|
132
143
|
}
|
|
133
144
|
|
|
134
145
|
/**
|
|
@@ -138,6 +149,8 @@ interface ResponseContext<TContext = unknown, TData = unknown> {
|
|
|
138
149
|
export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
139
150
|
private readonly responseEngine: ResponseEngine<TContext, TData>;
|
|
140
151
|
private readonly responsePipeline: ResponsePipeline<TContext, TData>;
|
|
152
|
+
private readonly batchExecutor: BatchExecutor<TContext, TData>;
|
|
153
|
+
private readonly batchPromptBuilder: BatchPromptBuilder<TContext, TData>;
|
|
141
154
|
|
|
142
155
|
constructor(
|
|
143
156
|
private readonly agent: Agent<TContext, TData>,
|
|
@@ -157,6 +170,12 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
157
170
|
this.agent.updateCollectedData.bind(this.agent),
|
|
158
171
|
this.getToolManager()
|
|
159
172
|
);
|
|
173
|
+
|
|
174
|
+
// Initialize batch executor for multi-step execution
|
|
175
|
+
this.batchExecutor = new BatchExecutor<TContext, TData>();
|
|
176
|
+
|
|
177
|
+
// Initialize batch prompt builder for combined prompts
|
|
178
|
+
this.batchPromptBuilder = new BatchPromptBuilder<TContext, TData>();
|
|
160
179
|
}
|
|
161
180
|
|
|
162
181
|
/**
|
|
@@ -418,12 +437,16 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
418
437
|
}
|
|
419
438
|
|
|
420
439
|
// PHASE 2: ROUTING + STEP SELECTION - Determine which route and step to use
|
|
440
|
+
// Also performs pre-extraction and batch determination
|
|
421
441
|
let routingResult: {
|
|
422
442
|
selectedRoute?: Route<TContext, TData>;
|
|
423
443
|
selectedStep?: Step<TContext, TData>;
|
|
424
444
|
responseDirectives?: string[];
|
|
425
445
|
session: SessionState<TData>;
|
|
426
446
|
isRouteComplete: boolean;
|
|
447
|
+
batchSteps?: StepOptions<TContext, TData>[];
|
|
448
|
+
batchStoppedReason?: StoppedReason;
|
|
449
|
+
batchStoppedAtStep?: StepOptions<TContext, TData>;
|
|
427
450
|
};
|
|
428
451
|
try {
|
|
429
452
|
routingResult = await this.handleUnifiedRoutingAndStepSelection({
|
|
@@ -444,6 +467,9 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
444
467
|
selectedStep: routingResult.selectedStep,
|
|
445
468
|
responseDirectives: routingResult.responseDirectives,
|
|
446
469
|
isRouteComplete: routingResult.isRouteComplete,
|
|
470
|
+
batchSteps: routingResult.batchSteps,
|
|
471
|
+
batchStoppedReason: routingResult.batchStoppedReason,
|
|
472
|
+
batchStoppedAtStep: routingResult.batchStoppedAtStep,
|
|
447
473
|
};
|
|
448
474
|
} catch (error) {
|
|
449
475
|
// Re-throw ResponseGenerationError as-is, wrap others
|
|
@@ -469,6 +495,12 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
469
495
|
responseDirectives?: string[];
|
|
470
496
|
session: SessionState<TData>;
|
|
471
497
|
isRouteComplete: boolean;
|
|
498
|
+
/** Batch of steps to execute (for multi-step execution) */
|
|
499
|
+
batchSteps?: StepOptions<TContext, TData>[];
|
|
500
|
+
/** Reason why batch determination stopped */
|
|
501
|
+
batchStoppedReason?: StoppedReason;
|
|
502
|
+
/** Step that caused batch to stop (if applicable) */
|
|
503
|
+
batchStoppedAtStep?: StepOptions<TContext, TData>;
|
|
472
504
|
}> {
|
|
473
505
|
try {
|
|
474
506
|
// Use the ResponsePipeline for optimized routing and step selection
|
|
@@ -480,12 +512,84 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
480
512
|
context: params.context,
|
|
481
513
|
signal: params.signal,
|
|
482
514
|
});
|
|
515
|
+
|
|
516
|
+
let updatedSession = routingResult.session;
|
|
517
|
+
let isRouteComplete = routingResult.isRouteComplete;
|
|
518
|
+
|
|
519
|
+
// PRE-EXTRACTION: If entering a route that collects data, extract data from user message first
|
|
520
|
+
// This allows us to skip steps whose data is already provided
|
|
521
|
+
// Requirement 3.1: Perform Pre_Extraction before determining the Batch
|
|
522
|
+
if (routingResult.selectedRoute && !isRouteComplete) {
|
|
523
|
+
// Always pre-extract when route collects data (not just on new route entry)
|
|
524
|
+
// This ensures batch determination has the most up-to-date data
|
|
525
|
+
if (this.shouldPreExtractData(routingResult.selectedRoute)) {
|
|
526
|
+
logger.debug(
|
|
527
|
+
`[ResponseModal] Pre-extracting data for route: ${routingResult.selectedRoute.title}`
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
const extractedData = await this.preExtractRouteData({
|
|
531
|
+
route: routingResult.selectedRoute,
|
|
532
|
+
history: params.history,
|
|
533
|
+
context: params.context,
|
|
534
|
+
session: updatedSession,
|
|
535
|
+
signal: params.signal,
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
if (extractedData && Object.keys(extractedData).length > 0) {
|
|
539
|
+
logger.debug(
|
|
540
|
+
`[ResponseModal] Pre-extracted data:`,
|
|
541
|
+
extractedData
|
|
542
|
+
);
|
|
543
|
+
// Requirement 3.3: Merge pre-extracted data into session before batch determination
|
|
544
|
+
updatedSession = mergeCollected(updatedSession, extractedData);
|
|
545
|
+
// Also update agent's collected data
|
|
546
|
+
await this.agent.updateCollectedData(extractedData);
|
|
547
|
+
|
|
548
|
+
// Re-check route completion after pre-extraction
|
|
549
|
+
const allRequiredFieldsCollected = routingResult.selectedRoute.isComplete(updatedSession.data || {});
|
|
550
|
+
if (allRequiredFieldsCollected) {
|
|
551
|
+
logger.debug(
|
|
552
|
+
`[ResponseModal] Route ${routingResult.selectedRoute.title} completed after pre-extraction`
|
|
553
|
+
);
|
|
554
|
+
isRouteComplete = true;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// BATCH DETERMINATION: Use BatchExecutor to determine which steps can execute together
|
|
561
|
+
// Requirement 3.4: Pre-extraction results affect batch determination
|
|
562
|
+
let batchSteps: StepOptions<TContext, TData>[] | undefined;
|
|
563
|
+
let batchStoppedReason: StoppedReason | undefined;
|
|
564
|
+
let batchStoppedAtStep: StepOptions<TContext, TData> | undefined;
|
|
565
|
+
|
|
566
|
+
if (routingResult.selectedRoute && !isRouteComplete) {
|
|
567
|
+
// Determine current step position for batch determination
|
|
568
|
+
const currentStep = routingResult.selectedStep ||
|
|
569
|
+
(updatedSession.currentStep ? routingResult.selectedRoute.getStep(updatedSession.currentStep.id) : undefined);
|
|
570
|
+
|
|
571
|
+
logger.debug(`[ResponseModal] Determining batch starting from step: ${currentStep?.id || 'initial'}`);
|
|
572
|
+
|
|
573
|
+
const batchResult = await this.batchExecutor.determineBatch({
|
|
574
|
+
route: routingResult.selectedRoute,
|
|
575
|
+
currentStep,
|
|
576
|
+
sessionData: updatedSession.data || {},
|
|
577
|
+
context: params.context,
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
batchSteps = batchResult.steps;
|
|
581
|
+
batchStoppedReason = batchResult.stoppedReason;
|
|
582
|
+
batchStoppedAtStep = batchResult.stoppedAtStep;
|
|
583
|
+
|
|
584
|
+
logger.debug(`[ResponseModal] Batch determined: ${batchSteps.length} steps, stopped reason: ${batchStoppedReason}`);
|
|
585
|
+
}
|
|
586
|
+
|
|
483
587
|
// Determine next step using pipeline method for consistency
|
|
484
|
-
const stepResult = this.responsePipeline.determineNextStep({
|
|
588
|
+
const stepResult = await this.responsePipeline.determineNextStep({
|
|
485
589
|
selectedRoute: routingResult.selectedRoute,
|
|
486
590
|
selectedStep: routingResult.selectedStep,
|
|
487
|
-
session:
|
|
488
|
-
isRouteComplete
|
|
591
|
+
session: updatedSession, // Use updated session with pre-extracted data
|
|
592
|
+
isRouteComplete, // Use updated completion status
|
|
489
593
|
});
|
|
490
594
|
|
|
491
595
|
return {
|
|
@@ -493,13 +597,106 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
493
597
|
selectedStep: stepResult.nextStep, // Use the determined next step
|
|
494
598
|
responseDirectives: routingResult.responseDirectives,
|
|
495
599
|
session: stepResult.session,
|
|
496
|
-
isRouteComplete
|
|
600
|
+
isRouteComplete, // Use updated completion status
|
|
601
|
+
batchSteps,
|
|
602
|
+
batchStoppedReason,
|
|
603
|
+
batchStoppedAtStep,
|
|
497
604
|
};
|
|
498
605
|
} catch (error) {
|
|
499
606
|
throw ResponseGenerationError.fromError(error, 'routing_optimization', params);
|
|
500
607
|
}
|
|
501
608
|
}
|
|
502
609
|
|
|
610
|
+
/**
|
|
611
|
+
* Check if a route should pre-extract data before determining the initial step
|
|
612
|
+
* @private
|
|
613
|
+
*/
|
|
614
|
+
private shouldPreExtractData(route: Route<TContext, TData>): boolean {
|
|
615
|
+
// Pre-extract if route has declared required or optional fields
|
|
616
|
+
if (route.requiredFields && route.requiredFields.length > 0) {
|
|
617
|
+
return true;
|
|
618
|
+
}
|
|
619
|
+
if (route.optionalFields && route.optionalFields.length > 0) {
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Pre-extract if any step in the route collects data
|
|
624
|
+
const steps = route.getAllSteps();
|
|
625
|
+
const hasDataCollectionSteps = steps.some(
|
|
626
|
+
step => step.collect && step.collect.length > 0
|
|
627
|
+
);
|
|
628
|
+
|
|
629
|
+
return hasDataCollectionSteps;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Pre-extract data from user message when entering a route
|
|
634
|
+
* This allows skipping steps whose data is already provided
|
|
635
|
+
* @private
|
|
636
|
+
*/
|
|
637
|
+
private async preExtractRouteData(params: {
|
|
638
|
+
route: Route<TContext, TData>;
|
|
639
|
+
history: Event[];
|
|
640
|
+
context: TContext;
|
|
641
|
+
session: SessionState<TData>;
|
|
642
|
+
signal?: AbortSignal;
|
|
643
|
+
}): Promise<Partial<TData>> {
|
|
644
|
+
const { route, history, context, signal } = params;
|
|
645
|
+
|
|
646
|
+
// Build a schema for data extraction based on route's fields
|
|
647
|
+
const extractionSchema = this.agent.getSchema();
|
|
648
|
+
if (!extractionSchema) {
|
|
649
|
+
logger.warn(`[ResponseModal] No schema available for pre-extraction`);
|
|
650
|
+
return {};
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// Get last user message
|
|
654
|
+
const lastMessage = getLastMessageFromHistory(history);
|
|
655
|
+
|
|
656
|
+
// Build extraction prompt
|
|
657
|
+
const extractionPrompt = [
|
|
658
|
+
`Extract any relevant information from the user's message that matches the following data fields.`,
|
|
659
|
+
`Only extract information that is explicitly stated or clearly implied.`,
|
|
660
|
+
``,
|
|
661
|
+
`User's message: "${lastMessage}"`,
|
|
662
|
+
``,
|
|
663
|
+
`Extract data for these fields if present:`,
|
|
664
|
+
];
|
|
665
|
+
|
|
666
|
+
// Add field descriptions
|
|
667
|
+
if (route.requiredFields) {
|
|
668
|
+
extractionPrompt.push(`Required fields: ${route.requiredFields.join(', ')}`);
|
|
669
|
+
}
|
|
670
|
+
if (route.optionalFields) {
|
|
671
|
+
extractionPrompt.push(`Optional fields: ${route.optionalFields.join(', ')}`);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
extractionPrompt.push(
|
|
675
|
+
``,
|
|
676
|
+
`Return ONLY the extracted data as JSON. If no data can be extracted, return an empty object {}.`
|
|
677
|
+
);
|
|
678
|
+
|
|
679
|
+
// Call AI to extract data
|
|
680
|
+
const agentOptions = this.agent.getAgentOptions();
|
|
681
|
+
try {
|
|
682
|
+
const result = await agentOptions.provider.generateMessage<TContext, Partial<TData>>({
|
|
683
|
+
prompt: extractionPrompt.join('\n'),
|
|
684
|
+
history,
|
|
685
|
+
context,
|
|
686
|
+
signal,
|
|
687
|
+
parameters: {
|
|
688
|
+
jsonSchema: extractionSchema,
|
|
689
|
+
schemaName: 'data_extraction',
|
|
690
|
+
},
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
return result.structured || {};
|
|
694
|
+
} catch (error) {
|
|
695
|
+
logger.error(`[ResponseModal] Pre-extraction failed:`, error);
|
|
696
|
+
return {};
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
503
700
|
/**
|
|
504
701
|
* Unified response generation for non-streaming responses
|
|
505
702
|
* @private
|
|
@@ -507,7 +704,17 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
507
704
|
private async generateUnifiedResponse(
|
|
508
705
|
responseContext: ResponseContext<TContext, TData>
|
|
509
706
|
): Promise<AgentResponse<TData>> {
|
|
510
|
-
const {
|
|
707
|
+
const {
|
|
708
|
+
effectiveContext,
|
|
709
|
+
session: initialSession,
|
|
710
|
+
history,
|
|
711
|
+
selectedRoute,
|
|
712
|
+
selectedStep,
|
|
713
|
+
responseDirectives,
|
|
714
|
+
isRouteComplete,
|
|
715
|
+
batchSteps,
|
|
716
|
+
batchStoppedReason,
|
|
717
|
+
} = responseContext;
|
|
511
718
|
let session = initialSession;
|
|
512
719
|
|
|
513
720
|
// Get last user message (needed for both route and completion handling)
|
|
@@ -517,42 +724,87 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
517
724
|
|
|
518
725
|
let message: string;
|
|
519
726
|
let toolCalls: Array<{ toolName: string; arguments: Record<string, unknown> }> | undefined = undefined;
|
|
727
|
+
let executedSteps: StepRef[] | undefined;
|
|
728
|
+
let stoppedReason: StoppedReason | undefined;
|
|
520
729
|
|
|
521
730
|
|
|
522
731
|
|
|
523
732
|
if (selectedRoute && !isRouteComplete) {
|
|
524
|
-
//
|
|
733
|
+
// Check if we have batch steps to execute
|
|
734
|
+
if (batchSteps && batchSteps.length > 0) {
|
|
735
|
+
// BATCH EXECUTION: Execute multiple steps in a single LLM call
|
|
736
|
+
logger.debug(`[ResponseModal] Executing batch of ${batchSteps.length} steps`);
|
|
525
737
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
738
|
+
const batchResult = await this.executeBatchResponse({
|
|
739
|
+
selectedRoute,
|
|
740
|
+
batchSteps,
|
|
741
|
+
responseDirectives,
|
|
742
|
+
session,
|
|
743
|
+
history,
|
|
744
|
+
context: effectiveContext,
|
|
745
|
+
historyEvents,
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
message = batchResult.message;
|
|
749
|
+
toolCalls = batchResult.toolCalls;
|
|
750
|
+
session = batchResult.session;
|
|
751
|
+
executedSteps = batchResult.executedSteps;
|
|
752
|
+
stoppedReason = batchStoppedReason;
|
|
753
|
+
|
|
754
|
+
} else {
|
|
755
|
+
// SINGLE STEP EXECUTION: Fall back to single-step processing
|
|
756
|
+
// This happens when batch determination returns empty (first step needs input)
|
|
757
|
+
const result = await this.processRouteResponse({
|
|
758
|
+
selectedRoute,
|
|
759
|
+
selectedStep,
|
|
760
|
+
responseDirectives,
|
|
761
|
+
session,
|
|
762
|
+
history,
|
|
763
|
+
context: effectiveContext,
|
|
764
|
+
lastMessageText,
|
|
765
|
+
historyEvents,
|
|
766
|
+
signal: undefined,
|
|
767
|
+
});
|
|
537
768
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
769
|
+
message = result.message;
|
|
770
|
+
toolCalls = result.toolCalls;
|
|
771
|
+
session = result.session;
|
|
772
|
+
|
|
773
|
+
// Track executed step for single-step execution
|
|
774
|
+
if (selectedStep) {
|
|
775
|
+
executedSteps = [{
|
|
776
|
+
id: selectedStep.id,
|
|
777
|
+
routeId: selectedRoute.id,
|
|
778
|
+
}];
|
|
779
|
+
}
|
|
780
|
+
stoppedReason = batchStoppedReason || 'needs_input';
|
|
781
|
+
}
|
|
541
782
|
|
|
542
783
|
} else if (isRouteComplete && selectedRoute) {
|
|
543
784
|
// Handle route completion
|
|
785
|
+
logger.debug(`[ResponseModal] Generating completion message for route: ${selectedRoute.title}`);
|
|
544
786
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
787
|
+
try {
|
|
788
|
+
message = await this.handleRouteCompletion({
|
|
789
|
+
selectedRoute,
|
|
790
|
+
session,
|
|
791
|
+
context: effectiveContext,
|
|
792
|
+
lastMessageText,
|
|
793
|
+
historyEvents,
|
|
794
|
+
signal: undefined,
|
|
795
|
+
});
|
|
552
796
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
797
|
+
// Set step to END_ROUTE marker
|
|
798
|
+
session = enterStep(session, END_ROUTE_ID, "Route completed");
|
|
799
|
+
stoppedReason = 'route_complete';
|
|
800
|
+
logger.debug(`[ResponseModal] Route ${selectedRoute.title} completed. Entered END_ROUTE step.`);
|
|
801
|
+
} catch (error) {
|
|
802
|
+
logger.error(`[ResponseModal] Error generating completion message:`, error);
|
|
803
|
+
// Fallback to simple completion message
|
|
804
|
+
message = `Thank you! I've recorded all the information for your ${selectedRoute.title.toLowerCase()}.`;
|
|
805
|
+
session = enterStep(session, END_ROUTE_ID, "Route completed");
|
|
806
|
+
stoppedReason = 'route_complete';
|
|
807
|
+
}
|
|
556
808
|
|
|
557
809
|
} else {
|
|
558
810
|
// Fallback: No routes defined, generate a simple response
|
|
@@ -562,16 +814,298 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
562
814
|
context: effectiveContext,
|
|
563
815
|
session,
|
|
564
816
|
});
|
|
817
|
+
|
|
818
|
+
// For fallback responses, set empty executedSteps and no stoppedReason
|
|
819
|
+
// since there's no route/step execution happening
|
|
820
|
+
executedSteps = [];
|
|
821
|
+
stoppedReason = undefined;
|
|
565
822
|
}
|
|
566
823
|
|
|
824
|
+
// Ensure response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
825
|
+
// - executedSteps: array of steps executed (empty array if none)
|
|
826
|
+
// - stoppedReason: why execution stopped (undefined for fallback)
|
|
827
|
+
// - session.currentStep: reflects final step position
|
|
567
828
|
return {
|
|
568
829
|
message,
|
|
569
830
|
session,
|
|
570
831
|
toolCalls,
|
|
571
832
|
isRouteComplete,
|
|
833
|
+
executedSteps: executedSteps || [],
|
|
834
|
+
stoppedReason,
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* Execute a batch of steps with a single LLM call
|
|
840
|
+
*
|
|
841
|
+
* This method:
|
|
842
|
+
* 1. Executes all prepare hooks for steps in the batch (in order)
|
|
843
|
+
* 2. Builds a combined prompt using BatchPromptBuilder
|
|
844
|
+
* 3. Makes a single LLM call
|
|
845
|
+
* 4. Collects data from the response for all steps
|
|
846
|
+
* 5. Executes all finalize hooks for steps in the batch (in order)
|
|
847
|
+
*
|
|
848
|
+
* @private
|
|
849
|
+
* **Validates: Requirements 1.1, 4.4, 5.1, 5.2**
|
|
850
|
+
*/
|
|
851
|
+
private async executeBatchResponse(params: {
|
|
852
|
+
selectedRoute: Route<TContext, TData>;
|
|
853
|
+
batchSteps: StepOptions<TContext, TData>[];
|
|
854
|
+
responseDirectives?: string[];
|
|
855
|
+
session: SessionState<TData>;
|
|
856
|
+
history: HistoryItem[];
|
|
857
|
+
context: TContext;
|
|
858
|
+
historyEvents: Event[];
|
|
859
|
+
signal?: AbortSignal;
|
|
860
|
+
}): Promise<{
|
|
861
|
+
message: string;
|
|
862
|
+
toolCalls?: Array<{ toolName: string; arguments: Record<string, unknown> }>;
|
|
863
|
+
session: SessionState<TData>;
|
|
864
|
+
executedSteps: StepRef[];
|
|
865
|
+
}> {
|
|
866
|
+
const { selectedRoute, batchSteps, history, context, historyEvents, signal } = params;
|
|
867
|
+
let session = params.session;
|
|
868
|
+
|
|
869
|
+
logger.debug(`[ResponseModal] Starting batch execution for ${batchSteps.length} steps`);
|
|
870
|
+
|
|
871
|
+
// Create hook executor function
|
|
872
|
+
const executeHook = async (
|
|
873
|
+
hook: HookFunction<TContext, TData>,
|
|
874
|
+
hookContext: TContext,
|
|
875
|
+
data?: Partial<TData>,
|
|
876
|
+
step?: StepOptions<TContext, TData>
|
|
877
|
+
): Promise<void> => {
|
|
878
|
+
// Find the route for this step
|
|
879
|
+
const route = selectedRoute;
|
|
880
|
+
// Convert StepOptions to Step if needed for executePrepareFinalize
|
|
881
|
+
const stepInstance = step?.id ? route.getStep(step.id) : undefined;
|
|
882
|
+
await this.executePrepareFinalize(hook, hookContext, data, route, stepInstance);
|
|
883
|
+
};
|
|
884
|
+
|
|
885
|
+
// PHASE 1: Execute all prepare hooks (Requirement 5.1)
|
|
886
|
+
logger.debug(`[ResponseModal] Executing prepare hooks for batch`);
|
|
887
|
+
const prepareResult = await this.batchExecutor.executePrepareHooks({
|
|
888
|
+
steps: batchSteps,
|
|
889
|
+
context,
|
|
890
|
+
data: session.data,
|
|
891
|
+
executeHook,
|
|
892
|
+
});
|
|
893
|
+
|
|
894
|
+
if (!prepareResult.success) {
|
|
895
|
+
// Prepare hook failed - return error response
|
|
896
|
+
logger.error(`[ResponseModal] Prepare hook failed:`, prepareResult.error);
|
|
897
|
+
throw new ResponseGenerationError(
|
|
898
|
+
`Prepare hook failed: ${prepareResult.error?.message}`,
|
|
899
|
+
{
|
|
900
|
+
phase: 'prepare_hooks',
|
|
901
|
+
context: {
|
|
902
|
+
stepId: prepareResult.error?.stepId,
|
|
903
|
+
executedSteps: prepareResult.executedSteps,
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// PHASE 2: Build combined prompt using BatchPromptBuilder (Requirement 4.4)
|
|
910
|
+
logger.debug(`[ResponseModal] Building batch prompt`);
|
|
911
|
+
const batchPromptResult = await this.batchPromptBuilder.buildBatchPrompt({
|
|
912
|
+
steps: batchSteps,
|
|
913
|
+
route: selectedRoute,
|
|
914
|
+
history: historyEvents,
|
|
915
|
+
context,
|
|
916
|
+
session,
|
|
917
|
+
agentOptions: this.agent.getAgentOptions(),
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
logger.debug(`[ResponseModal] Batch prompt built with ${batchPromptResult.stepCount} steps, collecting: ${batchPromptResult.collectFields.join(', ')}`);
|
|
921
|
+
|
|
922
|
+
// Build response schema for batch (includes all collect fields)
|
|
923
|
+
const responseSchema = this.buildBatchResponseSchema(batchPromptResult.collectFields);
|
|
924
|
+
|
|
925
|
+
// Collect available tools for AI (from all steps in batch)
|
|
926
|
+
const availableTools = this.collectBatchAvailableTools(selectedRoute, batchSteps);
|
|
927
|
+
|
|
928
|
+
// PHASE 3: Make single LLM call (Requirement 4.4)
|
|
929
|
+
logger.debug(`[ResponseModal] Making LLM call for batch`);
|
|
930
|
+
const agentOptions = this.agent.getAgentOptions();
|
|
931
|
+
const result = await agentOptions.provider.generateMessage({
|
|
932
|
+
prompt: batchPromptResult.prompt,
|
|
933
|
+
history: historyEvents,
|
|
934
|
+
context,
|
|
935
|
+
tools: availableTools,
|
|
936
|
+
signal,
|
|
937
|
+
parameters: responseSchema ? { jsonSchema: responseSchema, schemaName: "batch_response" } : undefined,
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
let message = result.structured?.message || result.message;
|
|
941
|
+
let toolCalls = result.structured?.toolCalls;
|
|
942
|
+
|
|
943
|
+
logger.debug(`[ResponseModal] LLM response received for batch`);
|
|
944
|
+
|
|
945
|
+
// Execute tools if any
|
|
946
|
+
if (toolCalls && toolCalls.length > 0) {
|
|
947
|
+
const toolResult = await this.executeUnifiedToolLoop({
|
|
948
|
+
toolCalls,
|
|
949
|
+
context,
|
|
950
|
+
session,
|
|
951
|
+
history,
|
|
952
|
+
selectedRoute,
|
|
953
|
+
responsePrompt: batchPromptResult.prompt,
|
|
954
|
+
availableTools,
|
|
955
|
+
responseSchema,
|
|
956
|
+
signal,
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
session = toolResult.session;
|
|
960
|
+
toolCalls = toolResult.finalToolCalls;
|
|
961
|
+
if (toolResult.finalMessage) {
|
|
962
|
+
message = toolResult.finalMessage;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// PHASE 4: Collect data from response for all steps (Requirement 6.1, 6.2, 6.3)
|
|
967
|
+
logger.debug(`[ResponseModal] Collecting batch data`);
|
|
968
|
+
const collectResult = this.batchExecutor.collectBatchData({
|
|
969
|
+
steps: batchSteps,
|
|
970
|
+
llmResponse: result.structured || {},
|
|
971
|
+
session,
|
|
972
|
+
schema: this.agent.getSchema(),
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
session = collectResult.session;
|
|
976
|
+
|
|
977
|
+
if (collectResult.collectedData && Object.keys(collectResult.collectedData).length > 0) {
|
|
978
|
+
// Update agent's collected data
|
|
979
|
+
await this.agent.updateCollectedData(collectResult.collectedData);
|
|
980
|
+
logger.debug(`[ResponseModal] Batch collected data:`, collectResult.collectedData);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
if (collectResult.validationErrors && collectResult.validationErrors.length > 0) {
|
|
984
|
+
logger.warn(`[ResponseModal] Batch data validation errors:`, collectResult.validationErrors);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// Update session to final step position
|
|
988
|
+
const lastStep = batchSteps[batchSteps.length - 1];
|
|
989
|
+
if (lastStep?.id) {
|
|
990
|
+
session = enterStep(session, lastStep.id, lastStep.description);
|
|
991
|
+
logger.debug(`[ResponseModal] Updated session to final batch step: ${lastStep.id}`);
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// PHASE 5: Execute all finalize hooks (Requirement 5.2)
|
|
995
|
+
logger.debug(`[ResponseModal] Executing finalize hooks for batch`);
|
|
996
|
+
const finalizeResult = await this.batchExecutor.executeFinalizeHooks({
|
|
997
|
+
steps: batchSteps,
|
|
998
|
+
context,
|
|
999
|
+
data: session.data,
|
|
1000
|
+
executeHook,
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
if (finalizeResult.errors && finalizeResult.errors.length > 0) {
|
|
1004
|
+
// Log finalize errors but don't fail (Requirement 5.5)
|
|
1005
|
+
logger.warn(`[ResponseModal] Some finalize hooks failed:`, finalizeResult.errors);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
// Build executed steps list
|
|
1009
|
+
const executedSteps: StepRef[] = batchSteps
|
|
1010
|
+
.filter(step => step.id)
|
|
1011
|
+
.map(step => ({
|
|
1012
|
+
id: step.id!,
|
|
1013
|
+
routeId: selectedRoute.id,
|
|
1014
|
+
}));
|
|
1015
|
+
|
|
1016
|
+
logger.debug(`[ResponseModal] Batch execution complete. Executed ${executedSteps.length} steps`);
|
|
1017
|
+
|
|
1018
|
+
return {
|
|
1019
|
+
message,
|
|
1020
|
+
toolCalls,
|
|
1021
|
+
session,
|
|
1022
|
+
executedSteps,
|
|
572
1023
|
};
|
|
573
1024
|
}
|
|
574
1025
|
|
|
1026
|
+
/**
|
|
1027
|
+
* Build response schema for batch execution
|
|
1028
|
+
* @private
|
|
1029
|
+
*/
|
|
1030
|
+
private buildBatchResponseSchema(collectFields: string[]): Record<string, unknown> {
|
|
1031
|
+
const properties: Record<string, unknown> = {
|
|
1032
|
+
message: {
|
|
1033
|
+
type: "string",
|
|
1034
|
+
description: "Your response to the user",
|
|
1035
|
+
},
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
const agentSchema = this.agent.getSchema();
|
|
1039
|
+
|
|
1040
|
+
// Add collect fields to schema, using agent schema definitions when available
|
|
1041
|
+
for (const field of collectFields) {
|
|
1042
|
+
if (agentSchema?.properties && agentSchema.properties[field]) {
|
|
1043
|
+
properties[field] = agentSchema.properties[field];
|
|
1044
|
+
} else {
|
|
1045
|
+
// Dynamic fallback when no agent schema is defined
|
|
1046
|
+
properties[field] = {
|
|
1047
|
+
type: "string",
|
|
1048
|
+
description: `Collected value for ${field}`,
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
return {
|
|
1054
|
+
type: "object",
|
|
1055
|
+
properties,
|
|
1056
|
+
required: ["message"],
|
|
1057
|
+
additionalProperties: true,
|
|
1058
|
+
};
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* Collect available tools from all steps in the batch
|
|
1063
|
+
* @private
|
|
1064
|
+
*/
|
|
1065
|
+
private collectBatchAvailableTools(
|
|
1066
|
+
route: Route<TContext, TData>,
|
|
1067
|
+
batchSteps: StepOptions<TContext, TData>[]
|
|
1068
|
+
): Array<{
|
|
1069
|
+
id: string;
|
|
1070
|
+
name: string;
|
|
1071
|
+
description?: string;
|
|
1072
|
+
parameters?: unknown;
|
|
1073
|
+
}> {
|
|
1074
|
+
const availableTools = new Map<string, Tool<TContext, TData>>();
|
|
1075
|
+
|
|
1076
|
+
// Add agent-level tools
|
|
1077
|
+
this.agent.getTools().forEach((tool) => {
|
|
1078
|
+
availableTools.set(tool.id, tool);
|
|
1079
|
+
});
|
|
1080
|
+
|
|
1081
|
+
// Add route-level tools
|
|
1082
|
+
route.getTools().forEach((tool: Tool<TContext, TData>) => {
|
|
1083
|
+
availableTools.set(tool.id, tool);
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
// Add step-level tools from all batch steps
|
|
1087
|
+
for (const step of batchSteps) {
|
|
1088
|
+
if (step.tools) {
|
|
1089
|
+
for (const toolRef of step.tools) {
|
|
1090
|
+
if (typeof toolRef === "string") {
|
|
1091
|
+
// Reference to registered tool - already in availableTools
|
|
1092
|
+
} else if (typeof toolRef === 'object' && 'id' in toolRef && toolRef.id) {
|
|
1093
|
+
// Inline tool definition
|
|
1094
|
+
availableTools.set(toolRef.id, toolRef);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// Convert to the format expected by AI providers
|
|
1101
|
+
return Array.from(availableTools.values()).map((tool) => ({
|
|
1102
|
+
id: tool.id,
|
|
1103
|
+
name: tool.name || tool.id,
|
|
1104
|
+
description: tool.description,
|
|
1105
|
+
parameters: tool.parameters,
|
|
1106
|
+
}));
|
|
1107
|
+
}
|
|
1108
|
+
|
|
575
1109
|
/**
|
|
576
1110
|
* Unified streaming response generation
|
|
577
1111
|
* @private
|
|
@@ -579,7 +1113,17 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
579
1113
|
private async *generateUnifiedStreamingResponse(
|
|
580
1114
|
responseContext: ResponseContext<TContext, TData>
|
|
581
1115
|
): AsyncGenerator<AgentResponseStreamChunk<TData>> {
|
|
582
|
-
const {
|
|
1116
|
+
const {
|
|
1117
|
+
effectiveContext,
|
|
1118
|
+
session: initialSession,
|
|
1119
|
+
history,
|
|
1120
|
+
selectedRoute,
|
|
1121
|
+
selectedStep,
|
|
1122
|
+
responseDirectives,
|
|
1123
|
+
isRouteComplete,
|
|
1124
|
+
batchSteps,
|
|
1125
|
+
batchStoppedReason,
|
|
1126
|
+
} = responseContext;
|
|
583
1127
|
const session = initialSession;
|
|
584
1128
|
|
|
585
1129
|
// Get last user message (needed for both route and completion handling)
|
|
@@ -588,17 +1132,35 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
588
1132
|
const lastMessageText = getLastMessageFromHistory(historyEvents);
|
|
589
1133
|
|
|
590
1134
|
if (selectedRoute && !isRouteComplete) {
|
|
591
|
-
//
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
1135
|
+
// Check if we have batch steps to execute
|
|
1136
|
+
if (batchSteps && batchSteps.length > 0) {
|
|
1137
|
+
// BATCH EXECUTION: Execute multiple steps with streaming
|
|
1138
|
+
// Note: For streaming, we still use batch execution but stream the response
|
|
1139
|
+
logger.debug(`[ResponseModal] Streaming batch execution for ${batchSteps.length} steps`);
|
|
1140
|
+
|
|
1141
|
+
yield* this.streamBatchResponse({
|
|
1142
|
+
selectedRoute,
|
|
1143
|
+
batchSteps,
|
|
1144
|
+
responseDirectives,
|
|
1145
|
+
session,
|
|
1146
|
+
history,
|
|
1147
|
+
context: effectiveContext,
|
|
1148
|
+
historyEvents,
|
|
1149
|
+
batchStoppedReason,
|
|
1150
|
+
});
|
|
1151
|
+
} else {
|
|
1152
|
+
// SINGLE STEP EXECUTION: Fall back to single-step streaming
|
|
1153
|
+
yield* this.processRouteStreamingResponse({
|
|
1154
|
+
selectedRoute,
|
|
1155
|
+
selectedStep,
|
|
1156
|
+
responseDirectives,
|
|
1157
|
+
session,
|
|
1158
|
+
history,
|
|
1159
|
+
context: effectiveContext,
|
|
1160
|
+
lastMessageText,
|
|
1161
|
+
historyEvents,
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
602
1164
|
|
|
603
1165
|
} else if (isRouteComplete && selectedRoute) {
|
|
604
1166
|
// Handle route completion streaming
|
|
@@ -619,6 +1181,148 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
619
1181
|
});
|
|
620
1182
|
}
|
|
621
1183
|
}
|
|
1184
|
+
|
|
1185
|
+
/**
|
|
1186
|
+
* Stream a batch response with multiple steps
|
|
1187
|
+
*
|
|
1188
|
+
* Similar to executeBatchResponse but streams the LLM response.
|
|
1189
|
+
*
|
|
1190
|
+
* @private
|
|
1191
|
+
*/
|
|
1192
|
+
private async *streamBatchResponse(params: {
|
|
1193
|
+
selectedRoute: Route<TContext, TData>;
|
|
1194
|
+
batchSteps: StepOptions<TContext, TData>[];
|
|
1195
|
+
responseDirectives?: string[];
|
|
1196
|
+
session: SessionState<TData>;
|
|
1197
|
+
history: HistoryItem[];
|
|
1198
|
+
context: TContext;
|
|
1199
|
+
historyEvents: Event[];
|
|
1200
|
+
batchStoppedReason?: StoppedReason;
|
|
1201
|
+
signal?: AbortSignal;
|
|
1202
|
+
}): AsyncGenerator<AgentResponseStreamChunk<TData>> {
|
|
1203
|
+
const { selectedRoute, batchSteps, context, historyEvents, batchStoppedReason, signal } = params;
|
|
1204
|
+
let session = params.session;
|
|
1205
|
+
|
|
1206
|
+
// Create hook executor function
|
|
1207
|
+
const executeHook = async (
|
|
1208
|
+
hook: HookFunction<TContext, TData>,
|
|
1209
|
+
hookContext: TContext,
|
|
1210
|
+
data?: Partial<TData>,
|
|
1211
|
+
step?: StepOptions<TContext, TData>
|
|
1212
|
+
): Promise<void> => {
|
|
1213
|
+
const route = selectedRoute;
|
|
1214
|
+
const stepInstance = step?.id ? route.getStep(step.id) : undefined;
|
|
1215
|
+
await this.executePrepareFinalize(hook, hookContext, data, route, stepInstance);
|
|
1216
|
+
};
|
|
1217
|
+
|
|
1218
|
+
// PHASE 1: Execute all prepare hooks
|
|
1219
|
+
const prepareResult = await this.batchExecutor.executePrepareHooks({
|
|
1220
|
+
steps: batchSteps,
|
|
1221
|
+
context,
|
|
1222
|
+
data: session.data,
|
|
1223
|
+
executeHook,
|
|
1224
|
+
});
|
|
1225
|
+
|
|
1226
|
+
if (!prepareResult.success) {
|
|
1227
|
+
// Yield error chunk
|
|
1228
|
+
yield {
|
|
1229
|
+
delta: "",
|
|
1230
|
+
accumulated: "",
|
|
1231
|
+
done: true,
|
|
1232
|
+
session,
|
|
1233
|
+
error: new ResponseGenerationError(
|
|
1234
|
+
`Prepare hook failed: ${prepareResult.error?.message}`,
|
|
1235
|
+
{ phase: 'prepare_hooks' }
|
|
1236
|
+
),
|
|
1237
|
+
};
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
// PHASE 2: Build combined prompt
|
|
1242
|
+
const batchPromptResult = await this.batchPromptBuilder.buildBatchPrompt({
|
|
1243
|
+
steps: batchSteps,
|
|
1244
|
+
route: selectedRoute,
|
|
1245
|
+
history: historyEvents,
|
|
1246
|
+
context,
|
|
1247
|
+
session,
|
|
1248
|
+
agentOptions: this.agent.getAgentOptions(),
|
|
1249
|
+
});
|
|
1250
|
+
|
|
1251
|
+
const responseSchema = this.buildBatchResponseSchema(batchPromptResult.collectFields);
|
|
1252
|
+
const availableTools = this.collectBatchAvailableTools(selectedRoute, batchSteps);
|
|
1253
|
+
|
|
1254
|
+
// PHASE 3: Stream LLM response
|
|
1255
|
+
const agentOptions = this.agent.getAgentOptions();
|
|
1256
|
+
const stream = agentOptions.provider.generateMessageStream({
|
|
1257
|
+
prompt: batchPromptResult.prompt,
|
|
1258
|
+
history: historyEvents,
|
|
1259
|
+
context,
|
|
1260
|
+
tools: availableTools,
|
|
1261
|
+
signal,
|
|
1262
|
+
parameters: responseSchema ? { jsonSchema: responseSchema, schemaName: "batch_stream_response" } : undefined,
|
|
1263
|
+
});
|
|
1264
|
+
|
|
1265
|
+
// Build executed steps list
|
|
1266
|
+
const executedSteps: StepRef[] = batchSteps
|
|
1267
|
+
.filter(step => step.id)
|
|
1268
|
+
.map(step => ({
|
|
1269
|
+
id: step.id!,
|
|
1270
|
+
routeId: selectedRoute.id,
|
|
1271
|
+
}));
|
|
1272
|
+
|
|
1273
|
+
// Stream chunks
|
|
1274
|
+
for await (const chunk of stream) {
|
|
1275
|
+
// On final chunk, collect data and execute finalize hooks
|
|
1276
|
+
if (chunk.done) {
|
|
1277
|
+
// Collect data from response
|
|
1278
|
+
if (chunk.structured) {
|
|
1279
|
+
const collectResult = this.batchExecutor.collectBatchData({
|
|
1280
|
+
steps: batchSteps,
|
|
1281
|
+
llmResponse: chunk.structured,
|
|
1282
|
+
session,
|
|
1283
|
+
schema: this.agent.getSchema(),
|
|
1284
|
+
});
|
|
1285
|
+
|
|
1286
|
+
session = collectResult.session;
|
|
1287
|
+
|
|
1288
|
+
if (collectResult.collectedData && Object.keys(collectResult.collectedData).length > 0) {
|
|
1289
|
+
await this.agent.updateCollectedData(collectResult.collectedData);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
// Update session to final step position
|
|
1294
|
+
const lastStep = batchSteps[batchSteps.length - 1];
|
|
1295
|
+
if (lastStep?.id) {
|
|
1296
|
+
session = enterStep(session, lastStep.id, lastStep.description);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// Execute finalize hooks
|
|
1300
|
+
await this.batchExecutor.executeFinalizeHooks({
|
|
1301
|
+
steps: batchSteps,
|
|
1302
|
+
context,
|
|
1303
|
+
data: session.data,
|
|
1304
|
+
executeHook,
|
|
1305
|
+
});
|
|
1306
|
+
|
|
1307
|
+
// Finalize session
|
|
1308
|
+
await this.finalizeSession(session, context);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
yield {
|
|
1312
|
+
delta: chunk.delta,
|
|
1313
|
+
accumulated: chunk.accumulated,
|
|
1314
|
+
done: chunk.done,
|
|
1315
|
+
session,
|
|
1316
|
+
toolCalls: chunk.structured?.toolCalls,
|
|
1317
|
+
isRouteComplete: false,
|
|
1318
|
+
executedSteps: chunk.done ? executedSteps : undefined,
|
|
1319
|
+
stoppedReason: chunk.done ? batchStoppedReason : undefined,
|
|
1320
|
+
metadata: chunk.metadata,
|
|
1321
|
+
structured: chunk.structured,
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
622
1326
|
/**
|
|
623
1327
|
* Execute prepare function for current step if available
|
|
624
1328
|
* @private
|
|
@@ -698,12 +1402,27 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
698
1402
|
if (selectedStep) {
|
|
699
1403
|
nextStep = selectedStep;
|
|
700
1404
|
} else {
|
|
701
|
-
//
|
|
1405
|
+
// Determine current step from session if we're already in this route
|
|
1406
|
+
const isInSameRoute = session.currentRoute?.id === selectedRoute.id;
|
|
1407
|
+
const currentStep = isInSameRoute && session.currentStep
|
|
1408
|
+
? selectedRoute.getStep(session.currentStep.id)
|
|
1409
|
+
: undefined;
|
|
1410
|
+
|
|
1411
|
+
logger.debug(`[ResponseModal] Step determination: route match=${isInSameRoute}, currentRoute=${session.currentRoute?.id}, selectedRoute=${selectedRoute.id}, currentStep=${currentStep?.id || 'none'}`);
|
|
1412
|
+
|
|
1413
|
+
// Get candidate steps based on current position in the route
|
|
702
1414
|
const routingEngine = this.agent.getRoutingEngine();
|
|
703
|
-
const candidates = routingEngine.
|
|
1415
|
+
const candidates = await routingEngine.getCandidateStepsWithConditions(
|
|
1416
|
+
selectedRoute,
|
|
1417
|
+
currentStep, // Pass current step instead of undefined to maintain progression
|
|
1418
|
+
createTemplateContext({ data: session.data, session, context })
|
|
1419
|
+
);
|
|
1420
|
+
|
|
1421
|
+
logger.debug(`[ResponseModal] Found ${candidates.length} candidate steps${currentStep ? ' from current step ' + currentStep.id : ' (new route entry)'}`);
|
|
1422
|
+
|
|
704
1423
|
if (candidates.length > 0) {
|
|
705
1424
|
nextStep = candidates[0].step;
|
|
706
|
-
logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id} for new route`);
|
|
1425
|
+
logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new route'}`);
|
|
707
1426
|
} else {
|
|
708
1427
|
// Fallback to initial step even if it should be skipped
|
|
709
1428
|
nextStep = selectedRoute.initialStep;
|
|
@@ -712,8 +1431,34 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
712
1431
|
}
|
|
713
1432
|
|
|
714
1433
|
// Update session with next step
|
|
715
|
-
|
|
716
|
-
|
|
1434
|
+
// If the next step has requires fields that are missing, stay at the previous step
|
|
1435
|
+
if (nextStep.requires && nextStep.requires.length > 0) {
|
|
1436
|
+
const sessionData = session.data || {};
|
|
1437
|
+
const missingRequires = nextStep.requires.filter(
|
|
1438
|
+
field => (sessionData as Record<string, unknown>)[String(field)] === undefined
|
|
1439
|
+
);
|
|
1440
|
+
if (missingRequires.length > 0) {
|
|
1441
|
+
const warning = `[Agent] Cannot advance to step "${nextStep.description || nextStep.id}": ` +
|
|
1442
|
+
`missing required fields [${missingRequires.join(', ')}]. Staying at current step.`;
|
|
1443
|
+
logger.warn(warning);
|
|
1444
|
+
console.warn(warning);
|
|
1445
|
+
// Stay at the current step - don't enter the next one
|
|
1446
|
+
const currentStepId = session.currentStep?.id;
|
|
1447
|
+
if (currentStepId) {
|
|
1448
|
+
const currentStepInstance = selectedRoute.getStep(currentStepId);
|
|
1449
|
+
if (currentStepInstance) {
|
|
1450
|
+
nextStep = currentStepInstance;
|
|
1451
|
+
logger.debug(`[ResponseModal] Staying at current step: ${nextStep.id} due to missing requires`);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
} else {
|
|
1455
|
+
session = enterStep(session, nextStep.id, nextStep.description);
|
|
1456
|
+
logger.debug(`[ResponseModal] Entered step: ${nextStep.id}`);
|
|
1457
|
+
}
|
|
1458
|
+
} else {
|
|
1459
|
+
session = enterStep(session, nextStep.id, nextStep.description);
|
|
1460
|
+
logger.debug(`[ResponseModal] Entered step: ${nextStep.id}`);
|
|
1461
|
+
}
|
|
717
1462
|
|
|
718
1463
|
// Build response schema for this route (with collect fields from step)
|
|
719
1464
|
const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep, this.agent.getSchema());
|
|
@@ -722,8 +1467,8 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
722
1467
|
const responsePrompt = await this.responseEngine.buildResponsePrompt({
|
|
723
1468
|
route: selectedRoute,
|
|
724
1469
|
currentStep: nextStep,
|
|
725
|
-
rules: selectedRoute.getRules(),
|
|
726
|
-
prohibitions: selectedRoute.getProhibitions(),
|
|
1470
|
+
rules: [...this.agent.getRules(), ...selectedRoute.getRules()],
|
|
1471
|
+
prohibitions: [...this.agent.getProhibitions(), ...selectedRoute.getProhibitions()],
|
|
727
1472
|
directives: responseDirectives,
|
|
728
1473
|
history: historyEvents, // Use Event[] for buildResponsePrompt
|
|
729
1474
|
lastMessage: lastMessageText, // Use string for buildResponsePrompt
|
|
@@ -752,6 +1497,15 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
752
1497
|
let message = result.structured?.message || result.message;
|
|
753
1498
|
let toolCalls = result.structured?.toolCalls;
|
|
754
1499
|
|
|
1500
|
+
// Debug: Log initial AI response
|
|
1501
|
+
logger.debug(`[ResponseModal] Initial AI response:`, {
|
|
1502
|
+
hasMessage: !!message,
|
|
1503
|
+
messageLength: message?.length || 0,
|
|
1504
|
+
hasToolCalls: !!toolCalls,
|
|
1505
|
+
toolCallsCount: toolCalls?.length || 0,
|
|
1506
|
+
toolNames: toolCalls?.map(tc => tc.toolName) || [],
|
|
1507
|
+
});
|
|
1508
|
+
|
|
755
1509
|
// Execute tools with unified loop handling
|
|
756
1510
|
const toolResult = await this.executeUnifiedToolLoop({
|
|
757
1511
|
toolCalls,
|
|
@@ -800,11 +1554,22 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
800
1554
|
if (selectedStep) {
|
|
801
1555
|
nextStep = selectedStep;
|
|
802
1556
|
} else {
|
|
1557
|
+
// Determine current step from session if we're already in this route
|
|
1558
|
+
const currentStep = session.currentRoute?.id === selectedRoute.id && session.currentStep
|
|
1559
|
+
? selectedRoute.getStep(session.currentStep.id)
|
|
1560
|
+
: undefined;
|
|
1561
|
+
|
|
1562
|
+
// Get candidate steps based on current position in the route
|
|
803
1563
|
const routingEngine = this.agent.getRoutingEngine();
|
|
804
|
-
const candidates = routingEngine.
|
|
1564
|
+
const candidates = await routingEngine.getCandidateStepsWithConditions(
|
|
1565
|
+
selectedRoute,
|
|
1566
|
+
currentStep, // Pass current step instead of undefined to maintain progression
|
|
1567
|
+
createTemplateContext({ data: session.data, session, context })
|
|
1568
|
+
);
|
|
1569
|
+
|
|
805
1570
|
if (candidates.length > 0) {
|
|
806
1571
|
nextStep = candidates[0].step;
|
|
807
|
-
logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id} for new route`);
|
|
1572
|
+
logger.debug(`[ResponseModal] Using first valid step: ${nextStep.id}${currentStep ? ' (progressing from ' + currentStep.id + ')' : ' for new route'}`);
|
|
808
1573
|
} else {
|
|
809
1574
|
nextStep = selectedRoute.initialStep;
|
|
810
1575
|
logger.warn(`[ResponseModal] No valid steps found, using initial step: ${nextStep.id}`);
|
|
@@ -812,16 +1577,41 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
812
1577
|
}
|
|
813
1578
|
|
|
814
1579
|
// Update session with next step
|
|
815
|
-
|
|
816
|
-
|
|
1580
|
+
// If the next step has requires fields that are missing, stay at the previous step
|
|
1581
|
+
if (nextStep.requires && nextStep.requires.length > 0) {
|
|
1582
|
+
const sessionData = session.data || {};
|
|
1583
|
+
const missingRequires = nextStep.requires.filter(
|
|
1584
|
+
field => (sessionData as Record<string, unknown>)[String(field)] === undefined
|
|
1585
|
+
);
|
|
1586
|
+
if (missingRequires.length > 0) {
|
|
1587
|
+
const warning = `[Agent] Cannot advance to step "${nextStep.description || nextStep.id}": ` +
|
|
1588
|
+
`missing required fields [${missingRequires.join(', ')}]. Staying at current step.`;
|
|
1589
|
+
logger.warn(warning);
|
|
1590
|
+
console.warn(warning);
|
|
1591
|
+
const currentStepId = session.currentStep?.id;
|
|
1592
|
+
if (currentStepId) {
|
|
1593
|
+
const currentStepInstance = selectedRoute.getStep(currentStepId);
|
|
1594
|
+
if (currentStepInstance) {
|
|
1595
|
+
nextStep = currentStepInstance;
|
|
1596
|
+
logger.debug(`[ResponseModal] Staying at current step: ${nextStep.id} due to missing requires`);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
} else {
|
|
1600
|
+
session = enterStep(session, nextStep.id, nextStep.description);
|
|
1601
|
+
logger.debug(`[ResponseModal] Entered step: ${nextStep.id}`);
|
|
1602
|
+
}
|
|
1603
|
+
} else {
|
|
1604
|
+
session = enterStep(session, nextStep.id, nextStep.description);
|
|
1605
|
+
logger.debug(`[ResponseModal] Entered step: ${nextStep.id}`);
|
|
1606
|
+
}
|
|
817
1607
|
|
|
818
1608
|
// Build response schema and prompt (same as non-streaming)
|
|
819
1609
|
const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, nextStep, this.agent.getSchema());
|
|
820
1610
|
const responsePrompt = await this.responseEngine.buildResponsePrompt({
|
|
821
1611
|
route: selectedRoute,
|
|
822
1612
|
currentStep: nextStep,
|
|
823
|
-
rules: selectedRoute.getRules(),
|
|
824
|
-
prohibitions: selectedRoute.getProhibitions(),
|
|
1613
|
+
rules: [...this.agent.getRules(), ...selectedRoute.getRules()],
|
|
1614
|
+
prohibitions: [...this.agent.getProhibitions(), ...selectedRoute.getProhibitions()],
|
|
825
1615
|
directives: responseDirectives,
|
|
826
1616
|
history: historyEvents, // Use Event[] for buildResponsePrompt
|
|
827
1617
|
lastMessage: lastMessageText, // Use string for buildResponsePrompt
|
|
@@ -887,6 +1677,10 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
887
1677
|
await this.finalizeSession(session, context);
|
|
888
1678
|
}
|
|
889
1679
|
|
|
1680
|
+
// Response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
1681
|
+
// - executedSteps: single step executed in this response
|
|
1682
|
+
// - stoppedReason: 'needs_input' for single-step execution (waiting for user input)
|
|
1683
|
+
// - session.currentStep: reflects the executed step
|
|
890
1684
|
yield {
|
|
891
1685
|
delta: chunk.delta,
|
|
892
1686
|
accumulated: chunk.accumulated,
|
|
@@ -894,6 +1688,8 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
894
1688
|
session,
|
|
895
1689
|
toolCalls,
|
|
896
1690
|
isRouteComplete: false,
|
|
1691
|
+
executedSteps: chunk.done ? [{ id: nextStep.id, routeId: selectedRoute.id }] : undefined,
|
|
1692
|
+
stoppedReason: chunk.done ? 'needs_input' : undefined,
|
|
897
1693
|
metadata: chunk.metadata,
|
|
898
1694
|
structured: chunk.structured,
|
|
899
1695
|
};
|
|
@@ -934,7 +1730,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
934
1730
|
|
|
935
1731
|
// Execute initial dynamic tool calls
|
|
936
1732
|
if (toolCalls && toolCalls.length > 0) {
|
|
937
|
-
logger.debug(`[ResponseModal] Executing ${toolCalls.length} dynamic tool calls
|
|
1733
|
+
logger.debug(`[ResponseModal] Executing ${toolCalls.length} dynamic tool calls:`, toolCalls.map(tc => tc.toolName));
|
|
938
1734
|
|
|
939
1735
|
for (const toolCall of toolCalls) {
|
|
940
1736
|
const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
|
|
@@ -1009,7 +1805,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1009
1805
|
|
|
1010
1806
|
while (hasToolCalls && toolLoopCount < MAX_TOOL_LOOPS) {
|
|
1011
1807
|
toolLoopCount++;
|
|
1012
|
-
logger.debug(`[ResponseModal] Starting tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS}`);
|
|
1808
|
+
logger.debug(`[ResponseModal] Starting tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS} with ${toolCalls?.length || 0} tool calls`);
|
|
1013
1809
|
|
|
1014
1810
|
// Create tool result events with proper Event format structure
|
|
1015
1811
|
const toolResultEvents: Event<ToolEventData>[] = [];
|
|
@@ -1041,12 +1837,21 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1041
1837
|
const updatedHistoryEvents = [...historyEvents, ...toolResultEvents];
|
|
1042
1838
|
|
|
1043
1839
|
// Make follow-up AI call to see if more tools are needed
|
|
1840
|
+
// After first iteration, don't provide tools to force a text response
|
|
1044
1841
|
const agentOptions = this.agent.getAgentOptions();
|
|
1842
|
+
const shouldProvideTools = toolLoopCount === 1;
|
|
1843
|
+
|
|
1844
|
+
logger.debug(`[ResponseModal] Making follow-up AI call (loop ${toolLoopCount}):`, {
|
|
1845
|
+
providingTools: shouldProvideTools,
|
|
1846
|
+
toolsCount: shouldProvideTools ? availableTools.length : 0,
|
|
1847
|
+
addingTextInstruction: toolLoopCount > 1,
|
|
1848
|
+
});
|
|
1849
|
+
|
|
1045
1850
|
const followUpResult = await agentOptions.provider.generateMessage({
|
|
1046
|
-
prompt: responsePrompt,
|
|
1851
|
+
prompt: responsePrompt + (toolLoopCount > 1 ? "\n\nProvide a text response to the user based on the tool results." : ""),
|
|
1047
1852
|
history: updatedHistoryEvents, // Use Event[] for AI provider
|
|
1048
1853
|
context,
|
|
1049
|
-
tools: availableTools,
|
|
1854
|
+
tools: shouldProvideTools ? availableTools : [], // Only provide tools on first iteration
|
|
1050
1855
|
parameters: responseSchema ? {
|
|
1051
1856
|
jsonSchema: responseSchema,
|
|
1052
1857
|
schemaName: "tool_followup",
|
|
@@ -1058,6 +1863,14 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1058
1863
|
const followUpToolCalls = followUpResult.structured?.toolCalls;
|
|
1059
1864
|
hasToolCalls = followUpToolCalls && followUpToolCalls.length > 0;
|
|
1060
1865
|
|
|
1866
|
+
logger.debug(`[ResponseModal] Follow-up AI response (loop ${toolLoopCount}):`, {
|
|
1867
|
+
hasMessage: !!followUpResult.message,
|
|
1868
|
+
messageLength: followUpResult.message?.length || 0,
|
|
1869
|
+
hasToolCalls,
|
|
1870
|
+
toolCallsCount: followUpToolCalls?.length || 0,
|
|
1871
|
+
toolNames: followUpToolCalls?.map(tc => tc.toolName) || [],
|
|
1872
|
+
});
|
|
1873
|
+
|
|
1061
1874
|
if (hasToolCalls) {
|
|
1062
1875
|
logger.debug(`[ResponseModal] Follow-up call produced ${followUpToolCalls!.length} additional tool calls`);
|
|
1063
1876
|
|
|
@@ -1136,6 +1949,13 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1136
1949
|
logger.warn(`[ResponseModal] Tool loop limit reached (${MAX_TOOL_LOOPS}), stopping`);
|
|
1137
1950
|
}
|
|
1138
1951
|
|
|
1952
|
+
logger.debug(`[ResponseModal] Tool loop completed:`, {
|
|
1953
|
+
totalIterations: toolLoopCount,
|
|
1954
|
+
hasFinalMessage: !!finalMessage,
|
|
1955
|
+
finalMessageLength: finalMessage?.length || 0,
|
|
1956
|
+
finalToolCallsCount: toolCalls?.length || 0,
|
|
1957
|
+
});
|
|
1958
|
+
|
|
1139
1959
|
return {
|
|
1140
1960
|
session,
|
|
1141
1961
|
finalToolCalls: toolCalls,
|
|
@@ -1162,15 +1982,34 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1162
1982
|
let updatedSession = session;
|
|
1163
1983
|
|
|
1164
1984
|
// Extract collected data from final response (only for route-based interactions)
|
|
1165
|
-
if (selectedRoute && result.structured
|
|
1985
|
+
if (selectedRoute && result.structured) {
|
|
1166
1986
|
try {
|
|
1167
1987
|
const collectedData: Record<string, unknown> = {};
|
|
1168
1988
|
// AgentStructuredResponse extends Record<string, unknown>, so we can safely access properties
|
|
1169
1989
|
const structuredData = result.structured;
|
|
1170
1990
|
|
|
1171
|
-
|
|
1991
|
+
// Collect ALL route fields (required + optional) from structured response
|
|
1992
|
+
const allRouteFields = new Set<string>();
|
|
1993
|
+
|
|
1994
|
+
// Add route required fields
|
|
1995
|
+
if (selectedRoute.requiredFields) {
|
|
1996
|
+
selectedRoute.requiredFields.forEach(field => allRouteFields.add(String(field)));
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
// Add route optional fields
|
|
2000
|
+
if (selectedRoute.optionalFields) {
|
|
2001
|
+
selectedRoute.optionalFields.forEach(field => allRouteFields.add(String(field)));
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
// Also include current step's collect fields (in case they're not in route fields)
|
|
2005
|
+
if (nextStep?.collect) {
|
|
2006
|
+
nextStep.collect.forEach(field => allRouteFields.add(String(field)));
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
// Extract all available fields from structured response
|
|
2010
|
+
for (const field of allRouteFields) {
|
|
1172
2011
|
const fieldKey = String(field);
|
|
1173
|
-
if (fieldKey in structuredData) {
|
|
2012
|
+
if (fieldKey in structuredData && structuredData[fieldKey] !== undefined && structuredData[fieldKey] !== null) {
|
|
1174
2013
|
collectedData[fieldKey] = structuredData[fieldKey];
|
|
1175
2014
|
}
|
|
1176
2015
|
}
|
|
@@ -1244,37 +2083,66 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1244
2083
|
prompt: endStepSpec.prompt || "Summarize what was accomplished and confirm completion based on the conversation history and collected data",
|
|
1245
2084
|
});
|
|
1246
2085
|
|
|
1247
|
-
// Build response schema for completion
|
|
1248
|
-
const
|
|
1249
|
-
|
|
2086
|
+
// Build response schema for completion (message only, no data collection)
|
|
2087
|
+
const completionSchema = {
|
|
2088
|
+
type: "object",
|
|
2089
|
+
properties: {
|
|
2090
|
+
message: {
|
|
2091
|
+
type: "string",
|
|
2092
|
+
description: "Completion message confirming what was accomplished",
|
|
2093
|
+
},
|
|
2094
|
+
},
|
|
2095
|
+
required: ["message"],
|
|
2096
|
+
additionalProperties: false,
|
|
2097
|
+
};
|
|
2098
|
+
|
|
2099
|
+
const templateContext = createTemplateContext({ context, session, history: historyEvents });
|
|
2100
|
+
|
|
2101
|
+
// Build completion response prompt using ResponseEngine
|
|
2102
|
+
// Filter out conditional guidelines - only include always-active ones
|
|
2103
|
+
const alwaysActiveGuidelines = [
|
|
2104
|
+
...this.agent.getGuidelines().filter(g => !g.condition),
|
|
2105
|
+
...selectedRoute.getGuidelines().filter(g => !g.condition),
|
|
2106
|
+
];
|
|
2107
|
+
let completitionPrompt = "Summarize what was accomplished and confirm completion"
|
|
2108
|
+
if(endStepSpec.prompt){
|
|
2109
|
+
completitionPrompt = await render(endStepSpec.prompt, templateContext)
|
|
2110
|
+
}
|
|
1250
2111
|
|
|
1251
|
-
// Build completion response prompt
|
|
1252
2112
|
const completionPrompt = await this.responseEngine.buildResponsePrompt({
|
|
1253
2113
|
route: selectedRoute,
|
|
1254
2114
|
currentStep: completionStep,
|
|
1255
2115
|
rules: selectedRoute.getRules(),
|
|
1256
2116
|
prohibitions: selectedRoute.getProhibitions(),
|
|
1257
|
-
directives:
|
|
1258
|
-
|
|
1259
|
-
|
|
2117
|
+
directives: [
|
|
2118
|
+
`Task completed: ${selectedRoute.title}`,
|
|
2119
|
+
`Collected data: ${JSON.stringify(session.data, null, 2)}`,
|
|
2120
|
+
"Do NOT ask for more information - the task is complete",
|
|
2121
|
+
completitionPrompt,
|
|
2122
|
+
],
|
|
2123
|
+
history: historyEvents,
|
|
2124
|
+
lastMessage: lastMessageText,
|
|
1260
2125
|
agentOptions: this.agent.getAgentOptions(),
|
|
1261
|
-
combinedGuidelines:
|
|
2126
|
+
combinedGuidelines: alwaysActiveGuidelines, // Only non-conditional guidelines
|
|
1262
2127
|
combinedTerms: this.mergeTerms(this.agent.getTerms(), selectedRoute.getTerms()),
|
|
1263
2128
|
context,
|
|
1264
2129
|
session,
|
|
1265
|
-
agentSchema:
|
|
2130
|
+
agentSchema: undefined, // No data collection schema for completion
|
|
1266
2131
|
});
|
|
1267
2132
|
|
|
1268
2133
|
// Generate completion message using AI provider
|
|
1269
2134
|
const agentOptions = this.agent.getAgentOptions();
|
|
2135
|
+
logger.debug(`[ResponseModal] Calling AI provider for completion message...`);
|
|
2136
|
+
|
|
1270
2137
|
const completionResult = await agentOptions.provider.generateMessage({
|
|
1271
2138
|
prompt: completionPrompt,
|
|
1272
|
-
history: historyEvents,
|
|
2139
|
+
history: historyEvents,
|
|
1273
2140
|
context,
|
|
1274
2141
|
signal,
|
|
1275
|
-
parameters: { jsonSchema:
|
|
2142
|
+
parameters: { jsonSchema: completionSchema, schemaName: "completion_message" },
|
|
1276
2143
|
});
|
|
1277
2144
|
|
|
2145
|
+
logger.debug(`[ResponseModal] AI provider returned completion result`);
|
|
1278
2146
|
const message = completionResult.structured?.message || completionResult.message;
|
|
1279
2147
|
logger.debug(`[ResponseModal] Generated completion message for route: ${selectedRoute.title}`);
|
|
1280
2148
|
|
|
@@ -1333,7 +2201,7 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1333
2201
|
|
|
1334
2202
|
// Build response schema for completion
|
|
1335
2203
|
const responseSchema = this.responseEngine.responseSchemaForRoute(selectedRoute, completionStep, this.agent.getSchema());
|
|
1336
|
-
const templateContext = { context, session, history: historyEvents }; // Use Event[] for template context
|
|
2204
|
+
const templateContext = createTemplateContext({ context, session, history: historyEvents }); // Use Event[] for template context
|
|
1337
2205
|
|
|
1338
2206
|
// Build completion response prompt
|
|
1339
2207
|
const completionPrompt = await this.responseEngine.buildResponsePrompt({
|
|
@@ -1401,6 +2269,10 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1401
2269
|
await this.finalizeSession(session, context);
|
|
1402
2270
|
}
|
|
1403
2271
|
|
|
2272
|
+
// Response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
2273
|
+
// - executedSteps: empty for route completion (no new steps executed)
|
|
2274
|
+
// - stoppedReason: 'route_complete' for completed routes
|
|
2275
|
+
// - session.currentStep: set to END_ROUTE
|
|
1404
2276
|
yield {
|
|
1405
2277
|
delta: chunk.delta,
|
|
1406
2278
|
accumulated: chunk.accumulated,
|
|
@@ -1408,6 +2280,8 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1408
2280
|
session,
|
|
1409
2281
|
toolCalls: undefined,
|
|
1410
2282
|
isRouteComplete: true,
|
|
2283
|
+
executedSteps: chunk.done ? [] : undefined,
|
|
2284
|
+
stoppedReason: chunk.done ? 'route_complete' : undefined,
|
|
1411
2285
|
metadata: chunk.metadata,
|
|
1412
2286
|
structured: chunk.structured,
|
|
1413
2287
|
};
|
|
@@ -1502,6 +2376,10 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1502
2376
|
await this.finalizeSession(session, context);
|
|
1503
2377
|
}
|
|
1504
2378
|
|
|
2379
|
+
// Response structure completeness (Requirement 8.1, 8.2, 8.3)
|
|
2380
|
+
// - executedSteps: empty for fallback (no route/step execution)
|
|
2381
|
+
// - stoppedReason: undefined for fallback (no route context)
|
|
2382
|
+
// - session.currentStep: unchanged (no step progression)
|
|
1505
2383
|
yield {
|
|
1506
2384
|
delta: chunk.delta,
|
|
1507
2385
|
accumulated: chunk.accumulated,
|
|
@@ -1509,6 +2387,8 @@ export class ResponseModal<TContext = unknown, TData = unknown> {
|
|
|
1509
2387
|
session,
|
|
1510
2388
|
toolCalls: undefined,
|
|
1511
2389
|
isRouteComplete: false,
|
|
2390
|
+
executedSteps: chunk.done ? [] : undefined,
|
|
2391
|
+
stoppedReason: undefined,
|
|
1512
2392
|
metadata: chunk.metadata,
|
|
1513
2393
|
structured: chunk.structured,
|
|
1514
2394
|
};
|