diff --git a/open-sse/services/autoCombo/autoPrefix.ts b/open-sse/services/autoCombo/autoPrefix.ts new file mode 100644 index 0000000000..9501f9ed19 --- /dev/null +++ b/open-sse/services/autoCombo/autoPrefix.ts @@ -0,0 +1,50 @@ +export type AutoVariant = "coding" | "fast" | "cheap" | "offline" | "smart" | "lkgp"; + +export interface AutoPrefixParseResult { + valid: boolean; + variant?: AutoVariant; + error?: string; +} + +const VALID_VARIANTS: AutoVariant[] = ["coding", "fast", "cheap", "offline", "smart", "lkgp"]; + +/** + * Parses a model name to determine if it's an auto-prefixed model and extracts the variant. + * + * Examples: + * - "auto" -> { valid: true, variant: undefined } (default) + * - "auto/coding" -> { valid: true, variant: "coding" } + * - "auto/lkgp" -> { valid: true, variant: "lkgp" } + * - "auto/" -> { valid: true, variant: undefined } (default) + * - "autocoding" -> { valid: false, error: "Invalid auto prefix format" } + * - "otherModel" -> { valid: false, error: "Not an auto-prefixed model" } + */ +export function parseAutoPrefix(model: string): AutoPrefixParseResult { + if (!model.startsWith("auto")) { + return { valid: false, error: "Not an auto-prefixed model" }; + } + + const parts = model.split("/"); + + if (parts.length === 1) { + if (parts[0] === "auto") { + return { valid: true, variant: undefined }; // Default auto + } else { + return { valid: false, error: "Invalid auto prefix format" }; + } + } + + if (parts.length === 2) { + if (parts[0] !== "auto") { + return { valid: false, error: "Invalid auto prefix format" }; + } + const variant = parts[1] as AutoVariant; + if (variant === "" || VALID_VARIANTS.includes(variant)) { + return { valid: true, variant: variant === "" ? undefined : variant }; + } else { + return { valid: false, error: `Invalid auto variant: ${variant}` }; + } + } + + return { valid: false, error: "Invalid auto prefix format" }; +} diff --git a/tests/unit/autoPrefix.test.ts b/tests/unit/autoPrefix.test.ts new file mode 100644 index 0000000000..cb0588dc61 --- /dev/null +++ b/tests/unit/autoPrefix.test.ts @@ -0,0 +1,89 @@ +import { parseAutoPrefix } from "../../open-sse/services/autoCombo/autoPrefix.ts"; +import assert from "node:assert/strict"; +import { describe, it } from "node:test"; + +describe("parseAutoPrefix", () => { + it('should return valid for "auto" with no variant', () => { + const result = parseAutoPrefix("auto"); + assert.strictEqual(result.valid, true); + assert.strictEqual(result.variant, undefined); + }); + + it('should return valid for "auto/" with no variant', () => { + const result = parseAutoPrefix("auto/"); + assert.strictEqual(result.valid, true); + assert.strictEqual(result.variant, undefined); + }); + + it('should return valid for "auto/coding" with coding variant', () => { + const result = parseAutoPrefix("auto/coding"); + assert.strictEqual(result.valid, true); + assert.strictEqual(result.variant, "coding"); + }); + + it('should return valid for "auto/fast" with fast variant', () => { + const result = parseAutoPrefix("auto/fast"); + assert.strictEqual(result.valid, true); + assert.strictEqual(result.variant, "fast"); + }); + + it('should return valid for "auto/cheap" with cheap variant', () => { + const result = parseAutoPrefix("auto/cheap"); + assert.strictEqual(result.valid, true); + assert.strictEqual(result.variant, "cheap"); + }); + + it('should return valid for "auto/offline" with offline variant', () => { + const result = parseAutoPrefix("auto/offline"); + assert.strictEqual(result.valid, true); + assert.strictEqual(result.variant, "offline"); + }); + + it('should return valid for "auto/smart" with smart variant', () => { + const result = parseAutoPrefix("auto/smart"); + assert.strictEqual(result.valid, true); + assert.strictEqual(result.variant, "smart"); + }); + + it('should return valid for "auto/lkgp" with lkgp variant', () => { + const result = parseAutoPrefix("auto/lkgp"); + assert.strictEqual(result.valid, true); + assert.strictEqual(result.variant, "lkgp"); + }); + + it('should return invalid for "autocoding" (invalid format)', () => { + const result = parseAutoPrefix("autocoding"); + assert.strictEqual(result.valid, false); + assert.match(result.error || "", /Invalid auto prefix format/); + }); + + it('should return invalid for "auto/unknown" (invalid variant)', () => { + const result = parseAutoPrefix("auto/unknown"); + assert.strictEqual(result.valid, false); + assert.match(result.error || "", /Invalid auto variant: unknown/); + }); + + it("should return invalid for a non-auto prefixed model", () => { + const result = parseAutoPrefix("otherModel"); + assert.strictEqual(result.valid, false); + assert.match(result.error || "", /Not an auto-prefixed model/); + }); + + it("should return invalid for empty string", () => { + const result = parseAutoPrefix(""); + assert.strictEqual(result.valid, false); + assert.match(result.error || "", /Not an auto-prefixed model/); + }); + + it("should return invalid for null/undefined input (handled by TS but for robustness)", () => { + // @ts-ignore testing invalid input that TS normally prevents + const result = parseAutoPrefix(null); + assert.strictEqual(result.valid, false); + assert.match(result.error || "", /Not an auto-prefixed model/); + + // @ts-ignore + const result2 = parseAutoPrefix(undefined); + assert.strictEqual(result2.valid, false); + assert.match(result2.error || "", /Not an auto-prefixed model/); + }); +});