Files
open-design/apps/daemon/tests/json-event-stream.test.ts
T
Zakaria a46764fb1b
ci / Validate workspace (push) Has been cancelled
landing-page-ci / Validate landing page (push) Has been cancelled
landing-page-deploy / Deploy landing page (push) Has been cancelled
github-metrics / Generate repository metrics SVG (push) Has been cancelled
refresh-contributors-wall / Refresh contributors wall cache bust (push) Waiting to run
first-commit
2026-05-04 14:58:14 -04:00

274 lines
8.0 KiB
TypeScript

// @ts-nocheck
import { test } from 'vitest';
import assert from 'node:assert/strict';
import { createJsonEventStreamHandler } from '../src/json-event-stream.js';
test('opencode json stream emits text and usage events', () => {
const events = [];
const handler = createJsonEventStreamHandler('opencode', (event) => events.push(event));
handler.feed(
'{"type":"step_start","sessionID":"ses-1","part":{"type":"step-start"}}\n' +
'{"type":"text","sessionID":"ses-1","part":{"type":"text","text":"hello"}}\n' +
'{"type":"step_finish","sessionID":"ses-1","part":{"type":"step-finish","tokens":{"input":11,"output":7,"reasoning":3,"cache":{"read":5,"write":2}},"cost":0}}\n',
);
assert.deepEqual(events, [
{ type: 'status', label: 'running' },
{ type: 'text_delta', delta: 'hello' },
{
type: 'usage',
usage: {
input_tokens: 11,
output_tokens: 7,
thought_tokens: 3,
cached_read_tokens: 5,
cached_write_tokens: 2,
},
costUsd: 0,
},
]);
});
test('opencode json stream emits tool events', () => {
const events = [];
const handler = createJsonEventStreamHandler('opencode', (event) => events.push(event));
handler.feed(
JSON.stringify({
type: 'tool_use',
part: {
tool: 'read',
callID: 'call-1',
state: {
input: JSON.stringify({ file: 'foo.txt' }),
output: 'done',
status: 'completed',
},
},
}) + '\n',
);
assert.deepEqual(events, [
{ type: 'tool_use', id: 'call-1', name: 'read', input: { file: 'foo.txt' } },
{ type: 'tool_result', toolUseId: 'call-1', content: 'done', isError: false },
]);
});
test('unknown json stream lines become raw events', () => {
const events = [];
const handler = createJsonEventStreamHandler('opencode', (event) => events.push(event));
handler.feed('not-json\n');
handler.flush();
assert.deepEqual(events, [{ type: 'raw', line: 'not-json' }]);
});
test('gemini stream emits init text and usage events', () => {
const events = [];
const handler = createJsonEventStreamHandler('gemini', (event) => events.push(event));
handler.feed(
JSON.stringify({ type: 'init', session_id: 'gm-1', model: 'gemini-3-flash-preview' }) + '\n' +
JSON.stringify({ type: 'message', role: 'assistant', content: 'hello', delta: true }) + '\n' +
JSON.stringify({
type: 'result',
status: 'success',
stats: { input_tokens: 9, output_tokens: 4, cached: 2, duration_ms: 321 },
}) +
'\n',
);
assert.deepEqual(events, [
{ type: 'status', label: 'initializing', model: 'gemini-3-flash-preview' },
{ type: 'text_delta', delta: 'hello' },
{
type: 'usage',
usage: { input_tokens: 9, output_tokens: 4, cached_read_tokens: 2 },
durationMs: 321,
},
]);
});
test('cursor stream emits partial text once and usage events', () => {
const events = [];
const handler = createJsonEventStreamHandler('cursor-agent', (event) => events.push(event));
handler.feed(
JSON.stringify({ type: 'system', subtype: 'init', model: 'GPT-5 Mini' }) + '\n' +
JSON.stringify({
type: 'assistant',
timestamp_ms: 1,
message: { role: 'assistant', content: [{ type: 'text', text: 'OD' }] },
}) +
'\n' +
JSON.stringify({
type: 'assistant',
timestamp_ms: 2,
message: { role: 'assistant', content: [{ type: 'text', text: '_OK' }] },
}) +
'\n' +
JSON.stringify({
type: 'assistant',
message: { role: 'assistant', content: [{ type: 'text', text: 'OD_OK' }] },
}) +
'\n' +
JSON.stringify({
type: 'result',
duration_ms: 120,
usage: { inputTokens: 5, outputTokens: 2, cacheReadTokens: 1, cacheWriteTokens: 0 },
}) +
'\n',
);
assert.deepEqual(events, [
{ type: 'status', label: 'initializing', model: 'GPT-5 Mini' },
{ type: 'text_delta', delta: 'OD' },
{ type: 'text_delta', delta: '_OK' },
{
type: 'usage',
usage: { input_tokens: 5, output_tokens: 2, cached_read_tokens: 1, cached_write_tokens: 0 },
durationMs: 120,
},
]);
});
test('cursor stream emits suffix when final assistant extends partial text', () => {
const events = [];
const handler = createJsonEventStreamHandler('cursor-agent', (event) => events.push(event));
handler.feed(
JSON.stringify({
type: 'assistant',
timestamp_ms: 1,
message: { role: 'assistant', content: [{ type: 'text', text: 'hello' }] },
}) +
'\n' +
JSON.stringify({
type: 'assistant',
message: { role: 'assistant', content: [{ type: 'text', text: 'hello world' }] },
}) +
'\n',
);
assert.deepEqual(events, [
{ type: 'text_delta', delta: 'hello' },
{ type: 'text_delta', delta: ' world' },
]);
});
test('cursor stream de-duplicates cumulative timestamped assistant chunks', () => {
const events = [];
const handler = createJsonEventStreamHandler('cursor-agent', (event) => events.push(event));
handler.feed(
JSON.stringify({
type: 'assistant',
timestamp_ms: 1,
message: { role: 'assistant', content: [{ type: 'text', text: 'hello' }] },
}) +
'\n' +
JSON.stringify({
type: 'assistant',
timestamp_ms: 2,
message: { role: 'assistant', content: [{ type: 'text', text: 'hello world' }] },
}) +
'\n' +
JSON.stringify({
type: 'assistant',
timestamp_ms: 3,
message: { role: 'assistant', content: [{ type: 'text', text: 'hello world' }] },
}) +
'\n',
);
assert.deepEqual(events, [
{ type: 'text_delta', delta: 'hello' },
{ type: 'text_delta', delta: ' world' },
]);
});
test('codex json stream emits status text and usage events', () => {
const events = [];
const handler = createJsonEventStreamHandler('codex', (event) => events.push(event));
handler.feed(
JSON.stringify({ type: 'thread.started', thread_id: 'thr-1' }) + '\n' +
JSON.stringify({ type: 'turn.started' }) + '\n' +
JSON.stringify({
type: 'item.completed',
item: { id: 'item-1', type: 'agent_message', text: 'hello' },
}) +
'\n' +
JSON.stringify({
type: 'turn.completed',
usage: { input_tokens: 12, cached_input_tokens: 4, output_tokens: 3 },
}) +
'\n',
);
assert.deepEqual(events, [
{ type: 'status', label: 'initializing' },
{ type: 'status', label: 'running' },
{ type: 'text_delta', delta: 'hello' },
{ type: 'usage', usage: { input_tokens: 12, output_tokens: 3, cached_read_tokens: 4 } },
]);
});
test('codex json stream emits command execution tool events', () => {
const events = [];
const handler = createJsonEventStreamHandler('codex', (event) => events.push(event));
handler.feed(
JSON.stringify({
type: 'item.started',
item: {
id: 'item-1',
type: 'command_execution',
command: "/bin/zsh -lc 'echo hello-from-codex'",
aggregated_output: '',
exit_code: null,
status: 'in_progress',
},
}) +
'\n' +
JSON.stringify({
type: 'item.completed',
item: {
id: 'item-1',
type: 'command_execution',
command: "/bin/zsh -lc 'echo hello-from-codex'",
aggregated_output: 'hello-from-codex\n',
exit_code: 0,
status: 'completed',
},
}) +
'\n',
);
assert.deepEqual(events, [
{
type: 'tool_use',
id: 'item-1',
name: 'Bash',
input: { command: "/bin/zsh -lc 'echo hello-from-codex'" },
},
{
type: 'tool_result',
toolUseId: 'item-1',
content: 'hello-from-codex\n',
isError: false,
},
]);
});
test('unhandled structured events fall back to raw', () => {
const events = [];
const handler = createJsonEventStreamHandler('codex', (event) => events.push(event));
handler.feed(JSON.stringify({ type: 'unhandled.event', foo: 'bar' }) + '\n');
assert.deepEqual(events, [{ type: 'raw', line: '{"type":"unhandled.event","foo":"bar"}' }]);
});