import { AGENT_HISTORY_LIMIT, mergeAgentOperationHistory, } from "../agentMessageHelpers";
export function createInitialAgentSessionState(input = {}) {
    return {
        loadStatus: input.isLoading ? "loading" : "idle",
        error: null,
        agent: input.agent,
        transcript: input.agent?.messages ?? [],
        operationHistory: [],
        queuedPrompts: [],
        metadata: null,
        costLimitExceeded: null,
        contextWindowStatus: null,
        liveTotals: null,
        activeInlineDialog: null,
        run: {
            currentRunId: null,
            lastSeq: 0,
            lastSettledRunId: null,
            status: input.agent?.status ?? null,
            lastStatusReason: null,
            isConnecting: false,
            isSubmitting: false,
            isWaitingForResponse: false,
            isAgentThinking: false,
            stopGuardActive: false,
        },
        reconciliation: {
            snapshotEpoch: 0,
            latestAcceptedSnapshotEpoch: 0,
            seenMessageIds: collectMessageIds(input.agent?.messages ?? []),
        },
    };
}
export function normalizeSessionRunId(value) {
    if (typeof value !== "string")
        return null;
    const trimmed = value.trim().toLowerCase();
    if (!trimmed)
        return null;
    if (trimmed === "00000000-0000-0000-0000-000000000000")
        return null;
    return trimmed;
}
export function createOptimisticUserMessage(input) {
    return {
        id: input.id,
        agentId: input.agentId,
        messageIndex: -1,
        role: "user",
        content: input.content,
        name: "user",
        messageType: "user",
        isCompleted: true,
        model: "",
        tokensUsed: 0,
        inputTokens: 0,
        outputTokens: 0,
        cachedInputTokens: 0,
        inputTokenCost: 0,
        outputTokenCost: 0,
        cachedInputTokenCost: 0,
        totalCost: 0,
        currency: "USD",
        createdDate: input.createdDate ?? new Date().toISOString(),
        toolCalls: [],
        ...(input.attachments?.length ? { attachments: input.attachments } : {}),
    };
}
export function applyAssistantContentChunkToTranscript(transcript, chunk) {
    const existingMessageIndex = transcript.findIndex((message) => message.id === chunk.messageId);
    const deltaContent = chunk.deltaContent || "";
    const totalContentLength = chunk.totalContentLength || 0;
    const previousContentLength = typeof chunk.previousContentLength === "number"
        ? chunk.previousContentLength
        : totalContentLength > 0
            ? Math.max(0, totalContentLength - deltaContent.length)
            : 0;
    if (existingMessageIndex === -1) {
        return [
            ...transcript,
            {
                ...chunk.createMessage(),
                content: chunk.isIncremental && previousContentLength > 0 ? "" : deltaContent,
                reasoning: chunk.reasoning || "",
            },
        ];
    }
    const existingMessage = transcript[existingMessageIndex];
    if (!existingMessage)
        return transcript;
    const currentContentLength = existingMessage.content?.length || 0;
    if (chunk.isIncremental &&
        currentContentLength >= totalContentLength &&
        totalContentLength > 0) {
        return transcript;
    }
    const updatedMessage = { ...existingMessage };
    if (!chunk.isIncremental) {
        updatedMessage.content = deltaContent;
        updatedMessage.reasoning = chunk.reasoning || "";
    }
    else {
        if (currentContentLength < previousContentLength) {
            updatedMessage.reasoning =
                chunk.reasoning || existingMessage.reasoning || "";
            return transcript.map((message, index) => index === existingMessageIndex ? updatedMessage : message);
        }
        const overlapLength = Math.max(0, currentContentLength - previousContentLength);
        updatedMessage.content =
            existingMessage.content + deltaContent.slice(overlapLength);
        updatedMessage.reasoning =
            chunk.reasoning || existingMessage.reasoning || "";
    }
    return transcript.map((message, index) => index === existingMessageIndex ? updatedMessage : message);
}
/**
 * Merge a resynced assistant snapshot into the existing transcript message
 * without ever shrinking what we already have. A resync carries the content
 * buffered on the server at reconnect time; live streaming may have advanced
 * past it, so blindly replacing content/reasoning/toolCalls with the buffered
 * snapshot can truncate newer streamed state. We keep the longer value of each
 * field, mirroring the regression guard in
 * applyAssistantContentChunkToTranscript.
 */
