import { validateToolCall } from '../../../tools/tool-registry.js';
import { encoding_for_model, get_encoding } from 'tiktoken';
import { normalizeFunctionCallId } from '../../bridge-id-utils.js';
const DEFAULT_OPTIONS = {
    strictToolRequired: true,
    textNormalizer: undefined,
    toolProtocol: undefined
};
const SHELL_LIKE_TOOL_NAMES = new Set(['exec_command', 'shell_command', 'shell', 'bash', 'terminal']);
const SHELL_TOOL_NAME_ALIASES = new Map([
    ['shell_command', 'exec_command'],
    ['shell', 'exec_command'],
    ['bash', 'exec_command'],
    ['terminal', 'exec_command']
]);
const SHELL_ALLOWED_TOOL_CANDIDATES = [
    'exec_command',
    'shell_command',
    'bash',
    'shell',
    'terminal'
];
const DEFAULT_TOKEN_ENCODING = 'cl100k_base';
const tokenEncoderCache = new Map();
let defaultTokenEncoder = null;
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
const readString = (value) => {
    if (typeof value !== 'string') {
        return undefined;
    }
    const trimmed = value.trim();
    return trimmed.length ? trimmed : undefined;
};
function flattenMessageContent(content) {
    if (typeof content === 'string') {
        return content.trim();
    }
    if (Array.isArray(content)) {
        const parts = [];
        for (const part of content) {
            if (!isRecord(part)) {
                continue;
            }
            const text = readString(part.text) ?? readString(part.content) ?? readString(part.value);
            if (text) {
                parts.push(text);
            }
        }
        return parts.join('\n').trim();
    }
    if (isRecord(content)) {
        const direct = readString(content.text) ?? readString(content.content);
        if (direct) {
            return direct;
        }
        if (Array.isArray(content.content)) {
            return flattenMessageContent(content.content);
        }
    }
    return '';
}
function extractResponsesMessageText(item) {
    const parts = [];
    const content = Array.isArray(item.content) ? item.content : [];
    for (const part of content) {
        if (!isRecord(part)) {
            continue;
        }
        const text = readString(part.text) ?? readString(part.content) ?? readString(part.value);
        if (text) {
            parts.push(text);
        }
    }
    const outputText = readString(item.output_text);
    if (outputText) {
        parts.push(outputText);
    }
    return parts.join('\n').trim();
}
function readNumber(value) {
    if (typeof value === 'number' && Number.isFinite(value)) {
        return value;
    }
    if (typeof value === 'string') {
        const trimmed = value.trim();
        if (!trimmed.length) {
            return undefined;
        }
        const parsed = Number(trimmed);
        if (Number.isFinite(parsed)) {
            return parsed;
        }
    }
    return undefined;
}
function readBoolean(input, fallback) {
    if (typeof input === 'boolean') {
        return input;
    }
    if (typeof input === 'string') {
        const normalized = input.trim().toLowerCase();
        if (['true', '1', 'yes', 'on'].includes(normalized)) {
            return true;
        }
        if (['false', '0', 'no', 'off'].includes(normalized)) {
            return false;
        }
    }
    return fallback;
}
function readOptionalBoolean(input) {
    if (typeof input === 'boolean') {
        return input;
    }
    if (typeof input === 'string') {
        const normalized = input.trim().toLowerCase();
        if (['true', '1', 'yes', 'on'].includes(normalized)) {
            return true;
        }
        if (['false', '0', 'no', 'off'].includes(normalized)) {
            return false;
        }
    }
    return undefined;
}
function readToolProtocol(input) {
    if (typeof input !== 'string') {
        return undefined;
    }
    const normalized = input.trim().toLowerCase();
    if (normalized === 'text' || normalized === 'native') {
        return normalized;
    }
    return undefined;
}
function getTokenEncoder(modelHint) {
    const normalized = typeof modelHint === 'string' ? modelHint.trim() : '';
    if (normalized) {
        const cached = tokenEncoderCache.get(normalized);
        if (cached) {
            return cached;
        }
        try {
            const encoder = encoding_for_model(normalized);
            tokenEncoderCache.set(normalized, encoder);
            return encoder;
        }
        catch {
            // fall through to default encoder
        }
    }
    if (!defaultTokenEncoder) {
        defaultTokenEncoder = get_encoding(DEFAULT_TOKEN_ENCODING);
    }
    return defaultTokenEncoder;
}
function countTextTokens(text, modelHint) {
    const trimmed = text.trim();
    if (!trimmed.length) {
        return 0;
    }
    try {
        return getTokenEncoder(modelHint).encode(trimmed).length;
    }
    catch {
        return 0;
    }
}
function resolveOptions(adapterContext, config) {
    const context = (adapterContext ?? {});
    const deepseekNode = isRecord(context.deepseek)
        ? context.deepseek
        : isRecord(context.__rt) && isRecord(context.__rt.deepseek)
            ? context.__rt.deepseek
            : undefined;
    if (!deepseekNode) {
        const toolProtocolOverride = readToolProtocol(config?.toolProtocol);
        return {
            ...DEFAULT_OPTIONS,
            strictToolRequired: readOptionalBoolean(config?.strictToolRequired) ?? DEFAULT_OPTIONS.strictToolRequired,
            textNormalizer: config?.textNormalizer,
            toolProtocol: toolProtocolOverride ?? DEFAULT_OPTIONS.toolProtocol
        };
    }
    const strictOverride = readOptionalBoolean(config?.strictToolRequired);
    const toolProtocolOverride = readToolProtocol(config?.toolProtocol);
    const legacyFallback = readOptionalBoolean(deepseekNode.textToolFallback);
    const toolProtocol = toolProtocolOverride ??
        readToolProtocol(deepseekNode.toolProtocol) ??
        (legacyFallback !== undefined ? (legacyFallback ? 'text' : 'native') : undefined);
    return {
        strictToolRequired: strictOverride ??
            readBoolean(deepseekNode.strictToolRequired, DEFAULT_OPTIONS.strictToolRequired),
        textNormalizer: config?.textNormalizer && typeof config.textNormalizer === 'object'
            ? config.textNormalizer
            : undefined,
        toolProtocol
    };
}
function resolveCapturedRequest(adapterContext) {
    const context = (adapterContext ?? {});
    if (isRecord(context.capturedChatRequest)) {
        return context.capturedChatRequest;
    }
    return undefined;
}
function resolveEstimatedInputTokens(adapterContext) {
    const context = (adapterContext ?? {});
    const candidates = [
        context.estimatedInputTokens,
        context.estimated_tokens,
        context.estimatedTokens
    ];
    for (const candidate of candidates) {
        const value = readNumber(candidate);
        if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
            return Math.max(1, Math.round(value));
        }
    }
    return undefined;
}
function resolveModelHint(root, captured, adapterContext) {
    return (readString(root.model) ??
        readString(captured?.model) ??
        readString(adapterContext?.modelId) ??
        readString(adapterContext?.clientModelId) ??
        readString(adapterContext?.originalModelId));
}
function looksLikeKnownProviderResponseShape(value) {
    if (!isRecord(value))
        return false;
    if (Array.isArray(value.choices))
        return true;
    if (Array.isArray(value.output) || value.object === 'response')
        return true;
    if (typeof value.type === 'string' && String(value.type).toLowerCase() === 'message' && Array.isArray(value.content)) {
        return true;
    }
    if (Array.isArray(value.candidates))
        return true;
    return false;
}
function tryUnwrapKnownShape(value, depth) {
    if (depth < 0) {
        return null;
    }
    if (looksLikeKnownProviderResponseShape(value)) {
        return value;
    }
    if (!isRecord(value)) {
        return null;
    }
    for (const key of ['data', 'body', 'response', 'payload', 'result', 'biz_data']) {
        const nested = value[key];
        const unwrapped = tryUnwrapKnownShape(nested, depth - 1);
        if (unwrapped) {
            return unwrapped;
        }
    }
    return null;
}
function isLikelyRateLimitMessage(message) {
    return /(rate.?limit|quota|too many|exceed|exceeded|limit reached|message count)/i.test(message);
}
function throwDeepSeekBusinessEnvelopeError(root, adapterContext) {
    const dataNode = isRecord(root.data) ? root.data : undefined;
    const upstreamCode = readNumber(root.code);
    const bizCode = readNumber(dataNode?.biz_code);
    const bizMsg = readString(dataNode?.biz_msg);
    const topMsg = readString(root.msg);
    const message = bizMsg ?? topMsg ?? 'DeepSeek returned a non-chat business envelope';
    const error = new Error(`[deepseek-web] upstream business error: ${message}`);
    error.code = 'DEEPSEEK_BIZ_ERROR';
    if ((typeof bizCode === 'number' && bizCode === 3) || isLikelyRateLimitMessage(message)) {
        error.statusCode = 429;
    }
    error.details = {
        requestId: readString(root.request_id) ??
            readString(adapterContext?.requestId),
        upstreamCode,
        bizCode,
        bizMsg,
        upstreamMsg: topMsg,
        payloadKeys: Object.keys(root).slice(0, 20),
        phase: 'chat_process.resp.stage3.compat'
    };
    throw error;
}
function normalizeDeepSeekBusinessEnvelope(root, adapterContext) {
    if (looksLikeKnownProviderResponseShape(root)) {
        return root;
    }
    const hasEnvelopeKeys = Object.prototype.hasOwnProperty.call(root, 'code')
        && Object.prototype.hasOwnProperty.call(root, 'data');
    if (!hasEnvelopeKeys) {
        return root;
    }
    const unwrapped = tryUnwrapKnownShape(root.data, 6);
    if (unwrapped) {
        return unwrapped;
    }
    const dataNode = isRecord(root.data) ? root.data : undefined;
    const upstreamCode = readNumber(root.code);
    const bizCode = readNumber(dataNode?.biz_code);
    const bizMsg = readString(dataNode?.biz_msg);
    const topMsg = readString(root.msg);
    if ((typeof upstreamCode === 'number' && upstreamCode !== 0) ||
        (typeof bizCode === 'number' && bizCode !== 0) ||
        Boolean(bizMsg) ||
        Boolean(topMsg)) {
        throwDeepSeekBusinessEnvelopeError(root, adapterContext);
    }
    return root;
}
function resolveRequestedToolNames(captured) {
    const names = new Set();
    if (!captured) {
        return names;
    }
    const toolsRaw = Array.isArray(captured.tools) ? captured.tools : [];
    for (const tool of toolsRaw) {
        if (!isRecord(tool)) {
            continue;
        }
        const fnNode = isRecord(tool.function) ? tool.function : undefined;
        const name = readString(fnNode?.name) ?? readString(tool.name);
        if (name) {
            names.add(name);
        }
    }
    const toolChoice = captured.tool_choice;
    if (isRecord(toolChoice)) {
        const type = readString(toolChoice.type)?.toLowerCase();
        if (type === 'function') {
            const fnNode = isRecord(toolChoice.function)
                ? toolChoice.function
                : undefined;
            const forcedName = readString(fnNode?.name) ?? readString(toolChoice.name);
            if (forcedName) {
                names.add(forcedName);
            }
        }
    }
    return names;
}
function isToolChoiceRequired(captured) {
    if (!captured) {
        return false;
    }
    const toolChoice = captured.tool_choice;
    if (typeof toolChoice === 'string') {
        const normalized = toolChoice.trim().toLowerCase();
        if (normalized === 'required') {
            return true;
        }
        if (normalized === 'none' || normalized === 'auto') {
            return false;
        }
    }
    if (isRecord(toolChoice)) {
        const type = readString(toolChoice.type)?.toLowerCase();
        if (type === 'function') {
            return true;
        }
    }
    return false;
}
function tryParseJsonText(value) {
    try {
        return JSON.parse(value);
    }
    catch {
        // Best-effort repair: some upstream payloads place raw newlines/tabs inside JSON strings.
        let out = '';
        let changed = false;
        let inString = false;
        let escaped = false;
        for (let i = 0; i < value.length; i += 1) {
            const ch = value[i] ?? '';
            if (inString) {
                if (escaped) {
                    out += ch;
                    escaped = false;
                    continue;
                }
                if (ch === '\\') {
                    out += ch;
                    escaped = true;
                    continue;
                }
                if (ch === '"') {
                    out += ch;
                    inString = false;
                    continue;
                }
                if (ch === '\n') {
                    out += '\\n';
                    changed = true;
                    continue;
                }
                if (ch === '\r') {
                    out += '\\n';
                    changed = true;
                    continue;
                }
                if (ch === '\t') {
                    out += '\\t';
                    changed = true;
                    continue;
                }
                const code = ch.charCodeAt(0);
                if (code >= 0 && code < 0x20) {
                    out += `\\u${code.toString(16).padStart(4, '0')}`;
                    changed = true;
                    continue;
                }
                out += ch;
                continue;
            }
            if (ch === '"') {
                inString = true;
            }
            out += ch;
        }
        if (!changed) {
            return null;
        }
        try {
            return JSON.parse(out);
        }
        catch {
            return null;
        }
    }
}
function normalizeToolArguments(value, toolName) {
    if (typeof value === 'string') {
        const trimmed = value.trim();
        if (!trimmed.length) {
            return JSON.stringify({});
        }
        const parsed = tryParseJsonText(trimmed);
        if (parsed !== null) {
            return JSON.stringify(parsed);
        }
        if (toolName) {
            const validation = validateToolCall(toolName, trimmed);
            if (validation.ok && typeof validation.normalizedArgs === 'string' && validation.normalizedArgs.trim().length > 0) {
                return validation.normalizedArgs;
            }
        }
        return null;
    }
    if (value === undefined || value === null) {
        const empty = JSON.stringify({});
        if (!toolName) {
            return empty;
        }
        const validation = validateToolCall(toolName, empty);
        if (validation.ok && typeof validation.normalizedArgs === 'string' && validation.normalizedArgs.trim().length > 0) {
            return validation.normalizedArgs;
        }
        return empty;
    }
    try {
        const serialized = JSON.stringify(value);
        if (!toolName) {
            return serialized;
        }
        const validation = validateToolCall(toolName, serialized);
        if (validation.ok && typeof validation.normalizedArgs === 'string' && validation.normalizedArgs.trim().length > 0) {
            return validation.normalizedArgs;
        }
        return serialized;
    }
    catch {
        return null;
    }
}
function hasAllowedToolName(allowed, candidate) {
    if (allowed.has(candidate)) {
        return true;
    }
    const lowered = candidate.toLowerCase();
    for (const name of allowed) {
        if (name.toLowerCase() === lowered) {
            return true;
        }
    }
    return false;
}
function findAllowedToolNameCaseInsensitive(allowed, candidate) {
    if (allowed.has(candidate)) {
        return candidate;
    }
    const lowered = candidate.toLowerCase();
    for (const name of allowed) {
        if (name.toLowerCase() === lowered) {
            return name;
        }
    }
    return undefined;
}
function resolveAllowedShellToolName(allowedToolNames) {
    for (const candidate of SHELL_ALLOWED_TOOL_CANDIDATES) {
        const resolved = findAllowedToolNameCaseInsensitive(allowedToolNames, candidate);
        if (resolved) {
            return resolved;
        }
    }
    return undefined;
}
function resolveToolNameForCompat(rawName, allowedToolNames) {
    const normalizedRawName = rawName.toLowerCase();
    const alias = SHELL_TOOL_NAME_ALIASES.get(normalizedRawName);
    const shellLike = SHELL_LIKE_TOOL_NAMES.has(normalizedRawName) || alias === 'exec_command';
    if (allowedToolNames.size > 0 && shellLike) {
        const allowedShell = resolveAllowedShellToolName(allowedToolNames);
        if (allowedShell) {
            return allowedShell;
        }
    }
    if (!alias) {
        return findAllowedToolNameCaseInsensitive(allowedToolNames, rawName) ?? rawName;
    }
    if (allowedToolNames.size === 0) {
        return alias;
    }
    const allowedAlias = findAllowedToolNameCaseInsensitive(allowedToolNames, alias);
    if (allowedAlias) {
        return allowedAlias;
    }
    const allowedRaw = findAllowedToolNameCaseInsensitive(allowedToolNames, rawName);
    if (allowedRaw) {
        return allowedRaw;
    }
    return alias;
}
function readCommandFromShellArgs(args) {
    const input = isRecord(args.input) ? args.input : undefined;
    const direct = readString(args.cmd) ??
        readString(args.command) ??
        readString(args.script) ??
        (() => {
            const arr = Array.isArray(args.command) ? args.command : Array.isArray(args.cmd) ? args.cmd : undefined;
            if (!arr)
                return undefined;
            const tokens = arr.map((item) => (item == null ? '' : String(item).trim())).filter((item) => item.length > 0);
            return tokens.length ? tokens.join(' ') : undefined;
        })();
    if (direct) {
        return direct;
    }
    if (!input) {
        return undefined;
    }
    return (readString(input.cmd) ??
        readString(input.command) ??
        readString(input.script) ??
        (() => {
            const arr = Array.isArray(input.command) ? input.command : Array.isArray(input.cmd) ? input.cmd : undefined;
            if (!arr)
                return undefined;
            const tokens = arr.map((item) => (item == null ? '' : String(item).trim())).filter((item) => item.length > 0);
            return tokens.length ? tokens.join(' ') : undefined;
        })());
}
function readWorkdirFromShellArgs(args) {
    const input = isRecord(args.input) ? args.input : undefined;
    return (readString(args.workdir) ??
        readString(args.cwd) ??
        readString(args.workDir) ??
        readString(input?.workdir) ??
        readString(input?.cwd));
}
function normalizeShellLikeArguments(argsString, argsSource) {
    const parsed = tryParseJsonText(argsString);
    const args = isRecord(parsed) ? { ...parsed } : isRecord(argsSource) ? { ...argsSource } : {};
    const cmd = readCommandFromShellArgs(args);
    if (!cmd) {
        return argsString;
    }
    const workdir = readWorkdirFromShellArgs(args);
    const next = {
        ...args,
        cmd,
        command: cmd
    };
    if (workdir) {
        next.workdir = workdir;
    }
    if (Object.prototype.hasOwnProperty.call(next, 'toon')) {
        delete next.toon;
    }
    try {
        return JSON.stringify(next);
    }
    catch {
        return JSON.stringify({ cmd, command: cmd, ...(workdir ? { workdir } : {}) });
    }
}
function coerceToolCallsValue(toolCallsRaw) {
    if (Array.isArray(toolCallsRaw)) {
        return toolCallsRaw;
    }
    if (typeof toolCallsRaw !== 'string') {
        return [];
    }
    const parsed = tryParseJsonText(toolCallsRaw.trim());
    if (Array.isArray(parsed)) {
        return parsed;
    }
    if (isRecord(parsed) && Array.isArray(parsed.tool_calls)) {
        return parsed.tool_calls;
    }
    return [];
}
function normalizeToolCallEntry(entry, allowedToolNames, callIdPrefix, index) {
    const fn = isRecord(entry.function) ? entry.function : undefined;
    const rawName = readString(entry.name) ?? readString(fn?.name);
    if (!rawName) {
        return null;
    }
    const name = resolveToolNameForCompat(rawName, allowedToolNames);
    const argsSource = entry.input !== undefined
        ? entry.input
        : entry.arguments !== undefined
            ? entry.arguments
            : fn?.arguments;
    const normalizedArgs = normalizeToolArguments(argsSource, name);
    if (!normalizedArgs) {
        return null;
    }
    const finalArgs = SHELL_LIKE_TOOL_NAMES.has(name.toLowerCase())
        ? normalizeShellLikeArguments(normalizedArgs, argsSource)
        : normalizedArgs;
    const id = readString(entry.id) ??
        readString(entry.call_id) ??
        `${callIdPrefix}_${index + 1}`;
    return {
        id,
        type: 'function',
        function: {
            name,
            arguments: finalArgs
        }
    };
}
function normalizeToolCalls(toolCallsRaw, allowedToolNames, callIdPrefix) {
    const toolCalls = coerceToolCallsValue(toolCallsRaw);
    const normalized = [];
    for (const [index, entry] of toolCalls.entries()) {
        if (!isRecord(entry)) {
            continue;
        }
        const call = normalizeToolCallEntry(entry, allowedToolNames, callIdPrefix, index);
        if (call) {
            normalized.push(call);
        }
    }
    return normalized;
}
function normalizeMessageToolCalls(message, allowedToolNames, callIdPrefix) {
    const nextCalls = normalizeToolCalls(message.tool_calls, allowedToolNames, callIdPrefix);
    if (!nextCalls.length) {
        delete message.tool_calls;
        return false;
    }
    message.tool_calls = nextCalls;
    message.content = null;
    return true;
}
function normalizeUsageSnapshot(raw) {
    if (!isRecord(raw)) {
        return {};
    }
    const prompt = readNumber(raw.prompt_tokens) ?? readNumber(raw.input_tokens);
    const completion = readNumber(raw.completion_tokens) ?? readNumber(raw.output_tokens);
    const total = readNumber(raw.total_tokens);
    return {
        ...(typeof prompt === 'number' ? { prompt: Math.max(0, Math.round(prompt)) } : {}),
        ...(typeof completion === 'number' ? { completion: Math.max(0, Math.round(completion)) } : {}),
        ...(typeof total === 'number' ? { total: Math.max(0, Math.round(total)) } : {})
    };
}
function estimateCompletionTokensFromChoices(choices, modelHint) {
    const segments = [];
    for (const choice of choices) {
        if (!isRecord(choice)) {
            continue;
        }
        const message = isRecord(choice.message) ? choice.message : undefined;
        if (!message) {
            continue;
        }
        const content = message.content;
        if (typeof content === 'string' && content.trim().length) {
            segments.push(content);
        }
        else if (Array.isArray(content)) {
            for (const part of content) {
                if (!isRecord(part)) {
                    continue;
                }
                const text = readString(part.text);
                if (text) {
                    segments.push(text);
                }
            }
        }
        if (Array.isArray(message.tool_calls) && message.tool_calls.length) {
            try {
                segments.push(JSON.stringify(message.tool_calls));
            }
            catch {
                // ignore serialization failure
            }
        }
    }
    if (!segments.length) {
        return 0;
    }
    const joined = segments.join('\n');
    return countTextTokens(joined, modelHint);
}
function applyUsageEstimate(root, choices, adapterContext, captured) {
    const current = normalizeUsageSnapshot(root.usage);
    const prompt = current.prompt ?? resolveEstimatedInputTokens(adapterContext);
    const completion = current.completion ??
        estimateCompletionTokensFromChoices(choices, resolveModelHint(root, captured, adapterContext));
    const total = current.total ??
        (typeof prompt === 'number' && typeof completion === 'number' ? prompt + completion : undefined);
    if (typeof prompt !== 'number' &&
        typeof completion !== 'number' &&
        typeof total !== 'number') {
        return;
    }
    const usage = isRecord(root.usage) ? { ...root.usage } : {};
    if (typeof prompt === 'number') {
        usage.prompt_tokens = prompt;
        usage.input_tokens = prompt;
    }
    if (typeof completion === 'number') {
        usage.completion_tokens = completion;
        usage.output_tokens = completion;
    }
    if (typeof total === 'number') {
        usage.total_tokens = total;
    }
    root.usage = usage;
}
function normalizeChoice(choice, options, allowedToolNames, callIdPrefix) {
    const message = isRecord(choice.message) ? choice.message : undefined;
    if (!message) {
        return { hasNative: false, hasText: false, harvestedFunctionResults: false };
    }
    const native = normalizeMessageToolCalls(message, allowedToolNames, callIdPrefix);
    if (native) {
        const finish = readString(choice.finish_reason)?.toLowerCase();
        if (!finish || finish === 'stop') {
            choice.finish_reason = 'tool_calls';
        }
        return { hasNative: true, hasText: false, harvestedFunctionResults: false };
    }
    if (options.toolProtocol === 'text') {
        const contentText = flattenMessageContent(message.content);
        if (contentText && (contentText.startsWith('{') || contentText.startsWith('['))) {
            message.tool_calls = contentText;
        }
        const text = normalizeMessageToolCalls(message, allowedToolNames, callIdPrefix);
        if (text) {
            const finish = readString(choice.finish_reason)?.toLowerCase();
            if (!finish || finish === 'stop') {
                choice.finish_reason = 'tool_calls';
            }
            return { hasNative: false, hasText: true, harvestedFunctionResults: false };
        }
    }
    return {
        hasNative: false,
        hasText: false,
        harvestedFunctionResults: false
    };
}
function harvestResponsesTextToolCalls(root, options, allowedToolNames) {
    if (options.toolProtocol !== 'text') {
        return { harvested: false };
    }
    const output = Array.isArray(root.output) ? root.output : [];
    if (!output.length) {
        return { harvested: false };
    }
    let harvested = false;
    const nextOutput = [];
    let callIndex = 0;
    for (const item of output) {
        if (!isRecord(item)) {
            nextOutput.push(item);
            continue;
        }
        const type = readString(item.type)?.toLowerCase() ?? '';
        if (type !== 'message') {
            nextOutput.push(item);
            continue;
        }
        const role = readString(item.role)?.toLowerCase() ?? 'assistant';
        if (role !== 'assistant') {
            nextOutput.push(item);
            continue;
        }
        const text = extractResponsesMessageText(item);
        if (!text || (!text.trim().startsWith('{') && !text.trim().startsWith('['))) {
            nextOutput.push(item);
            continue;
        }
        const normalizedCalls = normalizeToolCalls(text.trim(), allowedToolNames, 'deepseek_resp_call');
        if (!normalizedCalls.length) {
            nextOutput.push(item);
            continue;
        }
        harvested = true;
        for (const call of normalizedCalls) {
            callIndex += 1;
            const callId = readString(call.id) ?? `deepseek_resp_call_${callIndex}`;
            const itemId = normalizeFunctionCallId({ callId, fallback: `fc_${callId}` });
            nextOutput.push({
                type: 'function_call',
                id: itemId,
                call_id: callId,
                name: call.function.name,
                arguments: call.function.arguments
            });
        }
    }
    if (harvested) {
        root.output = nextOutput;
    }
    return { harvested };
}
function writeCompatState(root, state, source, harvestedFunctionResults) {
    const metadata = isRecord(root.metadata) ? root.metadata : {};
    metadata.deepseek = {
        ...(isRecord(metadata.deepseek) ? metadata.deepseek : {}),
        toolCallState: state,
        toolCallSource: source,
        ...(harvestedFunctionResults ? { functionResultsTextHarvested: true } : {})
    };
    root.metadata = metadata;
}
export function applyDeepSeekWebResponseTransform(payload, adapterContext, config) {
    if (!payload || typeof payload !== 'object') {
        return payload;
    }
    const cloned = structuredClone(payload);
    const root = normalizeDeepSeekBusinessEnvelope(cloned, adapterContext);
    const options = resolveOptions(adapterContext, config);
    const captured = resolveCapturedRequest(adapterContext);
    const allowedToolNames = resolveRequestedToolNames(captured);
    const toolChoiceRequired = isToolChoiceRequired(captured);
    const choices = Array.isArray(root.choices) ? root.choices : [];
    let hasNative = false;
    let hasText = false;
    let harvestedFunctionResults = false;
    for (const [index, choice] of choices.entries()) {
        if (!isRecord(choice)) {
            continue;
        }
        const result = normalizeChoice(choice, options, allowedToolNames, `deepseek_call_${index + 1}`);
        hasNative = hasNative || result.hasNative;
        hasText = hasText || result.hasText;
        harvestedFunctionResults = harvestedFunctionResults || result.harvestedFunctionResults;
    }
    if (!choices.length) {
        const harvested = harvestResponsesTextToolCalls(root, options, allowedToolNames);
        hasText = hasText || harvested.harvested;
    }
    const state = hasNative
        ? 'native_tool_calls'
        : hasText
            ? 'text_tool_calls'
            : 'no_tool_calls';
    const source = hasNative ? 'native' : hasText ? 'text' : 'none';
    writeCompatState(root, state, source, harvestedFunctionResults);
    applyUsageEstimate(root, choices, adapterContext, captured);
    if (toolChoiceRequired && options.strictToolRequired && !hasNative && !hasText) {
        const error = new Error('DeepSeek tool_choice=required but no valid tool call was produced');
        error.code = 'DEEPSEEK_TOOL_REQUIRED_MISSING';
        error.details = {
            requestId: readString(adapterContext?.requestId),
            phase: 'chat_process.resp.stage3.compat',
            state,
            strictToolRequired: options.strictToolRequired
        };
        throw error;
    }
    return root;
}
