"use strict";
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.OpenAIResponsesProcessor = void 0;
exports.getResponsesApiCompactionThreshold = getResponsesApiCompactionThreshold;
exports.createResponsesRequestBody = createResponsesRequestBody;
exports.getResponsesApiCompactionThresholdFromBody = getResponsesApiCompactionThresholdFromBody;
exports.responseApiInputToRawMessagesForLogging = responseApiInputToRawMessagesForLogging;
exports.processResponseFromChatEndpoint = processResponseFromChatEndpoint;
exports.sendCompletionOutputTelemetry = sendCompletionOutputTelemetry;
const prompt_tsx_1 = require("@vscode/prompt-tsx");
const arrays_1 = require("../../../util/vs/base/common/arrays");
const async_1 = require("../../../util/vs/base/common/async");
const buffer_1 = require("../../../util/vs/base/common/buffer");
const lazy_1 = require("../../../util/vs/base/common/lazy");
const sseParser_1 = require("../../../util/vs/base/common/sseParser");
const types_1 = require("../../../util/vs/base/common/types");
const uuid_1 = require("../../../util/vs/base/common/uuid");
const commonTypes_1 = require("../../chat/common/commonTypes");
const configurationService_1 = require("../../configuration/common/configurationService");
const logService_1 = require("../../log/common/logService");
const anthropic_1 = require("../../networking/common/anthropic");
const fetch_1 = require("../../networking/common/fetch");
const openai_1 = require("../../networking/common/openai");
const toolDeferralService_1 = require("../../networking/common/toolDeferralService");
const chatStream_1 = require("../../networking/node/chatStream");
const chatWebSocketManager_1 = require("../../networking/node/chatWebSocketManager");
const nullExperimentationService_1 = require("../../telemetry/common/nullExperimentationService");
const chatModelCapabilities_1 = require("../common/chatModelCapabilities");
const compactionDataContainer_1 = require("../common/compactionDataContainer");
const phaseDataContainer_1 = require("../common/phaseDataContainer");
const statefulMarkerContainer_1 = require("../common/statefulMarkerContainer");
const thinkingDataContainer_1 = require("../common/thinkingDataContainer");
const responsesApiDebugDump_1 = require("./responsesApiDebugDump");
function getResponsesApiCompactionThreshold(configService, expService, endpoint) {
    const contextManagementEnabled = configService.getExperimentBasedConfig(configurationService_1.ConfigKey.ResponsesApiContextManagementEnabled, expService) && !openai_1.modelsWithoutResponsesContextManagement.has(endpoint.family);
    if (!contextManagementEnabled) {
        return undefined;
    }
    return endpoint.modelMaxPromptTokens > 0
        ? Math.floor(endpoint.modelMaxPromptTokens * 0.9)
        : 50000;
}
function createResponsesRequestBody(accessor, options, model, endpoint) {
    const configService = accessor.get(configurationService_1.IConfigurationService);
    const expService = accessor.get(nullExperimentationService_1.IExperimentationService);
    const verbosity = (0, chatModelCapabilities_1.getVerbosityForModelSync)(endpoint);
    const compactThreshold = getResponsesApiCompactionThreshold(configService, expService, endpoint);
    // compaction supported for all the models but works well for codex models and any future models after 5.3
    const webSocketStatefulMarker = resolveWebSocketStatefulMarker(accessor, options);
    // When WebSocket is in use, always defer to the WebSocket marker (which may be
    // undefined if the connection is new or the summary state changed). Never fall
    // back to the HTTP marker lookup in that case.
    const ignoreStatefulMarker = !!options.ignoreStatefulMarker || !!options.useWebSocket;
    const modeChanged = !!options.modeChanged;
    // Tool search: when enabled, split tools into non-deferred (included in the request) and deferred
    // (excluded from the request entirely). Uses OpenAI's client-executed tool search protocol: we add
    // { type: 'tool_search', execution: 'client' }. The model emits tool_search_call, which we handle via
    // our ToolSearchTool embeddings search, then round-trip as tool_search_output in the next request.
    const toolSearchEnabled = !!endpoint.supportsToolSearch
        && !!options.requestOptions?.tools?.some(t => t.function.name === anthropic_1.CUSTOM_TOOL_SEARCH_NAME);
    const isAllowedConversationAgent = options.location === commonTypes_1.ChatLocation.Agent || options.location === commonTypes_1.ChatLocation.MessagesProxy;
    const isSubagent = options.telemetryProperties?.subType?.startsWith('subagent') ?? false;
    const shouldDeferTools = toolSearchEnabled && isAllowedConversationAgent && !isSubagent;
    const toolDeferralService = shouldDeferTools ? accessor.get(toolDeferralService_1.IToolDeferralService) : undefined;
    const functionTools = [];
    if (options.requestOptions?.tools) {
        for (const tool of options.requestOptions.tools) {
            if (!tool.function.name || tool.function.name.length === 0) {
                continue;
            }
            // Always skip the tool_search function tool — 'tool_search' is a reserved namespace in the
            // Responses API. Client-executed tool search uses { type: 'tool_search', execution: 'client' } instead.
            if (tool.function.name === anthropic_1.CUSTOM_TOOL_SEARCH_NAME) {
                continue;
            }
            const isDeferred = shouldDeferTools && !toolDeferralService.isNonDeferredTool(tool.function.name);
            // Client-executed tool search: deferred tools are NOT sent in the request.
            // They are returned via tool_search_output when the model searches for them.
            if (isDeferred) {
                continue;
            }
            functionTools.push({
                ...tool.function,
                type: 'function',
                strict: false,
                parameters: (tool.function.parameters || {}),
            });
        }
    }
    // Build final tools array
    const finalTools = [...functionTools];
    if (shouldDeferTools) {
        // Client-executed tool search: the model emits tool_search_call, our ToolSearchTool
        // handles the embeddings search, and we return tool_search_output with full definitions.
        finalTools.unshift({
            type: 'tool_search',
            execution: 'client',
            description: 'Search for relevant tools by describing what you need. Returns tool definitions for tools matching your query.',
            parameters: {
                type: 'object',
                properties: {
                    query: {
                        type: 'string',
                        description: 'Natural language description of what tool capability you are looking for.',
                    },
                },
                required: ['query'],
            },
        });
    }
    const toolsMap = options.requestOptions?.tools
        ? new Map(options.requestOptions.tools.map(t => [t.function.name, t]))
        : undefined;
    const shouldLoadToolFromToolSearch = shouldDeferTools ? (name) => !toolDeferralService.isNonDeferredTool(name) : undefined;
    const body = {
        model,
        ...rawMessagesToResponseAPI(model, options.messages, ignoreStatefulMarker, webSocketStatefulMarker, {
            toolsMap,
            shouldLoadToolFromToolSearch,
            modeChanged,
        }),
        stream: true,
        tools: finalTools.length > 0 ? finalTools : undefined,
        // Only a subset of completion post options are supported, and some
        // are renamed. Handle them manually:
        max_output_tokens: options.postOptions.max_tokens,
        tool_choice: typeof options.postOptions.tool_choice === 'object'
            ? { type: 'function', name: options.postOptions.tool_choice.function.name }
            : options.postOptions.tool_choice,
        top_logprobs: options.postOptions.logprobs ? 3 : undefined,
        store: false,
        text: verbosity ? { verbosity } : undefined,
    };
    if (compactThreshold !== undefined) {
        body.context_management = [{
                'type': openai_1.openAIContextManagementCompactionType,
                // Trigger compaction at 90% of the model max prompt context to keep headroom for active turns.
                'compact_threshold': compactThreshold
            }];
    }
    body.truncation = configService.getConfig(configurationService_1.ConfigKey.Advanced.UseResponsesApiTruncation) ?
        'auto' :
        'disabled';
    const thinkingExplicitlyDisabled = options.modelCapabilities?.enableThinking === false;
    const summaryConfig = configService.getExperimentBasedConfig(configurationService_1.ConfigKey.ResponsesApiReasoningSummary, expService);
    const shouldDisableReasoningSummary = endpoint.family === 'gpt-5.3-codex-spark-preview' || thinkingExplicitlyDisabled;
    const effortFromSetting = configService.getConfig(configurationService_1.ConfigKey.Advanced.ReasoningEffortOverride);
    const effort = endpoint.supportsReasoningEffort?.length
        ? (effortFromSetting || options.modelCapabilities?.reasoningEffort || 'medium')
        : undefined;
    const summary = summaryConfig === 'off' || shouldDisableReasoningSummary ? undefined : summaryConfig;
    if (effort || summary) {
        body.reasoning = {
            ...(effort ? { effort } : {}),
            ...(summary ? { summary } : {})
        };
    }
    body.include = ['reasoning.encrypted_content'];
    const promptCacheKeyEnabled = configService.getExperimentBasedConfig(configurationService_1.ConfigKey.ResponsesApiPromptCacheKeyEnabled, expService);
    if (promptCacheKeyEnabled && options.conversationId) {
        body.prompt_cache_key = `${options.conversationId}:${endpoint.family}`;
    }
    return body;
}
function getResponsesApiCompactionThresholdFromBody(body) {
    const contextManagement = body.context_management;
    if (!Array.isArray(contextManagement)) {
        return undefined;
    }
    for (const item of contextManagement) {
        if (item.type === openai_1.openAIContextManagementCompactionType && typeof item.compact_threshold === 'number') {
            return item.compact_threshold;
        }
    }
    return undefined;
}
function resolveWebSocketStatefulMarker(accessor, options) {
    if (options.ignoreStatefulMarker || !options.useWebSocket || !options.conversationId) {
        return undefined;
    }
    const wsManager = accessor.get(chatWebSocketManager_1.IChatWebSocketManager);
    // If client-side summarization state changed since the stateful marker
    // was stored (new summary, or rollback removing a summary), the server's
    // state no longer matches. Skip the marker so the full history is sent.
    const connSummarizedAt = wsManager.getSummarizedAtRoundId(options.conversationId);
    if (options.summarizedAtRoundId !== connSummarizedAt) {
        return undefined;
    }
    return wsManager.getStatefulMarker(options.conversationId);
}
function rawMessagesToResponseAPI(modelId, messages, ignoreStatefulMarker, webSocketStatefulMarker, options = {}) {
    const { toolsMap, shouldLoadToolFromToolSearch, modeChanged = false } = options;
    const latestCompactionMessageIndex = getLatestCompactionMessageIndex(messages);
    const latestCompactionMessage = latestCompactionMessageIndex !== undefined ? createCompactionRoundTripMessage(messages[latestCompactionMessageIndex]) : undefined;
    let previousResponseId;
    let markerIndex;
    if (webSocketStatefulMarker) {
        // WebSocket path: use the connection's current stateful marker if present in messages
        markerIndex = (0, statefulMarkerContainer_1.getIndexOfStatefulMarker)(webSocketStatefulMarker, messages);
        if (markerIndex !== undefined) {
            previousResponseId = webSocketStatefulMarker;
        }
    }
    else if (!ignoreStatefulMarker) {
        // HTTP path: look up the latest marker for this model from messages
        const statefulMarkerAndIndex = (0, statefulMarkerContainer_1.getStatefulMarkerAndIndex)(modelId, messages);
        if (statefulMarkerAndIndex) {
            previousResponseId = statefulMarkerAndIndex.statefulMarker;
            markerIndex = statefulMarkerAndIndex.index;
        }
    }
    if (modeChanged) {
        previousResponseId = undefined;
        markerIndex = undefined;
    }
    const toolSearchCallIds = new Set();
    const toolSearchLoadedTools = new Set();
    // Only pre-scan when history will be sliced (matches the slicing block below);
    // otherwise the serialization loop visits each tool_search_call before its
    // result and populates these sets in order on its own.
    const willSliceHistory = markerIndex !== undefined || latestCompactionMessageIndex !== undefined;
    if (willSliceHistory) {
        for (const message of messages) {
            if (message.role === prompt_tsx_1.Raw.ChatRole.Assistant && message.toolCalls) {
                for (const toolCall of message.toolCalls) {
                    if (toolCall.function.name === anthropic_1.CUSTOM_TOOL_SEARCH_NAME) {
                        toolSearchCallIds.add(toolCall.id);
                    }
                }
            }
            else if (message.role === prompt_tsx_1.Raw.ChatRole.Tool && message.toolCallId && toolSearchCallIds.has(message.toolCallId) && toolsMap) {
                const resultText = message.content
                    .filter(c => c.type === prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text)
                    .map(c => c.text)
                    .join('');
                for (const t of buildToolSearchOutputTools(resultText, toolsMap, shouldLoadToolFromToolSearch)) {
                    toolSearchLoadedTools.add(t.name);
                }
            }
        }
    }
    if (markerIndex !== undefined) {
        // Requests that resume from previous_response_id send only post-marker history,
        // but they still need the latest compaction item even when that item predates
        // the marker. This keeps both websocket and non-websocket traffic aligned.
        messages = messages.slice(markerIndex + 1);
        if (latestCompactionMessageIndex !== undefined) {
            if (latestCompactionMessageIndex > markerIndex) {
                messages = messages.slice(latestCompactionMessageIndex - (markerIndex + 1));
            }
            else if (latestCompactionMessage) {
                messages = [latestCompactionMessage, ...messages];
            }
        }
    }
    else if (latestCompactionMessageIndex !== undefined) {
        messages = messages.slice(latestCompactionMessageIndex);
    }
    const input = [];
    for (const message of messages) {
        switch (message.role) {
            case prompt_tsx_1.Raw.ChatRole.Assistant:
                if (message.content.length) {
                    input.push(...extractCompactionData(message.content));
                    input.push(...extractThinkingData(message.content));
                    const asstContent = message.content.map(rawContentToResponsesAssistantContent).filter(types_1.isDefined);
                    if (asstContent.length) {
                        const assistantMessage = {
                            role: 'assistant',
                            content: asstContent,
                            type: 'message',
                            phase: extractPhaseData(message.content),
                        };
                        // The Responses API expects previous assistant message content as output_text/refusal,
                        // but the SDK's ResponseOutputMessage type requires response-only id/status fields.
                        input.push(assistantMessage);
                    }
                }
                if (message.toolCalls) {
                    for (const toolCall of message.toolCalls) {
                        if (toolCall.function.name === anthropic_1.CUSTOM_TOOL_SEARCH_NAME) {
                            // Client-executed tool search: emit as tool_search_call instead of function_call
                            toolSearchCallIds.add(toolCall.id);
                            let parsedArgs = {};
                            try {
                                parsedArgs = JSON.parse(toolCall.function.arguments || '{}');
                            }
                            catch { }
                            input.push({
                                type: 'tool_search_call',
                                execution: 'client',
                                call_id: toolCall.id,
                                status: 'completed',
                                arguments: parsedArgs,
                            });
                        }
                        else {
                            // Tools loaded via tool_search need a namespace field to round-trip correctly
                            const namespace = toolSearchLoadedTools.has(toolCall.function.name) ? toolCall.function.name : undefined;
                            input.push({ type: 'function_call', name: toolCall.function.name, arguments: toolCall.function.arguments, call_id: toolCall.id, ...(namespace ? { namespace } : {}) });
                        }
                    }
                }
                break;
            case prompt_tsx_1.Raw.ChatRole.Tool:
                if (message.toolCallId) {
                    if (toolSearchCallIds.has(message.toolCallId)) {
                        // Client-executed tool search result: convert tool names to tool_search_output with full definitions
                        const resultText = message.content
                            .filter(c => c.type === prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text)
                            .map(c => c.text)
                            .join('');
                        const loadedTools = toolsMap ? buildToolSearchOutputTools(resultText, toolsMap, shouldLoadToolFromToolSearch) : [];
                        for (const t of loadedTools) {
                            toolSearchLoadedTools.add(t.name);
                        }
                        input.push({
                            type: 'tool_search_output',
                            execution: 'client',
                            call_id: message.toolCallId,
                            status: 'completed',
                            tools: loadedTools,
                        });
                    }
                    else {
                        const asText = message.content
                            .filter(c => c.type === prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text)
                            .map(c => c.text)
                            .join('');
                        const asImages = message.content
                            .filter(c => c.type === prompt_tsx_1.Raw.ChatCompletionContentPartKind.Image)
                            .map((c) => ({
                            type: 'input_image',
                            detail: c.imageUrl.detail || 'auto',
                            image_url: c.imageUrl.url,
                        }));
                        // todod@connor4312: hack while responses API only supports text output from tools
                        input.push({ type: 'function_call_output', call_id: message.toolCallId, output: asText });
                        if (asImages.length) {
                            input.push({ role: 'user', content: [{ type: 'input_text', text: 'Image associated with the above tool call:' }, ...asImages] });
                        }
                    }
                }
                break;
            case prompt_tsx_1.Raw.ChatRole.User:
                input.push({ role: 'user', content: message.content.map(rawContentToResponsesContent).filter(types_1.isDefined) });
                break;
            case prompt_tsx_1.Raw.ChatRole.System:
                input.push({ role: 'system', content: message.content.map(rawContentToResponsesContent).filter(types_1.isDefined) });
                break;
        }
    }
    return { input, previous_response_id: previousResponseId };
}
/**
 * Converts a JSON array of tool names (from ToolSearchTool) into full tool definitions
 * for the tool_search_output. Falls back to an empty array on parse failure.
 */
