feat: init
This commit is contained in:
+91
@@ -0,0 +1,91 @@
|
||||
import { requestUrl, RequestUrlParam } from "obsidian";
|
||||
import type { BeaverSettings } from "./settings";
|
||||
|
||||
export interface ChatRequest {
|
||||
filename: string;
|
||||
content: string;
|
||||
agent?: string;
|
||||
}
|
||||
|
||||
export interface ChatResponse {
|
||||
status: "ok" | "nothing_to_do" | "in_progress";
|
||||
reason?: string;
|
||||
agent?: string;
|
||||
turns_appended?: number;
|
||||
new_content?: string;
|
||||
}
|
||||
|
||||
export class BeaverApiError extends Error {
|
||||
status: number;
|
||||
body: unknown;
|
||||
constructor(status: number, message: string, body: unknown) {
|
||||
super(message);
|
||||
this.status = status;
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
|
||||
function baseUrl(settings: BeaverSettings): string {
|
||||
const url = settings.baseUrl.trim().replace(/\/+$/, "");
|
||||
if (!url) throw new Error("Beaver: base URL is not configured");
|
||||
return url;
|
||||
}
|
||||
|
||||
function authHeader(settings: BeaverSettings): Record<string, string> {
|
||||
const token = settings.token.trim();
|
||||
if (!token) throw new Error("Beaver: bearer token is not configured");
|
||||
return { Authorization: `Bearer ${token}` };
|
||||
}
|
||||
|
||||
async function call(
|
||||
settings: BeaverSettings,
|
||||
init: Omit<RequestUrlParam, "url"> & { path: string },
|
||||
): Promise<unknown> {
|
||||
const { path, ...rest } = init;
|
||||
const url = `${baseUrl(settings)}${path}`;
|
||||
const headers = {
|
||||
...authHeader(settings),
|
||||
...(rest.headers ?? {}),
|
||||
};
|
||||
// throw=false → we handle non-2xx ourselves so we can extract FastAPI's
|
||||
// {detail: "..."} body and surface a useful message.
|
||||
const res = await requestUrl({ url, throw: false, ...rest, headers });
|
||||
if (res.status < 200 || res.status >= 300) {
|
||||
let detail: unknown;
|
||||
try {
|
||||
detail = res.json;
|
||||
} catch {
|
||||
detail = res.text;
|
||||
}
|
||||
const detailMsg =
|
||||
detail && typeof detail === "object" && "detail" in detail
|
||||
? String((detail as { detail: unknown }).detail)
|
||||
: typeof detail === "string"
|
||||
? detail
|
||||
: `HTTP ${res.status}`;
|
||||
throw new BeaverApiError(res.status, detailMsg, detail);
|
||||
}
|
||||
return res.json;
|
||||
}
|
||||
|
||||
export async function listAgents(settings: BeaverSettings): Promise<string[]> {
|
||||
const body = (await call(settings, { path: "/agents", method: "GET" })) as {
|
||||
agents?: Array<{ name?: unknown }>;
|
||||
};
|
||||
const list = body.agents ?? [];
|
||||
return list
|
||||
.map((a) => (typeof a?.name === "string" ? a.name : null))
|
||||
.filter((n): n is string => !!n);
|
||||
}
|
||||
|
||||
export async function sendChat(
|
||||
settings: BeaverSettings,
|
||||
req: ChatRequest,
|
||||
): Promise<ChatResponse> {
|
||||
return (await call(settings, {
|
||||
path: "/chat",
|
||||
method: "POST",
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify(req),
|
||||
})) as ChatResponse;
|
||||
}
|
||||
Reference in New Issue
Block a user