517583d1c4
- Mobile-first PWA with dark glassmorphic theme - Pulse: status card, recent sessions, memory snapshot - Memory: view/edit agent + user memory with usage bars - History: session list, platform filter, search, session replay - TanStack Query hooks for all Hermes WebAPI endpoints - Bottom tab navigation, safe-area support
89 lines
3.0 KiB
TypeScript
89 lines
3.0 KiB
TypeScript
const BASE = process.env.NEXT_PUBLIC_HERMES_API || "http://localhost:8787";
|
|
|
|
async function get<T>(path: string): Promise<T> {
|
|
const res = await fetch(`${BASE}${path}`);
|
|
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
return res.json();
|
|
}
|
|
|
|
async function post<T>(path: string, body?: unknown): Promise<T> {
|
|
const res = await fetch(`${BASE}${path}`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
});
|
|
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
return res.json();
|
|
}
|
|
|
|
async function patch<T>(path: string, body: unknown): Promise<T> {
|
|
const res = await fetch(`${BASE}${path}`, {
|
|
method: "PATCH",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(body),
|
|
});
|
|
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
return res.json();
|
|
}
|
|
|
|
async function del<T>(path: string, body?: unknown): Promise<T> {
|
|
const res = await fetch(`${BASE}${path}`, {
|
|
method: "DELETE",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
});
|
|
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
return res.json();
|
|
}
|
|
|
|
import type {
|
|
Session, Message, MemoryResponse, SkillSummary, SkillDetail,
|
|
CronJob, ConfigResponse, SearchResult,
|
|
} from "./types";
|
|
|
|
// Sessions
|
|
export const fetchSessions = (limit = 50, offset = 0, source?: string) =>
|
|
get<{ items: Session[]; total: number }>(
|
|
`/api/sessions?limit=${limit}&offset=${offset}${source ? `&source=${source}` : ""}`
|
|
);
|
|
|
|
export const fetchSession = (id: string) =>
|
|
get<{ session: Session }>(`/api/sessions/${id}`);
|
|
|
|
export const fetchMessages = (sessionId: string, limit = 200, offset = 0) =>
|
|
get<{ items: Message[]; total: number }>(
|
|
`/api/sessions/${sessionId}/messages?limit=${limit}&offset=${offset}`
|
|
);
|
|
|
|
export const searchSessions = (q: string, limit = 20) =>
|
|
get<{ query: string; count: number; results: SearchResult[] }>(
|
|
`/api/sessions/search?q=${encodeURIComponent(q)}&limit=${limit}`
|
|
);
|
|
|
|
// Memory
|
|
export const fetchMemory = () => get<MemoryResponse>("/api/memory");
|
|
|
|
export const addMemory = (target: string, content: string) =>
|
|
post<{ success: boolean }>("/api/memory", { target, content });
|
|
|
|
export const patchMemory = (target: string, old_text: string, content: string) =>
|
|
patch<{ success: boolean }>("/api/memory", { target, old_text, content });
|
|
|
|
export const deleteMemory = (target: string, old_text: string) =>
|
|
del<{ success: boolean }>("/api/memory", { target, old_text });
|
|
|
|
// Skills
|
|
export const fetchSkills = (category?: string) =>
|
|
get<{ success: boolean; skills: SkillSummary[] }>(
|
|
`/api/skills${category ? `?category=${category}` : ""}`
|
|
);
|
|
|
|
export const fetchSkill = (name: string) =>
|
|
get<SkillDetail>(`/api/skills/${name}`);
|
|
|
|
// Config
|
|
export const fetchConfig = () => get<ConfigResponse>("/api/config");
|
|
|
|
// Health
|
|
export const fetchHealth = () => get<{ status: string }>("/api/health");
|