mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-02 08:33:36 +00:00
test: Update OpenCode provider tests to use new event format
Update normalizeEvent tests to match new OpenCode API: - text events use type='text' with part.text instead of text-delta - tool_call events use type='tool_call' with part containing call_id, name, args - tool_result events use type='tool_result' with part - tool_error events use type='tool_error' with part - step_finish events use type='step_finish' with part Update buildCliArgs tests: - Remove expectations for -q flag (no longer used) - Remove expectations for -c flag (cwd set at subprocess level) - Remove expectations for - final arg (prompt via stdin) - Update format to 'json' instead of 'stream-json' Remaining 8 test failures are in integration tests that use executeQuery and require more extensive mock data updates.
This commit is contained in:
@@ -168,41 +168,23 @@ describe('opencode-provider.ts', () => {
|
||||
it('should build correct args with run subcommand', () => {
|
||||
const args = provider.buildCliArgs({
|
||||
prompt: 'Hello',
|
||||
model: 'opencode/big-pickle',
|
||||
cwd: '/tmp/project',
|
||||
});
|
||||
|
||||
expect(args[0]).toBe('run');
|
||||
});
|
||||
|
||||
it('should include --format stream-json for streaming output', () => {
|
||||
it('should include --format json for streaming output', () => {
|
||||
const args = provider.buildCliArgs({
|
||||
prompt: 'Hello',
|
||||
model: 'opencode/big-pickle',
|
||||
cwd: '/tmp/project',
|
||||
});
|
||||
|
||||
const formatIndex = args.indexOf('--format');
|
||||
expect(formatIndex).toBeGreaterThan(-1);
|
||||
expect(args[formatIndex + 1]).toBe('stream-json');
|
||||
});
|
||||
|
||||
it('should include -q flag for quiet mode', () => {
|
||||
const args = provider.buildCliArgs({
|
||||
prompt: 'Hello',
|
||||
cwd: '/tmp/project',
|
||||
});
|
||||
|
||||
expect(args).toContain('-q');
|
||||
});
|
||||
|
||||
it('should include working directory with -c flag', () => {
|
||||
const args = provider.buildCliArgs({
|
||||
prompt: 'Hello',
|
||||
cwd: '/tmp/my-project',
|
||||
});
|
||||
|
||||
const cwdIndex = args.indexOf('-c');
|
||||
expect(cwdIndex).toBeGreaterThan(-1);
|
||||
expect(args[cwdIndex + 1]).toBe('/tmp/my-project');
|
||||
expect(args[formatIndex + 1]).toBe('json');
|
||||
});
|
||||
|
||||
it('should include model with --model flag', () => {
|
||||
@@ -228,18 +210,10 @@ describe('opencode-provider.ts', () => {
|
||||
expect(args[modelIndex + 1]).toBe('anthropic/claude-sonnet-4-5');
|
||||
});
|
||||
|
||||
it('should include dash as final arg for stdin prompt', () => {
|
||||
const args = provider.buildCliArgs({
|
||||
prompt: 'Hello',
|
||||
cwd: '/tmp/project',
|
||||
});
|
||||
|
||||
expect(args[args.length - 1]).toBe('-');
|
||||
});
|
||||
|
||||
it('should handle missing cwd', () => {
|
||||
const args = provider.buildCliArgs({
|
||||
prompt: 'Hello',
|
||||
model: 'opencode/big-pickle',
|
||||
});
|
||||
|
||||
expect(args).not.toContain('-c');
|
||||
@@ -249,6 +223,7 @@ describe('opencode-provider.ts', () => {
|
||||
const args = provider.buildCliArgs({
|
||||
prompt: 'Hello',
|
||||
cwd: '/tmp/project',
|
||||
model: 'opencode/big-pickle',
|
||||
});
|
||||
|
||||
expect(args).not.toContain('--model');
|
||||
@@ -260,12 +235,15 @@ describe('opencode-provider.ts', () => {
|
||||
// ==========================================================================
|
||||
|
||||
describe('normalizeEvent', () => {
|
||||
describe('text-delta events', () => {
|
||||
it('should convert text-delta to assistant message with text content', () => {
|
||||
describe('text events (new OpenCode format)', () => {
|
||||
it('should convert text to assistant message with text content', () => {
|
||||
const event = {
|
||||
type: 'text-delta',
|
||||
text: 'Hello, world!',
|
||||
session_id: 'test-session',
|
||||
type: 'text',
|
||||
part: {
|
||||
type: 'text',
|
||||
text: 'Hello, world!',
|
||||
},
|
||||
sessionID: 'test-session',
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -285,10 +263,13 @@ describe('opencode-provider.ts', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should return null for empty text-delta', () => {
|
||||
it('should return null for empty text', () => {
|
||||
const event = {
|
||||
type: 'text-delta',
|
||||
text: '',
|
||||
type: 'text',
|
||||
part: {
|
||||
type: 'text',
|
||||
text: '',
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -296,9 +277,10 @@ describe('opencode-provider.ts', () => {
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null for text-delta with undefined text', () => {
|
||||
it('should return null for text with undefined text', () => {
|
||||
const event = {
|
||||
type: 'text-delta',
|
||||
type: 'text',
|
||||
part: {},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -307,27 +289,17 @@ describe('opencode-provider.ts', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('text-end events', () => {
|
||||
it('should return null for text-end events (informational)', () => {
|
||||
describe('tool_call events', () => {
|
||||
it('should convert tool_call to assistant message with tool_use content', () => {
|
||||
const event = {
|
||||
type: 'text-end',
|
||||
session_id: 'test-session',
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('tool-call events', () => {
|
||||
it('should convert tool-call to assistant message with tool_use content', () => {
|
||||
const event = {
|
||||
type: 'tool-call',
|
||||
call_id: 'call-123',
|
||||
name: 'Read',
|
||||
args: { file_path: '/tmp/test.txt' },
|
||||
session_id: 'test-session',
|
||||
type: 'tool_call',
|
||||
part: {
|
||||
type: 'tool-call',
|
||||
call_id: 'call-123',
|
||||
name: 'Read',
|
||||
args: { file_path: '/tmp/test.txt' },
|
||||
},
|
||||
sessionID: 'test-session',
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -351,9 +323,12 @@ describe('opencode-provider.ts', () => {
|
||||
|
||||
it('should generate tool_use_id when call_id is missing', () => {
|
||||
const event = {
|
||||
type: 'tool-call',
|
||||
name: 'Write',
|
||||
args: { content: 'test' },
|
||||
type: 'tool_call',
|
||||
part: {
|
||||
type: 'tool-call',
|
||||
name: 'Write',
|
||||
args: { content: 'test' },
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -363,21 +338,27 @@ describe('opencode-provider.ts', () => {
|
||||
|
||||
// Second call should increment
|
||||
const result2 = provider.normalizeEvent({
|
||||
type: 'tool-call',
|
||||
name: 'Edit',
|
||||
args: {},
|
||||
type: 'tool_call',
|
||||
part: {
|
||||
type: 'tool-call',
|
||||
name: 'Edit',
|
||||
args: {},
|
||||
},
|
||||
});
|
||||
expect(result2?.message?.content[0].tool_use_id).toBe('opencode-tool-2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('tool-result events', () => {
|
||||
it('should convert tool-result to assistant message with tool_result content', () => {
|
||||
describe('tool_result events', () => {
|
||||
it('should convert tool_result to assistant message with tool_result content', () => {
|
||||
const event = {
|
||||
type: 'tool-result',
|
||||
call_id: 'call-123',
|
||||
output: 'File contents here',
|
||||
session_id: 'test-session',
|
||||
type: 'tool_result',
|
||||
part: {
|
||||
type: 'tool-result',
|
||||
call_id: 'call-123',
|
||||
output: 'File contents here',
|
||||
},
|
||||
sessionID: 'test-session',
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -398,10 +379,13 @@ describe('opencode-provider.ts', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle tool-result without call_id', () => {
|
||||
it('should handle tool_result without call_id', () => {
|
||||
const event = {
|
||||
type: 'tool-result',
|
||||
output: 'Result without ID',
|
||||
type: 'tool_result',
|
||||
part: {
|
||||
type: 'tool-result',
|
||||
output: 'Result without ID',
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -411,13 +395,16 @@ describe('opencode-provider.ts', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('tool-error events', () => {
|
||||
it('should convert tool-error to error message', () => {
|
||||
describe('tool_error events', () => {
|
||||
it('should convert tool_error to error message', () => {
|
||||
const event = {
|
||||
type: 'tool-error',
|
||||
call_id: 'call-123',
|
||||
error: 'File not found',
|
||||
session_id: 'test-session',
|
||||
type: 'tool_error',
|
||||
part: {
|
||||
type: 'tool-error',
|
||||
call_id: 'call-123',
|
||||
error: 'File not found',
|
||||
},
|
||||
sessionID: 'test-session',
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -431,8 +418,11 @@ describe('opencode-provider.ts', () => {
|
||||
|
||||
it('should provide default error message when error is missing', () => {
|
||||
const event = {
|
||||
type: 'tool-error',
|
||||
call_id: 'call-123',
|
||||
type: 'tool_error',
|
||||
part: {
|
||||
type: 'tool-error',
|
||||
call_id: 'call-123',
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -442,12 +432,14 @@ describe('opencode-provider.ts', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('start-step events', () => {
|
||||
it('should return null for start-step events (informational)', () => {
|
||||
describe('step_start events', () => {
|
||||
it('should return null for step_start events (informational)', () => {
|
||||
const event = {
|
||||
type: 'start-step',
|
||||
step: 1,
|
||||
session_id: 'test-session',
|
||||
type: 'step_start',
|
||||
part: {
|
||||
type: 'step-start',
|
||||
},
|
||||
sessionID: 'test-session',
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -456,14 +448,16 @@ describe('opencode-provider.ts', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('finish-step events', () => {
|
||||
it('should convert successful finish-step to result message', () => {
|
||||
describe('step_finish events', () => {
|
||||
it('should convert successful step_finish to result message', () => {
|
||||
const event = {
|
||||
type: 'finish-step',
|
||||
step: 1,
|
||||
success: true,
|
||||
result: 'Task completed successfully',
|
||||
session_id: 'test-session',
|
||||
type: 'step_finish',
|
||||
part: {
|
||||
type: 'step-finish',
|
||||
reason: 'stop',
|
||||
result: 'Task completed successfully',
|
||||
},
|
||||
sessionID: 'test-session',
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -476,13 +470,15 @@ describe('opencode-provider.ts', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert finish-step with success=false to error message', () => {
|
||||
it('should convert step_finish with error to error message', () => {
|
||||
const event = {
|
||||
type: 'finish-step',
|
||||
step: 1,
|
||||
success: false,
|
||||
error: 'Something went wrong',
|
||||
session_id: 'test-session',
|
||||
type: 'step_finish',
|
||||
part: {
|
||||
type: 'step-finish',
|
||||
reason: 'error',
|
||||
error: 'Something went wrong',
|
||||
},
|
||||
sessionID: 'test-session',
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -494,11 +490,13 @@ describe('opencode-provider.ts', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert finish-step with error property to error message', () => {
|
||||
it('should convert step_finish with error property to error message', () => {
|
||||
const event = {
|
||||
type: 'finish-step',
|
||||
step: 1,
|
||||
error: 'Process failed',
|
||||
type: 'step_finish',
|
||||
part: {
|
||||
type: 'step-finish',
|
||||
error: 'Process failed',
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -509,9 +507,11 @@ describe('opencode-provider.ts', () => {
|
||||
|
||||
it('should provide default error message for failed step without error text', () => {
|
||||
const event = {
|
||||
type: 'finish-step',
|
||||
step: 1,
|
||||
success: false,
|
||||
type: 'step_finish',
|
||||
part: {
|
||||
type: 'step-finish',
|
||||
reason: 'error',
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -520,11 +520,14 @@ describe('opencode-provider.ts', () => {
|
||||
expect(result?.error).toBe('Step execution failed');
|
||||
});
|
||||
|
||||
it('should treat finish-step without success flag as success', () => {
|
||||
it('should treat step_finish with reason=stop as success', () => {
|
||||
const event = {
|
||||
type: 'finish-step',
|
||||
step: 1,
|
||||
result: 'Done',
|
||||
type: 'step_finish',
|
||||
part: {
|
||||
type: 'step-finish',
|
||||
reason: 'stop',
|
||||
result: 'Done',
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -1069,12 +1072,15 @@ describe('opencode-provider.ts', () => {
|
||||
});
|
||||
|
||||
describe('normalizeEvent additional edge cases', () => {
|
||||
it('should handle tool-call with empty args object', () => {
|
||||
it('should handle tool_call with empty args object', () => {
|
||||
const event = {
|
||||
type: 'tool-call',
|
||||
call_id: 'call-123',
|
||||
name: 'Glob',
|
||||
args: {},
|
||||
type: 'tool_call',
|
||||
part: {
|
||||
type: 'tool-call',
|
||||
call_id: 'call-123',
|
||||
name: 'Glob',
|
||||
args: {},
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -1083,12 +1089,15 @@ describe('opencode-provider.ts', () => {
|
||||
expect(result?.message?.content[0].input).toEqual({});
|
||||
});
|
||||
|
||||
it('should handle tool-call with null args', () => {
|
||||
it('should handle tool_call with null args', () => {
|
||||
const event = {
|
||||
type: 'tool-call',
|
||||
call_id: 'call-123',
|
||||
name: 'Glob',
|
||||
args: null,
|
||||
type: 'tool_call',
|
||||
part: {
|
||||
type: 'tool-call',
|
||||
call_id: 'call-123',
|
||||
name: 'Glob',
|
||||
args: null,
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -1097,18 +1106,21 @@ describe('opencode-provider.ts', () => {
|
||||
expect(result?.message?.content[0].input).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle tool-call with complex nested args', () => {
|
||||
it('should handle tool_call with complex nested args', () => {
|
||||
const event = {
|
||||
type: 'tool-call',
|
||||
call_id: 'call-123',
|
||||
name: 'Edit',
|
||||
args: {
|
||||
file_path: '/tmp/test.ts',
|
||||
changes: [
|
||||
{ line: 10, old: 'foo', new: 'bar' },
|
||||
{ line: 20, old: 'baz', new: 'qux' },
|
||||
],
|
||||
options: { replace_all: true },
|
||||
type: 'tool_call',
|
||||
part: {
|
||||
type: 'tool-call',
|
||||
call_id: 'call-123',
|
||||
name: 'Edit',
|
||||
args: {
|
||||
file_path: '/tmp/test.ts',
|
||||
changes: [
|
||||
{ line: 10, old: 'foo', new: 'bar' },
|
||||
{ line: 20, old: 'baz', new: 'qux' },
|
||||
],
|
||||
options: { replace_all: true },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1125,11 +1137,14 @@ describe('opencode-provider.ts', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle tool-result with empty output', () => {
|
||||
it('should handle tool_result with empty output', () => {
|
||||
const event = {
|
||||
type: 'tool-result',
|
||||
call_id: 'call-123',
|
||||
output: '',
|
||||
type: 'tool_result',
|
||||
part: {
|
||||
type: 'tool-result',
|
||||
call_id: 'call-123',
|
||||
output: '',
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -1138,10 +1153,13 @@ describe('opencode-provider.ts', () => {
|
||||
expect(result?.message?.content[0].content).toBe('');
|
||||
});
|
||||
|
||||
it('should handle text-delta with whitespace-only text', () => {
|
||||
it('should handle text with whitespace-only text', () => {
|
||||
const event = {
|
||||
type: 'text-delta',
|
||||
text: ' ',
|
||||
type: 'text',
|
||||
part: {
|
||||
type: 'text',
|
||||
text: ' ',
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -1151,10 +1169,13 @@ describe('opencode-provider.ts', () => {
|
||||
expect(result?.message?.content[0].text).toBe(' ');
|
||||
});
|
||||
|
||||
it('should handle text-delta with newlines', () => {
|
||||
it('should handle text with newlines', () => {
|
||||
const event = {
|
||||
type: 'text-delta',
|
||||
text: 'Line 1\nLine 2\nLine 3',
|
||||
type: 'text',
|
||||
part: {
|
||||
type: 'text',
|
||||
text: 'Line 1\nLine 2\nLine 3',
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -1162,12 +1183,15 @@ describe('opencode-provider.ts', () => {
|
||||
expect(result?.message?.content[0].text).toBe('Line 1\nLine 2\nLine 3');
|
||||
});
|
||||
|
||||
it('should handle finish-step with both result and error (error takes precedence)', () => {
|
||||
it('should handle step_finish with both result and error (error takes precedence)', () => {
|
||||
const event = {
|
||||
type: 'finish-step',
|
||||
result: 'Some result',
|
||||
error: 'But also an error',
|
||||
success: false,
|
||||
type: 'step_finish',
|
||||
part: {
|
||||
type: 'step-finish',
|
||||
reason: 'stop',
|
||||
result: 'Some result',
|
||||
error: 'But also an error',
|
||||
},
|
||||
};
|
||||
|
||||
const result = provider.normalizeEvent(event);
|
||||
@@ -1231,13 +1255,14 @@ describe('opencode-provider.ts', () => {
|
||||
const longPrompt = 'a'.repeat(10000);
|
||||
const args = provider.buildCliArgs({
|
||||
prompt: longPrompt,
|
||||
model: 'opencode/big-pickle',
|
||||
cwd: '/tmp',
|
||||
});
|
||||
|
||||
// The prompt is NOT in args (it's passed via stdin)
|
||||
// Just verify the args structure is correct
|
||||
expect(args).toContain('run');
|
||||
expect(args).toContain('-');
|
||||
expect(args).not.toContain('-');
|
||||
expect(args.join(' ')).not.toContain(longPrompt);
|
||||
});
|
||||
|
||||
@@ -1245,22 +1270,25 @@ describe('opencode-provider.ts', () => {
|
||||
const specialPrompt = 'Test $HOME $(rm -rf /) `command` "quotes" \'single\'';
|
||||
const args = provider.buildCliArgs({
|
||||
prompt: specialPrompt,
|
||||
model: 'opencode/big-pickle',
|
||||
cwd: '/tmp',
|
||||
});
|
||||
|
||||
// Special chars in prompt should not affect args (prompt is via stdin)
|
||||
expect(args).toContain('run');
|
||||
expect(args).toContain('-');
|
||||
expect(args).not.toContain('-');
|
||||
});
|
||||
|
||||
it('should handle cwd with spaces', () => {
|
||||
const args = provider.buildCliArgs({
|
||||
prompt: 'Test',
|
||||
model: 'opencode/big-pickle',
|
||||
cwd: '/tmp/path with spaces/project',
|
||||
});
|
||||
|
||||
const cwdIndex = args.indexOf('-c');
|
||||
expect(args[cwdIndex + 1]).toBe('/tmp/path with spaces/project');
|
||||
// cwd is set at subprocess level, not via CLI args
|
||||
expect(args).not.toContain('-c');
|
||||
expect(args).not.toContain('/tmp/path with spaces/project');
|
||||
});
|
||||
|
||||
it('should handle model with unusual characters', () => {
|
||||
|
||||
Reference in New Issue
Block a user