Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 0 additions & 31 deletions src/pricing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,37 +368,6 @@ describe("pricing module", () => {
});
});

describe("getModelCount", () => {
it("returns 0 when no cache loaded", async () => {
const { getModelCount } = await loadPricing();
expect(getModelCount()).toBe(0);
});

it("returns correct count after loading data", async () => {
globalThis.fetch = vi.fn().mockResolvedValue({
ok: true,
json: async () => ({
"model-a": {
input_cost_per_token: 0.001,
output_cost_per_token: 0.002,
},
"model-b": {
input_cost_per_token: 0.003,
output_cost_per_token: 0.004,
},
"model-c": {
input_cost_per_token: 0.005,
output_cost_per_token: 0.006,
},
}),
});

const { refreshPrices, getModelCount } = await loadPricing();
await refreshPrices();
expect(getModelCount()).toBe(3);
});
});

describe("disk cache", () => {
it("calls writeFileSync after refreshPrices", async () => {
globalThis.fetch = vi.fn().mockResolvedValue({
Expand Down
4 changes: 0 additions & 4 deletions src/pricing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,3 @@ export async function getModels(): Promise<Record<string, ModelEntry>> {
}
return cache.models;
}

export function getModelCount(): number {
return cache ? Object.keys(cache.models).length : 0;
}
66 changes: 1 addition & 65 deletions src/search.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import type { ModelEntry } from "./pricing.js";
import { fuzzyMatch, fuzzyMatchMultiple, fuzzyMatchWithMetadata } from "./search.js";
import { fuzzyMatch, fuzzyMatchWithMetadata } from "./search.js";

/** Helper to build a minimal ModelEntry for testing */
function makeModel(overrides: Partial<ModelEntry> & { key: string }): ModelEntry {
Expand Down Expand Up @@ -181,63 +181,6 @@ describe("fuzzyMatch", () => {
});
});

describe("fuzzyMatchMultiple", () => {
it("strips openrouter/ prefix before matching", () => {
const results = fuzzyMatchMultiple("openrouter/claude", sampleModels);
expect(results.length).toBeGreaterThanOrEqual(1);
const keys = results.map((r) => r.key);
expect(keys.some((k) => k.includes("claude"))).toBe(true);
});

it("strips azure/ prefix before matching multiple", () => {
const results = fuzzyMatchMultiple("azure/gpt", sampleModels);
expect(results.length).toBeGreaterThanOrEqual(1);
const keys = results.map((r) => r.key);
expect(keys.some((k) => k.includes("gpt"))).toBe(true);
});

it("returns up to the default limit of 5 results", () => {
const results = fuzzyMatchMultiple("claude", sampleModels);
// We have 2 claude models, so should return at most 2 for "claude"
expect(results.length).toBeGreaterThanOrEqual(1);
expect(results.length).toBeLessThanOrEqual(5);
});

it("respects the limit parameter", () => {
const results = fuzzyMatchMultiple("model", sampleModels, 2);
expect(results.length).toBeLessThanOrEqual(2);
});

it("returns ModelEntry objects with correct structure", () => {
const results = fuzzyMatchMultiple("gpt", sampleModels, 3);
expect(results.length).toBeGreaterThanOrEqual(1);

for (const entry of results) {
expect(entry).toHaveProperty("key");
expect(entry).toHaveProperty("input_cost_per_token");
expect(entry).toHaveProperty("output_cost_per_token");
expect(entry).toHaveProperty("litellm_provider");
}
});

it("returns empty array for garbage query", () => {
const results = fuzzyMatchMultiple("xyzzyplugh_12345", sampleModels);
expect(results).toEqual([]);
});

it("returns empty array for empty models", () => {
const results = fuzzyMatchMultiple("gpt-4o", {});
expect(results).toEqual([]);
});

it("matches claude models with a general query", () => {
const results = fuzzyMatchMultiple("claude", sampleModels, 10);
const keys = results.map((r) => r.key);
expect(keys).toContain("claude-sonnet-4-5");
expect(keys).toContain("claude-opus-4");
});
});

describe("fine-tuned model patterns (ft: prefix)", () => {
it("extracts base model from OpenAI fine-tuned pattern", () => {
const result = fuzzyMatch("ft:gpt-4o:my-org:custom_suffix:id", sampleModels);
Expand Down Expand Up @@ -278,13 +221,6 @@ describe("fine-tuned model patterns (ft: prefix)", () => {
expect(result?.key).toBe("gpt-4o");
});

it("fuzzyMatchMultiple handles fine-tuned patterns", () => {
const results = fuzzyMatchMultiple("ft:gpt:my-org:suffix:id", sampleModels);
expect(results.length).toBeGreaterThanOrEqual(1);
const keys = results.map((r) => r.key);
expect(keys.some((k) => k.includes("gpt"))).toBe(true);
});

it("returns null for invalid fine-tuned pattern with missing base model", () => {
const result = fuzzyMatch("ft:nonexistent-model:org:suffix:id", sampleModels);
expect(result).toBeNull();
Expand Down
15 changes: 0 additions & 15 deletions src/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,3 @@ export function fuzzyMatchWithMetadata(
const entry = fuzzyMatch(query, models);
return { entry, isFineTuned };
}

export function fuzzyMatchMultiple(
query: string,
models: Record<string, ModelEntry>,
limit = 5,
): ModelEntry[] {
// Strip provider prefix first, then handle fine-tuned pattern
const withoutProvider = stripProviderPrefix(query);
const { base } = extractFineTunedBase(withoutProvider);
const normalizedQuery = base;

const index = buildIndex(models);
const results = index.search(normalizedQuery, { limit });
return results.map((r) => models[r.item.key]);
}