/**
 * Custom message types and transformers for the coding agent.
 *
 * Extends the base AgentMessage type with coding-agent specific message types,
 * and provides a transformer to convert them to LLM-compatible messages.
 */
export const BRANCH_SUMMARY_PREFIX = `The following is a summary of a branch that this conversation came back from:

<summary>
`;
export const BRANCH_SUMMARY_SUFFIX = `</summary>`;
/** Normalize lax JavaScript/legacy message input before it reaches history or providers. */
export function normalizeMessageContent(message) {
    switch (message.role) {
        case "user":
        case "assistant":
        case "toolResult":
        case "custom":
            return message.content == null ? { ...message, content: [] } : message;
        default:
            return message;
    }
}
export function userLikeContentBlockIsLlmVisible(block) {
    if (!block || typeof block !== "object")
        return false;
    const candidate = block;
    if (candidate.type === "image")
        return true;
    if (candidate.type === "text")
        return typeof candidate.text === "string" && candidate.text.trim().length > 0;
    // Future provider-supported blocks must fail visible; only malformed/untyped blocks fail closed.
    return typeof candidate.type === "string" && candidate.type.trim().length > 0;
}
/** Whether user/custom content survives provider conversion as a visible input. */
export function userLikeContentIsLlmVisible(content, deletedBlockIndexes = new Set()) {
    if (typeof content === "string")
        return content.trim().length > 0;
    if (!Array.isArray(content))
        return false;
    return content.some((block, index) => !deletedBlockIndexes.has(index) && userLikeContentBlockIsLlmVisible(block));
}
/** Whether an Atomic message emits an LLM-visible user-like turn boundary. */
export function messageStartsLlmUserTurn(message, deletedBlockIndexes = new Set()) {
    switch (message.role) {
        case "user":
            return userLikeContentIsLlmVisible(message.content, deletedBlockIndexes);
        case "custom":
            return (message.excludeFromContext !== true &&
                userLikeContentIsLlmVisible(message.content, deletedBlockIndexes));
        case "branchSummary":
            // Empty summaries are omitted by session reconstruction. Whitespace is
            // visible because the branch-summary wrapper itself is non-whitespace.
            return typeof message.summary === "string" && message.summary.length > 0;
        case "bashExecution":
            return message.excludeFromContext !== true;
        default:
            return false;
    }
}
/** Whether an Atomic message survives conversion into provider-visible context. */
export function messageIsLlmVisible(message, deletedBlockIndexes = new Set()) {
    if (message.role === "assistant" || message.role === "toolResult")
        return true;
    return messageStartsLlmUserTurn(message, deletedBlockIndexes);
}
/** Filter invalid user-like blocks only in transient provider-bound content. */
function filterUserLikeContentBlocks(content) {
    return content.filter(userLikeContentBlockIsLlmVisible);
}
/** Normalize raw blocks only in the transient LLM-compatible message returned by convertToLlm. */
function normalizeRawRedactedThinking(message) {
    if (message.role !== "assistant" || !Array.isArray(message.content))
        return message;
    let changed = false;
    const content = message.content.map((block) => {
        if (!block || typeof block !== "object")
            return block;
        const candidate = block;
        if (candidate.type !== "redacted_thinking" || typeof candidate.data !== "string")
            return block;
        changed = true;
        return {
            type: "thinking",
            thinking: "",
            thinkingSignature: candidate.data,
            redacted: true,
        };
    });
    return changed ? { ...message, content } : message;
}
/**
 * Convert a BashExecutionMessage to user message text for LLM context.
 */
