auto-model-router 0.3.4 → 0.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/.omp-plugin/marketplace.json +2 -2
- package/README.md +29 -4
- package/omp-extension/report-logic.ts +93 -0
- package/omp-extension/router-configure.ts +128 -2
- package/omp-extension/router-embed.ts +9 -6
- package/package.json +1 -1
- package/src/catalog/ollama-catalog.ts +30 -2
- package/src/cli/config-wizard.ts +11 -0
- package/src/cli/report.ts +7 -2
- package/src/config/defaults.ts +17 -0
- package/src/config/schema.ts +8 -0
- package/src/config/types.ts +65 -0
- package/src/cost/feedback.ts +81 -0
- package/src/cost/ledger.ts +110 -5
- package/src/cost/report.ts +118 -2
- package/src/cost/types.ts +32 -1
- package/src/router/candidates.ts +13 -4
- package/src/router/classify.ts +13 -0
- package/src/router/features.ts +59 -1
- package/src/router/index.ts +23 -5
- package/src/router/learned.ts +202 -0
- package/src/router/select.ts +64 -8
- package/src/router/types.ts +39 -1
- package/src/server/http.ts +82 -5
- package/src/server/overrides.ts +83 -0
- package/src/server/providers.ts +10 -2
- package/src/server/turn.ts +16 -1
- package/src/upstream/ollama-usage.ts +79 -2
- package/src/util/sqlite.ts +30 -0
- package/src/wire/openai/request.ts +4 -0
- package/src/wire/types.ts +2 -0
- package/test/classify.test.ts +13 -0
- package/test/config-wizard.test.ts +8 -6
- package/test/controls.test.ts +238 -0
- package/test/escalate.test.ts +1 -0
- package/test/failover.test.ts +6 -4
- package/test/features.test.ts +63 -0
- package/test/http-resilience.test.ts +1 -1
- package/test/learned.test.ts +61 -0
- package/test/ollama.test.ts +74 -2
- package/test/report-hub.test.ts +6 -2
- package/test/report-logic.test.ts +3 -0
- package/test/report.test.ts +57 -0
- package/test/select.test.ts +126 -1
- package/test/trust-attribution.test.ts +95 -0
- package/test/turn.test.ts +36 -4
- package/tools/replay.ts +267 -156
- package/tools/train-classifier.ts +111 -0
package/test/turn.test.ts
CHANGED
|
@@ -29,7 +29,7 @@ import type {
|
|
|
29
29
|
|
|
30
30
|
function mkConfig(escalation: Partial<EscalationConfig> = {}): RouterConfig {
|
|
31
31
|
return {
|
|
32
|
-
server: { host: "127.0.0.1", port: 8787, maxConcurrentTurns: 24 },
|
|
32
|
+
server: { host: "127.0.0.1", port: 8787, maxConcurrentTurns: 24, subagentProfile: "auto-sub" },
|
|
33
33
|
openrouter: { baseUrl: "https://openrouter.ai/api/v1", apiKey: "", title: "test", timeoutMs: 30_000, catalogTtlMs: 3_600_000, catalogRefreshMs: 0 },
|
|
34
34
|
ollama: { enabled: false, baseUrl: "http://127.0.0.1:11434/v1", apiKey: "", timeoutMs: 30_000, catalogTtlMs: 300_000, includeLocal: false, prices: {}, twins: {}, costBias: 1, biasUntilUsage: 0.9, usagePollMs: 0, quotaCooldownMs: 0, rateLimitCooldownMs: 0, planCreditsUsd: 0 },
|
|
35
35
|
benchmarks: { enabled: false, artificialAnalysisApiKey: "", benchlm: true, refreshMs: 86_400_000, timeoutMs: 30_000, useLocalScores: false },
|
|
@@ -46,10 +46,10 @@ function mkConfig(escalation: Partial<EscalationConfig> = {}): RouterConfig {
|
|
|
46
46
|
data: { axis: "intelligence", minQuality: 0 },
|
|
47
47
|
chat: { axis: "intelligence", minQuality: 0 },
|
|
48
48
|
},
|
|
49
|
-
filters: { allow: [], deny: [], includeFree: false, requireToolSupport: true, minTrust: 0.6, minTrustSamples: 5, trustScopedByHarness: false, trustWindowDays: 0, contextHeadroom: 1.2, latencyWeight: 0, latencyReferenceMs: 5000, latencyReferenceTokensPerSec: 30, latencyMinSamples: 20, escalationCostWeight: 0 },
|
|
49
|
+
filters: { allow: [], deny: [], includeFree: false, requireToolSupport: true, minTrust: 0.6, feedbackWeight: 0, minTrustSamples: 5, trustScopedByHarness: false, trustWindowDays: 0, contextHeadroom: 1.2, latencyWeight: 0, latencyReferenceMs: 5000, latencyReferenceTokensPerSec: 30, cacheReliabilityMinSamples: 10, latencyMinSamples: 20, escalationCostWeight: 0 },
|
|
50
50
|
classifier: {
|
|
51
51
|
ambiguityThreshold: 0,
|
|
52
|
-
model: "test/adjudicator",
|
|
52
|
+
model: "test/adjudicator", learnedModelPath: "",
|
|
53
53
|
maxCostFraction: 0.1,
|
|
54
54
|
maxCostUsd: 0.01,
|
|
55
55
|
timeoutMs: 5000,
|
|
@@ -57,7 +57,7 @@ function mkConfig(escalation: Partial<EscalationConfig> = {}): RouterConfig {
|
|
|
57
57
|
toolAxis: "coding",
|
|
58
58
|
chatAxis: "intelligence",
|
|
59
59
|
agenticLoopDepth: 3,
|
|
60
|
-
mechanicalRetryFactor: 0.2,
|
|
60
|
+
mechanicalRetryFactor: 0.2, readOnlyToolWeight: 0,
|
|
61
61
|
reasoningWeights: { medium: 0.14, high: 0.24, xhigh: 0.3, max: 0.34 },
|
|
62
62
|
},
|
|
63
63
|
escalation: {
|
|
@@ -76,6 +76,7 @@ function mkConfig(escalation: Partial<EscalationConfig> = {}): RouterConfig {
|
|
|
76
76
|
context: { enabled: false, baseUrl: "", token: "", defaultScope: "", timeoutMs: 3_000, maxStalenessMs: 900_000, maxBlockChars: 24_000, memoryLimit: 8, docsLimit: 2, sessionLimit: 6, briefChars: 0, recordTurns: false, maxQueue: 64 },
|
|
77
77
|
compaction: { enabled: false, budgetTokens: 40_000, floorRatio: 1, fitToWindow: true, protectRecentTurns: 4, maxToolResultBytes: 4_096, keepHeadBytes: 512, keepTailBytes: 512, elideSupersededReads: true, collapseDuplicateResults: true, replanGrowthRatio: 1 },
|
|
78
78
|
budget: { onExceeded: "downgrade" },
|
|
79
|
+
report: { baselines: [] },
|
|
79
80
|
profiles: [],
|
|
80
81
|
ledger: { path: ":memory:", blendWindowDays: 7, blendMinSamples: 20, fallbackBlend: { inputPerMtok: 1, outputPerMtok: 4 }, conversationTtlMs: 86_400_000 },
|
|
81
82
|
adaptiveTierFloors: true,
|
|
@@ -91,6 +92,7 @@ function mkReq(): NormRequest {
|
|
|
91
92
|
harnessId: "",
|
|
92
93
|
ompSessionId: "",
|
|
93
94
|
agentdoxScope: "",
|
|
95
|
+
isSubagent: false,
|
|
94
96
|
requestedModel: "auto",
|
|
95
97
|
messages: [{ role: "user", text: "hi", images: 0, textBytes: 2, toolCalls: [] }],
|
|
96
98
|
tools: [],
|
|
@@ -896,4 +898,34 @@ describe("latency measurement covers the work the router actually does", () => {
|
|
|
896
898
|
expect(map.get("conv-test")!.cacheWarmSlug).toBe(ollamaModel.slug);
|
|
897
899
|
});
|
|
898
900
|
|
|
901
|
+
test("an Ollama estimate is scaled by the ledger-vs-meter calibration", async () => {
|
|
902
|
+
const ollamaModel: CatalogModel = {
|
|
903
|
+
slug: "ollama/glm-5.3-flash",
|
|
904
|
+
provider: "ollama",
|
|
905
|
+
canonicalSlug: "ollama/glm-5.3-flash",
|
|
906
|
+
name: "glm",
|
|
907
|
+
contextLength: 1_000_000,
|
|
908
|
+
supportsTools: true,
|
|
909
|
+
supportsReasoning: true,
|
|
910
|
+
reasoningMandatory: false,
|
|
911
|
+
supportsToolChoice: false,
|
|
912
|
+
inputModalities: ["text"],
|
|
913
|
+
price: { prompt: 0.15 / 1e6, cacheRead: 0.03 / 1e6, completion: 0.5 / 1e6 },
|
|
914
|
+
priceTiers: [],
|
|
915
|
+
quality: {},
|
|
916
|
+
tokenizer: "Other",
|
|
917
|
+
isFree: false,
|
|
918
|
+
createdAtMs: 0,
|
|
919
|
+
author: "ollama",
|
|
920
|
+
};
|
|
921
|
+
const priced = { ...catalog, find: (slug: string) => (slug === ollamaModel.slug ? ollamaModel : undefined) };
|
|
922
|
+
const { router } = mkRouter([mkDecision("simple", ollamaModel.slug)]);
|
|
923
|
+
const { upstream } = mkUpstream([{ kind: "chunks", chunks: [startChunk(ollamaModel.slug), textChunk("ok"), finishChunk("stop"), usageChunk({ promptTokens: 100_000, completionTokens: 0 }, null)] }]);
|
|
924
|
+
const { ledger, entries } = mkLedger();
|
|
925
|
+
const { store } = mkConversations();
|
|
926
|
+
await runTurn(mkReq(), mkSink().sink, { config: mkConfig(), router, upstream, ledger, conversations: store, catalog: priced, context: createDisabledBridge(), ollamaCostScale: () => 1.25 }, new AbortController().signal);
|
|
927
|
+
// 100k × $0.15/M = $0.015, scaled ×1.25.
|
|
928
|
+
expect(entries[0]!.reportedUsd).toBeCloseTo(0.01875, 6);
|
|
929
|
+
});
|
|
930
|
+
|
|
899
931
|
});
|