import { getPrefixedLogger } from "../../../util/logger.js";
/**
 * Threshold for compacting tool call inputs.
 * Inputs larger than this (in characters) will be summarized or truncated.
 */
export const INPUT_COMPACTION_THRESHOLD_CHARS = 100;
// --- Caching constants and types ---
export const PROVIDER_CACHE_MAX_BREAKPOINTS = 4;
export const PROVIDER_CACHE_MIN_CACHEABLE_TOKENS = 1024;
export const CACHE_BREAKPOINT_PROVIDER_OPTIONS = {
    bedrock: { cachePoint: { type: "default" } },
    anthropic: { cacheControl: { type: "ephemeral" } },
};
const logger = getPrefixedLogger("[context-v2:types]");
/**
 * Normalizes a tool result output to ensure it conforms to LanguageModelV2ToolResultOutput.
 * This prevents validation errors when passing messages to the AI SDK.
 */
export function normalizeToolResultOutput(output) {
    if (output === null || output === undefined) {
        return { type: "json", value: null };
    }
    if (typeof output !== "object") {
        return { type: "json", value: output };
    }
    const outputObj = output;
    if (!("type" in outputObj) || typeof outputObj.type !== "string") {
        return { type: "json", value: output };
    }
    const validTypes = [
        "text",
        "json",
        "error-text",
        "error-json",
        "content",
    ];
    if (!validTypes.includes(outputObj.type)) {
        logger.warn(`Invalid tool result output type: ${outputObj.type}. Normalizing to json type.`);
        return { type: "json", value: output };
    }
    return output;
}
/**
 * Normalizes tool messages to ensure all tool results have valid output formats.
 */
export function normalizeToolMessage(msg) {
    if (msg.role !== "tool" || !Array.isArray(msg.content)) {
        return msg;
    }
    const normalizedContent = msg.content.map((part) => {
        if (typeof part === "object" &&
            part !== null &&
            "type" in part &&
            part.type === "tool-result" &&
            "output" in part) {
            const toolResult = part;
            const normalizedOutput = normalizeToolResultOutput(toolResult.output);
            if (normalizedOutput !== toolResult.output) {
                logger.debug(`Normalized tool result output for ${toolResult.toolName} (callId: ${toolResult.toolCallId})`);
            }
            return { ...toolResult, output: normalizedOutput };
        }
        return part;
    });
    return { ...msg, content: normalizedContent };
}
/**
 * Normalizes provider options on reasoning blocks to work across both
 * Anthropic (Vertex) and Bedrock providers.
 */
export function normalizeReasoningProviderOptions(msg) {
    if (typeof msg.content === "string") {
        return;
    }
    for (const part of msg.content) {
        if (part.type !== "reasoning") {
            continue;
        }
        const providerOptions = part.providerOptions;
        if (!providerOptions)
            return;
        const anthropicSignature = providerOptions.anthropic?.signature;
        const bedrockSignature = providerOptions.bedrock?.signature;
        const signature = anthropicSignature || bedrockSignature;
        if (signature) {
            providerOptions.anthropic = { ...providerOptions.anthropic, signature };
            providerOptions.bedrock = { ...providerOptions.bedrock, signature };
        }
    }
}
/**
 * Repairs broken tool calls in assistant messages.
 *
 * - Ensures tool-call inputs are valid objects (not null, undefined, or arrays)
 * - Removes tool-call parts without corresponding tool-result in the next message
 *
 * This prevents errors from LLM providers like:
 * - Bedrock: "messages.X.content.Y.tool_use.input: Input should be a valid dictionary"
 * - Vertex: "tool_use ids were found without tool_result blocks immediately after"
 */
export function repairBrokenToolCalls(msg, index, messages) {
    if (msg.role !== "assistant" || typeof msg.content === "string") {
        return msg;
    }
    let content = [...msg.content];
    // Fix tool-call inputs that are not objects
    let inputsFixed = 0;
    content = content.map((part) => {
        if (part.type === "tool-call") {
            const toolCall = part;
            if (typeof toolCall.input !== "object" ||
                toolCall.input === null ||
                Array.isArray(toolCall.input)) {
                inputsFixed++;
                return { ...part, input: {} };
            }
        }
        return part;
    });
    if (inputsFixed > 0) {
        logger.debug(`Fixed ${inputsFixed} tool call(s) with non-object input at index ${index}`);
    }
    // Collect tool-result IDs from the next message
    const toolResultIds = new Set();
    const nextMsg = messages[index + 1];
    if (nextMsg &&
        (nextMsg.role === "assistant" || nextMsg.role === "tool") &&
        typeof nextMsg.content !== "string") {
        for (const part of nextMsg.content) {
            if (typeof part === "object" &&
                part !== null &&
                "type" in part &&
                part.type === "tool-result" &&
                "toolCallId" in part) {
                toolResultIds.add(part.toolCallId);
            }
        }
    }
    // Get tool-call IDs from this message
    const hasToolCalls = content.some((part) => typeof part === "object" &&
        part !== null &&
        "type" in part &&
        part.type === "tool-call");
    if (!hasToolCalls) {
        return { ...msg, content };
    }
    // Also check for tool-result in the same message (parallel tool calls)
    for (const part of content) {
        if (typeof part === "object" &&
            part !== null &&
            "type" in part &&
            part.type === "tool-result" &&
            "toolCallId" in part) {
            toolResultIds.add(part.toolCallId);
        }
    }
    // Remove orphaned tool-call parts
    const before = content.length;
    content = content.filter((part) => {
        if (typeof part === "object" &&
            part !== null &&
            "type" in part &&
            part.type === "tool-call" &&
            "toolCallId" in part) {
            return toolResultIds.has(part.toolCallId);
        }
        return true;
    });
    const removed = before - content.length;
    if (removed > 0) {
        logger.debug(`Removed ${removed} orphaned tool call(s) from assistant message at index ${index}`);
    }
    return { ...msg, content };
}
function stripUndefined(obj) {
    if (obj === null || typeof obj !== "object") {
        return obj;
    }
    if (Array.isArray(obj)) {
        return obj.map(stripUndefined);
    }
    const result = {};
    for (const [key, value] of Object.entries(obj)) {
        if (value !== undefined) {
            result[key] = stripUndefined(value);
        }
    }
    return result;
}
export function stripUndefinedFromToolOutputs(msg) {
    if (msg.role !== "tool" || !Array.isArray(msg.content)) {
        return msg;
    }
    const cleanedContent = msg.content.map((part) => {
        if (typeof part === "object" &&
            part !== null &&
            "type" in part &&
            part.type === "tool-result" &&
            "output" in part) {
            const toolResult = part;
            // Only strip undefined from the output value, not the entire tool result
            const output = toolResult.output;
            if (output && typeof output === "object" && "value" in output) {
                const typedOutput = output;
                return {
                    ...toolResult,
                    output: {
                        ...typedOutput,
                        value: stripUndefined(typedOutput.value),
                    },
                };
            }
        }
        return part;
    });
    return { ...msg, content: cleanedContent };
}
export function toSdkMessages(messages) {
    return messages.map((msg) => {
        const { _superblocks, ...sdkMessage } = msg;
        return sdkMessage;
    });
}
export function toStoredMessage(msg, metadata = {}) {
    return {
        ...msg,
        _superblocks: { timestamp: Date.now(), ...metadata },
    };
}
export function extractTokenUsage(usage) {
    return {
        input: usage.inputTokens ?? 0,
        output: usage.outputTokens ?? 0,
        cacheRead: usage.cachedInputTokens ?? 0,
    };
}
//# sourceMappingURL=types.js.map