@falai/agent 0.8.0 → 0.9.0-alpha-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 +306 -133
- package/dist/{adapters → cjs/src/adapters}/MemoryAdapter.d.ts +4 -4
- package/dist/cjs/src/adapters/MemoryAdapter.d.ts.map +1 -0
- package/dist/cjs/{adapters → src/adapters}/MemoryAdapter.js +41 -21
- package/dist/cjs/src/adapters/MemoryAdapter.js.map +1 -0
- package/dist/{adapters → cjs/src/adapters}/MongoAdapter.d.ts +3 -3
- package/dist/cjs/src/adapters/MongoAdapter.d.ts.map +1 -0
- package/dist/cjs/{adapters → src/adapters}/MongoAdapter.js +2 -1
- package/dist/cjs/src/adapters/MongoAdapter.js.map +1 -0
- package/dist/cjs/{adapters → src/adapters}/OpenSearchAdapter.d.ts +3 -3
- package/dist/cjs/src/adapters/OpenSearchAdapter.d.ts.map +1 -0
- package/dist/cjs/{adapters → src/adapters}/OpenSearchAdapter.js +10 -13
- package/dist/cjs/src/adapters/OpenSearchAdapter.js.map +1 -0
- package/dist/cjs/{adapters → src/adapters}/PostgreSQLAdapter.d.ts +3 -3
- package/dist/cjs/src/adapters/PostgreSQLAdapter.d.ts.map +1 -0
- package/dist/cjs/{adapters → src/adapters}/PostgreSQLAdapter.js +1 -1
- package/dist/cjs/src/adapters/PostgreSQLAdapter.js.map +1 -0
- package/dist/cjs/{adapters → src/adapters}/PrismaAdapter.d.ts +3 -3
- package/dist/cjs/src/adapters/PrismaAdapter.d.ts.map +1 -0
- package/dist/cjs/{adapters → src/adapters}/PrismaAdapter.js +35 -5
- package/dist/cjs/src/adapters/PrismaAdapter.js.map +1 -0
- package/dist/cjs/{adapters → src/adapters}/RedisAdapter.d.ts +3 -3
- package/dist/cjs/src/adapters/RedisAdapter.d.ts.map +1 -0
- package/dist/cjs/{adapters → src/adapters}/RedisAdapter.js +3 -2
- package/dist/cjs/src/adapters/RedisAdapter.js.map +1 -0
- package/dist/{adapters → cjs/src/adapters}/SQLiteAdapter.d.ts +3 -3
- package/dist/cjs/src/adapters/SQLiteAdapter.d.ts.map +1 -0
- package/dist/cjs/{adapters → src/adapters}/SQLiteAdapter.js +2 -1
- package/dist/cjs/src/adapters/SQLiteAdapter.js.map +1 -0
- package/dist/cjs/src/adapters/index.d.ts.map +1 -0
- package/dist/cjs/src/adapters/index.js.map +1 -0
- package/dist/cjs/src/constants/index.d.ts.map +1 -0
- package/dist/cjs/src/constants/index.js.map +1 -0
- package/dist/{core → cjs/src/core}/Agent.d.ts +67 -69
- package/dist/cjs/src/core/Agent.d.ts.map +1 -0
- package/dist/cjs/src/core/Agent.js +1433 -0
- package/dist/cjs/src/core/Agent.js.map +1 -0
- package/dist/cjs/src/core/Events.d.ts +26 -0
- package/dist/cjs/src/core/Events.d.ts.map +1 -0
- package/dist/cjs/src/core/Events.js +144 -0
- package/dist/cjs/src/core/Events.js.map +1 -0
- package/dist/cjs/src/core/PersistenceManager.d.ts +98 -0
- package/dist/cjs/src/core/PersistenceManager.d.ts.map +1 -0
- package/dist/cjs/{core → src/core}/PersistenceManager.js +62 -32
- package/dist/cjs/src/core/PersistenceManager.js.map +1 -0
- package/dist/cjs/src/core/PromptComposer.d.ts +27 -0
- package/dist/cjs/src/core/PromptComposer.d.ts.map +1 -0
- package/dist/cjs/src/core/PromptComposer.js +157 -0
- package/dist/cjs/src/core/PromptComposer.js.map +1 -0
- package/dist/cjs/src/core/ResponseEngine.d.ts +31 -0
- package/dist/cjs/src/core/ResponseEngine.d.ts.map +1 -0
- package/dist/cjs/src/core/ResponseEngine.js +84 -0
- package/dist/cjs/src/core/ResponseEngine.js.map +1 -0
- package/dist/cjs/src/core/ResponsePipeline.d.ts +143 -0
- package/dist/cjs/src/core/ResponsePipeline.d.ts.map +1 -0
- package/dist/cjs/src/core/ResponsePipeline.js +446 -0
- package/dist/cjs/src/core/ResponsePipeline.js.map +1 -0
- package/dist/cjs/src/core/Route.d.ts +126 -0
- package/dist/cjs/src/core/Route.d.ts.map +1 -0
- package/dist/cjs/{core → src/core}/Route.js +116 -20
- package/dist/cjs/src/core/Route.js.map +1 -0
- package/dist/{core → cjs/src/core}/RoutingEngine.d.ts +33 -38
- package/dist/cjs/src/core/RoutingEngine.d.ts.map +1 -0
- package/dist/cjs/{core → src/core}/RoutingEngine.js +102 -108
- package/dist/cjs/src/core/RoutingEngine.js.map +1 -0
- package/dist/cjs/src/core/SessionManager.d.ts +76 -0
- package/dist/cjs/src/core/SessionManager.d.ts.map +1 -0
- package/dist/cjs/src/core/SessionManager.js +197 -0
- package/dist/cjs/src/core/SessionManager.js.map +1 -0
- package/dist/cjs/src/core/Step.d.ts +96 -0
- package/dist/cjs/src/core/Step.d.ts.map +1 -0
- package/dist/cjs/src/core/Step.js +206 -0
- package/dist/cjs/src/core/Step.js.map +1 -0
- package/dist/cjs/src/core/ToolExecutor.d.ts +43 -0
- package/dist/cjs/src/core/ToolExecutor.d.ts.map +1 -0
- package/dist/cjs/{core → src/core}/ToolExecutor.js +19 -18
- package/dist/cjs/src/core/ToolExecutor.js.map +1 -0
- package/dist/{index.d.ts → cjs/src/index.d.ts} +7 -15
- package/dist/cjs/src/index.d.ts.map +1 -0
- package/dist/cjs/{index.js → src/index.js} +21 -19
- package/dist/cjs/src/index.js.map +1 -0
- package/dist/cjs/{providers → src/providers}/AnthropicProvider.d.ts +1 -1
- package/dist/cjs/src/providers/AnthropicProvider.d.ts.map +1 -0
- package/dist/cjs/{providers → src/providers}/AnthropicProvider.js +54 -2
- package/dist/cjs/src/providers/AnthropicProvider.js.map +1 -0
- package/dist/{providers → cjs/src/providers}/GeminiProvider.d.ts +1 -1
- package/dist/cjs/src/providers/GeminiProvider.d.ts.map +1 -0
- package/dist/cjs/{providers → src/providers}/GeminiProvider.js +65 -0
- package/dist/cjs/src/providers/GeminiProvider.js.map +1 -0
- package/dist/cjs/{providers → src/providers}/OpenAIProvider.d.ts +1 -1
- package/dist/cjs/src/providers/OpenAIProvider.d.ts.map +1 -0
- package/dist/cjs/{providers → src/providers}/OpenAIProvider.js +70 -1
- package/dist/cjs/src/providers/OpenAIProvider.js.map +1 -0
- package/dist/{providers → cjs/src/providers}/OpenRouterProvider.d.ts +1 -1
- package/dist/cjs/src/providers/OpenRouterProvider.d.ts.map +1 -0
- package/dist/cjs/{providers → src/providers}/OpenRouterProvider.js +76 -0
- package/dist/cjs/src/providers/OpenRouterProvider.js.map +1 -0
- package/dist/cjs/src/providers/index.d.ts.map +1 -0
- package/dist/cjs/src/providers/index.js.map +1 -0
- package/dist/cjs/{types → src/types}/agent.d.ts +54 -35
- package/dist/cjs/src/types/agent.d.ts.map +1 -0
- package/dist/cjs/src/types/agent.js.map +1 -0
- package/dist/cjs/{types → src/types}/ai.d.ts +7 -0
- package/dist/cjs/src/types/ai.d.ts.map +1 -0
- package/dist/cjs/src/types/ai.js.map +1 -0
- package/dist/{types → cjs/src/types}/history.d.ts +76 -18
- package/dist/cjs/src/types/history.d.ts.map +1 -0
- package/dist/cjs/src/types/history.js +33 -0
- package/dist/cjs/src/types/history.js.map +1 -0
- package/dist/cjs/src/types/index.d.ts +20 -0
- package/dist/cjs/src/types/index.d.ts.map +1 -0
- package/dist/cjs/src/types/index.js +30 -0
- package/dist/cjs/src/types/index.js.map +1 -0
- package/dist/{types → cjs/src/types}/persistence.d.ts +39 -23
- package/dist/cjs/src/types/persistence.d.ts.map +1 -0
- package/dist/cjs/src/types/persistence.js.map +1 -0
- package/dist/cjs/{types → src/types}/route.d.ts +85 -31
- package/dist/cjs/src/types/route.d.ts.map +1 -0
- package/dist/cjs/{types → src/types}/route.js.map +1 -1
- package/dist/cjs/src/types/routing.d.ts.map +1 -0
- package/dist/{types → cjs/src/types}/routing.js.map +1 -1
- package/dist/cjs/src/types/schema.d.ts.map +1 -0
- package/dist/{types → cjs/src/types}/schema.js.map +1 -1
- package/dist/cjs/src/types/session.d.ts +70 -0
- package/dist/cjs/src/types/session.d.ts.map +1 -0
- package/dist/cjs/src/types/session.js +6 -0
- package/dist/cjs/src/types/session.js.map +1 -0
- package/dist/cjs/src/types/template.d.ts +30 -0
- package/dist/cjs/src/types/template.d.ts.map +1 -0
- package/dist/cjs/src/types/template.js +3 -0
- package/dist/cjs/src/types/template.js.map +1 -0
- package/dist/cjs/{types → src/types}/tool.d.ts +6 -8
- package/dist/cjs/src/types/tool.d.ts.map +1 -0
- package/dist/cjs/{types → src/types}/tool.js.map +1 -1
- package/dist/cjs/src/utils/clone.d.ts +8 -0
- package/dist/cjs/src/utils/clone.d.ts.map +1 -0
- package/dist/cjs/src/utils/clone.js +36 -0
- package/dist/cjs/src/utils/clone.js.map +1 -0
- package/dist/{utils → cjs/src/utils}/event.d.ts +1 -1
- package/dist/cjs/src/utils/event.d.ts.map +1 -0
- package/dist/cjs/{utils → src/utils}/event.js +2 -2
- package/dist/cjs/src/utils/event.js.map +1 -0
- package/dist/cjs/src/utils/history.d.ts +31 -0
- package/dist/cjs/src/utils/history.d.ts.map +1 -0
- package/dist/cjs/src/utils/history.js +128 -0
- package/dist/cjs/src/utils/history.js.map +1 -0
- package/dist/cjs/src/utils/id.d.ts.map +1 -0
- package/dist/cjs/src/utils/id.js.map +1 -0
- package/dist/cjs/src/utils/index.d.ts +13 -0
- package/dist/cjs/src/utils/index.d.ts.map +1 -0
- package/dist/cjs/src/utils/index.js +49 -0
- package/dist/cjs/src/utils/index.js.map +1 -0
- package/dist/cjs/src/utils/logger.d.ts.map +1 -0
- package/dist/cjs/src/utils/logger.js.map +1 -0
- package/dist/cjs/src/utils/retry.d.ts.map +1 -0
- package/dist/cjs/src/utils/retry.js.map +1 -0
- package/dist/cjs/src/utils/session.d.ts +51 -0
- package/dist/cjs/src/utils/session.d.ts.map +1 -0
- package/dist/cjs/{types → src/utils}/session.js +36 -13
- package/dist/cjs/src/utils/session.js.map +1 -0
- package/dist/cjs/src/utils/template.d.ts +107 -0
- package/dist/cjs/src/utils/template.d.ts.map +1 -0
- package/dist/cjs/src/utils/template.js +283 -0
- package/dist/cjs/src/utils/template.js.map +1 -0
- package/dist/{cjs → src}/adapters/MemoryAdapter.d.ts +4 -4
- package/dist/src/adapters/MemoryAdapter.d.ts.map +1 -0
- package/dist/{adapters → src/adapters}/MemoryAdapter.js +41 -21
- package/dist/src/adapters/MemoryAdapter.js.map +1 -0
- package/dist/{cjs → src}/adapters/MongoAdapter.d.ts +3 -3
- package/dist/src/adapters/MongoAdapter.d.ts.map +1 -0
- package/dist/{adapters → src/adapters}/MongoAdapter.js +2 -1
- package/dist/src/adapters/MongoAdapter.js.map +1 -0
- package/dist/{adapters → src/adapters}/OpenSearchAdapter.d.ts +3 -3
- package/dist/src/adapters/OpenSearchAdapter.d.ts.map +1 -0
- package/dist/{adapters → src/adapters}/OpenSearchAdapter.js +10 -13
- package/dist/src/adapters/OpenSearchAdapter.js.map +1 -0
- package/dist/{adapters → src/adapters}/PostgreSQLAdapter.d.ts +3 -3
- package/dist/src/adapters/PostgreSQLAdapter.d.ts.map +1 -0
- package/dist/{adapters → src/adapters}/PostgreSQLAdapter.js +1 -1
- package/dist/src/adapters/PostgreSQLAdapter.js.map +1 -0
- package/dist/{adapters → src/adapters}/PrismaAdapter.d.ts +3 -3
- package/dist/src/adapters/PrismaAdapter.d.ts.map +1 -0
- package/dist/{adapters → src/adapters}/PrismaAdapter.js +35 -5
- package/dist/src/adapters/PrismaAdapter.js.map +1 -0
- package/dist/{adapters → src/adapters}/RedisAdapter.d.ts +3 -3
- package/dist/src/adapters/RedisAdapter.d.ts.map +1 -0
- package/dist/{adapters → src/adapters}/RedisAdapter.js +3 -2
- package/dist/src/adapters/RedisAdapter.js.map +1 -0
- package/dist/{cjs → src}/adapters/SQLiteAdapter.d.ts +3 -3
- package/dist/src/adapters/SQLiteAdapter.d.ts.map +1 -0
- package/dist/{adapters → src/adapters}/SQLiteAdapter.js +2 -1
- package/dist/src/adapters/SQLiteAdapter.js.map +1 -0
- package/dist/src/adapters/index.js.map +1 -0
- package/dist/src/constants/index.js.map +1 -0
- package/dist/{cjs → src}/core/Agent.d.ts +67 -69
- package/dist/src/core/Agent.d.ts.map +1 -0
- package/dist/src/core/Agent.js +1429 -0
- package/dist/src/core/Agent.js.map +1 -0
- package/dist/src/core/Events.d.ts +26 -0
- package/dist/src/core/Events.d.ts.map +1 -0
- package/dist/src/core/Events.js +137 -0
- package/dist/src/core/Events.js.map +1 -0
- package/dist/src/core/PersistenceManager.d.ts +98 -0
- package/dist/src/core/PersistenceManager.d.ts.map +1 -0
- package/dist/{core → src/core}/PersistenceManager.js +56 -26
- package/dist/src/core/PersistenceManager.js.map +1 -0
- package/dist/src/core/PromptComposer.d.ts +27 -0
- package/dist/src/core/PromptComposer.d.ts.map +1 -0
- package/dist/src/core/PromptComposer.js +153 -0
- package/dist/src/core/PromptComposer.js.map +1 -0
- package/dist/src/core/ResponseEngine.d.ts +31 -0
- package/dist/src/core/ResponseEngine.d.ts.map +1 -0
- package/dist/src/core/ResponseEngine.js +80 -0
- package/dist/src/core/ResponseEngine.js.map +1 -0
- package/dist/src/core/ResponsePipeline.d.ts +143 -0
- package/dist/src/core/ResponsePipeline.d.ts.map +1 -0
- package/dist/src/core/ResponsePipeline.js +442 -0
- package/dist/src/core/ResponsePipeline.js.map +1 -0
- package/dist/src/core/Route.d.ts +126 -0
- package/dist/src/core/Route.d.ts.map +1 -0
- package/dist/{core → src/core}/Route.js +116 -20
- package/dist/src/core/Route.js.map +1 -0
- package/dist/{cjs → src}/core/RoutingEngine.d.ts +33 -38
- package/dist/src/core/RoutingEngine.d.ts.map +1 -0
- package/dist/{core → src/core}/RoutingEngine.js +98 -104
- package/dist/src/core/RoutingEngine.js.map +1 -0
- package/dist/src/core/SessionManager.d.ts +76 -0
- package/dist/src/core/SessionManager.d.ts.map +1 -0
- package/dist/src/core/SessionManager.js +193 -0
- package/dist/src/core/SessionManager.js.map +1 -0
- package/dist/src/core/Step.d.ts +96 -0
- package/dist/src/core/Step.d.ts.map +1 -0
- package/dist/src/core/Step.js +202 -0
- package/dist/src/core/Step.js.map +1 -0
- package/dist/src/core/ToolExecutor.d.ts +43 -0
- package/dist/src/core/ToolExecutor.d.ts.map +1 -0
- package/dist/src/core/ToolExecutor.js +70 -0
- package/dist/src/core/ToolExecutor.js.map +1 -0
- package/dist/{cjs → src}/index.d.ts +7 -15
- package/dist/src/index.d.ts.map +1 -0
- package/dist/{index.js → src/index.js} +6 -7
- package/dist/src/index.js.map +1 -0
- package/dist/{providers → src/providers}/AnthropicProvider.d.ts +1 -1
- package/dist/src/providers/AnthropicProvider.d.ts.map +1 -0
- package/dist/{providers → src/providers}/AnthropicProvider.js +54 -2
- package/dist/src/providers/AnthropicProvider.js.map +1 -0
- package/dist/{cjs → src}/providers/GeminiProvider.d.ts +1 -1
- package/dist/{cjs → src}/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/{providers → src/providers}/GeminiProvider.js +65 -0
- package/dist/src/providers/GeminiProvider.js.map +1 -0
- package/dist/{providers → src/providers}/OpenAIProvider.d.ts +1 -1
- package/dist/{cjs → src}/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/{providers → src/providers}/OpenAIProvider.js +70 -1
- package/dist/src/providers/OpenAIProvider.js.map +1 -0
- package/dist/{cjs → src}/providers/OpenRouterProvider.d.ts +1 -1
- package/dist/{cjs → src}/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/{providers → src/providers}/OpenRouterProvider.js +76 -0
- package/dist/src/providers/OpenRouterProvider.js.map +1 -0
- package/dist/src/providers/index.js.map +1 -0
- package/dist/{types → src/types}/agent.d.ts +54 -35
- package/dist/src/types/agent.d.ts.map +1 -0
- package/dist/src/types/agent.js.map +1 -0
- package/dist/{types → src/types}/ai.d.ts +7 -0
- package/dist/src/types/ai.d.ts.map +1 -0
- package/dist/{cjs → src}/types/ai.js.map +1 -1
- package/dist/{cjs → src}/types/history.d.ts +76 -18
- package/dist/src/types/history.d.ts.map +1 -0
- package/dist/src/types/history.js +30 -0
- package/dist/src/types/history.js.map +1 -0
- package/dist/src/types/index.d.ts +20 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +10 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/{cjs → src}/types/persistence.d.ts +39 -23
- package/dist/src/types/persistence.d.ts.map +1 -0
- package/dist/src/types/persistence.js.map +1 -0
- package/dist/{types → src/types}/route.d.ts +85 -31
- package/dist/src/types/route.d.ts.map +1 -0
- package/dist/{types → src/types}/route.js.map +1 -1
- package/dist/src/types/session.d.ts +70 -0
- package/dist/src/types/session.d.ts.map +1 -0
- package/dist/src/types/session.js +5 -0
- package/dist/src/types/session.js.map +1 -0
- package/dist/src/types/template.d.ts +30 -0
- package/dist/src/types/template.d.ts.map +1 -0
- package/dist/src/types/template.js +2 -0
- package/dist/src/types/template.js.map +1 -0
- package/dist/{types → src/types}/tool.d.ts +6 -8
- package/dist/{cjs → src}/types/tool.d.ts.map +1 -1
- package/dist/{types → src/types}/tool.js.map +1 -1
- package/dist/src/utils/clone.d.ts +8 -0
- package/dist/src/utils/clone.d.ts.map +1 -0
- package/dist/src/utils/clone.js +33 -0
- package/dist/src/utils/clone.js.map +1 -0
- package/dist/{cjs → src}/utils/event.d.ts +1 -1
- package/dist/{cjs → src}/utils/event.d.ts.map +1 -1
- package/dist/{utils → src/utils}/event.js +1 -1
- package/dist/src/utils/event.js.map +1 -0
- package/dist/src/utils/history.d.ts +31 -0
- package/dist/src/utils/history.d.ts.map +1 -0
- package/dist/src/utils/history.js +121 -0
- package/dist/src/utils/history.js.map +1 -0
- package/dist/src/utils/id.js.map +1 -0
- package/dist/src/utils/index.d.ts +13 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +19 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/retry.js.map +1 -0
- package/dist/src/utils/session.d.ts +51 -0
- package/dist/src/utils/session.d.ts.map +1 -0
- package/dist/{types → src/utils}/session.js +34 -13
- package/dist/src/utils/session.js.map +1 -0
- package/dist/src/utils/template.d.ts +107 -0
- package/dist/src/utils/template.d.ts.map +1 -0
- package/dist/src/utils/template.js +276 -0
- package/dist/src/utils/template.js.map +1 -0
- package/docs/README.md +174 -68
- package/docs/{API_REFERENCE.md → api/README.md} +902 -263
- package/docs/api/overview.md +798 -0
- package/docs/core/agent/README.md +642 -0
- package/docs/{CONTEXT_MANAGEMENT.md → core/agent/context-management.md} +144 -95
- package/docs/{ARCHITECTURE.md → core/agent/session-management.md} +74 -59
- package/docs/core/ai-integration/prompt-composition.md +196 -0
- package/docs/core/ai-integration/providers.md +515 -0
- package/docs/core/ai-integration/response-processing.md +165 -0
- package/docs/core/conversation-flows/data-collection.md +545 -0
- package/docs/core/conversation-flows/route-dsl.md +479 -0
- package/docs/core/conversation-flows/routes.md +61 -0
- package/docs/core/conversation-flows/step-transitions.md +595 -0
- package/docs/core/conversation-flows/steps.md +130 -0
- package/docs/{ADAPTERS.md → core/persistence/adapters.md} +2 -2
- package/docs/core/persistence/session-storage.md +644 -0
- package/docs/core/routing/intelligent-routing.md +339 -0
- package/docs/core/tools/tool-definition.md +346 -0
- package/docs/core/tools/tool-execution.md +815 -0
- package/docs/core/tools/tool-scoping.md +628 -0
- package/docs/guides/getting-started/README.md +384 -0
- package/examples/{company-qna-agent.ts → advanced-patterns/knowledge-based-agent.ts} +104 -69
- package/examples/{persistent-onboarding.ts → advanced-patterns/persistent-onboarding.ts} +181 -103
- package/examples/{rules-prohibitions.ts → advanced-patterns/route-lifecycle-hooks.ts} +102 -82
- package/examples/{streaming-agent.ts → advanced-patterns/streaming-responses.ts} +90 -69
- package/examples/ai-providers/anthropic-integration.ts +377 -0
- package/examples/{openai-agent.ts → ai-providers/openai-integration.ts} +37 -43
- package/examples/{route-transitions.ts → conversation-flows/completion-transitions.ts} +115 -108
- package/examples/{declarative-agent.ts → core-concepts/basic-agent.ts} +175 -131
- package/examples/core-concepts/schema-driven-extraction.ts +301 -0
- package/examples/core-concepts/session-management.ts +394 -0
- package/examples/integrations/database-integration.ts +615 -0
- package/examples/{healthcare-agent.ts → integrations/healthcare-integration.ts} +204 -111
- package/examples/{opensearch-persistence.ts → integrations/search-integration.ts} +159 -128
- package/examples/integrations/server-session-management.ts +299 -0
- package/examples/persistence/custom-adapter.ts +529 -0
- package/examples/{prisma-persistence.ts → persistence/database-persistence.ts} +168 -241
- package/examples/persistence/memory-sessions.ts +506 -0
- package/examples/{prisma-schema.example.prisma → persistence/prisma-schema.example.prisma} +1 -1
- package/examples/{redis-persistence.ts → persistence/redis-persistence.ts} +152 -173
- package/examples/tools/basic-tools.ts +550 -0
- package/examples/{extracted-data-modification.ts → tools/data-enrichment-tools.ts} +82 -79
- package/package.json +14 -10
- package/src/adapters/MemoryAdapter.ts +74 -46
- package/src/adapters/MongoAdapter.ts +33 -24
- package/src/adapters/OpenSearchAdapter.ts +41 -37
- package/src/adapters/PostgreSQLAdapter.ts +35 -24
- package/src/adapters/PrismaAdapter.ts +69 -27
- package/src/adapters/RedisAdapter.ts +38 -26
- package/src/adapters/SQLiteAdapter.ts +32 -22
- package/src/core/Agent.ts +1102 -487
- package/src/core/Events.ts +100 -112
- package/src/core/PersistenceManager.ts +87 -57
- package/src/core/PromptComposer.ts +158 -85
- package/src/core/ResponseEngine.ts +118 -38
- package/src/core/ResponsePipeline.ts +715 -0
- package/src/core/Route.ts +168 -51
- package/src/core/RoutingEngine.ts +178 -209
- package/src/core/SessionManager.ts +241 -0
- package/src/core/Step.ts +149 -67
- package/src/core/ToolExecutor.ts +37 -42
- package/src/index.ts +31 -37
- package/src/providers/AnthropicProvider.ts +71 -5
- package/src/providers/GeminiProvider.ts +83 -2
- package/src/providers/OpenAIProvider.ts +95 -3
- package/src/providers/OpenRouterProvider.ts +102 -2
- package/src/types/agent.ts +50 -38
- package/src/types/ai.ts +7 -0
- package/src/types/history.ts +91 -18
- package/src/types/index.ts +43 -7
- package/src/types/persistence.ts +46 -28
- package/src/types/route.ts +104 -45
- package/src/types/session.ts +19 -213
- package/src/types/template.ts +36 -0
- package/src/types/tool.ts +9 -11
- package/src/utils/clone.ts +36 -0
- package/src/utils/event.ts +1 -1
- package/src/utils/history.ts +143 -0
- package/src/utils/index.ts +53 -0
- package/src/utils/session.ts +229 -0
- package/src/utils/template.ts +335 -0
- package/dist/adapters/MemoryAdapter.d.ts.map +0 -1
- package/dist/adapters/MemoryAdapter.js.map +0 -1
- package/dist/adapters/MongoAdapter.d.ts.map +0 -1
- package/dist/adapters/MongoAdapter.js.map +0 -1
- package/dist/adapters/OpenSearchAdapter.d.ts.map +0 -1
- package/dist/adapters/OpenSearchAdapter.js.map +0 -1
- package/dist/adapters/PostgreSQLAdapter.d.ts.map +0 -1
- package/dist/adapters/PostgreSQLAdapter.js.map +0 -1
- package/dist/adapters/PrismaAdapter.d.ts.map +0 -1
- package/dist/adapters/PrismaAdapter.js.map +0 -1
- package/dist/adapters/RedisAdapter.d.ts.map +0 -1
- package/dist/adapters/RedisAdapter.js.map +0 -1
- package/dist/adapters/SQLiteAdapter.d.ts.map +0 -1
- package/dist/adapters/SQLiteAdapter.js.map +0 -1
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/adapters/index.js.map +0 -1
- package/dist/cjs/adapters/MemoryAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/MemoryAdapter.js.map +0 -1
- package/dist/cjs/adapters/MongoAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/MongoAdapter.js.map +0 -1
- package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/OpenSearchAdapter.js.map +0 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.js.map +0 -1
- package/dist/cjs/adapters/PrismaAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/PrismaAdapter.js.map +0 -1
- package/dist/cjs/adapters/RedisAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/RedisAdapter.js.map +0 -1
- package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +0 -1
- package/dist/cjs/adapters/SQLiteAdapter.js.map +0 -1
- package/dist/cjs/adapters/index.js.map +0 -1
- package/dist/cjs/constants/index.js.map +0 -1
- package/dist/cjs/core/Agent.d.ts.map +0 -1
- package/dist/cjs/core/Agent.js +0 -966
- package/dist/cjs/core/Agent.js.map +0 -1
- package/dist/cjs/core/DomainRegistry.d.ts +0 -36
- package/dist/cjs/core/DomainRegistry.d.ts.map +0 -1
- package/dist/cjs/core/DomainRegistry.js +0 -72
- package/dist/cjs/core/DomainRegistry.js.map +0 -1
- package/dist/cjs/core/Events.d.ts +0 -41
- package/dist/cjs/core/Events.d.ts.map +0 -1
- package/dist/cjs/core/Events.js +0 -99
- package/dist/cjs/core/Events.js.map +0 -1
- package/dist/cjs/core/PersistenceManager.d.ts +0 -96
- package/dist/cjs/core/PersistenceManager.d.ts.map +0 -1
- package/dist/cjs/core/PersistenceManager.js.map +0 -1
- package/dist/cjs/core/PromptComposer.d.ts +0 -24
- package/dist/cjs/core/PromptComposer.d.ts.map +0 -1
- package/dist/cjs/core/PromptComposer.js +0 -127
- package/dist/cjs/core/PromptComposer.js.map +0 -1
- package/dist/cjs/core/ResponseEngine.d.ts +0 -14
- package/dist/cjs/core/ResponseEngine.d.ts.map +0 -1
- package/dist/cjs/core/ResponseEngine.js +0 -56
- package/dist/cjs/core/ResponseEngine.js.map +0 -1
- package/dist/cjs/core/Route.d.ts +0 -90
- package/dist/cjs/core/Route.d.ts.map +0 -1
- package/dist/cjs/core/Route.js.map +0 -1
- package/dist/cjs/core/RoutingEngine.d.ts.map +0 -1
- package/dist/cjs/core/RoutingEngine.js.map +0 -1
- package/dist/cjs/core/Step.d.ts +0 -72
- package/dist/cjs/core/Step.d.ts.map +0 -1
- package/dist/cjs/core/Step.js +0 -150
- package/dist/cjs/core/Step.js.map +0 -1
- package/dist/cjs/core/Tool.d.ts +0 -39
- package/dist/cjs/core/Tool.d.ts.map +0 -1
- package/dist/cjs/core/Tool.js +0 -34
- package/dist/cjs/core/Tool.js.map +0 -1
- package/dist/cjs/core/ToolExecutor.d.ts +0 -29
- package/dist/cjs/core/ToolExecutor.d.ts.map +0 -1
- package/dist/cjs/core/ToolExecutor.js.map +0 -1
- package/dist/cjs/core/Transition.d.ts +0 -32
- package/dist/cjs/core/Transition.d.ts.map +0 -1
- package/dist/cjs/core/Transition.js +0 -89
- package/dist/cjs/core/Transition.js.map +0 -1
- package/dist/cjs/index.d.ts.map +0 -1
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/providers/AnthropicProvider.d.ts.map +0 -1
- package/dist/cjs/providers/AnthropicProvider.js.map +0 -1
- package/dist/cjs/providers/GeminiProvider.js.map +0 -1
- package/dist/cjs/providers/OpenAIProvider.js.map +0 -1
- package/dist/cjs/providers/OpenRouterProvider.js.map +0 -1
- package/dist/cjs/providers/index.js.map +0 -1
- package/dist/cjs/types/agent.d.ts.map +0 -1
- package/dist/cjs/types/agent.js.map +0 -1
- package/dist/cjs/types/ai.d.ts.map +0 -1
- package/dist/cjs/types/history.d.ts.map +0 -1
- package/dist/cjs/types/history.js +0 -37
- package/dist/cjs/types/history.js.map +0 -1
- package/dist/cjs/types/index.d.ts +0 -12
- package/dist/cjs/types/index.d.ts.map +0 -1
- package/dist/cjs/types/index.js +0 -12
- package/dist/cjs/types/index.js.map +0 -1
- package/dist/cjs/types/persistence.d.ts.map +0 -1
- package/dist/cjs/types/persistence.js.map +0 -1
- package/dist/cjs/types/route.d.ts.map +0 -1
- package/dist/cjs/types/session.d.ts +0 -104
- package/dist/cjs/types/session.d.ts.map +0 -1
- package/dist/cjs/types/session.js.map +0 -1
- package/dist/cjs/utils/event.js.map +0 -1
- package/dist/cjs/utils/id.js.map +0 -1
- package/dist/cjs/utils/logger.js.map +0 -1
- package/dist/cjs/utils/retry.js.map +0 -1
- package/dist/constants/index.d.ts.map +0 -1
- package/dist/constants/index.js.map +0 -1
- package/dist/core/Agent.d.ts.map +0 -1
- package/dist/core/Agent.js +0 -962
- package/dist/core/Agent.js.map +0 -1
- package/dist/core/DomainRegistry.d.ts +0 -36
- package/dist/core/DomainRegistry.d.ts.map +0 -1
- package/dist/core/DomainRegistry.js +0 -68
- package/dist/core/DomainRegistry.js.map +0 -1
- package/dist/core/Events.d.ts +0 -41
- package/dist/core/Events.d.ts.map +0 -1
- package/dist/core/Events.js +0 -94
- package/dist/core/Events.js.map +0 -1
- package/dist/core/PersistenceManager.d.ts +0 -96
- package/dist/core/PersistenceManager.d.ts.map +0 -1
- package/dist/core/PersistenceManager.js.map +0 -1
- package/dist/core/PromptComposer.d.ts +0 -24
- package/dist/core/PromptComposer.d.ts.map +0 -1
- package/dist/core/PromptComposer.js +0 -123
- package/dist/core/PromptComposer.js.map +0 -1
- package/dist/core/ResponseEngine.d.ts +0 -14
- package/dist/core/ResponseEngine.d.ts.map +0 -1
- package/dist/core/ResponseEngine.js +0 -52
- package/dist/core/ResponseEngine.js.map +0 -1
- package/dist/core/Route.d.ts +0 -90
- package/dist/core/Route.d.ts.map +0 -1
- package/dist/core/Route.js.map +0 -1
- package/dist/core/RoutingEngine.d.ts.map +0 -1
- package/dist/core/RoutingEngine.js.map +0 -1
- package/dist/core/Step.d.ts +0 -72
- package/dist/core/Step.d.ts.map +0 -1
- package/dist/core/Step.js +0 -146
- package/dist/core/Step.js.map +0 -1
- package/dist/core/Tool.d.ts +0 -39
- package/dist/core/Tool.d.ts.map +0 -1
- package/dist/core/Tool.js +0 -31
- package/dist/core/Tool.js.map +0 -1
- package/dist/core/ToolExecutor.d.ts +0 -29
- package/dist/core/ToolExecutor.d.ts.map +0 -1
- package/dist/core/ToolExecutor.js +0 -69
- package/dist/core/ToolExecutor.js.map +0 -1
- package/dist/core/Transition.d.ts +0 -32
- package/dist/core/Transition.d.ts.map +0 -1
- package/dist/core/Transition.js +0 -85
- package/dist/core/Transition.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers/AnthropicProvider.d.ts.map +0 -1
- package/dist/providers/AnthropicProvider.js.map +0 -1
- package/dist/providers/GeminiProvider.d.ts.map +0 -1
- package/dist/providers/GeminiProvider.js.map +0 -1
- package/dist/providers/OpenAIProvider.d.ts.map +0 -1
- package/dist/providers/OpenAIProvider.js.map +0 -1
- package/dist/providers/OpenRouterProvider.d.ts.map +0 -1
- package/dist/providers/OpenRouterProvider.js.map +0 -1
- package/dist/providers/index.d.ts.map +0 -1
- package/dist/providers/index.js.map +0 -1
- package/dist/types/agent.d.ts.map +0 -1
- package/dist/types/agent.js.map +0 -1
- package/dist/types/ai.d.ts.map +0 -1
- package/dist/types/ai.js.map +0 -1
- package/dist/types/history.d.ts.map +0 -1
- package/dist/types/history.js +0 -34
- package/dist/types/history.js.map +0 -1
- package/dist/types/index.d.ts +0 -12
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -6
- package/dist/types/index.js.map +0 -1
- package/dist/types/persistence.d.ts.map +0 -1
- package/dist/types/persistence.js.map +0 -1
- package/dist/types/route.d.ts.map +0 -1
- package/dist/types/routing.d.ts.map +0 -1
- package/dist/types/schema.d.ts.map +0 -1
- package/dist/types/session.d.ts +0 -104
- package/dist/types/session.d.ts.map +0 -1
- package/dist/types/session.js.map +0 -1
- package/dist/types/tool.d.ts.map +0 -1
- package/dist/utils/event.d.ts.map +0 -1
- package/dist/utils/event.js.map +0 -1
- package/dist/utils/id.d.ts.map +0 -1
- package/dist/utils/id.js.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/retry.d.ts.map +0 -1
- package/dist/utils/retry.js.map +0 -1
- package/docs/AGENT.md +0 -535
- package/docs/DOCS.md +0 -263
- package/docs/DOMAINS.md +0 -735
- package/docs/EXAMPLES.md +0 -467
- package/docs/GETTING_STARTED.md +0 -424
- package/docs/PERSISTENCE.md +0 -815
- package/docs/PROVIDERS.md +0 -612
- package/docs/ROUTES.md +0 -1085
- package/docs/STEPS.md +0 -883
- package/examples/business-onboarding.ts +0 -791
- package/examples/custom-database-persistence.ts +0 -574
- package/examples/domain-scoping.ts +0 -366
- package/examples/travel-agent.ts +0 -584
- package/src/core/DomainRegistry.ts +0 -80
- package/src/core/Tool.ts +0 -112
- package/src/core/Transition.ts +0 -115
- /package/dist/{adapters → cjs/src/adapters}/index.d.ts +0 -0
- /package/dist/cjs/{adapters → src/adapters}/index.js +0 -0
- /package/dist/cjs/{constants → src/constants}/index.d.ts +0 -0
- /package/dist/cjs/{constants → src/constants}/index.js +0 -0
- /package/dist/cjs/{providers → src/providers}/index.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/index.js +0 -0
- /package/dist/cjs/{types → src/types}/agent.js +0 -0
- /package/dist/cjs/{types → src/types}/ai.js +0 -0
- /package/dist/cjs/{types → src/types}/persistence.js +0 -0
- /package/dist/cjs/{types → src/types}/route.js +0 -0
- /package/dist/cjs/{types → src/types}/routing.d.ts +0 -0
- /package/dist/cjs/{types → src/types}/routing.js +0 -0
- /package/dist/cjs/{types → src/types}/schema.d.ts +0 -0
- /package/dist/cjs/{types → src/types}/schema.js +0 -0
- /package/dist/cjs/{types → src/types}/tool.js +0 -0
- /package/dist/cjs/{utils → src/utils}/id.d.ts +0 -0
- /package/dist/cjs/{utils → src/utils}/id.js +0 -0
- /package/dist/cjs/{utils → src/utils}/logger.d.ts +0 -0
- /package/dist/cjs/{utils → src/utils}/logger.js +0 -0
- /package/dist/cjs/{utils → src/utils}/retry.d.ts +0 -0
- /package/dist/cjs/{utils → src/utils}/retry.js +0 -0
- /package/dist/{cjs → src}/adapters/index.d.ts +0 -0
- /package/dist/{cjs → src}/adapters/index.d.ts.map +0 -0
- /package/dist/{adapters → src/adapters}/index.js +0 -0
- /package/dist/{constants → src/constants}/index.d.ts +0 -0
- /package/dist/{cjs → src}/constants/index.d.ts.map +0 -0
- /package/dist/{constants → src/constants}/index.js +0 -0
- /package/dist/{providers → src/providers}/index.d.ts +0 -0
- /package/dist/{cjs → src}/providers/index.d.ts.map +0 -0
- /package/dist/{providers → src/providers}/index.js +0 -0
- /package/dist/{types → src/types}/agent.js +0 -0
- /package/dist/{types → src/types}/ai.js +0 -0
- /package/dist/{types → src/types}/persistence.js +0 -0
- /package/dist/{types → src/types}/route.js +0 -0
- /package/dist/{types → src/types}/routing.d.ts +0 -0
- /package/dist/{cjs → src}/types/routing.d.ts.map +0 -0
- /package/dist/{types → src/types}/routing.js +0 -0
- /package/dist/{cjs → src}/types/routing.js.map +0 -0
- /package/dist/{types → src/types}/schema.d.ts +0 -0
- /package/dist/{cjs → src}/types/schema.d.ts.map +0 -0
- /package/dist/{types → src/types}/schema.js +0 -0
- /package/dist/{cjs → src}/types/schema.js.map +0 -0
- /package/dist/{types → src/types}/tool.js +0 -0
- /package/dist/{utils → src/utils}/id.d.ts +0 -0
- /package/dist/{cjs → src}/utils/id.d.ts.map +0 -0
- /package/dist/{utils → src/utils}/id.js +0 -0
- /package/dist/{utils → src/utils}/logger.d.ts +0 -0
- /package/dist/{cjs → src}/utils/logger.d.ts.map +0 -0
- /package/dist/{utils → src/utils}/logger.js +0 -0
- /package/dist/{utils → src/utils}/retry.d.ts +0 -0
- /package/dist/{cjs → src}/utils/retry.d.ts.map +0 -0
- /package/dist/{utils → src/utils}/retry.js +0 -0
- /package/docs/{PUBLISHING.md → guides/advanced-patterns/publishing.md} +0 -0
package/src/core/Agent.ts
CHANGED
|
@@ -2,52 +2,64 @@
|
|
|
2
2
|
* Core Agent implementation
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
import type {
|
|
6
|
+
AgentOptions,
|
|
7
|
+
Term,
|
|
8
|
+
Guideline,
|
|
9
|
+
Tool,
|
|
10
|
+
Event,
|
|
11
|
+
RouteOptions,
|
|
12
|
+
SessionState,
|
|
13
|
+
AgentStructuredResponse,
|
|
14
|
+
Template,
|
|
15
|
+
StepRef,
|
|
16
|
+
History,
|
|
17
|
+
AgentResponseStreamChunk,
|
|
18
|
+
AgentResponse,
|
|
19
|
+
StructuredSchema,
|
|
20
|
+
} from "../types";
|
|
21
|
+
import { EventKind, MessageRole } from "../types/history";
|
|
11
22
|
import {
|
|
12
|
-
createSession,
|
|
13
23
|
enterRoute,
|
|
14
24
|
enterStep,
|
|
15
25
|
mergeCollected,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
26
|
+
logger,
|
|
27
|
+
LoggerLevel,
|
|
28
|
+
render,
|
|
29
|
+
getLastMessageFromHistory,
|
|
30
|
+
normalizeHistory,
|
|
31
|
+
cloneDeep,
|
|
32
|
+
} from "../utils";
|
|
19
33
|
|
|
20
34
|
import { Route } from "./Route";
|
|
21
35
|
import { Step } from "./Step";
|
|
22
|
-
import { DomainRegistry } from "./DomainRegistry";
|
|
23
36
|
import { PersistenceManager } from "./PersistenceManager";
|
|
37
|
+
import { SessionManager } from "./SessionManager";
|
|
24
38
|
import { RoutingEngine } from "./RoutingEngine";
|
|
25
39
|
import { ResponseEngine } from "./ResponseEngine";
|
|
26
40
|
import { ToolExecutor } from "./ToolExecutor";
|
|
27
|
-
import {
|
|
41
|
+
import { ResponsePipeline } from "./ResponsePipeline";
|
|
28
42
|
import { END_ROUTE_ID } from "../constants";
|
|
29
|
-
import { ToolRef } from "../types";
|
|
30
43
|
|
|
31
44
|
/**
|
|
32
45
|
* Main Agent class with generic context support
|
|
33
46
|
*/
|
|
34
47
|
export class Agent<TContext = unknown> {
|
|
35
|
-
private terms: Term[] = [];
|
|
36
|
-
private guidelines: Guideline[] = [];
|
|
37
|
-
private
|
|
48
|
+
private terms: Term<TContext>[] = [];
|
|
49
|
+
private guidelines: Guideline<TContext>[] = [];
|
|
50
|
+
private tools: Tool<TContext, unknown[], unknown, unknown>[] = [];
|
|
38
51
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
52
|
private routes: Route<TContext, any>[] = [];
|
|
40
|
-
private domainRegistry = new DomainRegistry();
|
|
41
53
|
private context: TContext | undefined;
|
|
42
54
|
private persistenceManager: PersistenceManager | undefined;
|
|
43
55
|
private routingEngine: RoutingEngine<TContext>;
|
|
44
56
|
private responseEngine: ResponseEngine<TContext>;
|
|
45
|
-
private
|
|
57
|
+
private responsePipeline: ResponsePipeline<TContext>;
|
|
58
|
+
private currentSession?: SessionState;
|
|
59
|
+
private knowledgeBase: Record<string, unknown> = {};
|
|
46
60
|
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
*/
|
|
50
|
-
public readonly domain: Record<string, Record<string, unknown>> = {};
|
|
61
|
+
/** Public session manager for easy session management */
|
|
62
|
+
public session: SessionManager<unknown>;
|
|
51
63
|
|
|
52
64
|
constructor(private readonly options: AgentOptions<TContext>) {
|
|
53
65
|
// Set log level based on debug option
|
|
@@ -75,6 +87,14 @@ export class Agent<TContext = unknown> {
|
|
|
75
87
|
switchThreshold: 70,
|
|
76
88
|
});
|
|
77
89
|
this.responseEngine = new ResponseEngine<TContext>();
|
|
90
|
+
this.responsePipeline = new ResponsePipeline<TContext>(
|
|
91
|
+
options,
|
|
92
|
+
this.routes,
|
|
93
|
+
this.tools,
|
|
94
|
+
this.routingEngine,
|
|
95
|
+
this.updateContext.bind(this),
|
|
96
|
+
this.updateData.bind(this)
|
|
97
|
+
);
|
|
78
98
|
|
|
79
99
|
// Initialize persistence if configured
|
|
80
100
|
if (options.persistence) {
|
|
@@ -91,9 +111,11 @@ export class Agent<TContext = unknown> {
|
|
|
91
111
|
}
|
|
92
112
|
}
|
|
93
113
|
|
|
94
|
-
// Initialize from options
|
|
114
|
+
// Initialize from options - use create methods for consistency
|
|
95
115
|
if (options.terms) {
|
|
96
|
-
|
|
116
|
+
options.terms.forEach((term) => {
|
|
117
|
+
this.createTerm(term);
|
|
118
|
+
});
|
|
97
119
|
}
|
|
98
120
|
|
|
99
121
|
if (options.guidelines) {
|
|
@@ -102,9 +124,9 @@ export class Agent<TContext = unknown> {
|
|
|
102
124
|
});
|
|
103
125
|
}
|
|
104
126
|
|
|
105
|
-
if (options.
|
|
106
|
-
options.
|
|
107
|
-
this.
|
|
127
|
+
if (options.tools) {
|
|
128
|
+
options.tools.forEach((tool) => {
|
|
129
|
+
this.createTool(tool);
|
|
108
130
|
});
|
|
109
131
|
}
|
|
110
132
|
|
|
@@ -113,6 +135,22 @@ export class Agent<TContext = unknown> {
|
|
|
113
135
|
this.createRoute<unknown>(routeOptions);
|
|
114
136
|
});
|
|
115
137
|
}
|
|
138
|
+
|
|
139
|
+
// Initialize knowledge base
|
|
140
|
+
if (options.knowledgeBase) {
|
|
141
|
+
this.knowledgeBase = { ...options.knowledgeBase };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Initialize session manager
|
|
145
|
+
this.session = new SessionManager(this.persistenceManager);
|
|
146
|
+
|
|
147
|
+
// Store sessionId for later use in getOrCreate calls
|
|
148
|
+
if (options.sessionId) {
|
|
149
|
+
// The session will be loaded on first getOrCreate call
|
|
150
|
+
this.session.getOrCreate(options.sessionId).catch((err) => {
|
|
151
|
+
logger.error("Failed to start session", err);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
116
154
|
}
|
|
117
155
|
|
|
118
156
|
/**
|
|
@@ -136,6 +174,13 @@ export class Agent<TContext = unknown> {
|
|
|
136
174
|
return this.options.goal;
|
|
137
175
|
}
|
|
138
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Get agent identity
|
|
179
|
+
*/
|
|
180
|
+
get identity(): Template<TContext> | undefined {
|
|
181
|
+
return this.options.identity;
|
|
182
|
+
}
|
|
183
|
+
|
|
139
184
|
/**
|
|
140
185
|
* Create a new route (journey)
|
|
141
186
|
* @template TData - Type of data collected throughout the route
|
|
@@ -151,7 +196,7 @@ export class Agent<TContext = unknown> {
|
|
|
151
196
|
/**
|
|
152
197
|
* Create a domain term for the glossary
|
|
153
198
|
*/
|
|
154
|
-
createTerm(term: Term): this {
|
|
199
|
+
createTerm(term: Term<TContext>): this {
|
|
155
200
|
this.terms.push(term);
|
|
156
201
|
return this;
|
|
157
202
|
}
|
|
@@ -159,7 +204,7 @@ export class Agent<TContext = unknown> {
|
|
|
159
204
|
/**
|
|
160
205
|
* Create a behavioral guideline
|
|
161
206
|
*/
|
|
162
|
-
createGuideline(guideline: Guideline): this {
|
|
207
|
+
createGuideline(guideline: Guideline<TContext>): this {
|
|
163
208
|
const guidelineWithId = {
|
|
164
209
|
...guideline,
|
|
165
210
|
id: guideline.id || `guideline_${this.guidelines.length}`,
|
|
@@ -170,50 +215,24 @@ export class Agent<TContext = unknown> {
|
|
|
170
215
|
}
|
|
171
216
|
|
|
172
217
|
/**
|
|
173
|
-
*
|
|
218
|
+
* Register a tool at the agent level
|
|
174
219
|
*/
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
...capability,
|
|
178
|
-
id: capability.id || `capability_${this.capabilities.length}`,
|
|
179
|
-
};
|
|
180
|
-
this.capabilities.push(capabilityWithId);
|
|
220
|
+
createTool(tool: Tool<TContext, unknown[], unknown, unknown>): this {
|
|
221
|
+
this.tools.push(tool);
|
|
181
222
|
return this;
|
|
182
223
|
}
|
|
183
224
|
|
|
184
225
|
/**
|
|
185
|
-
*
|
|
186
|
-
* Automatically tags all ToolRef objects with their domain name for security enforcement
|
|
226
|
+
* Register multiple tools at the agent level
|
|
187
227
|
*/
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
): void {
|
|
192
|
-
// Tag all tools in this domain with the domain name for security enforcement
|
|
193
|
-
const taggedDomain = { ...domainObject };
|
|
194
|
-
for (const key in taggedDomain) {
|
|
195
|
-
const value = taggedDomain[key];
|
|
196
|
-
// Check if value is a ToolRef (has handler, id, name properties)
|
|
197
|
-
if (
|
|
198
|
-
value &&
|
|
199
|
-
typeof value === "object" &&
|
|
200
|
-
"handler" in value &&
|
|
201
|
-
"id" in value &&
|
|
202
|
-
"name" in value
|
|
203
|
-
) {
|
|
204
|
-
// Tag the tool with its domain name
|
|
205
|
-
(value as Record<string, unknown>).domainName = name;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
this.domainRegistry.register(name, taggedDomain);
|
|
210
|
-
// Attach to the domain property for easy access
|
|
211
|
-
this.domain[name] = taggedDomain;
|
|
228
|
+
registerTools(tools: Tool<TContext, unknown[], unknown, unknown>[]): this {
|
|
229
|
+
tools.forEach((tool) => this.createTool(tool));
|
|
230
|
+
return this;
|
|
212
231
|
}
|
|
213
232
|
|
|
214
233
|
/**
|
|
215
234
|
* Update the agent's context
|
|
216
|
-
* Triggers
|
|
235
|
+
* Triggers both agent-level and route-specific onContextUpdate lifecycle hooks if configured
|
|
217
236
|
*/
|
|
218
237
|
async updateContext(updates: Partial<TContext>): Promise<void> {
|
|
219
238
|
const previousContext = this.context;
|
|
@@ -224,7 +243,20 @@ export class Agent<TContext = unknown> {
|
|
|
224
243
|
...(updates as Record<string, unknown>),
|
|
225
244
|
} as TContext;
|
|
226
245
|
|
|
227
|
-
// Trigger lifecycle hook if configured
|
|
246
|
+
// Trigger route-specific lifecycle hook if configured and session has current route
|
|
247
|
+
if (this.currentSession?.currentRoute) {
|
|
248
|
+
const currentRoute = this.routes.find(
|
|
249
|
+
(r) => r.id === this.currentSession!.currentRoute?.id
|
|
250
|
+
);
|
|
251
|
+
if (
|
|
252
|
+
currentRoute?.hooks?.onContextUpdate &&
|
|
253
|
+
previousContext !== undefined
|
|
254
|
+
) {
|
|
255
|
+
await currentRoute.handleContextUpdate(this.context, previousContext);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Trigger agent-level lifecycle hook if configured
|
|
228
260
|
if (this.options.hooks?.onContextUpdate && previousContext !== undefined) {
|
|
229
261
|
await this.options.hooks.onContextUpdate(this.context, previousContext);
|
|
230
262
|
}
|
|
@@ -232,22 +264,35 @@ export class Agent<TContext = unknown> {
|
|
|
232
264
|
|
|
233
265
|
/**
|
|
234
266
|
* Update collected data in session with lifecycle hook support
|
|
235
|
-
* Triggers
|
|
267
|
+
* Triggers both agent-level and route-specific onDataUpdate lifecycle hooks if configured
|
|
236
268
|
* @internal
|
|
237
269
|
*/
|
|
238
270
|
private async updateData<TData = unknown>(
|
|
239
|
-
session:
|
|
240
|
-
|
|
241
|
-
): Promise<
|
|
271
|
+
session: SessionState<TData>,
|
|
272
|
+
dataUpdate: Partial<TData>
|
|
273
|
+
): Promise<SessionState<TData>> {
|
|
242
274
|
const previousCollected = { ...session.data };
|
|
243
275
|
|
|
244
276
|
// Merge new collected data
|
|
245
277
|
let newCollected = {
|
|
246
278
|
...session.data,
|
|
247
|
-
...
|
|
279
|
+
...dataUpdate,
|
|
248
280
|
};
|
|
249
281
|
|
|
250
|
-
// Trigger lifecycle hook if configured
|
|
282
|
+
// Trigger route-specific lifecycle hook if configured and session has a current route
|
|
283
|
+
if (session.currentRoute) {
|
|
284
|
+
const currentRoute = this.routes.find(
|
|
285
|
+
(r) => r.id === session.currentRoute?.id
|
|
286
|
+
);
|
|
287
|
+
if (currentRoute?.hooks?.onDataUpdate) {
|
|
288
|
+
newCollected = await currentRoute.handleDataUpdate(
|
|
289
|
+
newCollected,
|
|
290
|
+
previousCollected
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Trigger agent-level lifecycle hook if configured
|
|
251
296
|
if (this.options.hooks?.onDataUpdate) {
|
|
252
297
|
newCollected = (await this.options.hooks.onDataUpdate(
|
|
253
298
|
newCollected,
|
|
@@ -261,9 +306,8 @@ export class Agent<TContext = unknown> {
|
|
|
261
306
|
|
|
262
307
|
/**
|
|
263
308
|
* Get current context (fetches from provider if configured)
|
|
264
|
-
* @internal
|
|
265
309
|
*/
|
|
266
|
-
|
|
310
|
+
async getContext(): Promise<TContext | undefined> {
|
|
267
311
|
// If context provider is configured, use it to fetch fresh context
|
|
268
312
|
if (this.options.contextProvider) {
|
|
269
313
|
return await this.options.contextProvider();
|
|
@@ -276,193 +320,74 @@ export class Agent<TContext = unknown> {
|
|
|
276
320
|
/**
|
|
277
321
|
* Generate a response based on history and context as a stream
|
|
278
322
|
*/
|
|
279
|
-
async *respondStream(params: {
|
|
280
|
-
history:
|
|
323
|
+
async *respondStream<TData = Record<string, unknown>>(params: {
|
|
324
|
+
history: History;
|
|
281
325
|
step?: StepRef;
|
|
282
|
-
session?:
|
|
326
|
+
session?: SessionState<TData>;
|
|
283
327
|
contextOverride?: Partial<TContext>;
|
|
284
328
|
signal?: AbortSignal;
|
|
285
|
-
}): AsyncGenerator<{
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
session
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if
|
|
300
|
-
|
|
301
|
-
// Update stored context with the result from beforeRespond
|
|
302
|
-
this.context = currentContext;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// Merge context with override
|
|
306
|
-
const effectiveContext = {
|
|
307
|
-
...(currentContext as Record<string, unknown>),
|
|
308
|
-
...(contextOverride as Record<string, unknown>),
|
|
309
|
-
} as TContext;
|
|
310
|
-
|
|
311
|
-
// Initialize or get session (use current session if available)
|
|
312
|
-
let session = params.session || this.currentSession || createSession();
|
|
329
|
+
}): AsyncGenerator<AgentResponseStreamChunk<TData>> {
|
|
330
|
+
const { history: simpleHistory, signal } = params;
|
|
331
|
+
const history = normalizeHistory(simpleHistory);
|
|
332
|
+
|
|
333
|
+
// Prepare context and session using the response pipeline
|
|
334
|
+
this.responsePipeline.setContext(this.context);
|
|
335
|
+
this.responsePipeline.setCurrentSession(this.currentSession);
|
|
336
|
+
let session: SessionState;
|
|
337
|
+
const responseContext = await this.responsePipeline.prepareResponseContext({
|
|
338
|
+
contextOverride: params.contextOverride,
|
|
339
|
+
session: params.session ? cloneDeep(params.session) : undefined,
|
|
340
|
+
});
|
|
341
|
+
const { effectiveContext } = responseContext;
|
|
342
|
+
session = responseContext.session;
|
|
343
|
+
// Update our stored context if it was modified by beforeRespond hook
|
|
344
|
+
this.context = this.responsePipeline.getStoredContext();
|
|
313
345
|
|
|
314
|
-
// PHASE 1:
|
|
346
|
+
// PHASE 1: PREPARE - Execute prepare function if current step has one
|
|
315
347
|
if (session.currentRoute && session.currentStep) {
|
|
316
348
|
const currentRoute = this.routes.find(
|
|
317
349
|
(r) => r.id === session.currentRoute?.id
|
|
318
350
|
);
|
|
319
351
|
if (currentRoute) {
|
|
320
352
|
const currentStep = currentRoute.getStep(session.currentStep.id);
|
|
321
|
-
if (currentStep) {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
toolTransition.spec.tool as ToolRef<TContext, unknown[], unknown>,
|
|
331
|
-
effectiveContext,
|
|
332
|
-
this.updateContext.bind(this),
|
|
333
|
-
history,
|
|
334
|
-
session.data,
|
|
335
|
-
allowedDomains
|
|
336
|
-
);
|
|
337
|
-
|
|
338
|
-
// Update context with tool results
|
|
339
|
-
if (result.contextUpdate) {
|
|
340
|
-
await this.updateContext(
|
|
341
|
-
result.contextUpdate as Partial<TContext>
|
|
342
|
-
);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Update collected data with tool results
|
|
346
|
-
if (result.collectedUpdate) {
|
|
347
|
-
session = await this.updateData(session, result.collectedUpdate);
|
|
348
|
-
logger.debug(
|
|
349
|
-
`[Agent] Tool updated collected data:`,
|
|
350
|
-
result.collectedUpdate
|
|
351
|
-
);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
logger.debug(
|
|
355
|
-
`[Agent] Executed tool: ${result.toolName} (success: ${result.success})`
|
|
356
|
-
);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// PHASE 2: ROUTING + STEP SELECTION - Determine which route and step to use (combined)
|
|
363
|
-
let selectedRoute: Route<TContext> | undefined;
|
|
364
|
-
let responseDirectives: string[] | undefined;
|
|
365
|
-
let selectedStep: Step<TContext> | undefined;
|
|
366
|
-
let isRouteComplete = false;
|
|
367
|
-
|
|
368
|
-
// Check for pending transition from previous route completion
|
|
369
|
-
if (session.pendingTransition) {
|
|
370
|
-
const targetRoute = this.routes.find(
|
|
371
|
-
(r) => r.id === session.pendingTransition?.targetRouteId
|
|
372
|
-
);
|
|
373
|
-
|
|
374
|
-
if (targetRoute) {
|
|
375
|
-
logger.debug(
|
|
376
|
-
`[Agent] Auto-transitioning from pending transition to route: ${targetRoute.title}`
|
|
377
|
-
);
|
|
378
|
-
// Clear pending transition and enter new route
|
|
379
|
-
session = {
|
|
380
|
-
...session,
|
|
381
|
-
pendingTransition: undefined,
|
|
382
|
-
};
|
|
383
|
-
session = enterRoute(session, targetRoute.id, targetRoute.title);
|
|
384
|
-
|
|
385
|
-
// Merge initial data if available
|
|
386
|
-
if (targetRoute.initialData) {
|
|
387
|
-
session = mergeCollected(session, targetRoute.initialData);
|
|
353
|
+
if (currentStep?.prepare) {
|
|
354
|
+
logger.debug(`[Agent] Executing prepare for step: ${currentStep.id}`);
|
|
355
|
+
await this.executePrepareFinalize(
|
|
356
|
+
currentStep.prepare,
|
|
357
|
+
effectiveContext,
|
|
358
|
+
session.data,
|
|
359
|
+
currentRoute,
|
|
360
|
+
currentStep
|
|
361
|
+
);
|
|
388
362
|
}
|
|
389
|
-
|
|
390
|
-
selectedRoute = targetRoute;
|
|
391
|
-
} else {
|
|
392
|
-
logger.warn(
|
|
393
|
-
`[Agent] Pending transition target route not found: ${session.pendingTransition.targetRouteId}`
|
|
394
|
-
);
|
|
395
|
-
// Clear invalid transition
|
|
396
|
-
session = {
|
|
397
|
-
...session,
|
|
398
|
-
pendingTransition: undefined,
|
|
399
|
-
};
|
|
400
363
|
}
|
|
401
364
|
}
|
|
402
365
|
|
|
403
|
-
//
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
routes: this.routes,
|
|
366
|
+
// PHASE 2: ROUTING + STEP SELECTION - Use response pipeline
|
|
367
|
+
const routingResult =
|
|
368
|
+
await this.responsePipeline.handleRoutingAndStepSelection({
|
|
407
369
|
session,
|
|
408
370
|
history,
|
|
409
|
-
agentMeta: {
|
|
410
|
-
name: this.options.name,
|
|
411
|
-
goal: this.options.goal,
|
|
412
|
-
description: this.options.description,
|
|
413
|
-
personality: this.options.personality,
|
|
414
|
-
},
|
|
415
|
-
provider: this.options.provider,
|
|
416
371
|
context: effectiveContext,
|
|
417
372
|
signal,
|
|
418
373
|
});
|
|
374
|
+
const selectedRoute = routingResult.selectedRoute;
|
|
375
|
+
const selectedStep = routingResult.selectedStep;
|
|
376
|
+
const responseDirectives = routingResult.responseDirectives;
|
|
377
|
+
const isRouteComplete = routingResult.isRouteComplete;
|
|
378
|
+
session = routingResult.session;
|
|
379
|
+
|
|
380
|
+
// PHASE 3: DETERMINE NEXT STEP - Use pipeline method
|
|
381
|
+
const stepResult = this.responsePipeline.determineNextStep({
|
|
382
|
+
selectedRoute,
|
|
383
|
+
selectedStep,
|
|
384
|
+
session,
|
|
385
|
+
isRouteComplete,
|
|
386
|
+
});
|
|
387
|
+
const nextStep = stepResult.nextStep;
|
|
388
|
+
session = stepResult.session;
|
|
419
389
|
|
|
420
|
-
selectedRoute = orchestration.selectedRoute;
|
|
421
|
-
selectedStep = orchestration.selectedStep;
|
|
422
|
-
responseDirectives = orchestration.responseDirectives;
|
|
423
|
-
session = orchestration.session;
|
|
424
|
-
isRouteComplete = orchestration.isRouteComplete || false;
|
|
425
|
-
|
|
426
|
-
// Log if route is complete
|
|
427
|
-
if (isRouteComplete) {
|
|
428
|
-
logger.debug(
|
|
429
|
-
`[Agent] Route complete: all required data collected, END_ROUTE reached`
|
|
430
|
-
);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
// PHASE 3: DETERMINE NEXT STEP - Use step from combined decision or get initial step
|
|
435
390
|
if (selectedRoute && !isRouteComplete) {
|
|
436
|
-
let nextStep: Step<TContext>;
|
|
437
|
-
|
|
438
|
-
// If we have a selected step from the combined routing decision, use it
|
|
439
|
-
if (selectedStep) {
|
|
440
|
-
nextStep = selectedStep;
|
|
441
|
-
} else {
|
|
442
|
-
// New route or no step selected - get initial step or first valid step
|
|
443
|
-
const candidates = this.routingEngine.getCandidateSteps(
|
|
444
|
-
selectedRoute,
|
|
445
|
-
undefined,
|
|
446
|
-
session.data || {}
|
|
447
|
-
);
|
|
448
|
-
if (candidates.length > 0) {
|
|
449
|
-
nextStep = candidates[0].step;
|
|
450
|
-
logger.debug(
|
|
451
|
-
`[Agent] Using first valid step: ${nextStep.id} for new route`
|
|
452
|
-
);
|
|
453
|
-
} else {
|
|
454
|
-
// Fallback to initial step even if it should be skipped
|
|
455
|
-
nextStep = selectedRoute.initialStep;
|
|
456
|
-
logger.warn(
|
|
457
|
-
`[Agent] No valid steps found, using initial step: ${nextStep.id}`
|
|
458
|
-
);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// Update session with next step
|
|
463
|
-
session = enterStep(session, nextStep.id, nextStep.description);
|
|
464
|
-
logger.debug(`[Agent] Entered step: ${nextStep.id}`);
|
|
465
|
-
|
|
466
391
|
// PHASE 4: RESPONSE GENERATION - Stream message using selected route and step
|
|
467
392
|
// Get last user message
|
|
468
393
|
const lastUserMessage = getLastMessageFromHistory(history);
|
|
@@ -473,21 +398,42 @@ export class Agent<TContext = unknown> {
|
|
|
473
398
|
nextStep
|
|
474
399
|
);
|
|
475
400
|
|
|
401
|
+
// Check if selected route and next step are defined
|
|
402
|
+
if (!selectedRoute || !nextStep) {
|
|
403
|
+
logger.error("[Agent] Selected route or next step is not defined", {
|
|
404
|
+
selectedRoute,
|
|
405
|
+
nextStep,
|
|
406
|
+
});
|
|
407
|
+
throw new Error("Selected route or next step is not defined");
|
|
408
|
+
}
|
|
409
|
+
|
|
476
410
|
// Build response prompt
|
|
477
|
-
const responsePrompt = this.responseEngine.buildResponsePrompt(
|
|
478
|
-
selectedRoute,
|
|
479
|
-
nextStep,
|
|
480
|
-
selectedRoute.getRules(),
|
|
481
|
-
selectedRoute.getProhibitions(),
|
|
482
|
-
responseDirectives,
|
|
411
|
+
const responsePrompt = await this.responseEngine.buildResponsePrompt({
|
|
412
|
+
route: selectedRoute,
|
|
413
|
+
currentStep: nextStep,
|
|
414
|
+
rules: selectedRoute.getRules(),
|
|
415
|
+
prohibitions: selectedRoute.getProhibitions(),
|
|
416
|
+
directives: responseDirectives,
|
|
483
417
|
history,
|
|
484
|
-
lastUserMessage,
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
418
|
+
lastMessage: lastUserMessage,
|
|
419
|
+
agentOptions: this.options,
|
|
420
|
+
// Combine agent and route properties according to the specified logic
|
|
421
|
+
combinedGuidelines: [
|
|
422
|
+
...this.getGuidelines(),
|
|
423
|
+
...selectedRoute.getGuidelines(),
|
|
424
|
+
],
|
|
425
|
+
combinedTerms: this.mergeTerms(
|
|
426
|
+
this.getTerms(),
|
|
427
|
+
selectedRoute.getTerms()
|
|
428
|
+
),
|
|
429
|
+
context: effectiveContext,
|
|
430
|
+
session,
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
// Collect available tools for AI
|
|
434
|
+
const availableTools = this.collectAvailableTools(
|
|
435
|
+
selectedRoute,
|
|
436
|
+
nextStep
|
|
491
437
|
);
|
|
492
438
|
|
|
493
439
|
// Generate message stream using AI provider
|
|
@@ -495,6 +441,7 @@ export class Agent<TContext = unknown> {
|
|
|
495
441
|
prompt: responsePrompt,
|
|
496
442
|
history,
|
|
497
443
|
context: effectiveContext,
|
|
444
|
+
tools: availableTools,
|
|
498
445
|
signal,
|
|
499
446
|
parameters: {
|
|
500
447
|
jsonSchema: responseSchema,
|
|
@@ -504,18 +451,206 @@ export class Agent<TContext = unknown> {
|
|
|
504
451
|
|
|
505
452
|
// Stream chunks to caller
|
|
506
453
|
for await (const chunk of stream) {
|
|
507
|
-
|
|
454
|
+
let toolCalls:
|
|
508
455
|
| Array<{ toolName: string; arguments: Record<string, unknown> }>
|
|
509
456
|
| undefined = undefined;
|
|
510
457
|
|
|
458
|
+
// Extract tool calls from AI response on final chunk
|
|
459
|
+
if (chunk.done && chunk.structured?.toolCalls) {
|
|
460
|
+
toolCalls = chunk.structured.toolCalls;
|
|
461
|
+
|
|
462
|
+
// Execute dynamic tool calls
|
|
463
|
+
if (toolCalls.length > 0) {
|
|
464
|
+
logger.debug(
|
|
465
|
+
`[Agent] Executing ${toolCalls.length} dynamic tool calls`
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
for (const toolCall of toolCalls) {
|
|
469
|
+
const tool = this.findAvailableTool(
|
|
470
|
+
toolCall.toolName,
|
|
471
|
+
selectedRoute
|
|
472
|
+
);
|
|
473
|
+
if (!tool) {
|
|
474
|
+
logger.warn(`[Agent] Tool not found: ${toolCall.toolName}`);
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const toolExecutor = new ToolExecutor<TContext, unknown>();
|
|
479
|
+
const result = await toolExecutor.executeTool({
|
|
480
|
+
tool: tool,
|
|
481
|
+
context: effectiveContext,
|
|
482
|
+
updateContext: this.updateContext.bind(this),
|
|
483
|
+
history,
|
|
484
|
+
data: session.data,
|
|
485
|
+
toolArguments: toolCall.arguments,
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
// Update context with tool results
|
|
489
|
+
if (result.contextUpdate) {
|
|
490
|
+
await this.updateContext(
|
|
491
|
+
result.contextUpdate as Partial<TContext>
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Update collected data with tool results
|
|
496
|
+
if (result.dataUpdate) {
|
|
497
|
+
session = await this.updateData(session, result.dataUpdate);
|
|
498
|
+
logger.debug(
|
|
499
|
+
`[Agent] Tool updated collected data:`,
|
|
500
|
+
result.dataUpdate
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
logger.debug(
|
|
505
|
+
`[Agent] Executed dynamic tool: ${result.toolName} (success: ${result.success})`
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// TOOL LOOP: Allow AI to make follow-up tool calls after initial tool execution (streaming)
|
|
512
|
+
const MAX_TOOL_LOOPS = 5;
|
|
513
|
+
let toolLoopCount = 0;
|
|
514
|
+
let hasToolCalls = toolCalls && toolCalls.length > 0;
|
|
515
|
+
|
|
516
|
+
while (hasToolCalls && toolLoopCount < MAX_TOOL_LOOPS) {
|
|
517
|
+
toolLoopCount++;
|
|
518
|
+
logger.debug(
|
|
519
|
+
`[Agent] Starting streaming tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS}`
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
// Add tool execution results to history so AI knows what happened
|
|
523
|
+
const toolResultsEvents: Event[] = [];
|
|
524
|
+
for (const toolCall of toolCalls || []) {
|
|
525
|
+
const tool = this.findAvailableTool(
|
|
526
|
+
toolCall.toolName,
|
|
527
|
+
selectedRoute
|
|
528
|
+
);
|
|
529
|
+
if (tool) {
|
|
530
|
+
toolResultsEvents.push({
|
|
531
|
+
kind: EventKind.TOOL,
|
|
532
|
+
source: MessageRole.AGENT,
|
|
533
|
+
timestamp: new Date().toISOString(),
|
|
534
|
+
data: {
|
|
535
|
+
tool_calls: [
|
|
536
|
+
{
|
|
537
|
+
tool_id: toolCall.toolName,
|
|
538
|
+
arguments: toolCall.arguments,
|
|
539
|
+
result: {
|
|
540
|
+
data: "Tool executed successfully",
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
],
|
|
544
|
+
},
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Create updated history with tool results
|
|
550
|
+
const updatedHistory = [...history, ...toolResultsEvents];
|
|
551
|
+
|
|
552
|
+
// Make follow-up streaming AI call to see if more tools are needed
|
|
553
|
+
const followUpStream = this.options.provider.generateMessageStream({
|
|
554
|
+
prompt: responsePrompt,
|
|
555
|
+
history: updatedHistory,
|
|
556
|
+
context: effectiveContext,
|
|
557
|
+
tools: availableTools,
|
|
558
|
+
parameters: {
|
|
559
|
+
jsonSchema: responseSchema,
|
|
560
|
+
schemaName: "tool_followup",
|
|
561
|
+
},
|
|
562
|
+
signal,
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
let followUpToolCalls:
|
|
566
|
+
| Array<{ toolName: string; arguments: Record<string, unknown> }>
|
|
567
|
+
| undefined;
|
|
568
|
+
|
|
569
|
+
for await (const followUpChunk of followUpStream) {
|
|
570
|
+
// Extract tool calls from follow-up stream
|
|
571
|
+
if (followUpChunk.done && followUpChunk.structured?.toolCalls) {
|
|
572
|
+
followUpToolCalls = followUpChunk.structured.toolCalls;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
hasToolCalls = followUpToolCalls && followUpToolCalls.length > 0;
|
|
577
|
+
|
|
578
|
+
if (hasToolCalls) {
|
|
579
|
+
logger.debug(
|
|
580
|
+
`[Agent] Follow-up streaming call produced ${
|
|
581
|
+
followUpToolCalls!.length
|
|
582
|
+
} additional tool calls`
|
|
583
|
+
);
|
|
584
|
+
|
|
585
|
+
// Execute the follow-up tool calls
|
|
586
|
+
for (const toolCall of followUpToolCalls!) {
|
|
587
|
+
const tool = this.findAvailableTool(
|
|
588
|
+
toolCall.toolName,
|
|
589
|
+
selectedRoute
|
|
590
|
+
);
|
|
591
|
+
if (!tool) {
|
|
592
|
+
logger.warn(
|
|
593
|
+
`[Agent] Tool not found in streaming follow-up: ${toolCall.toolName}`
|
|
594
|
+
);
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const toolExecutor = new ToolExecutor<TContext, unknown>();
|
|
599
|
+
const result = await toolExecutor.executeTool({
|
|
600
|
+
tool: tool,
|
|
601
|
+
context: effectiveContext,
|
|
602
|
+
updateContext: this.updateContext.bind(this),
|
|
603
|
+
history: updatedHistory,
|
|
604
|
+
data: session.data,
|
|
605
|
+
toolArguments: toolCall.arguments,
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
// Update context with follow-up tool results
|
|
609
|
+
if (result.contextUpdate) {
|
|
610
|
+
await this.updateContext(
|
|
611
|
+
result.contextUpdate as Partial<TContext>
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (result.dataUpdate) {
|
|
616
|
+
session = await this.updateData(session, result.dataUpdate);
|
|
617
|
+
logger.debug(
|
|
618
|
+
`[Agent] Streaming follow-up tool updated collected data:`,
|
|
619
|
+
result.dataUpdate
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
logger.debug(
|
|
624
|
+
`[Agent] Executed streaming follow-up tool: ${result.toolName} (success: ${result.success})`
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Update toolCalls for next iteration
|
|
629
|
+
toolCalls = followUpToolCalls;
|
|
630
|
+
} else {
|
|
631
|
+
logger.debug(
|
|
632
|
+
`[Agent] Streaming tool loop completed after ${toolLoopCount} iterations`
|
|
633
|
+
);
|
|
634
|
+
// Update toolCalls for final response
|
|
635
|
+
toolCalls = followUpToolCalls || [];
|
|
636
|
+
break;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (toolLoopCount >= MAX_TOOL_LOOPS) {
|
|
641
|
+
logger.warn(
|
|
642
|
+
`[Agent] Streaming tool loop limit reached (${MAX_TOOL_LOOPS}), stopping`
|
|
643
|
+
);
|
|
644
|
+
}
|
|
645
|
+
|
|
511
646
|
// Extract collected data on final chunk
|
|
512
|
-
if (chunk.done && chunk.structured && nextStep.
|
|
647
|
+
if (chunk.done && chunk.structured && nextStep.collect) {
|
|
513
648
|
const collectedData: Record<string, unknown> = {};
|
|
514
649
|
// The structured response includes both base fields and collected extraction fields
|
|
515
650
|
const structuredData = chunk.structured as AgentStructuredResponse &
|
|
516
651
|
Record<string, unknown>;
|
|
517
652
|
|
|
518
|
-
for (const field of nextStep.
|
|
653
|
+
for (const field of nextStep.collect) {
|
|
519
654
|
if (field in structuredData) {
|
|
520
655
|
collectedData[field] = structuredData[field];
|
|
521
656
|
}
|
|
@@ -548,12 +683,34 @@ export class Agent<TContext = unknown> {
|
|
|
548
683
|
session.id &&
|
|
549
684
|
this.options.persistence?.autoSave !== false
|
|
550
685
|
) {
|
|
551
|
-
await this.persistenceManager.
|
|
686
|
+
await this.persistenceManager.saveSessionState(session.id, session);
|
|
552
687
|
logger.debug(
|
|
553
688
|
`[Agent] Auto-saved session step to persistence: ${session.id}`
|
|
554
689
|
);
|
|
555
690
|
}
|
|
556
691
|
|
|
692
|
+
// Execute finalize function on final chunk
|
|
693
|
+
if (chunk.done && session.currentRoute && session.currentStep) {
|
|
694
|
+
const currentRoute = this.routes.find(
|
|
695
|
+
(r) => r.id === session.currentRoute?.id
|
|
696
|
+
);
|
|
697
|
+
if (currentRoute) {
|
|
698
|
+
const currentStep = currentRoute.getStep(session.currentStep.id);
|
|
699
|
+
if (currentStep?.finalize) {
|
|
700
|
+
logger.debug(
|
|
701
|
+
`[Agent] Executing finalize for step: ${currentStep.id}`
|
|
702
|
+
);
|
|
703
|
+
await this.executePrepareFinalize(
|
|
704
|
+
currentStep.finalize,
|
|
705
|
+
effectiveContext,
|
|
706
|
+
session.data,
|
|
707
|
+
currentRoute,
|
|
708
|
+
currentStep
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
557
714
|
// Update current session if we have one
|
|
558
715
|
if (chunk.done && this.currentSession) {
|
|
559
716
|
this.currentSession = session;
|
|
@@ -566,6 +723,8 @@ export class Agent<TContext = unknown> {
|
|
|
566
723
|
session, // Return updated session
|
|
567
724
|
toolCalls,
|
|
568
725
|
isRouteComplete,
|
|
726
|
+
metadata: chunk.metadata,
|
|
727
|
+
structured: chunk.structured,
|
|
569
728
|
};
|
|
570
729
|
}
|
|
571
730
|
} else if (isRouteComplete && selectedRoute) {
|
|
@@ -576,40 +735,49 @@ export class Agent<TContext = unknown> {
|
|
|
576
735
|
const endStepSpec = selectedRoute.endStepSpec;
|
|
577
736
|
|
|
578
737
|
// Create a temporary step for completion message generation using endStep configuration
|
|
579
|
-
const completionStep = new Step<TContext>(
|
|
580
|
-
|
|
581
|
-
endStepSpec.
|
|
582
|
-
|
|
583
|
-
endStepSpec.
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
"Summarize what was accomplished and confirm completion based on the conversation history and collected data"
|
|
589
|
-
);
|
|
738
|
+
const completionStep = new Step<TContext, unknown>(selectedRoute.id, {
|
|
739
|
+
description: endStepSpec.description,
|
|
740
|
+
id: endStepSpec.id || END_ROUTE_ID,
|
|
741
|
+
collect: endStepSpec.collect,
|
|
742
|
+
requires: endStepSpec.requires,
|
|
743
|
+
prompt:
|
|
744
|
+
endStepSpec.prompt ||
|
|
745
|
+
"Summarize what was accomplished and confirm completion based on the conversation history and collected data",
|
|
746
|
+
});
|
|
590
747
|
|
|
591
748
|
// Build response schema for completion
|
|
592
749
|
const responseSchema = this.responseEngine.responseSchemaForRoute(
|
|
593
750
|
selectedRoute,
|
|
594
751
|
completionStep
|
|
595
752
|
);
|
|
753
|
+
const templateContext = {
|
|
754
|
+
context: effectiveContext,
|
|
755
|
+
session,
|
|
756
|
+
history,
|
|
757
|
+
};
|
|
596
758
|
|
|
597
759
|
// Build completion response prompt
|
|
598
|
-
const completionPrompt = this.responseEngine.buildResponsePrompt(
|
|
599
|
-
selectedRoute,
|
|
600
|
-
completionStep,
|
|
601
|
-
selectedRoute.getRules(),
|
|
602
|
-
selectedRoute.getProhibitions(),
|
|
603
|
-
undefined, // No directives for completion
|
|
760
|
+
const completionPrompt = await this.responseEngine.buildResponsePrompt({
|
|
761
|
+
route: selectedRoute,
|
|
762
|
+
currentStep: completionStep,
|
|
763
|
+
rules: selectedRoute.getRules(),
|
|
764
|
+
prohibitions: selectedRoute.getProhibitions(),
|
|
765
|
+
directives: undefined, // No directives for completion
|
|
604
766
|
history,
|
|
605
|
-
lastUserMessage,
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
767
|
+
lastMessage: lastUserMessage,
|
|
768
|
+
agentOptions: this.options,
|
|
769
|
+
// Combine agent and route properties according to the specified logic
|
|
770
|
+
combinedGuidelines: [
|
|
771
|
+
...this.getGuidelines(),
|
|
772
|
+
...selectedRoute.getGuidelines(),
|
|
773
|
+
],
|
|
774
|
+
combinedTerms: this.mergeTerms(
|
|
775
|
+
this.getTerms(),
|
|
776
|
+
selectedRoute.getTerms()
|
|
777
|
+
),
|
|
778
|
+
context: effectiveContext,
|
|
779
|
+
session,
|
|
780
|
+
});
|
|
613
781
|
|
|
614
782
|
// Stream completion message using AI provider
|
|
615
783
|
const stream = this.options.provider.generateMessageStream({
|
|
@@ -642,12 +810,16 @@ export class Agent<TContext = unknown> {
|
|
|
642
810
|
);
|
|
643
811
|
|
|
644
812
|
if (targetRoute) {
|
|
813
|
+
const renderedCondition = await render(
|
|
814
|
+
transitionConfig.condition,
|
|
815
|
+
templateContext
|
|
816
|
+
);
|
|
645
817
|
// Set pending transition in session
|
|
646
818
|
session = {
|
|
647
819
|
...session,
|
|
648
820
|
pendingTransition: {
|
|
649
821
|
targetRouteId: targetRoute.id,
|
|
650
|
-
condition:
|
|
822
|
+
condition: renderedCondition,
|
|
651
823
|
reason: "route_complete",
|
|
652
824
|
},
|
|
653
825
|
};
|
|
@@ -681,22 +853,20 @@ export class Agent<TContext = unknown> {
|
|
|
681
853
|
session,
|
|
682
854
|
toolCalls: undefined,
|
|
683
855
|
isRouteComplete: true,
|
|
856
|
+
metadata: chunk.metadata,
|
|
857
|
+
structured: chunk.structured,
|
|
684
858
|
};
|
|
685
859
|
}
|
|
686
860
|
} else {
|
|
687
861
|
// Fallback: No routes defined, stream a simple response
|
|
688
|
-
const fallbackPrompt =
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
.addGlossary(this.terms)
|
|
697
|
-
.addGuidelines(this.guidelines)
|
|
698
|
-
.addCapabilities(this.capabilities)
|
|
699
|
-
.build();
|
|
862
|
+
const fallbackPrompt = await this.responseEngine.buildFallbackPrompt({
|
|
863
|
+
history,
|
|
864
|
+
agentOptions: this.options,
|
|
865
|
+
terms: this.terms,
|
|
866
|
+
guidelines: this.guidelines,
|
|
867
|
+
context: effectiveContext,
|
|
868
|
+
session,
|
|
869
|
+
});
|
|
700
870
|
|
|
701
871
|
const stream = this.options.provider.generateMessageStream({
|
|
702
872
|
prompt: fallbackPrompt,
|
|
@@ -729,6 +899,8 @@ export class Agent<TContext = unknown> {
|
|
|
729
899
|
session, // Return updated session
|
|
730
900
|
toolCalls: undefined,
|
|
731
901
|
isRouteComplete: false,
|
|
902
|
+
metadata: chunk.metadata,
|
|
903
|
+
structured: chunk.structured,
|
|
732
904
|
};
|
|
733
905
|
}
|
|
734
906
|
}
|
|
@@ -737,19 +909,15 @@ export class Agent<TContext = unknown> {
|
|
|
737
909
|
/**
|
|
738
910
|
* Generate a response based on history and context
|
|
739
911
|
*/
|
|
740
|
-
async respond(params: {
|
|
741
|
-
history:
|
|
912
|
+
async respond<TData = Record<string, unknown>>(params: {
|
|
913
|
+
history: History;
|
|
742
914
|
step?: StepRef;
|
|
743
|
-
session?:
|
|
915
|
+
session?: SessionState<TData>;
|
|
744
916
|
contextOverride?: Partial<TContext>;
|
|
745
917
|
signal?: AbortSignal;
|
|
746
|
-
}): Promise<{
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
toolCalls?: Array<{ toolName: string; arguments: Record<string, unknown> }>;
|
|
750
|
-
isRouteComplete?: boolean;
|
|
751
|
-
}> {
|
|
752
|
-
const { history, contextOverride, signal } = params;
|
|
918
|
+
}): Promise<AgentResponse<TData>> {
|
|
919
|
+
const { history: simpleHistory, contextOverride, signal } = params;
|
|
920
|
+
const history = normalizeHistory(simpleHistory);
|
|
753
921
|
|
|
754
922
|
// Get current context (may fetch from provider)
|
|
755
923
|
let currentContext = await this.getContext();
|
|
@@ -769,60 +937,34 @@ export class Agent<TContext = unknown> {
|
|
|
769
937
|
|
|
770
938
|
// Initialize or get session (use current session if available)
|
|
771
939
|
let session =
|
|
772
|
-
params.session ||
|
|
940
|
+
cloneDeep(params.session) ||
|
|
941
|
+
cloneDeep(this.currentSession) ||
|
|
942
|
+
(await this.session.getOrCreate());
|
|
773
943
|
|
|
774
|
-
// PHASE 1:
|
|
944
|
+
// PHASE 1: PREPARE - Execute prepare function if current step has one
|
|
775
945
|
if (session.currentRoute && session.currentStep) {
|
|
776
946
|
const currentRoute = this.routes.find(
|
|
777
947
|
(r) => r.id === session.currentRoute?.id
|
|
778
948
|
);
|
|
779
949
|
if (currentRoute) {
|
|
780
950
|
const currentStep = currentRoute.getStep(session.currentStep.id);
|
|
781
|
-
if (currentStep) {
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
toolTransition.spec.tool as ToolRef<TContext, unknown[], unknown>,
|
|
791
|
-
effectiveContext,
|
|
792
|
-
this.updateContext.bind(this),
|
|
793
|
-
history,
|
|
794
|
-
session.data,
|
|
795
|
-
allowedDomains
|
|
796
|
-
);
|
|
797
|
-
|
|
798
|
-
// Update context with tool results
|
|
799
|
-
if (result.contextUpdate) {
|
|
800
|
-
await this.updateContext(
|
|
801
|
-
result.contextUpdate as Partial<TContext>
|
|
802
|
-
);
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
// Update collected data with tool results
|
|
806
|
-
if (result.collectedUpdate) {
|
|
807
|
-
session = await this.updateData(session, result.collectedUpdate);
|
|
808
|
-
logger.debug(
|
|
809
|
-
`[Agent] Tool updated collected data:`,
|
|
810
|
-
result.collectedUpdate
|
|
811
|
-
);
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
logger.debug(
|
|
815
|
-
`[Agent] Executed tool: ${result.toolName} (success: ${result.success})`
|
|
816
|
-
);
|
|
817
|
-
}
|
|
951
|
+
if (currentStep?.prepare) {
|
|
952
|
+
logger.debug(`[Agent] Executing prepare for step: ${currentStep.id}`);
|
|
953
|
+
await this.executePrepareFinalize(
|
|
954
|
+
currentStep.prepare,
|
|
955
|
+
effectiveContext,
|
|
956
|
+
session.data,
|
|
957
|
+
currentRoute,
|
|
958
|
+
currentStep
|
|
959
|
+
);
|
|
818
960
|
}
|
|
819
961
|
}
|
|
820
962
|
}
|
|
821
963
|
|
|
822
964
|
// PHASE 2: ROUTING + STEP SELECTION - Determine which route and step to use (combined)
|
|
823
|
-
let selectedRoute: Route<TContext> | undefined;
|
|
965
|
+
let selectedRoute: Route<TContext, unknown> | undefined;
|
|
824
966
|
let responseDirectives: string[] | undefined;
|
|
825
|
-
let selectedStep: Step<TContext> | undefined;
|
|
967
|
+
let selectedStep: Step<TContext, unknown> | undefined;
|
|
826
968
|
let isRouteComplete = false;
|
|
827
969
|
|
|
828
970
|
// Check for pending transition from previous route completion
|
|
@@ -866,12 +1008,7 @@ export class Agent<TContext = unknown> {
|
|
|
866
1008
|
routes: this.routes,
|
|
867
1009
|
session,
|
|
868
1010
|
history,
|
|
869
|
-
|
|
870
|
-
name: this.options.name,
|
|
871
|
-
goal: this.options.goal,
|
|
872
|
-
description: this.options.description,
|
|
873
|
-
personality: this.options.personality,
|
|
874
|
-
},
|
|
1011
|
+
agentOptions: this.options,
|
|
875
1012
|
provider: this.options.provider,
|
|
876
1013
|
context: effectiveContext,
|
|
877
1014
|
signal,
|
|
@@ -893,13 +1030,18 @@ export class Agent<TContext = unknown> {
|
|
|
893
1030
|
|
|
894
1031
|
// PHASE 3: DETERMINE NEXT STEP - Use step from combined decision or get initial step
|
|
895
1032
|
let message: string;
|
|
896
|
-
|
|
1033
|
+
let toolCalls:
|
|
897
1034
|
| Array<{ toolName: string; arguments: Record<string, unknown> }>
|
|
898
1035
|
| undefined = undefined;
|
|
1036
|
+
let responsePrompt: string;
|
|
1037
|
+
let availableTools: Tool<TContext, unknown[], unknown, unknown>[] = [];
|
|
1038
|
+
let responseSchema: StructuredSchema | undefined;
|
|
1039
|
+
let nextStep: Step<TContext, unknown> | undefined;
|
|
899
1040
|
|
|
900
|
-
|
|
901
|
-
|
|
1041
|
+
// Get last user message (needed for both route and completion handling)
|
|
1042
|
+
const lastUserMessage = getLastMessageFromHistory(history);
|
|
902
1043
|
|
|
1044
|
+
if (selectedRoute && !isRouteComplete) {
|
|
903
1045
|
// If we have a selected step from the combined routing decision, use it
|
|
904
1046
|
if (selectedStep) {
|
|
905
1047
|
nextStep = selectedStep;
|
|
@@ -933,115 +1075,332 @@ export class Agent<TContext = unknown> {
|
|
|
933
1075
|
const lastUserMessage = getLastMessageFromHistory(history);
|
|
934
1076
|
|
|
935
1077
|
// Build response schema for this route (with collect fields from step)
|
|
936
|
-
|
|
1078
|
+
responseSchema = this.responseEngine.responseSchemaForRoute(
|
|
937
1079
|
selectedRoute,
|
|
938
1080
|
nextStep
|
|
939
1081
|
);
|
|
940
1082
|
|
|
941
1083
|
// Build response prompt
|
|
942
|
-
|
|
1084
|
+
responsePrompt = await this.responseEngine.buildResponsePrompt({
|
|
1085
|
+
route: selectedRoute,
|
|
1086
|
+
currentStep: nextStep,
|
|
1087
|
+
rules: selectedRoute.getRules(),
|
|
1088
|
+
prohibitions: selectedRoute.getProhibitions(),
|
|
1089
|
+
directives: responseDirectives,
|
|
1090
|
+
history,
|
|
1091
|
+
lastMessage: lastUserMessage,
|
|
1092
|
+
agentOptions: this.options,
|
|
1093
|
+
// Combine agent and route properties according to the specified logic
|
|
1094
|
+
combinedGuidelines: [
|
|
1095
|
+
...this.getGuidelines(),
|
|
1096
|
+
...selectedRoute.getGuidelines(),
|
|
1097
|
+
],
|
|
1098
|
+
combinedTerms: this.mergeTerms(
|
|
1099
|
+
this.getTerms(),
|
|
1100
|
+
selectedRoute.getTerms()
|
|
1101
|
+
),
|
|
1102
|
+
context: effectiveContext,
|
|
1103
|
+
session,
|
|
1104
|
+
});
|
|
1105
|
+
|
|
1106
|
+
// Collect available tools for AI
|
|
1107
|
+
availableTools = this.collectAvailableTools(
|
|
943
1108
|
selectedRoute,
|
|
944
|
-
nextStep
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1109
|
+
nextStep
|
|
1110
|
+
) as Tool<TContext, unknown[], unknown, unknown>[];
|
|
1111
|
+
} else {
|
|
1112
|
+
// No route selected - generate basic response without route context
|
|
1113
|
+
logger.debug(`[Agent] No route selected, generating basic response`);
|
|
1114
|
+
|
|
1115
|
+
// Build basic response prompt without route context
|
|
1116
|
+
responsePrompt = await this.responseEngine.buildFallbackPrompt({
|
|
948
1117
|
history,
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1118
|
+
agentOptions: this.options,
|
|
1119
|
+
terms: this.getTerms(),
|
|
1120
|
+
guidelines: this.getGuidelines(),
|
|
1121
|
+
context: effectiveContext,
|
|
1122
|
+
session,
|
|
1123
|
+
});
|
|
1124
|
+
|
|
1125
|
+
// Use agent-level tools only
|
|
1126
|
+
availableTools = [...this.tools];
|
|
1127
|
+
responseSchema = undefined;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
// Generate message using AI provider (common for both route and no-route cases)
|
|
1131
|
+
const result = await this.options.provider.generateMessage({
|
|
1132
|
+
prompt: responsePrompt,
|
|
1133
|
+
history,
|
|
1134
|
+
context: effectiveContext,
|
|
1135
|
+
tools: availableTools,
|
|
1136
|
+
signal,
|
|
1137
|
+
parameters: responseSchema
|
|
1138
|
+
? {
|
|
1139
|
+
jsonSchema: responseSchema,
|
|
1140
|
+
schemaName: "response_output",
|
|
1141
|
+
}
|
|
1142
|
+
: undefined,
|
|
1143
|
+
});
|
|
1144
|
+
|
|
1145
|
+
message = result.structured?.message || result.message;
|
|
1146
|
+
|
|
1147
|
+
// Process dynamic tool calls from AI response (common for both route and no-route cases)
|
|
1148
|
+
if (result.structured?.toolCalls) {
|
|
1149
|
+
toolCalls = result.structured.toolCalls;
|
|
1150
|
+
|
|
1151
|
+
// Execute dynamic tool calls
|
|
1152
|
+
if (toolCalls.length > 0) {
|
|
1153
|
+
logger.debug(
|
|
1154
|
+
`[Agent] Executing ${toolCalls.length} dynamic tool calls`
|
|
1155
|
+
);
|
|
1156
|
+
|
|
1157
|
+
for (const toolCall of toolCalls) {
|
|
1158
|
+
const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
|
|
1159
|
+
if (!tool) {
|
|
1160
|
+
logger.warn(`[Agent] Tool not found: ${toolCall.toolName}`);
|
|
1161
|
+
continue;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
const toolExecutor = new ToolExecutor<TContext, unknown>();
|
|
1165
|
+
const toolResult = await toolExecutor.executeTool({
|
|
1166
|
+
tool: tool,
|
|
1167
|
+
context: effectiveContext,
|
|
1168
|
+
updateContext: this.updateContext.bind(this),
|
|
1169
|
+
history,
|
|
1170
|
+
data: session.data,
|
|
1171
|
+
toolArguments: toolCall.arguments,
|
|
1172
|
+
});
|
|
1173
|
+
|
|
1174
|
+
// Update context with tool results
|
|
1175
|
+
if (toolResult.contextUpdate) {
|
|
1176
|
+
await this.updateContext(
|
|
1177
|
+
toolResult.contextUpdate as Partial<TContext>
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
// Update collected data with tool results
|
|
1182
|
+
if (toolResult.dataUpdate) {
|
|
1183
|
+
session = await this.updateData(session, toolResult.dataUpdate);
|
|
1184
|
+
logger.debug(
|
|
1185
|
+
`[Agent] Tool updated collected data:`,
|
|
1186
|
+
toolResult.dataUpdate
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
logger.debug(
|
|
1191
|
+
`[Agent] Executed dynamic tool: ${toolResult.toolName} (success: ${toolResult.success})`
|
|
1192
|
+
);
|
|
955
1193
|
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// TOOL LOOP: Allow AI to make follow-up tool calls after initial tool execution
|
|
1198
|
+
const MAX_TOOL_LOOPS = 5;
|
|
1199
|
+
let toolLoopCount = 0;
|
|
1200
|
+
let hasToolCalls = toolCalls && toolCalls.length > 0;
|
|
1201
|
+
|
|
1202
|
+
while (hasToolCalls && toolLoopCount < MAX_TOOL_LOOPS) {
|
|
1203
|
+
toolLoopCount++;
|
|
1204
|
+
logger.debug(
|
|
1205
|
+
`[Agent] Starting tool loop ${toolLoopCount}/${MAX_TOOL_LOOPS}`
|
|
956
1206
|
);
|
|
957
1207
|
|
|
958
|
-
//
|
|
959
|
-
const
|
|
1208
|
+
// Add tool execution results to history so AI knows what happened
|
|
1209
|
+
const toolResultsEvents: Event[] = [];
|
|
1210
|
+
for (const toolCall of toolCalls || []) {
|
|
1211
|
+
const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
|
|
1212
|
+
if (tool) {
|
|
1213
|
+
toolResultsEvents.push({
|
|
1214
|
+
kind: EventKind.TOOL,
|
|
1215
|
+
source: MessageRole.AGENT,
|
|
1216
|
+
timestamp: new Date().toISOString(),
|
|
1217
|
+
data: {
|
|
1218
|
+
tool_calls: [
|
|
1219
|
+
{
|
|
1220
|
+
tool_id: toolCall.toolName,
|
|
1221
|
+
arguments: toolCall.arguments,
|
|
1222
|
+
result: {
|
|
1223
|
+
data: "Tool executed successfully",
|
|
1224
|
+
},
|
|
1225
|
+
},
|
|
1226
|
+
],
|
|
1227
|
+
},
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
// Create updated history with tool results
|
|
1233
|
+
const updatedHistory = [...history, ...toolResultsEvents];
|
|
1234
|
+
|
|
1235
|
+
// Make follow-up AI call to see if more tools are needed
|
|
1236
|
+
const followUpResult = await this.options.provider.generateMessage({
|
|
960
1237
|
prompt: responsePrompt,
|
|
961
|
-
history,
|
|
1238
|
+
history: updatedHistory,
|
|
962
1239
|
context: effectiveContext,
|
|
963
|
-
|
|
1240
|
+
tools: availableTools,
|
|
964
1241
|
parameters: {
|
|
965
|
-
jsonSchema: responseSchema,
|
|
966
|
-
schemaName: "
|
|
1242
|
+
jsonSchema: responseSchema as StructuredSchema,
|
|
1243
|
+
schemaName: "tool_followup",
|
|
967
1244
|
},
|
|
1245
|
+
signal,
|
|
968
1246
|
});
|
|
969
1247
|
|
|
970
|
-
|
|
1248
|
+
// Check if follow-up call has more tool calls
|
|
1249
|
+
const followUpToolCalls = followUpResult.structured?.toolCalls;
|
|
1250
|
+
hasToolCalls = followUpToolCalls && followUpToolCalls.length > 0;
|
|
1251
|
+
|
|
1252
|
+
if (hasToolCalls) {
|
|
1253
|
+
logger.debug(
|
|
1254
|
+
`[Agent] Follow-up call produced ${
|
|
1255
|
+
followUpToolCalls!.length
|
|
1256
|
+
} additional tool calls`
|
|
1257
|
+
);
|
|
971
1258
|
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1259
|
+
// Execute the follow-up tool calls
|
|
1260
|
+
for (const toolCall of followUpToolCalls!) {
|
|
1261
|
+
const tool = this.findAvailableTool(toolCall.toolName, selectedRoute);
|
|
1262
|
+
if (!tool) {
|
|
1263
|
+
logger.warn(
|
|
1264
|
+
`[Agent] Tool not found in follow-up: ${toolCall.toolName}`
|
|
1265
|
+
);
|
|
1266
|
+
continue;
|
|
1267
|
+
}
|
|
978
1268
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1269
|
+
const toolExecutor = new ToolExecutor<TContext, unknown>();
|
|
1270
|
+
const toolResult = await toolExecutor.executeTool({
|
|
1271
|
+
tool: tool,
|
|
1272
|
+
context: effectiveContext,
|
|
1273
|
+
updateContext: this.updateContext.bind(this),
|
|
1274
|
+
history: updatedHistory,
|
|
1275
|
+
data: session.data,
|
|
1276
|
+
toolArguments: toolCall.arguments,
|
|
1277
|
+
});
|
|
1278
|
+
|
|
1279
|
+
// Update context with follow-up tool results
|
|
1280
|
+
if (toolResult.contextUpdate) {
|
|
1281
|
+
await this.updateContext(
|
|
1282
|
+
toolResult.contextUpdate as Partial<TContext>
|
|
1283
|
+
);
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
if (toolResult.dataUpdate) {
|
|
1287
|
+
session = await this.updateData(session, toolResult.dataUpdate);
|
|
1288
|
+
logger.debug(
|
|
1289
|
+
`[Agent] Follow-up tool updated collected data:`,
|
|
1290
|
+
toolResult.dataUpdate
|
|
1291
|
+
);
|
|
982
1292
|
}
|
|
1293
|
+
|
|
1294
|
+
logger.debug(
|
|
1295
|
+
`[Agent] Executed follow-up tool: ${toolResult.toolName} (success: ${toolResult.success})`
|
|
1296
|
+
);
|
|
983
1297
|
}
|
|
984
1298
|
|
|
985
|
-
//
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
1299
|
+
// Update toolCalls for next iteration or final response
|
|
1300
|
+
toolCalls = followUpToolCalls;
|
|
1301
|
+
} else {
|
|
1302
|
+
logger.debug(
|
|
1303
|
+
`[Agent] Tool loop completed after ${toolLoopCount} iterations`
|
|
1304
|
+
);
|
|
1305
|
+
// Update final message and toolCalls from follow-up result if no more tools
|
|
1306
|
+
message = followUpResult.structured?.message || followUpResult.message;
|
|
1307
|
+
toolCalls = followUpToolCalls || [];
|
|
1308
|
+
break;
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
if (toolLoopCount >= MAX_TOOL_LOOPS) {
|
|
1313
|
+
logger.warn(
|
|
1314
|
+
`[Agent] Tool loop limit reached (${MAX_TOOL_LOOPS}), stopping`
|
|
1315
|
+
);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
// Extract collected data from final response (only for route-based interactions)
|
|
1319
|
+
if (selectedRoute && result.structured && nextStep?.collect) {
|
|
1320
|
+
const collectedData: Record<string, unknown> = {};
|
|
1321
|
+
// The structured response includes both base fields and collected extraction fields
|
|
1322
|
+
const structuredData = result.structured as AgentStructuredResponse &
|
|
1323
|
+
Record<string, unknown>;
|
|
1324
|
+
|
|
1325
|
+
for (const field of nextStep.collect) {
|
|
1326
|
+
if (field in structuredData) {
|
|
1327
|
+
collectedData[field] = structuredData[field];
|
|
989
1328
|
}
|
|
990
1329
|
}
|
|
991
1330
|
|
|
992
|
-
//
|
|
993
|
-
if (
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
"contextUpdate" in result.structured
|
|
997
|
-
) {
|
|
998
|
-
await this.updateContext(
|
|
999
|
-
(result.structured as { contextUpdate?: Partial<TContext> })
|
|
1000
|
-
.contextUpdate as Partial<TContext>
|
|
1001
|
-
);
|
|
1331
|
+
// Merge collected data into session
|
|
1332
|
+
if (Object.keys(collectedData).length > 0) {
|
|
1333
|
+
session = await this.updateData(session, collectedData);
|
|
1334
|
+
logger.debug(`[Agent] Collected data:`, collectedData);
|
|
1002
1335
|
}
|
|
1003
|
-
}
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
// Extract any additional data from structured response
|
|
1339
|
+
if (
|
|
1340
|
+
result.structured &&
|
|
1341
|
+
typeof result.structured === "object" &&
|
|
1342
|
+
"contextUpdate" in result.structured
|
|
1343
|
+
) {
|
|
1344
|
+
await this.updateContext(
|
|
1345
|
+
(result.structured as { contextUpdate?: Partial<TContext> })
|
|
1346
|
+
.contextUpdate as Partial<TContext>
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
// Handle route completion if route is complete
|
|
1351
|
+
if (isRouteComplete) {
|
|
1004
1352
|
// Route is complete - generate completion message then check for onComplete transition
|
|
1005
|
-
const lastUserMessage = getLastMessageFromHistory(history);
|
|
1006
1353
|
|
|
1007
1354
|
// Get endStep spec from route
|
|
1008
|
-
const endStepSpec = selectedRoute
|
|
1355
|
+
const endStepSpec = selectedRoute!.endStepSpec;
|
|
1009
1356
|
|
|
1010
1357
|
// Create a temporary step for completion message generation using endStep configuration
|
|
1011
|
-
const completionStep = new Step<TContext>(
|
|
1012
|
-
|
|
1013
|
-
endStepSpec.
|
|
1014
|
-
|
|
1015
|
-
endStepSpec.
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
"Summarize what was accomplished and confirm completion based on the conversation history and collected data"
|
|
1021
|
-
);
|
|
1358
|
+
const completionStep = new Step<TContext, unknown>(selectedRoute!.id, {
|
|
1359
|
+
description: endStepSpec.description,
|
|
1360
|
+
id: endStepSpec.id || END_ROUTE_ID,
|
|
1361
|
+
collect: endStepSpec.collect,
|
|
1362
|
+
requires: endStepSpec.requires,
|
|
1363
|
+
prompt:
|
|
1364
|
+
endStepSpec.prompt ||
|
|
1365
|
+
"Summarize what was accomplished and confirm completion based on the conversation history and collected data",
|
|
1366
|
+
});
|
|
1022
1367
|
|
|
1023
1368
|
// Build response schema for completion
|
|
1024
1369
|
const responseSchema = this.responseEngine.responseSchemaForRoute(
|
|
1025
|
-
selectedRoute
|
|
1370
|
+
selectedRoute!,
|
|
1026
1371
|
completionStep
|
|
1027
1372
|
);
|
|
1373
|
+
const templateContext = {
|
|
1374
|
+
context: effectiveContext,
|
|
1375
|
+
session,
|
|
1376
|
+
history,
|
|
1377
|
+
};
|
|
1378
|
+
if (!selectedRoute) {
|
|
1379
|
+
throw new Error("Selected route is not defined");
|
|
1380
|
+
}
|
|
1028
1381
|
|
|
1029
1382
|
// Build completion response prompt
|
|
1030
|
-
const completionPrompt = this.responseEngine.buildResponsePrompt(
|
|
1031
|
-
selectedRoute,
|
|
1032
|
-
completionStep,
|
|
1033
|
-
selectedRoute.getRules(),
|
|
1034
|
-
selectedRoute.getProhibitions(),
|
|
1035
|
-
undefined, // No directives for completion
|
|
1383
|
+
const completionPrompt = await this.responseEngine.buildResponsePrompt({
|
|
1384
|
+
route: selectedRoute,
|
|
1385
|
+
currentStep: completionStep,
|
|
1386
|
+
rules: selectedRoute.getRules(),
|
|
1387
|
+
prohibitions: selectedRoute.getProhibitions(),
|
|
1388
|
+
directives: undefined, // No directives for completion
|
|
1036
1389
|
history,
|
|
1037
|
-
lastUserMessage,
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1390
|
+
lastMessage: lastUserMessage,
|
|
1391
|
+
agentOptions: this.options,
|
|
1392
|
+
// Combine agent and route properties according to the specified logic
|
|
1393
|
+
combinedGuidelines: [
|
|
1394
|
+
...this.getGuidelines(),
|
|
1395
|
+
...selectedRoute.getGuidelines(),
|
|
1396
|
+
],
|
|
1397
|
+
combinedTerms: this.mergeTerms(
|
|
1398
|
+
this.getTerms(),
|
|
1399
|
+
selectedRoute.getTerms()
|
|
1400
|
+
),
|
|
1401
|
+
context: effectiveContext,
|
|
1402
|
+
session,
|
|
1403
|
+
});
|
|
1045
1404
|
|
|
1046
1405
|
// Generate completion message using AI provider
|
|
1047
1406
|
const completionResult = await this.options.provider.generateMessage({
|
|
@@ -1076,12 +1435,16 @@ export class Agent<TContext = unknown> {
|
|
|
1076
1435
|
);
|
|
1077
1436
|
|
|
1078
1437
|
if (targetRoute) {
|
|
1438
|
+
const renderedCondition = await render(
|
|
1439
|
+
transitionConfig.condition,
|
|
1440
|
+
templateContext
|
|
1441
|
+
);
|
|
1079
1442
|
// Set pending transition in session
|
|
1080
1443
|
session = {
|
|
1081
1444
|
...session,
|
|
1082
1445
|
pendingTransition: {
|
|
1083
1446
|
targetRouteId: targetRoute.id,
|
|
1084
|
-
condition:
|
|
1447
|
+
condition: renderedCondition,
|
|
1085
1448
|
reason: "route_complete",
|
|
1086
1449
|
},
|
|
1087
1450
|
};
|
|
@@ -1102,18 +1465,14 @@ export class Agent<TContext = unknown> {
|
|
|
1102
1465
|
);
|
|
1103
1466
|
} else {
|
|
1104
1467
|
// Fallback: No routes defined, generate a simple response
|
|
1105
|
-
const fallbackPrompt =
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
.addGlossary(this.terms)
|
|
1114
|
-
.addGuidelines(this.guidelines)
|
|
1115
|
-
.addCapabilities(this.capabilities)
|
|
1116
|
-
.build();
|
|
1468
|
+
const fallbackPrompt = await this.responseEngine.buildFallbackPrompt({
|
|
1469
|
+
history,
|
|
1470
|
+
agentOptions: this.options,
|
|
1471
|
+
terms: this.terms,
|
|
1472
|
+
guidelines: this.guidelines,
|
|
1473
|
+
context: effectiveContext,
|
|
1474
|
+
session,
|
|
1475
|
+
});
|
|
1117
1476
|
|
|
1118
1477
|
const result = await this.options.provider.generateMessage({
|
|
1119
1478
|
prompt: fallbackPrompt,
|
|
@@ -1142,12 +1501,34 @@ export class Agent<TContext = unknown> {
|
|
|
1142
1501
|
session.id &&
|
|
1143
1502
|
this.options.persistence?.autoSave !== false
|
|
1144
1503
|
) {
|
|
1145
|
-
await this.persistenceManager.
|
|
1504
|
+
await this.persistenceManager.saveSessionState(session.id, session);
|
|
1146
1505
|
logger.debug(
|
|
1147
1506
|
`[Agent] Auto-saved session step to persistence: ${session.id}`
|
|
1148
1507
|
);
|
|
1149
1508
|
}
|
|
1150
1509
|
|
|
1510
|
+
// Execute finalize function
|
|
1511
|
+
if (session.currentRoute && session.currentStep) {
|
|
1512
|
+
const currentRoute = this.routes.find(
|
|
1513
|
+
(r) => r.id === session.currentRoute?.id
|
|
1514
|
+
);
|
|
1515
|
+
if (currentRoute) {
|
|
1516
|
+
const currentStep = currentRoute.getStep(session.currentStep.id);
|
|
1517
|
+
if (currentStep?.finalize) {
|
|
1518
|
+
logger.debug(
|
|
1519
|
+
`[Agent] Executing finalize for step: ${currentStep.id}`
|
|
1520
|
+
);
|
|
1521
|
+
await this.executePrepareFinalize(
|
|
1522
|
+
currentStep.finalize,
|
|
1523
|
+
effectiveContext,
|
|
1524
|
+
session.data,
|
|
1525
|
+
currentRoute,
|
|
1526
|
+
currentStep
|
|
1527
|
+
);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1151
1532
|
// Update current session if we have one
|
|
1152
1533
|
if (this.currentSession) {
|
|
1153
1534
|
this.currentSession = session;
|
|
@@ -1171,93 +1552,275 @@ export class Agent<TContext = unknown> {
|
|
|
1171
1552
|
/**
|
|
1172
1553
|
* Get all terms
|
|
1173
1554
|
*/
|
|
1174
|
-
getTerms(): Term[] {
|
|
1555
|
+
getTerms(): Term<TContext>[] {
|
|
1175
1556
|
return [...this.terms];
|
|
1176
1557
|
}
|
|
1177
1558
|
|
|
1178
1559
|
/**
|
|
1179
|
-
* Get all
|
|
1560
|
+
* Get all tools
|
|
1180
1561
|
*/
|
|
1181
|
-
|
|
1182
|
-
return [...this.
|
|
1562
|
+
getTools(): Tool<TContext, unknown[], unknown, unknown>[] {
|
|
1563
|
+
return [...this.tools];
|
|
1183
1564
|
}
|
|
1184
1565
|
|
|
1185
1566
|
/**
|
|
1186
|
-
*
|
|
1567
|
+
* Find an available tool by name for the given route
|
|
1568
|
+
* Route-level tools take precedence over agent-level tools
|
|
1569
|
+
* @private
|
|
1187
1570
|
*/
|
|
1188
|
-
|
|
1189
|
-
|
|
1571
|
+
private findAvailableTool(
|
|
1572
|
+
toolName: string,
|
|
1573
|
+
route?: Route<TContext, unknown>
|
|
1574
|
+
): Tool<TContext, unknown[], unknown, unknown> | undefined {
|
|
1575
|
+
// Check route-level tools first (if route provided)
|
|
1576
|
+
if (route) {
|
|
1577
|
+
const routeTool = route
|
|
1578
|
+
.getTools()
|
|
1579
|
+
.find((tool) => tool.id === toolName || tool.name === toolName);
|
|
1580
|
+
if (routeTool) return routeTool;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
// Fall back to agent-level tools
|
|
1584
|
+
return this.tools.find(
|
|
1585
|
+
(tool) => tool.id === toolName || tool.name === toolName
|
|
1586
|
+
);
|
|
1190
1587
|
}
|
|
1191
1588
|
|
|
1192
1589
|
/**
|
|
1193
|
-
*
|
|
1590
|
+
* Collect all available tools for the given route and step context
|
|
1591
|
+
* @private
|
|
1194
1592
|
*/
|
|
1195
|
-
|
|
1196
|
-
|
|
1593
|
+
private collectAvailableTools(
|
|
1594
|
+
route?: Route<TContext, unknown>,
|
|
1595
|
+
step?: Step<TContext, unknown>
|
|
1596
|
+
): Array<{
|
|
1597
|
+
id: string;
|
|
1598
|
+
name: string;
|
|
1599
|
+
description?: string;
|
|
1600
|
+
parameters?: unknown;
|
|
1601
|
+
}> {
|
|
1602
|
+
const availableTools = new Map<
|
|
1603
|
+
string,
|
|
1604
|
+
Tool<TContext, unknown[], unknown, unknown>
|
|
1605
|
+
>();
|
|
1606
|
+
|
|
1607
|
+
// Add agent-level tools
|
|
1608
|
+
this.tools.forEach((tool) => {
|
|
1609
|
+
availableTools.set(tool.id, tool);
|
|
1610
|
+
});
|
|
1611
|
+
|
|
1612
|
+
// Add route-level tools (these take precedence)
|
|
1613
|
+
if (route) {
|
|
1614
|
+
route.getTools().forEach((tool) => {
|
|
1615
|
+
availableTools.set(tool.id, tool);
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
// Filter by step-level allowed tools if specified
|
|
1620
|
+
if (step?.tools) {
|
|
1621
|
+
const allowedToolIds = new Set<string>();
|
|
1622
|
+
const stepTools: Tool<TContext, unknown[], unknown, unknown>[] = [];
|
|
1623
|
+
|
|
1624
|
+
for (const toolRef of step.tools) {
|
|
1625
|
+
if (typeof toolRef === "string") {
|
|
1626
|
+
// Reference to registered tool
|
|
1627
|
+
allowedToolIds.add(toolRef);
|
|
1628
|
+
} else {
|
|
1629
|
+
// Inline tool definition
|
|
1630
|
+
if (toolRef.id) {
|
|
1631
|
+
allowedToolIds.add(toolRef.id);
|
|
1632
|
+
stepTools.push(toolRef);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
// If step specifies tools, only include those
|
|
1638
|
+
if (allowedToolIds.size > 0) {
|
|
1639
|
+
const filteredTools = new Map<
|
|
1640
|
+
string,
|
|
1641
|
+
Tool<TContext, unknown[], unknown, unknown>
|
|
1642
|
+
>();
|
|
1643
|
+
for (const toolId of allowedToolIds) {
|
|
1644
|
+
const tool = availableTools.get(toolId);
|
|
1645
|
+
if (tool) {
|
|
1646
|
+
filteredTools.set(toolId, tool);
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
// Add inline tools
|
|
1650
|
+
stepTools.forEach((tool) => {
|
|
1651
|
+
if (tool.id) {
|
|
1652
|
+
filteredTools.set(tool.id, tool);
|
|
1653
|
+
}
|
|
1654
|
+
});
|
|
1655
|
+
availableTools.clear();
|
|
1656
|
+
filteredTools.forEach((tool, id) => availableTools.set(id, tool));
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
// Convert to the format expected by AI providers
|
|
1661
|
+
return Array.from(availableTools.values()).map((tool) => ({
|
|
1662
|
+
id: tool.id,
|
|
1663
|
+
name: tool.name || tool.id,
|
|
1664
|
+
description: tool.description,
|
|
1665
|
+
parameters: tool.parameters,
|
|
1666
|
+
}));
|
|
1197
1667
|
}
|
|
1198
1668
|
|
|
1199
1669
|
/**
|
|
1200
|
-
*
|
|
1670
|
+
* Execute a prepare or finalize function/tool
|
|
1671
|
+
* @private
|
|
1201
1672
|
*/
|
|
1202
|
-
|
|
1203
|
-
|
|
1673
|
+
private async executePrepareFinalize(
|
|
1674
|
+
prepareOrFinalize:
|
|
1675
|
+
| string
|
|
1676
|
+
| Tool<TContext, unknown[], unknown, unknown>
|
|
1677
|
+
| ((context: TContext, data?: Partial<unknown>) => void | Promise<void>)
|
|
1678
|
+
| undefined,
|
|
1679
|
+
context: TContext,
|
|
1680
|
+
data?: Partial<unknown>,
|
|
1681
|
+
route?: Route<TContext, unknown>,
|
|
1682
|
+
step?: Step<TContext, unknown>
|
|
1683
|
+
): Promise<void> {
|
|
1684
|
+
if (!prepareOrFinalize) return;
|
|
1685
|
+
|
|
1686
|
+
if (typeof prepareOrFinalize === "function") {
|
|
1687
|
+
// It's a function - call it directly
|
|
1688
|
+
await prepareOrFinalize(context, data);
|
|
1689
|
+
} else {
|
|
1690
|
+
// It's a tool reference - find and execute the tool
|
|
1691
|
+
let tool: Tool<TContext, unknown[], unknown, unknown> | undefined;
|
|
1692
|
+
|
|
1693
|
+
if (typeof prepareOrFinalize === "string") {
|
|
1694
|
+
// Tool ID - find it in available tools
|
|
1695
|
+
const availableTools = new Map<
|
|
1696
|
+
string,
|
|
1697
|
+
Tool<TContext, unknown[], unknown, unknown>
|
|
1698
|
+
>();
|
|
1699
|
+
|
|
1700
|
+
// Add agent-level tools
|
|
1701
|
+
this.tools.forEach((t) => {
|
|
1702
|
+
availableTools.set(t.id, t);
|
|
1703
|
+
});
|
|
1704
|
+
|
|
1705
|
+
// Add route-level tools
|
|
1706
|
+
if (route) {
|
|
1707
|
+
route.getTools().forEach((t) => {
|
|
1708
|
+
availableTools.set(t.id, t);
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
// Add step-level tools
|
|
1713
|
+
if (step?.tools) {
|
|
1714
|
+
for (const toolRef of step.tools) {
|
|
1715
|
+
if (typeof toolRef === "string") {
|
|
1716
|
+
// Keep as is
|
|
1717
|
+
} else if (toolRef.id) {
|
|
1718
|
+
availableTools.set(toolRef.id, toolRef);
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
tool = availableTools.get(prepareOrFinalize);
|
|
1724
|
+
} else {
|
|
1725
|
+
// Tool object - use directly
|
|
1726
|
+
tool = prepareOrFinalize;
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
if (tool) {
|
|
1730
|
+
const toolExecutor = new ToolExecutor<TContext, unknown>();
|
|
1731
|
+
const result = await toolExecutor.executeTool({
|
|
1732
|
+
tool,
|
|
1733
|
+
context,
|
|
1734
|
+
updateContext: this.updateContext.bind(this),
|
|
1735
|
+
history: [], // Empty history for prepare/finalize
|
|
1736
|
+
data,
|
|
1737
|
+
});
|
|
1738
|
+
|
|
1739
|
+
if (!result.success) {
|
|
1740
|
+
logger.error(
|
|
1741
|
+
`[Agent] Tool execution failed in prepare/finalize: ${result.error}`
|
|
1742
|
+
);
|
|
1743
|
+
throw new Error(`Tool execution failed: ${result.error}`);
|
|
1744
|
+
}
|
|
1745
|
+
} else {
|
|
1746
|
+
logger.warn(
|
|
1747
|
+
`[Agent] Tool not found for prepare/finalize: ${
|
|
1748
|
+
typeof prepareOrFinalize === "string"
|
|
1749
|
+
? prepareOrFinalize
|
|
1750
|
+
: "inline tool"
|
|
1751
|
+
}`
|
|
1752
|
+
);
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1204
1755
|
}
|
|
1205
1756
|
|
|
1206
1757
|
/**
|
|
1207
|
-
*
|
|
1758
|
+
* Get all guidelines
|
|
1208
1759
|
*/
|
|
1209
|
-
|
|
1210
|
-
return this.
|
|
1760
|
+
getGuidelines(): Guideline<TContext>[] {
|
|
1761
|
+
return [...this.guidelines];
|
|
1211
1762
|
}
|
|
1212
1763
|
|
|
1213
1764
|
/**
|
|
1214
|
-
* Get
|
|
1215
|
-
* @param routeId - Route ID to check
|
|
1216
|
-
* @returns Filtered domains object, or all domains if route has no restrictions
|
|
1765
|
+
* Get the agent's knowledge base
|
|
1217
1766
|
*/
|
|
1218
|
-
|
|
1219
|
-
|
|
1767
|
+
getKnowledgeBase(): Record<string, unknown> {
|
|
1768
|
+
return { ...this.knowledgeBase };
|
|
1769
|
+
}
|
|
1220
1770
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1771
|
+
/**
|
|
1772
|
+
* Merge terms with route-specific taking precedence on conflicts
|
|
1773
|
+
* @private
|
|
1774
|
+
*/
|
|
1775
|
+
private mergeTerms(
|
|
1776
|
+
agentTerms: Term<TContext>[],
|
|
1777
|
+
routeTerms: Term<TContext>[]
|
|
1778
|
+
): Term<TContext>[] {
|
|
1779
|
+
const merged = new Map<string, Term<TContext>>();
|
|
1780
|
+
|
|
1781
|
+
// Add agent terms first
|
|
1782
|
+
agentTerms.forEach((term) => {
|
|
1783
|
+
const name =
|
|
1784
|
+
typeof term.name === "string" ? term.name : term.name.toString();
|
|
1785
|
+
merged.set(name, term);
|
|
1786
|
+
});
|
|
1787
|
+
|
|
1788
|
+
// Add route terms (these take precedence)
|
|
1789
|
+
routeTerms.forEach((term) => {
|
|
1790
|
+
const name =
|
|
1791
|
+
typeof term.name === "string" ? term.name : term.name.toString();
|
|
1792
|
+
merged.set(name, term);
|
|
1793
|
+
});
|
|
1225
1794
|
|
|
1226
|
-
|
|
1227
|
-
return this.domainRegistry.getFiltered(allowedDomains);
|
|
1795
|
+
return Array.from(merged.values());
|
|
1228
1796
|
}
|
|
1229
1797
|
|
|
1230
1798
|
/**
|
|
1231
|
-
* Get
|
|
1232
|
-
* @param routeTitle - Route title to check
|
|
1233
|
-
* @returns Filtered domains object, or all domains if route has no restrictions
|
|
1799
|
+
* Get the persistence manager (if configured)
|
|
1234
1800
|
*/
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
const route = this.routes.find((r) => r.title === routeTitle);
|
|
1239
|
-
|
|
1240
|
-
if (!route) {
|
|
1241
|
-
// Route not found, return all domains
|
|
1242
|
-
return this.domainRegistry.all();
|
|
1243
|
-
}
|
|
1801
|
+
getPersistenceManager(): PersistenceManager | undefined {
|
|
1802
|
+
return this.persistenceManager;
|
|
1803
|
+
}
|
|
1244
1804
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1805
|
+
/**
|
|
1806
|
+
* Check if persistence is enabled
|
|
1807
|
+
*/
|
|
1808
|
+
hasPersistence(): boolean {
|
|
1809
|
+
return this.persistenceManager !== undefined;
|
|
1247
1810
|
}
|
|
1248
1811
|
|
|
1249
1812
|
/**
|
|
1250
1813
|
* Set the current session for convenience methods
|
|
1251
1814
|
* @param session - Session step to use for subsequent calls
|
|
1252
1815
|
*/
|
|
1253
|
-
setCurrentSession(session:
|
|
1816
|
+
setCurrentSession(session: SessionState): void {
|
|
1254
1817
|
this.currentSession = session;
|
|
1255
1818
|
}
|
|
1256
1819
|
|
|
1257
1820
|
/**
|
|
1258
1821
|
* Get the current session (if set)
|
|
1259
1822
|
*/
|
|
1260
|
-
getCurrentSession():
|
|
1823
|
+
getCurrentSession(): SessionState | undefined {
|
|
1261
1824
|
return this.currentSession;
|
|
1262
1825
|
}
|
|
1263
1826
|
|
|
@@ -1303,11 +1866,12 @@ export class Agent<TContext = unknown> {
|
|
|
1303
1866
|
* const nextResponse = await agent.respond({ history, session: updatedSession });
|
|
1304
1867
|
* }
|
|
1305
1868
|
*/
|
|
1306
|
-
nextStepRoute(
|
|
1869
|
+
async nextStepRoute(
|
|
1307
1870
|
routeIdOrTitle: string,
|
|
1308
|
-
session?:
|
|
1309
|
-
condition?:
|
|
1310
|
-
|
|
1871
|
+
session?: SessionState,
|
|
1872
|
+
condition?: Template<TContext, unknown>,
|
|
1873
|
+
history?: Event[]
|
|
1874
|
+
): Promise<SessionState> {
|
|
1311
1875
|
const targetSession = session || this.currentSession;
|
|
1312
1876
|
|
|
1313
1877
|
if (!targetSession) {
|
|
@@ -1328,12 +1892,19 @@ export class Agent<TContext = unknown> {
|
|
|
1328
1892
|
.join(", ")}`
|
|
1329
1893
|
);
|
|
1330
1894
|
}
|
|
1895
|
+
const templateContext = {
|
|
1896
|
+
context: this.context,
|
|
1897
|
+
session,
|
|
1898
|
+
history,
|
|
1899
|
+
data: this.currentSession?.data,
|
|
1900
|
+
};
|
|
1901
|
+
const renderedCondition = await render(condition, templateContext);
|
|
1331
1902
|
|
|
1332
|
-
const updatedSession:
|
|
1903
|
+
const updatedSession: SessionState = {
|
|
1333
1904
|
...targetSession,
|
|
1334
1905
|
pendingTransition: {
|
|
1335
1906
|
targetRouteId: targetRoute.id,
|
|
1336
|
-
condition,
|
|
1907
|
+
condition: renderedCondition,
|
|
1337
1908
|
reason: "manual",
|
|
1338
1909
|
},
|
|
1339
1910
|
};
|
|
@@ -1349,4 +1920,48 @@ export class Agent<TContext = unknown> {
|
|
|
1349
1920
|
|
|
1350
1921
|
return updatedSession;
|
|
1351
1922
|
}
|
|
1923
|
+
|
|
1924
|
+
/**
|
|
1925
|
+
* Simplified respond method using SessionManager
|
|
1926
|
+
* Automatically manages conversation history through the session
|
|
1927
|
+
*/
|
|
1928
|
+
async chat<TData = Record<string, unknown>>(
|
|
1929
|
+
message?: string,
|
|
1930
|
+
options?: {
|
|
1931
|
+
history?: History; // Optional: override session history for this response
|
|
1932
|
+
contextOverride?: Partial<TContext>;
|
|
1933
|
+
signal?: AbortSignal;
|
|
1934
|
+
}
|
|
1935
|
+
): Promise<AgentResponse<TData>> {
|
|
1936
|
+
// Determine which history to use
|
|
1937
|
+
let history: History;
|
|
1938
|
+
if (options?.history) {
|
|
1939
|
+
// Use provided history for this response only
|
|
1940
|
+
history = options.history;
|
|
1941
|
+
} else {
|
|
1942
|
+
// Add user message to session history if provided
|
|
1943
|
+
if (message) {
|
|
1944
|
+
await this.session.addMessage("user", message);
|
|
1945
|
+
}
|
|
1946
|
+
history = this.session.getHistory();
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
// Get or create session
|
|
1950
|
+
const session = await this.session.getOrCreate();
|
|
1951
|
+
|
|
1952
|
+
// Use existing respond method with session-managed history
|
|
1953
|
+
const result = await this.respond({
|
|
1954
|
+
history,
|
|
1955
|
+
session,
|
|
1956
|
+
contextOverride: options?.contextOverride,
|
|
1957
|
+
signal: options?.signal,
|
|
1958
|
+
});
|
|
1959
|
+
|
|
1960
|
+
// Add agent response to session history (only if not using override history)
|
|
1961
|
+
if (!options?.history) {
|
|
1962
|
+
await this.session.addMessage("assistant", result.message);
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
return result as AgentResponse<TData>;
|
|
1966
|
+
}
|
|
1352
1967
|
}
|