feat(observabilidade): parser JSONL com detecção de tool_calls e skills
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { parseSessionFile } from '../services/sessions/parser.js'
|
||||
import { mkdtempSync, writeFileSync } from 'fs'
|
||||
import { tmpdir } from 'os'
|
||||
import { join } from 'path'
|
||||
|
||||
function writeJsonl(lines: object[]): string {
|
||||
const dir = mkdtempSync(join(tmpdir(), 'obs-test-'))
|
||||
const path = join(dir, 'session-test.jsonl')
|
||||
writeFileSync(path, lines.map((l) => JSON.stringify(l)).join('\n'))
|
||||
return path
|
||||
}
|
||||
|
||||
describe('parseSessionFile', () => {
|
||||
it('extrai metadata básica de sessão mínima', async () => {
|
||||
const path = writeJsonl([
|
||||
{ type: 'permission-mode', permissionMode: 'default', sessionId: 's1' },
|
||||
{
|
||||
type: 'user',
|
||||
timestamp: '2026-04-23T10:00:00Z',
|
||||
message: { role: 'user', content: [{ type: 'text', text: 'olá mundo' }] },
|
||||
},
|
||||
{
|
||||
type: 'assistant',
|
||||
timestamp: '2026-04-23T10:00:30Z',
|
||||
message: { role: 'assistant', content: [{ type: 'text', text: 'olá' }] },
|
||||
},
|
||||
])
|
||||
const result = await parseSessionFile(path)
|
||||
expect(result.meta.session_id).toBe('s1')
|
||||
expect(result.meta.user_messages).toBe(1)
|
||||
expect(result.meta.assistant_msgs).toBe(1)
|
||||
expect(result.meta.tool_calls).toBe(0)
|
||||
expect(result.meta.first_prompt).toBe('olá mundo')
|
||||
expect(result.meta.permission_mode).toBe('default')
|
||||
expect(result.meta.outcome).toBe('completed')
|
||||
})
|
||||
|
||||
it('conta tool_calls e recolhe tools_used', async () => {
|
||||
const path = writeJsonl([
|
||||
{
|
||||
type: 'assistant',
|
||||
timestamp: '2026-04-23T10:00:00Z',
|
||||
message: {
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{ type: 'tool_use', name: 'Bash', input: { command: 'ls' } },
|
||||
{ type: 'tool_use', name: 'Read', input: { file_path: '/tmp/x' } },
|
||||
],
|
||||
},
|
||||
},
|
||||
])
|
||||
const result = await parseSessionFile(path)
|
||||
expect(result.meta.tool_calls).toBe(2)
|
||||
expect(result.meta.tools_used).toEqual(expect.arrayContaining(['Bash', 'Read']))
|
||||
})
|
||||
|
||||
it('detecta skill invocation em system-reminder', async () => {
|
||||
const path = writeJsonl([
|
||||
{
|
||||
type: 'system',
|
||||
timestamp: '2026-04-23T10:00:00Z',
|
||||
message: { role: 'system', content: [{ type: 'text', text: 'Launching skill: superpowers:brainstorming' }] },
|
||||
},
|
||||
])
|
||||
const result = await parseSessionFile(path)
|
||||
expect(result.meta.skills_invoked).toContain('superpowers:brainstorming')
|
||||
})
|
||||
|
||||
it('ignora linhas JSON inválidas silenciosamente', async () => {
|
||||
const path = writeJsonl([
|
||||
{ type: 'user', message: { role: 'user', content: [{ type: 'text', text: 'válido' }] } },
|
||||
])
|
||||
const { writeFileSync } = await import('fs')
|
||||
writeFileSync(path, 'linha inválida\n' + JSON.stringify({ type: 'user', message: { role: 'user', content: [{ type: 'text', text: 'válido' }] } }))
|
||||
const result = await parseSessionFile(path)
|
||||
expect(result.meta.user_messages).toBe(1)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user