@falai/agent 2.2.4 → 2.4.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 +2 -2
- package/dist/adapters/MemoryAdapter.d.ts.map +1 -1
- package/dist/adapters/MemoryAdapter.js +10 -1
- package/dist/adapters/MemoryAdapter.js.map +1 -1
- package/dist/adapters/MongoAdapter.d.ts.map +1 -1
- package/dist/adapters/MongoAdapter.js +33 -2
- package/dist/adapters/MongoAdapter.js.map +1 -1
- package/dist/adapters/OpenSearchAdapter.d.ts.map +1 -1
- package/dist/adapters/OpenSearchAdapter.js +15 -1
- package/dist/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/adapters/PostgreSQLAdapter.d.ts.map +1 -1
- package/dist/adapters/PostgreSQLAdapter.js +35 -5
- package/dist/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/adapters/PrismaAdapter.d.ts.map +1 -1
- package/dist/adapters/PrismaAdapter.js +58 -15
- package/dist/adapters/PrismaAdapter.js.map +1 -1
- package/dist/adapters/RedisAdapter.d.ts.map +1 -1
- package/dist/adapters/RedisAdapter.js +10 -1
- package/dist/adapters/RedisAdapter.js.map +1 -1
- package/dist/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/adapters/SQLiteAdapter.js +38 -6
- package/dist/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/cjs/adapters/MemoryAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/MemoryAdapter.js +10 -1
- package/dist/cjs/adapters/MemoryAdapter.js.map +1 -1
- package/dist/cjs/adapters/MongoAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/MongoAdapter.js +33 -2
- package/dist/cjs/adapters/MongoAdapter.js.map +1 -1
- package/dist/cjs/adapters/OpenSearchAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/OpenSearchAdapter.js +15 -1
- package/dist/cjs/adapters/OpenSearchAdapter.js.map +1 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/PostgreSQLAdapter.js +35 -5
- package/dist/cjs/adapters/PostgreSQLAdapter.js.map +1 -1
- package/dist/cjs/adapters/PrismaAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/PrismaAdapter.js +58 -15
- package/dist/cjs/adapters/PrismaAdapter.js.map +1 -1
- package/dist/cjs/adapters/RedisAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/RedisAdapter.js +10 -1
- package/dist/cjs/adapters/RedisAdapter.js.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.d.ts.map +1 -1
- package/dist/cjs/adapters/SQLiteAdapter.js +38 -6
- package/dist/cjs/adapters/SQLiteAdapter.js.map +1 -1
- package/dist/cjs/core/Agent.d.ts +28 -18
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +58 -68
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/AutoChainExecutor.d.ts.map +1 -1
- package/dist/cjs/core/AutoChainExecutor.js +14 -20
- package/dist/cjs/core/AutoChainExecutor.js.map +1 -1
- package/dist/cjs/core/BranchEvaluator.d.ts +4 -3
- package/dist/cjs/core/BranchEvaluator.d.ts.map +1 -1
- package/dist/cjs/core/BranchEvaluator.js +18 -23
- package/dist/cjs/core/BranchEvaluator.js.map +1 -1
- package/dist/cjs/core/Flow.d.ts +2 -1
- package/dist/cjs/core/Flow.d.ts.map +1 -1
- package/dist/cjs/core/Flow.js +10 -3
- package/dist/cjs/core/Flow.js.map +1 -1
- package/dist/cjs/core/FlowRouter.d.ts +1 -0
- package/dist/cjs/core/FlowRouter.d.ts.map +1 -1
- package/dist/cjs/core/FlowRouter.js +28 -5
- package/dist/cjs/core/FlowRouter.js.map +1 -1
- package/dist/cjs/core/PersistenceManager.d.ts +3 -0
- package/dist/cjs/core/PersistenceManager.d.ts.map +1 -1
- package/dist/cjs/core/PersistenceManager.js +57 -5
- package/dist/cjs/core/PersistenceManager.js.map +1 -1
- package/dist/cjs/core/PromptComposer.d.ts.map +1 -1
- package/dist/cjs/core/PromptComposer.js +24 -10
- package/dist/cjs/core/PromptComposer.js.map +1 -1
- package/dist/cjs/core/ResponseGenerationError.d.ts +30 -0
- package/dist/cjs/core/ResponseGenerationError.d.ts.map +1 -0
- package/dist/cjs/core/ResponseGenerationError.js +37 -0
- package/dist/cjs/core/ResponseGenerationError.js.map +1 -0
- package/dist/cjs/core/ResponseModal.d.ts +43 -102
- package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
- package/dist/cjs/core/ResponseModal.js +178 -1194
- package/dist/cjs/core/ResponseModal.js.map +1 -1
- package/dist/cjs/core/ResponsePipeline.d.ts +58 -152
- package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/cjs/core/ResponsePipeline.js +408 -457
- package/dist/cjs/core/ResponsePipeline.js.map +1 -1
- package/dist/cjs/core/SessionFinalizer.d.ts +34 -0
- package/dist/cjs/core/SessionFinalizer.d.ts.map +1 -0
- package/dist/cjs/core/SessionFinalizer.js +61 -0
- package/dist/cjs/core/SessionFinalizer.js.map +1 -0
- package/dist/cjs/core/SessionManager.d.ts +1 -1
- package/dist/cjs/core/SessionManager.d.ts.map +1 -1
- package/dist/cjs/core/SessionManager.js +18 -7
- package/dist/cjs/core/SessionManager.js.map +1 -1
- package/dist/cjs/core/SignalCoordinator.d.ts +103 -0
- package/dist/cjs/core/SignalCoordinator.d.ts.map +1 -0
- package/dist/cjs/core/SignalCoordinator.js +207 -0
- package/dist/cjs/core/SignalCoordinator.js.map +1 -0
- package/dist/cjs/core/SignalEvaluator.d.ts +2 -2
- package/dist/cjs/core/SignalEvaluator.d.ts.map +1 -1
- package/dist/cjs/core/SignalEvaluator.js +11 -26
- package/dist/cjs/core/SignalEvaluator.js.map +1 -1
- package/dist/cjs/core/Step.d.ts +3 -1
- package/dist/cjs/core/Step.d.ts.map +1 -1
- package/dist/cjs/core/Step.js +10 -3
- package/dist/cjs/core/Step.js.map +1 -1
- package/dist/cjs/core/StepLifecycle.d.ts +33 -0
- package/dist/cjs/core/StepLifecycle.d.ts.map +1 -0
- package/dist/cjs/core/StepLifecycle.js +97 -0
- package/dist/cjs/core/StepLifecycle.js.map +1 -0
- package/dist/cjs/core/ToolLoopExecutor.d.ts +104 -0
- package/dist/cjs/core/ToolLoopExecutor.d.ts.map +1 -0
- package/dist/cjs/core/ToolLoopExecutor.js +391 -0
- package/dist/cjs/core/ToolLoopExecutor.js.map +1 -0
- package/dist/cjs/core/ToolManager.d.ts +1 -1
- package/dist/cjs/core/ToolManager.d.ts.map +1 -1
- package/dist/cjs/core/ToolManager.js.map +1 -1
- package/dist/cjs/index.d.ts +4 -5
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +7 -6
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.d.ts +2 -0
- package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.js +28 -56
- package/dist/cjs/providers/AnthropicProvider.js.map +1 -1
- package/dist/cjs/providers/DeepSeekProvider.d.ts +25 -21
- package/dist/cjs/providers/DeepSeekProvider.d.ts.map +1 -1
- package/dist/cjs/providers/DeepSeekProvider.js +48 -407
- package/dist/cjs/providers/DeepSeekProvider.js.map +1 -1
- package/dist/cjs/providers/GeminiProvider.d.ts +2 -0
- package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/cjs/providers/GeminiProvider.js +27 -56
- package/dist/cjs/providers/GeminiProvider.js.map +1 -1
- package/dist/cjs/providers/OpenAICompatibleProvider.d.ts +129 -0
- package/dist/cjs/providers/OpenAICompatibleProvider.d.ts.map +1 -0
- package/dist/cjs/providers/OpenAICompatibleProvider.js +485 -0
- package/dist/cjs/providers/OpenAICompatibleProvider.js.map +1 -0
- package/dist/cjs/providers/OpenAIProvider.d.ts +9 -28
- package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.js +23 -417
- package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.d.ts +10 -27
- package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.js +28 -417
- package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
- package/dist/cjs/providers/errorClassification.d.ts +61 -0
- package/dist/cjs/providers/errorClassification.d.ts.map +1 -0
- package/dist/cjs/providers/errorClassification.js +123 -0
- package/dist/cjs/providers/errorClassification.js.map +1 -0
- package/dist/cjs/providers/index.d.ts +4 -0
- package/dist/cjs/providers/index.d.ts.map +1 -1
- package/dist/cjs/providers/index.js +7 -1
- package/dist/cjs/providers/index.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +2 -1
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/ai.d.ts +20 -0
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/cjs/types/errors.d.ts +33 -0
- package/dist/cjs/types/errors.d.ts.map +1 -1
- package/dist/cjs/types/errors.js +37 -1
- package/dist/cjs/types/errors.js.map +1 -1
- package/dist/cjs/types/flow.d.ts +10 -5
- package/dist/cjs/types/flow.d.ts.map +1 -1
- package/dist/cjs/types/history.d.ts +1 -1
- package/dist/cjs/types/history.d.ts.map +1 -1
- package/dist/cjs/types/index.d.ts +5 -4
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js +3 -1
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/persistence.d.ts +43 -2
- package/dist/cjs/types/persistence.d.ts.map +1 -1
- package/dist/cjs/types/session.d.ts +8 -0
- package/dist/cjs/types/session.d.ts.map +1 -1
- package/dist/cjs/types/signals.d.ts +12 -2
- package/dist/cjs/types/signals.d.ts.map +1 -1
- package/dist/cjs/types/template.d.ts +3 -1
- package/dist/cjs/types/template.d.ts.map +1 -1
- package/dist/cjs/types/tool.d.ts +4 -4
- package/dist/cjs/types/tool.d.ts.map +1 -1
- package/dist/cjs/utils/condition.d.ts +19 -0
- package/dist/cjs/utils/condition.d.ts.map +1 -1
- package/dist/cjs/utils/condition.js +86 -15
- package/dist/cjs/utils/condition.js.map +1 -1
- package/dist/cjs/utils/session.d.ts +1 -0
- package/dist/cjs/utils/session.d.ts.map +1 -1
- package/dist/cjs/utils/session.js +1 -0
- package/dist/cjs/utils/session.js.map +1 -1
- package/dist/core/Agent.d.ts +28 -18
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +58 -68
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/AutoChainExecutor.d.ts.map +1 -1
- package/dist/core/AutoChainExecutor.js +14 -20
- package/dist/core/AutoChainExecutor.js.map +1 -1
- package/dist/core/BranchEvaluator.d.ts +4 -3
- package/dist/core/BranchEvaluator.d.ts.map +1 -1
- package/dist/core/BranchEvaluator.js +18 -23
- package/dist/core/BranchEvaluator.js.map +1 -1
- package/dist/core/Flow.d.ts +2 -1
- package/dist/core/Flow.d.ts.map +1 -1
- package/dist/core/Flow.js +10 -3
- package/dist/core/Flow.js.map +1 -1
- package/dist/core/FlowRouter.d.ts +1 -0
- package/dist/core/FlowRouter.d.ts.map +1 -1
- package/dist/core/FlowRouter.js +28 -5
- package/dist/core/FlowRouter.js.map +1 -1
- package/dist/core/PersistenceManager.d.ts +3 -0
- package/dist/core/PersistenceManager.d.ts.map +1 -1
- package/dist/core/PersistenceManager.js +58 -6
- package/dist/core/PersistenceManager.js.map +1 -1
- package/dist/core/PromptComposer.d.ts.map +1 -1
- package/dist/core/PromptComposer.js +24 -10
- package/dist/core/PromptComposer.js.map +1 -1
- package/dist/core/ResponseGenerationError.d.ts +30 -0
- package/dist/core/ResponseGenerationError.d.ts.map +1 -0
- package/dist/core/ResponseGenerationError.js +33 -0
- package/dist/core/ResponseGenerationError.js.map +1 -0
- package/dist/core/ResponseModal.d.ts +43 -102
- package/dist/core/ResponseModal.d.ts.map +1 -1
- package/dist/core/ResponseModal.js +171 -1186
- package/dist/core/ResponseModal.js.map +1 -1
- package/dist/core/ResponsePipeline.d.ts +58 -152
- package/dist/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/core/ResponsePipeline.js +409 -458
- package/dist/core/ResponsePipeline.js.map +1 -1
- package/dist/core/SessionFinalizer.d.ts +34 -0
- package/dist/core/SessionFinalizer.d.ts.map +1 -0
- package/dist/core/SessionFinalizer.js +57 -0
- package/dist/core/SessionFinalizer.js.map +1 -0
- package/dist/core/SessionManager.d.ts +1 -1
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +18 -7
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/SignalCoordinator.d.ts +103 -0
- package/dist/core/SignalCoordinator.d.ts.map +1 -0
- package/dist/core/SignalCoordinator.js +203 -0
- package/dist/core/SignalCoordinator.js.map +1 -0
- package/dist/core/SignalEvaluator.d.ts +2 -2
- package/dist/core/SignalEvaluator.d.ts.map +1 -1
- package/dist/core/SignalEvaluator.js +11 -26
- package/dist/core/SignalEvaluator.js.map +1 -1
- package/dist/core/Step.d.ts +3 -1
- package/dist/core/Step.d.ts.map +1 -1
- package/dist/core/Step.js +10 -3
- package/dist/core/Step.js.map +1 -1
- package/dist/core/StepLifecycle.d.ts +33 -0
- package/dist/core/StepLifecycle.d.ts.map +1 -0
- package/dist/core/StepLifecycle.js +93 -0
- package/dist/core/StepLifecycle.js.map +1 -0
- package/dist/core/ToolLoopExecutor.d.ts +104 -0
- package/dist/core/ToolLoopExecutor.d.ts.map +1 -0
- package/dist/core/ToolLoopExecutor.js +387 -0
- package/dist/core/ToolLoopExecutor.js.map +1 -0
- package/dist/core/ToolManager.d.ts +1 -1
- package/dist/core/ToolManager.d.ts.map +1 -1
- package/dist/core/ToolManager.js.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/providers/AnthropicProvider.d.ts +2 -0
- package/dist/providers/AnthropicProvider.d.ts.map +1 -1
- package/dist/providers/AnthropicProvider.js +22 -50
- package/dist/providers/AnthropicProvider.js.map +1 -1
- package/dist/providers/DeepSeekProvider.d.ts +25 -21
- package/dist/providers/DeepSeekProvider.d.ts.map +1 -1
- package/dist/providers/DeepSeekProvider.js +49 -408
- package/dist/providers/DeepSeekProvider.js.map +1 -1
- package/dist/providers/GeminiProvider.d.ts +2 -0
- package/dist/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/providers/GeminiProvider.js +21 -50
- package/dist/providers/GeminiProvider.js.map +1 -1
- package/dist/providers/OpenAICompatibleProvider.d.ts +129 -0
- package/dist/providers/OpenAICompatibleProvider.d.ts.map +1 -0
- package/dist/providers/OpenAICompatibleProvider.js +481 -0
- package/dist/providers/OpenAICompatibleProvider.js.map +1 -0
- package/dist/providers/OpenAIProvider.d.ts +9 -28
- package/dist/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/OpenAIProvider.js +23 -417
- package/dist/providers/OpenAIProvider.js.map +1 -1
- package/dist/providers/OpenRouterProvider.d.ts +10 -27
- package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/providers/OpenRouterProvider.js +28 -417
- package/dist/providers/OpenRouterProvider.js.map +1 -1
- package/dist/providers/errorClassification.d.ts +61 -0
- package/dist/providers/errorClassification.d.ts.map +1 -0
- package/dist/providers/errorClassification.js +116 -0
- package/dist/providers/errorClassification.js.map +1 -0
- package/dist/providers/index.d.ts +4 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +2 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/types/agent.d.ts +2 -1
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/ai.d.ts +20 -0
- package/dist/types/ai.d.ts.map +1 -1
- package/dist/types/errors.d.ts +33 -0
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/errors.js +34 -0
- package/dist/types/errors.js.map +1 -1
- package/dist/types/flow.d.ts +10 -5
- package/dist/types/flow.d.ts.map +1 -1
- package/dist/types/history.d.ts +1 -1
- package/dist/types/history.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/persistence.d.ts +43 -2
- package/dist/types/persistence.d.ts.map +1 -1
- package/dist/types/session.d.ts +8 -0
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/signals.d.ts +12 -2
- package/dist/types/signals.d.ts.map +1 -1
- package/dist/types/template.d.ts +3 -1
- package/dist/types/template.d.ts.map +1 -1
- package/dist/types/tool.d.ts +4 -4
- package/dist/types/tool.d.ts.map +1 -1
- package/dist/utils/condition.d.ts +19 -0
- package/dist/utils/condition.d.ts.map +1 -1
- package/dist/utils/condition.js +84 -15
- package/dist/utils/condition.js.map +1 -1
- package/dist/utils/session.d.ts +1 -0
- package/dist/utils/session.d.ts.map +1 -1
- package/dist/utils/session.js +1 -0
- package/dist/utils/session.js.map +1 -1
- package/docs/README.md +1 -1
- package/docs/guides/branching.md +1 -1
- package/docs/guides/compaction.md +12 -5
- package/docs/guides/conditions.md +15 -2
- package/docs/guides/error-handling.md +59 -9
- package/docs/guides/instructions.md +2 -2
- package/docs/guides/persistence.md +69 -2
- package/docs/guides/streaming.md +2 -0
- package/docs/migration/README.md +5 -1
- package/docs/migration/v2-3-to-v2-4.md +316 -0
- package/docs/reference/adapters.md +55 -7
- package/docs/reference/branches.md +2 -2
- package/docs/reference/create-agent.md +3 -3
- package/docs/reference/errors.md +66 -1
- package/docs/reference/flow.md +1 -1
- package/docs/reference/instruction.md +4 -4
- package/docs/reference/providers.md +100 -3
- package/docs/reference/signals.md +11 -3
- package/docs/reference/step.md +2 -2
- package/docs/reference/tool.md +3 -1
- package/docs/start/05-go-to-production.md +3 -0
- package/package.json +1 -1
- package/src/adapters/MemoryAdapter.ts +15 -1
- package/src/adapters/MongoAdapter.ts +41 -2
- package/src/adapters/OpenSearchAdapter.ts +24 -1
- package/src/adapters/PostgreSQLAdapter.ts +45 -5
- package/src/adapters/PrismaAdapter.ts +82 -16
- package/src/adapters/RedisAdapter.ts +19 -1
- package/src/adapters/SQLiteAdapter.ts +47 -5
- package/src/core/Agent.ts +70 -85
- package/src/core/AutoChainExecutor.ts +27 -57
- package/src/core/BranchEvaluator.ts +24 -30
- package/src/core/Flow.ts +10 -3
- package/src/core/FlowRouter.ts +36 -4
- package/src/core/PersistenceManager.ts +79 -10
- package/src/core/PromptComposer.ts +25 -12
- package/src/core/ResponseGenerationError.ts +56 -0
- package/src/core/ResponseModal.ts +233 -1482
- package/src/core/ResponsePipeline.ts +492 -662
- package/src/core/SessionFinalizer.ts +78 -0
- package/src/core/SessionManager.ts +21 -9
- package/src/core/SignalCoordinator.ts +263 -0
- package/src/core/SignalEvaluator.ts +12 -29
- package/src/core/Step.ts +11 -3
- package/src/core/StepLifecycle.ts +139 -0
- package/src/core/ToolLoopExecutor.ts +492 -0
- package/src/core/ToolManager.ts +2 -1
- package/src/index.ts +7 -5
- package/src/providers/AnthropicProvider.ts +30 -72
- package/src/providers/DeepSeekProvider.ts +74 -586
- package/src/providers/GeminiProvider.ts +29 -70
- package/src/providers/OpenAICompatibleProvider.ts +738 -0
- package/src/providers/OpenAIProvider.ts +29 -602
- package/src/providers/OpenRouterProvider.ts +38 -596
- package/src/providers/errorClassification.ts +172 -0
- package/src/providers/index.ts +13 -0
- package/src/types/agent.ts +2 -1
- package/src/types/ai.ts +22 -0
- package/src/types/errors.ts +57 -0
- package/src/types/flow.ts +10 -5
- package/src/types/history.ts +1 -2
- package/src/types/index.ts +5 -1
- package/src/types/persistence.ts +50 -2
- package/src/types/session.ts +9 -0
- package/src/types/signals.ts +14 -2
- package/src/types/template.ts +3 -1
- package/src/types/tool.ts +10 -10
- package/src/utils/condition.ts +115 -18
- package/src/utils/session.ts +2 -0
|
@@ -0,0 +1,738 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared base class for OpenAI-compatible chat-completions providers
|
|
3
|
+
* (OpenAI, DeepSeek, OpenRouter).
|
|
4
|
+
*
|
|
5
|
+
* Handles message/history building, tool-call parsing, streaming chunk
|
|
6
|
+
* handling, backup-model fallback, retry wiring, schema passthrough and
|
|
7
|
+
* normalized error wrapping. Subclasses supply the configured client,
|
|
8
|
+
* naming, capabilities and any genuinely provider-specific behavior via
|
|
9
|
+
* the protected hooks.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import OpenAI from "openai";
|
|
13
|
+
import type {
|
|
14
|
+
ChatCompletionChunk,
|
|
15
|
+
ChatCompletionCreateParamsNonStreaming,
|
|
16
|
+
ChatCompletionCreateParamsStreaming,
|
|
17
|
+
} from "openai/resources/chat/completions";
|
|
18
|
+
import { FunctionParameters } from "openai/resources/shared.mjs";
|
|
19
|
+
|
|
20
|
+
import type {
|
|
21
|
+
AiProvider,
|
|
22
|
+
GenerateMessageInput,
|
|
23
|
+
GenerateMessageOutput,
|
|
24
|
+
GenerateMessageStreamChunk,
|
|
25
|
+
AgentStructuredResponse,
|
|
26
|
+
StructuredSchema,
|
|
27
|
+
} from "../types";
|
|
28
|
+
import type { ProviderCapabilities } from "../types/ai";
|
|
29
|
+
import type { HistoryItem } from "../types/history";
|
|
30
|
+
import { withTimeoutAndRetry, logger } from "../utils";
|
|
31
|
+
import {
|
|
32
|
+
classifyProviderError,
|
|
33
|
+
getErrorMessage,
|
|
34
|
+
isBackupEligible,
|
|
35
|
+
toProviderError,
|
|
36
|
+
type ErrorClassificationOptions,
|
|
37
|
+
} from "./errorClassification";
|
|
38
|
+
|
|
39
|
+
const DEFAULT_RETRY_CONFIG = {
|
|
40
|
+
timeout: 60000,
|
|
41
|
+
retries: 3,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Default request parameters shared by OpenAI-compatible providers
|
|
46
|
+
*/
|
|
47
|
+
export type OpenAICompatibleRequestConfig = Partial<
|
|
48
|
+
Omit<ChatCompletionCreateParamsNonStreaming, "model" | "messages">
|
|
49
|
+
>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Initialization values supplied by subclasses
|
|
53
|
+
*/
|
|
54
|
+
export interface OpenAICompatibleProviderInit {
|
|
55
|
+
/** Configured OpenAI SDK client (subclass sets API key, base URL, headers) */
|
|
56
|
+
client: OpenAI;
|
|
57
|
+
/** Primary model */
|
|
58
|
+
model: string;
|
|
59
|
+
/** Backup models to try if primary fails (default: []) */
|
|
60
|
+
backupModels?: string[];
|
|
61
|
+
/** Default request parameters */
|
|
62
|
+
config?: OpenAICompatibleRequestConfig;
|
|
63
|
+
/** Retry configuration */
|
|
64
|
+
retryConfig?: {
|
|
65
|
+
timeout?: number;
|
|
66
|
+
retries?: number;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Base implementation of AiProvider for OpenAI-compatible APIs with
|
|
72
|
+
* backup models and retry logic.
|
|
73
|
+
*/
|
|
74
|
+
export abstract class OpenAICompatibleProvider implements AiProvider {
|
|
75
|
+
public abstract readonly name: string;
|
|
76
|
+
public abstract readonly capabilities: ProviderCapabilities;
|
|
77
|
+
|
|
78
|
+
/** Uppercase tag used in log lines, e.g. "OPENAI" */
|
|
79
|
+
protected abstract readonly logLabel: string;
|
|
80
|
+
/** Human-readable name used in retry/error messages, e.g. "OpenAI" */
|
|
81
|
+
protected abstract readonly displayName: string;
|
|
82
|
+
|
|
83
|
+
protected readonly client: OpenAI;
|
|
84
|
+
protected readonly primaryModel: string;
|
|
85
|
+
protected readonly backupModels: string[];
|
|
86
|
+
protected readonly config?: OpenAICompatibleRequestConfig;
|
|
87
|
+
protected readonly retryConfig: { timeout: number; retries: number };
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Provider-specific error classification signals.
|
|
91
|
+
* model_not_found/model_overloaded historically triggered backup models.
|
|
92
|
+
*/
|
|
93
|
+
protected readonly classificationOptions: ErrorClassificationOptions = {
|
|
94
|
+
overloadedCodes: ["model_not_found", "model_overloaded"],
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
protected constructor(init: OpenAICompatibleProviderInit) {
|
|
98
|
+
this.client = init.client;
|
|
99
|
+
this.primaryModel = init.model;
|
|
100
|
+
this.backupModels = init.backupModels ?? [];
|
|
101
|
+
this.config = init.config;
|
|
102
|
+
this.retryConfig = {
|
|
103
|
+
timeout: init.retryConfig?.timeout || DEFAULT_RETRY_CONFIG.timeout,
|
|
104
|
+
retries: init.retryConfig?.retries || DEFAULT_RETRY_CONFIG.retries,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ---------------------------------------------------------------------
|
|
109
|
+
// Public API
|
|
110
|
+
// ---------------------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
async generateMessage<
|
|
113
|
+
TContext = unknown,
|
|
114
|
+
TStructured = AgentStructuredResponse
|
|
115
|
+
>(
|
|
116
|
+
input: GenerateMessageInput<TContext>
|
|
117
|
+
): Promise<GenerateMessageOutput<TStructured>> {
|
|
118
|
+
return this.generateWithBackup<TContext, TStructured>(input);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async *generateMessageStream<
|
|
122
|
+
TContext = unknown,
|
|
123
|
+
TStructured = AgentStructuredResponse
|
|
124
|
+
>(
|
|
125
|
+
input: GenerateMessageInput<TContext>
|
|
126
|
+
): AsyncGenerator<GenerateMessageStreamChunk<TStructured>> {
|
|
127
|
+
yield* this.generateStreamWithBackup<TContext, TStructured>(input);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ---------------------------------------------------------------------
|
|
131
|
+
// Provider-specific hooks
|
|
132
|
+
// ---------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Generate a structured (JSON schema) response. Default uses the
|
|
136
|
+
* responses.parse API (OpenAI, OpenRouter). Subclasses whose API lacks
|
|
137
|
+
* responses.parse (e.g. DeepSeek) override this to use chat completions
|
|
138
|
+
* with a structured response_format instead.
|
|
139
|
+
*/
|
|
140
|
+
protected async executeStructuredGenerate(
|
|
141
|
+
model: string,
|
|
142
|
+
input: GenerateMessageInput<unknown>,
|
|
143
|
+
jsonSchema: StructuredSchema
|
|
144
|
+
): Promise<GenerateMessageOutput> {
|
|
145
|
+
const response = await this.client.responses.parse({
|
|
146
|
+
model,
|
|
147
|
+
instructions: input.prompt,
|
|
148
|
+
input: "",
|
|
149
|
+
reasoning: {
|
|
150
|
+
effort: input.parameters?.reasoning?.effort || "low",
|
|
151
|
+
},
|
|
152
|
+
text: {
|
|
153
|
+
format: {
|
|
154
|
+
type: "json_schema",
|
|
155
|
+
name: input.parameters?.schemaName || "structured_output",
|
|
156
|
+
// Adapt common schema format to the provider's format
|
|
157
|
+
schema: this.adaptSchema(jsonSchema),
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (!response.output_parsed) {
|
|
163
|
+
throw new Error(`No parsed output returned from ${this.displayName}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const structured = response.output_parsed as AgentStructuredResponse;
|
|
167
|
+
const message = structured.message;
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
message,
|
|
171
|
+
metadata: {
|
|
172
|
+
model: response.model,
|
|
173
|
+
tokensUsed: response.usage?.total_tokens,
|
|
174
|
+
promptTokens: response.usage?.input_tokens,
|
|
175
|
+
completionTokens: response.usage?.output_tokens,
|
|
176
|
+
},
|
|
177
|
+
structured,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* response_format applied to chat-completions requests when a JSON
|
|
183
|
+
* schema is present. Default requests a generic JSON object (parsed at
|
|
184
|
+
* the end); subclasses with native json_schema support in chat
|
|
185
|
+
* completions (e.g. DeepSeek) override this.
|
|
186
|
+
*/
|
|
187
|
+
protected structuredResponseFormat(
|
|
188
|
+
_jsonSchema: StructuredSchema,
|
|
189
|
+
_schemaName: string | undefined
|
|
190
|
+
): ChatCompletionCreateParamsNonStreaming["response_format"] {
|
|
191
|
+
return { type: "json_object" };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Hook for provider-specific streaming request parameters
|
|
196
|
+
* (e.g. DeepSeek's stream_options.include_usage).
|
|
197
|
+
*/
|
|
198
|
+
protected configureStreamParams(
|
|
199
|
+
_params: ChatCompletionCreateParamsStreaming
|
|
200
|
+
): void {
|
|
201
|
+
// Default: no extra parameters
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Hook for provider-specific stream delta handling
|
|
206
|
+
* (e.g. DeepSeek's reasoning_content).
|
|
207
|
+
*/
|
|
208
|
+
protected onStreamDelta(_delta: ChatCompletionChunk.Choice.Delta): void {
|
|
209
|
+
// Default: no extra handling
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// ---------------------------------------------------------------------
|
|
213
|
+
// Shared building blocks
|
|
214
|
+
// ---------------------------------------------------------------------
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Adapt common schema format to the provider's format.
|
|
218
|
+
* OpenAI-compatible APIs use standard JSON Schema, so this is a
|
|
219
|
+
* passthrough.
|
|
220
|
+
*/
|
|
221
|
+
protected adaptSchema(schema: StructuredSchema): Record<string, unknown> {
|
|
222
|
+
// Our StructuredSchema is already JSON Schema compatible
|
|
223
|
+
return schema;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Build OpenAI-formatted messages from HistoryItem[] array.
|
|
228
|
+
* Maps directly to ChatCompletionMessageParam format.
|
|
229
|
+
*/
|
|
230
|
+
protected buildChatMessages(history: HistoryItem[]): Array<unknown> {
|
|
231
|
+
const messages: Array<unknown> = [];
|
|
232
|
+
|
|
233
|
+
for (const item of history) {
|
|
234
|
+
switch (item.role) {
|
|
235
|
+
case "system":
|
|
236
|
+
messages.push({ role: "system", content: item.content });
|
|
237
|
+
break;
|
|
238
|
+
case "user":
|
|
239
|
+
messages.push({ role: "user", content: item.content });
|
|
240
|
+
break;
|
|
241
|
+
case "assistant":
|
|
242
|
+
if (item.tool_calls && item.tool_calls.length > 0) {
|
|
243
|
+
messages.push({
|
|
244
|
+
role: "assistant",
|
|
245
|
+
content: item.content || null,
|
|
246
|
+
tool_calls: item.tool_calls.map((tc) => ({
|
|
247
|
+
id: tc.id,
|
|
248
|
+
type: "function",
|
|
249
|
+
function: {
|
|
250
|
+
name: tc.name,
|
|
251
|
+
arguments: JSON.stringify(tc.arguments),
|
|
252
|
+
},
|
|
253
|
+
})),
|
|
254
|
+
});
|
|
255
|
+
} else {
|
|
256
|
+
messages.push({ role: "assistant", content: item.content || "" });
|
|
257
|
+
}
|
|
258
|
+
break;
|
|
259
|
+
case "tool":
|
|
260
|
+
messages.push({
|
|
261
|
+
role: "tool",
|
|
262
|
+
tool_call_id: item.tool_call_id,
|
|
263
|
+
content:
|
|
264
|
+
typeof item.content === "string"
|
|
265
|
+
? item.content
|
|
266
|
+
: JSON.stringify(item.content),
|
|
267
|
+
});
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return messages;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Map framework tool definitions to OpenAI function tools.
|
|
277
|
+
*/
|
|
278
|
+
private buildToolParams(
|
|
279
|
+
tools: NonNullable<GenerateMessageInput<unknown>["tools"]>
|
|
280
|
+
): ChatCompletionCreateParamsNonStreaming["tools"] {
|
|
281
|
+
return tools.map((tool) => ({
|
|
282
|
+
type: "function" as const,
|
|
283
|
+
function: {
|
|
284
|
+
name: tool.name || tool.id,
|
|
285
|
+
description: tool.description,
|
|
286
|
+
parameters: tool.parameters as FunctionParameters, // JSON schema
|
|
287
|
+
},
|
|
288
|
+
}));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Parse tool calls from a (complete or delta) tool_calls array,
|
|
293
|
+
* tolerating malformed JSON arguments.
|
|
294
|
+
*/
|
|
295
|
+
private parseToolCallArguments(
|
|
296
|
+
rawArguments: string | undefined,
|
|
297
|
+
streaming: boolean
|
|
298
|
+
): Record<string, unknown> {
|
|
299
|
+
if (!rawArguments) {
|
|
300
|
+
return {};
|
|
301
|
+
}
|
|
302
|
+
try {
|
|
303
|
+
return JSON.parse(rawArguments) as Record<string, unknown>;
|
|
304
|
+
} catch (error) {
|
|
305
|
+
logger.warn(
|
|
306
|
+
`[${this.logLabel}] Failed to parse tool call arguments${
|
|
307
|
+
streaming ? " in stream" : ""
|
|
308
|
+
}: ${getErrorMessage(error)}`
|
|
309
|
+
);
|
|
310
|
+
return {};
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Determines if an error should trigger backup model usage.
|
|
316
|
+
* Derived from the normalized error classification.
|
|
317
|
+
*/
|
|
318
|
+
protected shouldUseBackupModel(error: unknown): boolean {
|
|
319
|
+
return isBackupEligible(
|
|
320
|
+
classifyProviderError(error, this.classificationOptions)
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Wrap a terminal failure in a normalized ProviderError.
|
|
326
|
+
*/
|
|
327
|
+
protected wrapTerminalError(error: unknown): Error {
|
|
328
|
+
return toProviderError(error, this.name, this.classificationOptions);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ---------------------------------------------------------------------
|
|
332
|
+
// Generation with backup models
|
|
333
|
+
// ---------------------------------------------------------------------
|
|
334
|
+
|
|
335
|
+
private async generateWithBackup<
|
|
336
|
+
TContext = unknown,
|
|
337
|
+
TStructured = AgentStructuredResponse
|
|
338
|
+
>(
|
|
339
|
+
input: GenerateMessageInput<TContext>
|
|
340
|
+
): Promise<GenerateMessageOutput<TStructured>> {
|
|
341
|
+
// Try primary model first
|
|
342
|
+
try {
|
|
343
|
+
return await this.generateWithModel<TContext, TStructured>(
|
|
344
|
+
this.primaryModel,
|
|
345
|
+
input
|
|
346
|
+
);
|
|
347
|
+
} catch (primaryError: unknown) {
|
|
348
|
+
const primaryErrMsg = getErrorMessage(primaryError);
|
|
349
|
+
logger.warn(
|
|
350
|
+
`[${this.logLabel}] Primary model ${this.primaryModel} failed: ${primaryErrMsg}`
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
if (!this.shouldUseBackupModel(primaryError)) {
|
|
354
|
+
throw this.wrapTerminalError(primaryError);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
logger.debug(`[${this.logLabel}] Trying backup models`);
|
|
358
|
+
|
|
359
|
+
let lastBackupError: unknown = primaryError;
|
|
360
|
+
|
|
361
|
+
for (let i = 0; i < this.backupModels.length; i++) {
|
|
362
|
+
const backupModel = this.backupModels[i];
|
|
363
|
+
logger.debug(
|
|
364
|
+
`[${this.logLabel}] Trying backup model ${i + 1}/${
|
|
365
|
+
this.backupModels.length
|
|
366
|
+
}: ${backupModel}`
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
try {
|
|
370
|
+
const result = await this.generateWithModel<TContext, TStructured>(
|
|
371
|
+
backupModel,
|
|
372
|
+
input
|
|
373
|
+
);
|
|
374
|
+
logger.debug(`[${this.logLabel}] Backup model ${backupModel} succeeded`);
|
|
375
|
+
return result;
|
|
376
|
+
} catch (backupError: unknown) {
|
|
377
|
+
const backupErrMsg = getErrorMessage(backupError);
|
|
378
|
+
logger.warn(
|
|
379
|
+
`[${this.logLabel}] Backup model ${backupModel} failed: ${backupErrMsg}`
|
|
380
|
+
);
|
|
381
|
+
lastBackupError = backupError;
|
|
382
|
+
|
|
383
|
+
if (
|
|
384
|
+
!this.shouldUseBackupModel(backupError) &&
|
|
385
|
+
i < this.backupModels.length - 1
|
|
386
|
+
) {
|
|
387
|
+
logger.debug(
|
|
388
|
+
`[${this.logLabel}] Backup model error doesn't qualify for further attempts`
|
|
389
|
+
);
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const lastBackupErrMsg = getErrorMessage(lastBackupError);
|
|
396
|
+
logger.error(
|
|
397
|
+
`[${this.logLabel}] All models failed. Primary: ${primaryErrMsg}, Last backup: ${lastBackupErrMsg}`
|
|
398
|
+
);
|
|
399
|
+
throw this.wrapTerminalError(lastBackupError);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
private async *generateStreamWithBackup<
|
|
404
|
+
TContext = unknown,
|
|
405
|
+
TStructured = AgentStructuredResponse
|
|
406
|
+
>(
|
|
407
|
+
input: GenerateMessageInput<TContext>
|
|
408
|
+
): AsyncGenerator<GenerateMessageStreamChunk<TStructured>> {
|
|
409
|
+
// Try primary model first
|
|
410
|
+
try {
|
|
411
|
+
yield* this.generateStreamWithModel<TContext, TStructured>(
|
|
412
|
+
this.primaryModel,
|
|
413
|
+
input
|
|
414
|
+
);
|
|
415
|
+
} catch (primaryError: unknown) {
|
|
416
|
+
const primaryErrMsg = getErrorMessage(primaryError);
|
|
417
|
+
logger.warn(
|
|
418
|
+
`[${this.logLabel}] Primary model ${this.primaryModel} failed: ${primaryErrMsg}`
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
if (!this.shouldUseBackupModel(primaryError)) {
|
|
422
|
+
throw this.wrapTerminalError(primaryError);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
logger.debug(`[${this.logLabel}] Trying backup models for streaming`);
|
|
426
|
+
|
|
427
|
+
let lastBackupError: unknown = primaryError;
|
|
428
|
+
|
|
429
|
+
for (let i = 0; i < this.backupModels.length; i++) {
|
|
430
|
+
const backupModel = this.backupModels[i];
|
|
431
|
+
logger.debug(
|
|
432
|
+
`[${this.logLabel}] Trying backup model ${i + 1}/${
|
|
433
|
+
this.backupModels.length
|
|
434
|
+
}: ${backupModel}`
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
try {
|
|
438
|
+
yield* this.generateStreamWithModel<TContext, TStructured>(
|
|
439
|
+
backupModel,
|
|
440
|
+
input
|
|
441
|
+
);
|
|
442
|
+
logger.debug(`[${this.logLabel}] Backup model ${backupModel} succeeded`);
|
|
443
|
+
return;
|
|
444
|
+
} catch (backupError: unknown) {
|
|
445
|
+
const backupErrMsg = getErrorMessage(backupError);
|
|
446
|
+
logger.warn(
|
|
447
|
+
`[${this.logLabel}] Backup model ${backupModel} failed: ${backupErrMsg}`
|
|
448
|
+
);
|
|
449
|
+
lastBackupError = backupError;
|
|
450
|
+
|
|
451
|
+
if (
|
|
452
|
+
!this.shouldUseBackupModel(backupError) &&
|
|
453
|
+
i < this.backupModels.length - 1
|
|
454
|
+
) {
|
|
455
|
+
logger.debug(
|
|
456
|
+
`[${this.logLabel}] Backup model error doesn't qualify for further attempts`
|
|
457
|
+
);
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const lastBackupErrMsg = getErrorMessage(lastBackupError);
|
|
464
|
+
logger.error(
|
|
465
|
+
`[${this.logLabel}] All models failed. Primary: ${primaryErrMsg}, Last backup: ${lastBackupErrMsg}`
|
|
466
|
+
);
|
|
467
|
+
throw this.wrapTerminalError(lastBackupError);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// ---------------------------------------------------------------------
|
|
472
|
+
// Non-streaming generation
|
|
473
|
+
// ---------------------------------------------------------------------
|
|
474
|
+
|
|
475
|
+
private async generateWithModel<
|
|
476
|
+
TContext = unknown,
|
|
477
|
+
TStructured = AgentStructuredResponse
|
|
478
|
+
>(
|
|
479
|
+
model: string,
|
|
480
|
+
input: GenerateMessageInput<TContext>
|
|
481
|
+
): Promise<GenerateMessageOutput<TStructured>> {
|
|
482
|
+
const operation = async (): Promise<GenerateMessageOutput> => {
|
|
483
|
+
// Use structured output path if JSON schema is provided
|
|
484
|
+
if (input.parameters?.jsonSchema) {
|
|
485
|
+
return this.executeStructuredGenerate(
|
|
486
|
+
model,
|
|
487
|
+
input,
|
|
488
|
+
input.parameters.jsonSchema
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
return this.executeChatCompletion(model, input);
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
return withTimeoutAndRetry(
|
|
495
|
+
operation,
|
|
496
|
+
this.retryConfig.timeout,
|
|
497
|
+
this.retryConfig.retries,
|
|
498
|
+
`${this.displayName} ${model}`
|
|
499
|
+
) as Promise<GenerateMessageOutput<TStructured>>;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Non-streaming chat-completions request: builds messages/tools,
|
|
504
|
+
* extracts text and tool calls, and merges structured output.
|
|
505
|
+
*/
|
|
506
|
+
protected async executeChatCompletion(
|
|
507
|
+
model: string,
|
|
508
|
+
input: GenerateMessageInput<unknown>
|
|
509
|
+
): Promise<GenerateMessageOutput> {
|
|
510
|
+
const historyMessages = this.buildChatMessages(input.history);
|
|
511
|
+
historyMessages.push({ role: "user", content: input.prompt });
|
|
512
|
+
|
|
513
|
+
const params: ChatCompletionCreateParamsNonStreaming = {
|
|
514
|
+
model,
|
|
515
|
+
messages:
|
|
516
|
+
historyMessages as ChatCompletionCreateParamsNonStreaming["messages"],
|
|
517
|
+
...this.config,
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
// Override with input parameters if provided
|
|
521
|
+
if (input.parameters?.maxOutputTokens !== undefined) {
|
|
522
|
+
params.max_tokens = input.parameters.maxOutputTokens;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Add tools if provided
|
|
526
|
+
if (input.tools && input.tools.length > 0) {
|
|
527
|
+
params.tools = this.buildToolParams(input.tools);
|
|
528
|
+
params.tool_choice = "auto";
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// Use structured output format if JSON schema is provided
|
|
532
|
+
if (input.parameters?.jsonSchema) {
|
|
533
|
+
params.response_format = this.structuredResponseFormat(
|
|
534
|
+
input.parameters.jsonSchema,
|
|
535
|
+
input.parameters.schemaName
|
|
536
|
+
);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
const response = await this.client.chat.completions.create(params);
|
|
540
|
+
|
|
541
|
+
const message = response.choices[0]?.message?.content || "";
|
|
542
|
+
|
|
543
|
+
let toolCalls: Array<{
|
|
544
|
+
toolName: string;
|
|
545
|
+
arguments: Record<string, unknown>;
|
|
546
|
+
}> = [];
|
|
547
|
+
if (response.choices?.[0]?.message?.tool_calls) {
|
|
548
|
+
toolCalls = response.choices[0].message.tool_calls
|
|
549
|
+
.filter((toolCall) => toolCall.type === "function")
|
|
550
|
+
.map((toolCall) => ({
|
|
551
|
+
toolName: toolCall.function.name,
|
|
552
|
+
arguments: this.parseToolCallArguments(
|
|
553
|
+
toolCall.function.arguments,
|
|
554
|
+
false
|
|
555
|
+
),
|
|
556
|
+
}));
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// Only throw error if we have no text AND no function calls
|
|
560
|
+
if (!message && toolCalls.length === 0) {
|
|
561
|
+
throw new Error(`No response from ${this.displayName}`);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Parse structured output if schema was provided
|
|
565
|
+
let structured: AgentStructuredResponse | undefined;
|
|
566
|
+
if (input.parameters?.jsonSchema && message) {
|
|
567
|
+
try {
|
|
568
|
+
structured = JSON.parse(message) as AgentStructuredResponse;
|
|
569
|
+
} catch (error) {
|
|
570
|
+
logger.warn(`[${this.logLabel}] Failed to parse JSON response:`, error);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// If tools were used, include them in structured response
|
|
575
|
+
if (toolCalls.length > 0) {
|
|
576
|
+
structured = {
|
|
577
|
+
...(structured || {}),
|
|
578
|
+
message: structured?.message || message,
|
|
579
|
+
toolCalls,
|
|
580
|
+
} as AgentStructuredResponse;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return {
|
|
584
|
+
message,
|
|
585
|
+
metadata: {
|
|
586
|
+
model: response.model,
|
|
587
|
+
finishReason: response.choices[0]?.finish_reason,
|
|
588
|
+
tokensUsed: response.usage?.total_tokens,
|
|
589
|
+
promptTokens: response.usage?.prompt_tokens,
|
|
590
|
+
completionTokens: response.usage?.completion_tokens,
|
|
591
|
+
},
|
|
592
|
+
structured,
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// ---------------------------------------------------------------------
|
|
597
|
+
// Streaming generation
|
|
598
|
+
// ---------------------------------------------------------------------
|
|
599
|
+
|
|
600
|
+
private async *generateStreamWithModel<
|
|
601
|
+
TContext = unknown,
|
|
602
|
+
TStructured = AgentStructuredResponse
|
|
603
|
+
>(
|
|
604
|
+
model: string,
|
|
605
|
+
input: GenerateMessageInput<TContext>
|
|
606
|
+
): AsyncGenerator<GenerateMessageStreamChunk<TStructured>> {
|
|
607
|
+
// Build messages from history and append prompt as final user message
|
|
608
|
+
const historyMessages = this.buildChatMessages(input.history);
|
|
609
|
+
historyMessages.push({ role: "user" as const, content: input.prompt });
|
|
610
|
+
|
|
611
|
+
const params: ChatCompletionCreateParamsStreaming = {
|
|
612
|
+
...this.config,
|
|
613
|
+
model,
|
|
614
|
+
messages:
|
|
615
|
+
historyMessages as ChatCompletionCreateParamsNonStreaming["messages"],
|
|
616
|
+
stream: true as const,
|
|
617
|
+
};
|
|
618
|
+
this.configureStreamParams(params);
|
|
619
|
+
|
|
620
|
+
// Override with input parameters if provided
|
|
621
|
+
if (input.parameters?.maxOutputTokens !== undefined) {
|
|
622
|
+
params.max_tokens = input.parameters.maxOutputTokens;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// Add tools if provided
|
|
626
|
+
if (input.tools && input.tools.length > 0) {
|
|
627
|
+
params.tools = this.buildToolParams(input.tools);
|
|
628
|
+
params.tool_choice = "auto";
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// Streaming path does not support responses.parse; if schema present,
|
|
632
|
+
// request structured output and parse at the end.
|
|
633
|
+
if (input.parameters?.jsonSchema) {
|
|
634
|
+
params.response_format = this.structuredResponseFormat(
|
|
635
|
+
input.parameters.jsonSchema,
|
|
636
|
+
input.parameters.schemaName
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
const stream = await this.client.chat.completions.create(params);
|
|
641
|
+
|
|
642
|
+
let accumulated = "";
|
|
643
|
+
let currentModel = model;
|
|
644
|
+
let finishReason: string | undefined;
|
|
645
|
+
let promptTokens: number | undefined;
|
|
646
|
+
let completionTokens: number | undefined;
|
|
647
|
+
let totalTokens: number | undefined;
|
|
648
|
+
const toolCalls: Array<{
|
|
649
|
+
toolName: string;
|
|
650
|
+
arguments: Record<string, unknown>;
|
|
651
|
+
}> = [];
|
|
652
|
+
|
|
653
|
+
for await (const chunk of stream) {
|
|
654
|
+
currentModel = chunk.model;
|
|
655
|
+
|
|
656
|
+
// Some providers include usage in (possibly choice-less) chunks
|
|
657
|
+
if (chunk.usage) {
|
|
658
|
+
promptTokens = chunk.usage.prompt_tokens;
|
|
659
|
+
completionTokens = chunk.usage.completion_tokens;
|
|
660
|
+
totalTokens = chunk.usage.total_tokens;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const choice = chunk.choices?.[0];
|
|
664
|
+
if (!choice) continue;
|
|
665
|
+
|
|
666
|
+
// Extract tool calls from delta
|
|
667
|
+
if (choice.delta?.tool_calls) {
|
|
668
|
+
for (const toolCall of choice.delta.tool_calls) {
|
|
669
|
+
if (toolCall.function) {
|
|
670
|
+
toolCalls.push({
|
|
671
|
+
toolName: toolCall.function.name || "",
|
|
672
|
+
arguments: this.parseToolCallArguments(
|
|
673
|
+
toolCall.function.arguments,
|
|
674
|
+
true
|
|
675
|
+
),
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Provider-specific delta handling (e.g. DeepSeek reasoning_content)
|
|
682
|
+
this.onStreamDelta(choice.delta);
|
|
683
|
+
|
|
684
|
+
const delta = choice.delta?.content || "";
|
|
685
|
+
if (delta) {
|
|
686
|
+
accumulated += delta;
|
|
687
|
+
yield {
|
|
688
|
+
delta,
|
|
689
|
+
accumulated,
|
|
690
|
+
done: false,
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
if (choice.finish_reason) {
|
|
695
|
+
finishReason = choice.finish_reason;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// Parse JSON response if schema was provided
|
|
700
|
+
let structured: TStructured | undefined;
|
|
701
|
+
if (input.parameters?.jsonSchema && accumulated) {
|
|
702
|
+
try {
|
|
703
|
+
structured = JSON.parse(accumulated) as TStructured;
|
|
704
|
+
} catch (error) {
|
|
705
|
+
logger.warn(
|
|
706
|
+
`[${this.logLabel}] Failed to parse JSON response in stream:`,
|
|
707
|
+
error
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// Include tool calls in structured response (even without JSON schema)
|
|
713
|
+
if (toolCalls.length > 0) {
|
|
714
|
+
structured = {
|
|
715
|
+
...(structured || {}),
|
|
716
|
+
message:
|
|
717
|
+
(structured as AgentStructuredResponse | undefined)?.message ||
|
|
718
|
+
accumulated,
|
|
719
|
+
toolCalls,
|
|
720
|
+
} as TStructured;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// Yield final chunk
|
|
724
|
+
yield {
|
|
725
|
+
delta: "",
|
|
726
|
+
accumulated,
|
|
727
|
+
done: true,
|
|
728
|
+
metadata: {
|
|
729
|
+
model: currentModel,
|
|
730
|
+
finishReason,
|
|
731
|
+
tokensUsed: totalTokens,
|
|
732
|
+
promptTokens,
|
|
733
|
+
completionTokens,
|
|
734
|
+
},
|
|
735
|
+
structured,
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
}
|