kagent-ts 0.1.3 → 0.1.5
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/LICENSE +68 -21
- package/README.md +27 -371
- package/dist/compression/progressive-compressor.d.ts +66 -0
- package/dist/compression/progressive-compressor.d.ts.map +1 -0
- package/dist/compression/progressive-compressor.js +367 -0
- package/dist/compression/progressive-compressor.js.map +1 -0
- package/dist/compression/types.d.ts +1 -5
- package/dist/compression/types.d.ts.map +1 -1
- package/dist/context/context-manager.d.ts +34 -15
- package/dist/context/context-manager.d.ts.map +1 -1
- package/dist/context/context-manager.js +78 -28
- package/dist/context/context-manager.js.map +1 -1
- package/dist/context/types.d.ts +20 -4
- package/dist/context/types.d.ts.map +1 -1
- package/dist/core/agent.d.ts +407 -35
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +685 -70
- package/dist/core/agent.js.map +1 -1
- package/dist/core/fusion-agent.d.ts +207 -0
- package/dist/core/fusion-agent.d.ts.map +1 -0
- package/dist/core/fusion-agent.js +769 -0
- package/dist/core/fusion-agent.js.map +1 -0
- package/dist/core/hooks.d.ts +19 -7
- package/dist/core/hooks.d.ts.map +1 -1
- package/dist/core/plan-solve-agent.d.ts +1 -15
- package/dist/core/plan-solve-agent.d.ts.map +1 -1
- package/dist/core/plan-solve-agent.js +144 -117
- package/dist/core/plan-solve-agent.js.map +1 -1
- package/dist/core/react-agent.d.ts +0 -13
- package/dist/core/react-agent.d.ts.map +1 -1
- package/dist/core/react-agent.js +128 -101
- package/dist/core/react-agent.js.map +1 -1
- package/dist/core/response-schema.d.ts +65 -0
- package/dist/core/response-schema.d.ts.map +1 -1
- package/dist/core/response-schema.js +174 -1
- package/dist/core/response-schema.js.map +1 -1
- package/dist/core/system-prompts.d.ts +27 -0
- package/dist/core/system-prompts.d.ts.map +1 -0
- package/dist/core/system-prompts.js +112 -0
- package/dist/core/system-prompts.js.map +1 -0
- package/dist/eval/benchmark.d.ts +81 -0
- package/dist/eval/benchmark.d.ts.map +1 -0
- package/dist/eval/benchmark.js +292 -0
- package/dist/eval/benchmark.js.map +1 -0
- package/dist/eval/eval-runner.d.ts +79 -0
- package/dist/eval/eval-runner.d.ts.map +1 -0
- package/dist/eval/eval-runner.js +252 -0
- package/dist/eval/eval-runner.js.map +1 -0
- package/dist/eval/index.d.ts +7 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js +13 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/eval/tool-call-evaluator.d.ts +72 -0
- package/dist/eval/tool-call-evaluator.d.ts.map +1 -0
- package/dist/eval/tool-call-evaluator.js +265 -0
- package/dist/eval/tool-call-evaluator.js.map +1 -0
- package/dist/eval/types.d.ts +219 -0
- package/dist/eval/types.d.ts.map +1 -0
- package/dist/eval/types.js +3 -0
- package/dist/eval/types.js.map +1 -0
- package/dist/index.d.ts +61 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +121 -8
- package/dist/index.js.map +1 -1
- package/dist/llm/anthropic-provider.d.ts +141 -0
- package/dist/llm/anthropic-provider.d.ts.map +1 -0
- package/dist/llm/anthropic-provider.js +486 -0
- package/dist/llm/anthropic-provider.js.map +1 -0
- package/dist/llm/errors.d.ts +26 -0
- package/dist/llm/errors.d.ts.map +1 -0
- package/dist/llm/errors.js +19 -0
- package/dist/llm/errors.js.map +1 -0
- package/dist/llm/factory.d.ts +73 -0
- package/dist/llm/factory.d.ts.map +1 -0
- package/dist/llm/factory.js +77 -0
- package/dist/llm/factory.js.map +1 -0
- package/dist/llm/fallback-provider.d.ts +47 -0
- package/dist/llm/fallback-provider.d.ts.map +1 -0
- package/dist/llm/fallback-provider.js +91 -0
- package/dist/llm/fallback-provider.js.map +1 -0
- package/dist/llm/interface.d.ts +54 -11
- package/dist/llm/interface.d.ts.map +1 -1
- package/dist/llm/interface.js +34 -0
- package/dist/llm/interface.js.map +1 -1
- package/dist/llm/model-router.d.ts +126 -0
- package/dist/llm/model-router.d.ts.map +1 -0
- package/dist/llm/model-router.js +178 -0
- package/dist/llm/model-router.js.map +1 -0
- package/dist/llm/openai-provider.d.ts +8 -32
- package/dist/llm/openai-provider.d.ts.map +1 -1
- package/dist/llm/openai-provider.js +27 -60
- package/dist/llm/openai-provider.js.map +1 -1
- package/dist/llm/rate-limiter.d.ts +41 -0
- package/dist/llm/rate-limiter.d.ts.map +1 -0
- package/dist/llm/rate-limiter.js +93 -0
- package/dist/llm/rate-limiter.js.map +1 -0
- package/dist/llm/retry.d.ts +26 -0
- package/dist/llm/retry.d.ts.map +1 -0
- package/dist/llm/retry.js +44 -0
- package/dist/llm/retry.js.map +1 -0
- package/dist/llm/token-budget.d.ts +97 -0
- package/dist/llm/token-budget.d.ts.map +1 -0
- package/dist/llm/token-budget.js +115 -0
- package/dist/llm/token-budget.js.map +1 -0
- package/dist/logging/index.d.ts +2 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +7 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/logger.d.ts +38 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +34 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +8 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/mcp-client-manager.d.ts +72 -0
- package/dist/mcp/mcp-client-manager.d.ts.map +1 -0
- package/dist/mcp/mcp-client-manager.js +235 -0
- package/dist/mcp/mcp-client-manager.js.map +1 -0
- package/dist/mcp/mcp-types.d.ts +58 -0
- package/dist/mcp/mcp-types.d.ts.map +1 -0
- package/dist/mcp/mcp-types.js +20 -0
- package/dist/mcp/mcp-types.js.map +1 -0
- package/dist/memory/index.d.ts +3 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +6 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/memory-manager.d.ts +119 -0
- package/dist/memory/memory-manager.d.ts.map +1 -0
- package/dist/memory/memory-manager.js +334 -0
- package/dist/memory/memory-manager.js.map +1 -0
- package/dist/messages/types.d.ts +2 -0
- package/dist/messages/types.d.ts.map +1 -1
- package/dist/orchestrator/index.d.ts +5 -0
- package/dist/orchestrator/index.d.ts.map +1 -0
- package/dist/orchestrator/index.js +13 -0
- package/dist/orchestrator/index.js.map +1 -0
- package/dist/orchestrator/json-extractor.d.ts +18 -0
- package/dist/orchestrator/json-extractor.d.ts.map +1 -0
- package/dist/orchestrator/json-extractor.js +111 -0
- package/dist/orchestrator/json-extractor.js.map +1 -0
- package/dist/orchestrator/orchestrator-agent.d.ts +152 -0
- package/dist/orchestrator/orchestrator-agent.d.ts.map +1 -0
- package/dist/orchestrator/orchestrator-agent.js +675 -0
- package/dist/orchestrator/orchestrator-agent.js.map +1 -0
- package/dist/orchestrator/orchestrator-response.d.ts +40 -0
- package/dist/orchestrator/orchestrator-response.d.ts.map +1 -0
- package/dist/orchestrator/orchestrator-response.js +275 -0
- package/dist/orchestrator/orchestrator-response.js.map +1 -0
- package/dist/orchestrator/orchestrator-types.d.ts +116 -0
- package/dist/orchestrator/orchestrator-types.d.ts.map +1 -0
- package/dist/orchestrator/orchestrator-types.js +3 -0
- package/dist/orchestrator/orchestrator-types.js.map +1 -0
- package/dist/preferences/preference-manager.d.ts +8 -3
- package/dist/preferences/preference-manager.d.ts.map +1 -1
- package/dist/preferences/preference-manager.js +17 -4
- package/dist/preferences/preference-manager.js.map +1 -1
- package/dist/rag/chroma-store.d.ts +52 -0
- package/dist/rag/chroma-store.d.ts.map +1 -0
- package/dist/rag/chroma-store.js +110 -0
- package/dist/rag/chroma-store.js.map +1 -0
- package/dist/rag/document-loader.d.ts +21 -0
- package/dist/rag/document-loader.d.ts.map +1 -0
- package/dist/rag/document-loader.js +129 -0
- package/dist/rag/document-loader.js.map +1 -0
- package/dist/rag/embedding-provider.d.ts +36 -0
- package/dist/rag/embedding-provider.d.ts.map +1 -0
- package/dist/rag/embedding-provider.js +74 -0
- package/dist/rag/embedding-provider.js.map +1 -0
- package/dist/rag/index.d.ts +17 -0
- package/dist/rag/index.d.ts.map +1 -0
- package/dist/rag/index.js +27 -0
- package/dist/rag/index.js.map +1 -0
- package/dist/rag/keyword-index.d.ts +53 -0
- package/dist/rag/keyword-index.d.ts.map +1 -0
- package/dist/rag/keyword-index.js +161 -0
- package/dist/rag/keyword-index.js.map +1 -0
- package/dist/rag/llm-reranker.d.ts +36 -0
- package/dist/rag/llm-reranker.d.ts.map +1 -0
- package/dist/rag/llm-reranker.js +95 -0
- package/dist/rag/llm-reranker.js.map +1 -0
- package/dist/rag/rag-manager.d.ts +54 -0
- package/dist/rag/rag-manager.d.ts.map +1 -0
- package/dist/rag/rag-manager.js +179 -0
- package/dist/rag/rag-manager.js.map +1 -0
- package/dist/rag/rag-types.d.ts +143 -0
- package/dist/rag/rag-types.d.ts.map +1 -0
- package/dist/rag/rag-types.js +9 -0
- package/dist/rag/rag-types.js.map +1 -0
- package/dist/rag/rrf.d.ts +47 -0
- package/dist/rag/rrf.d.ts.map +1 -0
- package/dist/rag/rrf.js +70 -0
- package/dist/rag/rrf.js.map +1 -0
- package/dist/rag/search-knowledge.d.ts +24 -0
- package/dist/rag/search-knowledge.d.ts.map +1 -0
- package/dist/rag/search-knowledge.js +86 -0
- package/dist/rag/search-knowledge.js.map +1 -0
- package/dist/rag/text-splitter.d.ts +25 -0
- package/dist/rag/text-splitter.d.ts.map +1 -0
- package/dist/rag/text-splitter.js +136 -0
- package/dist/rag/text-splitter.js.map +1 -0
- package/dist/rag/vector-store.d.ts +34 -0
- package/dist/rag/vector-store.d.ts.map +1 -0
- package/dist/rag/vector-store.js +73 -0
- package/dist/rag/vector-store.js.map +1 -0
- package/dist/reflection/error-notebook.d.ts +125 -0
- package/dist/reflection/error-notebook.d.ts.map +1 -0
- package/dist/reflection/error-notebook.js +368 -0
- package/dist/reflection/error-notebook.js.map +1 -0
- package/dist/reflection/index.d.ts +8 -0
- package/dist/reflection/index.d.ts.map +1 -0
- package/dist/reflection/index.js +12 -0
- package/dist/reflection/index.js.map +1 -0
- package/dist/reflection/memory-reflector.d.ts +97 -0
- package/dist/reflection/memory-reflector.d.ts.map +1 -0
- package/dist/reflection/memory-reflector.js +215 -0
- package/dist/reflection/memory-reflector.js.map +1 -0
- package/dist/reflection/reflection-agent.d.ts +105 -0
- package/dist/reflection/reflection-agent.d.ts.map +1 -0
- package/dist/reflection/reflection-agent.js +234 -0
- package/dist/reflection/reflection-agent.js.map +1 -0
- package/dist/reflection/reflection-hook.d.ts +50 -0
- package/dist/reflection/reflection-hook.d.ts.map +1 -0
- package/dist/reflection/reflection-hook.js +108 -0
- package/dist/reflection/reflection-hook.js.map +1 -0
- package/dist/rules/project-rules.d.ts +47 -0
- package/dist/rules/project-rules.d.ts.map +1 -0
- package/dist/rules/project-rules.js +166 -0
- package/dist/rules/project-rules.js.map +1 -0
- package/dist/security/boundaries.d.ts +81 -0
- package/dist/security/boundaries.d.ts.map +1 -0
- package/dist/security/boundaries.js +158 -0
- package/dist/security/boundaries.js.map +1 -0
- package/dist/security/index.d.ts +2 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +11 -0
- package/dist/security/index.js.map +1 -0
- package/dist/session/session-types.d.ts +25 -4
- package/dist/session/session-types.d.ts.map +1 -1
- package/dist/skills/file-skill-loader.d.ts +9 -20
- package/dist/skills/file-skill-loader.d.ts.map +1 -1
- package/dist/skills/file-skill-loader.js +35 -164
- package/dist/skills/file-skill-loader.js.map +1 -1
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +1 -2
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/skill-manager.d.ts +22 -29
- package/dist/skills/skill-manager.d.ts.map +1 -1
- package/dist/skills/skill-manager.js +63 -85
- package/dist/skills/skill-manager.js.map +1 -1
- package/dist/skills/types.d.ts +4 -16
- package/dist/skills/types.d.ts.map +1 -1
- package/dist/subagent/index.d.ts +4 -0
- package/dist/subagent/index.d.ts.map +1 -0
- package/dist/subagent/index.js +8 -0
- package/dist/subagent/index.js.map +1 -0
- package/dist/subagent/subagent-loader.d.ts +53 -0
- package/dist/subagent/subagent-loader.d.ts.map +1 -0
- package/dist/subagent/subagent-loader.js +155 -0
- package/dist/subagent/subagent-loader.js.map +1 -0
- package/dist/subagent/subagent-manager.d.ts +161 -0
- package/dist/subagent/subagent-manager.d.ts.map +1 -0
- package/dist/subagent/subagent-manager.js +468 -0
- package/dist/subagent/subagent-manager.js.map +1 -0
- package/dist/subagent/subagent-types.d.ts +77 -0
- package/dist/subagent/subagent-types.d.ts.map +1 -0
- package/dist/subagent/subagent-types.js +3 -0
- package/dist/subagent/subagent-types.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts +3 -0
- package/dist/tools/builtin/bash.d.ts.map +1 -0
- package/dist/tools/builtin/bash.js +87 -0
- package/dist/tools/builtin/bash.js.map +1 -0
- package/dist/tools/builtin/edit-file.d.ts.map +1 -1
- package/dist/tools/builtin/edit-file.js +1 -0
- package/dist/tools/builtin/edit-file.js.map +1 -1
- package/dist/tools/builtin/index.d.ts +14 -0
- package/dist/tools/builtin/index.d.ts.map +1 -1
- package/dist/tools/builtin/index.js +45 -1
- package/dist/tools/builtin/index.js.map +1 -1
- package/dist/tools/builtin/list-errors.d.ts +7 -0
- package/dist/tools/builtin/list-errors.d.ts.map +1 -0
- package/dist/tools/builtin/list-errors.js +64 -0
- package/dist/tools/builtin/list-errors.js.map +1 -0
- package/dist/tools/builtin/list-subagents.d.ts +7 -0
- package/dist/tools/builtin/list-subagents.d.ts.map +1 -0
- package/dist/tools/builtin/list-subagents.js +21 -0
- package/dist/tools/builtin/list-subagents.js.map +1 -0
- package/dist/tools/builtin/recall.d.ts +11 -0
- package/dist/tools/builtin/recall.d.ts.map +1 -0
- package/dist/tools/builtin/recall.js +60 -0
- package/dist/tools/builtin/recall.js.map +1 -0
- package/dist/tools/builtin/remember.d.ts +12 -0
- package/dist/tools/builtin/remember.d.ts.map +1 -0
- package/dist/tools/builtin/remember.js +72 -0
- package/dist/tools/builtin/remember.js.map +1 -0
- package/dist/tools/builtin/skill.d.ts +14 -0
- package/dist/tools/builtin/skill.d.ts.map +1 -0
- package/dist/tools/builtin/skill.js +71 -0
- package/dist/tools/builtin/skill.js.map +1 -0
- package/dist/tools/builtin/spawn-subagent.d.ts +7 -0
- package/dist/tools/builtin/spawn-subagent.d.ts.map +1 -0
- package/dist/tools/builtin/spawn-subagent.js +43 -0
- package/dist/tools/builtin/spawn-subagent.js.map +1 -0
- package/dist/tools/builtin/web-fetch.d.ts +3 -0
- package/dist/tools/builtin/web-fetch.d.ts.map +1 -0
- package/dist/tools/builtin/web-fetch.js +101 -0
- package/dist/tools/builtin/web-fetch.js.map +1 -0
- package/dist/tools/builtin/write-file.d.ts.map +1 -1
- package/dist/tools/builtin/write-file.js +1 -0
- package/dist/tools/builtin/write-file.js.map +1 -1
- package/dist/tools/circuit-breaker.d.ts +19 -10
- package/dist/tools/circuit-breaker.d.ts.map +1 -1
- package/dist/tools/circuit-breaker.js +22 -11
- package/dist/tools/circuit-breaker.js.map +1 -1
- package/dist/tools/error-tracker.d.ts +28 -44
- package/dist/tools/error-tracker.d.ts.map +1 -1
- package/dist/tools/error-tracker.js +39 -156
- package/dist/tools/error-tracker.js.map +1 -1
- package/dist/tools/tool-filter.d.ts +70 -0
- package/dist/tools/tool-filter.d.ts.map +1 -0
- package/dist/tools/tool-filter.js +92 -0
- package/dist/tools/tool-filter.js.map +1 -0
- package/dist/tools/tool-output-truncator.d.ts +36 -0
- package/dist/tools/tool-output-truncator.d.ts.map +1 -0
- package/dist/tools/tool-output-truncator.js +117 -0
- package/dist/tools/tool-output-truncator.js.map +1 -0
- package/dist/tools/tool-registry.d.ts +25 -9
- package/dist/tools/tool-registry.d.ts.map +1 -1
- package/dist/tools/tool-registry.js +77 -28
- package/dist/tools/tool-registry.js.map +1 -1
- package/dist/tools/tool-validator.d.ts +13 -0
- package/dist/tools/tool-validator.d.ts.map +1 -0
- package/dist/tools/tool-validator.js +116 -0
- package/dist/tools/tool-validator.js.map +1 -0
- package/dist/tools/types.d.ts +86 -3
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js +51 -2
- package/dist/tools/types.js.map +1 -1
- package/dist/trace/trace-logger.d.ts +30 -4
- package/dist/trace/trace-logger.d.ts.map +1 -1
- package/dist/trace/trace-logger.js +83 -7
- package/dist/trace/trace-logger.js.map +1 -1
- package/package.json +14 -4
- package/dist/compression/sliding-window.d.ts +0 -21
- package/dist/compression/sliding-window.d.ts.map +0 -1
- package/dist/compression/sliding-window.js +0 -44
- package/dist/compression/sliding-window.js.map +0 -1
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ModelRouter = void 0;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
const logger_1 = require("../logging/logger");
|
|
6
|
+
/**
|
|
7
|
+
* ModelRouter — routes LLM calls to different providers based on task type.
|
|
8
|
+
*
|
|
9
|
+
* Implements `LLMProvider` so it drops in anywhere a plain provider is
|
|
10
|
+
* expected. The default route is `main` — call `.forSubAgent()`,
|
|
11
|
+
* `.forReflection()`, or `.forLightweight()` to get a task-specific
|
|
12
|
+
* provider handle.
|
|
13
|
+
*
|
|
14
|
+
* Each route automatically wraps its model in a fallback chain when
|
|
15
|
+
* `fallbacks` are configured.
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* ```ts
|
|
19
|
+
* const router = new ModelRouter({
|
|
20
|
+
* main: new OpenAIProvider({ model: "gpt-4o" }),
|
|
21
|
+
* subAgent: new OpenAIProvider({ model: "gpt-4o-mini" }),
|
|
22
|
+
* reflection: new AnthropicProvider({ model: "claude-haiku-4-5-20251001" }),
|
|
23
|
+
* fallbacks: [new AnthropicProvider({ model: "claude-sonnet-4-6" })],
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* const agent = new ReActAgent({ llm: router, subAgentsDir: "./subagents" });
|
|
27
|
+
* // Main loop uses gpt-4o; sub-agents use gpt-4o-mini.
|
|
28
|
+
*
|
|
29
|
+
* // For reflection hook:
|
|
30
|
+
* const hook = createReflectionHook({
|
|
31
|
+
* llm: router.forReflection(),
|
|
32
|
+
* notebook: errorNotebook,
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
class ModelRouter {
|
|
37
|
+
config;
|
|
38
|
+
logger;
|
|
39
|
+
constructor(config) {
|
|
40
|
+
if (!config.main) {
|
|
41
|
+
throw new Error("ModelRouter: `main` provider is required.");
|
|
42
|
+
}
|
|
43
|
+
this.config = config;
|
|
44
|
+
this.logger = config.logger ?? new logger_1.ConsoleLogger();
|
|
45
|
+
}
|
|
46
|
+
// ─── LLMProvider Implementation (delegates to main) ──────────────────
|
|
47
|
+
/** The main model identifier. */
|
|
48
|
+
get model() {
|
|
49
|
+
return this.config.main.model;
|
|
50
|
+
}
|
|
51
|
+
async chat(messages, tools, signal) {
|
|
52
|
+
return this.route("main").chat(messages, tools, signal);
|
|
53
|
+
}
|
|
54
|
+
async *chatStream(messages, tools, signal) {
|
|
55
|
+
yield* this.route("main").chatStream(messages, tools, signal);
|
|
56
|
+
}
|
|
57
|
+
getTokenCount(text, model) {
|
|
58
|
+
return this.config.main.getTokenCount(text, model);
|
|
59
|
+
}
|
|
60
|
+
// ─── Route Accessors ─────────────────────────────────────────────────
|
|
61
|
+
/**
|
|
62
|
+
* Get the LLM provider for sub-agents.
|
|
63
|
+
*
|
|
64
|
+
* Delegates to `subAgent` when configured, otherwise falls back to `main`.
|
|
65
|
+
* Wraps the provider with any shared fallback chain.
|
|
66
|
+
*/
|
|
67
|
+
forSubAgent() {
|
|
68
|
+
return this.route("subAgent");
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get the LLM provider for post-execution reflection / QA.
|
|
72
|
+
*
|
|
73
|
+
* Delegates to `reflection` when configured, otherwise falls back to `main`.
|
|
74
|
+
* Wraps the provider with any shared fallback chain.
|
|
75
|
+
*/
|
|
76
|
+
forReflection() {
|
|
77
|
+
return this.route("reflection");
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get the LLM provider for lightweight tasks.
|
|
81
|
+
*
|
|
82
|
+
* Delegates to `lightweight` when configured, otherwise falls back to `main`.
|
|
83
|
+
* Wraps the provider with any shared fallback chain.
|
|
84
|
+
*/
|
|
85
|
+
forLightweight() {
|
|
86
|
+
return this.route("lightweight");
|
|
87
|
+
}
|
|
88
|
+
// ─── Internal ────────────────────────────────────────────────────────
|
|
89
|
+
/**
|
|
90
|
+
* Resolve a route to its effective provider.
|
|
91
|
+
*
|
|
92
|
+
* Priority: route-specific provider → main.
|
|
93
|
+
* If fallbacks are configured, the provider is wrapped in a fallback chain.
|
|
94
|
+
*/
|
|
95
|
+
route(route) {
|
|
96
|
+
const primary = this.resolveRoute(route);
|
|
97
|
+
// If no fallbacks configured, return the primary directly (hot path).
|
|
98
|
+
if (!this.config.fallbacks || this.config.fallbacks.length === 0) {
|
|
99
|
+
return primary;
|
|
100
|
+
}
|
|
101
|
+
// Wrap in a lightweight fallback chain specific to this route.
|
|
102
|
+
return this.createFallbackWrapper(primary, route);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Resolve the primary provider for a route.
|
|
106
|
+
*/
|
|
107
|
+
resolveRoute(route) {
|
|
108
|
+
switch (route) {
|
|
109
|
+
case "main":
|
|
110
|
+
return this.config.main;
|
|
111
|
+
case "subAgent":
|
|
112
|
+
return this.config.subAgent ?? this.config.main;
|
|
113
|
+
case "reflection":
|
|
114
|
+
return this.config.reflection ?? this.config.main;
|
|
115
|
+
case "lightweight":
|
|
116
|
+
return this.config.lightweight ?? this.config.main;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Create a lightweight inline fallback wrapper around a primary provider.
|
|
121
|
+
*
|
|
122
|
+
* This avoids importing FallbackProvider to keep the dependency graph
|
|
123
|
+
* clean. The inline wrapper behaves identically.
|
|
124
|
+
*/
|
|
125
|
+
createFallbackWrapper(primary, route) {
|
|
126
|
+
const chain = [primary, ...this.config.fallbacks];
|
|
127
|
+
const logger = this.logger; // capture for closure
|
|
128
|
+
return {
|
|
129
|
+
get model() {
|
|
130
|
+
return primary.model;
|
|
131
|
+
},
|
|
132
|
+
async chat(messages, tools, signal) {
|
|
133
|
+
let lastError;
|
|
134
|
+
for (let i = 0; i < chain.length; i++) {
|
|
135
|
+
try {
|
|
136
|
+
const response = await chain[i].chat(messages, tools, signal);
|
|
137
|
+
if (i > 0) {
|
|
138
|
+
logger.info("ModelRouter", `Route "${route}" recovered via fallback "${chain[i].model}" (attempt ${i + 1}).`);
|
|
139
|
+
}
|
|
140
|
+
return response;
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
if (!(err instanceof errors_1.LLMNetworkError))
|
|
144
|
+
throw err;
|
|
145
|
+
lastError = err;
|
|
146
|
+
logger.warn("ModelRouter", `Route "${route}": "${chain[i].model}" failed — ${err.message}. ` +
|
|
147
|
+
(i < chain.length - 1 ? "Trying next..." : "Exhausted."));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
throw lastError;
|
|
151
|
+
},
|
|
152
|
+
async *chatStream(messages, tools, signal) {
|
|
153
|
+
let lastError;
|
|
154
|
+
for (let i = 0; i < chain.length; i++) {
|
|
155
|
+
try {
|
|
156
|
+
const stream = chain[i].chatStream(messages, tools, signal);
|
|
157
|
+
if (i > 0) {
|
|
158
|
+
logger.info("ModelRouter", `Route "${route}" stream recovered via "${chain[i].model}".`);
|
|
159
|
+
}
|
|
160
|
+
yield* stream;
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
if (!(err instanceof errors_1.LLMNetworkError))
|
|
165
|
+
throw err;
|
|
166
|
+
lastError = err;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
throw lastError;
|
|
170
|
+
},
|
|
171
|
+
getTokenCount(text, model) {
|
|
172
|
+
return primary.getTokenCount(text, model);
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
exports.ModelRouter = ModelRouter;
|
|
178
|
+
//# sourceMappingURL=model-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-router.js","sourceRoot":"","sources":["../../src/llm/model-router.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,31 +1,17 @@
|
|
|
1
1
|
import { LLMProvider, LLMResponse, LLMStreamEvent } from "./interface";
|
|
2
2
|
import { MessageData } from "../messages/types";
|
|
3
3
|
import { Tool } from "../tools/types";
|
|
4
|
+
export { LLMNetworkError, type NetworkErrorCause, type RetryConfig } from "./errors";
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
+
* @deprecated Use `RetryConfig` from `"./errors"` instead.
|
|
6
7
|
*/
|
|
7
|
-
export type
|
|
8
|
-
/**
|
|
9
|
-
* Thrown by the LLM provider when all retry attempts for a network-related
|
|
10
|
-
* failure have been exhausted. The agent catches this to save a checkpoint
|
|
11
|
-
* and guide the user to resume their session.
|
|
12
|
-
*/
|
|
13
|
-
export declare class LLMNetworkError extends Error {
|
|
14
|
-
readonly cause: NetworkErrorCause;
|
|
15
|
-
constructor(message: string, cause: NetworkErrorCause);
|
|
16
|
-
}
|
|
8
|
+
export type { RetryConfig as OpenAIRetryConfig } from "./errors";
|
|
17
9
|
/**
|
|
18
10
|
* Check whether an error is network-related and thus retryable.
|
|
11
|
+
* OpenAI-provider specific: checks `OpenAI.APIError` status codes.
|
|
19
12
|
*/
|
|
20
13
|
export declare function isNetworkError(error: unknown): boolean;
|
|
21
|
-
|
|
22
|
-
/** Max retry attempts for network errors (default: 3). */
|
|
23
|
-
maxRetries?: number;
|
|
24
|
-
/** Initial backoff delay in ms (default: 1000). */
|
|
25
|
-
baseDelayMs?: number;
|
|
26
|
-
/** Maximum backoff delay in ms (default: 30000). */
|
|
27
|
-
maxDelayMs?: number;
|
|
28
|
-
}
|
|
14
|
+
import { type RetryConfig } from "./errors";
|
|
29
15
|
/**
|
|
30
16
|
* Configuration options for the OpenAI LLM provider.
|
|
31
17
|
*/
|
|
@@ -36,7 +22,7 @@ export interface OpenAIConfig {
|
|
|
36
22
|
maxTokens?: number;
|
|
37
23
|
baseURL?: string;
|
|
38
24
|
/** Retry configuration for network resilience. */
|
|
39
|
-
retry?:
|
|
25
|
+
retry?: RetryConfig;
|
|
40
26
|
/** Request timeout in ms (default: none — SDK default ~10 min). */
|
|
41
27
|
timeout?: number;
|
|
42
28
|
}
|
|
@@ -58,7 +44,7 @@ export declare class OpenAIProvider implements LLMProvider {
|
|
|
58
44
|
private retryConfig;
|
|
59
45
|
private timeout;
|
|
60
46
|
constructor(config: OpenAIConfig);
|
|
61
|
-
chat(messages: MessageData[], tools?: Tool[]): Promise<LLMResponse>;
|
|
47
|
+
chat(messages: MessageData[], tools?: Tool[], signal?: AbortSignal): Promise<LLMResponse>;
|
|
62
48
|
/**
|
|
63
49
|
* Streaming chat completion.
|
|
64
50
|
*
|
|
@@ -69,7 +55,7 @@ export declare class OpenAIProvider implements LLMProvider {
|
|
|
69
55
|
* drops mid-response, the consumer sees an incomplete stream and the
|
|
70
56
|
* agent's outer loop handles the error on the next LLM call.
|
|
71
57
|
*/
|
|
72
|
-
chatStream(messages: MessageData[], tools?: Tool[]): AsyncIterable<LLMStreamEvent>;
|
|
58
|
+
chatStream(messages: MessageData[], tools?: Tool[], signal?: AbortSignal): AsyncIterable<LLMStreamEvent>;
|
|
73
59
|
/**
|
|
74
60
|
* Count tokens using tiktoken (with model-aware encoding) when available.
|
|
75
61
|
* Falls back to character-based estimation if tiktoken is not installed.
|
|
@@ -78,15 +64,5 @@ export declare class OpenAIProvider implements LLMProvider {
|
|
|
78
64
|
* @param model Optional model override. Defaults to this provider's model.
|
|
79
65
|
*/
|
|
80
66
|
getTokenCount(text: string, model?: string): number;
|
|
81
|
-
/**
|
|
82
|
-
* Wrap an async operation with network-error retry logic.
|
|
83
|
-
*
|
|
84
|
-
* Retry strategy:
|
|
85
|
-
* - Only network-related errors (timeout, connection reset, 429, 5xx) are retried.
|
|
86
|
-
* - Uses exponential backoff with full jitter: delay = base * 2^attempt * random(0.5, 1.0).
|
|
87
|
-
* - Non-retryable errors (401, 400, abort) propagate immediately.
|
|
88
|
-
* - After all retries are exhausted, throws `LLMNetworkError`.
|
|
89
|
-
*/
|
|
90
|
-
private withRetry;
|
|
91
67
|
}
|
|
92
68
|
//# sourceMappingURL=openai-provider.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-provider.d.ts","sourceRoot":"","sources":["../../src/llm/openai-provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"openai-provider.d.ts","sourceRoot":"","sources":["../../src/llm/openai-provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAC7F,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAKtC,OAAO,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAIrF;;GAEG;AACH,YAAY,EAAE,WAAW,IAAI,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAIjE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAyBtD;AAwBD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAK5C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID;;;;;;;;;GASG;AACH,qBAAa,cAAe,YAAW,WAAW;IAChD,SAAgB,KAAK,EAAE,MAAM,CAAC;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,OAAO,CAAqB;gBAExB,MAAM,EAAE,YAAY;IAuB1B,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IA6D/F;;;;;;;;;OASG;IACI,UAAU,CACf,QAAQ,EAAE,WAAW,EAAE,EACvB,KAAK,CAAC,EAAE,IAAI,EAAE,EACd,MAAM,CAAC,EAAE,WAAW,GACnB,aAAa,CAAC,cAAc,CAAC;IA0EhC;;;;;;OAMG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;CAGpD"}
|
|
@@ -6,26 +6,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.OpenAIProvider = exports.LLMNetworkError = void 0;
|
|
7
7
|
exports.isNetworkError = isNetworkError;
|
|
8
8
|
const openai_1 = __importDefault(require("openai"));
|
|
9
|
+
const interface_1 = require("./interface");
|
|
9
10
|
const token_counter_1 = require("../utils/token-counter");
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*/
|
|
15
|
-
class LLMNetworkError extends Error {
|
|
16
|
-
cause;
|
|
17
|
-
constructor(message, cause) {
|
|
18
|
-
super(message);
|
|
19
|
-
this.name = "LLMNetworkError";
|
|
20
|
-
this.cause = cause;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
exports.LLMNetworkError = LLMNetworkError;
|
|
11
|
+
// ─── Shared error types (re-exported for backward compatibility) ─────────────
|
|
12
|
+
var errors_1 = require("./errors");
|
|
13
|
+
Object.defineProperty(exports, "LLMNetworkError", { enumerable: true, get: function () { return errors_1.LLMNetworkError; } });
|
|
14
|
+
// ─── OpenAI-specific network error helpers ───────────────────────────────────
|
|
24
15
|
/**
|
|
25
16
|
* Check whether an error is network-related and thus retryable.
|
|
17
|
+
* OpenAI-provider specific: checks `OpenAI.APIError` status codes.
|
|
26
18
|
*/
|
|
27
19
|
function isNetworkError(error) {
|
|
28
|
-
if (error instanceof LLMNetworkError)
|
|
20
|
+
if (error instanceof Error && error.name === "LLMNetworkError")
|
|
29
21
|
return true;
|
|
30
22
|
if (error instanceof openai_1.default.APIError) {
|
|
31
23
|
// 429 (rate-limit) and 5xx (server) are retryable
|
|
@@ -44,13 +36,13 @@ function isNetworkError(error) {
|
|
|
44
36
|
msg.includes("fetch failed") ||
|
|
45
37
|
msg.includes("network") ||
|
|
46
38
|
msg.includes("socket hang up") ||
|
|
47
|
-
msg.includes("econnaborted")
|
|
48
|
-
msg.includes("abort"));
|
|
39
|
+
msg.includes("econnaborted"));
|
|
49
40
|
}
|
|
50
41
|
return false;
|
|
51
42
|
}
|
|
52
43
|
/**
|
|
53
44
|
* Map a raw error to its NetworkErrorCause category.
|
|
45
|
+
* OpenAI-provider specific: checks `OpenAI.APIError` status codes.
|
|
54
46
|
*/
|
|
55
47
|
function classifyError(error) {
|
|
56
48
|
if (error instanceof openai_1.default.APIError) {
|
|
@@ -74,7 +66,8 @@ function classifyError(error) {
|
|
|
74
66
|
}
|
|
75
67
|
return "unknown_network";
|
|
76
68
|
}
|
|
77
|
-
|
|
69
|
+
const retry_1 = require("./retry");
|
|
70
|
+
// ─── OpenAIProvider ──────────────────────────────────────────────────────────
|
|
78
71
|
/**
|
|
79
72
|
* OpenAI implementation of the LLMProvider interface.
|
|
80
73
|
* Uses the official `openai` npm package.
|
|
@@ -112,7 +105,7 @@ class OpenAIProvider {
|
|
|
112
105
|
maxDelayMs: config.retry?.maxDelayMs ?? 30000,
|
|
113
106
|
};
|
|
114
107
|
}
|
|
115
|
-
async chat(messages, tools) {
|
|
108
|
+
async chat(messages, tools, signal) {
|
|
116
109
|
// Convert internal Tool definitions to OpenAI tool format
|
|
117
110
|
const openaiTools = tools?.map((t) => ({
|
|
118
111
|
type: "function",
|
|
@@ -122,16 +115,16 @@ class OpenAIProvider {
|
|
|
122
115
|
parameters: t.parameters,
|
|
123
116
|
},
|
|
124
117
|
}));
|
|
125
|
-
const response = await
|
|
118
|
+
const response = await (0, retry_1.withRetry)(() => this.client.chat.completions.create({
|
|
126
119
|
model: this.model,
|
|
127
120
|
messages: messages,
|
|
128
121
|
temperature: this.temperature,
|
|
129
122
|
max_tokens: this.maxTokens,
|
|
130
123
|
tools: openaiTools,
|
|
131
|
-
}, { timeout: this.timeout }));
|
|
124
|
+
}, { timeout: this.timeout, signal }), this.retryConfig, { isRetryable: isNetworkError, classifyError });
|
|
132
125
|
const choice = response.choices[0];
|
|
133
126
|
const message = choice.message;
|
|
134
|
-
|
|
127
|
+
const result = {
|
|
135
128
|
content: message.content ?? "",
|
|
136
129
|
tool_calls: message.tool_calls?.map((tc) => ({
|
|
137
130
|
id: tc.id,
|
|
@@ -148,7 +141,16 @@ class OpenAIProvider {
|
|
|
148
141
|
total_tokens: response.usage.total_tokens,
|
|
149
142
|
}
|
|
150
143
|
: undefined,
|
|
144
|
+
stop_reason: choice.finish_reason ?? undefined,
|
|
151
145
|
};
|
|
146
|
+
// Flag response-level quality issues
|
|
147
|
+
if (choice.finish_reason === "length") {
|
|
148
|
+
result.responseError = {
|
|
149
|
+
code: interface_1.LLMResponseErrorCode.MAX_TOKENS,
|
|
150
|
+
message: "Response truncated: max_tokens reached. Content or tool call arguments may be incomplete.",
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
152
154
|
}
|
|
153
155
|
/**
|
|
154
156
|
* Streaming chat completion.
|
|
@@ -160,7 +162,7 @@ class OpenAIProvider {
|
|
|
160
162
|
* drops mid-response, the consumer sees an incomplete stream and the
|
|
161
163
|
* agent's outer loop handles the error on the next LLM call.
|
|
162
164
|
*/
|
|
163
|
-
async *chatStream(messages, tools) {
|
|
165
|
+
async *chatStream(messages, tools, signal) {
|
|
164
166
|
const openaiTools = tools?.map((t) => ({
|
|
165
167
|
type: "function",
|
|
166
168
|
function: {
|
|
@@ -171,7 +173,7 @@ class OpenAIProvider {
|
|
|
171
173
|
}));
|
|
172
174
|
// Retry only the initial stream creation — not mid-stream drops.
|
|
173
175
|
// Use async wrapper so TypeScript treats APIPromise → Promise correctly.
|
|
174
|
-
const stream = await
|
|
176
|
+
const stream = await (0, retry_1.withRetry)(async () => (await this.client.chat.completions.create({
|
|
175
177
|
model: this.model,
|
|
176
178
|
messages: messages,
|
|
177
179
|
temperature: this.temperature,
|
|
@@ -179,7 +181,7 @@ class OpenAIProvider {
|
|
|
179
181
|
tools: openaiTools,
|
|
180
182
|
stream: true,
|
|
181
183
|
stream_options: { include_usage: true },
|
|
182
|
-
}, { timeout: this.timeout })));
|
|
184
|
+
}, { timeout: this.timeout, signal })), this.retryConfig, { isRetryable: isNetworkError, classifyError });
|
|
183
185
|
let emittedDone = false;
|
|
184
186
|
for await (const chunk of stream) {
|
|
185
187
|
const delta = chunk.choices?.[0]?.delta;
|
|
@@ -227,41 +229,6 @@ class OpenAIProvider {
|
|
|
227
229
|
getTokenCount(text, model) {
|
|
228
230
|
return (0, token_counter_1.countTokens)(text, model ?? this.model);
|
|
229
231
|
}
|
|
230
|
-
// ─── Private Helpers ────────────────────────────────────────────────────
|
|
231
|
-
/**
|
|
232
|
-
* Wrap an async operation with network-error retry logic.
|
|
233
|
-
*
|
|
234
|
-
* Retry strategy:
|
|
235
|
-
* - Only network-related errors (timeout, connection reset, 429, 5xx) are retried.
|
|
236
|
-
* - Uses exponential backoff with full jitter: delay = base * 2^attempt * random(0.5, 1.0).
|
|
237
|
-
* - Non-retryable errors (401, 400, abort) propagate immediately.
|
|
238
|
-
* - After all retries are exhausted, throws `LLMNetworkError`.
|
|
239
|
-
*/
|
|
240
|
-
async withRetry(fn) {
|
|
241
|
-
const { maxRetries, baseDelayMs, maxDelayMs } = this.retryConfig;
|
|
242
|
-
let lastError;
|
|
243
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
244
|
-
try {
|
|
245
|
-
return await fn();
|
|
246
|
-
}
|
|
247
|
-
catch (error) {
|
|
248
|
-
lastError = error;
|
|
249
|
-
// Non-network errors propagate immediately (e.g. invalid API key)
|
|
250
|
-
if (!isNetworkError(error))
|
|
251
|
-
throw error;
|
|
252
|
-
if (attempt >= maxRetries)
|
|
253
|
-
break; // all retries exhausted
|
|
254
|
-
// Exponential backoff with full jitter
|
|
255
|
-
const delay = Math.min(baseDelayMs * Math.pow(2, attempt) * (0.5 + Math.random() * 0.5), maxDelayMs);
|
|
256
|
-
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
|
257
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
// All retries exhausted — wrap the final error
|
|
261
|
-
const cause = classifyError(lastError);
|
|
262
|
-
const message = lastError instanceof Error ? lastError.message : String(lastError);
|
|
263
|
-
throw new LLMNetworkError(message, cause);
|
|
264
|
-
}
|
|
265
232
|
}
|
|
266
233
|
exports.OpenAIProvider = OpenAIProvider;
|
|
267
234
|
//# sourceMappingURL=openai-provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openai-provider.js","sourceRoot":"","sources":["../../src/llm/openai-provider.ts"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"openai-provider.js","sourceRoot":"","sources":["../../src/llm/openai-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { LLMProvider, LLMResponse, LLMStreamEvent } from "./interface";
|
|
2
|
+
import { MessageData } from "../messages/types";
|
|
3
|
+
import { Tool } from "../tools/types";
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for the RateLimitedProvider.
|
|
6
|
+
*/
|
|
7
|
+
export interface RateLimitedProviderConfig {
|
|
8
|
+
/** The underlying LLM provider to wrap. */
|
|
9
|
+
provider: LLMProvider;
|
|
10
|
+
/** Maximum LLM calls per minute. */
|
|
11
|
+
maxCallsPerMinute: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* LLMProvider wrapper that enforces a maximum call rate.
|
|
15
|
+
*
|
|
16
|
+
* Calls that would exceed the limit are delayed until a slot opens in
|
|
17
|
+
* the 1-minute sliding window. This prevents the agent from hitting
|
|
18
|
+
* provider rate limits (HTTP 429) during high-throughput scenarios.
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* ```ts
|
|
22
|
+
* const provider = new RateLimitedProvider({
|
|
23
|
+
* provider: new OpenAIProvider({ ... }),
|
|
24
|
+
* maxCallsPerMinute: 500,
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare class RateLimitedProvider implements LLMProvider {
|
|
29
|
+
private provider;
|
|
30
|
+
private limiter;
|
|
31
|
+
constructor(config: RateLimitedProviderConfig);
|
|
32
|
+
get model(): string;
|
|
33
|
+
chat(messages: MessageData[], tools?: Tool[], signal?: AbortSignal): Promise<LLMResponse>;
|
|
34
|
+
chatStream(messages: MessageData[], tools?: Tool[], signal?: AbortSignal): AsyncIterable<LLMStreamEvent>;
|
|
35
|
+
getTokenCount(text: string, model?: string): number;
|
|
36
|
+
/** Number of calls in the current 1-minute window. */
|
|
37
|
+
get currentRateCount(): number;
|
|
38
|
+
/** Reset rate limiter counters. */
|
|
39
|
+
resetRateLimiter(): void;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/llm/rate-limiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAsDtC;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,2CAA2C;IAC3C,QAAQ,EAAE,WAAW,CAAC;IACtB,oCAAoC;IACpC,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,mBAAoB,YAAW,WAAW;IACrD,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,OAAO,CAAuB;gBAE1B,MAAM,EAAE,yBAAyB;IAK7C,IAAI,KAAK,IAAI,MAAM,CAElB;IAEK,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAKxF,UAAU,CACf,QAAQ,EAAE,WAAW,EAAE,EACvB,KAAK,CAAC,EAAE,IAAI,EAAE,EACd,MAAM,CAAC,EAAE,WAAW,GACnB,aAAa,CAAC,cAAc,CAAC;IAKhC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAInD,sDAAsD;IACtD,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED,mCAAmC;IACnC,gBAAgB,IAAI,IAAI;CAGzB"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RateLimitedProvider = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Simple sliding-window rate limiter.
|
|
6
|
+
*
|
|
7
|
+
* Tracks call timestamps and delays requests when the configured
|
|
8
|
+
* maximum calls-per-minute would be exceeded.
|
|
9
|
+
*/
|
|
10
|
+
class SlidingWindowLimiter {
|
|
11
|
+
timestamps = [];
|
|
12
|
+
maxPerMinute;
|
|
13
|
+
constructor(maxPerMinute) {
|
|
14
|
+
this.maxPerMinute = maxPerMinute;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Wait until a slot is available in the current window.
|
|
18
|
+
* Returns immediately if under the limit.
|
|
19
|
+
*/
|
|
20
|
+
async acquire() {
|
|
21
|
+
const now = Date.now();
|
|
22
|
+
const windowStart = now - 60_000;
|
|
23
|
+
// Drop timestamps outside the 1-minute window
|
|
24
|
+
this.timestamps = this.timestamps.filter((t) => t > windowStart);
|
|
25
|
+
if (this.timestamps.length < this.maxPerMinute) {
|
|
26
|
+
this.timestamps.push(now);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// Wait until the oldest call exits the window
|
|
30
|
+
const oldest = this.timestamps[0];
|
|
31
|
+
const waitMs = oldest - windowStart + 10; // small buffer
|
|
32
|
+
if (waitMs > 0) {
|
|
33
|
+
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
34
|
+
}
|
|
35
|
+
// Re-check after waiting
|
|
36
|
+
return this.acquire();
|
|
37
|
+
}
|
|
38
|
+
/** Number of calls in the current window. */
|
|
39
|
+
get currentCount() {
|
|
40
|
+
const windowStart = Date.now() - 60_000;
|
|
41
|
+
return this.timestamps.filter((t) => t > windowStart).length;
|
|
42
|
+
}
|
|
43
|
+
reset() {
|
|
44
|
+
this.timestamps = [];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* LLMProvider wrapper that enforces a maximum call rate.
|
|
49
|
+
*
|
|
50
|
+
* Calls that would exceed the limit are delayed until a slot opens in
|
|
51
|
+
* the 1-minute sliding window. This prevents the agent from hitting
|
|
52
|
+
* provider rate limits (HTTP 429) during high-throughput scenarios.
|
|
53
|
+
*
|
|
54
|
+
* Usage:
|
|
55
|
+
* ```ts
|
|
56
|
+
* const provider = new RateLimitedProvider({
|
|
57
|
+
* provider: new OpenAIProvider({ ... }),
|
|
58
|
+
* maxCallsPerMinute: 500,
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
class RateLimitedProvider {
|
|
63
|
+
provider;
|
|
64
|
+
limiter;
|
|
65
|
+
constructor(config) {
|
|
66
|
+
this.provider = config.provider;
|
|
67
|
+
this.limiter = new SlidingWindowLimiter(config.maxCallsPerMinute);
|
|
68
|
+
}
|
|
69
|
+
get model() {
|
|
70
|
+
return this.provider.model;
|
|
71
|
+
}
|
|
72
|
+
async chat(messages, tools, signal) {
|
|
73
|
+
await this.limiter.acquire();
|
|
74
|
+
return this.provider.chat(messages, tools, signal);
|
|
75
|
+
}
|
|
76
|
+
async *chatStream(messages, tools, signal) {
|
|
77
|
+
await this.limiter.acquire();
|
|
78
|
+
yield* this.provider.chatStream(messages, tools, signal);
|
|
79
|
+
}
|
|
80
|
+
getTokenCount(text, model) {
|
|
81
|
+
return this.provider.getTokenCount(text, model);
|
|
82
|
+
}
|
|
83
|
+
/** Number of calls in the current 1-minute window. */
|
|
84
|
+
get currentRateCount() {
|
|
85
|
+
return this.limiter.currentCount;
|
|
86
|
+
}
|
|
87
|
+
/** Reset rate limiter counters. */
|
|
88
|
+
resetRateLimiter() {
|
|
89
|
+
this.limiter.reset();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.RateLimitedProvider = RateLimitedProvider;
|
|
93
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/llm/rate-limiter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { NetworkErrorCause, RetryConfig } from "./errors";
|
|
2
|
+
/**
|
|
3
|
+
* Provider-specific callbacks that the generic retry wrapper delegates to
|
|
4
|
+
* when deciding whether an error is retryable and how to classify it.
|
|
5
|
+
*/
|
|
6
|
+
export interface RetryCallbacks {
|
|
7
|
+
/** Return true if the error is network-related and thus retryable. */
|
|
8
|
+
isRetryable: (error: unknown) => boolean;
|
|
9
|
+
/** Classify a retryable error into a NetworkErrorCause category. */
|
|
10
|
+
classifyError: (error: unknown) => NetworkErrorCause;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Wrap an async operation with network-error retry logic.
|
|
14
|
+
*
|
|
15
|
+
* Retry strategy:
|
|
16
|
+
* - The `callbacks.isRetryable` predicate decides which errors are retried.
|
|
17
|
+
* - Uses exponential backoff with full jitter: delay = base * 2^attempt * random(0.5, 1.0).
|
|
18
|
+
* - Non-retryable errors propagate immediately.
|
|
19
|
+
* - After all retries are exhausted, throws an `LLMNetworkError`.
|
|
20
|
+
*
|
|
21
|
+
* @param fn The async operation to retry.
|
|
22
|
+
* @param config Retry configuration (maxRetries, baseDelayMs, maxDelayMs).
|
|
23
|
+
* @param callbacks Provider-specific error classification callbacks.
|
|
24
|
+
*/
|
|
25
|
+
export declare function withRetry<T>(fn: () => Promise<T> | PromiseLike<T>, config: Required<RetryConfig>, callbacks: RetryCallbacks): Promise<T>;
|
|
26
|
+
//# sourceMappingURL=retry.d.ts.map
|