response-format.js 1.89 KB
/**
 * responseFormat(structured output)归一纯函数 —— 自 base.js 提取的职责单一模块。
 *
 * 契约:入站 responseFormat 只有两种归一形态,入口一次判别、内部信任:
 *   { type:'json_object' }                        —— 要求返回合法 JSON,无 schema 约束。
 *   { type:'json_schema', schema, name? }         —— 按 schema 约束的结构化输出。
 * 各 provider 只声明「支持哪种归一 type → 怎么落地」的分派表(responseFormatHandlers),
 * 不再各写 if-else;不支持的 type 由 base 统一 badRequest。
 */

import { LLMError } from './errors.js'

/**
 * 把入站 responseFormat 归一为两种单一形态之一。
 * 归一规则(MECE):显式 json_object → json_object;否则凡带 schema(或显式 json_schema)→ json_schema;
 * 其余无法表达的形态在此一次性 badRequest(杜绝静默忽略)。
 * @param {{ type?:string, name?:string, schema?:object }} rf 已非空的入站 responseFormat。
 * @param {string} provider
 * @returns {{ type:'json_object' } | { type:'json_schema', schema:object, name?:string }}
 */
export function normalizeResponseFormat(rf, provider) {
  if (rf.type === 'json_object') return { type: 'json_object' }
  if (rf.type === 'json_schema' || rf.schema != null) {
    if (rf.schema == null) {
      throw new LLMError({
        provider,
        reason: 'badRequest',
        retryable: false,
        message: `[${provider}] responseFormat json_schema requires a 'schema'`,
      })
    }
    /** @type {{ type:'json_schema', schema:object, name?:string }} */
    const out = { type: 'json_schema', schema: rf.schema }
    if (rf.name != null) out.name = rf.name
    return out
  }
  throw new LLMError({
    provider,
    reason: 'badRequest',
    retryable: false,
    message: `[${provider}] unrecognized responseFormat (expected json_object or json_schema)`,
  })
}