2026-04-16 08:38:18 +08:00
|
|
|
import { request } from '../client'
|
2026-04-11 21:33:04 +08:00
|
|
|
|
|
|
|
|
export interface SessionSummary {
|
|
|
|
|
id: string
|
|
|
|
|
source: string
|
|
|
|
|
model: string
|
|
|
|
|
title: string | null
|
2026-04-22 14:00:34 +08:00
|
|
|
preview?: string
|
2026-04-11 21:33:04 +08:00
|
|
|
started_at: number
|
|
|
|
|
ended_at: number | null
|
2026-04-19 23:32:01 +08:00
|
|
|
last_active?: number
|
2026-04-11 21:33:04 +08:00
|
|
|
message_count: number
|
|
|
|
|
tool_call_count: number
|
|
|
|
|
input_tokens: number
|
|
|
|
|
output_tokens: number
|
2026-04-14 14:47:18 +08:00
|
|
|
cache_read_tokens: number
|
|
|
|
|
cache_write_tokens: number
|
|
|
|
|
reasoning_tokens: number
|
2026-04-11 21:33:04 +08:00
|
|
|
billing_provider: string | null
|
|
|
|
|
estimated_cost_usd: number
|
2026-04-14 14:47:18 +08:00
|
|
|
actual_cost_usd: number | null
|
|
|
|
|
cost_status: string
|
2026-04-30 20:17:38 +08:00
|
|
|
workspace?: string | null
|
2026-04-11 21:33:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SessionDetail extends SessionSummary {
|
|
|
|
|
messages: HermesMessage[]
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-22 14:00:34 +08:00
|
|
|
export interface SessionSearchResult extends SessionSummary {
|
|
|
|
|
matched_message_id: number | null
|
|
|
|
|
snippet: string
|
|
|
|
|
rank: number
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-11 21:33:04 +08:00
|
|
|
export interface HermesMessage {
|
|
|
|
|
id: number
|
|
|
|
|
session_id: string
|
|
|
|
|
role: 'user' | 'assistant' | 'system' | 'tool'
|
|
|
|
|
content: string
|
|
|
|
|
tool_call_id: string | null
|
|
|
|
|
tool_calls: any[] | null
|
|
|
|
|
tool_name: string | null
|
|
|
|
|
timestamp: number
|
|
|
|
|
token_count: number | null
|
|
|
|
|
finish_reason: string | null
|
|
|
|
|
reasoning: string | null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function fetchSessions(source?: string, limit?: number): Promise<SessionSummary[]> {
|
|
|
|
|
const params = new URLSearchParams()
|
|
|
|
|
if (source) params.set('source', source)
|
|
|
|
|
if (limit) params.set('limit', String(limit))
|
|
|
|
|
const query = params.toString()
|
2026-04-16 08:38:18 +08:00
|
|
|
const res = await request<{ sessions: SessionSummary[] }>(`/api/hermes/sessions${query ? `?${query}` : ''}`)
|
2026-04-11 21:33:04 +08:00
|
|
|
return res.sessions
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-01 11:27:43 +08:00
|
|
|
/**
|
|
|
|
|
* Fetch Hermes sessions only (exclude api_server source)
|
|
|
|
|
*/
|
|
|
|
|
export async function fetchHermesSessions(source?: string, limit?: number): Promise<SessionSummary[]> {
|
|
|
|
|
const params = new URLSearchParams()
|
|
|
|
|
if (source) params.set('source', source)
|
|
|
|
|
if (limit) params.set('limit', String(limit))
|
|
|
|
|
const query = params.toString()
|
|
|
|
|
const res = await request<{ sessions: SessionSummary[] }>(`/api/hermes/sessions/hermes${query ? `?${query}` : ''}`)
|
|
|
|
|
return res.sessions
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-22 14:00:34 +08:00
|
|
|
export async function searchSessions(q: string, source?: string, limit?: number): Promise<SessionSearchResult[]> {
|
|
|
|
|
const params = new URLSearchParams()
|
|
|
|
|
params.set('q', q)
|
|
|
|
|
if (source) params.set('source', source)
|
|
|
|
|
if (limit) params.set('limit', String(limit))
|
|
|
|
|
const query = params.toString()
|
|
|
|
|
const res = await request<{ results: SessionSearchResult[] }>(`/api/hermes/search/sessions?${query}`)
|
|
|
|
|
return res.results
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-11 21:33:04 +08:00
|
|
|
export async function fetchSession(id: string): Promise<SessionDetail | null> {
|
|
|
|
|
try {
|
2026-04-16 08:38:18 +08:00
|
|
|
const res = await request<{ session: SessionDetail }>(`/api/hermes/sessions/${id}`)
|
2026-04-11 21:33:04 +08:00
|
|
|
return res.session
|
|
|
|
|
} catch {
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-01 11:27:43 +08:00
|
|
|
/**
|
|
|
|
|
* Fetch Hermes session detail only (exclude api_server source)
|
|
|
|
|
*/
|
|
|
|
|
export async function fetchHermesSession(id: string): Promise<SessionDetail | null> {
|
|
|
|
|
try {
|
|
|
|
|
const res = await request<{ session: SessionDetail }>(`/api/hermes/sessions/hermes/${id}`)
|
|
|
|
|
return res.session
|
|
|
|
|
} catch {
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-11 21:33:04 +08:00
|
|
|
export async function deleteSession(id: string): Promise<boolean> {
|
|
|
|
|
try {
|
2026-04-16 08:38:18 +08:00
|
|
|
await request(`/api/hermes/sessions/${id}`, { method: 'DELETE' })
|
2026-04-11 21:33:04 +08:00
|
|
|
return true
|
|
|
|
|
} catch {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-12 23:59:18 +08:00
|
|
|
|
|
|
|
|
export async function renameSession(id: string, title: string): Promise<boolean> {
|
|
|
|
|
try {
|
2026-04-16 08:38:18 +08:00
|
|
|
await request(`/api/hermes/sessions/${id}/rename`, {
|
2026-04-12 23:59:18 +08:00
|
|
|
method: 'POST',
|
|
|
|
|
body: JSON.stringify({ title }),
|
|
|
|
|
})
|
|
|
|
|
return true
|
|
|
|
|
} catch {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-22 16:14:50 +08:00
|
|
|
|
2026-04-30 20:17:38 +08:00
|
|
|
export async function setSessionWorkspace(id: string, workspace: string | null): Promise<boolean> {
|
|
|
|
|
try {
|
|
|
|
|
await request(`/api/hermes/sessions/${id}/workspace`, {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
body: JSON.stringify({ workspace: workspace || '' }),
|
|
|
|
|
})
|
|
|
|
|
return true
|
|
|
|
|
} catch {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-29 16:26:24 +08:00
|
|
|
export interface UsageStatsResponse {
|
|
|
|
|
total_input_tokens: number
|
|
|
|
|
total_output_tokens: number
|
|
|
|
|
total_cache_read_tokens: number
|
|
|
|
|
total_cache_write_tokens: number
|
|
|
|
|
total_reasoning_tokens: number
|
|
|
|
|
total_sessions: number
|
|
|
|
|
total_cost: number
|
2026-04-30 13:46:31 +02:00
|
|
|
total_api_calls?: number
|
|
|
|
|
period_days?: number
|
2026-04-29 16:26:24 +08:00
|
|
|
model_usage: Array<{
|
|
|
|
|
model: string
|
|
|
|
|
input_tokens: number
|
|
|
|
|
output_tokens: number
|
|
|
|
|
cache_read_tokens: number
|
|
|
|
|
cache_write_tokens: number
|
|
|
|
|
reasoning_tokens: number
|
|
|
|
|
sessions: number
|
|
|
|
|
}>
|
|
|
|
|
daily_usage: Array<{
|
|
|
|
|
date: string
|
|
|
|
|
tokens: number
|
|
|
|
|
cache: number
|
|
|
|
|
sessions: number
|
|
|
|
|
cost: number
|
|
|
|
|
}>
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-30 13:46:31 +02:00
|
|
|
export async function fetchUsageStats(days = 30): Promise<UsageStatsResponse> {
|
|
|
|
|
const safeDays = Number.isFinite(days) ? Math.max(1, Math.floor(days)) : 30
|
|
|
|
|
const params = new URLSearchParams()
|
|
|
|
|
params.set('days', String(safeDays))
|
|
|
|
|
return request<UsageStatsResponse>(`/api/hermes/usage/stats?${params}`)
|
2026-04-29 16:26:24 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-22 16:14:50 +08:00
|
|
|
export async function fetchSessionUsage(ids: string[]): Promise<Record<string, { input_tokens: number; output_tokens: number }>> {
|
|
|
|
|
if (ids.length === 0) return {}
|
|
|
|
|
const params = new URLSearchParams()
|
|
|
|
|
params.set('ids', ids.join(','))
|
|
|
|
|
return request(`/api/hermes/sessions/usage?${params}`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function fetchSessionUsageSingle(id: string): Promise<{ input_tokens: number; output_tokens: number } | null> {
|
|
|
|
|
try {
|
|
|
|
|
return await request<{ input_tokens: number; output_tokens: number }>(`/api/hermes/sessions/${id}/usage`)
|
|
|
|
|
} catch {
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function fetchContextLength(profile?: string): Promise<number> {
|
|
|
|
|
const params = new URLSearchParams()
|
|
|
|
|
if (profile) params.set('profile', profile)
|
|
|
|
|
const query = params.toString()
|
|
|
|
|
const res = await request<{ context_length: number }>(`/api/hermes/sessions/context-length${query ? `?${query}` : ''}`)
|
|
|
|
|
return res.context_length
|
|
|
|
|
}
|