Normalize active session ids in frontend

This commit is contained in:
武阳
2026-05-07 15:38:37 +08:00
parent ce6445bf77
commit 61e3cd1681
5 changed files with 53 additions and 18 deletions
@@ -10,7 +10,7 @@ export async function GET(req: Request) {
const incoming = new URL(req.url);
const url = new URL(`${CLAW_API_URL}/api/context-budget`);
url.searchParams.set("account_id", account.id);
const sessionId = incoming.searchParams.get("session_id");
const sessionId = incoming.searchParams.get("session_id")?.trim();
if (sessionId) url.searchParams.set("session_id", sessionId);
try {
@@ -10,7 +10,8 @@ export async function GET(
if (!account)
return Response.json({ error: "请先登录账号" }, { status: 401 });
const { sessionId } = await params;
const { sessionId: rawSessionId } = await params;
const sessionId = rawSessionId.trim();
const url = new URL(`${CLAW_API_URL}/api/sessions/${sessionId}`);
url.searchParams.set("account_id", account.id);
const response = await fetch(url, { cache: "no-store" });
@@ -32,7 +33,8 @@ export async function DELETE(
if (!account)
return Response.json({ error: "请先登录账号" }, { status: 401 });
const { sessionId } = await params;
const { sessionId: rawSessionId } = await params;
const sessionId = rawSessionId.trim();
const url = new URL(`${CLAW_API_URL}/api/sessions/${sessionId}`);
url.searchParams.set("account_id", account.id);
const response = await fetch(url, { method: "DELETE", cache: "no-store" });
@@ -54,7 +56,8 @@ export async function PATCH(
if (!account)
return Response.json({ error: "请先登录账号" }, { status: 401 });
const { sessionId } = await params;
const { sessionId: rawSessionId } = await params;
const sessionId = rawSessionId.trim();
const url = new URL(`${CLAW_API_URL}/api/sessions/${sessionId}`);
url.searchParams.set("account_id", account.id);
const response = await fetch(url, {
@@ -209,13 +209,15 @@ function SessionFilesPanel({
useEffect(() => {
let cancelled = false;
async function loadFiles() {
const activeSessionId =
sessionId ?? window.localStorage.getItem("claw.activeSessionId");
const activeSessionId = normalizeSessionId(
sessionId ?? window.localStorage.getItem("claw.activeSessionId"),
);
if (!activeSessionId) {
setPayload({ input: [], output: [] });
setStatus("当前还没有可用会话。");
return;
}
window.localStorage.setItem("claw.activeSessionId", activeSessionId);
setStatus("正在读取聊天中的文件...");
try {
const url = new URL("/api/claw/files", window.location.origin);
@@ -280,6 +282,12 @@ function SessionFilesPanel({
);
}
function normalizeSessionId(value: unknown) {
if (typeof value !== "string") return null;
const trimmed = value.trim();
return trimmed || null;
}
function FileSection({
title,
files,
@@ -519,8 +519,9 @@ function useComposerContextStatus() {
});
useEffect(() => {
if (typeof latestSessionId === "string" && latestSessionId) {
window.localStorage.setItem("claw.activeSessionId", latestSessionId);
const cleanLatestSessionId = normalizeSessionId(latestSessionId);
if (cleanLatestSessionId) {
window.localStorage.setItem("claw.activeSessionId", cleanLatestSessionId);
window.setTimeout(() => {
window.dispatchEvent(new Event("claw-sessions-changed"));
}, 0);
@@ -548,11 +549,15 @@ function useComposerContextStatus() {
const statePayload = stateResponse.ok
? ((await stateResponse.json()) as ClawState)
: {};
const sessionId =
(typeof latestSessionId === "string" && latestSessionId) ||
window.localStorage.getItem("claw.activeSessionId") ||
statePayload.active_session_id ||
null;
const sessionId = normalizeSessionId(
normalizeSessionId(latestSessionId) ||
normalizeSessionId(
window.localStorage.getItem("claw.activeSessionId"),
) ||
normalizeSessionId(statePayload.active_session_id),
);
if (sessionId)
window.localStorage.setItem("claw.activeSessionId", sessionId);
let sessionPayload: ClawStoredSession | null = null;
let contextBudget: ContextBudget | undefined;
if (sessionId) {
@@ -680,6 +685,12 @@ function readMetadataValue(metadata: unknown, key: string): unknown {
return undefined;
}
function normalizeSessionId(value: unknown) {
if (typeof value !== "string") return null;
const trimmed = value.trim();
return trimmed || null;
}
function formatCompactTokenCount(value: number) {
if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)}M`;
if (value >= 1_000) return `${(value / 1_000).toFixed(1)}K`;
@@ -357,15 +357,20 @@ function useSidebarSessions(open: boolean) {
repository: ExportedMessageRepository,
) => void,
) {
window.localStorage.setItem("claw.activeSessionId", sessionId);
const cleanSessionId = normalizeSessionId(sessionId);
if (!cleanSessionId) return;
window.localStorage.setItem("claw.activeSessionId", cleanSessionId);
setLoadingSessionId(sessionId);
try {
const response = await fetch(`/api/claw/sessions/${sessionId}`, {
const response = await fetch(`/api/claw/sessions/${cleanSessionId}`, {
cache: "no-store",
});
if (!response.ok) return;
const payload = (await response.json()) as ReplaySessionPayload;
replaySession(sessionId, toReplayRepository(payload, sessionId));
replaySession(
cleanSessionId,
toReplayRepository(payload, cleanSessionId),
);
} finally {
setLoadingSessionId(null);
}
@@ -430,13 +435,15 @@ function AccountMenu({
: [];
setState(nextState);
setSessions(nextSessions);
const activeSessionId =
const activeSessionId = normalizeSessionId(
window.localStorage.getItem("claw.activeSessionId") ??
nextState?.active_session_id;
nextState?.active_session_id,
);
if (!activeSessionId) {
setActiveSession(null);
return;
}
window.localStorage.setItem("claw.activeSessionId", activeSessionId);
const response = await fetch(`/api/claw/sessions/${activeSessionId}`, {
cache: "no-store",
});
@@ -610,6 +617,12 @@ function AccountMenu({
);
}
function normalizeSessionId(value: unknown) {
if (typeof value !== "string") return null;
const trimmed = value.trim();
return trimmed || null;
}
function aggregateUsageByModel(sessions: ClawSessionSummary[]) {
const byModel = new Map<
string,