import type { EngineChatMessage, EngineChatTool } from '../engine'; export const RELEASE_PROMPT_MATRIX_PATH = 'fixtures/release-prompts.json'; export const RELEASE_PROMPT_MATRIX_MIN_CASES = 6; export const RELEASE_PROMPT_MATRIX_MAX_TOKENS = 64; export interface ReleasePromptCase { id: string; messages: EngineChatMessage[]; tools: EngineChatTool[]; } function record(value: unknown, field: string): Record { if (typeof value !== 'object' || value === null || Array.isArray(value)) { throw new Error(`${field} must be an object.`); } return value as Record; } function nonEmptyString(value: unknown, field: string): string { if (typeof value !== 'string' || value.trim() === '') throw new Error(`${field} must be a non-empty string.`); return value; } function parseMessage(value: unknown, field: string): EngineChatMessage { const message = record(value, field); const role = nonEmptyString(message.role, `${field}.role`); const content = nonEmptyString(message.content, `${field}.content`); if (role !== 'system' && role !== 'user' && role !== 'assistant') { throw new Error(`${field}.role must be system, user, or assistant.`); } return { role, content }; } function parseTool(value: unknown, field: string): EngineChatTool { const tool = record(value, field); if (tool.type !== 'function') throw new Error(`${field}.type must be function.`); const fn = record(tool.function, `${field}.function`); const parameters = record(fn.parameters, `${field}.function.parameters`); if (parameters.type !== 'object') throw new Error(`${field}.function.parameters.type must be object.`); const properties = record(parameters.properties, `${field}.function.parameters.properties`); return { type: 'function', function: { name: nonEmptyString(fn.name, `${field}.function.name`), ...(typeof fn.description === 'string' ? { description: fn.description } : {}), parameters: { type: 'object', properties: properties as EngineChatTool['function']['parameters']['properties'], ...(Array.isArray(parameters.required) ? { required: parameters.required.map((entry, index) => nonEmptyString(entry, `${field}.function.parameters.required[${index}]`)) } : {}), }, }, }; } export function parseReleasePromptMatrix(value: unknown): ReleasePromptCase[] { if (!Array.isArray(value) || value.length < RELEASE_PROMPT_MATRIX_MIN_CASES) { throw new Error(`Release prompt matrix requires at least ${RELEASE_PROMPT_MATRIX_MIN_CASES} cases.`); } const ids = new Set(); const cases = value.map((entry, caseIndex) => { const item = record(entry, `cases[${caseIndex}]`); const id = nonEmptyString(item.id, `cases[${caseIndex}].id`); if (ids.has(id)) throw new Error(`Duplicate release prompt id: ${id}.`); ids.add(id); if (!Array.isArray(item.messages) || item.messages.length === 0) { throw new Error(`cases[${caseIndex}].messages must be a non-empty array.`); } const messages = item.messages.map((message, messageIndex) => ( parseMessage(message, `cases[${caseIndex}].messages[${messageIndex}]`) )); const tools = item.tools === undefined ? [] : Array.isArray(item.tools) ? item.tools.map((tool, toolIndex) => parseTool(tool, `cases[${caseIndex}].tools[${toolIndex}]`)) : (() => { throw new Error(`cases[${caseIndex}].tools must be an array.`); })(); return { id, messages, tools }; }); const multiturn = cases.find((entry) => entry.id === 'multiturn'); if (!multiturn || multiturn.messages.length < 4 || !multiturn.messages.some((message) => message.role === 'assistant')) { throw new Error('Release prompt matrix requires the locked multi-turn assistant-history case.'); } const toolCall = cases.find((entry) => entry.id === 'tool_call'); if (!toolCall || toolCall.tools.length === 0) { throw new Error('Release prompt matrix requires the locked tool-call case.'); } return cases; }