function buildToolSearchOutputTools(resultText, toolsMap, shouldLoadToolFromToolSearch) {
    let toolNames;
    try {
        toolNames = JSON.parse(resultText);
    }
    catch {
        return [];
    }
    if (!Array.isArray(toolNames)) {
        return [];
    }
    return toolNames
        .filter((name) => typeof name === 'string' && name !== anthropic_1.CUSTOM_TOOL_SEARCH_NAME && toolsMap.has(name) && shouldLoadToolFromToolSearch?.(name) === true)
        .map(name => {
        const tool = toolsMap.get(name);
        return {
            type: 'function',
            name: tool.function.name,
            description: tool.function.description || '',
            defer_loading: true,
            parameters: tool.function.parameters || { type: 'object', properties: {} },
            strict: false,
        };
    });
}
function createCompactionRoundTripMessage(message) {
    if (message.role !== prompt_tsx_1.Raw.ChatRole.Assistant) {
        return undefined;
    }
    const content = message.content.filter(part => part.type === prompt_tsx_1.Raw.ChatCompletionContentPartKind.Opaque && (0, compactionDataContainer_1.rawPartAsCompactionData)(part));
    if (!content.length) {
        return undefined;
    }
    return {
        role: prompt_tsx_1.Raw.ChatRole.Assistant,
        content,
    };
}
function getLatestCompactionMessageIndex(messages) {
    for (let idx = messages.length - 1; idx >= 0; idx--) {
        const message = messages[idx];
        for (const part of message.content) {
            if (part.type === prompt_tsx_1.Raw.ChatCompletionContentPartKind.Opaque && (0, compactionDataContainer_1.rawPartAsCompactionData)(part)) {
                return idx;
            }
        }
    }
    return undefined;
}
function rawContentToResponsesContent(part) {
    switch (part.type) {
        case prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text:
            return { type: 'input_text', text: part.text };
        case prompt_tsx_1.Raw.ChatCompletionContentPartKind.Image:
            return { type: 'input_image', detail: part.imageUrl.detail || 'auto', image_url: part.imageUrl.url };
        case prompt_tsx_1.Raw.ChatCompletionContentPartKind.Opaque: {
            const maybeCast = part.value;
            if (maybeCast.type === 'input_text' || maybeCast.type === 'input_image' || maybeCast.type === 'input_file') {
                return maybeCast;
            }
        }
    }
}
function rawContentToResponsesAssistantContent(part) {
    switch (part.type) {
        case prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text:
            if (part.text.trim()) {
                return { type: 'output_text', text: part.text };
            }
    }
}
function extractThinkingData(content) {
    return (0, arrays_1.coalesce)(content.map(part => {
        if (part.type === prompt_tsx_1.Raw.ChatCompletionContentPartKind.Opaque) {
            const thinkingData = (0, thinkingDataContainer_1.rawPartAsThinkingData)(part);
            if (thinkingData) {
                return {
                    type: 'reasoning',
                    id: thinkingData.id,
                    summary: [],
                    encrypted_content: thinkingData.encrypted,
                };
            }
        }
    }));
}
function extractPhaseData(content) {
    for (const part of content) {
        if (part.type === prompt_tsx_1.Raw.ChatCompletionContentPartKind.Opaque) {
            const phase = (0, phaseDataContainer_1.rawPartAsPhaseData)(part);
            if (phase) {
                return phase;
            }
        }
    }
    return undefined;
}
/**
 * Extracts compaction data from opaque content parts and converts them to
 * Responses API input items for round-tripping.
 */
