/** * What happened, in order, with timings — the record a session needs to be inspectable. * * KONECK kept only the message list. That is enough to resume a conversation and useless for * answering the questions people actually ask afterwards: where did twenty-five minutes go, which * tool was slow, how long was it waiting for the first token rather than generating, what was it * thinking before that edit. Every one of those was visible while it scrolled past and gone * afterwards. * * The DeepSeek Harness records this properly and its trajectory view is the reason you can answer * those questions there. This is the same idea at the scale a terminal can show: an append-only * list of typed events with durations, written alongside the messages in the session file. */ export type TrajectoryEvent = /** A turn began. */ /** * A turn began, and what was spent before its request went out. * * `prepMs` exists because a real session could not be accounted for: 48 minutes of wall clock * against 14.5 in the model and 16.1 in tools, and thirteen unexplained. The parts that are * measured are measured; the rest was invisible, so the answer to "where did the time go" was a * subtraction rather than a reading. Now the gap between a turn opening and its request leaving * is recorded as itself. */ { t: 'turn'; at: number; turn: number; prepMs?: number; } /** * One request to the model. * * `ttftMs` is time to first token — the wait before anything came back — kept apart from the * total because they have completely different causes. A slow first token is the provider * queueing or the prompt being large; slow generation after that is the model itself. */ | { t: 'request'; at: number; ms: number; ttftMs: number; promptTokens: number; completionTokens: number; } /** Reasoning arrived, and how much of it. */ | { t: 'thinking'; at: number; chars: number; } /** One tool call, with how long it took and whether it worked. */ | { t: 'tool'; at: number; name: string; ms: number; ok: boolean; detail: string; resultChars: number; } /** The conversation was summarised to fit. */ | { t: 'compact'; at: number; before: number; after: number; } /** The run stopped for a stated reason rather than finishing. */ | { t: 'stop'; at: number; reason: string; }; /** Bounded, because a long session should not be able to fill the disk with its own diary. */ export declare const MAX_EVENTS = 5000; export declare class Trajectory { private readonly events; add(event: TrajectoryEvent): void; all(): readonly TrajectoryEvent[]; get length(): number; } /** Totals worth knowing about a whole session, derived rather than tracked separately. */ export interface TrajectorySummary { turns: number; requests: number; modelMs: number; toolMs: number; waitingMs: number; promptTokens: number; completionTokens: number; slowestTool?: { name: string; ms: number; }; failedTools: number; compactions: number; thinkingChars: number; } export declare function summarise(events: readonly TrajectoryEvent[]): TrajectorySummary; /** * The trajectory as a person reads it: where the time went, then the events themselves. * * The totals come first because they answer the question that prompted the look. "Twenty-five * minutes, of which nineteen were waiting for first tokens" is the answer; the event list is the * evidence for it. */ export declare function renderTrajectory(events: readonly TrajectoryEvent[], limit?: number): string; //# sourceMappingURL=trajectory.d.ts.map