import { describe, expect, it } from 'vitest'; import { filterOpsForGrade, isAppendOnly, redactSnapshotForGrade } from '#/granularity/filterOps'; import { detachGrades, gradeFor, needsResetOnTransition } from '#/granularity/grade'; import { paginateTurns } from '#/pagination/paginate'; import { ViewRegistry } from '#/view/registry'; import { projectTranscriptUserOrigin } from '#/contract/origin'; import { groupMessagesIntoSnapshot, type HistoryContentPart } from '#/history/groupTurns'; import { foldWireRecordFacts, type HistoryWireRecord } from '#/history/foldFacts'; import { transcriptOperationSchema, transcriptQuerySchema, transcriptResponseSchema, transcriptGradeSpecSchema, transcriptUserOriginSchema, } from '#/contract/schema'; import type { TranscriptItem } from '#/model/item'; import type { AgentTranscriptSnapshot, TranscriptOperation } from '#/ops/operation'; const idLabel = (i: TranscriptItem): string => i.kind === 'turn' ? i.turnId : i.kind === 'marker' ? i.markerId : i.refId; describe('client metadata in transcript user origins', () => { it('retains user-invoked single skill frame metadata without exposing model-triggered activations as user input', () => { const origin = { kind: 'skill_activation', trigger: 'user-slash', skillName: 'example-skill', skillArgs: 'args', clientMetadata: [{ display_text: 'Save button' }] }; expect(transcriptUserOriginSchema.parse(projectTranscriptUserOrigin(origin))).toEqual(origin); expect(projectTranscriptUserOrigin({ ...origin, trigger: 'model-tool' })).toBeUndefined(); }); it('rebuilds a user turn payload without server-local paths', () => { const clientMetadata = [{ display_text: 'Visible prompt' }]; const origin = { kind: 'user', clientMetadata, skillActivations: [{ activationId: 'a1', skillName: 'deploy', skillArgs: 'now', skillPath: '/private/deploy/SKILL.md' }], attachments: [{ name: 'notes.pdf', mediaType: 'application/pdf', size: 42, path: '/private/notes.pdf' }], }; const snapshot = groupMessagesIntoSnapshot([ { role: 'user', content: [{ type: 'text', text: 'rendered skill' }, { type: 'text', text: 'visible prompt' }], toolCalls: [], origin }, { role: 'assistant', content: [{ type: 'text', text: 'reply' }], toolCalls: [] }, ]); const turn = snapshot.items.find((item) => item.kind === 'turn'); expect(turn?.origin).toEqual({ kind: 'user', payload: { kind: 'user', clientMetadata, skillActivations: [{ skillName: 'deploy', skillArgs: 'now' }] } }); expect(JSON.stringify(turn)).not.toContain('/private/'); expect(JSON.stringify(snapshot.attachments)).not.toContain('/private/'); }); it('keeps opening prompt metadata when rebuilding history turns', () => { const clientMetadata = [{ kimi_code_composer: { version: 1, doc: { type: 'doc' } } }]; const origin = { kind: 'user', clientMetadata }; const snapshot = groupMessagesIntoSnapshot([ { role: 'user', content: [{ type: 'text', text: 'visible prompt' }], toolCalls: [], origin }, { role: 'assistant', content: [{ type: 'text', text: 'reply' }], toolCalls: [] }, ]); const turn = snapshot.items.find((item) => item.kind === 'turn'); expect(turn?.origin).toEqual({ kind: 'user', payload: { kind: 'user', clientMetadata } }); expect(turn?.prompt).toBe('visible prompt'); }); it('projects and validates independent document snapshots without losing their nested fields', () => { const clientMetadata = [ { kimi_code_composer: { version: 1, doc: { type: 'doc', content: [{ type: 'paragraph' }] }, captureIds: ['capture-a'] } }, { kimi_code_composer: { version: 1, captureIds: ['capture-b'] } }, ]; const projected = projectTranscriptUserOrigin({ kind: 'user', clientMetadata }); expect(transcriptUserOriginSchema.parse(projected)).toEqual({ kind: 'user', clientMetadata }); expect(projectTranscriptUserOrigin({ kind: 'user' })).toStrictEqual({ kind: 'user' }); expect(projectTranscriptUserOrigin({ kind: 'injection', clientMetadata })).toBeUndefined(); }); }); describe('user slash skill activations as transcript origins', () => { it('projects a user-invoked activation and rejects a model-triggered one', () => { const origin = { kind: 'skill_activation', trigger: 'user-slash', skillName: 'example-skill', skillArgs: 'args' }; expect(transcriptUserOriginSchema.parse(projectTranscriptUserOrigin(origin))).toEqual(origin); expect(projectTranscriptUserOrigin({ ...origin, trigger: 'model-tool' })).toBeUndefined(); expect(projectTranscriptUserOrigin({ ...origin, skillName: '' })).toBeUndefined(); expect(projectTranscriptUserOrigin({ kind: 'user' })).toStrictEqual({ kind: 'user' }); }); }); const turnOp = (n: number): TranscriptOperation => ({ op: 'turn.upsert', turn: { kind: 'turn', turnId: `t${n}`, ordinal: n, state: 'running', origin: { kind: 'user' } }, }); const stepOp: TranscriptOperation = { op: 'step.upsert', turnId: 't1', step: { kind: 'step', stepId: 't1.1', turnId: 't1', ordinal: 1, state: 'running' }, }; const frameOp: TranscriptOperation = { op: 'frame.upsert', turnId: 't1', stepId: 't1.1', frame: { kind: 'text', frameId: 't1.1.f1', role: 'assistant', text: 'full' }, }; const appendOp: TranscriptOperation = { op: 'append', target: { type: 'frame', turnId: 't1', stepId: 't1.1', frameId: 't1.1.f1' }, offset: 0, text: 'chunk', }; const promptOp: TranscriptOperation = { op: 'prompt.upsert', prompt: { promptId: 'p1', status: 'queued', createdAt: '2026-07-22T00:00:00.000Z' }, }; describe('granularity', () => { const ops: TranscriptOperation[] = [ turnOp(1), stepOp, frameOp, appendOp, promptOp, { op: 'meta.merge', meta: { activity: 'turn' } }, ]; it('off admits nothing', () => { expect(filterOpsForGrade('off', ops)).toEqual([]); }); it('turn admits headers and global state only', () => { expect(filterOpsForGrade('turn', ops).map((op) => op.op)).toEqual([ 'turn.upsert', 'prompt.upsert', 'meta.merge', ]); }); it('block admits step/frame upserts but no appends', () => { expect(filterOpsForGrade('block', ops).map((op) => op.op)).toEqual([ 'turn.upsert', 'step.upsert', 'frame.upsert', 'prompt.upsert', 'meta.merge', ]); }); it('delta admits everything', () => { expect(filterOpsForGrade('delta', ops)).toHaveLength(ops.length); }); it('gradeFor resolves agent override over wildcard default', () => { const spec = { '*': 'turn', main: 'delta' } as const; expect(gradeFor(spec, 'main')).toBe('delta'); expect(gradeFor(spec, 'sub-1')).toBe('turn'); expect(gradeFor(undefined, 'main')).toBe('off'); }); it('upgrade needs reset, downgrade does not', () => { expect(needsResetOnTransition('turn', 'delta')).toBe(true); expect(needsResetOnTransition('delta', 'turn')).toBe(false); }); it('detachGrades writes explicit off so a wildcard default cannot resurrect the agent', () => { expect(detachGrades({ '*': 'delta' }, ['main'])).toEqual({ '*': 'delta', main: 'off' }); expect(detachGrades({ '*': 'delta', main: 'turn' }, ['main'])).toEqual({ '*': 'delta', main: 'off', }); }); it('detachGrades deletes a listed wildcard entry', () => { expect(detachGrades({ '*': 'delta', main: 'turn' }, ['*'])).toEqual({ main: 'turn' }); }); it('detachGrades collapses an all-off spec to undefined', () => { expect(detachGrades({ main: 'delta' }, ['main'])).toBeUndefined(); expect(detachGrades({ '*': 'delta', main: 'off' }, ['*'])).toBeUndefined(); expect(detachGrades(undefined, ['main'])).toBeUndefined(); }); it('append-only batches are volatile-safe', () => { expect(isAppendOnly([appendOp])).toBe(true); expect(isAppendOnly([appendOp, frameOp])).toBe(false); }); it('redactSnapshotForGrade strips step detail below block, keeps it at block+', () => { const snapshot: AgentTranscriptSnapshot = { items: [ { kind: 'turn', turnId: 't1', ordinal: 1, state: 'completed', origin: { kind: 'user' }, prompt: 'hi', steps: [ { kind: 'step', stepId: 't1.1', turnId: 't1', ordinal: 1, state: 'completed', frames: [{ kind: 'text', frameId: 't1.1.f1', role: 'assistant', text: 'body' }], }, ], }, { kind: 'marker', markerId: 'm1', marker: 'skill' }, ], tasks: [], interactions: [ { interactionId: 'appr-1', interactionKind: 'approval' as const, toolCallId: 'c1', state: 'pending' as const, }, ], attachments: [ { attachmentId: 'att_1', mediaType: 'image/png', source: { kind: 'url' as const, url: 'https://example.com/a.png' } }, ], todos: [{ todoId: 'todo', items: [{ title: 'write tests', status: 'in_progress' as const }] }], prompts: [{ promptId: 'p1', status: 'running' as const, createdAt: '2026-07-22T00:00:00.000Z' }], meta: {}, }; const turnGrade = redactSnapshotForGrade('turn', snapshot); expect(turnGrade.interactions).toHaveLength(1); expect(turnGrade.attachments).toHaveLength(1); expect(turnGrade.todos).toHaveLength(1); expect(turnGrade.prompts).toHaveLength(1); const turn = turnGrade.items[0]; expect(turn?.kind === 'turn' && turn.steps).toEqual([]); expect(turn?.kind === 'turn' && turn.prompt).toBe('hi'); expect(turnGrade.items[1]?.kind).toBe('marker'); expect(redactSnapshotForGrade('block', snapshot)).toBe(snapshot); expect(redactSnapshotForGrade('delta', snapshot)).toBe(snapshot); }); }); describe('paginateTurns', () => { const items: TranscriptItem[] = [ { kind: 'marker', markerId: 'm0', marker: 'goal' }, ...[1, 2, 3, 4, 5].flatMap((n): TranscriptItem[] => [ { kind: 'turn', turnId: `t${n}`, ordinal: n, state: 'completed', origin: { kind: 'user' }, steps: [], }, { kind: 'marker', markerId: `m${n}`, marker: 'skill' }, ]), ]; it('default page is the newest N turns with trailing segment items', () => { const page = paginateTurns(items, { pageSize: 2 }); expect(page.items.map(idLabel)).toEqual(['t4', 'm4', 't5', 'm5']); expect(page.hasMore).toBe(true); }); it('before_turn pages toward older turns; head marker rides the oldest segment', () => { const page = paginateTurns(items, { beforeTurn: 't4', pageSize: 2 }); expect(page.items.map(idLabel)).toEqual(['t2', 'm2', 't3', 'm3']); expect(page.hasMore).toBe(true); const oldest = paginateTurns(items, { beforeTurn: 't2', pageSize: 5 }); expect(oldest.items[0]).toEqual({ kind: 'marker', markerId: 'm0', marker: 'goal' }); expect(oldest.hasMore).toBe(false); }); it('after_turn pages toward newer turns without the head unit', () => { const page = paginateTurns(items, { afterTurn: 't3', pageSize: 2 }); expect(page.items.map(idLabel)).toEqual(['t4', 'm4', 't5', 'm5']); expect(page.hasMore).toBe(false); }); it('keeps head non-turn items with the newest page when turns exactly fill it', () => { const page = paginateTurns(items, { pageSize: 5 }); expect(page.items[0]).toEqual({ kind: 'marker', markerId: 'm0', marker: 'goal' }); expect(page.items.map(idLabel)).toEqual(['m0', 't1', 'm1', 't2', 'm2', 't3', 'm3', 't4', 'm4', 't5', 'm5']); expect(page.hasMore).toBe(false); }); it('returns a marker-only timeline as one page with nothing older', () => { const only = paginateTurns([{ kind: 'marker', markerId: 'm0', marker: 'goal' }], { pageSize: 3 }); expect(only.items.map(idLabel)).toEqual(['m0']); expect(only.hasMore).toBe(false); }); }); describe('ViewRegistry', () => { it('dispatches on view ?? name, origin.kind and marker keys', () => { const registry = new ViewRegistry({ fallbackTool: 'generic' }); registry.registerTool('read', 'readRenderer'); registry.registerTool('swarm', 'swarmRenderer'); registry.registerInput('cron', 'cronInput'); registry.registerMarker('goal', 'goalMarker'); expect( registry.resolveTool({ kind: 'tool', frameId: 'f', toolCallId: 'c1', name: 'Read', state: 'done' }), ).toBe('readRenderer'); expect( registry.resolveTool({ kind: 'tool', frameId: 'f', toolCallId: 'c2', name: 'AgentSwarm', view: 'swarm', state: 'running' }), ).toBe('swarmRenderer'); expect( registry.resolveTool({ kind: 'tool', frameId: 'f', toolCallId: 'c3', name: 'Bash', state: 'running' }), ).toBe('generic'); expect(registry.resolveInput({ kind: 'cron' })).toBe('cronInput'); expect(registry.resolveInput({ kind: 'user' })).toBeUndefined(); expect(registry.resolveMarker('goal')).toBe('goalMarker'); }); }); describe('contract schemas', () => { it('roundtrips every op kind', () => { const ops: TranscriptOperation[] = [ { op: 'reset', agentId: 'main', snapshot: { items: [], tasks: [], interactions: [], attachments: [], todos: [], prompts: [], meta: {}, hasMoreOlder: true } }, turnOp(1), stepOp, frameOp, appendOp, { op: 'marker.upsert', item: { kind: 'marker', markerId: 'm1', marker: 'goal' } }, { op: 'taskref.upsert', item: { kind: 'taskref', refId: 'r1', taskId: 'task1' } }, { op: 'task.upsert', task: { taskId: 'task1', kind: 'shell', state: 'running', detached: false, outputTail: '' } }, { op: 'interaction.upsert', interaction: { interactionId: 'appr-1', interactionKind: 'approval', toolCallId: 'c1', state: 'pending' }, }, { op: 'attachment.upsert', attachment: { attachmentId: 'att_1', mediaType: 'image/png', source: { kind: 'file', fileId: 'f1' } }, }, { op: 'todo.upsert', todo: { todoId: 'todo', items: [{ title: 'x', status: 'done' }] } }, promptOp, { op: 'meta.merge', meta: { goal: { objective: 'x', status: 'active' } } }, { op: 'items.remove', ids: ['t1'] }, ]; for (const op of ops) { expect(transcriptOperationSchema.parse(op)).toBeDefined(); } }); it('roundtrips ops carrying the extended wire detail', () => { const usage = { inputOther: 10, output: 5, inputCacheRead: 3, inputCacheCreation: 2 }; const ops: TranscriptOperation[] = [ { op: 'reset', agentId: 'main', snapshot: { items: [], tasks: [], interactions: [], attachments: [], todos: [], prompts: [ { promptId: 'p1', status: 'completed', userMessageId: 'u1', content: [{ type: 'text', text: 'hi' }], createdAt: '2026-07-22T00:00:00.000Z', finishedAt: '2026-07-22T00:01:00.000Z', steeredAt: '2026-07-22T00:00:30.000Z', }, ], meta: { agent: { model: 'k2', thinkingEffort: 'high', usage: { byModel: { k2: usage }, currentTurn: usage, total: usage }, contextTokens: 1234, maxContextTokens: 128000, contextUsage: 0.01, permission: 'auto', phase: { kind: 'retrying', turnId: 1, step: 1, stepId: 't1.1', failedAttempt: 1, nextAttempt: 2, maxAttempts: 3, delayMs: 500, since: 1000 }, }, }, }, }, { op: 'turn.upsert', turn: { kind: 'turn', turnId: 't1', triggerPromptId: 'prompt-1', ordinal: 1, state: 'failed', origin: { kind: 'user' }, usage: { inputTokens: 12, outputTokens: 5, cachedTokens: 3 }, durationMs: 1500, error: 'boom', }, }, { op: 'step.upsert', turnId: 't1', step: { kind: 'step', stepId: 't1.1', turnId: 't1', ordinal: 1, state: 'interrupted', usage, finishReason: 'stop', timing: { llmFirstTokenLatencyMs: 120, llmStreamDurationMs: 900, llmRequestBuildMs: 5, llmServerFirstTokenMs: 110, llmServerDecodeMs: 700, llmClientConsumeMs: 950, llmClientBlockedMs: 25, }, retry: { failedAttempt: 1, nextAttempt: 2, maxAttempts: 3, delayMs: 500, errorName: 'RateLimit', errorMessage: 'slow down', statusCode: 429 }, endReason: 'aborted', endMessage: 'user pressed escape', }, }, { op: 'frame.upsert', turnId: 't1', stepId: 't1.1', frame: { kind: 'tool', frameId: 't1.1.c1', toolCallId: 'c1', name: 'Bash', state: 'running', inputText: '{"command":"ls', progress: { kind: 'progress', text: 'half', percent: 50, customKind: 'bar', customData: { x: 1 } }, }, }, { op: 'task.upsert', task: { taskId: 'task1', kind: 'subagent', state: 'completed', detached: false, outputTail: '', resultSummary: 'scanned 12 files', error: 'partial failure', stateReason: 'waiting for input', usage, }, }, { op: 'meta.merge', meta: { agent: { model: 'k2', phase: { kind: 'ended', turnId: 1, reason: 'completed', durationMs: 1500, at: 2000 } } }, }, ]; for (const op of ops) { expect(transcriptOperationSchema.parse(op)).toEqual(op); } }); it('accepts provenance only on user text frames', () => { const base = { op: 'frame.upsert', turnId: 't1', stepId: 't1.1', } as const; expect(transcriptOperationSchema.safeParse({ ...base, frame: { kind: 'text', frameId: 't1.1.f1', role: 'user', text: 'steered in', origin: { kind: 'user', skillActivations: [{ skillName: 'review', skillArgs: 'strict' }] }, }, }).success).toBe(true); expect(transcriptOperationSchema.safeParse({ ...base, frame: { kind: 'text', frameId: 't1.1.f2', role: 'assistant', text: 'reply', origin: { kind: 'user' }, }, }).success).toBe(false); }); it('rejects mutually exclusive cursors and bad grades', () => { expect(() => transcriptGradeSpecSchema.parse({ '*': 'stream' })).toThrow(); const ok = transcriptResponseSchema.safeParse({ agent_id: 'main', items: [], has_more: false, tasks: [], interactions: [], attachments: [], todos: [], meta: {}, agents: [{ agentId: 'main', type: 'main' }], pending_interactions: [], }); expect(ok.success).toBe(true); }); it('rejects path-hostile agent ids in the transcript query', () => { const base = { agent_id: 'main', before_turn: undefined, after_turn: undefined, page_size: undefined }; expect(transcriptQuerySchema.safeParse({ ...base, agent_id: 'sub-1' }).success).toBe(true); expect(transcriptQuerySchema.safeParse({ ...base, agent_id: '01HF7YAT31J7SMRT1QXGJWKR8D' }).success).toBe(true); for (const hostile of ['../main', '..\\main', '..', 'a/b', 'a\\b', '.', 'a\0b', 'x'.repeat(200)]) { expect(transcriptQuerySchema.safeParse({ ...base, agent_id: hostile }).success).toBe(false); } }); }); describe('groupMessagesIntoSnapshot (cold path)', () => { const snapshotOf = (...parts: HistoryContentPart[]): AgentTranscriptSnapshot => groupMessagesIntoSnapshot([ { role: 'user', content: parts, toolCalls: [], origin: { kind: 'user' } }, ]); it('groups flat messages into turns with folded tool results', () => { const snapshot = groupMessagesIntoSnapshot([ { role: 'system', content: [{ type: 'text', text: 'sys' }] }, { role: 'user', content: [{ type: 'text', text: 'hello' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'think', think: 'hmm' }, { type: 'text', text: 'checking' }], toolCalls: [{ id: 'c1', name: 'Read', arguments: '{"path":"/a"}' }], }, { role: 'tool', content: [{ type: 'text', text: 'file body' }], toolCallId: 'c1', toolCalls: [] }, { role: 'assistant', content: [{ type: 'text', text: 'done' }], toolCalls: [], }, { role: 'user', content: [{ type: 'text', text: 'next' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'user', content: [{ type: 'text', text: 'summary of old' }], toolCalls: [], origin: { kind: 'compaction_summary' }, }, { role: 'user', content: [{ type: 'text', text: 'after' }], toolCalls: [], origin: { kind: 'user' } }, ]); const kinds = snapshot.items.map((i) => i.kind); expect(kinds).toEqual(['turn', 'turn', 'marker', 'turn']); const firstTurn = snapshot.items[0]; if (firstTurn?.kind !== 'turn') throw new Error('expected turn'); expect(firstTurn.prompt).toBe('hello'); expect(firstTurn.steps).toHaveLength(2); const tool = firstTurn.steps[0]?.frames.find((f) => f.kind === 'tool'); expect(tool?.kind === 'tool' && tool.output).toBe('file body'); expect(tool?.kind === 'tool' && tool.input).toEqual({ path: '/a' }); const marker = snapshot.items[2]; expect(marker?.kind === 'marker' && marker.marker).toBe('compaction'); }); it('folds task-notification user messages into the current turn instead of opening their own', () => { const snapshot = groupMessagesIntoSnapshot( [ { role: 'user', content: [{ type: 'text', text: 'run it' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'text', text: 'starting' }], toolCalls: [{ id: 'c1', name: 'Bash', arguments: '{"command":"ls"}' }], }, { role: 'user', content: [{ type: 'text', text: '\nTitle: Background agent completed\nSeverity: info\ninspect done.\n', }], toolCalls: [], origin: { kind: 'task', taskId: 'task-9' } as { kind: string }, }, { role: 'user', content: [{ type: 'text', text: '' }], toolCalls: [], origin: { kind: 'task', taskId: 'task-8' } as { kind: string }, }, { role: 'assistant', content: [{ type: 'text', text: 'continuing' }], toolCalls: [], }, ], { taskOriginTurnTaskIds: new Set() }, ); const turns = snapshot.items.filter((i) => i.kind === 'turn'); expect(turns).toHaveLength(1); const turn = turns[0]; if (turn?.kind !== 'turn') throw new Error('expected turn'); const userFrames = turn.steps .flatMap((step) => step.frames) .filter((f) => f.kind === 'text' && f.role === 'user'); expect(userFrames.map((f) => f.kind === 'text' && f.taskId)).toEqual(['task-9', 'task-8']); expect(userFrames[0]).toMatchObject({ text: 'Background agent completed\ninspect done.' }); const assistantTexts = turn.steps .flatMap((step) => step.frames) .filter((f) => f.kind === 'text' && f.role === 'assistant') .map((f) => f.kind === 'text' && f.text); expect(assistantTexts).toEqual(['starting', 'continuing']); expect(turn.steps).toHaveLength(2); expect(turn.steps[1]?.frames.map((f) => f.kind === 'text' && f.role)).toEqual([ 'user', 'user', 'assistant', ]); }); it('folds a user message whose content matches a turn.steer record into the current turn as a user frame', () => { const snapshot = groupMessagesIntoSnapshot( [ { role: 'user', content: [{ type: 'text', text: 'active' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'text', text: 'working' }], toolCalls: [] }, { role: 'user', content: [{ type: 'text', text: 'steered in' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'text', text: 'noted' }], toolCalls: [] }, ], { steeredContents: new Map([[JSON.stringify([{ type: 'text', text: 'steered in' }]), new Map([['user', 1]])]]) }, ); expect(snapshot.items.map((i) => i.kind)).toEqual(['turn']); const turn = snapshot.items[0]; if (turn?.kind !== 'turn') throw new Error('expected turn'); expect(turn.steps).toHaveLength(2); expect(turn.steps[1]?.frames[0]).toMatchObject({ kind: 'text', role: 'user', text: 'steered in', }); }); it('keeps a trailing steered message visible by appending it to the last step', () => { const snapshot = groupMessagesIntoSnapshot( [ { role: 'user', content: [{ type: 'text', text: 'active' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'text', text: 'working' }], toolCalls: [] }, { role: 'user', content: [{ type: 'text', text: 'steered in' }], toolCalls: [], origin: { kind: 'user' } }, ], { steeredContents: new Map([[JSON.stringify([{ type: 'text', text: 'steered in' }]), new Map([['user', 1]])]]) }, ); expect(snapshot.items.map((i) => i.kind)).toEqual(['turn']); const turn = snapshot.items[0]; if (turn?.kind !== 'turn') throw new Error('expected turn'); const lastStep = turn.steps.at(-1); expect(lastStep?.frames.at(-1)).toMatchObject({ kind: 'text', role: 'user', text: 'steered in', }); }); it('flushes a pending steer into the closing turn when a new turn opens before any reply', () => { const snapshot = groupMessagesIntoSnapshot( [ { role: 'user', content: [{ type: 'text', text: 'active' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'text', text: 'working' }], toolCalls: [] }, { role: 'user', content: [{ type: 'text', text: 'steered in' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'user', content: [{ type: 'text', text: 'next question' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'text', text: 'answer' }], toolCalls: [] }, ], { steeredContents: new Map([[JSON.stringify([{ type: 'text', text: 'steered in' }]), new Map([['user', 1]])]]) }, ); const turns = snapshot.items.filter((i) => i.kind === 'turn'); expect(turns).toHaveLength(2); const first = turns[0]; if (first?.kind !== 'turn') throw new Error('expected turn'); expect(first.steps.at(-1)?.frames.at(-1)).toMatchObject({ kind: 'text', role: 'user', text: 'steered in', }); const second = turns[1]; if (second?.kind !== 'turn') throw new Error('expected turn'); expect(second.prompt).toBe('next question'); }); it('still opens its own turn for a mid-conversation user message unknown to the steer map', () => { const snapshot = groupMessagesIntoSnapshot( [ { role: 'user', content: [{ type: 'text', text: 'active' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'text', text: 'working' }], toolCalls: [] }, { role: 'user', content: [{ type: 'text', text: 'plain follow-up' }], toolCalls: [], origin: { kind: 'user' } }, ], { steeredContents: new Map([[JSON.stringify([{ type: 'text', text: 'steered in' }]), new Map([['user', 1]])]]) }, ); expect(snapshot.items.map((i) => i.kind)).toEqual(['turn', 'turn']); }); it('stops folded notification text before child output blocks', () => { const xml = [ '', 'Title: Background agent completed', 'Severity: info', 'inspect done.', '/tmp/out.log', '/tmp/out.log', 'full output here', '', ].join('\n'); const snapshot = groupMessagesIntoSnapshot( [ { role: 'user', content: [{ type: 'text', text: 'run' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'text', text: 'go' }], toolCalls: [] }, { role: 'user', content: [{ type: 'text', text: xml }], toolCalls: [], origin: { kind: 'task', taskId: 'task-9' } as { kind: string } }, { role: 'assistant', content: [{ type: 'text', text: 'done' }], toolCalls: [] }, ], { taskOriginTurnTaskIds: new Set() }, ); const turn = snapshot.items[0]; if (turn?.kind !== 'turn') throw new Error('expected turn'); const frame = turn.steps.flatMap((step) => step.frames).find((f) => f.kind === 'text' && f.role === 'user'); expect(frame).toMatchObject({ text: 'Background agent completed\ninspect done.' }); }); it('stops folded notification text before an inline answer block', () => { const xml = [ '', 'Title: Background question answered', 'Severity: info', 'The user answered "Which database?".', '', '{"answers":{"Which database?":"Postgres"}}', '', '', ].join('\n'); const snapshot = groupMessagesIntoSnapshot( [ { role: 'user', content: [{ type: 'text', text: 'run' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'text', text: 'go' }], toolCalls: [] }, { role: 'user', content: [{ type: 'text', text: xml }], toolCalls: [], origin: { kind: 'task', taskId: 'question-1' } as { kind: string } }, { role: 'assistant', content: [{ type: 'text', text: 'done' }], toolCalls: [] }, ], { taskOriginTurnTaskIds: new Set() }, ); const turn = snapshot.items[0]; if (turn?.kind !== 'turn') throw new Error('expected turn'); const frame = turn.steps.flatMap((step) => step.frames).find((f) => f.kind === 'text' && f.role === 'user'); expect(frame).toMatchObject({ text: 'Background question answered\nThe user answered "Which database?".' }); }); it('buffers a folded notification that arrives before the first step into that step', () => { const xml = [ '', 'Title: Background agent completed', 'Severity: info', 'early done.', '', ].join('\n'); const snapshot = groupMessagesIntoSnapshot( [ { role: 'user', content: [{ type: 'text', text: 'run' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'user', content: [{ type: 'text', text: xml }], toolCalls: [], origin: { kind: 'task', taskId: 'task-9' } as { kind: string } }, { role: 'assistant', content: [{ type: 'text', text: 'go' }], toolCalls: [] }, ], { taskOriginTurnTaskIds: new Set() }, ); const turn = snapshot.items[0]; if (turn?.kind !== 'turn') throw new Error('expected turn'); expect(turn.steps).toHaveLength(1); expect(turn.steps[0]?.frames.map((f) => f.kind === 'text' && f.role)).toEqual([ 'user', 'assistant', ]); expect(turn.steps[0]?.frames[0]).toMatchObject({ text: 'Background agent completed\nearly done.', taskId: 'task-9', }); }); it('drops a folded notification when no turn is open yet', () => { const snapshot = groupMessagesIntoSnapshot( [ { role: 'user', content: [{ type: 'text', text: '' }], toolCalls: [], origin: { kind: 'task', taskId: 'task-9' } as { kind: string }, }, ], { taskOriginTurnTaskIds: new Set() }, ); expect(snapshot.items).toHaveLength(0); }); it('keeps body lines that start with an angle bracket but are not output blocks', () => { const xml = [ '', 'Title: Background agent completed', 'Severity: info', 'first line.', '
pasted markup
', 'last line.', '
', ].join('\n'); const snapshot = groupMessagesIntoSnapshot( [ { role: 'user', content: [{ type: 'text', text: 'run' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'text', text: 'go' }], toolCalls: [] }, { role: 'user', content: [{ type: 'text', text: xml }], toolCalls: [], origin: { kind: 'task', taskId: 'task-9' } as { kind: string } }, { role: 'assistant', content: [{ type: 'text', text: 'done' }], toolCalls: [] }, ], { taskOriginTurnTaskIds: new Set() }, ); const turn = snapshot.items[0]; if (turn?.kind !== 'turn') throw new Error('expected turn'); const frame = turn.steps.flatMap((step) => step.frames).find((f) => f.kind === 'text' && f.role === 'user'); expect(frame).toMatchObject({ text: 'Background agent completed\nfirst line.\n
pasted markup
\nlast line.', }); }); it('parses only the leading header lines, keeping later Title-like lines as body', () => { const xml = [ '', 'Title: Background agent completed', 'Severity: info', 'first line.', 'Title: details', 'last line.', '', ].join('\n'); const snapshot = groupMessagesIntoSnapshot( [ { role: 'user', content: [{ type: 'text', text: 'run' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'text', text: 'go' }], toolCalls: [] }, { role: 'user', content: [{ type: 'text', text: xml }], toolCalls: [], origin: { kind: 'task', taskId: 'task-9' } as { kind: string } }, { role: 'assistant', content: [{ type: 'text', text: 'done' }], toolCalls: [] }, ], { taskOriginTurnTaskIds: new Set() }, ); const turn = snapshot.items[0]; if (turn?.kind !== 'turn') throw new Error('expected turn'); const frame = turn.steps.flatMap((step) => step.frames).find((f) => f.kind === 'text' && f.role === 'user'); expect(frame).toMatchObject({ text: 'Background agent completed\nfirst line.\nTitle: details\nlast line.', }); }); it('keeps a body whose first line starts with Severity:', () => { const xml = [ '', 'Title: Background agent completed', 'Severity: info', 'Severity: this line is the task description, not a header', 'last line.', '', ].join('\n'); const snapshot = groupMessagesIntoSnapshot( [ { role: 'user', content: [{ type: 'text', text: 'run' }], toolCalls: [], origin: { kind: 'user' } }, { role: 'assistant', content: [{ type: 'text', text: 'go' }], toolCalls: [] }, { role: 'user', content: [{ type: 'text', text: xml }], toolCalls: [], origin: { kind: 'task', taskId: 'task-9' } as { kind: string } }, { role: 'assistant', content: [{ type: 'text', text: 'done' }], toolCalls: [] }, ], { taskOriginTurnTaskIds: new Set() }, ); const turn = snapshot.items[0]; if (turn?.kind !== 'turn') throw new Error('expected turn'); const frame = turn.steps.flatMap((step) => step.frames).find((f) => f.kind === 'text' && f.role === 'user'); expect(frame).toMatchObject({ text: 'Background agent completed\nSeverity: this line is the task description, not a header\nlast line.', }); }); it('expands a bundled prompt into per-skill markers and a caller-text turn', () => { const snapshot = groupMessagesIntoSnapshot([ { role: 'user', content: [ { type: 'text', text: 'rendered review block' }, { type: 'text', text: 'rendered security block' }, { type: 'text', text: 'please /skill:review and /skill:security' }, ], toolCalls: [], origin: { kind: 'user', skillActivations: [ { activationId: 'act-1', skillName: 'review' }, { activationId: 'act-2', skillName: 'security', skillArgs: 'src/app.ts' }, ], } as { kind: string }, }, { role: 'assistant', content: [{ type: 'text', text: 'done' }], toolCalls: [] }, ]); expect(snapshot.items.map((item) => item.kind)).toEqual(['marker', 'marker', 'turn']); const first = snapshot.items[0]; expect(first?.kind === 'marker' && first.marker).toBe('skill'); expect(first?.kind === 'marker' && first.payload).toMatchObject({ text: 'rendered review block', origin: { kind: 'skill_activation', trigger: 'user-slash', skillName: 'review' }, }); const second = snapshot.items[1]; expect(second?.kind === 'marker' && second.payload).toMatchObject({ text: 'rendered security block', origin: { skillName: 'security', skillArgs: 'src/app.ts' }, }); const turn = snapshot.items[2]; if (turn?.kind !== 'turn') throw new Error('expected turn'); expect(turn.prompt).toBe('please /skill:review and /skill:security'); expect(turn.steps).toHaveLength(1); }); it('maps media parts on the opening user message to attachment entities, dropping base64 bytes', () => { const snapshot = groupMessagesIntoSnapshot([ { role: 'user', content: [ { type: 'text', text: 'what is this? [Image #1]' }, { type: 'image', source: { kind: 'base64', media_type: 'image/png', data: 'aGVsbG8=' }, name: 'inline.png' }, { type: 'image', source: { kind: 'url', url: 'https://example.com/pic.png' }, name: 'remote.png' }, { type: 'image', source: { kind: 'file', file_id: 'file_8' }, name: 'stored.png' }, { type: 'file', file_id: 'file_9', name: 'notes.txt', media_type: 'text/plain', size: 128 }, ], toolCalls: [], origin: { kind: 'user' }, }, { role: 'assistant', content: [{ type: 'text', text: 'a screenshot' }], toolCalls: [] }, ]); expect(snapshot.attachments).toHaveLength(4); expect(snapshot.attachments[0]).toMatchObject({ attachmentId: 'att_1', mediaType: 'image/png', name: 'inline.png', source: undefined, }); expect(snapshot.attachments[1]).toMatchObject({ attachmentId: 'att_2', name: 'remote.png', source: { kind: 'url', url: 'https://example.com/pic.png' }, }); expect(snapshot.attachments[2]).toMatchObject({ attachmentId: 'att_3', name: 'stored.png', source: { kind: 'file', fileId: 'file_8' }, }); expect(snapshot.attachments[3]).toMatchObject({ attachmentId: 'att_4', mediaType: 'text/plain', name: 'notes.txt', source: { kind: 'file', fileId: 'file_9' }, }); const firstTurn = snapshot.items[0]; if (firstTurn?.kind !== 'turn') throw new Error('expected turn'); expect(firstTurn.attachmentIds).toEqual(['att_1', 'att_2', 'att_3', 'att_4']); }); it('folds origin file attachments on the opening user message into path-sourced entities', () => { const snapshot = groupMessagesIntoSnapshot([ { role: 'user', content: [ { type: 'text', text: 'Attached file "report.pdf" (application/pdf, 128 bytes): /data/report.pdf — open it with the Read tool', }, ], toolCalls: [], origin: { kind: 'user', attachments: [ { name: 'report.pdf', mediaType: 'application/pdf', size: 128, path: '/data/report.pdf' }, ], } as { kind: string }, }, { role: 'assistant', content: [{ type: 'text', text: 'done' }], toolCalls: [] }, ]); expect(snapshot.attachments).toEqual([ { attachmentId: 'att_1', mediaType: 'application/pdf', name: 'report.pdf', size: 128, }, ]); const turn = snapshot.items[0]; if (turn?.kind !== 'turn') throw new Error('expected turn'); expect(turn.attachmentIds).toEqual(['att_1']); }); it('folds origin file attachments on a skill activation message into path-sourced entities', () => { const snapshot = groupMessagesIntoSnapshot([ { role: 'user', content: [ { type: 'text', text: 'User activated the skill "update-config".', }, ], toolCalls: [], origin: { kind: 'skill_activation', activationId: 'act_1', skillName: 'update-config', trigger: 'user-slash', attachments: [ { name: 'note.txt', mediaType: 'text/plain', size: 21, path: '/data/note.txt' }, ], } as { kind: string }, }, { role: 'assistant', content: [{ type: 'text', text: 'done' }], toolCalls: [] }, ]); expect(snapshot.attachments).toEqual([ { attachmentId: 'att_1', mediaType: 'text/plain', name: 'note.txt', size: 21, }, ]); const turn = snapshot.items[1]; if (turn?.kind !== 'turn') throw new Error('expected turn'); expect(turn.attachmentIds).toEqual(['att_1']); }); it('maps persisted kimi-file media refs to attachments', () => { const snapshot = groupMessagesIntoSnapshot([ { role: 'user', content: [ { type: 'video_url', videoUrl: { url: 'kimi-file://file_1', name: 'clip.mp4' }, } as HistoryContentPart, ], toolCalls: [], origin: { kind: 'user' }, }, { role: 'user', content: [ { type: 'text', text: 'what is this?' }, { type: 'image_url', imageUrl: { url: 'kimi-file://file_2?path=%2Fcache%2Fshot.png', name: 'shot.png' }, } as HistoryContentPart, ], toolCalls: [], origin: { kind: 'user' }, }, ]); expect(snapshot.attachments).toEqual([ { attachmentId: 'att_1', mediaType: 'video/*', name: 'clip.mp4', source: { kind: 'session_media', fileId: 'file_1' }, }, { attachmentId: 'att_2', mediaType: 'image/*', name: 'shot.png', source: { kind: 'session_media', fileId: 'file_2' }, }, ]); const videoTurn = snapshot.items[0]; const imageTurn = snapshot.items[1]; if (videoTurn?.kind !== 'turn' || imageTurn?.kind !== 'turn') { throw new Error('expected turns'); } expect(videoTurn.attachmentIds).toEqual(['att_1']); expect(imageTurn.attachmentIds).toEqual(['att_2']); expect(videoTurn.prompt).toBe(''); expect(imageTurn.prompt).toBe('what is this?'); }); it('projects a daemon ref in a user-slash turn-opening input like a plain user turn', () => { const snapshot = groupMessagesIntoSnapshot([ { role: 'user', content: [ { type: 'text', text: '/gen-docs ' }, { type: 'image_url', imageUrl: { url: 'kimi-file://file_4?path=%2Fcache%2Fshot.png' }, } as HistoryContentPart, ], toolCalls: [], origin: { kind: 'skill_activation', trigger: 'user-slash', skillName: 'gen-docs' } as { kind: string; }, }, ]); expect(snapshot.attachments).toEqual([ { attachmentId: 'att_1', mediaType: 'image/*', source: { kind: 'session_media', fileId: 'file_4' }, }, ]); expect(snapshot.items.map((item) => item.kind)).toEqual(['marker', 'turn']); const marker = snapshot.items[0]; if (marker?.kind !== 'marker') throw new Error('expected marker'); expect((marker.payload as { text: string }).text).toBe('/gen-docs '); const turn = snapshot.items[1]; if (turn?.kind !== 'turn') throw new Error('expected turn'); expect(turn.prompt).toBe('/gen-docs '); expect(turn.attachmentIds).toEqual(['att_1']); }); it('keeps a kimi-file ref as a nameless attachment and inline tags as user text', () => { const snapshot = snapshotOf( { type: 'text', text: 'open please' }, { type: 'image_url', imageUrl: { url: 'kimi-file://file_3' }, } as HistoryContentPart, ); expect(snapshot.attachments).toEqual([ { attachmentId: 'att_1', mediaType: 'image/*', source: { kind: 'session_media', fileId: 'file_3' }, }, ]); const turn = snapshot.items[0]; if (turn?.kind !== 'turn') throw new Error('expected turn'); expect(turn.attachmentIds).toEqual(['att_1']); expect(turn.prompt).toBe('open please'); }); it('keeps a legacy tag+ref pair as prompt text plus the ref-derived attachment', () => { const snapshot = snapshotOf( { type: 'text', text: '' }, { type: 'image_url', imageUrl: { url: 'kimi-file://file_5?path=%2Fcache%2Fshot.png' }, } as HistoryContentPart, ); expect(snapshot.attachments).toEqual([ { attachmentId: 'att_1', mediaType: 'image/*', source: { kind: 'session_media', fileId: 'file_5' }, }, ]); const turn = snapshot.items[0]; if (turn?.kind !== 'turn') throw new Error('expected turn'); expect(turn.prompt).toBe(''); expect(turn.attachmentIds).toEqual(['att_1']); }); it('keeps standalone tags as prompt text', () => { const snapshot = snapshotOf( { type: 'text', text: '' }, { type: 'text', text: '' }, { type: 'text', text: '