chore: establish YCode replication baseline and TODO
This commit is contained in:
commit
6dc59f89ba
1118 files changed
+196002
No files matched your search
@@ -0,0 +1,185 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFileSync, existsSync } from 'node:fs'
|
||||
import { createHash } from 'node:crypto'
|
||||
import { convertWorkBuddyJsonl, convertWorkBuddyTranscript, migrateImportedWorkBuddyMessages, parseWorkBuddyJsonl, stripWorkBuddyPromptContext, type WorkBuddyImportOptions } from '../src/shared/workbuddy-import'
|
||||
import { projectWorkBuddyHistoryTool } from '../src/shared/workbuddy-history-projection'
|
||||
|
||||
const options: WorkBuddyImportOptions = {
|
||||
sessionId: 'independent-copy', title: '开始新会话', sourceSessionId: 'original-session',
|
||||
evidenceId: `ev_${'a'.repeat(64)}`, sourceSha256: 'b'.repeat(64), importedAt: 5000, branchMode: 'visible'
|
||||
}
|
||||
const text = (text: string) => [{ type: 'input_text', text }]
|
||||
const fixture = [
|
||||
{ type: 'session-meta', timestamp: 1, meta: { credential: 'never-copy-this' } },
|
||||
{ type: 'message', id: 'u1', role: 'user', timestamp: 10, content: text('First prompt') },
|
||||
{ type: 'reasoning', id: 'r1', parentId: 'u1', timestamp: 20, content: text('Recorded reasoning'), rawContent: ['never-copy-raw'] },
|
||||
{ type: 'function_call', id: 'c1', callId: 'call-1', timestamp: 30, name: 'Bash', arguments: '{"command":"echo hello"}', providerData: { token: 'never-copy-token' } },
|
||||
{ type: 'function_call_result', id: 'result-1', callId: 'call-1', timestamp: 50, status: 'completed', output: { type: 'input_text', text: 'hello\n' }, providerData: {
|
||||
secret: 'never-copy-secret', toolResult: { content: 'hello\n', renderer: { type: 'text', value: 'hello\n' }, rawResponse: { exitCode: 0 }, terminalId: 'never-resume-terminal', mcpMeta: { secret: true } }
|
||||
} },
|
||||
{ type: 'message', id: 'a1', role: 'assistant', timestamp: 60, status: 'completed', content: [{ type: 'output_text', text: 'Done' }] },
|
||||
{ type: 'message', id: 'u2', role: 'user', timestamp: 70, content: [
|
||||
...text('Image prompt'), { type: 'input_image', image: { blob_id: 'blob-one', blob_path: 'blobs/one.png', mime: 'image/png', size: 12, original_filename: 'test.png' } }
|
||||
] },
|
||||
{ type: 'function_call', id: 'c2', callId: 'call-2', timestamp: 80, name: 'Write', arguments: '{bad-json' },
|
||||
{ type: 'reasoning', id: 'r2', timestamp: 81, content: [], rawContent: ['never-copy-encrypted'] },
|
||||
{ type: 'message', id: 'a2', role: 'assistant', timestamp: 90, status: 'incomplete', content: text('Stopped') }
|
||||
]
|
||||
const result = convertWorkBuddyTranscript(fixture, options)
|
||||
assert.equal(result.messages.length, 4)
|
||||
assert.deepEqual(result.messages[1].parts?.map((part) => part.type), ['reasoning', 'tool', 'text'])
|
||||
assert.equal(result.messages[1].tools?.[0].output, 'hello\n')
|
||||
assert.equal(result.messages[1].tools?.[0].durationMs, 20)
|
||||
assert.equal(result.messages[1].turnDurationMs, 50)
|
||||
assert.equal(result.messages[1].tools?.[0].status, 'ok')
|
||||
assert.equal(result.messages[3].tools?.[0].status, 'cancelled')
|
||||
assert.equal(result.messages[3].tools?.[0].argsRaw, '{bad-json')
|
||||
assert.equal(result.messages[3].status, 'cancelled')
|
||||
assert.equal(result.stats.unresolvedToolCalls, 1)
|
||||
assert.equal(result.messages[2].attachments?.[0].name, 'test.png')
|
||||
assert.equal(result.messages[2].content, 'Image prompt')
|
||||
assert.equal(result.messages[2].attachments?.[0].previewUrl, undefined)
|
||||
assert.equal(result.provenance.referencedAttachments[0].attachmentId, result.messages[2].attachments?.[0].id)
|
||||
assert.equal(result.provenance.referencedAttachments[0].messageId, result.messages[2].id)
|
||||
const serialized = JSON.stringify(result)
|
||||
assert.ok(!serialized.includes('never-copy'))
|
||||
assert.ok(!serialized.includes('never-resume'))
|
||||
assert.ok(!serialized.includes('mcpMeta'))
|
||||
assert.ok(result.messages.every((message) => !message.interactions && !message.requestId && !message.nativeSessionPath && !message.nativeEntryId))
|
||||
assert.ok(result.messages.every((message) => !['u1', 'a1', 'u2', 'a2'].includes(message.id)))
|
||||
assert.ok(result.messages.flatMap((message) => message.tools ?? []).every((tool) => !['call-1', 'call-2'].includes(tool.id)))
|
||||
|
||||
const forks = [
|
||||
...fixture.slice(0, 6),
|
||||
{ type: 'message', id: 'old-user', role: 'user', timestamp: 70, content: text('Old prompt') },
|
||||
{ type: 'message', id: 'old-answer', role: 'assistant', timestamp: 80, content: text('Old answer') },
|
||||
{ type: 'resend-fork-notice', id: 'fork-1', editedUserItemId: 'old-user' },
|
||||
{ type: 'message', id: 'edited-user', role: 'user', timestamp: 90, content: text('Edited prompt') },
|
||||
{ type: 'message', id: 'new-answer', role: 'assistant', timestamp: 100, content: text('New answer') }
|
||||
]
|
||||
const visible = convertWorkBuddyTranscript(forks, options)
|
||||
assert.deepEqual(visible.messages.map((message) => message.content), ['First prompt', 'Done', 'Edited prompt', 'New answer'])
|
||||
assert.equal(visible.stats.forksApplied, 1)
|
||||
assert.equal(visible.stats.excludedBranchRecords, 2)
|
||||
const archive = convertWorkBuddyTranscript(forks, { ...options, branchMode: 'archive' })
|
||||
assert.equal(archive.messages.length, 6)
|
||||
assert.ok(archive.warnings.some((warning) => warning.includes('append-only')))
|
||||
assert.throws(() => convertWorkBuddyTranscript([{ type: 'resend-fork-notice', editedUserItemId: 'missing' }], options), /visible branch import was stopped/)
|
||||
|
||||
const longOutput = 'full-output\n'.repeat(1000)
|
||||
const reversed = convertWorkBuddyTranscript([
|
||||
{ type: 'message', role: 'user', timestamp: 1, content: 'Question' },
|
||||
{ type: 'function_call_result', callId: 'out-of-order', status: 'completed', timestamp: 3, output: text(longOutput) },
|
||||
{ type: 'function_call', callId: 'out-of-order', timestamp: 2, name: 'Read', arguments: '{}' }
|
||||
], options)
|
||||
assert.equal(reversed.messages[1].tools?.[0].output, longOutput)
|
||||
assert.equal(reversed.messages[1].tools?.[0].status, 'ok')
|
||||
assert.equal(reversed.stats.unmatchedToolResults, 0)
|
||||
assert.ok(reversed.messages[1].tools?.[0].summary!.length < longOutput.length)
|
||||
const error = convertWorkBuddyTranscript([
|
||||
{ type: 'function_call', callId: 'failure', name: 'Bash', arguments: '{}' },
|
||||
{ type: 'function_call_result', callId: 'failure', status: 'completed', output: text('Failed'), providerData: { toolResult: { error: { message: 'Recorded tool error' } } } },
|
||||
{ type: 'message', role: 'assistant', status: 'incomplete', content: text('Interrupted'), providerData: { error: { message: 'Recorded network error', credential: 'never-copy' } } }
|
||||
], options)
|
||||
assert.equal(error.messages[0].tools?.[0].status, 'error')
|
||||
assert.equal(error.messages[0].status, 'error')
|
||||
assert.equal(error.messages[0].error, 'Recorded network error')
|
||||
for (const marker of ['Interrupted by user', '[User Cancelled]']) {
|
||||
const cancelled = convertWorkBuddyTranscript([
|
||||
{ type: 'message', id: 'cancel-user', role: 'user', timestamp: 1, content: 'Prompt' },
|
||||
{ type: 'message', id: 'before-cancel', role: 'assistant', timestamp: 2, content: text('Retained answer') },
|
||||
{ type: 'message', id: 'cancel-record', role: 'assistant', timestamp: 3, status: 'incomplete', content: text(marker), providerData: { error: { message: marker } } }
|
||||
], options)
|
||||
assert.equal(cancelled.messages[1].status, 'cancelled')
|
||||
assert.equal(cancelled.messages[1].content, 'Retained answer')
|
||||
assert.equal(cancelled.messages[1].error, undefined)
|
||||
const oldMessage = { ...cancelled.messages[1], status: 'error' as const, error: marker,
|
||||
content: `Retained answer\n\n${marker}`, parts: [...cancelled.messages[1].parts!, { type: 'text' as const, text: marker }] }
|
||||
const migrated = migrateImportedWorkBuddyMessages([oldMessage], cancelled.provenance)
|
||||
assert.equal(migrated.repairedCancellations, 1)
|
||||
assert.deepEqual(migrated.messages[0], cancelled.messages[1])
|
||||
assert.equal(migrateImportedWorkBuddyMessages(migrated.messages, cancelled.provenance).changed, false)
|
||||
assert.equal(migrateImportedWorkBuddyMessages([oldMessage], undefined).changed, false)
|
||||
assert.equal(migrateImportedWorkBuddyMessages([{ ...oldMessage, content: 'User modified body' }], cancelled.provenance).changed, false)
|
||||
assert.equal(oldMessage.error, marker, 'migration must not mutate input')
|
||||
}
|
||||
const rawTool = { id: 'projection', name: 'DeferExecuteTool', args: { toolName: 'Read', params: { file_path: 'sample.txt' } },
|
||||
argsRaw: '{"toolName":"Read","params":{"file_path":"sample.txt"}}', status: 'ok' as const }
|
||||
assert.deepEqual(projectWorkBuddyHistoryTool(rawTool).args, { file_path: 'sample.txt' })
|
||||
assert.equal(projectWorkBuddyHistoryTool(rawTool).name, 'read_file')
|
||||
assert.equal(rawTool.name, 'DeferExecuteTool')
|
||||
assert.equal(projectWorkBuddyHistoryTool(rawTool).argsRaw, rawTool.argsRaw)
|
||||
assert.equal(projectWorkBuddyHistoryTool({ ...rawTool, args: { toolName: 'bad target', params: {} } }).name, 'defer_execute_tool')
|
||||
const todo = projectWorkBuddyHistoryTool({ ...rawTool, name: 'TaskUpdate', args: { taskId: '1', status: 'completed' },
|
||||
result: { acpV2PlanSnapshot: { entries: [{ content: 'Recorded task', status: 'completed' }] } } })
|
||||
assert.deepEqual((todo.args as { todos: unknown }).todos, [{ content: 'Recorded task', status: 'completed' }])
|
||||
const question = projectWorkBuddyHistoryTool({ ...rawTool, name: 'AskUserQuestion',
|
||||
args: { questions: [{ id: 'q_4', question: 'Shape?' }, { question: 'Gateway?' }] },
|
||||
result: { content: ' · q-4 → Desktop\n · Gateway? -> Own gateway' } })
|
||||
assert.deepEqual((question.metadata?.questionAnswer as { questions: unknown }).questions,
|
||||
[{ id: 'q_4', question: 'Shape?', answers: ['Desktop'] }, { id: 'q-1', question: 'Gateway?', answers: ['Own gateway'] }])
|
||||
assert.throws(() => convertWorkBuddyTranscript([], { ...options, sessionId: options.sourceSessionId }), /fresh/)
|
||||
assert.throws(() => parseWorkBuddyJsonl('{}\n{bad}\n'), /line 2/)
|
||||
assert.throws(() => parseWorkBuddyJsonl('[]'), /line 1/)
|
||||
assert.deepEqual(parseWorkBuddyJsonl('\uFEFF{}\r\n\r\n'), [{}])
|
||||
assert.equal(convertWorkBuddyTranscript([{ type: 'message', role: 'user', timestamp: '1791989670167', content: 'Numeric timestamp' }], options).messages[0].createdAt, 1791989670167)
|
||||
assert.equal(stripWorkBuddyPromptContext(' <system-reminder source="workspace">Injected\ncontext</system-reminder> \n<user_query>Visible\nrequest</user_query> '), 'Visible\nrequest')
|
||||
assert.equal(stripWorkBuddyPromptContext('<user_query>One</user_query>\n<system-reminder>Hidden</system-reminder>\n<user_query>Two</user_query>'), 'One\nTwo')
|
||||
assert.equal(stripWorkBuddyPromptContext('A literal <system-reminder without a closing tag'), 'A literal <system-reminder without a closing tag')
|
||||
const injected = convertWorkBuddyTranscript([
|
||||
{ type: 'message', id: 'real-user', role: 'user', timestamp: 1, content: text('<system-reminder>Injected</system-reminder><user_query>Actual request</user_query>') },
|
||||
{ type: 'function_call', callId: 'background', name: 'Bash', timestamp: 2, arguments: '{}' },
|
||||
{ type: 'message', id: 'notification', role: 'user', timestamp: 3, content: text('<task-notification><task-id>one</task-id></task-notification>\n\nInjected execution instructions'), providerData: { isMeta: true } },
|
||||
{ type: 'function_call_result', callId: 'background', timestamp: 4, status: 'completed', output: text('Background output') },
|
||||
{ type: 'message', role: 'assistant', timestamp: 5, status: 'completed', content: text('Final answer') }
|
||||
], options)
|
||||
assert.equal(injected.messages.length, 2)
|
||||
assert.equal(injected.messages[0].content, 'Actual request')
|
||||
assert.equal(injected.messages[1].tools?.[0].output, 'Background output')
|
||||
assert.equal(injected.messages[1].turnDurationMs, 4)
|
||||
assert.equal(injected.stats.hiddenInjectedUserRecords, 1)
|
||||
assert.equal(injected.stats.normalizedUserTexts, 1)
|
||||
assert.equal(injected.provenance.sourceEntries.find((entry) => entry.sourceId === 'notification')?.messageId, undefined)
|
||||
for (const candidate of [
|
||||
{ type: 'message', role: 'user', content: text('<task-notification>Quoted by human</task-notification>') },
|
||||
{ type: 'message', role: 'user', content: text('Visible meta message'), providerData: { isMeta: true } }
|
||||
]) assert.equal(convertWorkBuddyTranscript([candidate], options).messages.length, 1)
|
||||
|
||||
const evidencePath = '.tmp/rea-workbuddy-session-export.json'
|
||||
if (existsSync(evidencePath)) {
|
||||
const evidence = JSON.parse(readFileSync(evidencePath, 'utf8'))
|
||||
const file = evidence.normalized_result.file
|
||||
assert.equal(createHash('sha256').update(file.text).digest('hex'), file.sha256)
|
||||
const actual = convertWorkBuddyJsonl(file.text, { ...options,
|
||||
sourceSessionId: evidence.normalized_result.session_id, evidenceId: evidence.evidence_id, sourceSha256: file.sha256
|
||||
})
|
||||
assert.equal(actual.stats.sourceRecords, 2810)
|
||||
assert.equal(actual.stats.forksApplied, 2)
|
||||
assert.equal(actual.stats.unmatchedToolResults, 0)
|
||||
assert.equal(actual.stats.hiddenInjectedUserRecords, 10)
|
||||
assert.equal(actual.stats.normalizedUserTexts, 31)
|
||||
assert.equal(actual.messages.filter((message) => message.role === 'user').length, 31)
|
||||
assert.ok(actual.messages.length > 0)
|
||||
assert.equal(actual.provenance.referencedAttachments.length, 4)
|
||||
assert.equal(actual.messages.filter(message => message.status === 'cancelled').length, 6)
|
||||
assert.equal(actual.messages.filter(message => message.status === 'error').length, 1)
|
||||
assert.match(actual.messages.find(message => message.status === 'error')?.error ?? '', /429/)
|
||||
assert.equal(actual.messages.flatMap(message => message.parts ?? []).filter(part => part.type === 'text' && ['Interrupted by user', '[User Cancelled]'].includes(part.text.trim())).length, 0)
|
||||
const originalTools = actual.messages.flatMap(message => message.tools ?? [])
|
||||
const rawBefore = JSON.stringify(originalTools)
|
||||
const projectedTools = originalTools.map(projectWorkBuddyHistoryTool)
|
||||
assert.equal(projectedTools.length, 691)
|
||||
assert.equal(projectedTools.filter(tool => tool.name === 'todo_write').length, 24)
|
||||
assert.equal(projectedTools.filter(tool => tool.name === 'defer_execute_tool').length, 0)
|
||||
assert.equal(projectedTools.filter(tool => tool.name === 'present_files').length, 10)
|
||||
assert.equal(projectedTools.filter(tool => tool.name === 'askuserquestion').length, 1)
|
||||
assert.equal(JSON.stringify(originalTools), rawBefore)
|
||||
assert.deepEqual(projectedTools.map(tool => tool.argsRaw), originalTools.map(tool => tool.argsRaw))
|
||||
console.log(JSON.stringify({ actualReaEvidence: evidence.evidence_id, stats: actual.stats, roles: {
|
||||
user: actual.messages.filter((message) => message.role === 'user').length,
|
||||
assistant: actual.messages.filter((message) => message.role === 'assistant').length
|
||||
}, reasoningParts: actual.messages.flatMap((message) => message.parts ?? []).filter((part) => part.type === 'reasoning').length,
|
||||
toolStatuses: actual.messages.flatMap((message) => message.tools ?? []).reduce<Record<string, number>>((counts, tool) => ({ ...counts, [tool.status]: (counts[tool.status] ?? 0) + 1 }), {}),
|
||||
warnings: actual.warnings, attachments: actual.provenance.referencedAttachments.length }))
|
||||
}
|
||||
console.log('WorkBuddy import regression passed')
|
||||
Reference in new issue
Block a user