Fix active session replay state
This commit is contained in:
@@ -19,6 +19,10 @@ import {
|
||||
SidebarProvider,
|
||||
SidebarTrigger,
|
||||
} from "@/components/ui/sidebar";
|
||||
import {
|
||||
readActiveSessionId,
|
||||
writeActiveSessionId,
|
||||
} from "@/lib/claw-active-session";
|
||||
import { ClawSessionReplayProvider } from "@/lib/claw-session-replay";
|
||||
import { ClawAccountGate, useClawAccount } from "./claw-account-gate";
|
||||
|
||||
@@ -31,21 +35,13 @@ export const Assistant = () => {
|
||||
prepareSendMessagesRequest: async (options) => {
|
||||
const body = options.body as Record<string, unknown>;
|
||||
const messages = options.messages as UIMessage[];
|
||||
const selectedSessionId =
|
||||
typeof window !== "undefined"
|
||||
? window.localStorage.getItem("claw.activeSessionId")
|
||||
: null;
|
||||
const selectedSessionId = readActiveSessionId();
|
||||
const lastSessionId = getLastSessionId(messages);
|
||||
const selectedResumeSessionId =
|
||||
messages.length > 1 ? selectedSessionId : null;
|
||||
const outgoingSessionId =
|
||||
lastSessionId ?? selectedResumeSessionId ?? options.id;
|
||||
if (typeof window !== "undefined" && outgoingSessionId) {
|
||||
window.localStorage.setItem(
|
||||
"claw.activeSessionId",
|
||||
outgoingSessionId,
|
||||
);
|
||||
}
|
||||
writeActiveSessionId(outgoingSessionId);
|
||||
|
||||
return {
|
||||
body: {
|
||||
@@ -65,7 +61,7 @@ export const Assistant = () => {
|
||||
});
|
||||
const replaySession = useCallback(
|
||||
(sessionId: string, repository: ExportedMessageRepository) => {
|
||||
window.localStorage.setItem("claw.activeSessionId", sessionId);
|
||||
writeActiveSessionId(sessionId);
|
||||
runtime.thread.import(repository);
|
||||
},
|
||||
[runtime],
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { ReactNode } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { clearActiveSessionId } from "@/lib/claw-active-session";
|
||||
|
||||
export type ClawAccount = {
|
||||
id: string;
|
||||
@@ -131,7 +132,7 @@ export function ClawAccountBar({
|
||||
}) {
|
||||
async function logout() {
|
||||
await fetch("/api/claw/auth/logout", { method: "POST" });
|
||||
window.localStorage.removeItem("claw.activeSessionId");
|
||||
clearActiveSessionId();
|
||||
onLogout();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@ import {
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/components/ui/collapsible";
|
||||
import {
|
||||
readActiveSessionId,
|
||||
writeActiveSessionId,
|
||||
} from "@/lib/claw-active-session";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type ActivityContextValue = {
|
||||
@@ -71,12 +75,7 @@ export function ActivityProvider({ children }: { children: ReactNode }) {
|
||||
}, []);
|
||||
const openFiles = useCallback((nextSessionId?: string | null) => {
|
||||
setMode("files");
|
||||
setSessionId(
|
||||
nextSessionId ??
|
||||
(typeof window !== "undefined"
|
||||
? window.localStorage.getItem("claw.activeSessionId")
|
||||
: null),
|
||||
);
|
||||
setSessionId(nextSessionId ?? readActiveSessionId());
|
||||
setFilesRefreshToken((value) => value + 1);
|
||||
setOpen(true);
|
||||
}, []);
|
||||
@@ -257,7 +256,7 @@ function SessionFilesPanel({
|
||||
let cancelled = false;
|
||||
async function loadFiles() {
|
||||
const activeSessionId = normalizeSessionId(
|
||||
sessionId ?? window.localStorage.getItem("claw.activeSessionId"),
|
||||
sessionId ?? readActiveSessionId(),
|
||||
);
|
||||
setStatus("正在读取聊天中的文件...");
|
||||
try {
|
||||
@@ -285,10 +284,7 @@ function SessionFilesPanel({
|
||||
return;
|
||||
}
|
||||
if (nextPayload.session_id) {
|
||||
window.localStorage.setItem(
|
||||
"claw.activeSessionId",
|
||||
nextPayload.session_id,
|
||||
);
|
||||
writeActiveSessionId(nextPayload.session_id);
|
||||
}
|
||||
setPayload(nextPayload);
|
||||
setStatus("");
|
||||
|
||||
@@ -19,6 +19,11 @@ import {
|
||||
useState,
|
||||
} from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
clearActiveSessionId,
|
||||
readActiveSessionId,
|
||||
writeActiveSessionId,
|
||||
} from "@/lib/claw-active-session";
|
||||
import { useClawSessionReplay } from "@/lib/claw-session-replay";
|
||||
|
||||
type ClawSession = {
|
||||
@@ -106,7 +111,7 @@ const ThreadListNew: FC = () => {
|
||||
return (
|
||||
<div
|
||||
onClickCapture={() => {
|
||||
window.localStorage.removeItem("claw.activeSessionId");
|
||||
clearActiveSessionId();
|
||||
window.dispatchEvent(new Event("claw-active-session-cleared"));
|
||||
}}
|
||||
>
|
||||
@@ -141,7 +146,7 @@ const ClawSessionList: FC = () => {
|
||||
const renameInputRef = useRef<HTMLInputElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setActiveSessionId(window.localStorage.getItem("claw.activeSessionId"));
|
||||
setActiveSessionId(readActiveSessionId());
|
||||
const refreshSessions = () => {
|
||||
fetch("/api/claw/sessions")
|
||||
.then((res) => (res.ok ? res.json() : []))
|
||||
@@ -247,10 +252,7 @@ const ClawSessionList: FC = () => {
|
||||
className="aui-thread-list-item-trigger flex h-full min-w-0 flex-1 items-center truncate px-3 text-start text-sm"
|
||||
onClick={async () => {
|
||||
setOpenMenuSessionId(null);
|
||||
window.localStorage.setItem(
|
||||
"claw.activeSessionId",
|
||||
session.session_id,
|
||||
);
|
||||
writeActiveSessionId(session.session_id);
|
||||
setActiveSessionId(session.session_id);
|
||||
setLoadingSessionId(session.session_id);
|
||||
try {
|
||||
@@ -333,9 +335,7 @@ const ClawSessionList: FC = () => {
|
||||
);
|
||||
setOpenMenuSessionId(null);
|
||||
if (activeSessionId === session.session_id) {
|
||||
window.localStorage.removeItem(
|
||||
"claw.activeSessionId",
|
||||
);
|
||||
clearActiveSessionId();
|
||||
setActiveSessionId(null);
|
||||
window.dispatchEvent(
|
||||
new Event("claw-active-session-cleared"),
|
||||
|
||||
@@ -62,6 +62,11 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import {
|
||||
clearActiveSessionId,
|
||||
readActiveSessionId,
|
||||
writeActiveSessionId,
|
||||
} from "@/lib/claw-active-session";
|
||||
import { useClawSessionReplay } from "@/lib/claw-session-replay";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -193,6 +198,15 @@ function useRefreshReplayedRun() {
|
||||
const runStatus = await fetchLatestRunStatus(activeSessionId);
|
||||
if (cancelled) return;
|
||||
if (runStatus?.status === "queued" || runStatus?.status === "running") {
|
||||
const response = await fetch(`/api/claw/sessions/${activeSessionId}`, {
|
||||
cache: "no-store",
|
||||
});
|
||||
if (!response.ok || cancelled) return;
|
||||
const payload = await response.json();
|
||||
replaySession(
|
||||
activeSessionId,
|
||||
toReplayRepository(payload, activeSessionId, runStatus),
|
||||
);
|
||||
return;
|
||||
}
|
||||
const response = await fetch(`/api/claw/sessions/${activeSessionId}`, {
|
||||
@@ -243,7 +257,7 @@ function useReplayedRunState() {
|
||||
});
|
||||
const localSessionId =
|
||||
typeof window !== "undefined"
|
||||
? normalizeSessionId(window.localStorage.getItem("claw.activeSessionId"))
|
||||
? normalizeSessionId(readActiveSessionId())
|
||||
: null;
|
||||
const sessionId = replaySessionId ?? latestSessionId ?? localSessionId;
|
||||
return useMemo(
|
||||
@@ -722,7 +736,7 @@ function useComposerContextStatus() {
|
||||
useEffect(() => {
|
||||
const cleanLatestSessionId = normalizeSessionId(latestSessionId);
|
||||
if (cleanLatestSessionId) {
|
||||
window.localStorage.setItem("claw.activeSessionId", cleanLatestSessionId);
|
||||
writeActiveSessionId(cleanLatestSessionId);
|
||||
window.setTimeout(() => {
|
||||
window.dispatchEvent(new Event("claw-sessions-changed"));
|
||||
}, 0);
|
||||
@@ -752,13 +766,10 @@ function useComposerContextStatus() {
|
||||
: {};
|
||||
let sessionId = normalizeSessionId(
|
||||
normalizeSessionId(latestSessionId) ||
|
||||
normalizeSessionId(
|
||||
window.localStorage.getItem("claw.activeSessionId"),
|
||||
) ||
|
||||
normalizeSessionId(readActiveSessionId()) ||
|
||||
normalizeSessionId(statePayload.active_session_id),
|
||||
);
|
||||
if (sessionId)
|
||||
window.localStorage.setItem("claw.activeSessionId", sessionId);
|
||||
if (sessionId) writeActiveSessionId(sessionId);
|
||||
let sessionPayload: ClawStoredSession | null = null;
|
||||
let contextBudget: ContextBudget | undefined;
|
||||
if (sessionId) {
|
||||
@@ -772,7 +783,7 @@ function useComposerContextStatus() {
|
||||
sessionPayload =
|
||||
(await sessionResponse.json()) as ClawStoredSession;
|
||||
} else if (sessionResponse.status === 404) {
|
||||
window.localStorage.removeItem("claw.activeSessionId");
|
||||
clearActiveSessionId();
|
||||
sessionId = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,11 @@ import {
|
||||
SidebarTrigger,
|
||||
useSidebar,
|
||||
} from "@/components/ui/sidebar";
|
||||
import {
|
||||
clearActiveSessionId,
|
||||
readActiveSessionId,
|
||||
writeActiveSessionId,
|
||||
} from "@/lib/claw-active-session";
|
||||
import { useClawSessionReplay } from "@/lib/claw-session-replay";
|
||||
|
||||
type ThreadListSidebarProps = React.ComponentProps<typeof Sidebar> & {
|
||||
@@ -157,7 +162,7 @@ function CollapsedSidebarRail({
|
||||
<div className="flex flex-col items-center gap-3">
|
||||
<div
|
||||
onClickCapture={() => {
|
||||
window.localStorage.removeItem("claw.activeSessionId");
|
||||
clearActiveSessionId();
|
||||
window.dispatchEvent(new Event("claw-active-session-cleared"));
|
||||
}}
|
||||
>
|
||||
@@ -360,7 +365,7 @@ function useSidebarSessions(open: boolean) {
|
||||
) {
|
||||
const cleanSessionId = normalizeSessionId(sessionId);
|
||||
if (!cleanSessionId) return;
|
||||
window.localStorage.setItem("claw.activeSessionId", cleanSessionId);
|
||||
writeActiveSessionId(cleanSessionId);
|
||||
setLoadingSessionId(sessionId);
|
||||
try {
|
||||
const response = await fetch(`/api/claw/sessions/${cleanSessionId}`, {
|
||||
@@ -438,14 +443,13 @@ function AccountMenu({
|
||||
setState(nextState);
|
||||
setSessions(nextSessions);
|
||||
const activeSessionId = normalizeSessionId(
|
||||
window.localStorage.getItem("claw.activeSessionId") ??
|
||||
nextState?.active_session_id,
|
||||
readActiveSessionId() ?? nextState?.active_session_id,
|
||||
);
|
||||
if (!activeSessionId) {
|
||||
setActiveSession(null);
|
||||
return;
|
||||
}
|
||||
window.localStorage.setItem("claw.activeSessionId", activeSessionId);
|
||||
writeActiveSessionId(activeSessionId);
|
||||
const response = await fetch(`/api/claw/sessions/${activeSessionId}`, {
|
||||
cache: "no-store",
|
||||
});
|
||||
@@ -460,7 +464,7 @@ function AccountMenu({
|
||||
|
||||
async function logout() {
|
||||
await fetch("/api/claw/auth/logout", { method: "POST" });
|
||||
window.localStorage.removeItem("claw.activeSessionId");
|
||||
clearActiveSessionId();
|
||||
onLogout();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
"use client";
|
||||
|
||||
const ACTIVE_SESSION_ID_KEY = "claw.activeSessionId";
|
||||
|
||||
export function readActiveSessionId() {
|
||||
if (typeof window === "undefined") return null;
|
||||
return (
|
||||
normalizeSessionId(window.sessionStorage.getItem(ACTIVE_SESSION_ID_KEY)) ??
|
||||
normalizeSessionId(window.localStorage.getItem(ACTIVE_SESSION_ID_KEY))
|
||||
);
|
||||
}
|
||||
|
||||
export function writeActiveSessionId(sessionId: string | null | undefined) {
|
||||
if (typeof window === "undefined") return;
|
||||
const normalized = normalizeSessionId(sessionId);
|
||||
if (!normalized) {
|
||||
clearActiveSessionId();
|
||||
return;
|
||||
}
|
||||
window.sessionStorage.setItem(ACTIVE_SESSION_ID_KEY, normalized);
|
||||
window.localStorage.setItem(ACTIVE_SESSION_ID_KEY, normalized);
|
||||
}
|
||||
|
||||
export function clearActiveSessionId() {
|
||||
if (typeof window === "undefined") return;
|
||||
window.sessionStorage.removeItem(ACTIVE_SESSION_ID_KEY);
|
||||
window.localStorage.removeItem(ACTIVE_SESSION_ID_KEY);
|
||||
}
|
||||
|
||||
function normalizeSessionId(value: unknown) {
|
||||
if (typeof value !== "string") return null;
|
||||
const trimmed = value.trim();
|
||||
return trimmed || null;
|
||||
}
|
||||
Reference in New Issue
Block a user