function extractCompactionData(content) {
    return (0, arrays_1.coalesce)(content.map(part => {
        if (part.type === prompt_tsx_1.Raw.ChatCompletionContentPartKind.Opaque) {
            const compaction = (0, compactionDataContainer_1.rawPartAsCompactionData)(part);
            if (compaction) {
                return {
                    type: openai_1.openAIContextManagementCompactionType,
                    id: compaction.id,
                    encrypted_content: compaction.encrypted_content,
                };
            }
        }
    }));
}
/**
 * This is an approximate responses input -> raw messages helper, should be used for logging only
 */
function responseApiInputToRawMessagesForLogging(body) {
    const messages = [];
    const pendingFunctionCalls = [];
    const flushPendingFunctionCalls = () => {
        if (pendingFunctionCalls.length > 0) {
            messages.push({
                role: prompt_tsx_1.Raw.ChatRole.Assistant,
                content: [],
                toolCalls: pendingFunctionCalls.splice(0)
            });
        }
    };
    // Add system instructions if provided
    if (body.instructions) {
        messages.push({
            role: prompt_tsx_1.Raw.ChatRole.System,
            content: [{ type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text, text: body.instructions }]
        });
    }
    // Convert input to array format if it's a string
    const inputItems = typeof body.input === 'string' ? [{ role: 'user', content: body.input, type: 'message' }] : (body.input ?? []);
    for (const item of inputItems) {
        // Handle message items with roles
        if ('role' in item) {
            switch (item.role) {
                case 'user':
                    flushPendingFunctionCalls();
                    messages.push({
                        role: prompt_tsx_1.Raw.ChatRole.User,
                        content: ensureContentArray(item.content).map(responseContentToRawContent).filter(types_1.isDefined)
                    });
                    break;
                case 'system':
                case 'developer':
                    flushPendingFunctionCalls();
                    messages.push({
                        role: prompt_tsx_1.Raw.ChatRole.System,
                        content: ensureContentArray(item.content).map(responseContentToRawContent).filter(types_1.isDefined)
                    });
                    break;
                case 'assistant':
                    flushPendingFunctionCalls();
                    if (isResponseOutputMessage(item)) {
                        messages.push({
                            role: prompt_tsx_1.Raw.ChatRole.Assistant,
                            content: item.content.map(responseOutputToRawContent).filter(types_1.isDefined)
                        });
                    }
                    else if (isResponseInputItemMessage(item)) {
                        messages.push({
                            role: prompt_tsx_1.Raw.ChatRole.Assistant,
                            content: ensureContentArray(item.content).map(responseContentToRawContent).filter(types_1.isDefined)
                        });
                    }
                    break;
            }
        }
        else if ('type' in item) {
            // Handle other item types without roles
            switch (item.type) {
                case 'function_call':
                    // Collect function calls to be grouped with the next assistant message
                    pendingFunctionCalls.push({
                        id: item.call_id,
                        type: 'function',
                        function: {
                            name: item.name,
                            arguments: item.arguments
                        }
                    });
                    break;
                case 'function_call_output': {
                    flushPendingFunctionCalls();
                    const content = responseFunctionOutputToRawContents(item.output);
                    messages.push({
                        role: prompt_tsx_1.Raw.ChatRole.Tool,
                        content,
                        toolCallId: item.call_id
                    });
                    break;
                }
                case 'reasoning':
                    // We can't perfectly reconstruct the original thinking data
                    // but we can add a placeholder for logging
                    flushPendingFunctionCalls();
                    messages.push({
                        role: prompt_tsx_1.Raw.ChatRole.Assistant,
                        content: [{
                                type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text,
                                text: `Reasoning summary: ${item.summary.map(s => s.text).join('\n\n')}`
                            }]
                    });
                    break;
                default: {
                    // Client-executed tool search items (tool_search_call / tool_search_output)
                    const tsItem = item;
                    if (tsItem.type === 'tool_search_call') {
                        pendingFunctionCalls.push({
                            id: tsItem.call_id,
                            type: 'function',
                            function: {
                                name: anthropic_1.CUSTOM_TOOL_SEARCH_NAME,
                                arguments: JSON.stringify(tsItem.arguments ?? {}),
                            }
                        });
                    }
                    else if (tsItem.type === 'tool_search_output') {
                        flushPendingFunctionCalls();
                        const toolNames = tsItem.tools.map(t => t.name);
                        messages.push({
                            role: prompt_tsx_1.Raw.ChatRole.Tool,
                            content: [{
                                    type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text,
                                    text: JSON.stringify(toolNames),
                                }],
                            toolCallId: tsItem.call_id,
                        });
                    }
                    break;
                }
            }
        }
    }
    // Flush any remaining function calls at the end
    if (pendingFunctionCalls.length > 0) {
        messages.push({
            role: prompt_tsx_1.Raw.ChatRole.Assistant,
            content: [],
            toolCalls: pendingFunctionCalls.splice(0)
        });
    }
    return messages;
}
function isResponseOutputMessage(item) {
    return 'role' in item && item.role === 'assistant' && 'type' in item && item.type === 'message' && 'content' in item && Array.isArray(item.content);
}
function isResponseInputItemMessage(item) {
    return 'role' in item && item.role === 'assistant' && (!('type' in item) || item.type !== 'message');
}
function ensureContentArray(content) {
    if (typeof content === 'string') {
        return [{ type: 'input_text', text: content }];
    }
    return content;
}
function responseContentToRawContent(part) {
    switch (part.type) {
        case 'input_text':
            return { type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text, text: part.text };
        case 'input_image':
            return {
                type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Image,
                imageUrl: {
                    url: part.image_url || '',
                    detail: part.detail === 'auto' ?
                        undefined :
                        (part.detail ?? undefined)
                }
            };
        case 'input_file':
            // This is a rough approximation for logging
            return {
                type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Opaque,
                value: `[File Input - Filename: ${part.filename || 'unknown'}]`
            };
    }
}
function responseOutputToRawContent(part) {
    switch (part.type) {
        case 'output_text':
            return { type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text, text: part.text };
        case 'refusal':
            return { type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text, text: `[Refusal: ${part.refusal}]` };
    }
}
function responseFunctionOutputToRawContents(output) {
    if (typeof output === 'string') {
        return [{ type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text, text: output }];
    }
    return (0, arrays_1.coalesce)(output.map(responseContentToRawContent));
}
function isCompactionItem(value) {
    return typeof value === 'object' && value !== null && 'type' in value && String(value.type) === openai_1.openAIContextManagementCompactionType;
}
function hasOutputItem(chunk) {
    return 'item' in chunk && 'output_index' in chunk && typeof chunk.output_index === 'number';
}
function hasResponseOutput(chunk) {
    return 'response' in chunk && Array.isArray(chunk.response.output);
}
function getOutputItemIndex(chunk) {
    return chunk.output_index;
}
function isCompactionOutputItem(item) {
    return isCompactionItem(item);
}
function getLatestCompactionOutput(output, preferredOutputIndex) {
    let latestCompactionOutput;
    for (let idx = output.length - 1; idx >= 0; idx--) {
        const item = output[idx];
        if (isCompactionOutputItem(item)) {
            latestCompactionOutput = { item, outputIndex: idx };
            break;
        }
    }
    if (preferredOutputIndex !== undefined) {
        const preferredItem = output[preferredOutputIndex];
        if (preferredItem && isCompactionOutputItem(preferredItem) && (!latestCompactionOutput || preferredOutputIndex >= latestCompactionOutput.outputIndex)) {
            return { item: preferredItem, outputIndex: preferredOutputIndex };
        }
    }
    return latestCompactionOutput;
}
function keepLatestCompactionOutput(output, preferredOutputIndex) {
    const latestCompactionOutput = getLatestCompactionOutput(output, preferredOutputIndex);
    if (!latestCompactionOutput) {
        return output;
    }
    return output.filter((item, idx) => !isCompactionOutputItem(item) || idx === latestCompactionOutput.outputIndex);
}
async function processResponseFromChatEndpoint(instantiationService, telemetryService, logService, response, expectedNumChoices, finishCallback, telemetryData, compactionThreshold) {
    return new async_1.AsyncIterableObject(async (feed) => {
        const requestId = response.headers.get('X-Request-ID') ?? (0, uuid_1.generateUuid)();
        const ghRequestId = response.headers.get('x-github-request-id') ?? '';
        const { serverExperiments } = (0, fetch_1.getRequestId)(response.headers);
        const processor = instantiationService.createInstance(OpenAIResponsesProcessor, telemetryData, telemetryService, requestId, ghRequestId, serverExperiments, compactionThreshold);
        const dumper = (0, responsesApiDebugDump_1.createResponsesStreamDumper)(requestId, logService);
        const parser = new sseParser_1.SSEParser((ev) => {
            try {
                logService.trace(`SSE: ${ev.data}`);
                if (ev.data === '[DONE]') {
                    // Some OpenAI-compatible gateways (e.g. LiteLLM) emit the chat-completions
                    // `[DONE]` sentinel at the end of a Responses stream. Ignore it.
                    return;
                }
                const parsedData = JSON.parse(ev.data);
                const responseStreamEvent = { type: ev.type, ...parsedData };
                dumper.logEvent(responseStreamEvent);
                const completion = processor.push(responseStreamEvent, finishCallback);
                if (completion) {
                    sendCompletionOutputTelemetry(telemetryService, logService, completion, telemetryData);
                    feed.emitOne(completion);
                }
            }
            catch (e) {
                feed.reject(e);
            }
        });
        for await (const chunk of response.body) {
            parser.feed(chunk);
        }
    }, async () => {
        await response.body.destroy();
    });
}
function sendCompletionOutputTelemetry(telemetryService, logService, completion, telemetryData) {
    const telemetryMessage = (0, openai_1.rawMessageToCAPI)(completion.message);
    let telemetryDataWithUsage = telemetryData;
    if (completion.usage) {
        telemetryDataWithUsage = telemetryData.extendedBy({}, {
            promptTokens: completion.usage.prompt_tokens,
            completionTokens: completion.usage.completion_tokens,
            totalTokens: completion.usage.total_tokens,
            ...(completion.usage.prompt_tokens_details && { cachedTokens: completion.usage.prompt_tokens_details.cached_tokens }),
            ...(completion.usage.completion_tokens_details && {
                reasoningTokens: completion.usage.completion_tokens_details.reasoning_tokens,
                acceptedPredictionTokens: completion.usage.completion_tokens_details.accepted_prediction_tokens,
                rejectedPredictionTokens: completion.usage.completion_tokens_details.rejected_prediction_tokens,
            }),
        });
    }
    (0, chatStream_1.sendEngineMessagesTelemetry)(telemetryService, [telemetryMessage], telemetryDataWithUsage, true, logService);
}
/**
 * Map CAPI's `content_filters` (sent on a terminal Responses event when a
 * response is blocked) to a {@link FilterReason}. Returns `undefined` if no
 * reason can be deduced; the caller defaults to {@link FilterReason.Copyright}.
 */
