import { useQuery } from '@tanstack/react-query' import type { UseQueryResult } from '@tanstack/react-query' import { apiFetch } from '../../api/client' import { adaptSession } from '../../api/adapters' import type { Session, SessionDTO } from '../../api/adapters' export interface TurnDTO { turn_id: string seq: number role: 'user' | 'assistant' | 'tool' | 'system' timestamp: number content: string model?: string tokens_in?: number tokens_out?: number cost_usd?: number tool_calls?: unknown metadata?: unknown } export interface Turn { i: number role: 'user' | 'assistant' | 'tool' body: string model?: string tokensIn?: number tokensOut?: number toolName?: string toolKind?: 'call' | 'result' toolOutput?: string } export interface SessionWithTurnsDTO extends SessionDTO { turns: TurnDTO[] } export interface SessionWithTurns extends Omit { turns: Turn[] } function extractToolCall( raw: unknown, ): { toolName?: string; toolKind?: 'call' | 'result'; toolOutput?: string } { if (raw == null || typeof raw !== 'object') { return {} } const obj = raw as Record // opencode format: {tool, status, output} const opencodeTool = typeof obj['tool'] === 'string' ? obj['tool'] : undefined const opencodeStatus = typeof obj['status'] === 'string' ? obj['status'] : undefined if (opencodeTool != null) { const kind = opencodeStatus === 'completed' ? 'result' : 'call' const output = typeof obj['output'] === 'string' ? obj['output'] : undefined return { toolName: opencodeTool, toolKind: kind as 'call' | 'result', toolOutput: output } } // claude-code format: {name, type: "tool_use"|"tool_result"} const name = typeof obj['name'] === 'string' ? obj['name'] : undefined const type = typeof obj['type'] === 'string' ? obj['type'] : undefined const kind = type === 'tool_use' ? 'call' as const : type === 'tool_result' ? 'result' as const : undefined if (name != null && kind != null) { const output = typeof obj['content'] === 'string' ? obj['content'] : undefined return { toolName: name, toolKind: kind, toolOutput: output } } return {} } function extractFirstToolCall( raw: unknown, ): { toolName?: string; toolKind?: 'call' | 'result'; toolOutput?: string } { if (Array.isArray(raw) && raw.length > 0) { return extractToolCall(raw[0]) } return extractToolCall(raw) } export function adaptTurn(d: TurnDTO): Turn { const role: 'user' | 'assistant' | 'tool' = d.role === 'system' ? 'assistant' : d.role const { toolName, toolKind, toolOutput } = extractFirstToolCall(d.tool_calls) return { i: d.seq, role, body: d.content, model: d.model, tokensIn: d.tokens_in, tokensOut: d.tokens_out, toolName, toolKind, toolOutput, } } export function useSession( tool: string, host: string, id: string, ): UseQueryResult { return useQuery({ queryKey: ['session', tool, host, id], queryFn: async () => { const dto = await apiFetch( `/api/v1/sessions/${tool}/${host}/${id}`, ) const session = adaptSession(dto) return { ...session, turns: dto.turns.map(adaptTurn) } }, }) }