export function createRuntimeFrameEmbedder(options) {
    return {
        async embed(frame) {
            return options.embedText(formatRuntimeFrameForEmbedding(frame, options), frame);
        },
    };
}
export function formatRuntimeFrameForEmbedding(frame, options = {}) {
    const maxTextLength = options.maxTextLength ?? 4_000;
    const sections = [
        `kind: ${frame.kind}`,
        frame.tool ? `tool: ${frame.tool}` : undefined,
        typeof frame.ok === 'boolean' ? `ok: ${frame.ok}` : undefined,
        options.includeGoal ? `goal: ${frame.goal}` : undefined,
        '',
        frame.text,
    ].filter((section) => section !== undefined);
    return sections.join('\n').slice(0, maxTextLength);
}
export function createCyberLoopObserver(options) {
    let queue = Promise.resolve();
    let runId;
    let goal = '';
    let initialized = false;
    let previousFrame;
    let observedFrameKeys = new Set();
    const enqueue = (work) => {
        queue = queue.then(work, work).catch((error) => {
            options.onError?.(error);
        });
    };
    const setup = async (event) => {
        runId = event.runId;
        goal = event.goal;
        previousFrame = undefined;
        observedFrameKeys = new Set();
        initialized = true;
        for (const middleware of options.middleware) {
            await middleware.setup?.({ input: event });
        }
        const baselineFrame = options.baselineFrame?.(event);
        if (baselineFrame) {
            await observeFrame(baselineFrame, { annotate: false });
        }
    };
    const teardown = async (reason) => {
        if (!initialized) {
            return;
        }
        for (const middleware of options.middleware) {
            await middleware.teardown?.({ reason });
        }
        initialized = false;
    };
    const observeFrame = async (frame, observeOptions = {}) => {
        if (!initialized) {
            initialized = true;
            runId = frame.runId;
            goal = frame.goal;
            for (const middleware of options.middleware) {
                await middleware.setup?.({ input: frame.rawEvent });
            }
        }
        if (options.shouldObserveFrame && !options.shouldObserveFrame(frame)) {
            return;
        }
        const frameKey = runtimeFrameKey(frame);
        if (observedFrameKeys.has(frameKey)) {
            return;
        }
        observedFrameKeys.add(frameKey);
        let ctx = {
            step: frame.step,
            state: frame,
            prevState: previousFrame,
            budget: { used: frame.step, remaining: Number.POSITIVE_INFINITY },
            metadata: {},
        };
        let requestedHalt = false;
        for (const middleware of options.middleware) {
            const next = await middleware.beforeStep?.(ctx);
            if (next === 'halt') {
                requestedHalt = true;
                break;
            }
            if (next) {
                ctx = next;
            }
        }
        const result = {
            state: frame,
            action: frame.kind,
            feedback: frame.ok,
            cost: 1,
        };
        for (let i = options.middleware.length - 1; i >= 0; i--) {
            await options.middleware[i]?.afterStep?.(ctx, result);
        }
        previousFrame = frame;
        if (observeOptions.annotate !== false) {
            options.onAnnotation?.({
                runId: frame.runId,
                step: frame.step,
                frame,
                metadata: ctx.metadata,
                driftLevel: inferDriftLevel(ctx.metadata),
                requestedHalt,
                timestamp: new Date().toISOString(),
            });
        }
    };
    return {
        handleEvent(event) {
            enqueue(async () => {
                if (event.type === 'loop.started') {
                    await setup(event);
                    return;
                }
                const frame = eventToRuntimeFrame(event, { runId, goal });
                if (frame) {
                    await observeFrame(frame);
                }
                if (event.type === 'loop.finished') {
                    await teardown(event.outcome);
                }
            });
        },
        flush() {
            return queue;
        },
    };
}
function runtimeFrameKey(frame) {
    return [
        frame.runId,
        frame.step,
        frame.kind,
        frame.tool ?? '',
        frame.ok === undefined ? '' : String(frame.ok),
        frame.text,
    ].join('\u001f');
}
export function eventToRuntimeFrame(event, context = {}) {
    const runId = 'runId' in event ? event.runId : context.runId;
    if (!runId) {
        return undefined;
    }
    const goal = context.goal ?? (event.type === 'loop.started' ? event.goal : '');
    if (event.type === 'assistant.stream' && event.done) {
        return {
            runId,
            step: event.step,
            kind: 'assistant',
            goal,
            text: event.text,
            timestamp: event.timestamp,
            rawEvent: event,
        };
    }
    if (event.type === 'tool.completed') {
        return {
            runId,
            step: event.step,
            kind: 'tool',
            goal,
            text: formatToolCompletedText(event),
            timestamp: event.timestamp,
            tool: event.tool,
            toolCallId: event.toolCallId,
            ok: event.result.ok,
            rawEvent: event,
        };
    }
    if (event.type === 'trace' && event.event.type === 'assistant.turn') {
        return {
            runId,
            step: event.event.step,
            kind: 'assistant',
            goal,
            text: event.event.content,
            timestamp: event.timestamp,
            rawEvent: event,
        };
    }
    if (event.type === 'trace' && event.event.type === 'tool.completed') {
        return {
            runId,
            step: event.event.step,
            kind: 'tool',
            goal,
            text: formatTraceToolResultText(event.event.call.tool, event.event.result),
            timestamp: event.timestamp,
            tool: event.event.call.tool,
            toolCallId: event.event.call.id,
            ok: event.event.result.ok,
            rawEvent: event,
        };
    }
    if (event.type === 'checkpoint.saved') {
        return {
            runId,
            step: event.step,
            kind: 'checkpoint',
            goal,
            text: `Checkpoint saved for ${event.checkpoint.runId}`,
            timestamp: event.timestamp,
            rawEvent: event,
        };
    }
    if (event.type === 'heartbeat.decision') {
        return {
            runId,
            step: 0,
            kind: 'heartbeat',
            goal,
            text: `Heartbeat decision: ${event.decision}. ${event.summary}`,
            timestamp: event.timestamp,
            ok: event.decision !== 'escalate',
            rawEvent: event,
        };
    }
    if (event.type === 'loop.finished') {
        return {
            runId,
            step: event.state.trace.length,
            kind: 'final',
            goal: event.state.goal,
            text: event.summary,
            timestamp: event.timestamp,
            ok: event.outcome === 'done',
            rawEvent: event,
        };
    }
    return undefined;
}
export function inferDriftLevel(metadata) {
    const manifold = metadata.manifold;
    const grassmannian = metadata.grassmannian;
    const kinematics = metadata.kinematics;
    const hasCorrection = metadata.kinematicsCorrection != null;
    if (manifold?.isDrifting === true || grassmannian?.isDrifting === true) {
        return 'high';
    }
    if (kinematics?.isStable === false || hasCorrection) {
        return 'medium';
    }
    if (manifold || grassmannian || kinematics) {
        return 'low';
    }
    return 'unknown';
}
function formatToolCompletedText(event) {
    if (!event.result.ok) {
        return `Tool ${event.tool} failed: ${event.result.error ?? 'unknown error'}`;
    }
    const output = event.result.output;
    if (typeof output === 'string') {
        return `Tool ${event.tool} completed: ${output.slice(0, 1_000)}`;
    }
    return `Tool ${event.tool} completed: ${JSON.stringify(output).slice(0, 1_000)}`;
}
function formatTraceToolResultText(tool, result) {
    if (!result.ok) {
        return `Tool ${tool} failed: ${result.error ?? 'unknown error'}`;
    }
    if (typeof result.output === 'string') {
        return `Tool ${tool} completed: ${result.output.slice(0, 1_000)}`;
    }
    return `Tool ${tool} completed: ${JSON.stringify(result.output).slice(0, 1_000)}`;
}
//# sourceMappingURL=cyberloop.js.map