import { RuntimePersistence } from './persistence.js';
/** Returns an `AgentLoopEvent` handler with a stable internal turn counter. */
export function createAgentEventFunnel(options) {
    const persistence = new RuntimePersistence();
    const messageEntryIds = [];
    persistence.setCallbacks({
        onMessagePersisted: (entryId) => messageEntryIds.push(entryId)
    });
    let turnIndex = 0;
    const handleAgentStart = () => {
        turnIndex = 0;
        if (options.onAgentStart) {
            try {
                options.onAgentStart();
            }
            catch (err) {
                console.warn('[embedded-runtime] onAgentStart threw:', err);
            }
        }
        persistence.startInvocation(options.sessionStore, options.agent.state.systemPrompt, options.agent.state.tools.map((tool) => ({
            name: tool.name,
            description: tool.description,
            parameters: tool.parameters
        })));
    };
    const handleAgentEnd = () => {
        void options.compactionWiring.triggerIfNeeded(true).catch((err) => {
            console.warn('[embedded-runtime] post-turn compaction failed:', err);
        });
        // Always fire `onAgentEnd` (run-boundary update hook) — used by the
        // credit gate, which must update its disposition regardless of
        // whether the run succeeded, errored, or aborted.
        if (options.onAgentEnd) {
            try {
                options.onAgentEnd();
            }
            catch (err) {
                console.warn('[embedded-runtime] onAgentEnd threw:', err);
            }
        }
        // Fire suggestions only when the turn ended cleanly. `errorKind` is
        // set by `agent-runtime.ts` on classified failures and cleared on
        // the next prompt, so reading it at agent_end is the simplest
        // "did we just complete?" signal that doesn't depend on the
        // stop-reason mapping pipeline downstream.
        if (options.onAgentEndSuccess && options.agent.state.errorKind === undefined) {
            try {
                options.onAgentEndSuccess();
            }
            catch (err) {
                console.warn('[embedded-runtime] onAgentEndSuccess threw:', err);
            }
        }
    };
    return {
        handle(event) {
            if (event.type === 'message_end') {
                persistence.handle(event, options.sessionStore, turnIndex);
                options.runStatsAccumulator.handle(event);
                return;
            }
            options.runStatsAccumulator.handle(event);
            if (event.type === 'agent_start') {
                handleAgentStart();
                return;
            }
            persistence.handle(event, options.sessionStore, turnIndex);
            if (event.type === 'turn_end')
                turnIndex += 1;
            if (event.type === 'agent_end')
                handleAgentEnd();
        },
        getMessageEntryIds: () => messageEntryIds,
        truncateMessageEntryIds(keep) {
            if (keep < messageEntryIds.length)
                messageEntryIds.length = keep;
        },
        seedMessageEntryIds(ids) {
            messageEntryIds.length = 0;
            for (const id of ids)
                messageEntryIds.push(id);
        },
        appendCustomBoundaryMessage(message) {
            options.agent.appendMessage(message);
            const entryId = options.sessionStore.appendCustomMessageEntry(message.customType, message.content, message.display, message.details, new Date(message.timestamp).toISOString());
            messageEntryIds.push(entryId);
            return entryId;
        },
        assertAlignedWith(expectedLength) {
            if (messageEntryIds.length !== expectedLength) {
                throw new Error(`Funnel/messages drift: messageEntryIds.length=${messageEntryIds.length}, expected=${expectedLength}`);
            }
        }
    };
}
//# sourceMappingURL=agent-event-funnel.js.map