mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-26 17:12:27 +03:00
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.
79 lines
3.1 KiB
TypeScript
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");
|
|
});
|