"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CodexGen = void 0;
exports.resolveCodexToolChoice = resolveCodexToolChoice;
exports.resolveCodexServiceTier = resolveCodexServiceTier;
exports.resolveCodexInstructions = resolveCodexInstructions;
const log_1 = require("../../log");
const i18n_text_1 = require("../../runtime/i18n-text");
const work_language_1 = require("../../runtime/work-language");
const artifacts_1 = require("./artifacts");
const failure_classifier_1 = require("./failure-classifier");
const tool_call_context_1 = require("./tool-call-context");
const tool_output_limit_1 = require("./tool-output-limit");
const tool_result_image_ingest_1 = require("./tool-result-image-ingest");
const log = (0, log_1.createLogger)('llm/codex');
const codexFallbackInstructions = 'You are Codex CLI.';
function resolveCodexToolChoice(tools, requestContext) {
    const requirement = requestContext.toolUseRequirement ?? 'auto';
    if (tools.length === 0) {
        if (requirement === 'required') {
            throw new Error(`Codex request invariant violation: toolUseRequirement=required but no tools are available (dialog=${requestContext.dialogSelfId})`);
        }
        return 'none';
    }
    if (requirement === 'none')
        return 'none';
    if (requirement === 'required')
        return 'required';
    return 'auto';
}
function resolveCodexRequestTools(tools, requestContext) {
    return (requestContext.toolUseRequirement ?? 'auto') === 'none' ? [] : [...tools];
}
function toCodexAuthRequest(payload) {
    // `@longrun-ai/codex-auth` currently types ChatGPT Responses `tool_choice` as only `'auto'`,
    // while the wire API accepts the same `'none' | 'auto' | 'required'` control used by Responses.
    // Keep the widened type local to this adapter and cross the stale package boundary explicitly.
    return payload;
}
function resolveCodexServiceTier(serviceTier) {
    // The ChatGPT codex backend rejects the literal `default` tier even though some SDK typings
    // still list it. Omitting the field preserves the standard tier semantics without a 400.
    if (serviceTier === undefined || serviceTier === null || serviceTier === 'default') {
        return undefined;
    }
    return serviceTier;
}
function limitCodexToolOutputText(text, msg, limitChars) {
    const limited = (0, tool_output_limit_1.truncateProviderToolOutputText)(text, limitChars);
    if (limited.truncated) {
        log.warn('CODEX tool output truncated before provider request', undefined, {
            callId: msg.id,
            toolName: msg.name,
            originalChars: limited.originalChars,
            limitChars: limited.limitChars,
        });
    }
    return limited.text;
}
function limitCodexToolOutputItems(output, msg, limitChars) {
    let remainingChars = limitChars;
    let truncated = false;
    const limited = [];
    for (const item of output) {
        if (item.type !== 'input_text') {
            limited.push(item);
            continue;
        }
        if (remainingChars <= 0) {
            truncated = true;
            break;
        }
        const next = (0, tool_output_limit_1.truncateProviderToolOutputText)(item.text, remainingChars);
        limited.push({ type: 'input_text', text: next.text });
        remainingChars -= next.text.length;
        if (next.truncated) {
            truncated = true;
            break;
        }
    }
    if (truncated) {
        const originalChars = output.reduce((sum, item) => sum + (item.type === 'input_text' ? item.text.length : 0), 0);
        log.warn('CODEX tool output items truncated before provider request', undefined, {
            callId: msg.id,
            toolName: msg.name,
            originalTextChars: originalChars,
        });
    }
    return limited;
}
function isRecord(value) {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function tryExtractApiReturnedModel(value) {
    // NOTE: This payload is derived from an external API / transport layer.
    // Some upstream variants include `model`, but the exported TS types may not.
    // A runtime check is unavoidable here.
    if (!isRecord(value))
        return undefined;
    if (!('model' in value))
        return undefined;
    const model = value.model;
    if (typeof model !== 'string')
        return undefined;
    const trimmed = model.trim();
    return trimmed.length > 0 ? trimmed : undefined;
}
function resolveCodexInstructions(systemPrompt) {
    return systemPrompt.trim().length > 0 ? systemPrompt : codexFallbackInstructions;
}
function funcToolToCodex(funcTool) {
    // MCP schemas are passed through to providers. Codex tool schema types are narrower; runtime
    // validation is handled by provider rejection + the driver stop policy.
    const parameters = funcTool.parameters;
    const description = (0, i18n_text_1.getTextForLanguage)({ i18n: funcTool.descriptionI18n, fallback: funcTool.description }, (0, work_language_1.getWorkLanguage)());
    return {
        type: 'function',
        name: funcTool.name,
        description,
        strict: false,
        parameters,
    };
}
const CODEX_JSON_RESPONSE_FORMAT_NAME = 'dominds_json_response';
const CODEX_JSON_RESPONSE_SCHEMA = {
    type: 'object',
    additionalProperties: true,
};
function resolveCodexWebSearchMode(agent) {
    return agent.model_params?.codex?.web_search ?? 'live';
}
function resolveCodexJsonResponseEnabled(agent) {
    const providerSpecific = agent.model_params?.codex?.json_response;
    if (providerSpecific !== undefined)
        return providerSpecific;
    return agent.model_params?.json_response === true;
}
function buildCodexNativeTools(agent) {
    const webSearchMode = resolveCodexWebSearchMode(agent);
    if (webSearchMode === 'disabled')
        return [];
    const webSearchTool = {
        type: 'web_search',
        external_web_access: webSearchMode === 'live',
    };
    return [webSearchTool];
}
function buildCodexTextControls(agent) {
    // Provider isolation rule: the Codex wrapper only consumes `model_params.codex.*`.
    const codexParams = agent.model_params?.codex;
    const text = {};
    if (codexParams && codexParams.verbosity) {
        text.verbosity = codexParams.verbosity;
    }
    if (resolveCodexJsonResponseEnabled(agent)) {
        text.format = {
            type: 'json_schema',
            name: CODEX_JSON_RESPONSE_FORMAT_NAME,
            strict: true,
            schema: CODEX_JSON_RESPONSE_SCHEMA,
        };
    }
    return Object.keys(text).length > 0 ? text : undefined;
}
function buildCodexReasoning(agent) {
    // Provider isolation rule: do not borrow OpenAI Responses params inside the Codex wrapper.
    const codexParams = agent.model_params?.codex;
    if (codexParams?.reasoning_effort === undefined && codexParams?.reasoning_summary === undefined) {
        return null;
    }
    return {
        ...(codexParams?.reasoning_effort !== undefined
            ? { effort: codexParams.reasoning_effort }
            : {}),
        ...(codexParams?.reasoning_summary !== undefined
            ? { summary: codexParams.reasoning_summary }
            : { summary: 'auto' }),
    };
}
function assertNoCodexNativeToolCollisions(funcTools, nativeTools) {
    const names = new Set();
    for (const t of funcTools) {
        names.add(t.name);
    }
    for (const nativeTool of nativeTools) {
        if (nativeTool.type !== 'web_search' && nativeTool.type !== 'local_shell') {
            continue;
        }
        const nativeName = nativeTool.type;
        if (names.has(nativeName)) {
            throw new Error(`Codex native tool name collision: function tool '${nativeName}' conflicts with native '${nativeName}' tool.`);
        }
    }
}
function toLlmWebSearchCall(item, itemId, phase) {
    return {
        source: 'codex',
        phase,
        itemId,
        status: item.status,
        action: item.action,
    };
}
function tryGetWebSearchCallItemId(item) {
    const raw = typeof item.id === 'string' ? item.id.trim() : '';
    return raw.length > 0 ? raw : null;
}
function extractReasoningText(item) {
    const reasoning = extractReasoningPayload(item);
    let text = '';
    for (const part of reasoning.summary) {
        text += part.text;
    }
    for (const part of reasoning.content ?? []) {
        text += part.text;
    }
    return text;
}
function extractReasoningPayload(item) {
    const summary = [];
    for (const part of item.summary) {
        summary.push({ type: 'summary_text', text: part.text });
    }
    const content = item.content?.map((part) => ({ type: part.type, text: part.text }));
    const encrypted = typeof item.encrypted_content === 'string' && item.encrypted_content.length > 0
        ? item.encrypted_content
        : undefined;
    const reasoning = { summary };
    if (content && content.length > 0)
        reasoning.content = content;
    if (encrypted)
        reasoning.encrypted_content = encrypted;
    const hasReasoningData = summary.length > 0 || (content?.length ?? 0) > 0 || encrypted !== undefined;
    if (hasReasoningData) {
        reasoning.metadata = {
            itemType: item.type,
        };
        if (typeof item.id === 'string' && item.id.length > 0) {
            reasoning.metadata.itemId = item.id;
        }
    }
    return reasoning;
}
function hasReasoningPayloadSignals(payload) {
    return (payload.summary.length > 0 ||
        (payload.content?.length ?? 0) > 0 ||
        (payload.encrypted_content?.length ?? 0) > 0 ||
        payload.metadata !== undefined);
}
function buildReasoningPayloadFromText(text) {
    if (text.trim().length === 0)
        return undefined;
    return {
        summary: [{ type: 'summary_text', text }],
    };
}
function thinkingMessageToCodexReasoningItem(msg) {
    const reasoning = msg.reasoning ?? buildReasoningPayloadFromText(msg.content);
    if (!reasoning) {
        return { type: 'reasoning', summary: [] };
    }
    return {
        type: 'reasoning',
        summary: reasoning.summary.map((part) => ({ type: 'summary_text', text: part.text })),
        ...(reasoning.content ? { content: reasoning.content.map((part) => ({ ...part })) } : {}),
        ...(reasoning.encrypted_content ? { encrypted_content: reasoning.encrypted_content } : {}),
    };
}
function messageItem(role, text) {
    const contentType = role === 'assistant' ? 'output_text' : 'input_text';
    return {
        type: 'message',
        role,
        content: [
            {
                type: contentType,
                text,
            },
        ],
    };
}
function chatMessageToCodexItems(msg) {
    switch (msg.type) {
        case 'environment_msg':
        case 'prompting_msg':
            return [messageItem('user', msg.content)];
        case 'transient_guide_msg':
        case 'saying_msg':
            return [messageItem('assistant', msg.content)];
        case 'thinking_msg':
            return [thinkingMessageToCodexReasoningItem(msg)];
        case 'tellask_result_msg':
        case 'tellask_carryover_msg':
            return [messageItem('user', msg.content)];
        case 'func_call_msg':
            return [
                {
                    type: 'function_call',
                    name: msg.name,
                    arguments: msg.arguments,
                    call_id: msg.id,
                },
            ];
        case 'func_result_msg':
            return [
                {
                    type: 'function_call_output',
                    call_id: msg.id,
                    output: msg.content,
                },
            ];
        default: {
            const _exhaustive = msg;
            throw new Error(`Unsupported chat message: ${_exhaustive}`);
        }
    }
}
async function userLikeMessageToCodexItemsWithImages(msg, requestContext, providerConfig, allowedImageKeys, onUserImageIngest) {
    const items = msg.contentItems;
    if (!Array.isArray(items) || items.length === 0) {
        return chatMessageToCodexItems(msg);
    }
    const content = [{ type: 'input_text', text: msg.content }];
    const supportsImageInput = (0, tool_result_image_ingest_1.resolveModelImageInputSupport)(requestContext.modelKey === undefined
        ? undefined
        : providerConfig?.models[requestContext.modelKey], true);
    for (const [itemIndex, item] of items.entries()) {
        if (item.type === 'input_text') {
            content.push({ type: 'input_text', text: item.text });
            continue;
        }
        if (item.type === 'input_image') {
            if (!supportsImageInput) {
                if (onUserImageIngest) {
                    await onUserImageIngest((0, tool_result_image_ingest_1.buildUserImageIngest)({
                        requestContext,
                        ...(msg.type === 'prompting_msg' ? { msgId: msg.msgId } : {}),
                        artifact: item.artifact,
                        disposition: 'filtered_model_unsupported',
                        providerPathLabel: 'Codex Responses path',
                    }));
                }
                content.push({
                    type: 'input_text',
                    text: `[image not sent: current model does not support image input]`,
                });
                continue;
            }
            if (!(0, artifacts_1.isVisionImageMimeType)(item.mimeType)) {
                if (onUserImageIngest) {
                    await onUserImageIngest((0, tool_result_image_ingest_1.buildUserImageIngest)({
                        requestContext,
                        ...(msg.type === 'prompting_msg' ? { msgId: msg.msgId } : {}),
                        artifact: item.artifact,
                        disposition: 'filtered_mime_unsupported',
                        mimeType: item.mimeType,
                        providerPathLabel: 'Codex Responses path',
                    }));
                }
                content.push({
                    type: 'input_text',
                    text: `[image not sent: unsupported mimeType=${item.mimeType}]`,
                });
                continue;
            }
            if (!allowedImageKeys.has((0, tool_result_image_ingest_1.buildImageBudgetKeyForContentItem)({ msg, itemIndex, artifact: item.artifact }))) {
                if (onUserImageIngest) {
                    await onUserImageIngest((0, tool_result_image_ingest_1.buildUserImageIngest)({
                        requestContext,
                        ...(msg.type === 'prompting_msg' ? { msgId: msg.msgId } : {}),
                        artifact: item.artifact,
                        disposition: 'filtered_size_limit',
                        detail: (0, tool_result_image_ingest_1.buildImageBudgetLimitDetail)({
                            byteLength: item.byteLength,
                            budgetBytes: tool_result_image_ingest_1.CODEX_TOOL_RESULT_IMAGE_BUDGET_BYTES,
                        }),
                        providerPathLabel: 'Codex Responses path',
                    }));
                }
                content.push({
                    type: 'input_text',
                    text: `[image not sent: request image budget exceeded bytes=${String(item.byteLength)} budget=${String(tool_result_image_ingest_1.CODEX_TOOL_RESULT_IMAGE_BUDGET_BYTES)}]`,
                });
                continue;
            }
            const bytesResult = await (0, tool_result_image_ingest_1.readToolResultImageBytesSafe)(item.artifact);
            if (bytesResult.kind === 'missing') {
                if (onUserImageIngest) {
                    await onUserImageIngest((0, tool_result_image_ingest_1.buildUserImageIngest)({
                        requestContext,
                        ...(msg.type === 'prompting_msg' ? { msgId: msg.msgId } : {}),
                        artifact: item.artifact,
                        disposition: 'filtered_missing',
                        providerPathLabel: 'Codex Responses path',
                    }));
                }
                content.push({ type: 'input_text', text: `[image missing: ${item.artifact.relPath}]` });
                continue;
            }
            if (bytesResult.kind === 'read_failed') {
                if (onUserImageIngest) {
                    await onUserImageIngest((0, tool_result_image_ingest_1.buildUserImageIngest)({
                        requestContext,
                        ...(msg.type === 'prompting_msg' ? { msgId: msg.msgId } : {}),
                        artifact: item.artifact,
                        disposition: 'filtered_read_failed',
                        detail: bytesResult.detail,
                        providerPathLabel: 'Codex Responses path',
                    }));
                }
                content.push({ type: 'input_text', text: `[image unreadable: ${item.artifact.relPath}]` });
                continue;
            }
            if (onUserImageIngest) {
                await onUserImageIngest((0, tool_result_image_ingest_1.buildUserImageIngest)({
                    requestContext,
                    ...(msg.type === 'prompting_msg' ? { msgId: msg.msgId } : {}),
                    artifact: item.artifact,
                    disposition: 'fed_native',
                    providerPathLabel: 'Codex Responses path',
                }));
            }
            content.push({
                type: 'input_image',
                image_url: (0, artifacts_1.bytesToDataUrl)({ mimeType: item.mimeType, bytes: bytesResult.bytes }),
            });
            continue;
        }
        const _exhaustive = item;
        throw new Error(`Unsupported user content item: ${String(_exhaustive)}`);
    }
    return [
        {
            type: 'message',
            role: 'user',
            content,
        },
    ];
}
async function buildCodexFunctionCallOutput(msg, limitChars, requestContext, allowedImageKeys, supportsImageInput, onToolResultImageIngest) {
    const items = msg.contentItems;
    if (!Array.isArray(items) || items.length === 0) {
        return limitCodexToolOutputText(msg.content, msg, limitChars);
    }
    const out = [];
    for (const [itemIndex, item] of items.entries()) {
        if (item.type === 'input_text') {
            out.push({ type: 'input_text', text: item.text });
            continue;
        }
        if (item.type === 'input_image') {
            if (!supportsImageInput) {
                if (onToolResultImageIngest) {
                    await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
                        requestContext,
                        toolCallId: msg.id,
                        toolName: msg.name,
                        artifact: item.artifact,
                        disposition: 'filtered_model_unsupported',
                        providerPathLabel: 'Codex path',
                    }));
                }
                out.push({
                    type: 'input_text',
                    text: `[image not sent: current model does not support image input]`,
                });
                continue;
            }
            if (!(0, artifacts_1.isVisionImageMimeType)(item.mimeType)) {
                if (onToolResultImageIngest) {
                    await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
                        requestContext,
                        toolCallId: msg.id,
                        toolName: msg.name,
                        artifact: item.artifact,
                        disposition: 'filtered_mime_unsupported',
                        mimeType: item.mimeType,
                        providerPathLabel: 'Codex path',
                    }));
                }
                out.push({
                    type: 'input_text',
                    text: `[image omitted: unsupported mimeType=${item.mimeType}]`,
                });
                continue;
            }
            if (!allowedImageKeys.has((0, tool_result_image_ingest_1.buildImageBudgetKeyForContentItem)({ msg, itemIndex, artifact: item.artifact }))) {
                if (onToolResultImageIngest) {
                    await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
                        requestContext,
                        toolCallId: msg.id,
                        toolName: msg.name,
                        artifact: item.artifact,
                        disposition: 'filtered_size_limit',
                        detail: (0, tool_result_image_ingest_1.buildImageBudgetLimitDetail)({
                            byteLength: item.byteLength,
                            budgetBytes: tool_result_image_ingest_1.CODEX_TOOL_RESULT_IMAGE_BUDGET_BYTES,
                        }),
                        providerPathLabel: 'Codex path',
                    }));
                }
                out.push({
                    type: 'input_text',
                    text: `[image omitted: request image budget exceeded bytes=${String(item.byteLength)} budget=${String(tool_result_image_ingest_1.CODEX_TOOL_RESULT_IMAGE_BUDGET_BYTES)}]`,
                });
                continue;
            }
            const bytesResult = await (0, tool_result_image_ingest_1.readToolResultImageBytesSafe)(item.artifact);
            if (bytesResult.kind === 'missing') {
                if (onToolResultImageIngest) {
                    await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
                        requestContext,
                        toolCallId: msg.id,
                        toolName: msg.name,
                        artifact: item.artifact,
                        disposition: 'filtered_missing',
                        providerPathLabel: 'Codex path',
                    }));
                }
                out.push({ type: 'input_text', text: `[image missing: ${item.artifact.relPath}]` });
                continue;
            }
            if (bytesResult.kind === 'read_failed') {
                if (onToolResultImageIngest) {
                    await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
                        requestContext,
                        toolCallId: msg.id,
                        toolName: msg.name,
                        artifact: item.artifact,
                        disposition: 'filtered_read_failed',
                        detail: bytesResult.detail,
                        providerPathLabel: 'Codex path',
                    }));
                }
                out.push({ type: 'input_text', text: `[image unreadable: ${item.artifact.relPath}]` });
                continue;
            }
            if (onToolResultImageIngest) {
                await onToolResultImageIngest((0, tool_result_image_ingest_1.buildToolResultImageIngest)({
                    requestContext,
                    toolCallId: msg.id,
                    toolName: msg.name,
                    artifact: item.artifact,
                    disposition: 'fed_native',
                    providerPathLabel: 'Codex path',
                }));
            }
            const bytes = bytesResult.bytes;
            out.push({
                type: 'input_image',
                image_url: (0, artifacts_1.bytesToDataUrl)({ mimeType: item.mimeType, bytes }),
            });
            continue;
        }
        const _exhaustive = item;
        out.push({ type: 'input_text', text: `[unknown content item: ${String(_exhaustive)}]` });
    }
    return out.length > 0
        ? limitCodexToolOutputItems(out, msg, limitChars)
        : limitCodexToolOutputText(msg.content, msg, limitChars);
}
async function buildCodexInput(context, requestContext, providerConfig, onToolResultImageIngest, onUserImageIngest) {
    const normalized = (0, tool_call_context_1.normalizeToolCallPairs)(context);
    const violation = (0, tool_call_context_1.findFirstToolCallAdjacencyViolation)(normalized);
    if (violation) {
        const detail = (0, tool_call_context_1.formatToolCallAdjacencyViolation)(violation, 'CODEX provider projection');
        log.error(detail, new Error('codex_tool_call_adjacency_violation'), {
            callId: violation.callId,
            toolName: violation.toolName,
            violationKind: violation.kind,
            index: violation.index,
        });
        throw new Error(detail);
    }
    const input = [];
    const toolResultMaxChars = (0, tool_output_limit_1.resolveProviderToolResultMaxChars)(providerConfig);
    const allowedImageKeys = (0, tool_result_image_ingest_1.selectLatestImagesWithinBudget)(normalized, tool_result_image_ingest_1.CODEX_TOOL_RESULT_IMAGE_BUDGET_BYTES);
    const supportsImageInput = (0, tool_result_image_ingest_1.resolveModelImageInputSupport)(requestContext.modelKey === undefined
        ? undefined
        : providerConfig?.models[requestContext.modelKey], true);
    for (const msg of normalized) {
        if ((msg.type === 'prompting_msg' ||
            msg.type === 'tellask_result_msg' ||
            msg.type === 'tellask_carryover_msg') &&
            Array.isArray(msg.contentItems) &&
            msg.contentItems.length > 0) {
            input.push(...(await userLikeMessageToCodexItemsWithImages(msg, requestContext, providerConfig, allowedImageKeys, onUserImageIngest)));
            continue;
        }
        if (msg.type === 'func_call_msg') {
            input.push({
                type: 'function_call',
                name: msg.name,
                arguments: msg.arguments,
                call_id: msg.id,
            });
            continue;
        }
        if (msg.type === 'func_result_msg') {
            input.push({
                type: 'function_call_output',
                call_id: msg.id,
                output: await buildCodexFunctionCallOutput(msg, toolResultMaxChars, requestContext, allowedImageKeys, supportsImageInput, onToolResultImageIngest),
            });
            continue;
        }
        const items = chatMessageToCodexItems(msg);
        for (const item of items) {
            input.push(item);
        }
    }
    return input;
}
async function buildCodexRequest(providerConfig, agent, instructions, funcTools, requestContext, context, onToolResultImageIngest, onUserImageIngest) {
    if (!agent.model) {
        throw new Error(`Internal error: Model is undefined for agent '${agent.id}'`);
    }
    const input = await buildCodexInput(context, requestContext, providerConfig, onToolResultImageIngest, onUserImageIngest);
    // Provider isolation rule: request construction must only read Codex-native params here.
    const codexParams = agent.model_params?.codex;
    const parallelToolCalls = codexParams?.parallel_tool_calls ?? true;
    const reasoning = buildCodexReasoning(agent);
    const include = reasoning !== null ? ['reasoning.encrypted_content'] : [];
    const serviceTier = resolveCodexServiceTier(codexParams?.service_tier);
    const text = buildCodexTextControls(agent);
    const nativeTools = buildCodexNativeTools(agent);
    assertNoCodexNativeToolCollisions(funcTools, nativeTools);
    const tools = [...funcTools.map(funcToolToCodex), ...nativeTools];
    const requestTools = resolveCodexRequestTools(tools, requestContext);
    return {
        model: agent.model,
        instructions,
        input,
        tools: requestTools,
        tool_choice: resolveCodexToolChoice(requestTools, requestContext),
        parallel_tool_calls: parallelToolCalls,
        reasoning,
        ...(serviceTier !== undefined ? { service_tier: serviceTier } : {}),
        store: false,
        stream: true,
        include,
        ...(requestContext.promptCacheKey !== undefined &&
            requestContext.promptCacheKey.trim().length > 0
            ? { prompt_cache_key: requestContext.promptCacheKey }
            : {}),
        text,
    };
}
class CodexGen {
    get apiType() {
        return 'codex';
    }
    classifyFailure(error) {
        return (0, failure_classifier_1.classifyOpenAiLikeFailure)(error);
    }
    async genToReceiver(providerConfig, agent, systemPrompt, funcTools, requestContext, context, receiver, _genseq, abortSignal) {
        const codexHomeValue = process.env[providerConfig.apiKeyEnvVar] || '~/.codex';
        const codexHome = codexHomeValue.startsWith('~')
            ? process.env['HOME'] + codexHomeValue.substring(1)
            : codexHomeValue;
        // NOTE: `@longrun-ai/codex-auth` is an ESM package (`"type": "module"`). The Dominds backend is
        // compiled as CommonJS, so Node.js requires a dynamic `import()` for runtime access here.
        const codexAuth = await import('@longrun-ai/codex-auth');
        const authPreparation = codexAuth.prepareCodexFileAuth({
            codexHome,
            codexHomeEnvVar: providerConfig.apiKeyEnvVar,
            providerName: `Dominds codex provider '${providerConfig.name}'`,
        });
        if (authPreparation.kind === 'action_required') {
            throw new Error(codexAuth.formatCodexFileAuthActionRequired(authPreparation));
        }
        if (authPreparation.changedConfigToFile) {
            log.info('Codex CLI auth storage switched to file mode for Dominds codex provider', undefined, {
                codexHome: authPreparation.codexHome,
                configPath: authPreparation.configPath,
                previousStoreMode: authPreparation.previousStoreMode,
            });
        }
        const manager = new codexAuth.AuthManager({ codexHome });
        const client = await codexAuth.createChatGptClientFromManager(manager, {
            baseUrl: providerConfig.baseUrl,
        });
        if (!agent.model) {
            throw new Error(`Internal error: Model is undefined for agent '${agent.id}'`);
        }
        const instructions = resolveCodexInstructions(systemPrompt);
        const payload = await buildCodexRequest(providerConfig, agent, instructions, funcTools, requestContext, context, receiver.toolResultImageIngest, receiver.userImageIngest);
        let sayingStarted = false;
        let thinkingStarted = false;
        let sawOutputText = false;
        let activeStream = 'idle';
        let usage = { kind: 'unavailable' };
        let returnedModel;
        const streamedReasoningItemIds = new Set();
        let sawReasoningDeltaWithoutItemId = false;
        let currentThinkingContent = '';
        const eventReceiver = {
            onEvent: async (event) => {
                switch (event.type) {
                    case 'response.created':
                    case 'response.in_progress':
                        if (returnedModel === undefined) {
                            returnedModel = tryExtractApiReturnedModel(event.response);
                        }
                        return;
                    case 'response.failed': {
                        const error = event.response.error;
                        const message = error && typeof error.message === 'string' && error.message.length > 0
                            ? error.message
                            : 'Codex response failed.';
                        throw new Error(message);
                    }
                    case 'response.output_text.delta': {
                        const delta = event.delta;
                        if (delta.length > 0) {
                            if (activeStream === 'thinking') {
                                const detail = 'CODEX stream overlap violation: received output_text while thinking stream still active';
                                log.error(detail, new Error('codex_stream_overlap_violation'));
                                if (receiver.streamError) {
                                    await receiver.streamError(detail);
                                }
                                if (thinkingStarted) {
                                    await receiver.thinkingFinish(buildReasoningPayloadFromText(currentThinkingContent));
                                    thinkingStarted = false;
                                    currentThinkingContent = '';
                                }
                                activeStream = 'idle';
                            }
                            if (!sayingStarted) {
                                sayingStarted = true;
                                await receiver.sayingStart();
                                activeStream = 'saying';
                            }
                            await receiver.sayingChunk(delta);
                            sawOutputText = true;
                        }
                        return;
                    }
                    case 'response.output_text.done': {
                        if (!sawOutputText && event.text.length > 0) {
                            if (activeStream === 'thinking') {
                                const detail = 'CODEX stream overlap violation: received output_text while thinking stream still active';
                                log.error(detail, new Error('codex_stream_overlap_violation'));
                                if (receiver.streamError) {
                                    await receiver.streamError(detail);
                                }
                                if (thinkingStarted) {
                                    await receiver.thinkingFinish(buildReasoningPayloadFromText(currentThinkingContent));
                                    thinkingStarted = false;
                                    currentThinkingContent = '';
                                }
                                activeStream = 'idle';
                            }
                            if (!sayingStarted) {
                                sayingStarted = true;
                                await receiver.sayingStart();
                                activeStream = 'saying';
                            }
                            await receiver.sayingChunk(event.text);
                            sawOutputText = true;
                        }
                        if (sayingStarted) {
                            await receiver.sayingFinish();
                            sayingStarted = false;
                            if (activeStream === 'saying')
                                activeStream = 'idle';
                        }
                        return;
                    }
                    case 'response.content_part.added':
                    case 'response.content_part.done':
                        return;
                    case 'response.reasoning_summary_text.delta':
                    case 'response.reasoning_text.delta': {
                        const delta = event.delta;
                        if (delta.length > 0) {
                            if (typeof event.item_id === 'string' && event.item_id.length > 0) {
                                streamedReasoningItemIds.add(event.item_id);
                            }
                            else {
                                sawReasoningDeltaWithoutItemId = true;
                            }
                            if (activeStream === 'saying') {
                                const detail = 'CODEX stream overlap violation: received reasoning while saying stream still active';
                                log.error(detail, new Error('codex_stream_overlap_violation'));
                                if (receiver.streamError) {
                                    await receiver.streamError(detail);
                                }
                                if (sayingStarted) {
                                    await receiver.sayingFinish();
                                    sayingStarted = false;
                                }
                                activeStream = 'idle';
                            }
                            if (!thinkingStarted) {
                                thinkingStarted = true;
                                currentThinkingContent = '';
                                await receiver.thinkingStart();
                                activeStream = 'thinking';
                            }
                            currentThinkingContent += delta;
                            await receiver.thinkingChunk(delta);
                        }
                        return;
                    }
                    case 'response.reasoning_summary_part.added': {
                        if (activeStream === 'saying') {
                            const detail = 'CODEX stream overlap violation: received reasoning while saying stream still active';
                            log.error(detail, new Error('codex_stream_overlap_violation'));
                            if (receiver.streamError) {
                                await receiver.streamError(detail);
                            }
                            if (sayingStarted) {
                                await receiver.sayingFinish();
                                sayingStarted = false;
                            }
                            activeStream = 'idle';
                        }
                        if (!thinkingStarted) {
                            thinkingStarted = true;
                            currentThinkingContent = '';
                            await receiver.thinkingStart();
                            activeStream = 'thinking';
                        }
                        return;
                    }
                    case 'response.reasoning_summary_text.done':
                    case 'response.reasoning_text.done':
                    case 'response.reasoning_summary_part.done': {
                        if (thinkingStarted) {
                            await receiver.thinkingFinish(buildReasoningPayloadFromText(currentThinkingContent));
                            thinkingStarted = false;
                            currentThinkingContent = '';
                            if (activeStream === 'thinking')
                                activeStream = 'idle';
                        }
                        return;
                    }
                    case 'response.output_item.added':
                        if (event.item.type === 'web_search_call' && receiver.webSearchCall) {
                            const itemId = tryGetWebSearchCallItemId(event.item);
                            if (!itemId) {
                                const detail = 'Non-fatal LLM error: invalid web_search_call (missing itemId); dropping event';
                                log.error(detail, new Error('codex_web_search_call_missing_item_id'), {
                                    status: event.item.status,
                                    action: event.item.action,
                                });
                                if (receiver.streamError) {
                                    await receiver.streamError(detail);
                                }
                                return;
                            }
                            await receiver.webSearchCall(toLlmWebSearchCall(event.item, itemId, 'added'));
                        }
                        return;
                    case 'response.output_item.done': {
                        switch (event.item.type) {
                            case 'function_call':
                                await receiver.funcCall(event.item.call_id, event.item.name, event.item.arguments);
                                return;
                            case 'message': {
                                if (!sawOutputText) {
                                    let text = '';
                                    for (const part of event.item.content) {
                                        switch (part.type) {
                                            case 'output_text':
                                                text += part.text;
                                                break;
                                            case 'input_text':
                                            case 'input_image':
                                                break;
                                            default: {
                                                const _exhaustive = part;
                                                return _exhaustive;
                                            }
                                        }
                                    }
                                    if (text.length > 0) {
                                        if (activeStream === 'thinking') {
                                            const detail = 'CODEX stream overlap violation: received output_text while thinking stream still active';
                                            log.error(detail, new Error('codex_stream_overlap_violation'));
                                            if (receiver.streamError) {
                                                await receiver.streamError(detail);
                                            }
                                            if (thinkingStarted) {
                                                await receiver.thinkingFinish(buildReasoningPayloadFromText(currentThinkingContent));
                                                thinkingStarted = false;
                                                currentThinkingContent = '';
                                            }
                                            activeStream = 'idle';
                                        }
                                        if (!sayingStarted) {
                                            sayingStarted = true;
                                            await receiver.sayingStart();
                                            activeStream = 'saying';
                                        }
                                        await receiver.sayingChunk(text);
                                        await receiver.sayingFinish();
                                        sayingStarted = false;
                                        if (activeStream === 'saying')
                                            activeStream = 'idle';
                                        sawOutputText = true;
                                    }
                                }
                                return;
                            }
                            case 'reasoning': {
                                const payloadFromItem = extractReasoningPayload(event.item);
                                const itemId = typeof event.item.id === 'string' && event.item.id.length > 0
                                    ? event.item.id
                                    : null;
                                const sawReasoningDelta = itemId !== null
                                    ? streamedReasoningItemIds.has(itemId)
                                    : sawReasoningDeltaWithoutItemId;
                                if (!sawReasoningDelta) {
                                    const text = extractReasoningText(event.item);
                                    if (text.length > 0 || hasReasoningPayloadSignals(payloadFromItem)) {
                                        if (activeStream === 'saying') {
                                            const detail = 'CODEX stream overlap violation: received reasoning while saying stream still active';
                                            log.error(detail, new Error('codex_stream_overlap_violation'));
                                            if (receiver.streamError) {
                                                await receiver.streamError(detail);
                                            }
                                            if (sayingStarted) {
                                                await receiver.sayingFinish();
                                                sayingStarted = false;
                                            }
                                            activeStream = 'idle';
                                        }
                                        if (!thinkingStarted) {
                                            thinkingStarted = true;
                                            currentThinkingContent = '';
                                            await receiver.thinkingStart();
                                            activeStream = 'thinking';
                                        }
                                        if (text.length > 0) {
                                            currentThinkingContent += text;
                                            await receiver.thinkingChunk(text);
                                        }
                                        await receiver.thinkingFinish(payloadFromItem);
                                        thinkingStarted = false;
                                        currentThinkingContent = '';
                                        if (activeStream === 'thinking')
                                            activeStream = 'idle';
                                    }
                                }
                                else if (thinkingStarted) {
                                    await receiver.thinkingFinish(payloadFromItem);
                                    thinkingStarted = false;
                                    currentThinkingContent = '';
                                    if (activeStream === 'thinking')
                                        activeStream = 'idle';
                                }
                                else if (hasReasoningPayloadSignals(payloadFromItem)) {
                                    await receiver.thinkingStart();
                                    await receiver.thinkingFinish(payloadFromItem);
                                }
                                return;
                            }
                            case 'local_shell_call':
                            case 'function_call_output':
                            case 'custom_tool_call':
                            case 'custom_tool_call_output':
                            case 'ghost_snapshot':
                            case 'compaction':
                            case 'compaction_summary':
                                return;
                            case 'web_search_call':
                                if (receiver.webSearchCall) {
                                    const itemId = tryGetWebSearchCallItemId(event.item);
                                    if (!itemId) {
                                        const detail = 'Non-fatal LLM error: invalid web_search_call (missing itemId); dropping event';
                                        log.error(detail, new Error('codex_web_search_call_missing_item_id'), {
                                            status: event.item.status,
                                            action: event.item.action,
                                        });
                                        if (receiver.streamError) {
                                            await receiver.streamError(detail);
                                        }
                                        return;
                                    }
                                    await receiver.webSearchCall(toLlmWebSearchCall(event.item, itemId, 'done'));
                                }
                                return;
                            default: {
                                const _exhaustive = event.item;
                                return _exhaustive;
                            }
                        }
                    }
                    case 'response.completed': {
                        if (thinkingStarted) {
                            await receiver.thinkingFinish(buildReasoningPayloadFromText(currentThinkingContent));
                            thinkingStarted = false;
                            currentThinkingContent = '';
                        }
                        if (sayingStarted) {
                            await receiver.sayingFinish();
                            sayingStarted = false;
                        }
                        activeStream = 'idle';
                        if (returnedModel === undefined) {
                            returnedModel = tryExtractApiReturnedModel(event.response);
                        }
                        const responseUsage = event.response.usage;
                        if (responseUsage &&
                            typeof responseUsage.input_tokens === 'number' &&
                            typeof responseUsage.output_tokens === 'number') {
                            usage = {
                                kind: 'available',
                                promptTokens: responseUsage.input_tokens,
                                completionTokens: responseUsage.output_tokens,
                                totalTokens: typeof responseUsage.total_tokens === 'number'
                                    ? responseUsage.total_tokens
                                    : responseUsage.input_tokens + responseUsage.output_tokens,
                            };
                        }
                        return;
                    }
                    default: {
                        const _exhaustive = event;
                        return _exhaustive;
                    }
                }
            },
        };
        try {
            await client.trigger(toCodexAuthRequest(payload), eventReceiver, abortSignal ? { signal: abortSignal } : {});
        }
        catch (error) {
            log.warn('CODEX streaming error', error);
            throw error;
        }
        finally {
            if (thinkingStarted) {
                await receiver.thinkingFinish(buildReasoningPayloadFromText(currentThinkingContent));
            }
            if (sayingStarted) {
                await receiver.sayingFinish();
            }
        }
        return { usage, llmGenModel: returnedModel };
    }
    async genMoreMessages(_providerConfig, _agent, _systemPrompt, _funcTools, _requestContext, _context, _genseq) {
        throw new Error('Codex generator only supports streaming mode.');
    }
}
exports.CodexGen = CodexGen;