export function mergeResyncedAssistantMessage(existing, resync) {
    const content = resync.content.length >= (existing.content?.length ?? 0)
        ? resync.content
        : existing.content;
    const reasoning = resync.reasoning.length >= (existing.reasoning?.length ?? 0)
        ? resync.reasoning
        : existing.reasoning;
    const toolCalls = resync.toolCalls.length >= (existing.toolCalls?.length ?? 0)
        ? resync.toolCalls
        : existing.toolCalls;
    return { ...existing, content, reasoning, toolCalls };
}
export function applyHeartbeatMessageToTranscript(transcript, heartbeatMessage) {
    return [
        ...clearHeartbeatMessagesFromTranscript(transcript),
        heartbeatMessage,
    ];
}
export function clearHeartbeatMessagesFromTranscript(transcript) {
    const nextTranscript = transcript.filter((message) => message.messageType !== "heartbeat");
    return nextTranscript.length === transcript.length
        ? transcript
        : nextTranscript;
}
export function completeOpenAssistantMessagesInTranscript(transcript) {
    return transcript.map((message) => message.role === "assistant" && !message.isCompleted
        ? {
            ...message,
            isCompleted: true,
            messageType: "completed",
        }
        : message);
}
export function completeOpenStreamingMessagesInTranscript(transcript) {
    return transcript.map((message) => !message.isCompleted && message.messageType === "streaming"
        ? {
            ...message,
            isCompleted: true,
            messageType: "completed",
        }
        : message);
}
export function upsertToolCallInTranscript(transcript, input) {
    if (input.targetIndex < 0)
        return transcript;
    const targetMessage = transcript[input.targetIndex];
    if (!targetMessage)
        return transcript;
    const existingToolCalls = targetMessage.toolCalls || [];
    const existingIndex = existingToolCalls.findIndex((toolCall) => toolCall.toolCallId === input.toolCall.toolCallId);
    let nextToolCalls;
    if (existingIndex === -1) {
        nextToolCalls = [...existingToolCalls, input.toolCall];
    }
    else {
        const existing = existingToolCalls[existingIndex];
        if (!existing)
            return transcript;
        const newArgsText = stringifySessionToolField(input.toolCall.functionArguments);
        const existingArgsText = stringifySessionToolField(existing.functionArguments);
        const hasMoreCompleteArgs = (newArgsText.length > existingArgsText.length &&
            newArgsText !== existingArgsText) ||
            (existingArgsText === "{}" && newArgsText !== "{}");
        const hasNewResult = !!input.toolCall.functionResult && !existing.functionResult;
        const hasNewRichContent = !!input.toolCall.functionResultRichContent &&
            !existing.functionResultRichContent;
        const hasNewError = !!input.toolCall.functionError && !existing.functionError;
        const hasNewApprovalInfo = !!input.toolCall.requiresApproval && !existing.requiresApproval;
        const hasNewDbMessageId = !!input.toolCall.dbMessageId && !existing.dbMessageId;
        if (!hasMoreCompleteArgs &&
            !hasNewResult &&
            !hasNewRichContent &&
            !hasNewError &&
            !hasNewApprovalInfo &&
            !hasNewDbMessageId) {
            return transcript;
        }
        const merged = {
            ...existing,
            functionArguments: hasMoreCompleteArgs
                ? newArgsText
                : existingArgsText || existing.functionArguments,
            functionResult: input.toolCall.functionResult || existing.functionResult,
            functionResultRichContent: input.toolCall.functionResultRichContent ||
                existing.functionResultRichContent,
            functionError: input.toolCall.functionError || existing.functionError,
            requiresApproval: input.toolCall.requiresApproval || existing.requiresApproval,
        };
        if (input.toolCall.dbMessageId || existing.dbMessageId) {
            merged.dbMessageId =
                input.toolCall.dbMessageId || existing.dbMessageId;
        }
        nextToolCalls = [...existingToolCalls];
        nextToolCalls[existingIndex] = merged;
    }
    return transcript.map((message, index) => index === input.targetIndex
        ? { ...message, toolCalls: nextToolCalls }
        : message);
}
export function upsertToolCallForMessageInTranscript(transcript, input) {
    const existingIndex = transcript.findIndex((message) => message.id === input.messageId);
    const workingTranscript = existingIndex === -1 ? [...transcript, input.createMessage()] : transcript;
    const targetIndex = existingIndex === -1 ? workingTranscript.length - 1 : existingIndex;
    return upsertToolCallInTranscript(workingTranscript, {
        targetIndex,
        toolCall: input.toolCall,
    });
}
export function applyToolResultToTranscript(transcript, input) {
    if (input.targetIndex < 0) {
        return { transcript, allToolCallsCompleted: false };
    }
    const targetMessage = transcript[input.targetIndex];
    if (!targetMessage) {
        return { transcript, allToolCallsCompleted: false };
    }
    const existingToolCalls = targetMessage.toolCalls || [];
    const toolCallIndex = existingToolCalls.findIndex((toolCall) => toolCall.toolCallId === input.toolCallId);
    let nextToolCalls;
    if (toolCallIndex >= 0) {
        const existingToolCall = existingToolCalls[toolCallIndex];
        if (!existingToolCall) {
            return { transcript, allToolCallsCompleted: false };
        }
        const nextArgsText = stringifySessionToolField(input.fallbackToolCall.functionArguments);
        const existingArgsText = stringifySessionToolField(existingToolCall.functionArguments);
        const hasMoreCompleteArgs = (nextArgsText.length > existingArgsText.length &&
            nextArgsText !== existingArgsText) ||
            (existingArgsText === "{}" && nextArgsText !== "{}");
        nextToolCalls = [...existingToolCalls];
        nextToolCalls[toolCallIndex] = {
            ...existingToolCall,
            functionArguments: hasMoreCompleteArgs
                ? nextArgsText
                : existingToolCall.functionArguments,
            functionResult: input.fallbackToolCall.functionResult || "",
            functionResultRichContent: input.fallbackToolCall.functionResultRichContent ||
                existingToolCall.functionResultRichContent,
            functionError: input.fallbackToolCall.functionError || "",
            isCompleted: true,
            responseTimeMs: input.fallbackToolCall.responseTimeMs,
        };
    }
    else {
        nextToolCalls = [
            ...existingToolCalls,
            {
                ...input.fallbackToolCall,
                isCompleted: true,
            },
        ];
    }
    const allToolCallsCompleted = nextToolCalls.every((toolCall) => toolCall.isCompleted);
    const nextTranscript = transcript.map((message, index) => index === input.targetIndex
        ? { ...message, toolCalls: nextToolCalls }
        : message);
    return { transcript: nextTranscript, allToolCallsCompleted };
}
export function applyToolResultForMessageInTranscript(transcript, input) {
    const targetIndex = transcript.findIndex((message) => message.id === input.messageId);
    if (targetIndex === -1) {
        return { transcript, allToolCallsCompleted: false };
    }
    return applyToolResultToTranscript(transcript, {
        targetIndex,
        toolCallId: input.toolCallId,
        fallbackToolCall: input.fallbackToolCall,
    });
}
export function applyToolApprovalsRequiredToTranscript(transcript, input) {
    let changed = false;
    const nextTranscript = transcript.map((message) => {
        if (message.id !== input.messageId)
            return message;
        const existingToolCalls = message.toolCalls || [];
        const nextToolCalls = existingToolCalls.map((toolCall) => {
            if (!input.toolCallIds.includes(toolCall.toolCallId))
                return toolCall;
            const functionName = toolCall.functionName || "";
            if (functionName.includes("(pending approval)"))
                return toolCall;
            changed = true;
            return {
                ...toolCall,
                functionName: `${functionName} (pending approval)`,
            };
        });
        return nextToolCalls === existingToolCalls
            ? message
            : { ...message, toolCalls: nextToolCalls };
    });
    return changed ? nextTranscript : transcript;
}
export function applyBackendSnapshot(state, snapshot) {
    const epoch = snapshot.epoch ?? state.reconciliation.snapshotEpoch + 1;
    if (!snapshot.force &&
        epoch < state.reconciliation.latestAcceptedSnapshotEpoch) {
        return state;
    }
    const serverMessages = snapshot.agent.messages ?? [];
    const transcript = mergeSnapshotTranscript(state, snapshot.agent);
    const serverReturnedRunning = isRunningStatus(snapshot.agent.status);
    const nextRunStatus = serverReturnedRunning
        ? "running"
        : snapshot.agent.status;
    return {
        ...state,
        loadStatus: "ready",
        error: null,
        agent: snapshot.agent,
        transcript,
        operationHistory: snapshot.operationHistory ?? state.operationHistory,
        queuedPrompts: snapshot.queuedPrompts ?? state.queuedPrompts,
        metadata: snapshot.metadata !== undefined ? snapshot.metadata : state.metadata,
        costLimitExceeded: snapshot.costLimitExceeded !== undefined
            ? snapshot.costLimitExceeded
            : state.costLimitExceeded,
        contextWindowStatus: snapshot.contextWindowStatus !== undefined
            ? snapshot.contextWindowStatus
            : state.contextWindowStatus,
        liveTotals: snapshot.liveTotals !== undefined
            ? snapshot.liveTotals
            : state.liveTotals,
        run: {
            ...state.run,
            status: nextRunStatus,
            isConnecting: serverReturnedRunning ? state.run.isConnecting : false,
            isWaitingForResponse: serverReturnedRunning
                ? state.run.isWaitingForResponse
                : false,
            isAgentThinking: serverReturnedRunning
                ? state.run.isAgentThinking
                : false,
            stopGuardActive: serverReturnedRunning
                ? state.run.stopGuardActive
                : false,
        },
        reconciliation: {
            snapshotEpoch: epoch,
            latestAcceptedSnapshotEpoch: epoch,
            seenMessageIds: collectMessageIds(serverMessages),
        },
    };
}
export function applySnapshotLoading(state) {
    return {
        ...state,
        loadStatus: "loading",
        error: null,
    };
}
export function applySnapshotReady(state) {
    return {
        ...state,
        loadStatus: "ready",
        error: null,
    };
}
export function applySnapshotError(state, error) {
    return {
        ...state,
        loadStatus: "error",
        error,
    };
}
export function addOptimisticUserMessage(state, message) {
    if (state.transcript.some((existing) => existing.id === message.id && existing.role === "user")) {
        return {
            ...state,
            run: {
                ...state.run,
                isSubmitting: true,
            },
        };
    }
    return {
        ...state,
        transcript: [...state.transcript, message],
        run: {
            ...state.run,
            isSubmitting: true,
        },
    };
}
export function removeOptimisticUserMessage(state, messageId) {
    return {
        ...state,
        transcript: state.transcript.filter((message) => message.id !== messageId),
    };
}
/**
 * Collapse transcript entries that share a case-insensitive id, preserving the
 * position of the first occurrence and keeping the richer (longer
 * content+reasoning) copy. The rendered transcript groups consecutive assistant
 * messages and concatenates their bodies, so a duplicate row — e.g. a streamed
 * copy plus a resynced copy whose GUID differs only by casing — would paint the
 * same content twice. mergeMessagesById dedupes on the load path only; this is
 * the equivalent guard for the live transcript. Returns the original array
 * reference when there is nothing to collapse (the common case).
 */
