import { ensureAgentLoaded } from "./agent-loading.js";
export function startAgentRun(agentManager, agentId, prompt, logger, options) {
    // Out-of-band commands (e.g. /goal pause) must run WITHOUT canceling an
    // in-flight turn — replaceAgentRun would interrupt the running turn. The
    // intercept lives at this layer so it covers every prompt entrypoint.
    if (agentManager.tryRunOutOfBand(agentId, prompt)) {
        return { outOfBand: true };
    }
    const shouldReplace = Boolean(options?.replaceRunning && agentManager.hasInFlightRun(agentId));
    const runOptions = options?.runOptions;
    const iterator = shouldReplace
        ? agentManager.replaceAgentRun(agentId, prompt, runOptions)
        : agentManager.streamAgent(agentId, prompt, runOptions);
    void (async () => {
        try {
            for await (const _ of iterator) {
                // Events are broadcast via AgentManager subscribers.
            }
        }
        catch (error) {
            logger.error({ err: error, agentId }, "Agent stream failed");
        }
    })();
    return { outOfBand: false };
}
/**
 * Clear the archived flag from a stored agent record.
 * Shared across Session (app/WS), MCP, and CLI so every surface that acts on
 * an archived agent unarchives it the same way.
 */
export async function unarchiveAgentState(agentStorage, agentManager, agentId) {
    const record = await agentStorage.get(agentId);
    if (!record || !record.archivedAt) {
        return false;
    }
    const updatedAt = new Date().toISOString();
    await agentStorage.upsert({
        ...record,
        archivedAt: null,
        updatedAt,
    });
    agentManager.notifyAgentState(agentId);
    return true;
}
/**
 * Wrap a body in <paseo-system>…</paseo-system> so the receiving agent
 * recognizes the prompt as system-injected context — not a user turn.
 * Used by chat mentions, schedule fires, and notify-on-finish.
 */
export function formatSystemNotificationPrompt(reason) {
    return `<paseo-system>\n${reason}\n</paseo-system>`;
}
/**
 * Full send-prompt orchestration: (optional unarchive) → load → (optional
 * mode change) → (optional record user message) → start run.
 *
 * Every surface that sends a prompt to an agent (Session/WS, MCP, CLI-through-MCP,
 * chat mentions, notify-on-finish) MUST go through this so behavior can never
 * drift between them.
 *
 * When `unarchive` is false and the agent is archived, the call is a silent
 * no-op (returns `{ outOfBand: false }`) — the agent is not run.
 */
export async function sendPromptToAgent(params) {
    const unarchive = params.unarchive ?? true;
    const recordUserMessage = params.recordUserMessage ?? true;
    if (recordUserMessage && params.userMessageText === undefined) {
        throw new Error("userMessageText is required when recordUserMessage is true");
    }
    const record = await params.agentStorage.get(params.agentId);
    if (record?.archivedAt) {
        if (!unarchive) {
            return { outOfBand: false };
        }
        await unarchiveAgentState(params.agentStorage, params.agentManager, params.agentId);
    }
    await ensureAgentLoaded(params.agentId, {
        agentManager: params.agentManager,
        agentStorage: params.agentStorage,
        logger: params.logger,
    });
    if (params.sessionMode) {
        await params.agentManager.setAgentMode(params.agentId, params.sessionMode);
    }
    if (recordUserMessage && params.userMessageText !== undefined) {
        try {
            params.agentManager.recordUserMessage(params.agentId, params.userMessageText, {
                messageId: params.messageId,
                emitState: false,
            });
        }
        catch (error) {
            params.logger.error({ err: error, agentId: params.agentId }, "Failed to record user message");
        }
    }
    return startAgentRun(params.agentManager, params.agentId, params.prompt, params.logger, {
        replaceRunning: true,
        runOptions: params.runOptions,
    });
}
export function setupFinishNotification(params) {
    const { agentManager, agentStorage, childAgentId, callerAgentId, logger } = params;
    let hasSeenRunning = false;
    let fired = false;
    let unsubscribe = null;
    async function notify(reason) {
        if (fired) {
            return;
        }
        fired = true;
        unsubscribe?.();
        const title = agentManager.getAgent(childAgentId)?.config?.title ?? childAgentId;
        const body = `Agent ${childAgentId} (${title}) ${reason}.`;
        await sendPromptToAgent({
            agentManager,
            agentStorage,
            agentId: callerAgentId,
            prompt: formatSystemNotificationPrompt(body),
            unarchive: false,
            recordUserMessage: false,
            logger,
        });
    }
    unsubscribe = agentManager.subscribe((event) => {
        if (fired) {
            return;
        }
        if (event.type === "agent_state") {
            if (event.agent.lifecycle === "running") {
                hasSeenRunning = true;
                return;
            }
            if (event.agent.lifecycle === "error") {
                void notify("errored");
                return;
            }
            if (event.agent.lifecycle === "idle" && hasSeenRunning) {
                void notify("finished");
                return;
            }
            if (event.agent.lifecycle === "closed") {
                fired = true;
                unsubscribe?.();
                return;
            }
            return;
        }
        if (event.event.type === "permission_requested") {
            void notify("needs permission");
        }
    }, { agentId: childAgentId, replayState: false });
    // Check if the child is already running (catches the case where
    // the lifecycle flipped before our subscribe call was processed).
    // Do NOT treat an immediate "idle" as "finished" — the agent may
    // not have started yet (streamAgent sets a pending run before
    // transitioning to "running").
    const childSnapshot = agentManager.getAgent(childAgentId);
    if (!childSnapshot || childSnapshot.lifecycle === "closed") {
        unsubscribe();
        return;
    }
    if (childSnapshot.lifecycle === "running") {
        hasSeenRunning = true;
    }
    else if (childSnapshot.lifecycle === "error") {
        void notify("errored");
    }
}
//# sourceMappingURL=agent-prompt.js.map