~bigbes/lethe

ref: 12df3f43091141353457bf5058e9524e6d7a910c lethe/web/src/features/session/useSession.ts -rw-r--r-- 2.4 KiB
12df3f43 — Eugene Blikh web: adapter — add Session.sessionId, SavedSearch DTO; fix composite-id call sites a month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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'
}

export interface SessionWithTurnsDTO extends SessionDTO {
  turns: TurnDTO[]
}

export interface SessionWithTurns extends Omit<Session, 'turns'> {
  turns: Turn[]
}

function extractToolCalls(
  raw: unknown,
): { toolName?: string; toolKind?: 'call' | 'result' } {
  if (raw == null || typeof raw !== 'object') {
    return {}
  }
  const obj = raw as Record<string, unknown>
  const name = typeof obj['name'] === 'string' ? obj['name'] : undefined
  const kind =
    obj['kind'] === 'call' || obj['kind'] === 'result'
      ? (obj['kind'] as 'call' | 'result')
      : undefined
  if (name == null && kind == null) {
    return {}
  }
  return { toolName: name, toolKind: kind }
}

export function adaptTurn(d: TurnDTO): Turn {
  const role: 'user' | 'assistant' | 'tool' =
    d.role === 'system' ? 'assistant' : d.role
  const { toolName, toolKind } = extractToolCalls(d.tool_calls)
  return {
    i: d.seq,
    role,
    body: d.content,
    model: d.model,
    tokensIn: d.tokens_in,
    tokensOut: d.tokens_out,
    toolName,
    toolKind,
  }
}

export function useSession(
  tool: string,
  host: string,
  id: string,
): UseQueryResult<SessionWithTurns> {
  // id is the composite `tool/host/session_id` from Session.id.
  // Extract only the session_id tail for the API URL.
  const rawSessionId = id.split('/').slice(2).join('/')

  return useQuery({
    queryKey: ['session', tool, host, id],
    queryFn: async () => {
      const dto = await apiFetch<SessionWithTurnsDTO>(
        `/api/v1/sessions/${tool}/${host}/${rawSessionId}`,
      )
      const session = adaptSession(dto)
      return { ...session, turns: dto.turns.map(adaptTurn) }
    },
  })
}