Files
OmniRoute/tests/unit/cursor-errors-classify.test.ts
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.

Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.

Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
2026-08-23 11:45:01 -03:00

79 lines
3.1 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import {
classifyCursorError,
classifyCursorErrorKind,
isCursorBenignCancelError,
isCursorRequestTooLargeDetail,
resolveCursorEmptyTurnError,
CURSOR_EMPTY_TURN_MESSAGE,
} from "../../open-sse/executors/cursor/cursorErrors.ts";
test("classifyCursorErrorKind: resource_exhausted without size cue is rate_limit", () => {
assert.equal(classifyCursorErrorKind("resource_exhausted: quota exhausted"), "rate_limit");
assert.equal(classifyCursorErrorKind("You're out of usage. Increase limits"), "rate_limit");
});
test("classifyCursorErrorKind: resource_exhausted + size cue is invalid", () => {
assert.equal(classifyCursorErrorKind("resource_exhausted: tool catalog too large"), "invalid");
assert.equal(isCursorRequestTooLargeDetail("tool catalog too large"), true);
assert.equal(
isCursorRequestTooLargeDetail("resource_exhausted while loading tool catalog: quota exhausted"),
false
);
});
test("classifyCursorErrorKind: auth cues", () => {
assert.equal(classifyCursorErrorKind("Authentication error"), "auth");
assert.equal(classifyCursorErrorKind("unauthenticated"), "auth");
});
test("classifyCursorErrorKind: AI Model Not Found is rate_limit (Cursor out-of-usage)", () => {
assert.equal(
classifyCursorErrorKind("not_found: AI Model Not Found (reset after 109h 9s)"),
"rate_limit"
);
assert.equal(classifyCursorErrorKind("not_found: AI Model Not Found"), "rate_limit");
assert.equal(classifyCursorErrorKind("model not found"), "invalid");
});
test("classifyCursorError redacts credentials and paths", () => {
const out = classifyCursorError(
"Authentication failed authorization=secret-token path=/Users/alice/code/file"
);
assert.equal(out.kind, "auth");
assert.equal(out.status, 401);
assert.match(out.message, /\[REDACTED\]/);
assert.match(out.message, /\[REDACTED_PATH\]/);
assert.doesNotMatch(out.message, /secret-token/);
assert.doesNotMatch(out.message, /\/Users\/alice/);
});
test("isCursorBenignCancelError recognizes NGHTTP2_CANCEL / suspend", () => {
assert.equal(isCursorBenignCancelError({ code: "NGHTTP2_CANCEL" }), true);
assert.equal(isCursorBenignCancelError(new Error("nghttp2_cancel")), true);
assert.equal(isCursorBenignCancelError(new Error("Cursor stream suspended")), true);
assert.equal(isCursorBenignCancelError(new Error("resource_exhausted")), false);
});
test("resolveCursorEmptyTurnError: no upstream → actionable 502", () => {
const out = resolveCursorEmptyTurnError({});
assert.equal(out.status, 502);
assert.equal(out.message, CURSOR_EMPTY_TURN_MESSAGE);
});
test("resolveCursorEmptyTurnError: quotaExhaustedHint → 429", () => {
const out = resolveCursorEmptyTurnError({ quotaExhaustedHint: true });
assert.equal(out.status, 429);
assert.equal(out.type, "rate_limit_error");
assert.equal(out.message, CURSOR_EMPTY_TURN_MESSAGE);
});
test("resolveCursorEmptyTurnError: classifies upstream quota message as 429", () => {
const out = resolveCursorEmptyTurnError({
upstreamMessage: "resource_exhausted: too many requests",
});
assert.equal(out.status, 429);
assert.equal(out.kind, "rate_limit");
});