import { SpanKind, SpanStatusCode } from '../types.js';
/**
 * Start a turn lifecycle span.
 *
 * The returned Span should be stored and ended when the turn resolves
 * via `endTurnSpan`.
 *
 * @param tracer - RuntimeTracer instance.
 * @param ctx - Turn context from TURN_SUBMITTED event.
 */
export function startTurnSpan(tracer, ctx) {
    const attrs = {
        'turn.id': ctx.turnId,
        'session.id': ctx.sessionId,
        // Truncate prompt to avoid large attribute values
        'turn.prompt': ctx.prompt.length > 256 ? ctx.prompt.slice(0, 256) + '...' : ctx.prompt,
    };
    return tracer.startSpan('turn.lifecycle', {
        traceId: ctx.traceId,
        kind: SpanKind.INTERNAL,
        attributes: attrs,
    });
}
/**
 * End a turn lifecycle span with outcome context.
 *
 * @param span - The span returned by `startTurnSpan`.
 * @param ctx - Turn end context.
 */
export function endTurnSpan(span, ctx) {
    if (span.ended)
        return;
    span.addEvent(`turn.${ctx.outcome}`);
    span.setAttribute('turn.outcome', ctx.outcome);
    if (ctx.tokens) {
        span.setAttributes({
            'turn.tokens.input': ctx.tokens.input,
            'turn.tokens.output': ctx.tokens.output,
            'turn.tokens.cache_read': ctx.tokens.cacheRead ?? 0,
        });
    }
    if (ctx.outcome === 'error' && ctx.error) {
        span.setStatus({ code: SpanStatusCode.ERROR, message: ctx.error });
        span.setAttribute('turn.error', ctx.error);
    }
    else if (ctx.outcome === 'cancelled') {
        span.setStatus({ code: SpanStatusCode.OK });
        if (ctx.cancelReason) {
            span.setAttribute('turn.cancel_reason', ctx.cancelReason);
        }
    }
    else {
        span.setStatus({ code: SpanStatusCode.OK });
    }
    span.end();
}
