mirror of
https://github.com/agentscope-ai/ReMe.git
synced 2026-09-05 08:06:15 +00:00
* refactor(packaging): reorganize published packages * fix(packaging): install AgentScope extra in wheel smoke * docs: align package guides and documentation site * ci(workflow): add core dependency verification step in Python package build - Add a workflow step to verify released core dependencies by installing the wheel with core extras - Assert the presence of the static index.html file to ensure proper package contents - Create and use a temporary virtual environment for isolation during verification - Keep existing artifacts upload step intact and conditional on inputs.upload_artifacts flag * fix(ci): update package installation dependencies in Windows workflow - Change pip install from editable reme_studio and core to only dev and as extras - Remove installation of reme_studio and core to streamline dependency setup - Ensure Windows CI uses the correct extras for testing environment * fix(tests): add missing commas in toml file reads in package version tests - Added trailing commas in the tomllib.loads calls for auto-fin and daily_paper configs - Ensured consistent syntax to prevent potential tuple misinterpretation - Improved readability and correctness of the test setup code * fix(packaging): protect qwenpaw releases and test Studio health
155 lines
4.4 KiB
TypeScript
155 lines
4.4 KiB
TypeScript
import type {
|
|
AppConfig,
|
|
FileStat,
|
|
GraphSnapshot,
|
|
ReMeHealth,
|
|
ReMeResponse,
|
|
StreamChunk,
|
|
} from "./types";
|
|
import { decodeSseEvent } from "./chat-stream";
|
|
import { healthFromResponse } from "./health-status";
|
|
import { translate, useLanguageStore, type TranslationKey } from "./i18n";
|
|
import {
|
|
WORKSPACE_FILE_LIMIT,
|
|
workspaceFileListing,
|
|
type WorkspaceFileListing,
|
|
} from "./workspace-files";
|
|
import { displayReMeApiEndpoint, normalizeReMeApiUrl } from "./api-endpoint";
|
|
|
|
export const REME_API_URL = normalizeReMeApiUrl(
|
|
process.env.NEXT_PUBLIC_REME_API_URL || "http://127.0.0.1:2333",
|
|
);
|
|
export const REME_API_ENDPOINT = displayReMeApiEndpoint(
|
|
REME_API_URL,
|
|
typeof window === "undefined" ? undefined : window.location.origin,
|
|
);
|
|
const message = (key: TranslationKey, status: number) =>
|
|
translate(useLanguageStore.getState().language, key, {
|
|
status: String(status),
|
|
});
|
|
|
|
async function parseResponse<T>(response: Response): Promise<ReMeResponse<T>> {
|
|
let payload: ReMeResponse<T>;
|
|
try {
|
|
payload = (await response.json()) as ReMeResponse<T>;
|
|
} catch {
|
|
throw new Error(message("invalidResponse", response.status));
|
|
}
|
|
if (!response.ok || !payload.success) {
|
|
const detail =
|
|
typeof payload.answer === "string"
|
|
? payload.answer
|
|
: message("requestFailed", response.status);
|
|
throw new Error(detail);
|
|
}
|
|
return payload;
|
|
}
|
|
|
|
export async function callReMe<T>(
|
|
action: string,
|
|
body: Record<string, unknown> = {},
|
|
): Promise<ReMeResponse<T>> {
|
|
const response = await fetch(`${REME_API_URL}/${action}`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(body),
|
|
});
|
|
return parseResponse<T>(response);
|
|
}
|
|
|
|
export async function getAppConfig(): Promise<AppConfig> {
|
|
return (await callReMe<AppConfig>("app_config")).answer;
|
|
}
|
|
|
|
export async function getReMeVersion(): Promise<string> {
|
|
return String((await callReMe<string>("version")).answer);
|
|
}
|
|
|
|
export async function getReMeStatus(): Promise<ReMeResponse<string>> {
|
|
return callReMe<string>("status");
|
|
}
|
|
|
|
export async function getReMeHealth(): Promise<ReMeHealth | undefined> {
|
|
const response = await callReMe<string>("health_check");
|
|
return healthFromResponse(response);
|
|
}
|
|
|
|
export async function rebuildReMeIndex(): Promise<ReMeResponse<unknown>> {
|
|
return callReMe<unknown>("reindex");
|
|
}
|
|
|
|
export async function getGraphSnapshot(): Promise<GraphSnapshot> {
|
|
return (await callReMe<GraphSnapshot>("graph_snapshot")).answer;
|
|
}
|
|
|
|
export async function listWorkspaceFiles(
|
|
extensions: string[],
|
|
): Promise<WorkspaceFileListing> {
|
|
const response = await callReMe<string>("list", {
|
|
path: "",
|
|
recursive: true,
|
|
limit: WORKSPACE_FILE_LIMIT,
|
|
sort_by: "mtime",
|
|
extensions,
|
|
});
|
|
return workspaceFileListing(response.metadata.items);
|
|
}
|
|
|
|
export async function readWorkspaceFile(
|
|
path: string,
|
|
): Promise<{ content: string; stat: FileStat }> {
|
|
const response = await callReMe<string>("load", { path });
|
|
return {
|
|
content: String(response.answer ?? ""),
|
|
stat: response.metadata as unknown as FileStat,
|
|
};
|
|
}
|
|
|
|
export async function saveWorkspaceFile(
|
|
path: string,
|
|
content: string,
|
|
expectedMtime?: string,
|
|
): Promise<FileStat> {
|
|
const response = await callReMe<string>("save", {
|
|
path,
|
|
content,
|
|
expected_mtime: expectedMtime || null,
|
|
});
|
|
return response.metadata as unknown as FileStat;
|
|
}
|
|
|
|
export async function streamChat(
|
|
query: string,
|
|
sessionId: string | undefined,
|
|
signal: AbortSignal,
|
|
onChunk: (chunk: StreamChunk) => void,
|
|
): Promise<void> {
|
|
const response = await fetch(`${REME_API_URL}/chat`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Accept: "text/event-stream",
|
|
},
|
|
body: JSON.stringify({ query, session_id: sessionId || null }),
|
|
signal,
|
|
});
|
|
if (!response.ok || !response.body)
|
|
throw new Error(message("agentUnavailable", response.status));
|
|
|
|
const reader = response.body.getReader();
|
|
const decoder = new TextDecoder();
|
|
let buffer = "";
|
|
while (true) {
|
|
const { value, done } = await reader.read();
|
|
buffer += decoder.decode(value, { stream: !done });
|
|
const events = buffer.split(/\r?\n\r?\n/);
|
|
buffer = events.pop() || "";
|
|
for (const event of events) {
|
|
const chunk = decodeSseEvent(event);
|
|
if (chunk) onChunk(chunk);
|
|
}
|
|
if (done) break;
|
|
}
|
|
const finalChunk = decodeSseEvent(buffer);
|
|
if (finalChunk) onChunk(finalChunk);
|
|
}
|