feat(pi): add Cursor models through the OMP gateway
This commit is contained in:
parent
b9ab5a392e
commit
73e9b17305
4 changed files with 573 additions and 0 deletions
77
pi/extensions/omp-gateway/tests/catalog.test.ts
Normal file
77
pi/extensions/omp-gateway/tests/catalog.test.ts
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import { assertCursorOnlyCatalog, discoverCursorModels, gatewayCursorRows, gatewayPayload, loopbackBaseUrl } from "../catalog.ts";
|
||||
|
||||
function catalogs() {
|
||||
return {
|
||||
gateway: { data: [{ id: "cursor/grok-4.7", owned_by: "cursor", display_name: "Grok 4.7", context_length: 256000,
|
||||
max_output_tokens: 64000, input_modalities: ["text", "image"] }] },
|
||||
local: { models: [{ provider: "cursor", kind: "chat", id: "grok-4.7", name: "Grok 4.7", input: ["text", "image"],
|
||||
reasoning: true, thinking: ["low", "medium", "high", "xhigh"], contextWindow: 500000, maxTokens: 64000,
|
||||
cost: { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 } }] },
|
||||
};
|
||||
}
|
||||
|
||||
test("joins routable models with OMP pricing, capabilities, and thinking levels", () => {
|
||||
const { gateway, local } = catalogs();
|
||||
const models = discoverCursorModels(gateway, local, "http://127.0.0.1:4000/v1");
|
||||
assert.equal(models.length, 1);
|
||||
const [model] = models;
|
||||
assert.equal(model.provider, "cursor");
|
||||
assert.equal(model.id, "grok-4.7");
|
||||
assert.equal(model.contextWindow, 256000, "Use the conservative intersection, not a guessed 500k limit");
|
||||
assert.deepEqual(model.cost, { input: 2, output: 6, cacheRead: 0.5, cacheWrite: 0 });
|
||||
assert.equal(model.thinkingLevelMap?.max, null);
|
||||
assert.equal(model.thinkingLevelMap?.xhigh, "xhigh");
|
||||
assert.deepEqual(model.input, ["text", "image"]);
|
||||
});
|
||||
|
||||
test("excludes other providers, unsupported tools, non-chat models, and unsafe ids", () => {
|
||||
const { gateway } = catalogs();
|
||||
const valid = gateway.data[0];
|
||||
const payload = { data: [valid, { ...valid, owned_by: "xai" }, { ...valid, supports_tools: false },
|
||||
{ ...valid, kind: "image" }, { ...valid, id: "cursor/../../key" }, null] };
|
||||
assert.equal(gatewayCursorRows(payload).length, 1);
|
||||
assert.throws(() => gatewayCursorRows({ error: "not a catalog" }), /invalid model catalog/);
|
||||
});
|
||||
|
||||
test("rejects a shared-provider gateway before model discovery", () => {
|
||||
assertCursorOnlyCatalog(catalogs().gateway);
|
||||
assertCursorOnlyCatalog({ data: [] });
|
||||
for (const row of [{ id: "xai/grok-4.7", owned_by: "xai" },
|
||||
{ id: "xai/grok-4.7", owned_by: "cursor" }, null]) {
|
||||
assert.throws(() => assertCursorOnlyCatalog({ data: [row] }), /non-Cursor/);
|
||||
}
|
||||
});
|
||||
|
||||
test("never substitutes zero prices or guessed capabilities for malformed metadata", () => {
|
||||
const { gateway, local } = catalogs();
|
||||
local.models[0].cost.input = Number.NaN;
|
||||
assert.throws(() => discoverCursorModels(gateway, local, "http://localhost:4000/v1"), /invalid pricing/);
|
||||
const fresh = catalogs();
|
||||
fresh.local.models[0].thinking = [];
|
||||
assert.throws(() => discoverCursorModels(fresh.gateway, fresh.local, "http://localhost:4000/v1"), /thinking-level/);
|
||||
assert.throws(() => discoverCursorModels(fresh.gateway, { models: [] }, "http://localhost:4000/v1"), /do not match/);
|
||||
});
|
||||
|
||||
test("accepts an authoritative empty catalog and deduplicates model ids", () => {
|
||||
const { gateway, local } = catalogs();
|
||||
gateway.data.push(gateway.data[0]);
|
||||
assert.equal(discoverCursorModels(gateway, local, "http://localhost:4000/v1").length, 1);
|
||||
assert.deepEqual(discoverCursorModels({ data: [] }, local, "http://localhost:4000/v1"), []);
|
||||
});
|
||||
|
||||
test("qualifies wire ids and keeps session identity and request fields", () => {
|
||||
assert.deepEqual(gatewayPayload({ model: "grok-4.7", messages: [], temperature: 0.5 }, "grok-4.7", "session-one"),
|
||||
{ model: "cursor/grok-4.7", messages: [], temperature: 0.5, prompt_cache_key: "session-one" });
|
||||
assert.throws(() => gatewayPayload(null, "grok-4.7"), /Invalid/);
|
||||
assert.throws(() => gatewayPayload({}, "../bad"), /Invalid/);
|
||||
});
|
||||
|
||||
test("rejects remote endpoints, embedded credentials, and query strings", () => {
|
||||
assert.equal(loopbackBaseUrl("http://127.0.0.1:4000/v1/"), "http://127.0.0.1:4000/v1");
|
||||
assert.equal(loopbackBaseUrl("http://[::1]:4000/v1"), "http://[::1]:4000/v1");
|
||||
for (const url of ["https://remote.example/v1", "http://token@localhost:4000/v1", "http://localhost/v1?token=x", "http://localhost/"]) {
|
||||
assert.throws(() => loopbackBaseUrl(url), /loopback/);
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue