diff --git a/src/suite.ts b/src/suite.ts index 214c139..5a006f8 100644 --- a/src/suite.ts +++ b/src/suite.ts @@ -91,6 +91,13 @@ function validateSamplingOptions(data: Record, label: string): } } +function validateTags(tags: unknown, caseId: string): string[] | undefined { + if (tags === undefined) return undefined; + if (typeof tags === "string") return [tags]; + if (Array.isArray(tags)) return (tags as unknown[]).map(String); + throw new SuiteValidationError(`case "${caseId}" tags must be a string or array of strings`); +} + function validateCase(data: unknown, index: number, ids: Set): EvalCase { assert(data && typeof data === "object", `cases[${index}] must be an object`); const c = data as Record; @@ -123,7 +130,7 @@ function validateCase(data: unknown, index: number, ids: Set): EvalCase maxTokens: typeof c.maxTokens === "number" ? c.maxTokens : undefined, expected: typeof c.expected === "string" ? c.expected : undefined, scorers, - tags: Array.isArray(c.tags) ? (c.tags as string[]).map(String) : undefined, + tags: validateTags(c.tags, c.id as string), vars: isVars(c.vars) ? c.vars : undefined, }; } diff --git a/tests/suite.test.ts b/tests/suite.test.ts index 70dcc91..4368605 100644 --- a/tests/suite.test.ts +++ b/tests/suite.test.ts @@ -54,6 +54,21 @@ cases: expect(() => validateSuite({ cases: [] })).toThrow(SuiteValidationError); }); + it("coerces string tags to a single-element array", () => { + const suite = validateSuite({ + name: "d", + cases: [ + { + id: "arith", + tags: "arith", + input: { prompt: "2+2" }, + scorers: [{ type: "regex", pattern: "4" }], + }, + ], + }); + expect(suite.cases[0]!.tags).toEqual(["arith"]); + }); + it("rejects duplicate case ids", () => { expect(() => validateSuite({