Fix Jupyter workspace session scoping
This commit is contained in:
@@ -81,7 +81,9 @@ import {
|
|||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import {
|
import {
|
||||||
clearActiveSessionId,
|
clearActiveSessionId,
|
||||||
|
PENDING_WORKSPACE_SESSION_CHANGED_EVENT,
|
||||||
readActiveSessionId,
|
readActiveSessionId,
|
||||||
|
readPendingWorkspaceSessionId,
|
||||||
writeActiveSessionId,
|
writeActiveSessionId,
|
||||||
writePendingWorkspaceSessionId,
|
writePendingWorkspaceSessionId,
|
||||||
} from "@/lib/claw-active-session";
|
} from "@/lib/claw-active-session";
|
||||||
@@ -273,17 +275,46 @@ function useReplayedRunState() {
|
|||||||
readMetadataValue(replayRunMessage?.metadata, "runId"),
|
readMetadataValue(replayRunMessage?.metadata, "runId"),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
const localSessionId =
|
const sessionId = replaySessionId ?? latestSessionId;
|
||||||
typeof window !== "undefined"
|
|
||||||
? normalizeSessionId(readActiveSessionId())
|
|
||||||
: null;
|
|
||||||
const sessionId = replaySessionId ?? latestSessionId ?? localSessionId;
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => ({ active, sessionId, runId }),
|
() => ({ active, sessionId, runId }),
|
||||||
[active, sessionId, runId],
|
[active, sessionId, runId],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function usePendingWorkspaceSessionId() {
|
||||||
|
const [sessionId, setSessionId] = useState<string | null>(() =>
|
||||||
|
typeof window !== "undefined"
|
||||||
|
? normalizeSessionId(readPendingWorkspaceSessionId())
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const refresh = () => {
|
||||||
|
setSessionId(normalizeSessionId(readPendingWorkspaceSessionId()));
|
||||||
|
};
|
||||||
|
window.addEventListener(PENDING_WORKSPACE_SESSION_CHANGED_EVENT, refresh);
|
||||||
|
window.addEventListener("storage", refresh);
|
||||||
|
window.addEventListener("focus", refresh);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener(
|
||||||
|
PENDING_WORKSPACE_SESSION_CHANGED_EVENT,
|
||||||
|
refresh,
|
||||||
|
);
|
||||||
|
window.removeEventListener("storage", refresh);
|
||||||
|
window.removeEventListener("focus", refresh);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function useCurrentThreadSessionId({ includePending = false } = {}) {
|
||||||
|
const currentRun = useReplayedRunState();
|
||||||
|
const pendingSessionId = usePendingWorkspaceSessionId();
|
||||||
|
return currentRun.sessionId ?? (includePending ? pendingSessionId : null);
|
||||||
|
}
|
||||||
|
|
||||||
async function cancelLatestRun(sessionId: string, runId?: string | null) {
|
async function cancelLatestRun(sessionId: string, runId?: string | null) {
|
||||||
await fetch("/api/claw/runs/cancel", {
|
await fetch("/api/claw/runs/cancel", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -298,8 +329,9 @@ async function cancelLatestRun(sessionId: string, runId?: string | null) {
|
|||||||
const ChatTopActions: FC = () => {
|
const ChatTopActions: FC = () => {
|
||||||
const { openFiles } = useActivityPanel();
|
const { openFiles } = useActivityPanel();
|
||||||
const [workspaceOpen, setWorkspaceOpen] = useState(false);
|
const [workspaceOpen, setWorkspaceOpen] = useState(false);
|
||||||
const currentRun = useReplayedRunState();
|
const normalizedSessionId = useCurrentThreadSessionId({
|
||||||
const normalizedSessionId = currentRun.sessionId;
|
includePending: true,
|
||||||
|
});
|
||||||
const workspaceStatus = useJupyterWorkspaceStatus(normalizedSessionId);
|
const workspaceStatus = useJupyterWorkspaceStatus(normalizedSessionId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -444,11 +476,7 @@ function WorkspaceSwitchDialog({
|
|||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
const fieldId = useId();
|
const fieldId = useId();
|
||||||
const effectiveSessionId =
|
const effectiveSessionId = sessionId;
|
||||||
sessionId ??
|
|
||||||
(typeof window !== "undefined"
|
|
||||||
? normalizeSessionId(readActiveSessionId())
|
|
||||||
: null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!open || !effectiveSessionId) return;
|
if (!open || !effectiveSessionId) return;
|
||||||
@@ -726,6 +754,9 @@ const ThreadSuggestionItem: FC = () => {
|
|||||||
|
|
||||||
const Composer: FC = () => {
|
const Composer: FC = () => {
|
||||||
const replayedRun = useReplayedRunState();
|
const replayedRun = useReplayedRunState();
|
||||||
|
const workspaceSessionId = useCurrentThreadSessionId({
|
||||||
|
includePending: true,
|
||||||
|
});
|
||||||
return (
|
return (
|
||||||
<ComposerPrimitive.Root className="aui-composer-root relative flex w-full flex-col">
|
<ComposerPrimitive.Root className="aui-composer-root relative flex w-full flex-col">
|
||||||
<ComposerPrimitive.AttachmentDropzone asChild>
|
<ComposerPrimitive.AttachmentDropzone asChild>
|
||||||
@@ -734,7 +765,7 @@ const Composer: FC = () => {
|
|||||||
className="flex w-full flex-col gap-2 rounded-(--composer-radius) border bg-background p-(--composer-padding) transition-shadow focus-within:border-ring/75 focus-within:ring-2 focus-within:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50"
|
className="flex w-full flex-col gap-2 rounded-(--composer-radius) border bg-background p-(--composer-padding) transition-shadow focus-within:border-ring/75 focus-within:ring-2 focus-within:ring-ring/20 data-[dragging=true]:border-ring data-[dragging=true]:border-dashed data-[dragging=true]:bg-accent/50"
|
||||||
>
|
>
|
||||||
<ComposerAttachments />
|
<ComposerAttachments />
|
||||||
<ComposerWorkspaceStatus sessionId={replayedRun.sessionId} />
|
<ComposerWorkspaceStatus sessionId={workspaceSessionId} />
|
||||||
<ImeComposerInput
|
<ImeComposerInput
|
||||||
placeholder="Send a message..."
|
placeholder="Send a message..."
|
||||||
className="aui-composer-input max-h-32 min-h-10 w-full resize-none bg-transparent px-1.75 py-1 text-sm outline-none placeholder:text-muted-foreground/80"
|
className="aui-composer-input max-h-32 min-h-10 w-full resize-none bg-transparent px-1.75 py-1 text-sm outline-none placeholder:text-muted-foreground/80"
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
const ACTIVE_SESSION_ID_KEY = "claw.activeSessionId";
|
const ACTIVE_SESSION_ID_KEY = "claw.activeSessionId";
|
||||||
const PENDING_WORKSPACE_SESSION_ID_KEY = "claw.pendingWorkspaceSessionId";
|
const PENDING_WORKSPACE_SESSION_ID_KEY = "claw.pendingWorkspaceSessionId";
|
||||||
export const ACTIVE_SESSION_CHANGED_EVENT = "claw-active-session-changed";
|
export const ACTIVE_SESSION_CHANGED_EVENT = "claw-active-session-changed";
|
||||||
|
export const PENDING_WORKSPACE_SESSION_CHANGED_EVENT =
|
||||||
|
"claw-pending-workspace-session-changed";
|
||||||
|
|
||||||
export function readActiveSessionId() {
|
export function readActiveSessionId() {
|
||||||
if (typeof window === "undefined") return null;
|
if (typeof window === "undefined") return null;
|
||||||
@@ -55,6 +57,11 @@ export function writePendingWorkspaceSessionId(
|
|||||||
}
|
}
|
||||||
window.sessionStorage.setItem(PENDING_WORKSPACE_SESSION_ID_KEY, normalized);
|
window.sessionStorage.setItem(PENDING_WORKSPACE_SESSION_ID_KEY, normalized);
|
||||||
window.localStorage.setItem(PENDING_WORKSPACE_SESSION_ID_KEY, normalized);
|
window.localStorage.setItem(PENDING_WORKSPACE_SESSION_ID_KEY, normalized);
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent(PENDING_WORKSPACE_SESSION_CHANGED_EVENT, {
|
||||||
|
detail: { sessionId: normalized },
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function consumePendingWorkspaceSessionId() {
|
export function consumePendingWorkspaceSessionId() {
|
||||||
@@ -63,7 +70,7 @@ export function consumePendingWorkspaceSessionId() {
|
|||||||
return sessionId;
|
return sessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readPendingWorkspaceSessionId() {
|
export function readPendingWorkspaceSessionId() {
|
||||||
if (typeof window === "undefined") return null;
|
if (typeof window === "undefined") return null;
|
||||||
return (
|
return (
|
||||||
normalizeSessionId(
|
normalizeSessionId(
|
||||||
@@ -79,6 +86,11 @@ function clearPendingWorkspaceSessionId() {
|
|||||||
if (typeof window === "undefined") return;
|
if (typeof window === "undefined") return;
|
||||||
window.sessionStorage.removeItem(PENDING_WORKSPACE_SESSION_ID_KEY);
|
window.sessionStorage.removeItem(PENDING_WORKSPACE_SESSION_ID_KEY);
|
||||||
window.localStorage.removeItem(PENDING_WORKSPACE_SESSION_ID_KEY);
|
window.localStorage.removeItem(PENDING_WORKSPACE_SESSION_ID_KEY);
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent(PENDING_WORKSPACE_SESSION_CHANGED_EVENT, {
|
||||||
|
detail: { sessionId: null },
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeSessionId(value: unknown) {
|
function normalizeSessionId(value: unknown) {
|
||||||
|
|||||||
Reference in New Issue
Block a user