function extractFilterReasonFromContentFilters(filters) {
    if (!filters) {
        return undefined;
    }
    // Prefer a completion-side block; if none, fall back to a prompt-side block.
    const blocked = filters.filter(f => f.blocked);
    const completion = blocked.find(f => f.source_type === 'completion') ?? blocked[0];
    if (!completion) {
        return undefined;
    }
    // Look for a definitive BLOCK action in content_filter_raw. The label
    // `TextCopyright` maps to our Copyright filter; the multi-severity labels
    // map to hate/self-harm/sexual/violence.
    const blockingRule = completion.content_filter_raw?.find(r => r.action === 'BLOCK' && r.result === true);
    const label = blockingRule?.label?.toLowerCase() ?? '';
    if (label.includes('copyright')) {
        return openai_1.FilterReason.Copyright;
    }
    if (label.includes('selfharm') || label.includes('self_harm')) {
        return openai_1.FilterReason.SelfHarm;
    }
    if (label.includes('sexual')) {
        return openai_1.FilterReason.Sexual;
    }
    if (label.includes('violence')) {
        return openai_1.FilterReason.Violence;
    }
    if (label.includes('hate')) {
        return openai_1.FilterReason.Hate;
    }
    // Fall back to the Azure-spec'd per-category result map (`AzureContentFilterResultsForResponsesAPI`).
    const results = completion.content_filter_results ?? {};
    if (results.hate?.filtered) {
        return openai_1.FilterReason.Hate;
    }
    if (results.self_harm?.filtered) {
        return openai_1.FilterReason.SelfHarm;
    }
    if (results.sexual?.filtered) {
        return openai_1.FilterReason.Sexual;
    }
    if (results.violence?.filtered) {
        return openai_1.FilterReason.Violence;
    }
    if (results.protected_material_text?.filtered || results.protected_material_code?.filtered) {
        return openai_1.FilterReason.Copyright;
    }
    if (completion.source_type === 'prompt') {
        return openai_1.FilterReason.Prompt;
    }
    return undefined;
}
/**
 * Map a Responses-API `response.error` (string-coded per the OpenAI SDK) onto
 * our {@link APIErrorResponse} shape (numeric `code`). We can't preserve the
 * string code in `code`, so we stash it in `metadata.code` for BYOK diagnostics
 * (which `JSON.stringify` the whole struct).
 */
