From 997f5cd60bce5b4c797607b7b7d3fa783c627d5b Mon Sep 17 00:00:00 2001 From: wuyang6 Date: Thu, 14 May 2026 15:53:58 +0800 Subject: [PATCH] Add direct session URL route --- frontend/app/app/assistant.tsx | 48 ++++++++++++++++++- frontend/app/app/session/[sessionId]/page.tsx | 10 ++++ 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 frontend/app/app/session/[sessionId]/page.tsx diff --git a/frontend/app/app/assistant.tsx b/frontend/app/app/assistant.tsx index 86ce711..cd2e6d0 100644 --- a/frontend/app/app/assistant.tsx +++ b/frontend/app/app/assistant.tsx @@ -7,11 +7,15 @@ import { useChatRuntime, } from "@assistant-ui/react-ai-sdk"; import type { UIMessage } from "ai"; -import { useCallback, useMemo } from "react"; +import { useCallback, useEffect, useMemo, useRef } from "react"; import { ActivityPanel, ActivityProvider, } from "@/components/assistant-ui/activity-panel"; +import { + fetchLatestRunStatus, + toReplayRepository, +} from "@/components/assistant-ui/thread-list"; import { Thread } from "@/components/assistant-ui/thread"; import { ThreadListSidebar } from "@/components/assistant-ui/threadlist-sidebar"; import { @@ -27,8 +31,13 @@ import { import { ClawSessionReplayProvider } from "@/lib/claw-session-replay"; import { ClawAccountGate, useClawAccount } from "./claw-account-gate"; -export const Assistant = () => { +type AssistantProps = { + initialSessionId?: string; +}; + +export const Assistant = ({ initialSessionId }: AssistantProps = {}) => { const { account, isLoading, setAccount } = useClawAccount(); + const loadedInitialSessionRef = useRef(null); const transport = useMemo( () => new AssistantChatTransport({ @@ -81,6 +90,41 @@ export const Assistant = () => { [runtime], ); + useEffect(() => { + const sessionId = initialSessionId?.trim(); + if (!account || !sessionId) return; + if (loadedInitialSessionRef.current === sessionId) return; + loadedInitialSessionRef.current = sessionId; + const targetSessionId = sessionId; + let cancelled = false; + + async function loadSession() { + try { + writeActiveSessionId(targetSessionId); + const response = await fetch(`/api/claw/sessions/${targetSessionId}`, { + cache: "no-store", + }); + if (!response.ok || cancelled) return; + const payload = await response.json(); + const runStatus = await fetchLatestRunStatus(targetSessionId); + if (cancelled) return; + replaySession( + targetSessionId, + toReplayRepository(payload, targetSessionId, runStatus), + ); + } catch { + if (!cancelled) { + loadedInitialSessionRef.current = null; + } + } + } + + void loadSession(); + return () => { + cancelled = true; + }; + }, [account, initialSessionId, replaySession]); + if (isLoading) { return (
diff --git a/frontend/app/app/session/[sessionId]/page.tsx b/frontend/app/app/session/[sessionId]/page.tsx new file mode 100644 index 0000000..9fc260d --- /dev/null +++ b/frontend/app/app/session/[sessionId]/page.tsx @@ -0,0 +1,10 @@ +import { Assistant } from "../../assistant"; + +export default async function SessionPage({ + params, +}: { + params: Promise<{ sessionId: string }>; +}) { + const { sessionId } = await params; + return ; +}