mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 16:03:49 +00:00
fix(native-chat): render structured patches as diffs
This commit is contained in:
@@ -24,4 +24,28 @@ describe('NativeChatToolRun', () => {
|
||||
expect(screen.getByTitle('src/index.ts')).toHaveTextContent('src/index.ts')
|
||||
expect(screen.queryByTitle('{"file_path":"src/index.ts","offset":10}')).toBeNull()
|
||||
})
|
||||
|
||||
it('renders structured apply_patch changes as a reviewable diff instead of JSON', () => {
|
||||
const blocks: NativeChatBlock[] = [
|
||||
{
|
||||
type: 'tool-call',
|
||||
name: 'apply_patch',
|
||||
input: {
|
||||
changes: [
|
||||
{
|
||||
path: '/repo/src/app.ts',
|
||||
kind: { type: 'update', move_path: null },
|
||||
diff: '@@ -1 +1 @@\n-before\n+after'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const { container } = render(<NativeChatToolRun blocks={blocks} expandSignal />)
|
||||
|
||||
expect(screen.getByText('+after')).toBeInTheDocument()
|
||||
expect(screen.getByText('-before')).toBeInTheDocument()
|
||||
expect(container.querySelector('pre')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -30,6 +30,39 @@ describe('diffFromToolCall', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('reads structured apply_patch file changes as a diff', () => {
|
||||
const diff = diffFromToolCall('apply_patch', {
|
||||
changes: [
|
||||
{
|
||||
path: '/repo/src/app.ts',
|
||||
kind: { type: 'update', move_path: null },
|
||||
diff: '@@ -1,2 +1,2 @@\n const value = 1\n-old()\n+newValue()'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
expect(diff).toEqual([
|
||||
{ kind: 'meta', text: '--- /repo/src/app.ts' },
|
||||
{ kind: 'meta', text: '+++ /repo/src/app.ts' },
|
||||
{ kind: 'meta', text: '@@ -1,2 +1,2 @@' },
|
||||
{ kind: 'context', text: ' const value = 1' },
|
||||
{ kind: 'del', text: 'old()' },
|
||||
{ kind: 'add', text: 'newValue()' }
|
||||
])
|
||||
})
|
||||
|
||||
it('reads direct apply_patch text as a diff', () => {
|
||||
expect(
|
||||
diffFromToolCall('apply_patch', {
|
||||
patch: '@@ -1 +1 @@\n-before\n+after'
|
||||
})
|
||||
).toEqual([
|
||||
{ kind: 'meta', text: '@@ -1 +1 @@' },
|
||||
{ kind: 'del', text: 'before' },
|
||||
{ kind: 'add', text: 'after' }
|
||||
])
|
||||
})
|
||||
|
||||
it('returns null when there is no old/new payload', () => {
|
||||
expect(diffFromToolCall('Edit', { file_path: '/x' })).toBeNull()
|
||||
})
|
||||
|
||||
@@ -80,6 +80,35 @@ function toLines(value: unknown, maxLines: number): { lines: string[]; truncated
|
||||
return { lines: bounded, truncated }
|
||||
}
|
||||
|
||||
function patchTextFromToolInput(value: Record<string, unknown>): string | null {
|
||||
if (typeof value.patch === 'string') {
|
||||
return value.patch
|
||||
}
|
||||
if (typeof value.diff === 'string') {
|
||||
return value.diff
|
||||
}
|
||||
if (!Array.isArray(value.changes)) {
|
||||
return null
|
||||
}
|
||||
const sections = value.changes.flatMap((entry) => {
|
||||
if (typeof entry !== 'object' || entry === null) {
|
||||
return []
|
||||
}
|
||||
const change = entry as Record<string, unknown>
|
||||
if (typeof change.diff !== 'string') {
|
||||
return []
|
||||
}
|
||||
const path = typeof change.path === 'string' ? change.path : 'file'
|
||||
const kind =
|
||||
typeof change.kind === 'object' && change.kind !== null
|
||||
? (change.kind as Record<string, unknown>)
|
||||
: null
|
||||
const nextPath = kind && typeof kind.move_path === 'string' ? kind.move_path : path
|
||||
return [`--- ${path}\n+++ ${nextPath}\n${change.diff}`]
|
||||
})
|
||||
return sections.length > 0 ? sections.join('\n') : null
|
||||
}
|
||||
|
||||
export function diffFromToolCall(
|
||||
name: string,
|
||||
input: unknown,
|
||||
@@ -89,6 +118,10 @@ export function diffFromToolCall(
|
||||
return null
|
||||
}
|
||||
const value = input as Record<string, unknown>
|
||||
const patchText = patchTextFromToolInput(value)
|
||||
if (patchText !== null) {
|
||||
return diffFromText(patchText, maxLines)
|
||||
}
|
||||
const oldLines = toLines(value.old_string ?? value.oldString ?? value.old, maxLines)
|
||||
const newLines = toLines(
|
||||
value.new_string ?? value.newString ?? value.new ?? value.content ?? value.file_text,
|
||||
|
||||
Reference in New Issue
Block a user