mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-08-15 19:44:24 +00:00
98 lines
4.2 KiB
TypeScript
98 lines
4.2 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { decodeOpenClaw, toObservations } from '../../src/providers/openclaw/index.js'
|
|
import { ObservationEnvelope } from '../../src/observations.js'
|
|
import { OBSERVATION_SCHEMA_VERSION } from '../../src/schema.js'
|
|
import type { DecodeContext } from '../../src/contracts.js'
|
|
|
|
const context: DecodeContext = { privacyKey: 'k', providerId: 'openclaw', sourceRef: '/data/agents/myagent/sessions/test-sess-1.jsonl' }
|
|
|
|
const RECORDS: string[] = [
|
|
JSON.stringify({ type: 'session', version: 3, id: 'test-sess-1', timestamp: '2026-04-20T10:00:00.000Z', cwd: '/tmp' }),
|
|
JSON.stringify({ type: 'model_change', id: 'mc1', timestamp: '2026-04-20T10:00:01.000Z', provider: 'anthropic', modelId: 'claude-sonnet-4-6' }),
|
|
JSON.stringify({
|
|
type: 'message', id: 'u1', timestamp: '2026-04-20T10:00:02.000Z',
|
|
message: { role: 'user', content: [{ type: 'text', text: 'hello world' }] },
|
|
}),
|
|
JSON.stringify({
|
|
type: 'message', id: 'a1', timestamp: '2026-04-20T10:00:03.000Z',
|
|
message: {
|
|
role: 'assistant', model: 'claude-sonnet-4-6',
|
|
content: [{ type: 'text', text: 'Hi!' }],
|
|
usage: { input: 500, output: 100, cacheRead: 200, cacheWrite: 50, totalTokens: 850 },
|
|
},
|
|
}),
|
|
JSON.stringify({
|
|
type: 'message', id: 'a2', timestamp: '2026-04-20T10:00:05.000Z',
|
|
message: {
|
|
role: 'assistant', model: 'claude-sonnet-4-6',
|
|
content: [
|
|
{ type: 'text', text: 'Running command' },
|
|
{ type: 'toolCall', name: 'exec', arguments: { command: 'ls -la' } },
|
|
{ type: 'tool_use', name: 'write', arguments: { path: '/tmp/y' } },
|
|
],
|
|
usage: { input: 600, output: 200, cacheRead: 100, cacheWrite: 0, totalTokens: 900, cost: { total: 0.05 } },
|
|
},
|
|
}),
|
|
// Duplicate id -> must drop.
|
|
JSON.stringify({
|
|
type: 'message', id: 'a1', timestamp: '2026-04-20T10:00:06.000Z',
|
|
message: {
|
|
role: 'assistant', model: 'claude-sonnet-4-6',
|
|
content: [{ type: 'text', text: 'Duplicate' }],
|
|
usage: { input: 10, output: 10, cacheRead: 0, cacheWrite: 0, totalTokens: 20 },
|
|
},
|
|
}),
|
|
]
|
|
|
|
describe('openclaw rich decode (moved to @codeburn/core)', () => {
|
|
it('decodes assistant calls into cost-free rich calls, preserving provider-reported cost', () => {
|
|
const { calls } = decodeOpenClaw({ records: RECORDS, context })
|
|
expect(calls).toHaveLength(2)
|
|
|
|
const [first, second] = calls
|
|
expect(first!.model).toBe('claude-sonnet-4-6')
|
|
expect(first!.inputTokens).toBe(500)
|
|
expect(first!.outputTokens).toBe(100)
|
|
expect(first!.cacheReadInputTokens).toBe(200)
|
|
expect(first!.cacheCreationInputTokens).toBe(50)
|
|
expect(first!.costBasis).toBe('estimated')
|
|
expect(first).not.toHaveProperty('costUSD')
|
|
expect(first!.userMessage).toBe('hello world')
|
|
expect(first!.deduplicationKey).toBe('openclaw:test-sess-1:a1')
|
|
|
|
expect(second!.model).toBe('claude-sonnet-4-6')
|
|
expect(second!.inputTokens).toBe(600)
|
|
expect(second!.outputTokens).toBe(200)
|
|
expect(second!.costBasis).toBe('measured')
|
|
expect(second!.costUSD).toBe(0.05)
|
|
expect(second!.tools).toEqual(['Bash', 'Write'])
|
|
expect(second!.rawBashCommands).toEqual(['ls -la'])
|
|
expect(second!.userMessage).toBe('')
|
|
})
|
|
|
|
it('threads a live seenKeys set so a repeated id across passes drops', () => {
|
|
const seen = new Set<string>()
|
|
const first = decodeOpenClaw({ records: RECORDS.slice(0, 4), context, seenKeys: seen }).calls
|
|
expect(first).toHaveLength(1)
|
|
const again = decodeOpenClaw({ records: RECORDS.slice(0, 4), context, seenKeys: seen }).calls
|
|
expect(again).toEqual([])
|
|
})
|
|
|
|
it('toObservations produces a schema-valid, content-free envelope', () => {
|
|
const { calls } = decodeOpenClaw({ records: RECORDS, context })
|
|
const { sessions } = toObservations(
|
|
{ sessionId: 'test-sess-1', projectPath: '/tmp', calls },
|
|
{ privacyKey: 'test-privacy-key', provider: 'openclaw' },
|
|
)
|
|
const envelope = {
|
|
schemaVersion: OBSERVATION_SCHEMA_VERSION,
|
|
generator: { name: '@codeburn/core', version: '0.0.0-test' },
|
|
sessions,
|
|
}
|
|
expect(ObservationEnvelope.safeParse(envelope).success).toBe(true)
|
|
const toolNames = sessions.flatMap(s => s.calls.flatMap(c => c.toolNames))
|
|
expect(toolNames).toContain('Bash')
|
|
expect(toolNames).toContain('Write')
|
|
})
|
|
})
|