{"version":3,"file":"validation.mjs","names":[],"sources":["../../../../src/batteries/llm/openai_responses/validation.ts"],"sourcesContent":["/**\n * Runtime validation schema and wrapper for OpenAI Responses adapter options.\n *\n * @module @nhtio/adk/batteries/llm/openai_responses/validation\n *\n * @remarks\n * Schema and call-site wrapper for validating `OpenAIResponsesAdapterOptions`. Used at\n * construction time and at the start of every iteration against the merged options shape\n * (stash > executor > constructor). Throws `E_INVALID_OPENAI_RESPONSES_OPTIONS` on failure — same\n * hard-fail policy as every other ADK contract.\n *\n * Notable divergences from the sibling `openai_chat_completions`/`anthropic_messages` schemas:\n * - NO `instructions` key and NO `store` key at all — both are exclusively adapter-owned (see\n *   the battery's design notes). `.unknown(false)` rejects them the same way it rejects\n *   `previous_response_id`/`conversation`/`prompt`/`context_management` — ADK owns history and the\n *   system prompt on every battery; this one simply has no escape hatch for either.\n * - `max_output_tokens` carries `.min(16)` — an undocumented API minimum (`400 Invalid\n *   'max_output_tokens'... Expected a value >= 16`) enforced at config time instead of dispatch\n *   time.\n * - `background` only accepts `false`/undefined — `true` is rejected, since this adapter has no\n *   polling/resumption logic for a queued/in_progress background response (see the option's own\n *   doc comment in types.ts).\n */\n\nimport { isError } from '@nhtio/adk/guards'\nimport { validator, ValidationError } from '@nhtio/validation'\nimport { E_INVALID_OPENAI_RESPONSES_OPTIONS } from './exceptions'\nimport { byteStoreSchema, TokenEncoding } from '@nhtio/adk/common'\nimport type { OpenAIResponsesAdapterOptions } from './types'\n\n// ─── Sub-schemas ──────────────────────────────────────────────────────────────\n\nconst bucketLabelSchema = validator\n  .string()\n  .valid('standingInstructions', 'memories', 'retrievables', 'timeline')\n\nconst bucketOrderSchema = validator\n  .array()\n  .items(bucketLabelSchema)\n  .unique()\n  .default(['standingInstructions', 'memories', 'retrievables', 'timeline'])\n\nconst tokenEncodingSchema = validator\n  .alternatives(\n    // Known values are suggestions from the canonical list, not a whitelist: consumers may provide\n    // a custom or newer tokenizer name. The field accepts any non-empty string, explicit null, or\n    // absent (undefined = \"no token counting\"). `.optional()` preserves the null/undefined\n    // disposition required by adk/require-validator-any-required.\n    validator\n      .string()\n      .min(1)\n      .description(`Known encodings: ${TokenEncoding.join(', ')}`),\n    validator.any().valid(null).optional()\n  )\n  .default(null)\n\nconst retrySchema = validator\n  .object({\n    maxAttempts: validator.number().integer().min(1).default(1),\n    baseDelayMs: validator.number().integer().min(0).default(500),\n    maxDelayMs: validator.number().integer().min(1).default(30_000),\n    retriableStatuses: validator\n      .array()\n      .items(validator.number().integer().min(100).max(599))\n      .default([429, 502, 503, 504]),\n    honorRetryAfter: validator.boolean().default(true),\n  })\n  .unknown(false)\n\n// Optional fallback tool-call parser — mirrors chat_common's ToolCallParserName union.\nconst localToolCallParserSchema = validator\n  .alternatives(\n    validator\n      .string()\n      .valid(\n        'auto',\n        'hermes',\n        'gemma',\n        'gpt_oss',\n        'pythonic',\n        'bare_pythonic',\n        'loose_keyed',\n        'llama3_json',\n        'mistral',\n        'qwen3_coder',\n        'phi',\n        'none'\n      ),\n    validator.function()\n  )\n  .optional()\n\nconst helperSchema = validator.function()\n\nconst helpersSchema = validator\n  .object({\n    descriptionToChatCompletionsJsonSchema: helperSchema.optional(),\n    renderUntrustedContent: helperSchema.optional(),\n    renderTrustedContent: helperSchema.optional(),\n    renderStandingInstructions: helperSchema.optional(),\n    renderMemories: helperSchema.optional(),\n    renderRetrievables: helperSchema.optional(),\n    renderRetrievableHandleBody: helperSchema.optional(),\n    renderRetrievableSafetyDirective: helperSchema.optional(),\n    renderFirstPartyRetrievables: helperSchema.optional(),\n    renderThirdPartyPublicRetrievables: helperSchema.optional(),\n    renderThirdPartyPrivateRetrievables: helperSchema.optional(),\n    renderThought: helperSchema.optional(),\n    filterThoughts: helperSchema.optional(),\n    toolsToChatCompletionsTools: helperSchema.optional(),\n    renderChatCompletionsSystemPrompt: helperSchema.optional(),\n    renderArtifactHandleBody: helperSchema.optional(),\n    renderOpenAIResponsesMediaBlocks: helperSchema.optional(),\n    renderOpenAIResponsesTimelineMessage: helperSchema.optional(),\n    renderOpenAIResponsesToolCallResult: helperSchema.optional(),\n    toolsToOpenAIResponsesTools: helperSchema.optional(),\n    fingerprintOpenAIResponsesPrefix: helperSchema.optional(),\n    renderOpenAIResponsesReasoningItem: helperSchema.optional(),\n    buildOpenAIResponsesInput: helperSchema.optional(),\n    createResponsesOutputSlotMachine: helperSchema.optional(),\n  })\n  .unknown(false)\n\nconst unsupportedMediaPolicySchema = validator\n  .alternatives(\n    validator.string().valid('throw', 'fallback-stash', 'synthetic-description'),\n    validator\n      .object({\n        mode: validator.string().valid('fallback-stash').required(),\n        stashKeys: validator.array().items(validator.string().min(1)).required(),\n      })\n      .unknown(false)\n  )\n  .default('throw')\n\n// ─── Responses request-body sub-schemas ───────────────────────────────────────\n\nconst includeItemSchema = validator.string().min(1)\n\nconst reasoningSchema = validator\n  .object({\n    effort: validator\n      .string()\n      .valid('none', 'minimal', 'low', 'medium', 'high', 'xhigh')\n      .optional(),\n    summary: validator.string().valid('auto', 'concise', 'detailed').optional(),\n  })\n  .unknown(false)\n\nconst toolChoiceSchema = validator.alternatives(\n  validator.string().valid('none', 'auto', 'required'),\n  validator\n    .object({\n      type: validator.string().valid('function').required(),\n      name: validator.string().required(),\n    })\n    .unknown(false)\n)\n\nconst textFormatSchema = validator.object().unknown(true)\n\nconst textSchema = validator\n  .object({\n    format: textFormatSchema.optional(),\n    verbosity: validator.string().valid('low', 'medium', 'high').optional(),\n  })\n  .unknown(false)\n\nconst streamOptionsSchema = validator\n  .object({\n    include_obfuscation: validator.boolean().optional(),\n  })\n  .unknown(false)\n\n// ─── Top-level schema ─────────────────────────────────────────────────────────\n\n/**\n * Validator schema for `OpenAIResponsesAdapterOptions`.\n *\n * @remarks\n * Used by `validateOptions` at construction time and again at the start of every iteration after\n * options have been merged (stash > executor > constructor). Rejects unknown top-level keys so\n * typos, removed fields, and every server-side-conversation-state key\n * (`previous_response_id`/`conversation`/`prompt`/`context_management`) fail loud — as does\n * `instructions`/`store`, which are simply not part of this options interface at all (see the\n * module remarks above).\n */\nexport const openAIResponsesOptionsSchema = validator\n  .object<OpenAIResponsesAdapterOptions>({\n    // ADK control\n    apiKey: validator.string().optional(),\n    baseURL: validator.string().optional(),\n    organization: validator.string().optional(),\n    project: validator.string().optional(),\n    headers: validator.object().pattern(validator.string(), validator.string()).optional(),\n    stream: validator.boolean().default(true),\n    streamIdleTimeoutMs: validator.number().integer().min(0).default(0),\n    requestTimeoutMs: validator.number().integer().min(0).default(0),\n    retry: retrySchema.optional(),\n    fetch: validator.function().optional(),\n    bucketOrder: bucketOrderSchema,\n    contextWindow: validator.number().integer().min(1).optional(),\n    selfIdentity: validator.string().min(1).default('assistant'),\n    thoughtSurfacing: validator\n      .string()\n      .valid('all-self', 'latest-self', 'all')\n      .default('all-self'),\n    tokenEncoding: tokenEncodingSchema,\n    replayCompatibility: validator.array().items(validator.string().min(1)).default([]),\n    helpers: helpersSchema.optional(),\n    spoolStore: byteStoreSchema.optional(),\n    strictToolChoice: validator.boolean().default(false),\n    autoAck: validator.boolean().default(false),\n    unsupportedMediaPolicy: unsupportedMediaPolicySchema,\n\n    // Responses-specific ADK control\n    systemPromptChannel: validator\n      .string()\n      .valid('instructions', 'developer-item', 'system-item')\n      .default('instructions'),\n    reasoningReplay: validator.string().valid('off', 'encrypted', 'summary-only').default('off'),\n    strict: validator.boolean().optional(),\n\n    // Responses request body\n    model: validator.string().required(),\n    include: validator.array().items(includeItemSchema).optional(),\n    reasoning: reasoningSchema.optional(),\n    // Undocumented API minimum of 16 — see the module remarks and Known Gotcha #2.\n    max_output_tokens: validator.number().integer().min(16).optional(),\n    parallel_tool_calls: validator.boolean().optional(),\n    temperature: validator.number().min(0).max(2).optional(),\n    top_p: validator.number().min(0).max(1).optional(),\n    top_logprobs: validator.number().integer().min(0).max(20).optional(),\n    truncation: validator.string().valid('auto', 'disabled').optional(),\n    service_tier: validator\n      .string()\n      .valid('auto', 'default', 'flex', 'scale', 'priority')\n      .optional(),\n    prompt_cache_key: validator.string().optional(),\n    prompt_cache_retention: validator.string().valid('in_memory', '24h').optional(),\n    safety_identifier: validator.string().optional(),\n    metadata: validator.object().pattern(validator.string(), validator.string()).optional(),\n    tool_choice: toolChoiceSchema.optional(),\n    text: textSchema.optional(),\n    // `true` is rejected — no polling/resumption logic exists for a queued/in_progress background\n    // response (see the option's own doc comment in types.ts). `false`/undefined pass through.\n    background: validator.boolean().valid(false).optional(),\n    stream_options: streamOptionsSchema.optional(),\n    onRawGeneration: validator.function().optional(),\n    onPromptAssembled: validator.function().optional(),\n    toolCallIdFilter: validator.function().optional(),\n    localToolCallParser: localToolCallParserSchema,\n    forgeToolsFilter: validator.function().optional(),\n  })\n  .unknown(false)\n\nconst isValidationError = (value: unknown): value is ValidationError =>\n  isError(value) && Array.isArray((value as ValidationError).details)\n\nconst formatValidationDetails = (err: ValidationError): string =>\n  err.details.map((d) => d.message).join(' and ')\n\n/**\n * Validates an arbitrary input against `openAIResponsesOptionsSchema` and returns the resolved\n * options shape. Throws `E_INVALID_OPENAI_RESPONSES_OPTIONS` (carrying the validator's error report\n * on `cause`) on failure.\n *\n * @param input - The raw options object to validate.\n * @returns The resolved options object with defaults filled in.\n */\nexport const validateOptions = (input: unknown): OpenAIResponsesAdapterOptions => {\n  const { value, error } = openAIResponsesOptionsSchema.validate(input, {\n    abortEarly: false,\n    convert: false,\n  })\n  if (error) {\n    throw new E_INVALID_OPENAI_RESPONSES_OPTIONS([formatValidationDetails(error)], {\n      cause: error,\n    })\n  }\n  return value as OpenAIResponsesAdapterOptions\n}\n\n// suppress unused import warning when the alias isn't referenced\nvoid isValidationError\n"],"mappings":"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"}