function mapResponsesApiError(err) {
    if (!err) {
        return undefined;
    }
    return {
        code: 0,
        message: err.message ?? '',
        metadata: { code: err.code },
    };
}
let OpenAIResponsesProcessor = class OpenAIResponsesProcessor {
    constructor(telemetryData, telemetryService, requestId, ghRequestId, serverExperiments, compactionThreshold, logService) {
        this.telemetryData = telemetryData;
        this.telemetryService = telemetryService;
        this.requestId = requestId;
        this.ghRequestId = ghRequestId;
        this.serverExperiments = serverExperiments;
        this.compactionThreshold = compactionThreshold;
        this.logService = logService;
        this.textAccumulator = '';
        this.hasReceivedReasoningSummary = false;
        this.sawCompactionMessage = false;
        /** Maps output_index to { name, callId, arguments } for streaming tool call updates */
        this.toolCallInfo = new Map();
    }
    getCompactionItemsInChunk(chunk) {
        const compactionItems = [];
        if (hasOutputItem(chunk) && isCompactionItem(chunk.item)) {
            const outputIndex = getOutputItemIndex(chunk);
            compactionItems.push({ item: chunk.item, outputIndex });
        }
        if (hasResponseOutput(chunk)) {
            for (let idx = 0; idx < chunk.response.output.length; idx++) {
                const item = chunk.response.output[idx];
                if (isCompactionItem(item)) {
                    compactionItems.push({ item, outputIndex: idx });
                }
            }
        }
        return compactionItems;
    }
    captureCompactionItem(item, outputIndex, onProgress) {
        if (outputIndex !== undefined && this.latestCompactionOutputIndex !== undefined && outputIndex < this.latestCompactionOutputIndex) {
            return;
        }
        const previousCompactionItem = this.latestCompactionItem;
        this.sawCompactionMessage = true;
        this.latestCompactionOutputIndex = outputIndex ?? this.latestCompactionOutputIndex;
        this.latestCompactionItem = item;
        if (previousCompactionItem?.id === item.id && previousCompactionItem.encrypted_content === item.encrypted_content) {
            return;
        }
        onProgress({
            text: '',
            contextManagement: {
                type: openai_1.openAIContextManagementCompactionType,
                id: item.id,
                encrypted_content: item.encrypted_content,
            }
        });
    }
    push(chunk, _onProgress) {
        const onProgress = (delta) => {
            this.textAccumulator += delta.text;
            _onProgress(this.textAccumulator, 0, delta);
        };
        const compactionItems = this.getCompactionItemsInChunk(chunk);
        if (chunk.type !== 'response.completed') {
            for (const { item, outputIndex } of compactionItems) {
                this.captureCompactionItem(item, outputIndex, onProgress);
            }
        }
        switch (chunk.type) {
            case 'error':
                return onProgress({ text: '', copilotErrors: [{ agent: 'openai', code: chunk.code || 'unknown', message: chunk.message, type: 'error', identifier: chunk.param || undefined }] });
            case 'response.output_text.delta': {
                const capiChunk = chunk;
                // When text arrives from a new output item, emit a paragraph
                // separator so that e.g. commentary and final text don't fuse.
                if (this.lastTextDeltaOutputIndex !== undefined && capiChunk.output_index !== this.lastTextDeltaOutputIndex) {
                    onProgress({ text: '\n\n' });
                }
                this.lastTextDeltaOutputIndex = capiChunk.output_index;
                const haystack = new lazy_1.Lazy(() => new TextEncoder().encode(capiChunk.delta));
                return onProgress({
                    text: capiChunk.delta,
                    logprobs: capiChunk.logprobs && {
                        content: capiChunk.logprobs.map(lp => ({
                            ...mapLogProp(haystack, lp),
                            top_logprobs: lp.top_logprobs?.map(l => mapLogProp(haystack, l)) || []
                        }))
                    },
                });
            }
            case 'response.output_item.added':
                if (chunk.item.type === 'function_call') {
                    this.toolCallInfo.set(chunk.output_index, { name: chunk.item.name, callId: chunk.item.call_id, arguments: '' });
                    onProgress({
                        text: '',
                        beginToolCalls: [{ name: chunk.item.name, id: chunk.item.call_id }]
                    });
                }
                else if (chunk.item.type.toString() === 'tool_search_call') {
                    const tsItem = chunk.item;
                    if (tsItem.execution === 'client' && tsItem.call_id) {
                        // Client-executed tool search: treat as a regular tool call so our ToolSearchTool handles it.
                        this.toolCallInfo.set(chunk.output_index, { name: anthropic_1.CUSTOM_TOOL_SEARCH_NAME, callId: tsItem.call_id, arguments: '' });
                        onProgress({
                            text: '',
                            beginToolCalls: [{ name: anthropic_1.CUSTOM_TOOL_SEARCH_NAME, id: tsItem.call_id }]
                        });
                    }
                }
                return;
            case 'response.function_call_arguments.delta': {
                const info = this.toolCallInfo.get(chunk.output_index);
                if (info) {
                    info.arguments += chunk.delta;
                    onProgress({
                        text: '',
                        copilotToolCallStreamUpdates: [{
                                id: info.callId,
                                name: info.name,
                                arguments: info.arguments,
                            }],
                    });
                }
                return;
            }
            case 'response.output_item.done':
                if (chunk.item.type === 'function_call') {
                    this.toolCallInfo.delete(chunk.output_index);
                    onProgress({
                        text: '',
                        copilotToolCalls: [{
                                id: chunk.item.call_id,
                                name: chunk.item.name,
                                arguments: chunk.item.arguments,
                            }],
                        phase: chunk.item.phase
                    });
                }
                else if (chunk.item.type.toString() === 'tool_search_call') {
                    const tsCall = chunk.item;
                    if (tsCall.execution === 'client' && tsCall.call_id) {
                        // Client-executed tool search completed: emit as a completed copilotToolCall
                        this.toolCallInfo.delete(chunk.output_index);
                        onProgress({
                            text: '',
                            copilotToolCalls: [{
                                    id: tsCall.call_id,
                                    name: anthropic_1.CUSTOM_TOOL_SEARCH_NAME,
                                    arguments: JSON.stringify(tsCall.arguments ?? {}),
                                }],
                        });
                    }
                }
                else if (chunk.item.type === 'reasoning') {
                    onProgress({
                        text: '',
                        thinking: chunk.item.encrypted_content ? {
                            id: chunk.item.id,
                            // CAPI models don't stream the reasoning summary for some reason, byok do, so don't duplicate it
                            text: this.hasReceivedReasoningSummary ?
                                undefined :
                                chunk.item.summary.map(s => s.text),
                            encrypted: chunk.item.encrypted_content,
                        } : undefined
                    });
                }
                else if (chunk.item.type === 'message') {
                    onProgress({
                        text: '',
                        phase: chunk.item.phase
                    });
                }
                return;
            case 'response.reasoning_summary_text.delta':
                this.hasReceivedReasoningSummary = true;
                return onProgress({
                    text: '',
                    thinking: {
                        id: chunk.item_id,
                        text: chunk.delta,
                    }
                });
            case 'response.reasoning_summary_part.done':
                this.hasReceivedReasoningSummary = true;
                return onProgress({
                    text: '',
                    thinking: {
                        id: chunk.item_id
                    }
                });
            case 'response.completed': {
                const capiChunk = chunk;
                const normalizedOutput = keepLatestCompactionOutput(capiChunk.response.output, this.latestCompactionOutputIndex);
                const latestCompactionOutput = getLatestCompactionOutput(normalizedOutput, this.latestCompactionOutputIndex);
                const latestCompactionItem = latestCompactionOutput?.item;
                const previousCompactionItem = this.latestCompactionItem;
                if (latestCompactionItem) {
                    this.sawCompactionMessage = true;
                    this.latestCompactionOutputIndex = latestCompactionOutput.outputIndex;
                }
                const shouldEmitResolvedCompaction = latestCompactionItem && (!previousCompactionItem ||
                    previousCompactionItem.id !== latestCompactionItem.id ||
                    previousCompactionItem.encrypted_content !== latestCompactionItem.encrypted_content);
                if (latestCompactionItem) {
                    this.latestCompactionItem = latestCompactionItem;
                }
                if (this.compactionThreshold !== undefined && this.sawCompactionMessage) {
                    const promptTokens = chunk.response.usage?.input_tokens ?? 0;
                    const totalTokens = chunk.response.usage?.total_tokens ?? 0;
                    (0, chatStream_1.sendResponsesApiCompactionTelemetry)(this.telemetryService, {
                        outcome: 'compaction_returned',
                        headerRequestId: this.requestId,
                        gitHubRequestId: this.ghRequestId,
                        model: chunk.response.model,
                    }, {
                        compactThreshold: this.compactionThreshold,
                        promptTokens,
                        totalTokens,
                    });
                    this.logService.debug(`[responsesAPI_compaction] Compaction enabled. headerRequestId=${this.requestId}`);
                }
                else if (this.compactionThreshold !== undefined && (chunk.response.usage?.input_tokens ?? 0) >= this.compactionThreshold) {
                    const promptTokens = chunk.response.usage?.input_tokens ?? 0;
                    const totalTokens = chunk.response.usage?.total_tokens ?? 0;
                    (0, chatStream_1.sendResponsesApiCompactionTelemetry)(this.telemetryService, {
                        outcome: 'threshold_met_no_compaction',
                        headerRequestId: this.requestId,
                        gitHubRequestId: this.ghRequestId,
                        model: chunk.response.model,
                    }, {
                        compactThreshold: this.compactionThreshold,
                        promptTokens,
                        totalTokens,
                    });
                    this.logService.debug(`[responsesAPI_compaction] Compaction enabled but context not compacted after threshold was met. headerRequestId=${this.requestId}, gitHubRequestId=${this.ghRequestId}, promptTokens=${promptTokens}, totalTokens=${totalTokens}`);
                }
                onProgress({
                    text: '',
                    statefulMarker: chunk.response.id,
                    contextManagement: shouldEmitResolvedCompaction ? latestCompactionItem : undefined,
                });
                return {
                    blockFinished: true,
                    choiceIndex: 0,
                    model: chunk.response.model,
                    tokens: [],
                    telemetryData: this.telemetryData,
                    requestId: { headerRequestId: this.requestId, gitHubRequestId: this.ghRequestId, completionId: chunk.response.id, created: chunk.response.created_at, deploymentId: '', serverExperiments: this.serverExperiments },
                    usage: {
                        prompt_tokens: chunk.response.usage?.input_tokens ?? 0,
                        completion_tokens: chunk.response.usage?.output_tokens ?? 0,
                        total_tokens: chunk.response.usage?.total_tokens ?? 0,
                        prompt_tokens_details: {
                            cached_tokens: chunk.response.usage?.input_tokens_details?.cached_tokens ?? 0,
                        },
                        completion_tokens_details: {
                            reasoning_tokens: chunk.response.usage?.output_tokens_details?.reasoning_tokens ?? 0,
                            accepted_prediction_tokens: 0,
                            rejected_prediction_tokens: 0,
                        },
                        copilot_usage: capiChunk.copilot_usage?.total_nano_aiu !== undefined ? capiChunk.copilot_usage : undefined,
                    },
                    finishReason: openai_1.FinishedCompletionReason.Stop,
                    message: {
                        role: prompt_tsx_1.Raw.ChatRole.Assistant,
                        content: normalizedOutput.map((item) => {
                            if (item.type === 'message') {
                                return { type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text, text: item.content.map(c => c.type === 'output_text' ? c.text : c.refusal).join('') };
                            }
                            else if (item.type === 'image_generation_call' && item.result) {
                                return { type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Image, imageUrl: { url: item.result } };
                            }
                        }).filter(types_1.isDefined),
                    }
                };
            }
            case 'response.incomplete': {
                const incomplete = chunk.response;
                const reason = incomplete.incomplete_details?.reason;
                let finishReason;
                let filterReason;
                if (reason === 'max_output_tokens') {
                    finishReason = openai_1.FinishedCompletionReason.Length;
                }
                else if (reason === 'content_filter') {
                    finishReason = openai_1.FinishedCompletionReason.ContentFilter;
                    filterReason = extractFilterReasonFromContentFilters(incomplete.content_filters);
                }
                else {
                    // Unknown incomplete reason — treat as a server-side stream termination so the
                    // caller surfaces a "request failed" message instead of the generic flake.
                    finishReason = openai_1.FinishedCompletionReason.ServerError;
                }
                return this.buildTerminalCompletion(incomplete, finishReason, {
                    filterReason,
                    error: mapResponsesApiError(incomplete.error),
                });
            }
            case 'response.failed': {
                const failed = chunk.response;
                return this.buildTerminalCompletion(failed, openai_1.FinishedCompletionReason.ServerError, {
                    error: mapResponsesApiError(failed.error),
                });
            }
        }
    }
    /**
     * Build a {@link ChatCompletion} for a terminal Responses API event other than
     * `response.completed` (i.e. `response.incomplete` or `response.failed`). The
     * resulting completion is fed into the same downstream switch as a normal
     * completion so callers can map it to the appropriate user-facing error.
     */
    buildTerminalCompletion(response, finishReason, opts = {}) {
        const output = response.output ?? [];
        return {
            blockFinished: true,
            choiceIndex: 0,
            model: response.model,
            tokens: [],
            telemetryData: this.telemetryData,
            requestId: {
                headerRequestId: this.requestId,
                gitHubRequestId: this.ghRequestId,
                completionId: response.id,
                created: response.created_at,
                deploymentId: '',
                serverExperiments: this.serverExperiments,
            },
            usage: response.usage ? {
                prompt_tokens: response.usage.input_tokens ?? 0,
                completion_tokens: response.usage.output_tokens ?? 0,
                total_tokens: response.usage.total_tokens ?? 0,
                prompt_tokens_details: {
                    cached_tokens: response.usage.input_tokens_details?.cached_tokens ?? 0,
                },
                completion_tokens_details: {
                    reasoning_tokens: response.usage.output_tokens_details?.reasoning_tokens ?? 0,
                    accepted_prediction_tokens: 0,
                    rejected_prediction_tokens: 0,
                },
            } : undefined,
            finishReason,
            filterReason: opts.filterReason,
            error: opts.error,
            message: {
                role: prompt_tsx_1.Raw.ChatRole.Assistant,
                content: output.map((item) => {
                    if (item.type === 'message') {
                        return { type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Text, text: item.content.map(c => c.type === 'output_text' ? c.text : c.refusal).join('') };
                    }
                    else if (item.type === 'image_generation_call' && item.result) {
                        return { type: prompt_tsx_1.Raw.ChatCompletionContentPartKind.Image, imageUrl: { url: item.result } };
                    }
                }).filter(types_1.isDefined),
            },
        };
    }
};
exports.OpenAIResponsesProcessor = OpenAIResponsesProcessor;
exports.OpenAIResponsesProcessor = OpenAIResponsesProcessor = __decorate([
    __param(6, logService_1.ILogService)
], OpenAIResponsesProcessor);
function mapLogProp(text, lp) {
    let bytes = [];
    if (lp.token) {
        const needle = new TextEncoder().encode(lp.token);
        const haystack = text.value;
        const idx = (0, buffer_1.binaryIndexOf)(haystack, needle);
        if (idx !== -1) {
            bytes = [idx, idx + needle.length];
        }
    }
    return {
        token: lp.token,
        bytes,
        logprob: lp.logprob,
    };
}
//# sourceMappingURL=responsesApi.js.map