export function dedupeTranscriptById(transcript) {
    const indexByKey = new Map();
    const result = [];
    let changed = false;
    for (const message of transcript) {
        const key = message.id ? message.id.toLowerCase() : "";
        if (!key) {
            result.push(message);
            continue;
        }
        const existingIndex = indexByKey.get(key);
        if (existingIndex === undefined) {
            indexByKey.set(key, result.length);
            result.push(message);
            continue;
        }
        changed = true;
        const existing = result[existingIndex];
        if (existing && messageContentLength(message) > messageContentLength(existing)) {
            result[existingIndex] = message;
        }
    }
    return changed ? result : transcript;
}
function messageContentLength(message) {
    return (message.content?.length ?? 0) + (message.reasoning?.length ?? 0);
}
export function replaceTranscript(state, transcript) {
    const deduped = dedupeTranscriptById(transcript);
    return {
        ...state,
        transcript: deduped,
        reconciliation: {
            ...state.reconciliation,
            seenMessageIds: collectMessageIds(deduped),
        },
    };
}
export function reconcileServerUserMessage(state, echo) {
    const normalizedId = echo.messageId.toLowerCase();
    const transcript = applyServerUserMessageToTranscript(state.transcript, echo);
    return {
        ...state,
        transcript,
        reconciliation: {
            ...state.reconciliation,
            seenMessageIds: addUnique(state.reconciliation.seenMessageIds, normalizedId),
        },
    };
}
export function applyServerUserMessageToTranscript(transcript, echo) {
    const normalizedId = echo.messageId.toLowerCase();
    if (transcript.some((message) => message.id?.toLowerCase() === normalizedId)) {
        return transcript;
    }
    const serverMessage = {
        id: echo.messageId,
        agentId: echo.agentId,
        messageIndex: -1,
        role: "user",
        content: echo.content,
        name: echo.userName || "user",
        messageType: "user",
        isCompleted: true,
        model: "",
        tokensUsed: 0,
        inputTokens: 0,
        outputTokens: 0,
        cachedInputTokens: 0,
        inputTokenCost: 0,
        outputTokenCost: 0,
        cachedInputTokenCost: 0,
        totalCost: 0,
        currency: "USD",
        createdDate: echo.timestamp ?? new Date().toISOString(),
        toolCalls: [],
        ...(echo.attachments?.length ? { attachments: echo.attachments } : {}),
        ...(echo.messageOrigin ? { messageOrigin: echo.messageOrigin } : {}),
        ...(echo.triggerName ? { triggerName: echo.triggerName } : {}),
        ...(echo.sourceAgentName || echo.sourceAgent?.name
            ? {
                sourceAgentName: echo.sourceAgentName || echo.sourceAgent?.name,
            }
            : {}),
    };
    const tempIndex = findOptimisticUserMessageIndex(transcript, echo);
    return tempIndex === -1
        ? [...transcript, { ...serverMessage, messageIndex: transcript.length }]
        : transcript.map((message, index) => index === tempIndex
            ? { ...serverMessage, messageIndex: index }
            : message);
}
export function applyRunStart(state, input = {}) {
    if (state.run.stopGuardActive) {
        return state;
    }
    const runId = normalizeSessionRunId(input.runId);
    if (runId && state.run.lastSettledRunId === runId) {
        return state;
    }
    if (runId && state.run.currentRunId === runId) {
        return state;
    }
    const currentStatus = state.agent?.status;
    const shouldPreserveAttentionState = currentStatus === "waitingForInput" ||
        currentStatus === "waitingForApproval" ||
        currentStatus === "costLimitReached";
    const nextAgent = state.agent && !shouldPreserveAttentionState
        ? {
            ...state.agent,
            status: "running",
            ...(input.agentName ? { name: input.agentName } : {}),
            ...(input.profileId ? { profileId: input.profileId } : {}),
            ...(input.profileName ? { profileName: input.profileName } : {}),
        }
        : state.agent;
    return {
        ...state,
        agent: nextAgent,
        run: {
            ...state.run,
            currentRunId: runId ?? state.run.currentRunId,
            lastSeq: runId ? 0 : state.run.lastSeq,
            status: shouldPreserveAttentionState ? state.run.status : "running",
            lastStatusReason: null,
            isConnecting: shouldPreserveAttentionState
                ? state.run.isConnecting
                : true,
            isWaitingForResponse: shouldPreserveAttentionState
                ? state.run.isWaitingForResponse
                : true,
            isAgentThinking: shouldPreserveAttentionState
                ? state.run.isAgentThinking
                : true,
        },
        reconciliation: {
            ...state.reconciliation,
            seenMessageIds: collectMessageIds(state.transcript),
        },
    };
}
export function shouldAcceptRunFrame(state, input) {
    const runId = normalizeSessionRunId(input.runId);
    if (runId &&
        state.run.currentRunId !== null &&
        runId !== state.run.currentRunId) {
        return false;
    }
    if (runId && state.run.lastSettledRunId === runId) {
        return false;
    }
    const seq = typeof input.seq === "number" ? input.seq : null;
    if (seq !== null && seq <= state.run.lastSeq) {
        return false;
    }
    return true;
}
export function acceptRunFrame(state, input) {
    if (!shouldAcceptRunFrame(state, input))
        return state;
    const runId = normalizeSessionRunId(input.runId);
    const seq = typeof input.seq === "number" ? input.seq : null;
    return {
        ...state,
        run: {
            ...state.run,
            currentRunId: runId ?? state.run.currentRunId,
            lastSeq: seq !== null ? seq : state.run.lastSeq,
        },
    };
}
export function applyRunStatus(state, status, reason = null) {
    return {
        ...state,
        agent: state.agent ? { ...state.agent, status } : state.agent,
        run: {
            ...state.run,
            status,
            lastStatusReason: reason,
            isConnecting: status === "running" ? state.run.isConnecting : false,
            isWaitingForResponse: status === "running",
            isAgentThinking: status === "running",
        },
    };
}
export function armStopGuard(state) {
    return {
        ...state,
        agent: state.agent
            ? { ...state.agent, status: "idle", statusMessage: undefined }
            : state.agent,
        queuedPrompts: [],
        transcript: state.transcript.map((message) => !message.isCompleted && message.messageType === "streaming"
            ? { ...message, isCompleted: true, messageType: "completed" }
            : message),
        run: {
            ...state.run,
            status: "idle",
            stopGuardActive: true,
            isWaitingForResponse: false,
            isConnecting: false,
            isSubmitting: false,
            isAgentThinking: false,
        },
    };
}
export function clearStopGuard(state) {
    return {
        ...state,
        run: {
            ...state.run,
            stopGuardActive: false,
        },
    };
}
export function settleCompletedRun(state, input = {}) {
    const runId = normalizeSessionRunId(input.runId);
    if (runId && state.run.lastSettledRunId === runId) {
        return state;
    }
    if (runId &&
        state.run.currentRunId !== null &&
        state.run.currentRunId !== runId) {
        return state;
    }
    return {
        ...state,
        error: null,
        agent: state.agent
            ? {
                ...state.agent,
                status: "idle",
                statusMessage: input.finalStatus === "cancelled" ? "Run cancelled" : undefined,
            }
            : state.agent,
        transcript: state.transcript.map((message) => message.role === "assistant" && !message.isCompleted
            ? { ...message, isCompleted: true, messageType: "completed" }
            : message),
        run: {
            ...state.run,
            lastSettledRunId: runId ?? state.run.lastSettledRunId,
            lastStatusReason: null,
            stopGuardActive: false,
            status: "idle",
            isWaitingForResponse: false,
            isConnecting: false,
            isSubmitting: false,
            isAgentThinking: false,
        },
    };
}
export function applyQueuedPromptAdded(state, queueEntry) {
    if (state.queuedPrompts.some((prompt) => prompt.id === queueEntry.id)) {
        return state;
    }
    return {
        ...state,
        queuedPrompts: [...state.queuedPrompts, queueEntry],
    };
}
export function applyQueuedPromptProcessed(state, promptId) {
    return {
        ...state,
        queuedPrompts: state.queuedPrompts.filter((prompt) => prompt.id !== promptId),
    };
}
export function replaceQueuedPrompts(state, queuedPrompts) {
    return {
        ...state,
        queuedPrompts,
    };
}
export function applyOperationHistory(state, operations, limit = AGENT_HISTORY_LIMIT) {
    return {
        ...state,
        operationHistory: mergeAgentOperationHistory(state.operationHistory, operations, limit),
    };
}
export function replaceOperationHistory(state, operationHistory) {
    return {
        ...state,
        operationHistory,
    };
}
export function applyToolApprovalsRequired(state, input) {
    return {
        ...state,
        transcript: applyToolApprovalsRequiredToTranscript(state.transcript, input),
        run: {
            ...state.run,
            status: "waitingForApproval",
            lastStatusReason: null,
            isConnecting: false,
            isWaitingForResponse: false,
            isAgentThinking: false,
        },
    };
}
export function applyToolApprovalResolved(state, resolution) {
    return {
        ...state,
        transcript: applyToolApprovalResolvedToTranscript(state.transcript, resolution),
        run: {
            ...state.run,
            isWaitingForResponse: true,
            isAgentThinking: true,
        },
    };
}
export function applyToolApprovalResolvedToTranscript(transcript, resolution) {
    return transcript.map((message) => {
        const toolCalls = message.toolCalls ?? [];
        if (!toolCalls.some((toolCall) => toolCall.toolCallId === resolution.toolCallId)) {
            return message;
        }
        const updatedToolCalls = toolCalls.map((toolCall) => {
            if (toolCall.toolCallId !== resolution.toolCallId)
                return toolCall;
            const base = (toolCall.functionName || "")
                .replace(" (pending approval)", "")
                .replace(" (approved)", "")
                .replace(" (rejected)", "");
            return {
                ...toolCall,
                functionName: `${base}${resolution.approved ? " (approved)" : " (rejected)"}`,
                isCompleted: true,
                ...(resolution.approved ? {} : { functionError: "REJECTED" }),
            };
        });
        const allToolCallsCompleted = updatedToolCalls.length > 0 &&
            updatedToolCalls.every((toolCall) => toolCall.isCompleted);
        return {
            ...message,
            toolCalls: updatedToolCalls,
            ...(allToolCallsCompleted &&
                !message.isCompleted &&
                message.messageType === "streaming"
                ? { isCompleted: true, messageType: "completed" }
                : {}),
        };
    });
}
function mergeSnapshotTranscript(state, agent) {
    const dbMessages = agent.messages ?? [];
    const dbMessageIds = new Set(dbMessages
        .map((message) => message.id?.toLowerCase())
        .filter((id) => !!id));
    const localPendingUserMessages = state.transcript.filter((message) => message.role === "user" &&
        message.isCompleted &&
        !!message.id &&
        message.id.startsWith("temp-") &&
        !dbMessageIds.has(message.id.toLowerCase()));
    const hasLocalUserMessage = state.transcript.some((message) => message.role === "user");
    const hasActiveLocalRun = state.run.status === "running" || state.agent?.status === "running";
    const serverReturnedRunning = isRunningStatus(agent.status);
    if (!serverReturnedRunning &&
        hasActiveLocalRun &&
        (localPendingUserMessages.length > 0 ||
            (dbMessages.length === 0 && hasLocalUserMessage))) {
        return state.transcript;
    }
    return [...dbMessages, ...localPendingUserMessages];
}
function findOptimisticUserMessageIndex(messages, echo) {
    if (echo.clientMessageId) {
        const index = messages.findIndex((message) => message.id === echo.clientMessageId && message.role === "user");
        if (index !== -1)
            return index;
    }
    return messages.findIndex((message) => message.id?.startsWith("temp-") &&
        message.role === "user" &&
        message.content === echo.content);
}
function rememberSeenMessageId(state, messageId) {
    return {
        ...state,
        reconciliation: {
            ...state.reconciliation,
            seenMessageIds: addUnique(state.reconciliation.seenMessageIds, messageId),
        },
    };
}
function collectMessageIds(messages) {
    return messages
        .map((message) => message.id?.toLowerCase())
        .filter((id) => !!id);
}
function addUnique(values, value) {
    return values.includes(value) ? values : [...values, value];
}
function isRunningStatus(status) {
    return status === "running" || status === 1;
}
function stringifySessionToolField(value) {
    if (typeof value === "string")
        return value;
    if (value == null)
        return "";
    try {
        return JSON.stringify(value);
    }
    catch {
        return String(value);
    }
}
//# sourceMappingURL=agentSessionState.js.map