feat(webui): add initial webui with websocket chat flow
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import type { ChatSummary } from "./types";
|
||||
|
||||
export class ApiError extends Error {
|
||||
status: number;
|
||||
constructor(status: number, message: string) {
|
||||
super(message);
|
||||
this.status = status;
|
||||
this.name = "ApiError";
|
||||
}
|
||||
}
|
||||
|
||||
async function request<T>(
|
||||
url: string,
|
||||
token: string,
|
||||
init?: RequestInit,
|
||||
): Promise<T> {
|
||||
const res = await fetch(url, {
|
||||
...(init ?? {}),
|
||||
headers: {
|
||||
...(init?.headers ?? {}),
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
credentials: "same-origin",
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new ApiError(res.status, `HTTP ${res.status}`);
|
||||
}
|
||||
return (await res.json()) as T;
|
||||
}
|
||||
|
||||
function splitKey(key: string): { channel: string; chatId: string } {
|
||||
const idx = key.indexOf(":");
|
||||
if (idx === -1) return { channel: "", chatId: key };
|
||||
return { channel: key.slice(0, idx), chatId: key.slice(idx + 1) };
|
||||
}
|
||||
|
||||
export async function listSessions(
|
||||
token: string,
|
||||
base: string = "",
|
||||
): Promise<ChatSummary[]> {
|
||||
type Row = {
|
||||
key: string;
|
||||
created_at: string | null;
|
||||
updated_at: string | null;
|
||||
preview?: string;
|
||||
};
|
||||
const body = await request<{ sessions: Row[] }>(
|
||||
`${base}/api/sessions`,
|
||||
token,
|
||||
);
|
||||
return body.sessions.map((s) => ({
|
||||
key: s.key,
|
||||
...splitKey(s.key),
|
||||
createdAt: s.created_at,
|
||||
updatedAt: s.updated_at,
|
||||
preview: s.preview ?? "",
|
||||
}));
|
||||
}
|
||||
|
||||
export async function fetchSessionMessages(
|
||||
token: string,
|
||||
key: string,
|
||||
base: string = "",
|
||||
): Promise<{
|
||||
key: string;
|
||||
created_at: string | null;
|
||||
updated_at: string | null;
|
||||
messages: Array<{
|
||||
role: string;
|
||||
content: string;
|
||||
timestamp?: string;
|
||||
tool_calls?: unknown;
|
||||
tool_call_id?: string;
|
||||
name?: string;
|
||||
}>;
|
||||
}> {
|
||||
return request(
|
||||
`${base}/api/sessions/${encodeURIComponent(key)}/messages`,
|
||||
token,
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteSession(
|
||||
token: string,
|
||||
key: string,
|
||||
base: string = "",
|
||||
): Promise<boolean> {
|
||||
const body = await request<{ deleted: boolean }>(
|
||||
`${base}/api/sessions/${encodeURIComponent(key)}/delete`,
|
||||
token,
|
||||
);
|
||||
return body.deleted;
|
||||
}
|
||||
Reference in New Issue
Block a user