auto-model-router 0.27.0 → 0.27.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.
@@ -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.27.0",
10
+ "version": "0.27.1",
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.27.0",
17
+ "version": "0.27.1",
18
18
  "author": {
19
19
  "name": "drewappling",
20
20
  "email": "drewappling@gmail.com"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auto-model-router",
3
- "version": "0.27.0",
3
+ "version": "0.27.1",
4
4
  "private": false,
5
5
  "description": "Local cost/complexity-aware model router for Oh My Pi, backed by OpenRouter",
6
6
  "type": "module",
@@ -723,14 +723,34 @@ export function startServer(cfg: RouterConfig): StartedServer {
723
723
  const named = Array.isArray(body?.anchors) ? (body.anchors as unknown[]).filter((a): a is string => typeof a === "string") : [];
724
724
  const anchors = named.length > 0 ? [...new Set(named)] : pickAnchors(models, slug);
725
725
  if (anchors.length < MIN_ANCHORS) return wireErrorResponse({ status: 422, code: "invalid_request_error", message: `need at least ${MIN_ANCHORS} scored, tool-capable anchor models to calibrate against` });
726
+ // A rate-limited dispatch is not a failed task. Ollama Cloud answers "too many
727
+ // concurrent requests" well below four models in flight, and the runner folds a
728
+ // throwing completion in as grade 0 — which would score a provider's throttle as
729
+ // the model being wrong. Retry with backoff, and keep the default concurrency
730
+ // low enough that the throttle is rarely reached in the first place.
726
731
  const complete: Completer = async (target, messages) => {
727
- const out = await upstream.complete({ model: target, stream: false, temperature: 0, max_tokens: 1024, messages }, AbortSignal.timeout(120_000));
728
- return out.text;
732
+ let last: unknown = null;
733
+ for (let attempt = 0; attempt < 4; attempt++) {
734
+ if (attempt > 0) {
735
+ const { promise, resolve } = Promise.withResolvers<void>();
736
+ setTimeout(resolve, attempt * 4000);
737
+ await promise;
738
+ }
739
+ try {
740
+ const out = await upstream.complete({ model: target, stream: false, temperature: 0, max_tokens: 1024, messages }, AbortSignal.timeout(120_000));
741
+ return out.text;
742
+ } catch (err) {
743
+ last = err;
744
+ }
745
+ }
746
+ throw last instanceof Error ? last : new Error(String(last));
729
747
  };
730
748
  const judgeSlug = typeof body?.judge === "string" && body.judge !== "" ? body.judge : "";
749
+ const asked = typeof body?.concurrency === "number" ? Math.floor(body.concurrency) : 2;
731
750
  const results = await runEval({
732
751
  slugs: [slug, ...anchors],
733
752
  complete,
753
+ concurrency: Math.min(Math.max(1, asked), 8),
734
754
  ...(judgeSlug === "" ? {} : { judge: makeJudge(complete, judgeSlug) }),
735
755
  });
736
756
  const target = results[0]!;