export function bashExecutionToText(msg) {
    let text = `Ran \`${msg.command}\`\n`;
    if (msg.output) {
        text += `\`\`\`\n${msg.output}\n\`\`\``;
    }
    else {
        text += "(no output)";
    }
    if (msg.cancelled) {
        text += "\n\n(command cancelled)";
    }
    else if (msg.exitCode !== null && msg.exitCode !== undefined && msg.exitCode !== 0) {
        text += `\n\nCommand exited with code ${msg.exitCode}`;
    }
    if (msg.truncated && msg.fullOutputPath) {
        text += `\n\n[Output truncated. Full output: ${msg.fullOutputPath}]`;
    }
    return text;
}
export function createBranchSummaryMessage(summary, fromId, timestamp) {
    return {
        role: "branchSummary",
        summary,
        fromId,
        timestamp: new Date(timestamp).getTime(),
    };
}
/** Convert CustomMessageEntry to AgentMessage format */
export function createCustomMessage(customType, content, display, details, timestamp, excludeFromContext) {
    const message = {
        role: "custom",
        customType,
        content: content ?? [],
        display,
        details,
        timestamp: new Date(timestamp).getTime(),
    };
    if (excludeFromContext === true)
        message.excludeFromContext = true;
    return message;
}
function collectAssistantToolCallIds(message) {
    const content = message.content;
    const ids = new Set();
    if (!Array.isArray(content))
        return ids;
    for (const block of content) {
        if (!block || typeof block !== "object")
            continue;
        const candidate = block;
        if (candidate.type === "toolCall" && typeof candidate.id === "string")
            ids.add(candidate.id);
    }
    return ids;
}
function getToolResultCallId(message) {
    if (message.role !== "toolResult")
        return undefined;
    const toolCallId = message.toolCallId;
    return typeof toolCallId === "string" ? toolCallId : undefined;
}
export function repairOrphanToolResults(messages) {
    let allowedToolCallIds;
    let changed = false;
    const repaired = [];
    for (const message of messages) {
        if (message.role === "assistant") {
            allowedToolCallIds = collectAssistantToolCallIds(message);
            repaired.push(message);
            continue;
        }
        if (message.role === "toolResult") {
            const toolCallId = getToolResultCallId(message);
            if (toolCallId && allowedToolCallIds?.has(toolCallId)) {
                repaired.push(message);
                continue;
            }
            changed = true;
            continue;
        }
        allowedToolCallIds = undefined;
        repaired.push(message);
    }
    return changed ? repaired : messages;
}
/**
 * Transform AgentMessages (including custom types) to LLM-compatible Messages.
 *
 * This is used by:
 * - Agent's transormToLlm option (for prompt calls and queued messages)
 * - Branch summarization (for summarizing abandoned branches)
 * - Custom extensions and tools
 */
export function convertToLlm(messages) {
    const converted = messages
        .map((rawMessage) => {
        const m = normalizeRawRedactedThinking(normalizeMessageContent(rawMessage));
        switch (m.role) {
            case "bashExecution":
                if (!messageStartsLlmUserTurn(m))
                    return undefined;
                return {
                    role: "user",
                    content: [{ type: "text", text: bashExecutionToText(m) }],
                    timestamp: m.timestamp,
                };
            case "custom": {
                if (!messageStartsLlmUserTurn(m))
                    return undefined;
                const content = typeof m.content === "string"
                    ? [{ type: "text", text: m.content }]
                    : filterUserLikeContentBlocks(m.content);
                return { role: "user", content, timestamp: m.timestamp };
            }
            case "branchSummary":
                if (!messageStartsLlmUserTurn(m))
                    return undefined;
                return {
                    role: "user",
                    content: [{ type: "text", text: BRANCH_SUMMARY_PREFIX + m.summary + BRANCH_SUMMARY_SUFFIX }],
                    timestamp: m.timestamp,
                };
            case "user": {
                if (!messageStartsLlmUserTurn(m))
                    return undefined;
                if (!Array.isArray(m.content))
                    return m;
                return { ...m, content: filterUserLikeContentBlocks(m.content) };
            }
            case "assistant":
            case "toolResult":
                return m;
            case "compactionSummary":
                // Legacy generated summaries remain archival and never enter active LLM context.
                return undefined;
            default: {
                // Exhaustiveness guard: new AgentMessage roles must define provider conversion explicitly.
                const _exhaustiveCheck = m;
                void _exhaustiveCheck;
                return undefined;
            }
        }
    })
        .filter((m) => m !== undefined);
    return repairOrphanToolResults(converted);
}
//# sourceMappingURL=messages.js.map