import { AGENT_BACKGROUNDS, AGENT_IMAGE_BACKENDS, AGENT_JOB_STATES, AGENT_MODERATIONS, AGENT_MODELS, AGENT_OUTPUT_FORMATS, AGENT_PAGE_SSE_AGENT_USAGE, AGENT_QUALITIES, AGENT_RESPONSE_MODES, AGENT_STREAM_MODES, AGENT_STREAMING_STRATEGIES, AGENT_UPSTREAM_SSE_EDIT_REQUEST_FIELDS, AGENT_UPSTREAM_SSE_GENERATE_REQUEST_FIELDS, AGENT_UPSTREAM_SSE_ACTIVATION_STRATEGIES, type AgentAuthScheme, type AgentRoutingStrength, type AgentRoutingTransport, buildAgentCapabilities, readAgentPublicBaseUrl } from './agent-api-contracts'; import { AGENT_ENDPOINTS } from './agent-api-paths.mjs'; import { CHANNEL_REQUEST_MODES } from './channel-request-mode'; import { MAX_PROMPT_LENGTH } from './image-request-utils'; type AgentOpenApiSecurityRequirement = { BearerAuth: [] } | { AppPasswordHash: [] }; function buildAgentOpenApiSecurity(schemes: readonly AgentAuthScheme[]): AgentOpenApiSecurityRequirement[] { return schemes.map((scheme) => (scheme === 'bearer' ? { BearerAuth: [] } : { AppPasswordHash: [] })); } function buildAgentOpenApiSecuritySchemes(schemes: readonly AgentAuthScheme[]) { const securitySchemes: Record = {}; if (schemes.includes('bearer')) { securitySchemes.BearerAuth = { type: 'http', scheme: 'bearer' }; } if (schemes.includes('x-app-password-hash')) { securitySchemes.AppPasswordHash = { type: 'apiKey', in: 'header', name: 'X-App-Password-Hash' }; } return securitySchemes; } export function buildAgentOpenApiDocument(env: Record) { const capabilities = buildAgentCapabilities(env); const maxGenerateImageCount = capabilities.limits.generate_images.max; const maxEditImageCount = capabilities.limits.edit_images.max; const maxSourceImageCount = capabilities.limits.upload_images.max; const supportedBackgrounds = capabilities.upstream_profile.activeConstraints.gptImage2.allowTransparentBackground ? AGENT_BACKGROUNDS : AGENT_BACKGROUNDS.filter((value) => value !== 'transparent'); const jsonContent = (schemaRef: string) => ({ content: { 'application/json': { schema: { $ref: schemaRef } } } }); const agentSecurity = buildAgentOpenApiSecurity(capabilities.auth.schemes); const securitySchemes = buildAgentOpenApiSecuritySchemes(capabilities.auth.schemes); const commonAgentErrors = { '401': jsonContent('#/components/schemas/AgentError'), '403': jsonContent('#/components/schemas/AgentError'), '415': jsonContent('#/components/schemas/AgentError'), '429': jsonContent('#/components/schemas/AgentError'), '502': jsonContent('#/components/schemas/AgentError') }; return { openapi: '3.1.0', info: { title: 'Visual Journal Agent API', version: capabilities.api_version }, servers: [{ url: readAgentPublicBaseUrl(env) }], paths: { [AGENT_ENDPOINTS.capabilities]: { get: { summary: '获取机器可读的 Agent API 能力信息', responses: { '200': jsonContent('#/components/schemas/AgentCapabilities') } } }, [AGENT_ENDPOINTS.openapi]: { get: { summary: '获取 Agent API 的 OpenAPI 文档', responses: { '200': { description: 'OpenAPI 文档' } } } }, [AGENT_ENDPOINTS.generate]: { post: { summary: '为 Agent 生成图片', security: agentSecurity, parameters: [{ $ref: '#/components/parameters/IdempotencyKey' }], requestBody: { required: true, ...jsonContent('#/components/schemas/GenerateRequest') }, responses: { '200': jsonContent('#/components/schemas/AgentImageResponse'), '400': jsonContent('#/components/schemas/AgentError'), '409': { ...jsonContent('#/components/schemas/AgentError'), headers: { 'Retry-After': { schema: { type: 'integer', minimum: 1 } } } }, ...commonAgentErrors, '422': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.edit]: { post: { summary: '为 Agent 编辑图片', security: agentSecurity, parameters: [{ $ref: '#/components/parameters/IdempotencyKey' }], requestBody: { required: true, content: { 'multipart/form-data': { schema: { $ref: '#/components/schemas/EditRequest' } } } }, responses: { '200': jsonContent('#/components/schemas/AgentImageResponse'), '400': jsonContent('#/components/schemas/AgentError'), '409': { ...jsonContent('#/components/schemas/AgentError'), headers: { 'Retry-After': { schema: { type: 'integer', minimum: 1 } } } }, ...commonAgentErrors, '422': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.create_image_request]: { post: { summary: '提交服务端编排的 Agent 图片生成意图', security: agentSecurity, parameters: [{ $ref: '#/components/parameters/IdempotencyKey' }], requestBody: { required: true, ...jsonContent('#/components/schemas/GenerateRequest') }, responses: { '200': jsonContent('#/components/schemas/AgentJobStatusResponse'), '202': { ...jsonContent('#/components/schemas/AgentJobStatusResponse'), headers: { 'Retry-After': { schema: { type: 'integer', minimum: 1 } } } }, '400': jsonContent('#/components/schemas/AgentError'), '409': jsonContent('#/components/schemas/AgentError'), ...commonAgentErrors, '422': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.create_generate_job]: { post: { summary: '创建 Agent 图片生成 job', security: agentSecurity, parameters: [{ $ref: '#/components/parameters/IdempotencyKey' }], requestBody: { required: true, ...jsonContent('#/components/schemas/GenerateRequest') }, responses: { '200': jsonContent('#/components/schemas/AgentJobStatusResponse'), '202': { ...jsonContent('#/components/schemas/AgentJobStatusResponse'), headers: { 'Retry-After': { schema: { type: 'integer', minimum: 1 } } } }, '400': jsonContent('#/components/schemas/AgentError'), '409': jsonContent('#/components/schemas/AgentError'), ...commonAgentErrors, '422': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.job]: { get: { summary: '获取 Agent job 状态', security: agentSecurity, parameters: [{ $ref: '#/components/parameters/JobId' }], responses: { '200': jsonContent('#/components/schemas/AgentJobStatusResponse'), '401': jsonContent('#/components/schemas/AgentError'), '404': jsonContent('#/components/schemas/AgentError'), '410': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.job_result]: { get: { summary: '获取 Agent job 结果', security: agentSecurity, parameters: [{ $ref: '#/components/parameters/JobId' }], responses: { '200': jsonContent('#/components/schemas/AgentImageResponse'), '401': jsonContent('#/components/schemas/AgentError'), '403': jsonContent('#/components/schemas/AgentError'), '404': jsonContent('#/components/schemas/AgentError'), '409': { ...jsonContent('#/components/schemas/AgentError'), headers: { 'Retry-After': { schema: { type: 'integer', minimum: 1 } } } }, '410': jsonContent('#/components/schemas/AgentError'), '422': jsonContent('#/components/schemas/AgentError'), '429': jsonContent('#/components/schemas/AgentError'), '502': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.artifact_metadata]: { get: { summary: '获取产物元数据', security: agentSecurity, parameters: [{ $ref: '#/components/parameters/ArtifactId' }], responses: { '200': jsonContent('#/components/schemas/ArtifactMetadataResponse'), '401': jsonContent('#/components/schemas/AgentError'), '404': jsonContent('#/components/schemas/AgentError') } }, delete: { summary: '删除产物', security: agentSecurity, parameters: [{ $ref: '#/components/parameters/ArtifactId' }], responses: { '200': jsonContent('#/components/schemas/DeleteArtifactResponse'), '401': jsonContent('#/components/schemas/AgentError'), '404': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.artifact_content]: { get: { summary: '下载产物内容', security: agentSecurity, parameters: [{ $ref: '#/components/parameters/ArtifactId' }], responses: { '200': { description: '图片二进制内容', content: { 'image/png': { schema: { type: 'string', format: 'binary' } }, 'image/jpeg': { schema: { type: 'string', format: 'binary' } }, 'image/webp': { schema: { type: 'string', format: 'binary' } } } }, '401': jsonContent('#/components/schemas/AgentError'), '404': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.artifact_share]: { post: { summary: '为 Agent 产物创建浏览器可访问的分享链接', security: agentSecurity, parameters: [{ $ref: '#/components/parameters/ArtifactId' }], requestBody: { required: false, ...jsonContent('#/components/schemas/CreateArtifactShareRequest') }, responses: { '201': jsonContent('#/components/schemas/ArtifactShareResponse'), '400': jsonContent('#/components/schemas/AgentError'), '401': jsonContent('#/components/schemas/AgentError'), '404': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.page_request_feedback_batch]: { post: { summary: '批量读取页面请求的结果反馈', security: agentSecurity, requestBody: { required: true, ...jsonContent('#/components/schemas/PageRequestFeedbackBatchRequest') }, responses: { '200': jsonContent('#/components/schemas/PageRequestFeedbackBatchResponse'), '401': jsonContent('#/components/schemas/AgentError'), '422': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.page_request_feedback]: { get: { summary: '读取页面请求的结果反馈', security: agentSecurity, parameters: [{ $ref: '#/components/parameters/PageRequestId' }], responses: { '200': jsonContent('#/components/schemas/PageRequestFeedbackResponse'), '401': jsonContent('#/components/schemas/AgentError'), '422': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.channel_health_diagnostics]: { get: { summary: '读取当前进程的渠道健康诊断快照', description: '只读返回当前进程内存中的渠道、凭证和请求方式状态;不会为了读取而初始化路由或启动恢复探测,因此不会触发上游探测或图片生成,也不代表真实上游可用性。', security: agentSecurity, responses: { '200': jsonContent('#/components/schemas/AgentChannelHealthDiagnosticsResponse'), '401': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.agent_request_diagnostics_lookup]: { get: { summary: '按 request_id 或 idempotency_key 读取 Agent state 请求诊断', security: agentSecurity, parameters: [ { name: 'request_id', in: 'query', required: false, schema: { type: 'string', minLength: 1, maxLength: 200 } }, { name: 'idempotency_key', in: 'query', required: false, schema: { type: 'string', minLength: 1, maxLength: 200 } } ], responses: { '200': jsonContent('#/components/schemas/AgentRequestDiagnosticsLookupResponse'), '401': jsonContent('#/components/schemas/AgentError'), '404': jsonContent('#/components/schemas/AgentRequestDiagnosticsLookupResponse'), '422': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.agent_request_diagnostics]: { get: { summary: '按 request_id 读取 Agent state 请求诊断', security: agentSecurity, parameters: [{ $ref: '#/components/parameters/AgentRequestId' }], responses: { '200': jsonContent('#/components/schemas/AgentRequestDiagnosticsLookupResponse'), '401': jsonContent('#/components/schemas/AgentError'), '404': jsonContent('#/components/schemas/AgentRequestDiagnosticsLookupResponse'), '422': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.page_request_diagnostics_batch]: { post: { summary: '批量读取页面请求的日志诊断摘要', security: agentSecurity, requestBody: { required: true, ...jsonContent('#/components/schemas/PageRequestDiagnosticsBatchRequest') }, responses: { '200': jsonContent('#/components/schemas/PageRequestDiagnosticsBatchResponse'), '401': jsonContent('#/components/schemas/AgentError'), '422': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } }, [AGENT_ENDPOINTS.page_request_diagnostics]: { get: { summary: '读取页面请求的日志诊断摘要', security: agentSecurity, parameters: [ { $ref: '#/components/parameters/PageRequestId' }, { name: 'filename', in: 'query', required: false, schema: { type: 'array', items: { type: 'string' } }, style: 'form', explode: true } ], responses: { '200': jsonContent('#/components/schemas/PageRequestDiagnosticsResponse'), '401': jsonContent('#/components/schemas/AgentError'), '422': jsonContent('#/components/schemas/AgentError'), '500': jsonContent('#/components/schemas/AgentError') } } } }, components: { securitySchemes, parameters: { IdempotencyKey: { name: 'Idempotency-Key', in: 'header', required: true, schema: { type: 'string', minLength: 1, maxLength: 200 } }, ArtifactId: { name: 'id', in: 'path', required: true, schema: { type: 'string', minLength: 1 } }, JobId: { name: 'id', in: 'path', required: true, schema: { type: 'string', minLength: 1 } }, AgentRequestId: { name: 'id', in: 'path', required: true, schema: { type: 'string', minLength: 1, maxLength: 200 } }, PageRequestId: { name: 'id', in: 'path', required: true, schema: { type: 'string', minLength: 1, maxLength: 200 } } }, schemas: { AgentCapabilities: { type: 'object', required: [ 'api_version', 'schema_version', 'auth', 'endpoints', 'image_transport', 'upstream_profile', 'upstream_request_headers', 'request_mode_controls', 'defaults', 'limits', 'force_request_controls', 'model_limits', 'agent_streaming', 'orchestration', 'routing_rules', 'agent_jobs', 'supported', 'storage', 'page_request_diagnostics', 'agent_request_diagnostics', 'channel_health_diagnostics', 'idempotency' ], properties: { api_version: { type: 'string' }, schema_version: { type: 'string' }, auth: { type: 'object', required: ['required', 'schemes'], properties: { required: { type: 'boolean', const: capabilities.auth.required }, schemes: { type: 'array', items: { type: 'string' }, const: capabilities.auth.schemes } } }, endpoints: { type: 'object', additionalProperties: { type: 'string' } }, image_transport: { $ref: '#/components/schemas/ImageTransportCapabilities' }, upstream_request_headers: { type: 'object', required: ['default', 'channels'], properties: { default: { $ref: '#/components/schemas/UpstreamRequestHeaderSummary' }, channels: { type: 'array', items: { type: 'object', required: [ 'id', 'upstream_proxy', 'request_modes', 'request_mode_priority', 'request_headers' ], properties: { id: { type: 'string' }, upstream_proxy: { $ref: '#/components/schemas/UpstreamProxySummary' }, request_modes: { type: 'array', items: { type: 'string', enum: CHANNEL_REQUEST_MODES } }, request_mode_priority: { type: 'array', items: { type: 'string', enum: CHANNEL_REQUEST_MODES } }, request_headers: { $ref: '#/components/schemas/UpstreamRequestHeaderSummary' } }, additionalProperties: false } } }, additionalProperties: false }, request_mode_controls: { $ref: '#/components/schemas/AgentRequestModeControls' }, upstream_profile: { type: 'object', required: [ 'activeProfile', 'serverProfile', 'serverProfileMixed', 'requestProfile', 'activeConstraints', 'serverConstraints', 'requestConstraints' ], properties: { activeProfile: { type: 'string', enum: ['openai-compatible', 'matsca'], const: capabilities.upstream_profile.activeProfile }, serverProfile: { type: 'string', enum: ['openai-compatible', 'matsca'], const: capabilities.upstream_profile.serverProfile }, serverProfileMixed: { type: 'boolean', const: capabilities.upstream_profile.serverProfileMixed }, requestProfile: { type: 'string', enum: ['openai-compatible', 'matsca'], const: capabilities.upstream_profile.requestProfile }, activeConstraints: { $ref: '#/components/schemas/ImageUpstreamProfile' }, serverConstraints: { $ref: '#/components/schemas/ImageUpstreamProfile' }, requestConstraints: { $ref: '#/components/schemas/ImageUpstreamProfile' } }, additionalProperties: false }, defaults: { type: 'object', required: [ 'model', 'response_mode', 'state_backend', 'image_backend', 'stream_mode', 'streaming_strategy', 'partial_images' ], properties: { model: { type: 'string', enum: AGENT_MODELS }, response_mode: { type: 'string', enum: AGENT_RESPONSE_MODES }, state_backend: { type: 'string', enum: ['memory', 'sqlite', 'postgres'] }, image_backend: { type: 'string', enum: AGENT_IMAGE_BACKENDS }, stream_mode: { type: 'string', enum: AGENT_STREAM_MODES }, streaming_strategy: { type: 'string', enum: AGENT_STREAMING_STRATEGIES }, partial_images: { type: 'integer', minimum: capabilities.limits.partial_images.min, maximum: capabilities.limits.partial_images.max } } }, limits: { type: 'object', required: [ 'max_prompt_length', 'max_images', 'generate_images', 'edit_images', 'upload_images', 'max_upload_mb', 'partial_images', 'partial_images_by_backend', 'upstream_profile', 'upstream_profile_mixed' ], properties: { max_prompt_length: { type: 'integer', const: capabilities.limits.max_prompt_length }, max_images: { type: 'integer', const: capabilities.limits.max_images }, generate_images: { type: 'object', required: ['min', 'max'], properties: { min: { type: 'integer', const: capabilities.limits.generate_images.min }, max: { type: 'integer', const: capabilities.limits.generate_images.max } }, additionalProperties: false }, edit_images: { type: 'object', required: ['min', 'max'], properties: { min: { type: 'integer', const: capabilities.limits.edit_images.min }, max: { type: 'integer', const: capabilities.limits.edit_images.max } }, additionalProperties: false }, upload_images: { type: 'object', required: ['max'], properties: { max: { type: 'integer', const: capabilities.limits.upload_images.max } }, additionalProperties: false }, max_upload_mb: { type: 'number', const: capabilities.limits.max_upload_mb }, max_total_upload_mb: { type: 'number', const: capabilities.limits.max_total_upload_mb }, partial_images: { type: 'object', required: ['min', 'max'], properties: { min: { type: 'integer', const: capabilities.limits.partial_images.min }, max: { type: 'integer', const: capabilities.limits.partial_images.max } }, additionalProperties: false }, partial_images_by_backend: { type: 'object', required: ['images-api', 'responses-image-generation'], properties: { 'images-api': { type: 'object', required: ['min', 'max'], properties: { min: { type: 'integer', const: capabilities.limits.partial_images_by_backend['images-api'] .min }, max: { type: 'integer', const: capabilities.limits.partial_images_by_backend['images-api'] .max } }, additionalProperties: false }, 'responses-image-generation': { type: 'object', required: ['min', 'max'], properties: { min: { type: 'integer', const: capabilities.limits.partial_images_by_backend[ 'responses-image-generation' ].min }, max: { type: 'integer', const: capabilities.limits.partial_images_by_backend[ 'responses-image-generation' ].max } }, additionalProperties: false } }, additionalProperties: false }, upstream_profile: { type: 'string', enum: ['openai-compatible', 'matsca'], const: capabilities.limits.upstream_profile }, upstream_profile_mixed: { type: 'boolean', const: capabilities.limits.upstream_profile_mixed } }, additionalProperties: false }, model_limits: { $ref: '#/components/schemas/AgentModelLimits' }, force_request_controls: { type: 'object', required: ['field', 'cli_flag', 'default', 'effect', 'still_enforced', 'intended_for'], properties: { field: { type: 'string', const: capabilities.force_request_controls.field }, cli_flag: { type: 'string', const: capabilities.force_request_controls.cli_flag }, default: { type: 'boolean', const: false }, effect: { type: 'string', const: capabilities.force_request_controls.effect }, still_enforced: { type: 'array', items: { type: 'string' }, const: capabilities.force_request_controls.still_enforced }, intended_for: { type: 'array', items: { type: 'string' }, const: capabilities.force_request_controls.intended_for } }, additionalProperties: false }, agent_streaming: { $ref: '#/components/schemas/AgentStreamingCapabilities' }, orchestration: { $ref: '#/components/schemas/AgentOrchestrationCapabilities' }, routing_rules: { $ref: '#/components/schemas/AgentRoutingRules' }, agent_jobs: { $ref: '#/components/schemas/AgentJobCapabilities' }, supported: { type: 'object', required: [ 'models', 'output_formats', 'response_modes', 'qualities', 'backgrounds', 'moderations', 'legacy_sizes', 'image_backends', 'enabled_image_backends', 'image_backend_requirements', 'request_modes', 'streaming_strategies', 'stream_modes' ], properties: { models: { type: 'array', items: { type: 'string', enum: AGENT_MODELS } }, output_formats: { type: 'array', items: { type: 'string', enum: AGENT_OUTPUT_FORMATS } }, response_modes: { type: 'array', items: { type: 'string', enum: AGENT_RESPONSE_MODES } }, qualities: { type: 'array', items: { type: 'string', enum: AGENT_QUALITIES } }, backgrounds: { type: 'array', items: { type: 'string', enum: AGENT_BACKGROUNDS } }, moderations: { type: 'array', items: { type: 'string', enum: AGENT_MODERATIONS } }, legacy_sizes: { type: 'array', items: { type: 'string' } }, image_backends: { type: 'array', items: { type: 'string', enum: AGENT_IMAGE_BACKENDS } }, enabled_image_backends: { type: 'array', items: { type: 'string', enum: AGENT_IMAGE_BACKENDS } }, image_backend_requirements: { type: 'object', additionalProperties: { $ref: '#/components/schemas/ImageBackendRequirement' } }, request_modes: { type: 'array', items: { type: 'string', enum: CHANNEL_REQUEST_MODES } }, streaming_strategies: { type: 'array', items: { type: 'string', enum: AGENT_STREAMING_STRATEGIES } }, stream_modes: { type: 'array', items: { type: 'string', enum: AGENT_STREAM_MODES } } } }, storage: { type: 'object', required: ['image_storage_mode', 'postgres_configured'], properties: { image_storage_mode: { type: 'string' }, postgres_configured: { type: 'boolean' } } }, page_request_diagnostics: { $ref: '#/components/schemas/AgentPageRequestDiagnosticsCapabilities' }, agent_request_diagnostics: { $ref: '#/components/schemas/AgentRequestDiagnosticsCapabilities' }, channel_health_diagnostics: { $ref: '#/components/schemas/AgentChannelHealthDiagnosticsCapabilities' }, idempotency: { type: 'object' } } }, AgentModelLimits: { type: 'object', required: ['gpt-image-2'], properties: { 'gpt-image-2': { type: 'object', required: [ 'max_edge', 'max_pixels', 'edge_multiple', 'max_aspect', 'min_pixels', 'recommended_presets', 'large_image_risk' ], properties: { max_edge: { type: 'integer', minimum: 1 }, max_pixels: { type: 'integer', minimum: 1 }, edge_multiple: { type: 'integer', minimum: 1 }, max_aspect: { type: 'number', minimum: 1 }, min_pixels: { type: 'integer', minimum: 1 }, recommended_presets: { type: 'array', items: { type: 'object', required: ['name', 'size', 'purpose'], properties: { name: { type: 'string' }, size: { type: 'string' }, purpose: { type: 'string' } } } }, large_image_risk: { type: 'object', required: ['applies_to', 'guidance'], properties: { applies_to: { type: 'array', items: { type: 'string' } }, guidance: { type: 'string' } } } } } } }, ImageUpstreamProfile: { type: 'object', required: ['id', 'generateCount', 'editCount', 'partialImages', 'upload', 'gptImage2'], properties: { id: { type: 'string', enum: ['openai-compatible', 'matsca'] }, generateCount: { type: 'object', required: ['min', 'max'], properties: { min: { type: 'integer', minimum: 1 }, max: { type: 'integer', minimum: 1 } }, additionalProperties: false }, editCount: { type: 'object', required: ['min', 'max'], properties: { min: { type: 'integer', minimum: 1 }, max: { type: 'integer', minimum: 1 } }, additionalProperties: false }, partialImages: { type: 'object', required: ['min', 'max'], properties: { min: { type: 'integer', minimum: 0 }, max: { type: 'integer', minimum: 0 } }, additionalProperties: false }, upload: { type: 'object', required: ['maxImages', 'maxSingleBytes'], properties: { maxImages: { type: 'integer', minimum: 1 }, maxSingleBytes: { type: 'integer', minimum: 1 }, maxTotalBytes: { type: 'integer', minimum: 1 } }, additionalProperties: false }, gptImage2: { type: 'object', required: ['allowTransparentBackground', 'sizePolicy'], properties: { allowTransparentBackground: { type: 'boolean' }, sizePolicy: { type: 'string', enum: ['openai-compatible', 'positive-integer'] } }, additionalProperties: false } }, additionalProperties: false }, ImageBackendRequirement: { type: 'object', required: ['supported', 'enabled', 'required_env', 'missing_env'], properties: { supported: { type: 'boolean', const: true }, enabled: { type: 'boolean' }, required_env: { type: 'array', items: { type: 'string' } }, missing_env: { type: 'array', items: { type: 'string' } } } }, AppLogRetentionMetadata: { type: 'object', required: [ 'storage', 'max_entries', 'default_max_entries', 'min_entries', 'max_configured_entries', 'configured_by', 'persisted_across_process_restart', 'loss_modes', 'bounded', 'not_agent_state_backend' ], properties: { storage: { type: 'string', const: capabilities.page_request_diagnostics.retention.storage }, max_entries: { type: 'integer', minimum: 1, const: capabilities.page_request_diagnostics.retention.max_entries }, default_max_entries: { type: 'integer', minimum: 1, const: capabilities.page_request_diagnostics.retention.default_max_entries }, min_entries: { type: 'integer', minimum: 1, const: capabilities.page_request_diagnostics.retention.min_entries }, max_configured_entries: { type: 'integer', minimum: 1, const: capabilities.page_request_diagnostics.retention.max_configured_entries }, configured_by: { type: 'string', const: capabilities.page_request_diagnostics.retention.configured_by }, persisted_across_process_restart: { type: 'boolean', const: true }, loss_modes: { type: 'array', items: { type: 'string' }, const: capabilities.page_request_diagnostics.retention.loss_modes }, bounded: { type: 'boolean', const: true }, not_agent_state_backend: { type: 'boolean', const: true } } }, AgentPageRequestDiagnosticsCapabilities: { type: 'object', required: ['supported', 'source', 'endpoints', 'retention', 'no_match_hint'], properties: { supported: { type: 'boolean', const: true }, source: { type: 'string', enum: ['app_log'] }, endpoints: { type: 'object', required: ['single', 'batch'], properties: { single: { type: 'string', const: AGENT_ENDPOINTS.page_request_diagnostics }, batch: { type: 'string', const: AGENT_ENDPOINTS.page_request_diagnostics_batch } } }, retention: { $ref: '#/components/schemas/AppLogRetentionMetadata' }, no_match_hint: { type: 'string', const: capabilities.page_request_diagnostics.no_match_hint } } }, AgentRequestDiagnosticsRetention: { type: 'object', required: ['storage', 'ttl_seconds', 'bounded', 'loss_modes'], properties: { storage: { type: 'string', const: capabilities.agent_request_diagnostics.retention.storage }, ttl_seconds: { type: 'integer', minimum: 1, const: capabilities.agent_request_diagnostics.retention.ttl_seconds }, bounded: { type: 'boolean', const: true }, loss_modes: { type: 'array', items: { type: 'string' }, const: capabilities.agent_request_diagnostics.retention.loss_modes } }, additionalProperties: false }, AgentRequestDiagnosticsCapabilities: { type: 'object', required: ['supported', 'source', 'endpoints', 'lookup', 'retention'], properties: { supported: { type: 'boolean', const: true }, source: { type: 'string', enum: ['agent_state'] }, endpoints: { type: 'object', required: ['lookup', 'single'], properties: { lookup: { type: 'string', const: AGENT_ENDPOINTS.agent_request_diagnostics_lookup }, single: { type: 'string', const: AGENT_ENDPOINTS.agent_request_diagnostics } }, additionalProperties: false }, lookup: { type: 'object', required: ['by_request_id', 'by_idempotency_key'], properties: { by_request_id: { type: 'boolean', const: true }, by_idempotency_key: { type: 'boolean', const: true } }, additionalProperties: false }, retention: { $ref: '#/components/schemas/AgentRequestDiagnosticsRetention' } }, additionalProperties: false }, AgentChannelHealthDiagnosticsCapabilities: { type: 'object', required: ['supported', 'endpoint', 'source', 'state_scope', 'billable'], properties: { supported: { type: 'boolean', const: true }, endpoint: { type: 'string', const: AGENT_ENDPOINTS.channel_health_diagnostics }, source: { type: 'string', const: 'in_process_channel_router' }, state_scope: { type: 'string', const: 'process_local' }, billable: { type: 'boolean', const: false } }, additionalProperties: false }, AgentChannelHealthDiagnosticsResponse: { type: 'object', required: ['ok', 'billable', 'source', 'state_scope', 'state_initialized', 'snapshot'], properties: { ok: { type: 'boolean', const: true }, billable: { type: 'boolean', const: false }, source: { type: 'string', const: 'in_process_channel_router' }, state_scope: { type: 'string', const: 'process_local' }, state_initialized: { type: 'boolean' }, snapshot: { $ref: '#/components/schemas/AgentChannelHealthSnapshot' } }, additionalProperties: false }, AgentChannelHealthSnapshot: { type: 'object', required: ['observed_at', 'channels'], properties: { observed_at: { type: 'integer', minimum: 0 }, channels: { type: 'array', items: { $ref: '#/components/schemas/AgentChannelHealthChannel' } } }, additionalProperties: false }, AgentChannelHealthChannel: { type: 'object', required: [ 'channel_id', 'credential_count', 'healthy_credential_count', 'unhealthy_credential_count', 'state', 'probe_required', 'upstream_proxy', 'credentials' ], properties: { channel_id: { type: 'string' }, upstream_proxy: { $ref: '#/components/schemas/UpstreamProxySummary' }, credential_count: { type: 'integer', minimum: 0 }, healthy_credential_count: { type: 'integer', minimum: 0 }, unhealthy_credential_count: { type: 'integer', minimum: 0 }, state: { type: 'string', enum: ['healthy', 'cooldown', 'probe_pending'] }, probe_required: { type: 'boolean' }, credentials: { type: 'array', items: { $ref: '#/components/schemas/AgentChannelHealthCredential' } } }, additionalProperties: false }, AgentChannelHealthCredential: { type: 'object', required: ['credential_id', 'state', 'probe_required', 'request_modes'], properties: { credential_id: { type: 'string' }, state: { type: 'string', enum: ['healthy', 'cooldown', 'probe_pending'] }, cooldown_until: { type: 'integer', minimum: 0 }, probe_required: { type: 'boolean' }, last_failure: { $ref: '#/components/schemas/AgentChannelHealthFailure' }, request_modes: { type: 'array', items: { $ref: '#/components/schemas/AgentChannelHealthRequestMode' } } }, additionalProperties: false }, AgentChannelHealthRequestMode: { type: 'object', required: ['mode', 'state', 'probe_required'], properties: { mode: { type: 'string', enum: CHANNEL_REQUEST_MODES }, state: { type: 'string', enum: ['healthy', 'cooldown', 'probe_pending'] }, cooldown_until: { type: 'integer', minimum: 0 }, probe_required: { type: 'boolean' } }, additionalProperties: false }, AgentChannelHealthFailure: { type: 'object', required: ['at', 'scope'], properties: { at: { type: 'integer', minimum: 0 }, scope: { type: 'string', enum: ['credential', 'channel'] }, status: { type: 'integer' }, code: { type: 'string' }, request_id: { type: 'string' }, request_mode: { type: 'string', enum: CHANNEL_REQUEST_MODES } }, additionalProperties: false }, AgentStreamingCapabilities: { type: 'object', required: ['generate', 'edit', 'upstream_sse', 'page_sse'], properties: { generate: { $ref: '#/components/schemas/AgentEndpointStreamingCapability' }, edit: { $ref: '#/components/schemas/AgentEndpointStreamingCapability' }, upstream_sse: { type: 'object', required: [ 'supported', 'mode', 'endpoint', 'request_fields', 'request_fields_by_mode', 'image_backends', 'enabled_image_backends', 'streaming_strategies', 'stream_modes', 'activation_strategies', 'final_response_contract' ], properties: { supported: { type: 'boolean', const: true }, mode: { type: 'string', enum: ['internal_upstream_sse'] }, endpoint: { type: 'string' }, request_fields: { type: 'array', items: { type: 'string' }, const: AGENT_UPSTREAM_SSE_GENERATE_REQUEST_FIELDS }, request_fields_by_mode: { type: 'object', required: ['generate', 'edit'], properties: { generate: { type: 'array', items: { type: 'string' }, const: AGENT_UPSTREAM_SSE_GENERATE_REQUEST_FIELDS }, edit: { type: 'array', items: { type: 'string' }, const: AGENT_UPSTREAM_SSE_EDIT_REQUEST_FIELDS } } }, image_backends: { type: 'array', items: { type: 'string', enum: AGENT_IMAGE_BACKENDS } }, enabled_image_backends: { type: 'array', items: { type: 'string', enum: AGENT_IMAGE_BACKENDS } }, streaming_strategies: { type: 'array', items: { type: 'string', enum: AGENT_STREAMING_STRATEGIES } }, stream_modes: { type: 'array', items: { type: 'string', enum: AGENT_STREAM_MODES } }, activation_strategies: { type: 'array', items: { type: 'string', enum: AGENT_UPSTREAM_SSE_ACTIVATION_STRATEGIES } }, final_response_contract: { type: 'string', enum: ['AgentImageResponse'] } } }, page_sse: { type: 'object', required: [ 'supported', 'mode', 'endpoint', 'contract', 'transport_contract', 'auth', 'client_request_id', 'agent_usage' ], properties: { supported: { type: 'boolean', const: true }, mode: { type: 'string', enum: ['form_data_sse'] }, endpoint: { type: 'string' }, contract: { type: 'string', enum: ['page_ui_only'] }, transport_contract: { type: 'string', enum: ['page_form_data_sse'] }, auth: { type: 'object', required: ['required', 'schemes', 'form_field'], properties: { required: { type: 'boolean', const: capabilities.agent_streaming.page_sse.auth.required }, schemes: { type: 'array', items: { type: 'string', enum: ['form-password-hash'] }, const: capabilities.agent_streaming.page_sse.auth.schemes }, form_field: { type: 'string', const: 'passwordHash' } } }, client_request_id: { type: 'object', required: ['form_field', 'source_header', 'max_length'], properties: { form_field: { type: 'string', const: 'clientRequestId' }, source_header: { type: 'string', const: 'Idempotency-Key' }, max_length: { type: 'integer', const: capabilities.agent_streaming.page_sse.client_request_id.max_length } } }, agent_usage: { type: 'string', enum: [AGENT_PAGE_SSE_AGENT_USAGE] } } } } }, AgentRoutingRules: { type: 'object', required: [ 'high_resolution_edit', 'complex_ui_batch', 'long_image_recovery', 'agent_generate_small_smoke', 'page_sse_generate_diagnostics', 'retry_recovery' ], properties: { high_resolution_edit: { $ref: '#/components/schemas/AgentRoutingRule' }, complex_ui_batch: { $ref: '#/components/schemas/AgentRoutingRule' }, long_image_recovery: { $ref: '#/components/schemas/AgentRoutingRule' }, agent_generate_small_smoke: { $ref: '#/components/schemas/AgentRoutingRule' }, page_sse_generate_diagnostics: { $ref: '#/components/schemas/AgentRoutingRule' }, retry_recovery: { type: 'object', required: ['reuse_failed_idempotency_key', 'new_attempt_guidance'], properties: { reuse_failed_idempotency_key: { type: 'boolean', const: false }, new_attempt_guidance: { type: 'string' } } } } }, AgentRoutingRule: { type: 'object', required: ['when', 'conditions', 'endpoint', 'transport', 'strength', 'action', 'reason'], properties: { when: { type: 'array', items: { type: 'string' } }, conditions: { $ref: '#/components/schemas/AgentRoutingCondition' }, endpoint: { type: 'string' }, transport: { type: 'string', enum: ['agent_json', 'agent_job_polling', 'page_sse'] satisfies AgentRoutingTransport[] }, strength: { type: 'string', enum: ['default', 'recommended', 'explicit'] satisfies AgentRoutingStrength[] }, action: { $ref: '#/components/schemas/AgentRoutingAction' }, reason: { type: 'string' } } }, AgentRoutingCondition: { type: 'object', required: ['operation'], properties: { operation: { type: 'string', enum: ['generate', 'edit', 'generate_or_edit'] }, max_edge: { type: 'object', required: ['operator', 'value'], properties: { operator: { type: 'string', enum: ['gt', 'lte'] }, value: { type: 'integer', minimum: 1 } } }, batch: { type: 'boolean' }, single_request: { type: 'boolean' }, explicit_page_sse: { type: 'boolean' }, complex_ui: { type: 'boolean' }, long_image: { type: 'boolean' }, resume_or_recover: { type: 'boolean' } }, additionalProperties: false }, AgentRoutingAction: { type: 'object', required: [ 'endpoint', 'transport', 'strength', 'requires_new_idempotency_key_on_retry', 'no_automatic_fallback' ], properties: { endpoint: { type: 'string' }, transport: { type: 'string', enum: ['agent_json', 'agent_job_polling', 'page_sse'] satisfies AgentRoutingTransport[] }, strength: { type: 'string', enum: ['default', 'recommended', 'explicit'] satisfies AgentRoutingStrength[] }, fallback_endpoint: { type: 'string' }, fallback_mode: { type: 'string', enum: ['manual_after_diagnosis', 'fix_request_before_retry'] }, requires_new_idempotency_key_on_retry: { type: 'boolean' }, no_automatic_fallback: { type: 'boolean' } }, additionalProperties: false }, AgentEndpointStreamingCapability: { type: 'object', required: ['supported', 'mode', 'endpoint'], properties: { supported: { type: 'boolean', const: false }, mode: { type: 'string', enum: ['non_streaming_only'] }, endpoint: { type: 'string' } } }, AgentJobCapabilities: { type: 'object', required: ['supported', 'mode', 'intended_for', 'endpoints', 'states', 'current_guidance'], properties: { supported: { type: 'boolean', const: true }, mode: { type: 'string', enum: ['job_polling'] }, intended_for: { type: 'array', items: { type: 'string' } }, endpoints: { type: 'object', required: ['create_generate_job', 'get_job', 'get_job_result'], properties: { create_generate_job: { type: 'string' }, get_job: { type: 'string' }, get_job_result: { type: 'string' } } }, states: { type: 'array', items: { type: 'string', enum: AGENT_JOB_STATES } }, current_guidance: { type: 'string' } } }, AgentOrchestrationCapabilities: { type: 'object', required: [ 'supported', 'policy', 'endpoint', 'client_contract', 'transport_selection', 'result_mode', 'hidden_controls', 'diagnostics', 'current_guidance' ], properties: { supported: { type: 'boolean', const: true }, policy: { type: 'string', enum: ['server_orchestrated_generate_v1'] }, endpoint: { type: 'string', const: AGENT_ENDPOINTS.create_image_request }, client_contract: { type: 'string', enum: ['intent_only'] }, transport_selection: { type: 'string', enum: ['server_owned'] }, result_mode: { type: 'string', enum: ['job_polling'] }, hidden_controls: { type: 'array', items: { type: 'string' } }, diagnostics: { type: 'object', required: ['job_result', 'request_lookup'], properties: { job_result: { type: 'string', const: AGENT_ENDPOINTS.job_result }, request_lookup: { type: 'string', const: AGENT_ENDPOINTS.agent_request_diagnostics_lookup } }, additionalProperties: false }, current_guidance: { type: 'string' } }, additionalProperties: false }, GenerateRequest: { type: 'object', required: ['prompt'], allOf: [ { if: { properties: { image_backend: { const: 'responses-image-generation' } }, required: ['image_backend'] }, then: { properties: { partial_images: { type: 'integer', minimum: capabilities.limits.partial_images_by_backend['responses-image-generation'] .min, maximum: capabilities.limits.partial_images_by_backend['responses-image-generation'] .max, default: capabilities.defaults.partial_images } } } }, { if: { not: { properties: { force_request: { const: true } }, required: ['force_request'] } }, then: { properties: { background: { type: 'string', enum: supportedBackgrounds } } } } ], properties: { prompt: { type: 'string', maxLength: MAX_PROMPT_LENGTH }, model: { type: 'string', enum: AGENT_MODELS }, n: { type: 'integer', minimum: capabilities.limits.generate_images.min, maximum: maxGenerateImageCount }, size: { type: 'string' }, quality: { type: 'string', enum: AGENT_QUALITIES, default: 'high' }, output_format: { type: 'string', enum: AGENT_OUTPUT_FORMATS }, output_compression: { type: 'integer', minimum: 0, maximum: 100 }, background: { type: 'string', enum: AGENT_BACKGROUNDS }, moderation: { type: 'string', enum: AGENT_MODERATIONS }, response_mode: { type: 'string', enum: AGENT_RESPONSE_MODES, default: 'path' }, image_backend: { type: 'string', enum: AGENT_IMAGE_BACKENDS, default: 'images-api' }, responsesModel: { type: 'string', maxLength: 128, description: 'Responses image_generation 顶层模型;仅适用于 image_backend=responses-image-generation。' }, thinking: { type: 'string', enum: ['minimal', 'none', 'low', 'medium', 'high', 'xhigh'] }, promptOptimization: { type: 'boolean' }, force_web: { type: 'boolean' }, force_request: { type: 'boolean', description: '显式强制请求上游,跳过本服务本地 upstream profile 尺寸/背景限制;鉴权、幂等键、渠道白名单和安全校验仍然生效。' }, streaming_strategy: { type: 'string', enum: AGENT_STREAMING_STRATEGIES, default: 'auto' }, stream_mode: { type: 'string', enum: AGENT_STREAM_MODES, default: 'auto' }, partial_images: { type: 'integer', minimum: capabilities.limits.partial_images.min, maximum: capabilities.limits.partial_images.max, default: capabilities.defaults.partial_images } } }, EditRequest: { type: 'object', required: ['prompt'], anyOf: Array.from({ length: maxSourceImageCount }, (_, index) => ({ required: [`image_${index}`] })), description: `Agent edit 返回最终 JSON。请求必须至少提供一个 image_0..image_${maxSourceImageCount - 1} 源图字段。高分辨率 edit 默认优先使用页面端 /api/images form-data SSE;页面流式有问题时可显式回退到 Agent edit 诊断或执行。`, properties: { prompt: { type: 'string', maxLength: MAX_PROMPT_LENGTH }, model: { type: 'string', enum: AGENT_MODELS, default: 'gpt-image-2' }, n: { type: 'integer', minimum: capabilities.limits.edit_images.min, maximum: maxEditImageCount }, size: { type: 'string', default: 'auto' }, quality: { type: 'string', enum: AGENT_QUALITIES, default: 'auto' }, response_mode: { type: 'string', enum: AGENT_RESPONSE_MODES, default: 'path' }, stream_mode: { type: 'string', enum: AGENT_STREAM_MODES, default: 'auto' }, streaming_strategy: { type: 'string', enum: AGENT_STREAMING_STRATEGIES, default: 'auto' }, force_request: { type: 'boolean', description: '显式强制请求上游,跳过本服务本地 upstream profile 尺寸限制;鉴权、幂等键、渠道白名单、图片数量、partial_images、文件大小和 mask 校验仍然生效。' }, partial_images: { type: 'integer', minimum: capabilities.limits.partial_images.min, maximum: capabilities.limits.partial_images.max, default: capabilities.defaults.partial_images }, ...Object.fromEntries( Array.from({ length: maxSourceImageCount }, (_, index) => [ `image_${index}`, { type: 'string', format: 'binary' } ]) ), mask: { type: 'string', format: 'binary' } } }, AgentArtifact: { type: 'object', required: [ 'id', 'filename', 'content_url', 'metadata_url', 'output_format', 'mime_type', 'size_bytes', 'width', 'height' ], properties: { id: { type: 'string' }, filename: { type: 'string' }, content_url: { type: 'string' }, metadata_url: { type: 'string' }, output_format: { type: 'string', enum: AGENT_OUTPUT_FORMATS }, mime_type: { type: 'string' }, size_bytes: { type: 'integer', minimum: 0 }, width: { type: ['integer', 'null'] }, height: { type: ['integer', 'null'] }, b64_json: { type: 'string' } } }, AgentImageResponse: { type: 'object', required: ['request_id', 'idempotency_key', 'cached', 'images', 'created_at'], properties: { request_id: { type: 'string' }, idempotency_key: { type: 'string' }, cached: { type: 'boolean' }, images: { type: 'array', items: { $ref: '#/components/schemas/AgentArtifact' } }, usage: { type: 'object' }, created_at: { type: 'string', format: 'date-time' }, timing: { $ref: '#/components/schemas/AgentImageResponseTiming' }, execution: { $ref: '#/components/schemas/AgentImageResponseExecution' } } }, AgentImageResponseTiming: { type: 'object', required: ['started_at', 'completed_at', 'elapsed_ms', 'server_elapsed_ms'], properties: { started_at: { type: 'string', format: 'date-time' }, completed_at: { type: 'string', format: 'date-time' }, elapsed_ms: { type: 'integer', minimum: 0 }, server_elapsed_ms: { type: 'integer', minimum: 0 } }, additionalProperties: false }, ChannelRequestModeDecision: { type: 'object', required: ['requested_backend', 'fallback_applied'], properties: { requested_backend: { type: 'string', enum: AGENT_IMAGE_BACKENDS }, candidate_channel_request_modes: { type: 'array', items: { type: 'string', enum: CHANNEL_REQUEST_MODES } }, request_mode_priority: { type: 'array', items: { type: 'string', enum: CHANNEL_REQUEST_MODES } }, preferred_channel_request_mode: { type: 'string', enum: CHANNEL_REQUEST_MODES }, fallback_channel_request_mode: { type: 'string', enum: CHANNEL_REQUEST_MODES }, selected_channel_request_mode: { type: 'string', enum: CHANNEL_REQUEST_MODES }, fallback_applied: { type: 'boolean' }, selected_channel_id: { type: 'string' }, upstream_host: { type: 'string' }, no_channel_reason: { type: 'string' } }, additionalProperties: false }, AgentImageResponseExecution: { type: 'object', required: [ 'transport', 'endpoint', 'route_mode', 'operation', 'image_backend', 'stream_mode', 'streaming_strategy', 'channel_request_mode_fallback_applied', 'route_decision', 'request_headers' ], properties: { transport: { type: 'string', enum: ['agent_json', 'agent_job_polling', 'page_sse'] }, endpoint: { type: 'string' }, route_mode: { type: 'string', enum: ['agent', 'job', 'page_sse'] }, operation: { type: 'string', enum: ['generate', 'edit'] }, image_backend: { type: 'string', enum: AGENT_IMAGE_BACKENDS }, stream_mode: { type: 'string', enum: AGENT_STREAM_MODES }, streaming_strategy: { type: 'string', enum: AGENT_STREAMING_STRATEGIES }, channel_request_mode: { type: 'string', enum: CHANNEL_REQUEST_MODES }, channel_request_mode_fallback_applied: { type: 'boolean' }, route_decision: { $ref: '#/components/schemas/ChannelRequestModeDecision' }, selected_channel_id: { type: 'string' }, upstream_host: { type: 'string' }, request_headers: { $ref: '#/components/schemas/UpstreamRequestHeaderSummary' } }, additionalProperties: false }, AgentJobStatusResponse: { type: 'object', required: ['job'], properties: { job: { type: 'object', required: [ 'id', 'request_id', 'idempotency_key', 'mode', 'state', 'created_at', 'updated_at', 'expires_at' ], properties: { id: { type: 'string' }, request_id: { type: 'string' }, idempotency_key: { type: 'string' }, mode: { type: 'string', enum: ['generate', 'edit'] }, state: { type: 'string', enum: AGENT_JOB_STATES }, created_at: { type: 'string', format: 'date-time' }, updated_at: { type: 'string', format: 'date-time' }, expires_at: { type: 'string', format: 'date-time' }, result_url: { type: 'string' }, retry_after_seconds: { type: 'integer', minimum: 1 }, error: { type: 'object', required: ['code', 'message', 'retryable'], properties: { code: { type: 'string' }, message: { type: 'string' }, retryable: { type: 'boolean' }, details: { type: 'object' }, upstream_status: { type: 'integer' }, diagnostics: { $ref: '#/components/schemas/AgentErrorDiagnostics' } } } } } } }, ArtifactMetadataResponse: { type: 'object', required: ['artifact'], properties: { artifact: { $ref: '#/components/schemas/AgentArtifact' } } }, CreateArtifactShareRequest: { type: 'object', properties: { expires_in_minutes: { oneOf: [{ type: 'integer', minimum: 1 }, { type: 'null' }], description: '分享有效期分钟数;null 表示不过期,省略时使用服务端默认值。' }, access_code: { anyOf: [ { type: 'string', pattern: '^\\s*$' }, { type: 'string', minLength: 8, maxLength: 128 } ], description: '可选访问码;省略或空白字符串表示公开分享。' } }, additionalProperties: false }, ArtifactShareResponse: { type: 'object', required: [ 'artifact_id', 'token', 'share_url', 'direct_content_url', 'expires_at', 'access_code_required' ], properties: { artifact_id: { type: 'string' }, token: { type: 'string', pattern: '^[a-f0-9]{24}$' }, share_url: { type: 'string' }, direct_content_url: { type: 'string' }, expires_at: { oneOf: [{ type: 'string', format: 'date-time' }, { type: 'null' }] }, access_code_required: { type: 'boolean' } }, additionalProperties: false }, DeleteArtifactResponse: { type: 'object', required: ['deleted', 'id'], properties: { deleted: { type: 'boolean' }, id: { type: 'string' } } }, ResultFeedback: { type: 'object', required: ['target_type', 'target_id', 'value', 'source', 'updated_at'], properties: { target_type: { type: 'string', enum: ['page_request', 'agent_request', 'agent_artifact'] }, target_id: { type: 'string' }, value: { type: 'string', enum: ['usable', 'needs_revision'] }, source: { type: 'string', enum: ['webui', 'agent'] }, updated_at: { type: 'string', format: 'date-time' }, note: { type: 'string', maxLength: 500 } } }, FeedbackTarget: { type: 'object', required: ['type', 'id'], properties: { type: { type: 'string', enum: ['page_request'] }, id: { type: 'string' } } }, PageRequestFeedbackBatchRequest: { type: 'object', required: ['ids'], properties: { ids: { type: 'array', minItems: 1, maxItems: 50, items: { type: 'string' } } } }, PageRequestFeedbackBatchResponse: { type: 'object', required: ['targets', 'feedback'], properties: { targets: { type: 'array', items: { $ref: '#/components/schemas/FeedbackTarget' } }, feedback: { type: 'array', items: { $ref: '#/components/schemas/ResultFeedback' } } } }, PageRequestFeedbackResponse: { type: 'object', required: ['target', 'feedback'], properties: { target: { $ref: '#/components/schemas/FeedbackTarget' }, feedback: { oneOf: [{ $ref: '#/components/schemas/ResultFeedback' }, { type: 'null' }] } } }, PageRequestDiagnosticsBatchRequest: { type: 'object', required: ['ids'], properties: { ids: { type: 'array', minItems: 1, maxItems: 50, items: { type: 'string' } }, filenames: { type: 'array', maxItems: 20, items: { type: 'string' } } } }, AgentRequestDiagnosticsLookupResponse: { type: 'object', required: ['found'], properties: { found: { type: 'boolean' }, diagnostics: { $ref: '#/components/schemas/AgentRequestDiagnostics' } }, additionalProperties: false }, AgentRequestDiagnostics: { type: 'object', required: [ 'request', 'timeline', 'artifacts', 'state_backend', 'diagnostics_retention', 'diagnostics_boundary' ], properties: { request: { $ref: '#/components/schemas/AgentRequestDiagnosticsRequest' }, timeline: { type: 'array', items: { $ref: '#/components/schemas/AgentRequestTimelineEvent' } }, artifacts: { type: 'array', items: { $ref: '#/components/schemas/AgentRequestDiagnosticsArtifact' } }, response: { $ref: '#/components/schemas/AgentRequestDiagnosticsResponseSummary' }, error: { $ref: '#/components/schemas/AgentRequestDiagnosticsErrorSummary' }, feedback: { $ref: '#/components/schemas/ResultFeedback' }, state_backend: { type: 'string', enum: ['memory', 'sqlite', 'postgres'] }, diagnostics_retention: { $ref: '#/components/schemas/AgentRequestDiagnosticsRetention' }, diagnostics_boundary: { type: 'object', required: [ 'source', 'not_page_request_log', 'raw_request_json_redacted', 'api_key_redacted' ], properties: { source: { type: 'string', enum: ['agent_state'] }, not_page_request_log: { type: 'boolean', const: true }, raw_request_json_redacted: { type: 'boolean', const: true }, api_key_redacted: { type: 'boolean', const: true } }, additionalProperties: false } }, additionalProperties: false }, AgentRequestDiagnosticsRequest: { type: 'object', required: [ 'request_id', 'idempotency_key', 'mode', 'status', 'cached', 'created_at', 'updated_at', 'expires_at' ], properties: { request_id: { type: 'string' }, idempotency_key: { type: 'string' }, mode: { type: 'string', enum: ['generate', 'edit'] }, status: { type: 'string', enum: ['pending', 'running', 'succeeded', 'failed', 'orphaned'] }, cached: { type: 'boolean' }, created_at: { type: 'string', format: 'date-time' }, updated_at: { type: 'string', format: 'date-time' }, expires_at: { type: 'string', format: 'date-time' }, locked_until: { type: 'string', format: 'date-time' } }, additionalProperties: false }, AgentRequestTimelineEvent: { type: 'object', required: ['at', 'event'], properties: { at: { type: 'string', format: 'date-time' }, event: { type: 'string', enum: ['created', 'updated', 'locked_until', 'expires'] } }, additionalProperties: false }, AgentRequestDiagnosticsArtifact: { type: 'object', required: [ 'id', 'filename', 'content_url', 'metadata_url', 'output_format', 'mime_type', 'size_bytes', 'width', 'height', 'model', 'created_at' ], properties: { id: { type: 'string' }, filename: { type: 'string' }, content_url: { type: 'string' }, metadata_url: { type: 'string' }, output_format: { type: 'string' }, mime_type: { type: 'string' }, size_bytes: { type: 'integer', minimum: 0 }, width: { type: ['integer', 'null'] }, height: { type: ['integer', 'null'] }, model: { type: 'string' }, created_at: { type: 'string', format: 'date-time' } }, additionalProperties: false }, AgentRequestDiagnosticsResponseSummary: { type: 'object', required: [ 'request_id', 'idempotency_key', 'cached', 'image_count', 'artifact_ids', 'content_urls', 'created_at' ], properties: { request_id: { type: 'string' }, idempotency_key: { type: 'string' }, cached: { type: 'boolean' }, image_count: { type: 'integer', minimum: 0 }, artifact_ids: { type: 'array', items: { type: 'string' } }, content_urls: { type: 'array', items: { type: 'string' } }, created_at: { type: 'string', format: 'date-time' }, timing: { $ref: '#/components/schemas/AgentImageResponseTiming' }, execution: { $ref: '#/components/schemas/AgentImageResponseExecution' } }, additionalProperties: false }, AgentRequestDiagnosticsErrorSummary: { type: 'object', required: ['code', 'message', 'retryable'], properties: { code: { type: 'string' }, message: { type: 'string' }, retryable: { type: 'boolean' }, upstream_status: { type: 'integer' }, diagnostics: { $ref: '#/components/schemas/AgentErrorDiagnostics' } }, additionalProperties: false }, PageRequestDiagnosticsBatchItem: { allOf: [ { $ref: '#/components/schemas/PageRequestDiagnosticsResponse' }, { type: 'object', required: ['client_request_id'], properties: { client_request_id: { type: 'string' } } } ] }, PageRequestDiagnosticsBatchResponse: { type: 'object', required: ['targets', 'diagnostics_retention', 'diagnostics'], properties: { targets: { type: 'array', items: { $ref: '#/components/schemas/FeedbackTarget' } }, diagnostics_retention: { $ref: '#/components/schemas/AppLogRetentionMetadata' }, diagnostics: { type: 'array', items: { $ref: '#/components/schemas/PageRequestDiagnosticsBatchItem' } } } }, PageRequestDiagnosticsResponse: { type: 'object', required: ['scope', 'matched_log_count', 'events', 'diagnostics_retention'], properties: { scope: { type: 'object', required: ['request_ids', 'filenames', 'filename_matched_request_ids', 'copy_text'], properties: { request_ids: { type: 'array', items: { type: 'string' } }, filenames: { type: 'array', items: { type: 'string' } }, filename_matched_request_ids: { type: 'array', items: { type: 'string' } }, copy_text: { type: 'string' } } }, matched_log_count: { type: 'integer', minimum: 0 }, events: { type: 'array', items: { $ref: '#/components/schemas/PageRequestDiagnosticEvent' } }, diagnostics_retention: { $ref: '#/components/schemas/AppLogRetentionMetadata' }, diagnostics_note: { $ref: '#/components/schemas/PageRequestDiagnosticsNote' } } }, PageRequestDiagnosticsNote: { type: 'object', required: ['code', 'message', 'retention'], properties: { code: { type: 'string', enum: ['no_matching_logs_in_retention_window'] }, message: { type: 'string' }, retention: { $ref: '#/components/schemas/AppLogRetentionMetadata' } } }, PageRequestDiagnosticEvent: { type: 'object', required: ['id', 'at', 'level', 'message'], properties: { id: { type: 'integer' }, at: { type: 'string', format: 'date-time' }, level: { type: 'string', enum: ['debug', 'info', 'warn', 'error'] }, message: { type: 'string' }, client_request_id: { type: 'string' }, filenames: { type: 'array', items: { type: 'string' } }, diagnostics: { $ref: '#/components/schemas/PageRequestDiagnosticContext' } } }, PageRequestDiagnosticContext: { type: 'object', additionalProperties: false, properties: { providerDialect: { type: 'string' }, normalizedEventCount: { type: 'number' }, reason: { type: 'string' }, channel_id: { type: 'string' }, image_backend: { type: 'string' }, operation: { type: 'string' }, stream_mode: { type: 'string' }, streamingStrategy: { type: 'string' }, streaming_strategy: { type: 'string' }, partialImages: { type: 'number' }, partial_images: { type: 'number' }, upstream_status: { type: 'number' }, upstream_event_type: { type: 'string' }, transport_error: { type: 'boolean' } } }, AgentError: { type: 'object', required: ['error'], properties: { error: { type: 'object', required: ['code', 'message', 'retryable', 'request_id'], properties: { code: { type: 'string' }, message: { type: 'string' }, retryable: { type: 'boolean' }, details: { type: 'object' }, upstream_status: { type: 'integer' }, diagnostics: { $ref: '#/components/schemas/AgentErrorDiagnostics' }, request_id: { type: 'string' } } } } }, AgentErrorDiagnostics: { type: 'object', properties: { elapsed_ms: { type: 'integer', minimum: 0 }, channel_request_mode: { type: 'string', enum: CHANNEL_REQUEST_MODES }, channel_request_mode_fallback_applied: { type: 'boolean' }, route_decision: { $ref: '#/components/schemas/ChannelRequestModeDecision' }, selected_channel_id: { type: 'string' }, upstream_host: { type: 'string' }, upstream_status: { type: 'integer' }, upstream_event_type: { type: 'string' }, partial_image_count: { type: 'integer', minimum: 0 }, transport_error: { type: 'boolean' }, transport_error_kind: { type: 'string', enum: [ 'dns', 'tls', 'connect_timeout', 'connection_refused', 'socket_closed', 'upstream_timeout', 'sse_final_missing', 'fetch_failed', 'unknown_transport' ] }, retry_after_seconds: { type: 'integer', minimum: 1 }, retry_after_ms: { type: 'integer', minimum: 0 }, cooldown_until: { type: 'string', format: 'date-time' }, cooldown_target: { type: 'object', required: ['channel_id'], properties: { channel_id: { type: 'string' }, credential_id: { type: 'string' }, request_mode: { type: 'string', enum: CHANNEL_REQUEST_MODES } }, additionalProperties: false }, channel_cooldown_scope: { type: 'string', enum: ['credential', 'channel'] }, response_headers: { type: 'object', additionalProperties: { type: 'string' } } }, additionalProperties: false }, UpstreamRequestHeaderSummary: { type: 'object', required: [ 'user_agent_effective', 'has_extra_headers', 'allowed_header_names', 'configured_header_names' ], properties: { user_agent_effective: { type: 'string' }, has_extra_headers: { type: 'boolean' }, allowed_header_names: { type: 'array', items: { type: 'string' } }, configured_header_names: { type: 'array', items: { type: 'string' } } }, additionalProperties: false }, AgentRequestModeControls: { type: 'object', required: [ 'source', 'global_env', 'channel_env_pattern', 'global_priority_env', 'channel_priority_env_pattern', 'default_priority', 'default_priority_policy', 'mutable_at_runtime', 'agent_client_policy', 'final_gate_command', 'smoke_gate_commands' ], properties: { source: { type: 'string', const: 'admin_env_whitelist' }, global_env: { type: 'string' }, channel_env_pattern: { type: 'string' }, global_priority_env: { type: 'string' }, channel_priority_env_pattern: { type: 'string' }, default_priority: { type: 'array', items: { type: 'string', enum: CHANNEL_REQUEST_MODES } }, default_priority_policy: { type: 'string', const: 'lowest_cost_first' }, mutable_at_runtime: { type: 'boolean', const: false }, agent_client_policy: { type: 'string', const: 'diagnostics_only' }, final_gate_command: { type: 'string' }, smoke_gate_commands: { type: 'object', additionalProperties: { type: 'array', items: { type: 'string' } } } }, additionalProperties: false }, ImageTransportCapabilities: { type: 'object', required: [ 'upstream_timeout_ms', 'stream_data_interval_timeout_ms', 'upstream_max_retries', 'upstream_proxy' ], properties: { upstream_timeout_ms: { type: 'integer', minimum: 1, const: capabilities.image_transport.upstream_timeout_ms }, stream_data_interval_timeout_ms: { type: 'integer', minimum: 0, const: capabilities.image_transport.stream_data_interval_timeout_ms }, upstream_max_retries: { type: 'integer', minimum: 0, const: capabilities.image_transport.upstream_max_retries }, upstream_proxy: { $ref: '#/components/schemas/UpstreamProxySummary' } }, additionalProperties: false }, UpstreamProxySummary: { type: 'object', required: ['configured'], properties: { configured: { type: 'boolean' }, protocol: { type: 'string', enum: ['http', 'https'] } }, additionalProperties: false } } } }; }