auto-model-router 0.30.1 → 0.30.2
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/package.json +1 -1
- package/src/server/http.ts +51 -22
|
@@ -7,14 +7,14 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "auto-model-router: a local cost/complexity-aware model router for Oh My Pi, backed by OpenRouter",
|
|
10
|
-
"version": "0.30.
|
|
10
|
+
"version": "0.30.2",
|
|
11
11
|
"pluginRoot": "."
|
|
12
12
|
},
|
|
13
13
|
"plugins": [
|
|
14
14
|
{
|
|
15
15
|
"name": "auto-model-router",
|
|
16
16
|
"description": "Local cost/complexity-aware model router for Oh My Pi, backed by OpenRouter. Runs in-process, routes per turn by price and task complexity, with budget caps, mid-stream escalation, and cache-aware hysteresis.",
|
|
17
|
-
"version": "0.30.
|
|
17
|
+
"version": "0.30.2",
|
|
18
18
|
"author": {
|
|
19
19
|
"name": "drewappling",
|
|
20
20
|
"email": "drewappling@gmail.com"
|
package/package.json
CHANGED
package/src/server/http.ts
CHANGED
|
@@ -248,6 +248,11 @@ export function startServer(cfg: RouterConfig): StartedServer {
|
|
|
248
248
|
const overrides = createSessionOverrides();
|
|
249
249
|
const feedback = createFeedbackStore(db);
|
|
250
250
|
const kv = createKv(db);
|
|
251
|
+
/**
|
|
252
|
+
* Background local-benchmark runs. In memory and not persisted: a run is an explicit,
|
|
253
|
+
* attended admin action, and its lasting output is the `local_scores` row it writes.
|
|
254
|
+
*/
|
|
255
|
+
const benchmarkJobs = new Map<string, { state: "running" | "done" | "error"; slug: string; startedAtMs: number; result?: Record<string, unknown>; error?: string }>();
|
|
251
256
|
const digester = createDigester({ cfg, catalog, ledger, upstream, log });
|
|
252
257
|
const turnDeps = { config: cfg, router, upstream, ledger, conversations, catalog, context, overrides, ollamaCostScale, digester };
|
|
253
258
|
|
|
@@ -768,28 +773,52 @@ export function startServer(cfg: RouterConfig): StartedServer {
|
|
|
768
773
|
};
|
|
769
774
|
const judgeSlug = typeof body?.judge === "string" && body.judge !== "" ? body.judge : "";
|
|
770
775
|
const asked = typeof body?.concurrency === "number" ? Math.floor(body.concurrency) : 2;
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
776
|
+
// The run is a BACKGROUND job, not a long request. Bun caps `idleTimeout` at 255
|
|
777
|
+
// seconds, so a suite of any size over ten repeats outlives the socket: measured,
|
|
778
|
+
// a single pass returned in 193s and two passes died at ~350s with the response
|
|
779
|
+
// lost. The caller polls instead.
|
|
780
|
+
const jobId = `bench_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
781
|
+
const started = Date.now();
|
|
782
|
+
benchmarkJobs.set(jobId, { state: "running", slug, startedAtMs: started });
|
|
783
|
+
void (async () => {
|
|
784
|
+
try {
|
|
785
|
+
const results = await runEval({
|
|
786
|
+
slugs: [slug, ...anchors],
|
|
787
|
+
complete,
|
|
788
|
+
toolComplete,
|
|
789
|
+
repeats: Math.min(Math.max(1, typeof body?.repeats === "number" ? Math.floor(body.repeats) : 1), 20),
|
|
790
|
+
concurrency: Math.min(Math.max(1, asked), 8),
|
|
791
|
+
...(judgeSlug === "" ? {} : { judge: makeJudge(complete, judgeSlug) }),
|
|
792
|
+
});
|
|
793
|
+
const target = results[0]!;
|
|
794
|
+
const published = (s: string, axis: QualityAxis): number | undefined => models.find((m) => m.slug === s)?.quality[axis];
|
|
795
|
+
const cal = fitCalibration(results.slice(1), published);
|
|
796
|
+
const authorOf = (s: string): string => models.find((m) => m.slug === s)?.author ?? "";
|
|
797
|
+
const fresh = toLocalFeedScores([target], cal, authorOf);
|
|
798
|
+
const shared = { slug, anchors, raw: target.axes, byComplexity: target.byComplexity, repeats: target.repeats, spread: target.spread, errors: target.errors, tookMs: Date.now() - started };
|
|
799
|
+
if (fresh.length === 0) {
|
|
800
|
+
benchmarkJobs.set(jobId, { state: "done", slug, startedAtMs: started, result: { ...shared, calibrated: null, applied: false, reason: "no axis produced a usable fit; try more or better-spread anchors" } });
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
// Merge, never replace: other models' measurements are not this run's to discard.
|
|
804
|
+
const kept = loadLocalScores(db).filter((s) => s.key !== fresh[0]!.key);
|
|
805
|
+
saveLocalScores(db, [...kept, ...fresh]);
|
|
806
|
+
log.info("benchmarked a model with the local eval suite", { slug, anchors: anchors.length, repeats: target.repeats, errors: target.errors, useLocalScores: cfg.benchmarks.useLocalScores });
|
|
807
|
+
benchmarkJobs.set(jobId, { state: "done", slug, startedAtMs: started, result: { ...shared, calibrated: fresh[0], applied: cfg.benchmarks.useLocalScores } });
|
|
808
|
+
} catch (err) {
|
|
809
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
810
|
+
log.warn("local benchmark run failed", { slug, error: message });
|
|
811
|
+
benchmarkJobs.set(jobId, { state: "error", slug, startedAtMs: started, error: message });
|
|
812
|
+
}
|
|
813
|
+
})();
|
|
814
|
+
return json({ jobId, state: "running", slug, anchors });
|
|
815
|
+
}
|
|
816
|
+
if (req.method === "GET" && url.pathname === "/v1/router/benchmark") {
|
|
817
|
+
const jobId = url.searchParams.get("job");
|
|
818
|
+
if (jobId === null) return json({ jobs: [...benchmarkJobs.entries()].map(([id, j]) => ({ id, slug: j.slug, state: j.state, startedAtMs: j.startedAtMs })) });
|
|
819
|
+
const job = benchmarkJobs.get(jobId);
|
|
820
|
+
if (job === undefined) return wireErrorResponse({ status: 404, code: "invalid_request_error", message: `no benchmark job ${jobId}` });
|
|
821
|
+
return json({ id: jobId, slug: job.slug, state: job.state, startedAtMs: job.startedAtMs, ...(job.result === undefined ? {} : { result: job.result }), ...(job.error === undefined ? {} : { error: job.error }) });
|
|
793
822
|
}
|
|
794
823
|
if (req.method === "POST" && url.pathname === "/v1/router/feedback") {
|
|
795
824
|
// A user verdict on the newest routed turn of an omp session.
|