@yuaone/core 0.1.0
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 +663 -0
- package/README.md +15 -0
- package/dist/__tests__/context-manager.test.d.ts +6 -0
- package/dist/__tests__/context-manager.test.d.ts.map +1 -0
- package/dist/__tests__/context-manager.test.js +220 -0
- package/dist/__tests__/context-manager.test.js.map +1 -0
- package/dist/__tests__/governor.test.d.ts +6 -0
- package/dist/__tests__/governor.test.d.ts.map +1 -0
- package/dist/__tests__/governor.test.js +210 -0
- package/dist/__tests__/governor.test.js.map +1 -0
- package/dist/__tests__/model-router.test.d.ts +6 -0
- package/dist/__tests__/model-router.test.d.ts.map +1 -0
- package/dist/__tests__/model-router.test.js +329 -0
- package/dist/__tests__/model-router.test.js.map +1 -0
- package/dist/agent-logger.d.ts +384 -0
- package/dist/agent-logger.d.ts.map +1 -0
- package/dist/agent-logger.js +820 -0
- package/dist/agent-logger.js.map +1 -0
- package/dist/agent-loop.d.ts +163 -0
- package/dist/agent-loop.d.ts.map +1 -0
- package/dist/agent-loop.js +609 -0
- package/dist/agent-loop.js.map +1 -0
- package/dist/agent-modes.d.ts +85 -0
- package/dist/agent-modes.d.ts.map +1 -0
- package/dist/agent-modes.js +418 -0
- package/dist/agent-modes.js.map +1 -0
- package/dist/approval.d.ts +137 -0
- package/dist/approval.d.ts.map +1 -0
- package/dist/approval.js +299 -0
- package/dist/approval.js.map +1 -0
- package/dist/async-completion-queue.d.ts +56 -0
- package/dist/async-completion-queue.d.ts.map +1 -0
- package/dist/async-completion-queue.js +77 -0
- package/dist/async-completion-queue.js.map +1 -0
- package/dist/auto-fix.d.ts +174 -0
- package/dist/auto-fix.d.ts.map +1 -0
- package/dist/auto-fix.js +319 -0
- package/dist/auto-fix.js.map +1 -0
- package/dist/codebase-context.d.ts +396 -0
- package/dist/codebase-context.d.ts.map +1 -0
- package/dist/codebase-context.js +1260 -0
- package/dist/codebase-context.js.map +1 -0
- package/dist/conflict-resolver.d.ts +191 -0
- package/dist/conflict-resolver.d.ts.map +1 -0
- package/dist/conflict-resolver.js +524 -0
- package/dist/conflict-resolver.js.map +1 -0
- package/dist/constants.d.ts +52 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +141 -0
- package/dist/constants.js.map +1 -0
- package/dist/context-budget.d.ts +435 -0
- package/dist/context-budget.d.ts.map +1 -0
- package/dist/context-budget.js +903 -0
- package/dist/context-budget.js.map +1 -0
- package/dist/context-compressor.d.ts +143 -0
- package/dist/context-compressor.d.ts.map +1 -0
- package/dist/context-compressor.js +511 -0
- package/dist/context-compressor.js.map +1 -0
- package/dist/context-manager.d.ts +112 -0
- package/dist/context-manager.d.ts.map +1 -0
- package/dist/context-manager.js +247 -0
- package/dist/context-manager.js.map +1 -0
- package/dist/continuous-reflection.d.ts +267 -0
- package/dist/continuous-reflection.d.ts.map +1 -0
- package/dist/continuous-reflection.js +338 -0
- package/dist/continuous-reflection.js.map +1 -0
- package/dist/cross-file-refactor.d.ts +352 -0
- package/dist/cross-file-refactor.d.ts.map +1 -0
- package/dist/cross-file-refactor.js +1544 -0
- package/dist/cross-file-refactor.js.map +1 -0
- package/dist/dag-orchestrator.d.ts +138 -0
- package/dist/dag-orchestrator.d.ts.map +1 -0
- package/dist/dag-orchestrator.js +379 -0
- package/dist/dag-orchestrator.js.map +1 -0
- package/dist/debate-orchestrator.d.ts +301 -0
- package/dist/debate-orchestrator.d.ts.map +1 -0
- package/dist/debate-orchestrator.js +719 -0
- package/dist/debate-orchestrator.js.map +1 -0
- package/dist/dependency-analyzer.d.ts +113 -0
- package/dist/dependency-analyzer.d.ts.map +1 -0
- package/dist/dependency-analyzer.js +444 -0
- package/dist/dependency-analyzer.js.map +1 -0
- package/dist/design-loop.d.ts +59 -0
- package/dist/design-loop.d.ts.map +1 -0
- package/dist/design-loop.js +344 -0
- package/dist/design-loop.js.map +1 -0
- package/dist/doc-intelligence.d.ts +383 -0
- package/dist/doc-intelligence.d.ts.map +1 -0
- package/dist/doc-intelligence.js +1307 -0
- package/dist/doc-intelligence.js.map +1 -0
- package/dist/dynamic-role-generator.d.ts +76 -0
- package/dist/dynamic-role-generator.d.ts.map +1 -0
- package/dist/dynamic-role-generator.js +194 -0
- package/dist/dynamic-role-generator.js.map +1 -0
- package/dist/errors.d.ts +69 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +102 -0
- package/dist/errors.js.map +1 -0
- package/dist/event-bus.d.ts +159 -0
- package/dist/event-bus.d.ts.map +1 -0
- package/dist/event-bus.js +305 -0
- package/dist/event-bus.js.map +1 -0
- package/dist/execution-engine.d.ts +425 -0
- package/dist/execution-engine.d.ts.map +1 -0
- package/dist/execution-engine.js +1555 -0
- package/dist/execution-engine.js.map +1 -0
- package/dist/git-intelligence.d.ts +306 -0
- package/dist/git-intelligence.d.ts.map +1 -0
- package/dist/git-intelligence.js +1099 -0
- package/dist/git-intelligence.js.map +1 -0
- package/dist/governor.d.ts +77 -0
- package/dist/governor.d.ts.map +1 -0
- package/dist/governor.js +161 -0
- package/dist/governor.js.map +1 -0
- package/dist/hierarchical-planner.d.ts +313 -0
- package/dist/hierarchical-planner.d.ts.map +1 -0
- package/dist/hierarchical-planner.js +981 -0
- package/dist/hierarchical-planner.js.map +1 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +123 -0
- package/dist/index.js.map +1 -0
- package/dist/intent-inference.d.ts +103 -0
- package/dist/intent-inference.d.ts.map +1 -0
- package/dist/intent-inference.js +605 -0
- package/dist/intent-inference.js.map +1 -0
- package/dist/interrupt-manager.d.ts +143 -0
- package/dist/interrupt-manager.d.ts.map +1 -0
- package/dist/interrupt-manager.js +196 -0
- package/dist/interrupt-manager.js.map +1 -0
- package/dist/kernel.d.ts +564 -0
- package/dist/kernel.d.ts.map +1 -0
- package/dist/kernel.js +1419 -0
- package/dist/kernel.js.map +1 -0
- package/dist/language-support.d.ts +232 -0
- package/dist/language-support.d.ts.map +1 -0
- package/dist/language-support.js +1134 -0
- package/dist/language-support.js.map +1 -0
- package/dist/llm-client.d.ts +82 -0
- package/dist/llm-client.d.ts.map +1 -0
- package/dist/llm-client.js +475 -0
- package/dist/llm-client.js.map +1 -0
- package/dist/mcp-client.d.ts +232 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +718 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/memory-manager.d.ts +200 -0
- package/dist/memory-manager.d.ts.map +1 -0
- package/dist/memory-manager.js +568 -0
- package/dist/memory-manager.js.map +1 -0
- package/dist/memory.d.ts +87 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +341 -0
- package/dist/memory.js.map +1 -0
- package/dist/model-router.d.ts +245 -0
- package/dist/model-router.d.ts.map +1 -0
- package/dist/model-router.js +632 -0
- package/dist/model-router.js.map +1 -0
- package/dist/parallel-executor.d.ts +125 -0
- package/dist/parallel-executor.d.ts.map +1 -0
- package/dist/parallel-executor.js +201 -0
- package/dist/parallel-executor.js.map +1 -0
- package/dist/perf-optimizer.d.ts +212 -0
- package/dist/perf-optimizer.d.ts.map +1 -0
- package/dist/perf-optimizer.js +721 -0
- package/dist/perf-optimizer.js.map +1 -0
- package/dist/persona.d.ts +305 -0
- package/dist/persona.d.ts.map +1 -0
- package/dist/persona.js +887 -0
- package/dist/persona.js.map +1 -0
- package/dist/planner.d.ts +70 -0
- package/dist/planner.d.ts.map +1 -0
- package/dist/planner.js +264 -0
- package/dist/planner.js.map +1 -0
- package/dist/qa-pipeline.d.ts +365 -0
- package/dist/qa-pipeline.d.ts.map +1 -0
- package/dist/qa-pipeline.js +1352 -0
- package/dist/qa-pipeline.js.map +1 -0
- package/dist/reasoning-adapter.d.ts +116 -0
- package/dist/reasoning-adapter.d.ts.map +1 -0
- package/dist/reasoning-adapter.js +187 -0
- package/dist/reasoning-adapter.js.map +1 -0
- package/dist/role-registry.d.ts +55 -0
- package/dist/role-registry.d.ts.map +1 -0
- package/dist/role-registry.js +192 -0
- package/dist/role-registry.js.map +1 -0
- package/dist/sandbox-tiers.d.ts +327 -0
- package/dist/sandbox-tiers.d.ts.map +1 -0
- package/dist/sandbox-tiers.js +928 -0
- package/dist/sandbox-tiers.js.map +1 -0
- package/dist/security-scanner.d.ts +222 -0
- package/dist/security-scanner.d.ts.map +1 -0
- package/dist/security-scanner.js +1129 -0
- package/dist/security-scanner.js.map +1 -0
- package/dist/security.d.ts +93 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +393 -0
- package/dist/security.js.map +1 -0
- package/dist/self-reflection.d.ts +397 -0
- package/dist/self-reflection.d.ts.map +1 -0
- package/dist/self-reflection.js +908 -0
- package/dist/self-reflection.js.map +1 -0
- package/dist/session-persistence.d.ts +191 -0
- package/dist/session-persistence.d.ts.map +1 -0
- package/dist/session-persistence.js +395 -0
- package/dist/session-persistence.js.map +1 -0
- package/dist/speculative-executor.d.ts +210 -0
- package/dist/speculative-executor.d.ts.map +1 -0
- package/dist/speculative-executor.js +618 -0
- package/dist/speculative-executor.js.map +1 -0
- package/dist/state-machine.d.ts +289 -0
- package/dist/state-machine.d.ts.map +1 -0
- package/dist/state-machine.js +695 -0
- package/dist/state-machine.js.map +1 -0
- package/dist/sub-agent.d.ts +177 -0
- package/dist/sub-agent.d.ts.map +1 -0
- package/dist/sub-agent.js +303 -0
- package/dist/sub-agent.js.map +1 -0
- package/dist/system-prompt.d.ts +26 -0
- package/dist/system-prompt.d.ts.map +1 -0
- package/dist/system-prompt.js +84 -0
- package/dist/system-prompt.js.map +1 -0
- package/dist/test-intelligence.d.ts +439 -0
- package/dist/test-intelligence.d.ts.map +1 -0
- package/dist/test-intelligence.js +1165 -0
- package/dist/test-intelligence.js.map +1 -0
- package/dist/types.d.ts +632 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/vector-index.d.ts +314 -0
- package/dist/vector-index.d.ts.map +1 -0
- package/dist/vector-index.js +618 -0
- package/dist/vector-index.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module model-router.test
|
|
3
|
+
* @description ModelRouter unit tests (~30 cases).
|
|
4
|
+
*/
|
|
5
|
+
import { describe, it } from "node:test";
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { ModelRouter, } from "../model-router.js";
|
|
8
|
+
// ─── Helpers ───
|
|
9
|
+
function makeProviders(opts = {}) {
|
|
10
|
+
const providers = {};
|
|
11
|
+
if (opts.anthropic)
|
|
12
|
+
providers.anthropic = { apiKey: "sk-ant-test" };
|
|
13
|
+
if (opts.openai)
|
|
14
|
+
providers.openai = { apiKey: "sk-oai-test" };
|
|
15
|
+
if (opts.google)
|
|
16
|
+
providers.google = { apiKey: "goog-test" };
|
|
17
|
+
return providers;
|
|
18
|
+
}
|
|
19
|
+
function makeRouter(overrides = {}, providerOpts = {
|
|
20
|
+
anthropic: true,
|
|
21
|
+
}) {
|
|
22
|
+
return new ModelRouter({
|
|
23
|
+
providers: makeProviders(providerOpts),
|
|
24
|
+
costStrategy: "balanced",
|
|
25
|
+
...overrides,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// ─── Tests ───
|
|
29
|
+
describe("ModelRouter", () => {
|
|
30
|
+
// === 1. Single provider routing ===
|
|
31
|
+
describe("single provider routing", () => {
|
|
32
|
+
it("routes all tasks to Anthropic when only Anthropic key is configured", () => {
|
|
33
|
+
const router = makeRouter({}, { anthropic: true });
|
|
34
|
+
const tasks = ["planning", "coding", "search", "security_scan"];
|
|
35
|
+
for (const task of tasks) {
|
|
36
|
+
const decision = router.route(task);
|
|
37
|
+
assert.equal(decision.provider, "anthropic");
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
it("routes all tasks to OpenAI when only OpenAI key is configured", () => {
|
|
41
|
+
const router = makeRouter({}, { openai: true });
|
|
42
|
+
const tasks = ["planning", "coding", "search"];
|
|
43
|
+
for (const task of tasks) {
|
|
44
|
+
const decision = router.route(task);
|
|
45
|
+
assert.equal(decision.provider, "openai");
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
// === 2. Multi-provider routing ===
|
|
50
|
+
describe("multi-provider routing", () => {
|
|
51
|
+
it("distributes tasks across providers based on strengths", () => {
|
|
52
|
+
const router = makeRouter({ costStrategy: "quality" }, { anthropic: true, openai: true, google: true });
|
|
53
|
+
const planning = router.route("planning", undefined, "critical");
|
|
54
|
+
const search = router.route("search", undefined, "trivial");
|
|
55
|
+
// Planning should get a flagship model, search should get economy
|
|
56
|
+
assert.ok(planning.tier === "flagship" || planning.tier === "premium", `Expected flagship/premium for planning, got ${planning.tier}`);
|
|
57
|
+
assert.ok(search.tier === "economy" || search.tier === "standard", `Expected economy/standard for search, got ${search.tier}`);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
// === 3. Planning routes to flagship ===
|
|
61
|
+
it("routes planning+critical to a flagship model", () => {
|
|
62
|
+
const router = makeRouter({ costStrategy: "quality" }, { anthropic: true, openai: true });
|
|
63
|
+
const decision = router.route("planning", undefined, "critical");
|
|
64
|
+
assert.equal(decision.tier, "flagship");
|
|
65
|
+
});
|
|
66
|
+
// === 4. Coding routes to premium ===
|
|
67
|
+
it("routes coding+moderate to a premium model (quality strategy)", () => {
|
|
68
|
+
const router = makeRouter({ costStrategy: "quality" }, { anthropic: true });
|
|
69
|
+
const decision = router.route("coding", undefined, "moderate");
|
|
70
|
+
// Anthropic-only: sonnet (premium) should score highest for coding+moderate
|
|
71
|
+
assert.equal(decision.tier, "premium");
|
|
72
|
+
assert.ok(decision.model.includes("sonnet"));
|
|
73
|
+
});
|
|
74
|
+
// === 5. Search routes to economy ===
|
|
75
|
+
it("routes search+trivial to economy tier", () => {
|
|
76
|
+
const router = makeRouter({ costStrategy: "economy" }, { anthropic: true, openai: true });
|
|
77
|
+
const decision = router.route("search", undefined, "trivial");
|
|
78
|
+
assert.equal(decision.tier, "economy");
|
|
79
|
+
});
|
|
80
|
+
// === 6. Security scan routes to security-strong model ===
|
|
81
|
+
it("routes security_scan to model with security strength", () => {
|
|
82
|
+
const router = makeRouter({ costStrategy: "quality" }, { anthropic: true });
|
|
83
|
+
const decision = router.route("security_scan", undefined, "moderate");
|
|
84
|
+
// Anthropic sonnet has "security" strength
|
|
85
|
+
assert.ok(decision.model.includes("sonnet"), `Expected sonnet for security, got ${decision.model}`);
|
|
86
|
+
});
|
|
87
|
+
// === 7. Economy mode picks cheapest ===
|
|
88
|
+
it("economy mode prefers low-cost models", () => {
|
|
89
|
+
const router = makeRouter({ costStrategy: "economy" }, { anthropic: true, openai: true, google: true });
|
|
90
|
+
const decision = router.route("simple_edit", undefined, "trivial");
|
|
91
|
+
// Economy strategy favors low-cost models; with 3 providers the cheapest
|
|
92
|
+
// may be economy or standard tier (e.g., gemini-2.0-flash is standard but very cheap)
|
|
93
|
+
assert.ok(decision.tier === "economy" || decision.tier === "standard", `Expected economy or standard tier, got ${decision.tier}`);
|
|
94
|
+
assert.ok(decision.estimatedCostPer1kTokens < 0.01, "Should pick a cheap model");
|
|
95
|
+
});
|
|
96
|
+
// === 8. Quality mode picks best tier ===
|
|
97
|
+
it("quality mode prefers highest tier model", () => {
|
|
98
|
+
const router = makeRouter({ costStrategy: "quality" }, { anthropic: true, openai: true });
|
|
99
|
+
const decision = router.route("planning", undefined, "critical");
|
|
100
|
+
assert.equal(decision.tier, "flagship");
|
|
101
|
+
});
|
|
102
|
+
// === 9. Force provider overrides routing ===
|
|
103
|
+
it("forceProvider overrides routing to use specified provider", () => {
|
|
104
|
+
const router = makeRouter({ forceProvider: "openai" }, { anthropic: true, openai: true });
|
|
105
|
+
const decision = router.route("planning", undefined, "critical");
|
|
106
|
+
assert.equal(decision.provider, "openai");
|
|
107
|
+
});
|
|
108
|
+
// === 10. Force model overrides everything ===
|
|
109
|
+
it("forceModel overrides to use exact model", () => {
|
|
110
|
+
const router = makeRouter({ forceModel: "gpt-4o-mini" }, { openai: true });
|
|
111
|
+
const decision = router.route("planning", undefined, "critical");
|
|
112
|
+
assert.equal(decision.model, "gpt-4o-mini");
|
|
113
|
+
});
|
|
114
|
+
// === 11. No providers → throws ===
|
|
115
|
+
it("throws when no providers are configured", () => {
|
|
116
|
+
const router = new ModelRouter({
|
|
117
|
+
providers: {},
|
|
118
|
+
costStrategy: "balanced",
|
|
119
|
+
});
|
|
120
|
+
assert.throws(() => router.route("coding"), /No API keys configured/);
|
|
121
|
+
});
|
|
122
|
+
// === 12. Complexity estimation ===
|
|
123
|
+
describe("estimateComplexity", () => {
|
|
124
|
+
it("estimates 'fix typo' as trivial", () => {
|
|
125
|
+
const router = makeRouter();
|
|
126
|
+
assert.equal(router.estimateComplexity("fix typo in README"), "trivial");
|
|
127
|
+
});
|
|
128
|
+
it("estimates 'full rewrite' as critical", () => {
|
|
129
|
+
const router = makeRouter();
|
|
130
|
+
assert.equal(router.estimateComplexity("full rewrite of the auth system"), "critical");
|
|
131
|
+
});
|
|
132
|
+
it("estimates 'redesign' as complex", () => {
|
|
133
|
+
const router = makeRouter();
|
|
134
|
+
assert.equal(router.estimateComplexity("redesign the dashboard layout"), "complex");
|
|
135
|
+
});
|
|
136
|
+
it("estimates 'implement feature' as moderate", () => {
|
|
137
|
+
const router = makeRouter();
|
|
138
|
+
assert.equal(router.estimateComplexity("implement feature for user profiles"), "moderate");
|
|
139
|
+
});
|
|
140
|
+
it("returns 'moderate' for unrecognized description with no metrics", () => {
|
|
141
|
+
const router = makeRouter();
|
|
142
|
+
assert.equal(router.estimateComplexity("do something interesting"), "moderate");
|
|
143
|
+
});
|
|
144
|
+
it("uses file count for complexity when metrics dominate", () => {
|
|
145
|
+
const router = makeRouter();
|
|
146
|
+
// 50 files → critical (from metrics)
|
|
147
|
+
assert.equal(router.estimateComplexity("some task", 50, 100), "critical");
|
|
148
|
+
});
|
|
149
|
+
it("takes higher of keyword vs metrics complexity", () => {
|
|
150
|
+
const router = makeRouter();
|
|
151
|
+
// "fix typo" → trivial by keyword, but 20 files → complex by metrics
|
|
152
|
+
const result = router.estimateComplexity("fix typo", 20, 30);
|
|
153
|
+
assert.equal(result, "complex");
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
// === 13. toBYOKConfig ===
|
|
157
|
+
it("toBYOKConfig returns valid BYOKConfig from RoutingDecision", () => {
|
|
158
|
+
const router = makeRouter({}, { anthropic: true });
|
|
159
|
+
const decision = router.route("coding");
|
|
160
|
+
const config = router.toBYOKConfig(decision);
|
|
161
|
+
assert.equal(config.provider, "anthropic");
|
|
162
|
+
assert.equal(config.apiKey, "sk-ant-test");
|
|
163
|
+
assert.equal(config.model, decision.model);
|
|
164
|
+
assert.ok(config.baseUrl, "baseUrl should be set");
|
|
165
|
+
});
|
|
166
|
+
it("toBYOKConfig throws for unconfigured provider", () => {
|
|
167
|
+
const router = makeRouter({}, { anthropic: true });
|
|
168
|
+
const fakeDecision = {
|
|
169
|
+
provider: "openai",
|
|
170
|
+
model: "gpt-4o",
|
|
171
|
+
tier: "premium",
|
|
172
|
+
reason: "test",
|
|
173
|
+
fallbacks: [],
|
|
174
|
+
estimatedCostPer1kTokens: 0.005,
|
|
175
|
+
};
|
|
176
|
+
assert.throws(() => router.toBYOKConfig(fakeDecision), /No API key configured.*openai/);
|
|
177
|
+
});
|
|
178
|
+
// === 14. Fallbacks ===
|
|
179
|
+
it("includes fallback models in routing decision", () => {
|
|
180
|
+
const router = makeRouter({}, { anthropic: true });
|
|
181
|
+
const decision = router.route("coding");
|
|
182
|
+
// Anthropic has 3 models, primary + up to 2 fallbacks
|
|
183
|
+
assert.ok(decision.fallbacks.length >= 1, "Should have at least 1 fallback");
|
|
184
|
+
assert.ok(decision.fallbacks.length <= 2, "Should have at most 2 fallbacks");
|
|
185
|
+
});
|
|
186
|
+
// === 15. Stats recording ===
|
|
187
|
+
it("recordStats creates and updates model stats", () => {
|
|
188
|
+
const router = makeRouter();
|
|
189
|
+
assert.equal(router.getStats().length, 0);
|
|
190
|
+
router.recordStats("anthropic", "claude-sonnet-4-20250514", 500, true, 1000);
|
|
191
|
+
assert.equal(router.getStats().length, 1);
|
|
192
|
+
const stat = router.getStats()[0];
|
|
193
|
+
assert.equal(stat.provider, "anthropic");
|
|
194
|
+
assert.equal(stat.totalCalls, 1);
|
|
195
|
+
assert.equal(stat.avgLatencyMs, 500);
|
|
196
|
+
assert.equal(stat.successRate, 1.0);
|
|
197
|
+
});
|
|
198
|
+
it("recordStats computes running averages", () => {
|
|
199
|
+
const router = makeRouter();
|
|
200
|
+
router.recordStats("anthropic", "claude-sonnet-4-20250514", 400, true, 800);
|
|
201
|
+
router.recordStats("anthropic", "claude-sonnet-4-20250514", 600, true, 1200);
|
|
202
|
+
const stat = router.getStats()[0];
|
|
203
|
+
assert.equal(stat.totalCalls, 2);
|
|
204
|
+
assert.equal(stat.avgLatencyMs, 500);
|
|
205
|
+
assert.equal(stat.avgTokensPerTask, 1000);
|
|
206
|
+
assert.equal(stat.successRate, 1.0);
|
|
207
|
+
});
|
|
208
|
+
// === 16. Adaptive routing — poor stats lower priority ===
|
|
209
|
+
it("model with poor stats scores lower than one with good stats", () => {
|
|
210
|
+
const router = makeRouter({ costStrategy: "balanced" }, { anthropic: true, openai: true });
|
|
211
|
+
// Record many failures for sonnet
|
|
212
|
+
for (let i = 0; i < 10; i++) {
|
|
213
|
+
router.recordStats("anthropic", "claude-sonnet-4-20250514", 9000, false, 500);
|
|
214
|
+
}
|
|
215
|
+
// Record good stats for gpt-4o
|
|
216
|
+
for (let i = 0; i < 10; i++) {
|
|
217
|
+
router.recordStats("openai", "gpt-4o", 200, true, 500);
|
|
218
|
+
}
|
|
219
|
+
// Route for a task where both models have similar strengths (coding)
|
|
220
|
+
// Performance score contributes 0.2 weight, so the poor-performing model
|
|
221
|
+
// should rank lower even if it has matching strengths
|
|
222
|
+
const decision = router.route("coding", undefined, "moderate");
|
|
223
|
+
// The model with 0% success rate should not be the primary choice
|
|
224
|
+
// (it may still win on strength match, but let's verify the stats affect ranking)
|
|
225
|
+
const stats = router.getStats();
|
|
226
|
+
const sonnetStat = stats.find((s) => s.model === "claude-sonnet-4-20250514");
|
|
227
|
+
const gptStat = stats.find((s) => s.model === "gpt-4o");
|
|
228
|
+
assert.ok(sonnetStat);
|
|
229
|
+
assert.ok(gptStat);
|
|
230
|
+
assert.equal(sonnetStat.successRate, 0.0);
|
|
231
|
+
assert.equal(gptStat.successRate, 1.0);
|
|
232
|
+
// The actual routing result depends on the full scoring formula;
|
|
233
|
+
// we verify the stats are correctly tracked and affect the computation
|
|
234
|
+
assert.ok(decision.model, "Should return some model");
|
|
235
|
+
});
|
|
236
|
+
// === 17. Budget tracking ===
|
|
237
|
+
it("addCost accumulates and getAccumulatedCost returns total", () => {
|
|
238
|
+
const router = makeRouter();
|
|
239
|
+
assert.equal(router.getAccumulatedCost(), 0);
|
|
240
|
+
router.addCost(0.05);
|
|
241
|
+
router.addCost(0.03);
|
|
242
|
+
assert.ok(Math.abs(router.getAccumulatedCost() - 0.08) < 1e-10);
|
|
243
|
+
});
|
|
244
|
+
it("throws when session budget is exhausted", () => {
|
|
245
|
+
const router = makeRouter({ maxSessionCostUsd: 0.10 });
|
|
246
|
+
router.addCost(0.10);
|
|
247
|
+
assert.throws(() => router.route("coding"), /budget exhausted/i);
|
|
248
|
+
});
|
|
249
|
+
// === 18. getAvailableModels ===
|
|
250
|
+
it("getAvailableModels filters by configured providers", () => {
|
|
251
|
+
const routerAnth = makeRouter({}, { anthropic: true });
|
|
252
|
+
const models = routerAnth.getAvailableModels();
|
|
253
|
+
assert.ok(models.length > 0);
|
|
254
|
+
for (const m of models) {
|
|
255
|
+
assert.equal(m.provider, "anthropic");
|
|
256
|
+
}
|
|
257
|
+
const routerAll = makeRouter({}, { anthropic: true, openai: true, google: true });
|
|
258
|
+
const allModels = routerAll.getAvailableModels();
|
|
259
|
+
const providers = new Set(allModels.map((m) => m.provider));
|
|
260
|
+
assert.ok(providers.has("anthropic"));
|
|
261
|
+
assert.ok(providers.has("openai"));
|
|
262
|
+
assert.ok(providers.has("google"));
|
|
263
|
+
});
|
|
264
|
+
// === 19. hasProvider ===
|
|
265
|
+
it("hasProvider returns true when at least one key is configured", () => {
|
|
266
|
+
const router = makeRouter({}, { anthropic: true });
|
|
267
|
+
assert.equal(router.hasProvider(), true);
|
|
268
|
+
});
|
|
269
|
+
it("hasProvider returns false when no keys are configured", () => {
|
|
270
|
+
const router = new ModelRouter({
|
|
271
|
+
providers: {},
|
|
272
|
+
costStrategy: "balanced",
|
|
273
|
+
});
|
|
274
|
+
assert.equal(router.hasProvider(), false);
|
|
275
|
+
});
|
|
276
|
+
// === 20. routeForContract ===
|
|
277
|
+
it("routeForContract routes based on TaskContract", () => {
|
|
278
|
+
const router = makeRouter({ costStrategy: "balanced" }, { anthropic: true });
|
|
279
|
+
const decision = router.routeForContract({
|
|
280
|
+
id: "task-1",
|
|
281
|
+
goal: "implement feature for user auth",
|
|
282
|
+
assignedRole: "coder",
|
|
283
|
+
dependencies: [],
|
|
284
|
+
inputSchema: { files: ["src/auth.ts"], context: "Auth module" },
|
|
285
|
+
outputSchema: {
|
|
286
|
+
expectedFiles: ["src/auth.ts", "src/auth.test.ts"],
|
|
287
|
+
successCriteria: ["compiles", "tests pass"],
|
|
288
|
+
},
|
|
289
|
+
allowedTools: ["file_read", "file_write"],
|
|
290
|
+
sideEffectLevel: "write",
|
|
291
|
+
retryPolicy: { maxRetries: 2, backoffMs: 1000, failureTypes: ["TRANSIENT"] },
|
|
292
|
+
tokenBudget: 10000,
|
|
293
|
+
timeoutMs: 60000,
|
|
294
|
+
});
|
|
295
|
+
assert.equal(decision.provider, "anthropic");
|
|
296
|
+
assert.ok(decision.model, "Should return a model");
|
|
297
|
+
assert.ok(decision.tier, "Should return a tier");
|
|
298
|
+
});
|
|
299
|
+
// === Extra: RoutingDecision structure ===
|
|
300
|
+
it("routing decision has all required fields", () => {
|
|
301
|
+
const router = makeRouter({}, { anthropic: true });
|
|
302
|
+
const decision = router.route("coding");
|
|
303
|
+
assert.ok("provider" in decision);
|
|
304
|
+
assert.ok("model" in decision);
|
|
305
|
+
assert.ok("tier" in decision);
|
|
306
|
+
assert.ok("reason" in decision);
|
|
307
|
+
assert.ok("fallbacks" in decision);
|
|
308
|
+
assert.ok("estimatedCostPer1kTokens" in decision);
|
|
309
|
+
assert.ok(typeof decision.estimatedCostPer1kTokens === "number");
|
|
310
|
+
assert.ok(decision.estimatedCostPer1kTokens > 0);
|
|
311
|
+
});
|
|
312
|
+
// === Extra: Force model not in catalog ===
|
|
313
|
+
it("forceModel with unknown model returns standard tier", () => {
|
|
314
|
+
const router = makeRouter({ forceModel: "custom-model-v99", forceProvider: "anthropic" }, { anthropic: true });
|
|
315
|
+
const decision = router.route("coding");
|
|
316
|
+
assert.equal(decision.model, "custom-model-v99");
|
|
317
|
+
assert.equal(decision.tier, "standard");
|
|
318
|
+
});
|
|
319
|
+
// === Extra: Deterministic routing ===
|
|
320
|
+
it("returns same result for same input (deterministic)", () => {
|
|
321
|
+
const router = makeRouter({ costStrategy: "balanced" }, { anthropic: true, openai: true });
|
|
322
|
+
const d1 = router.route("coding", undefined, "moderate");
|
|
323
|
+
const d2 = router.route("coding", undefined, "moderate");
|
|
324
|
+
assert.equal(d1.provider, d2.provider);
|
|
325
|
+
assert.equal(d1.model, d2.model);
|
|
326
|
+
assert.equal(d1.tier, d2.tier);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
//# sourceMappingURL=model-router.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-router.test.js","sourceRoot":"","sources":["../../src/__tests__/model-router.test.ts"],"names":[],"mappings":"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"}
|