import { calculateCost } from "../models.js";
import { parseStreamingJson } from "../utils/json-parse.js";
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
import { transformMessages } from "./transform-messages.js";
const claudeCodeTools = [
    "Read",
    "Write",
    "Edit",
    "Bash",
    "Grep",
    "Glob",
    "AskUserQuestion",
    "EnterPlanMode",
    "ExitPlanMode",
    "KillShell",
    "NotebookEdit",
    "Skill",
    "Task",
    "TaskOutput",
    "TodoWrite",
    "WebFetch",
    "WebSearch",
];
const ccToolLookup = new Map(claudeCodeTools.map((t) => [t.toLowerCase(), t]));
export const toClaudeCodeName = (name) => ccToolLookup.get(name.toLowerCase()) ?? name;
export const fromClaudeCodeName = (name, tools) => {
    if (tools && tools.length > 0) {
        const lowerName = name.toLowerCase();
        const matchedTool = tools.find((tool) => tool.name.toLowerCase() === lowerName);
        if (matchedTool)
            return matchedTool.name;
    }
    return name;
};
function resolveCacheRetention(cacheRetention) {
    if (cacheRetention) {
        return cacheRetention;
    }
    if (typeof process !== "undefined" && process.env.PI_CACHE_RETENTION === "long") {
        return "long";
    }
    return "short";
}
export function getCacheControl(baseUrl, cacheRetention) {
    const retention = resolveCacheRetention(cacheRetention);
    if (retention === "none") {
        return { retention };
    }
    const ttl = retention === "long" && baseUrl.includes("api.anthropic.com") ? "1h" : undefined;
    return {
        retention,
        cacheControl: { type: "ephemeral", ...(ttl && { ttl }) },
    };
}
export function convertContentBlocks(content) {
    const hasImages = content.some((c) => c.type === "image");
    if (!hasImages) {
        return sanitizeSurrogates(content.map((c) => c.text).join("\n"));
    }
    const blocks = content.map((block) => {
        if (block.type === "text") {
            return {
                type: "text",
                text: sanitizeSurrogates(block.text),
            };
        }
        return {
            type: "image",
            source: {
                type: "base64",
                media_type: block.mimeType,
                data: block.data,
            },
        };
    });
    const hasText = blocks.some((b) => b.type === "text");
    if (!hasText) {
        blocks.unshift({
            type: "text",
            text: "(see attached image)",
        });
    }
    return blocks;
}
export function supportsAdaptiveThinking(modelId) {
    return (modelId.includes("opus-4-6") ||
        modelId.includes("opus-4.6") ||
        modelId.includes("sonnet-4-6") ||
        modelId.includes("sonnet-4.6"));
}
export function mapThinkingLevelToEffort(level, modelId) {
    switch (level) {
        case "minimal":
            return "low";
        case "low":
            return "low";
        case "medium":
            return "medium";
        case "high":
            return "high";
        case "xhigh":
            return modelId.includes("opus-4-6") || modelId.includes("opus-4.6") ? "max" : "high";
        default:
            return "high";
    }
}
export function isTransientNetworkError(error) {
    if (!(error instanceof Error))
        return false;
    const msg = error.message.toLowerCase();
    const code = error.code;
    return (code === 'ECONNRESET' ||
        code === 'EPIPE' ||
        code === 'ETIMEDOUT' ||
        code === 'ENOTFOUND' ||
        code === 'EAI_AGAIN' ||
        msg.includes('connector_closed') ||
        msg.includes('socket hang up') ||
        msg.includes('network') ||
        msg.includes('connection') && msg.includes('closed') ||
        msg.includes('fetch failed'));
}
export function extractRetryAfterMs(headers, errorText = "") {
    const normalizeDelay = (ms) => (ms > 0 ? Math.ceil(ms + 1000) : undefined);
    const retryAfter = headers.get("retry-after");
    if (retryAfter) {
        const seconds = Number(retryAfter);
        if (Number.isFinite(seconds)) {
            const delay = normalizeDelay(seconds * 1000);
            if (delay !== undefined)
                return delay;
        }
        const asDate = new Date(retryAfter).getTime();
        if (!Number.isNaN(asDate)) {
            const delay = normalizeDelay(asDate - Date.now());
            if (delay !== undefined)
                return delay;
        }
    }
    for (const header of ["x-ratelimit-reset-requests", "x-ratelimit-reset-tokens"]) {
        const value = headers.get(header);
        if (value) {
            const resetSeconds = Number(value);
            if (Number.isFinite(resetSeconds)) {
                const delay = normalizeDelay(resetSeconds * 1000 - Date.now());
                if (delay !== undefined)
                    return delay;
            }
        }
    }
    return undefined;
}
export function normalizeToolCallId(id) {
    return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
}
export function convertMessages(messages, model, isOAuthToken, cacheControl) {
    const params = [];
    const transformedMessages = transformMessages(messages, model, normalizeToolCallId);
    for (let i = 0; i < transformedMessages.length; i++) {
        const msg = transformedMessages[i];
        if (msg.role === "user") {
            if (typeof msg.content === "string") {
                if (msg.content.trim().length > 0) {
                    params.push({
                        role: "user",
                        content: sanitizeSurrogates(msg.content),
                    });
                }
            }
            else {
                const blocks = msg.content.map((item) => {
                    if (item.type === "text") {
                        return {
                            type: "text",
                            text: sanitizeSurrogates(item.text),
                        };
                    }
                    else {
                        return {
                            type: "image",
                            source: {
                                type: "base64",
                                media_type: item.mimeType,
                                data: item.data,
                            },
                        };
                    }
                });
                let filteredBlocks = !model?.input.includes("image") ? blocks.filter((b) => b.type !== "image") : blocks;
                filteredBlocks = filteredBlocks.filter((b) => {
                    if (b.type === "text") {
                        return b.text.trim().length > 0;
                    }
                    return true;
                });
                if (filteredBlocks.length === 0)
                    continue;
                params.push({
                    role: "user",
                    content: filteredBlocks,
                });
            }
        }
        else if (msg.role === "assistant") {
            const blocks = [];
            for (const block of msg.content) {
                if (block.type === "text") {
                    if (block.text.trim().length === 0)
                        continue;
                    blocks.push({
                        type: "text",
                        text: sanitizeSurrogates(block.text),
                    });
                }
                else if (block.type === "thinking") {
                    if (block.redacted) {
                        blocks.push({
                            type: "redacted_thinking",
                            data: block.thinkingSignature,
                        });
                        continue;
                    }
                    if (block.thinking.trim().length === 0)
                        continue;
                    if (!block.thinkingSignature || block.thinkingSignature.trim().length === 0) {
                        blocks.push({
                            type: "text",
                            text: sanitizeSurrogates(block.thinking),
                        });
                    }
                    else {
                        blocks.push({
                            type: "thinking",
                            thinking: sanitizeSurrogates(block.thinking),
                            signature: block.thinkingSignature,
                        });
                    }
                }
                else if (block.type === "toolCall") {
                    blocks.push({
                        type: "tool_use",
                        id: block.id,
                        name: isOAuthToken ? toClaudeCodeName(block.name) : block.name,
                        input: block.arguments ?? {},
                    });
                }
                else if (block.type === "serverToolUse") {
                    blocks.push({
                        type: "server_tool_use",
                        id: block.id,
                        name: block.name,
                        input: block.input ?? {},
                    });
                }
                else if (block.type === "webSearchResult") {
                    blocks.push({
                        type: "web_search_tool_result",
                        tool_use_id: block.toolUseId,
                        content: block.content,
                    });
                }
            }
            if (blocks.length === 0)
                continue;
            params.push({
                role: "assistant",
                content: blocks,
            });
        }
        else if (msg.role === "toolResult") {
            const toolResults = [];
            toolResults.push({
                type: "tool_result",
                tool_use_id: msg.toolCallId,
                content: convertContentBlocks(msg.content),
                is_error: msg.isError,
            });
            let j = i + 1;
            while (j < transformedMessages.length && transformedMessages[j].role === "toolResult") {
                const nextMsg = transformedMessages[j];
                toolResults.push({
                    type: "tool_result",
                    tool_use_id: nextMsg.toolCallId,
                    content: convertContentBlocks(nextMsg.content),
                    is_error: nextMsg.isError,
                });
                j++;
            }
            i = j - 1;
            params.push({
                role: "user",
                content: toolResults,
            });
        }
    }
    if (cacheControl && params.length > 0) {
        const lastMessage = params[params.length - 1];
        if (lastMessage.role === "user") {
            if (Array.isArray(lastMessage.content)) {
                const lastBlock = lastMessage.content[lastMessage.content.length - 1];
                if (lastBlock &&
                    (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "tool_result")) {
                    lastBlock.cache_control = cacheControl;
                }
            }
            else if (typeof lastMessage.content === "string") {
                lastMessage.content = [
                    {
                        type: "text",
                        text: lastMessage.content,
                        cache_control: cacheControl,
                    },
                ];
            }
        }
    }
    return params;
}
export function convertTools(tools, isOAuthToken) {
    if (!tools)
        return [];
    return tools.map((tool) => {
        const jsonSchema = tool.parameters;
        return {
            name: isOAuthToken ? toClaudeCodeName(tool.name) : tool.name,
            description: tool.description,
            input_schema: {
                type: "object",
                properties: jsonSchema.properties || {},
                required: jsonSchema.required || [],
            },
        };
    });
}
export function buildParams(model, context, isOAuthToken, options) {
    const { cacheControl } = getCacheControl(model.baseUrl, options?.cacheRetention);
    const apiModelId = model.id.replace(/\[.*\]$/, "");
    const params = {
        model: apiModelId,
        messages: convertMessages(context.messages, model, isOAuthToken, cacheControl),
        max_tokens: options?.maxTokens || (model.maxTokens / 3) | 0,
        stream: true,
    };
    if (isOAuthToken) {
        params.system = [
            {
                type: "text",
                text: "You are Claude Code, Anthropic's official CLI for Claude.",
                ...(cacheControl ? { cache_control: cacheControl } : {}),
            },
        ];
        if (context.systemPrompt) {
            params.system.push({
                type: "text",
                text: sanitizeSurrogates(context.systemPrompt),
                ...(cacheControl ? { cache_control: cacheControl } : {}),
            });
        }
    }
    else if (context.systemPrompt) {
        params.system = [
            {
                type: "text",
                text: sanitizeSurrogates(context.systemPrompt),
                ...(cacheControl ? { cache_control: cacheControl } : {}),
            },
        ];
    }
    if (options?.temperature !== undefined && !options?.thinkingEnabled) {
        params.temperature = options.temperature;
    }
    if (context.tools) {
        params.tools = convertTools(context.tools, isOAuthToken);
    }
    if (options?.thinkingEnabled && model.reasoning) {
        if (supportsAdaptiveThinking(model.id)) {
            params.thinking = { type: "adaptive" };
            if (options.effort) {
                params.output_config = { effort: options.effort };
            }
        }
        else {
            params.thinking = {
                type: "enabled",
                budget_tokens: options.thinkingBudgetTokens || 1024,
            };
        }
    }
    if (options?.metadata) {
        const userId = options.metadata.user_id;
        if (typeof userId === "string") {
            params.metadata = { user_id: userId };
        }
    }
    if (options?.toolChoice) {
        if (typeof options.toolChoice === "string") {
            params.tool_choice = { type: options.toolChoice };
        }
        else {
            params.tool_choice = options.toolChoice;
        }
    }
    return params;
}
export function mapStopReason(reason) {
    switch (reason) {
        case "end_turn":
            return "stop";
        case "max_tokens":
            return "length";
        case "tool_use":
            return "toolUse";
        case "refusal":
            return "error";
        case "pause_turn":
            return "stop";
        case "stop_sequence":
            return "stop";
        case "sensitive":
            return "error";
        default:
            throw new Error(`Unhandled stop reason: ${reason}`);
    }
}
export function processAnthropicStream(stream, args) {
    const { client, model, context, isOAuthToken, options, AnthropicSdkClass } = args;
    (async () => {
        const output = {
            role: "assistant",
            content: [],
            api: model.api,
            provider: model.provider,
            model: model.id,
            usage: {
                input: 0,
                output: 0,
                cacheRead: 0,
                cacheWrite: 0,
                totalTokens: 0,
                cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "stop",
            timestamp: Date.now(),
        };
        try {
            let params = buildParams(model, context, isOAuthToken, options);
            const nextParams = await options?.onPayload?.(params, model);
            if (nextParams !== undefined) {
                params = nextParams;
            }
            const anthropicStream = client.messages.stream({ ...params, stream: true }, { signal: options?.signal });
            stream.push({ type: "start", partial: output });
            const blocks = output.content;
            for await (const event of anthropicStream) {
                if (event.type === "message_start") {
                    output.usage.input = event.message.usage.input_tokens || 0;
                    output.usage.output = event.message.usage.output_tokens || 0;
                    output.usage.cacheRead = event.message.usage.cache_read_input_tokens || 0;
                    output.usage.cacheWrite = event.message.usage.cache_creation_input_tokens || 0;
                    output.usage.totalTokens =
                        output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
                    calculateCost(model, output.usage);
                }
                else if (event.type === "content_block_start") {
                    if (event.content_block.type === "text") {
                        const block = {
                            type: "text",
                            text: "",
                            index: event.index,
                        };
                        output.content.push(block);
                        stream.push({ type: "text_start", contentIndex: output.content.length - 1, partial: output });
                    }
                    else if (event.content_block.type === "thinking") {
                        const block = {
                            type: "thinking",
                            thinking: "",
                            thinkingSignature: "",
                            index: event.index,
                        };
                        output.content.push(block);
                        stream.push({ type: "thinking_start", contentIndex: output.content.length - 1, partial: output });
                    }
                    else if (event.content_block.type === "redacted_thinking") {
                        const block = {
                            type: "thinking",
                            thinking: "[Reasoning redacted]",
                            thinkingSignature: event.content_block.data,
                            redacted: true,
                            index: event.index,
                        };
                        output.content.push(block);
                        stream.push({ type: "thinking_start", contentIndex: output.content.length - 1, partial: output });
                    }
                    else if (event.content_block.type === "tool_use") {
                        const block = {
                            type: "toolCall",
                            id: event.content_block.id,
                            name: isOAuthToken
                                ? fromClaudeCodeName(event.content_block.name, context.tools)
                                : event.content_block.name,
                            arguments: event.content_block.input ?? {},
                            partialJson: "",
                            index: event.index,
                        };
                        output.content.push(block);
                        stream.push({ type: "toolcall_start", contentIndex: output.content.length - 1, partial: output });
                    }
                    else if (event.content_block.type === "server_tool_use") {
                        const serverBlock = event.content_block;
                        const block = {
                            type: "serverToolUse",
                            id: serverBlock.id,
                            name: serverBlock.name,
                            input: serverBlock.input,
                            index: event.index,
                        };
                        output.content.push(block);
                        stream.push({ type: "server_tool_use", contentIndex: output.content.length - 1, partial: output });
                    }
                    else if (event.content_block.type === "web_search_tool_result") {
                        const resultBlock = event.content_block;
                        const block = {
                            type: "webSearchResult",
                            toolUseId: resultBlock.tool_use_id,
                            content: resultBlock.content,
                            index: event.index,
                        };
                        output.content.push(block);
                        stream.push({ type: "web_search_result", contentIndex: output.content.length - 1, partial: output });
                    }
                }
                else if (event.type === "content_block_delta") {
                    if (event.delta.type === "text_delta") {
                        const index = blocks.findIndex((b) => b.index === event.index);
                        const block = blocks[index];
                        if (block && block.type === "text") {
                            block.text += event.delta.text;
                            stream.push({
                                type: "text_delta",
                                contentIndex: index,
                                delta: event.delta.text,
                                partial: output,
                            });
                        }
                    }
                    else if (event.delta.type === "thinking_delta") {
                        const index = blocks.findIndex((b) => b.index === event.index);
                        const block = blocks[index];
                        if (block && block.type === "thinking") {
                            block.thinking += event.delta.thinking;
                            stream.push({
                                type: "thinking_delta",
                                contentIndex: index,
                                delta: event.delta.thinking,
                                partial: output,
                            });
                        }
                    }
                    else if (event.delta.type === "input_json_delta") {
                        const index = blocks.findIndex((b) => b.index === event.index);
                        const block = blocks[index];
                        if (block && block.type === "toolCall") {
                            block.partialJson += event.delta.partial_json;
                            block.arguments = parseStreamingJson(block.partialJson);
                            stream.push({
                                type: "toolcall_delta",
                                contentIndex: index,
                                delta: event.delta.partial_json,
                                partial: output,
                            });
                        }
                    }
                    else if (event.delta.type === "signature_delta") {
                        const index = blocks.findIndex((b) => b.index === event.index);
                        const block = blocks[index];
                        if (block && block.type === "thinking") {
                            block.thinkingSignature = block.thinkingSignature || "";
                            block.thinkingSignature += event.delta.signature;
                        }
                    }
                }
                else if (event.type === "content_block_stop") {
                    const index = blocks.findIndex((b) => b.index === event.index);
                    const block = blocks[index];
                    if (block) {
                        delete block.index;
                        if (block.type === "text") {
                            stream.push({
                                type: "text_end",
                                contentIndex: index,
                                content: block.text,
                                partial: output,
                            });
                        }
                        else if (block.type === "thinking") {
                            stream.push({
                                type: "thinking_end",
                                contentIndex: index,
                                content: block.thinking,
                                partial: output,
                            });
                        }
                        else if (block.type === "toolCall") {
                            block.arguments = parseStreamingJson(block.partialJson);
                            delete block.partialJson;
                            stream.push({
                                type: "toolcall_end",
                                contentIndex: index,
                                toolCall: block,
                                partial: output,
                            });
                        }
                    }
                }
                else if (event.type === "message_delta") {
                    if (event.delta.stop_reason) {
                        output.stopReason = mapStopReason(event.delta.stop_reason);
                    }
                    if (event.usage.input_tokens != null) {
                        output.usage.input = event.usage.input_tokens;
                    }
                    if (event.usage.output_tokens != null) {
                        output.usage.output = event.usage.output_tokens;
                    }
                    if (event.usage.cache_read_input_tokens != null) {
                        output.usage.cacheRead = event.usage.cache_read_input_tokens;
                    }
                    if (event.usage.cache_creation_input_tokens != null) {
                        output.usage.cacheWrite = event.usage.cache_creation_input_tokens;
                    }
                    output.usage.totalTokens =
                        output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
                    calculateCost(model, output.usage);
                }
            }
            if (options?.signal?.aborted) {
                throw new Error("Request was aborted");
            }
            if (output.stopReason === "aborted" || output.stopReason === "error") {
                throw new Error("An unknown error occurred");
            }
            stream.push({ type: "done", reason: output.stopReason, message: output });
            stream.end();
        }
        catch (error) {
            for (const block of output.content)
                delete block.index;
            output.stopReason = options?.signal?.aborted ? "aborted" : "error";
            output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
            if (model.provider === "alibaba-coding-plan") {
                output.errorMessage = `[alibaba-coding-plan] ${output.errorMessage}`;
            }
            if (AnthropicSdkClass && error instanceof AnthropicSdkClass.APIError && error.headers) {
                const retryAfterMs = extractRetryAfterMs(error.headers, error.message);
                if (retryAfterMs !== undefined) {
                    output.retryAfterMs = retryAfterMs;
                }
            }
            if (isTransientNetworkError(error)) {
                output.retryAfterMs = output.retryAfterMs ?? 5000;
            }
            stream.push({ type: "error", reason: output.stopReason, error: output });
            stream.end();
        }
    })();
}
//# sourceMappingURL=anthropic-shared.js.map