@agent-native/core 0.31.1 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat-threads.d.ts","sourceRoot":"","sources":["../../src/client/use-chat-threads.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,iBAAiB,GAAG,WAAW,GAAG,WAAW,CAAC;AAMnD,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qEAAqE;IACrE,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAqED,wBAAgB,cAAc,CAC5B,MAAM,SAA+C,EACrD,UAAU,CAAC,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,eAAe,GAAG,IAAI,EAC9B,OAAO,CAAC,EAAE,qBAAqB;;;;iCA0Wd,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;uBAoNV,MAAM;uBAK/B,MAAM;6BAtMA,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;0BAkBtB,MAAM,UAAU,OAAO,KAAG,OAAO,CAAC,OAAO,CAAC;8BAuD1C,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;6BAgEzB,MAAM,SAAS,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;2BA0M7C,MAAM,mBACC,kBAAkB,GAAG,IAAI,KACzC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;yBA7GnB,MAAM,QACJ;QACJ,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,iBAAiB,CAAC;KACjC;8BA0Ec,MAAM,WAAW,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;2BA6HnD,MAAM,KAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;;sBAzP9C,MAAM;EA8Rd"}
1
+ {"version":3,"file":"use-chat-threads.d.ts","sourceRoot":"","sources":["../../src/client/use-chat-threads.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,KAAK,iBAAiB,GAAG,WAAW,GAAG,WAAW,CAAC;AAMnD,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qEAAqE;IACrE,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAqED,wBAAgB,cAAc,CAC5B,MAAM,SAA+C,EACrD,UAAU,CAAC,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,eAAe,GAAG,IAAI,EAC9B,OAAO,CAAC,EAAE,qBAAqB;;;;iCAiXd,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;uBAoNV,MAAM;uBAK/B,MAAM;6BAtMA,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;0BAkBtB,MAAM,UAAU,OAAO,KAAG,OAAO,CAAC,OAAO,CAAC;8BAuD1C,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;6BAgEzB,MAAM,SAAS,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;2BA0M7C,MAAM,mBACC,kBAAkB,GAAG,IAAI,KACzC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;yBA7GnB,MAAM,QACJ;QACJ,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,iBAAiB,CAAC;KACjC;8BA0Ec,MAAM,WAAW,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;2BA6HnD,MAAM,KAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;;sBAzP9C,MAAM;EA8Rd"}
@@ -333,7 +333,14 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
333
333
  setIsLoading(true);
334
334
  const loadedThreads = await fetchThreads();
335
335
  const savedId = activeThreadIdRef.current;
336
- const loadedHasSavedId = Boolean(savedId && (loadedThreads ?? []).some((t) => t.id === savedId));
336
+ if (loadedThreads === undefined) {
337
+ // Thread-list fetch failed. Do not reclassify a saved id as a new
338
+ // optimistic tab; AssistantChat should still get a chance to restore
339
+ // the specific saved thread via /threads/:id.
340
+ setIsLoading(false);
341
+ return;
342
+ }
343
+ const loadedHasSavedId = Boolean(savedId && loadedThreads.some((t) => t.id === savedId));
337
344
  if (savedId &&
338
345
  newlyCreatedRef.current.has(savedId) &&
339
346
  !loadedHasSavedId) {
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat-threads.js","sourceRoot":"","sources":["../../src/client/use-chat-threads.ts"],"names":[],"mappings":"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","sourcesContent":["import { useState, useEffect, useCallback, useRef, useMemo } from \"react\";\nimport { agentNativePath } from \"./api-path.js\";\n\nexport interface ChatThreadScope {\n type: string;\n id: string;\n label?: string;\n}\n\nexport interface ChatThreadSummary {\n id: string;\n title: string;\n preview: string;\n messageCount: number;\n createdAt: number;\n updatedAt: number;\n scope: ChatThreadScope | null;\n pinnedAt?: number | null;\n archivedAt?: number | null;\n}\n\nexport interface ChatThreadData {\n id: string;\n ownerEmail: string;\n title: string;\n preview: string;\n threadData: string;\n messageCount: number;\n createdAt: number;\n updatedAt: number;\n scope: ChatThreadScope | null;\n pinnedAt?: number | null;\n archivedAt?: number | null;\n}\n\nexport interface ChatThreadSnapshot {\n threadData: string;\n title: string;\n preview: string;\n messageCount: number;\n}\n\ntype ThreadTitleSource = \"generated\" | \"extracted\";\n\ninterface ForkSnapshotWithScope extends ChatThreadSnapshot {\n scope: ChatThreadScope | null;\n}\n\nexport interface UseChatThreadsOptions {\n /** Create an optimistic empty thread on mount when no active thread exists. */\n autoCreate?: boolean;\n /** Restore the active thread from localStorage. Defaults to true. */\n restoreActiveThread?: boolean;\n}\n\nconst ACTIVE_THREAD_KEY = \"agent-chat-active-thread\";\nconst THREADS_UPDATED_EVENT = \"agent-chat:threads-updated\";\n\nfunction emitThreadsUpdated() {\n if (typeof window === \"undefined\") return;\n window.dispatchEvent(new CustomEvent(THREADS_UPDATED_EVENT));\n}\n\nfunction scopeKeySegment(scope?: ChatThreadScope | null): string {\n if (!scope) return \"\";\n return `:scope:${scope.type}:${scope.id}`;\n}\n\nfunction activeThreadStorageKey(\n storageKey?: string,\n scope?: ChatThreadScope | null,\n): string {\n const scopePart = scopeKeySegment(scope);\n return storageKey\n ? `${ACTIVE_THREAD_KEY}:${storageKey}${scopePart}`\n : `${ACTIVE_THREAD_KEY}${scopePart}`;\n}\n\nfunction activeThreadSeenStorageKey(activeThreadKey: string): string {\n return `${activeThreadKey}:seen`;\n}\n\nfunction createLocalThreadId(): string {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return `thread-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\nfunction scopesMatch(\n a?: ChatThreadScope | null,\n b?: ChatThreadScope | null,\n): boolean {\n if (!a || !b) return false;\n return a.type === b.type && a.id === b.id;\n}\n\nfunction threadCanStayVisibleInScope(\n threadScope: ChatThreadScope | null,\n currentScope?: ChatThreadScope | null,\n): boolean {\n if (!threadScope) return true;\n return scopesMatch(threadScope, currentScope);\n}\n\nfunction nextThreadTitle(\n currentTitle: string | undefined,\n incomingTitle: string,\n incomingPreview: string,\n source: ThreadTitleSource = \"extracted\",\n options: { preserveUserTitle?: boolean } = {},\n): string {\n if (options.preserveUserTitle && currentTitle) return currentTitle;\n if (source === \"generated\") return incomingTitle;\n if (!currentTitle) return incomingTitle;\n if (!incomingTitle) return currentTitle;\n if (currentTitle !== incomingTitle && currentTitle !== incomingPreview) {\n return currentTitle;\n }\n return incomingTitle;\n}\n\nexport function useChatThreads(\n apiUrl = agentNativePath(\"/_agent-native/agent-chat\"),\n storageKey?: string,\n scope?: ChatThreadScope | null,\n options?: UseChatThreadsOptions,\n) {\n const autoCreate = options?.autoCreate !== false;\n const restoreActiveThread = options?.restoreActiveThread !== false;\n // Each (storageKey, scope) pair gets its own active-thread localStorage key\n // for chats that belong to a resource. General chats keep using the unscoped\n // key even while the user is looking at a resource, so clicking into a deck,\n // design, form, etc. doesn't make a global conversation vanish.\n const activeThreadKey = useMemo(() => {\n return activeThreadStorageKey(storageKey, scope);\n }, [storageKey, scope?.type, scope?.id]);\n // Companion key recording when the saved active thread was last live in\n // this client. A revived orphan tab (id in localStorage but not on the\n // server and not created this session) must keep its real last-seen time\n // so the 12h stale-tab cleanup can age it out — stamping it `Date.now()`\n // on every mount (the old behaviour) reset the clock forever, so\n // abandoned empty tabs never got pruned.\n const activeThreadSeenKey = useMemo(\n () => activeThreadSeenStorageKey(activeThreadKey),\n [activeThreadKey],\n );\n const initialActiveThreadRef = useRef<{\n id: string | null;\n isNew: boolean;\n } | null>(null);\n if (initialActiveThreadRef.current === null) {\n let id: string | null = null;\n let isNew = false;\n if (typeof window !== \"undefined\") {\n try {\n id = restoreActiveThread ? localStorage.getItem(activeThreadKey) : null;\n } catch {\n id = null;\n }\n if (!id && autoCreate) {\n id = createLocalThreadId();\n isNew = true;\n }\n }\n initialActiveThreadRef.current = { id, isNew };\n }\n\n const [threads, setThreads] = useState<ChatThreadSummary[]>([]);\n const threadsRef = useRef<ChatThreadSummary[]>(threads);\n threadsRef.current = threads;\n\n // IDs we generated client-side this session — consumers use this to know\n // whether to skip the per-thread restore skeleton, and we use it to\n // protect the optimistic-only thread from being yanked out of local\n // state when the server's threads list (which never sees it) loads.\n const newlyCreatedRef = useRef<Set<string>>(\n initialActiveThreadRef.current.isNew && initialActiveThreadRef.current.id\n ? new Set([initialActiveThreadRef.current.id])\n : new Set(),\n );\n const optimisticThreadScopesRef = useRef<Map<string, ChatThreadScope | null>>(\n new Map(),\n );\n const pendingPinnedAtRef = useRef<Map<string, number | null>>(new Map());\n const pendingArchivedAtRef = useRef<Map<string, number | null>>(new Map());\n const userRenamedThreadIdsRef = useRef<Set<string>>(new Set());\n const userRenamedClearTimersRef = useRef<\n Map<string, ReturnType<typeof setTimeout>>\n >(new Map());\n\n const clearUserRenamedThread = useCallback((threadId: string) => {\n const timer = userRenamedClearTimersRef.current.get(threadId);\n if (timer) {\n clearTimeout(timer);\n userRenamedClearTimersRef.current.delete(threadId);\n }\n userRenamedThreadIdsRef.current.delete(threadId);\n }, []);\n\n const markUserRenamedThread = useCallback((threadId: string) => {\n userRenamedThreadIdsRef.current.add(threadId);\n const existingTimer = userRenamedClearTimersRef.current.get(threadId);\n if (existingTimer) clearTimeout(existingTimer);\n const timer = setTimeout(() => {\n userRenamedClearTimersRef.current.delete(threadId);\n userRenamedThreadIdsRef.current.delete(threadId);\n }, 30_000);\n userRenamedClearTimersRef.current.set(threadId, timer);\n }, []);\n\n useEffect(() => {\n return () => {\n for (const timer of userRenamedClearTimersRef.current.values()) {\n clearTimeout(timer);\n }\n userRenamedClearTimersRef.current.clear();\n userRenamedThreadIdsRef.current.clear();\n };\n }, []);\n\n // Latest scope as a ref so `createThread` (a useCallback that we don't\n // want to depend on scope identity) reads the current value at call\n // time. The scope a new chat inherits is the one in effect when the +\n // button is clicked, not when the hook first mounted.\n const scopeRef = useRef<ChatThreadScope | null | undefined>(scope);\n scopeRef.current = scope;\n\n const readKnownThreadScope = useCallback(\n (id: string): ChatThreadScope | null | undefined => {\n const thread = threadsRef.current.find((t) => t.id === id);\n if (thread) return thread.scope ?? null;\n if (optimisticThreadScopesRef.current.has(id)) {\n return optimisticThreadScopesRef.current.get(id) ?? null;\n }\n return undefined;\n },\n [],\n );\n\n // Seed the active thread synchronously so the chat shell can paint\n // immediately. This may restore the saved id or create a local-only fresh id,\n // depending on options. Creating a local id is safe: no row is POSTed here,\n // so empty page loads do not create ghost `chat_threads` rows.\n const [activeThreadId, setActiveThreadId] = useState<string | null>(\n initialActiveThreadRef.current.id,\n );\n const [isLoading, setIsLoading] = useState(true);\n const fetchedRef = useRef(false);\n const activeThreadIdRef = useRef(activeThreadId);\n activeThreadIdRef.current = activeThreadId;\n\n // Persist active thread ID — and rehydrate on scope flips. When the user\n // navigates from deck A to deck B, `activeThreadKey` changes; we re-read B's\n // scoped thread only if the currently visible chat is itself scoped to a\n // different resource. Unscoped chats are global and stay visible.\n const persistedKeyRef = useRef(activeThreadKey);\n useEffect(() => {\n if (persistedKeyRef.current !== activeThreadKey) {\n const currentId = activeThreadIdRef.current;\n if (currentId) {\n const currentThreadScope = readKnownThreadScope(currentId);\n // Thread metadata not yet loaded from the server — we can't tell\n // whether the visible chat is general (stays) or scoped-elsewhere\n // (swaps). Defer until `threads` resolves and this effect re-runs;\n // we intentionally do NOT update `persistedKeyRef` so the next\n // render gets another shot. Without this guard, navigating into a\n // resource before `GET /threads` resolves silently dropped the\n // active general chat the user was just in.\n if (currentThreadScope === undefined) {\n return;\n }\n if (threadCanStayVisibleInScope(currentThreadScope, scopeRef.current)) {\n persistedKeyRef.current = activeThreadKey;\n return;\n }\n }\n persistedKeyRef.current = activeThreadKey;\n try {\n setActiveThreadId(localStorage.getItem(activeThreadKey));\n } catch {\n setActiveThreadId(null);\n }\n return;\n }\n try {\n if (activeThreadId) {\n const threadScope = readKnownThreadScope(activeThreadId);\n if (threadScope === undefined) return;\n const targetKey = activeThreadStorageKey(storageKey, threadScope);\n localStorage.setItem(targetKey, activeThreadId);\n localStorage.setItem(\n activeThreadSeenStorageKey(targetKey),\n String(Date.now()),\n );\n } else {\n localStorage.removeItem(activeThreadKey);\n localStorage.removeItem(activeThreadSeenKey);\n }\n } catch {}\n }, [\n activeThreadId,\n activeThreadKey,\n activeThreadSeenKey,\n readKnownThreadScope,\n storageKey,\n threads,\n ]);\n\n const fetchThreads = useCallback(async () => {\n try {\n const res = await fetch(`${apiUrl}/threads`);\n if (!res.ok) return;\n const data = await res.json();\n setThreads((prev) => {\n const loaded = (data.threads ?? []) as ChatThreadSummary[];\n const loadedIds = new Set(loaded.map((t) => t.id));\n // Preserve any optimistic threads we've created this session that\n // haven't shown up in the server list yet — the server only learns\n // about a thread when the user actually sends a message and the\n // agent run's `persistSubmittedUserMessage` writes the row.\n const optimisticOnly = prev.filter(\n (t) => newlyCreatedRef.current.has(t.id) && !loadedIds.has(t.id),\n );\n // Reconcile each server thread against our local copy. If the local\n // copy has a newer updatedAt or higher messageCount, keep those\n // fields — the server probably hasn't observed the user's latest\n // send yet, and naively replacing makes the recent-chats list\n // visibly jump back to older timestamps right after a send.\n const merged = loaded.map((server) => {\n const local = prev.find((t) => t.id === server.id);\n if (!local) return server;\n const next = { ...server };\n if (local.updatedAt > server.updatedAt) {\n next.updatedAt = local.updatedAt;\n }\n if (userRenamedThreadIdsRef.current.has(server.id) && local.title) {\n next.title = local.title;\n }\n if (pendingPinnedAtRef.current.has(server.id)) {\n next.pinnedAt = pendingPinnedAtRef.current.get(server.id) ?? null;\n }\n if (pendingArchivedAtRef.current.has(server.id)) {\n next.archivedAt =\n pendingArchivedAtRef.current.get(server.id) ?? null;\n }\n if (local.messageCount > server.messageCount) {\n next.messageCount = local.messageCount;\n if (local.preview) next.preview = local.preview;\n if (local.title) next.title = local.title;\n }\n // Preserve optimistic scope: when the server creates the row\n // on first message it does so without scope, and the next PUT\n // (saveThreadData) writes the local scope back. In the brief\n // window between those, the server list returns scope: null\n // while the user is clearly working inside a deck — keep the\n // local value so the tab bar doesn't blink unscoped.\n if (local.scope && !server.scope) {\n next.scope = local.scope;\n }\n return next;\n });\n return [...optimisticOnly, ...merged];\n });\n return data.threads as ChatThreadSummary[];\n } catch {\n return undefined;\n }\n }, [apiUrl]);\n\n // Add a client-generated thread to the local list optimistically.\n //\n // Critically, this does NOT `POST /threads` to the server — that path was\n // creating an empty row in `chat_threads` (message_count=0, no\n // agent_runs) on every page mount and every \"+\" click. The server\n // already creates the row idempotently the moment the user actually\n // sends their first message (`persistSubmittedUserMessage` →\n // `createThread`), so the client doesn't need to pre-create it. This\n // makes the threads table reflect real conversations only.\n const addOptimisticThread = useCallback(\n (\n id: string,\n threadScope: ChatThreadScope | null,\n // When reviving a tab the user left open in a prior session, pass the\n // persisted last-seen time so the 12h stale-tab cleanup can still age\n // it out. Omit for genuinely new tabs (defaults to now).\n seedAt?: number,\n ) => {\n const stamp =\n typeof seedAt === \"number\" && Number.isFinite(seedAt)\n ? seedAt\n : Date.now();\n const optimistic: ChatThreadSummary = {\n id,\n title: \"\",\n preview: \"\",\n messageCount: 0,\n createdAt: stamp,\n updatedAt: stamp,\n scope: threadScope,\n };\n optimisticThreadScopesRef.current.set(id, threadScope);\n setThreads((prev) =>\n prev.some((t) => t.id === id) ? prev : [optimistic, ...prev],\n );\n },\n [],\n );\n\n // Initial load: load threads from server, then reconcile against the\n // saved active thread.\n //\n // - savedId in loadedThreads → keep it (user's last conversation).\n // - savedId in newlyCreatedRef (we just created it this session) → keep\n // it; the server hasn't seen it yet because there's no POST anymore,\n // the row gets written when the user sends a message.\n // - savedId is set but neither on the server nor newly created here →\n // it's an empty tab the user left open. A never-messaged tab is never\n // POSTed (that was the 127-ghost-threads problem), and the only record\n // that it's a deliberately-open tab — newlyCreatedRef — is wiped by the\n // reload. So on refresh we can't tell it apart from a stale ghost.\n // Keep it exactly as the user left it: re-register it as an optimistic\n // empty tab rather than resurrecting an unrelated old conversation. The\n // composer is fully functional with this id (the server writes the row\n // on first message, same as any new tab), so there's no 404 to avoid.\n // This is what makes \"the state you left is the state you see on\n // refresh\" hold — stale (>12h) tabs are still cleared downstream.\n // - No savedId → synthesize a fresh local id (no POST; server creates the\n // row on first message). The server may contain chats from another\n // branch, preview, or project that shares the same user/database, so\n // auto-opening the latest server thread here leaks unrelated context into\n // a fresh surface. Existing threads remain available in History.\n useEffect(() => {\n if (fetchedRef.current) return;\n fetchedRef.current = true;\n\n (async () => {\n setIsLoading(true);\n const loadedThreads = await fetchThreads();\n const savedId = activeThreadIdRef.current;\n const loadedHasSavedId = Boolean(\n savedId && (loadedThreads ?? []).some((t) => t.id === savedId),\n );\n\n if (\n savedId &&\n newlyCreatedRef.current.has(savedId) &&\n !loadedHasSavedId\n ) {\n addOptimisticThread(savedId, scopeRef.current ?? null);\n } else if (\n savedId &&\n !newlyCreatedRef.current.has(savedId) &&\n !loadedHasSavedId\n ) {\n // The tab the user left open isn't a server thread and we didn't\n // create it this session (newlyCreatedRef was wiped by the\n // reload). Treat it as the empty tab it is — keep its id and\n // surface it as an optimistic thread so the tab bar restores it\n // verbatim instead of yanking in the most-recent old chat.\n newlyCreatedRef.current.add(savedId);\n // Seed from the persisted last-seen time (not now) so a tab the\n // user abandoned >12h ago is correctly recognized as stale and\n // pruned by the downstream cleanup instead of living forever.\n let seenAt: number | undefined;\n try {\n const raw = localStorage.getItem(activeThreadSeenKey);\n const parsed = raw ? Number.parseInt(raw, 10) : NaN;\n if (Number.isFinite(parsed)) seenAt = parsed;\n } catch {\n // localStorage unavailable — fall back to now (current behaviour).\n }\n addOptimisticThread(savedId, scopeRef.current ?? null, seenAt);\n // activeThreadId already === savedId from the localStorage\n // initializer; nothing else to set.\n } else if (!savedId && autoCreate) {\n // Brand new surface — synthesize a local id so the composer has a\n // target. No POST: the server creates the row on first send.\n const id = createLocalThreadId();\n newlyCreatedRef.current.add(id);\n addOptimisticThread(id, scopeRef.current ?? null);\n setActiveThreadId(id);\n }\n setIsLoading(false);\n })();\n }, [fetchThreads, addOptimisticThread, autoCreate]);\n\n const createThread = useCallback(\n (preferredId?: string): Promise<string | null> => {\n // Generate ID client-side for instant UI response. No POST — the\n // server creates the row when the user actually sends a message,\n // which prevents accumulation of empty thread rows when the user\n // clicks \"+\" but never chats.\n const id = preferredId || createLocalThreadId();\n newlyCreatedRef.current.add(id);\n addOptimisticThread(id, scopeRef.current ?? null);\n setActiveThreadId(id);\n return Promise.resolve(id);\n },\n [addOptimisticThread],\n );\n\n // Drop a thread's scope so it becomes a general (cross-resource) chat.\n // This is the \"Detach from <deck>\" escape hatch in the UI. The PUT\n // also bumps the thread's updatedAt so it surfaces in the All Chats\n // list right away.\n const detachThread = useCallback(\n async (threadId: string): Promise<void> => {\n try {\n await fetch(`${apiUrl}/threads/${encodeURIComponent(threadId)}`, {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ scope: null }),\n });\n setThreads((prev) =>\n prev.map((t) => (t.id === threadId ? { ...t, scope: null } : t)),\n );\n optimisticThreadScopesRef.current.set(threadId, null);\n emitThreadsUpdated();\n } catch {}\n },\n [apiUrl],\n );\n\n const pinThread = useCallback(\n async (threadId: string, pinned: boolean): Promise<boolean> => {\n const previousPinnedAt =\n threadsRef.current.find((t) => t.id === threadId)?.pinnedAt ?? null;\n const previousUpdatedAt =\n threadsRef.current.find((t) => t.id === threadId)?.updatedAt ?? null;\n const now = Date.now();\n const pinnedAt = pinned ? now : null;\n pendingPinnedAtRef.current.set(threadId, pinnedAt);\n const rollback = () => {\n if (pendingPinnedAtRef.current.get(threadId) !== pinnedAt) return;\n pendingPinnedAtRef.current.delete(threadId);\n setThreads((prev) =>\n prev.map((t) =>\n t.id === threadId\n ? {\n ...t,\n pinnedAt: previousPinnedAt,\n updatedAt: previousUpdatedAt ?? t.updatedAt,\n }\n : t,\n ),\n );\n };\n setThreads((prev) =>\n prev.map((t) => (t.id === threadId ? { ...t, pinnedAt } : t)),\n );\n try {\n const res = await fetch(\n `${apiUrl}/threads/${encodeURIComponent(threadId)}/pin`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ pinned }),\n },\n );\n if (!res.ok) {\n rollback();\n await fetchThreads();\n return false;\n }\n if (pendingPinnedAtRef.current.get(threadId) === pinnedAt) {\n pendingPinnedAtRef.current.delete(threadId);\n }\n emitThreadsUpdated();\n return true;\n } catch {\n rollback();\n await fetchThreads();\n return false;\n }\n },\n [apiUrl, fetchThreads],\n );\n\n const archiveThread = useCallback(\n async (threadId: string): Promise<boolean> => {\n const previousArchivedAt =\n threadsRef.current.find((t) => t.id === threadId)?.archivedAt ?? null;\n const previousUpdatedAt =\n threadsRef.current.find((t) => t.id === threadId)?.updatedAt ?? null;\n const previousActiveThreadId = activeThreadIdRef.current;\n const archivedAt = Date.now();\n pendingArchivedAtRef.current.set(threadId, archivedAt);\n const rollback = () => {\n if (pendingArchivedAtRef.current.get(threadId) !== archivedAt) return;\n pendingArchivedAtRef.current.delete(threadId);\n setThreads((prev) =>\n prev.map((t) =>\n t.id === threadId\n ? {\n ...t,\n archivedAt: previousArchivedAt,\n updatedAt: previousUpdatedAt ?? t.updatedAt,\n }\n : t,\n ),\n );\n if (\n previousActiveThreadId === threadId &&\n activeThreadIdRef.current === null\n ) {\n setActiveThreadId(threadId);\n }\n };\n setThreads((prev) =>\n prev.map((t) => (t.id === threadId ? { ...t, archivedAt } : t)),\n );\n try {\n const res = await fetch(\n `${apiUrl}/threads/${encodeURIComponent(threadId)}/archive`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ archived: true }),\n },\n );\n if (!res.ok) {\n rollback();\n await fetchThreads();\n return false;\n }\n if (pendingArchivedAtRef.current.get(threadId) === archivedAt) {\n pendingArchivedAtRef.current.delete(threadId);\n }\n if (threadId === activeThreadIdRef.current) {\n setActiveThreadId(null);\n }\n emitThreadsUpdated();\n return true;\n } catch {\n rollback();\n await fetchThreads();\n return false;\n }\n },\n [apiUrl, fetchThreads],\n );\n\n const renameThread = useCallback(\n async (threadId: string, title: string): Promise<boolean> => {\n const nextTitle = title.replace(/\\s+/g, \" \").trim().slice(0, 160);\n if (!nextTitle) return false;\n\n const previousTitle = threadsRef.current.find(\n (t) => t.id === threadId,\n )?.title;\n const rollback = () => {\n const currentTitle = threadsRef.current.find(\n (t) => t.id === threadId,\n )?.title;\n if (currentTitle !== nextTitle) return;\n clearUserRenamedThread(threadId);\n if (previousTitle !== undefined) {\n setThreads((prev) =>\n prev.map((t) =>\n t.id === threadId ? { ...t, title: previousTitle } : t,\n ),\n );\n }\n };\n markUserRenamedThread(threadId);\n setThreads((prev) =>\n prev.map((t) => (t.id === threadId ? { ...t, title: nextTitle } : t)),\n );\n\n try {\n const res = await fetch(\n `${apiUrl}/threads/${encodeURIComponent(threadId)}/rename`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ title: nextTitle }),\n },\n );\n if (!res.ok) {\n rollback();\n await fetchThreads();\n return false;\n }\n emitThreadsUpdated();\n return true;\n } catch {\n rollback();\n await fetchThreads();\n return false;\n }\n },\n [apiUrl, clearUserRenamedThread, fetchThreads, markUserRenamedThread],\n );\n\n const isNewThread = useCallback(\n (id: string) => newlyCreatedRef.current.has(id),\n [],\n );\n\n const switchThread = useCallback((id: string) => {\n setActiveThreadId(id);\n }, []);\n\n const removeThread = useCallback(\n async (id: string) => {\n try {\n await fetch(`${apiUrl}/threads/${encodeURIComponent(id)}`, {\n method: \"DELETE\",\n });\n emitThreadsUpdated();\n } catch {}\n clearUserRenamedThread(id);\n optimisticThreadScopesRef.current.delete(id);\n setThreads((prev) => prev.filter((t) => t.id !== id));\n if (id === activeThreadIdRef.current) {\n // Switch to the next available thread, or create a new one if the\n // list is now empty. Computed outside the setThreads updater so the\n // updater stays pure (StrictMode double-invokes updaters, which would\n // otherwise create duplicate optimistic threads on the empty branch).\n const remaining = threadsRef.current.filter((t) => t.id !== id);\n if (remaining.length > 0) {\n setActiveThreadId(remaining[0].id);\n } else {\n createThread();\n }\n }\n },\n [apiUrl, clearUserRenamedThread, createThread],\n );\n\n // Ref to look up the latest scope of a known thread inside\n // saveThreadData without making the callback re-create on every\n // setThreads. The thread's scope is owned by createThread /\n // detachThread / fetchThreads — saveThreadData just mirrors it on\n // every save so the server eventually catches up after\n // persistSubmittedUserMessage creates the row sans scope.\n const saveThreadData = useCallback(\n async (\n id: string,\n data: {\n threadData: string;\n title: string;\n preview: string;\n messageCount?: number;\n titleSource?: ThreadTitleSource;\n },\n ) => {\n try {\n const { titleSource, ...threadDataPayload } = data;\n const localThread = threadsRef.current.find((t) => t.id === id);\n const localScope = localThread?.scope ?? null;\n const preserveUserTitle = userRenamedThreadIdsRef.current.has(id);\n const title = nextThreadTitle(\n localThread?.title,\n data.title,\n data.preview,\n titleSource,\n { preserveUserTitle },\n );\n await fetch(`${apiUrl}/threads/${encodeURIComponent(id)}`, {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n ...threadDataPayload,\n title,\n scope: localScope,\n }),\n });\n emitThreadsUpdated();\n // Update local thread list metadata. If the thread isn't in our\n // local list yet (an optimistic-only thread that the server just\n // created via persistSubmittedUserMessage), add it so HistoryPopover\n // can show it once it has messages.\n setThreads((prev) => {\n const exists = prev.some((t) => t.id === id);\n if (exists) {\n return prev.map((t) =>\n t.id === id\n ? {\n ...t,\n title: nextThreadTitle(\n t.title,\n data.title,\n data.preview,\n titleSource,\n {\n preserveUserTitle:\n userRenamedThreadIdsRef.current.has(id),\n },\n ),\n preview: data.preview,\n ...(data.messageCount != null && {\n messageCount: data.messageCount,\n }),\n updatedAt: Date.now(),\n }\n : t,\n );\n }\n const now = Date.now();\n return [\n {\n id,\n title,\n preview: data.preview,\n messageCount: data.messageCount ?? 0,\n createdAt: now,\n updatedAt: now,\n scope: scopeRef.current ?? null,\n },\n ...prev,\n ];\n });\n } catch {}\n },\n [apiUrl],\n );\n\n const generateTitle = useCallback(\n async (threadId: string, message: string): Promise<string | null> => {\n try {\n const res = await fetch(`${apiUrl}/generate-title`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ message }),\n });\n if (!res.ok) return null;\n const data = await res.json();\n const title = data.title;\n if (!title) return null;\n if (userRenamedThreadIdsRef.current.has(threadId)) return null;\n // Update the title in local state\n setThreads((prev) =>\n prev.map((t) => (t.id === threadId ? { ...t, title } : t)),\n );\n return title;\n } catch {\n return null;\n }\n },\n [apiUrl],\n );\n\n const forkThread = useCallback(\n async (\n sourceId: string,\n sourceSnapshot?: ChatThreadSnapshot | null,\n ): Promise<string | null> => {\n const id = createLocalThreadId();\n const fallbackForkFromSnapshot = async (\n source: ForkSnapshotWithScope,\n ): Promise<ChatThreadSummary | null> => {\n const title = source.title ? `${source.title} (fork)` : \"\";\n const createdAt = Date.now();\n const createRes = await fetch(`${apiUrl}/threads`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n id,\n title,\n ...(source.scope ? { scope: source.scope } : {}),\n }),\n });\n if (!createRes.ok) return null;\n\n const saveRes = await fetch(\n `${apiUrl}/threads/${encodeURIComponent(id)}`,\n {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n threadData: source.threadData,\n title,\n preview: source.preview,\n messageCount: source.messageCount,\n scope: source.scope,\n }),\n },\n );\n if (!saveRes.ok) return null;\n\n return {\n id,\n title,\n preview: source.preview,\n messageCount: source.messageCount,\n createdAt,\n updatedAt: Date.now(),\n scope: source.scope,\n };\n };\n\n try {\n const localScope =\n threadsRef.current.find((t) => t.id === sourceId)?.scope ?? null;\n const source =\n sourceSnapshot && sourceSnapshot.messageCount > 0\n ? { ...sourceSnapshot, scope: localScope }\n : undefined;\n const res = await fetch(\n `${apiUrl}/threads/${encodeURIComponent(sourceId)}/fork`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ id, ...(source ? { source } : {}) }),\n },\n );\n let thread: ChatThreadSummary | null = null;\n if (!res.ok) {\n // Surface failures so a click on the Fork button isn't a silent\n // no-op when the source thread can't be found or auth has lapsed.\n console.error(\n `[chat] fork failed for ${sourceId}: ${res.status} ${res.statusText}`,\n );\n if (source && (res.status === 404 || res.status === 405)) {\n thread = await fallbackForkFromSnapshot(source);\n }\n if (!thread) return null;\n } else {\n thread = await res.json();\n }\n setThreads((prev) => [\n {\n id: thread.id,\n title: thread.title,\n preview: thread.preview,\n messageCount: thread.messageCount,\n createdAt: thread.createdAt,\n updatedAt: thread.updatedAt,\n scope: thread.scope ?? null,\n },\n ...prev,\n ]);\n emitThreadsUpdated();\n return thread.id;\n } catch (err) {\n console.error(`[chat] fork threw for ${sourceId}:`, err);\n return null;\n }\n },\n [apiUrl],\n );\n\n const searchThreads = useCallback(\n async (query: string): Promise<ChatThreadSummary[]> => {\n try {\n const res = await fetch(\n `${apiUrl}/threads?q=${encodeURIComponent(query)}`,\n );\n if (!res.ok) return [];\n const data = await res.json();\n return data.threads ?? [];\n } catch {\n return [];\n }\n },\n [apiUrl],\n );\n\n const refreshThreads = useCallback(() => {\n fetchThreads();\n }, [fetchThreads]);\n\n return {\n threads,\n activeThreadId,\n isLoading,\n createThread,\n switchThread,\n deleteThread: removeThread,\n detachThread,\n pinThread,\n archiveThread,\n renameThread,\n forkThread,\n saveThreadData,\n generateTitle,\n searchThreads,\n refreshThreads,\n isNewThread,\n };\n}\n"]}
1
+ {"version":3,"file":"use-chat-threads.js","sourceRoot":"","sources":["../../src/client/use-chat-threads.ts"],"names":[],"mappings":"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","sourcesContent":["import { useState, useEffect, useCallback, useRef, useMemo } from \"react\";\nimport { agentNativePath } from \"./api-path.js\";\n\nexport interface ChatThreadScope {\n type: string;\n id: string;\n label?: string;\n}\n\nexport interface ChatThreadSummary {\n id: string;\n title: string;\n preview: string;\n messageCount: number;\n createdAt: number;\n updatedAt: number;\n scope: ChatThreadScope | null;\n pinnedAt?: number | null;\n archivedAt?: number | null;\n}\n\nexport interface ChatThreadData {\n id: string;\n ownerEmail: string;\n title: string;\n preview: string;\n threadData: string;\n messageCount: number;\n createdAt: number;\n updatedAt: number;\n scope: ChatThreadScope | null;\n pinnedAt?: number | null;\n archivedAt?: number | null;\n}\n\nexport interface ChatThreadSnapshot {\n threadData: string;\n title: string;\n preview: string;\n messageCount: number;\n}\n\ntype ThreadTitleSource = \"generated\" | \"extracted\";\n\ninterface ForkSnapshotWithScope extends ChatThreadSnapshot {\n scope: ChatThreadScope | null;\n}\n\nexport interface UseChatThreadsOptions {\n /** Create an optimistic empty thread on mount when no active thread exists. */\n autoCreate?: boolean;\n /** Restore the active thread from localStorage. Defaults to true. */\n restoreActiveThread?: boolean;\n}\n\nconst ACTIVE_THREAD_KEY = \"agent-chat-active-thread\";\nconst THREADS_UPDATED_EVENT = \"agent-chat:threads-updated\";\n\nfunction emitThreadsUpdated() {\n if (typeof window === \"undefined\") return;\n window.dispatchEvent(new CustomEvent(THREADS_UPDATED_EVENT));\n}\n\nfunction scopeKeySegment(scope?: ChatThreadScope | null): string {\n if (!scope) return \"\";\n return `:scope:${scope.type}:${scope.id}`;\n}\n\nfunction activeThreadStorageKey(\n storageKey?: string,\n scope?: ChatThreadScope | null,\n): string {\n const scopePart = scopeKeySegment(scope);\n return storageKey\n ? `${ACTIVE_THREAD_KEY}:${storageKey}${scopePart}`\n : `${ACTIVE_THREAD_KEY}${scopePart}`;\n}\n\nfunction activeThreadSeenStorageKey(activeThreadKey: string): string {\n return `${activeThreadKey}:seen`;\n}\n\nfunction createLocalThreadId(): string {\n if (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return `thread-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\nfunction scopesMatch(\n a?: ChatThreadScope | null,\n b?: ChatThreadScope | null,\n): boolean {\n if (!a || !b) return false;\n return a.type === b.type && a.id === b.id;\n}\n\nfunction threadCanStayVisibleInScope(\n threadScope: ChatThreadScope | null,\n currentScope?: ChatThreadScope | null,\n): boolean {\n if (!threadScope) return true;\n return scopesMatch(threadScope, currentScope);\n}\n\nfunction nextThreadTitle(\n currentTitle: string | undefined,\n incomingTitle: string,\n incomingPreview: string,\n source: ThreadTitleSource = \"extracted\",\n options: { preserveUserTitle?: boolean } = {},\n): string {\n if (options.preserveUserTitle && currentTitle) return currentTitle;\n if (source === \"generated\") return incomingTitle;\n if (!currentTitle) return incomingTitle;\n if (!incomingTitle) return currentTitle;\n if (currentTitle !== incomingTitle && currentTitle !== incomingPreview) {\n return currentTitle;\n }\n return incomingTitle;\n}\n\nexport function useChatThreads(\n apiUrl = agentNativePath(\"/_agent-native/agent-chat\"),\n storageKey?: string,\n scope?: ChatThreadScope | null,\n options?: UseChatThreadsOptions,\n) {\n const autoCreate = options?.autoCreate !== false;\n const restoreActiveThread = options?.restoreActiveThread !== false;\n // Each (storageKey, scope) pair gets its own active-thread localStorage key\n // for chats that belong to a resource. General chats keep using the unscoped\n // key even while the user is looking at a resource, so clicking into a deck,\n // design, form, etc. doesn't make a global conversation vanish.\n const activeThreadKey = useMemo(() => {\n return activeThreadStorageKey(storageKey, scope);\n }, [storageKey, scope?.type, scope?.id]);\n // Companion key recording when the saved active thread was last live in\n // this client. A revived orphan tab (id in localStorage but not on the\n // server and not created this session) must keep its real last-seen time\n // so the 12h stale-tab cleanup can age it out — stamping it `Date.now()`\n // on every mount (the old behaviour) reset the clock forever, so\n // abandoned empty tabs never got pruned.\n const activeThreadSeenKey = useMemo(\n () => activeThreadSeenStorageKey(activeThreadKey),\n [activeThreadKey],\n );\n const initialActiveThreadRef = useRef<{\n id: string | null;\n isNew: boolean;\n } | null>(null);\n if (initialActiveThreadRef.current === null) {\n let id: string | null = null;\n let isNew = false;\n if (typeof window !== \"undefined\") {\n try {\n id = restoreActiveThread ? localStorage.getItem(activeThreadKey) : null;\n } catch {\n id = null;\n }\n if (!id && autoCreate) {\n id = createLocalThreadId();\n isNew = true;\n }\n }\n initialActiveThreadRef.current = { id, isNew };\n }\n\n const [threads, setThreads] = useState<ChatThreadSummary[]>([]);\n const threadsRef = useRef<ChatThreadSummary[]>(threads);\n threadsRef.current = threads;\n\n // IDs we generated client-side this session — consumers use this to know\n // whether to skip the per-thread restore skeleton, and we use it to\n // protect the optimistic-only thread from being yanked out of local\n // state when the server's threads list (which never sees it) loads.\n const newlyCreatedRef = useRef<Set<string>>(\n initialActiveThreadRef.current.isNew && initialActiveThreadRef.current.id\n ? new Set([initialActiveThreadRef.current.id])\n : new Set(),\n );\n const optimisticThreadScopesRef = useRef<Map<string, ChatThreadScope | null>>(\n new Map(),\n );\n const pendingPinnedAtRef = useRef<Map<string, number | null>>(new Map());\n const pendingArchivedAtRef = useRef<Map<string, number | null>>(new Map());\n const userRenamedThreadIdsRef = useRef<Set<string>>(new Set());\n const userRenamedClearTimersRef = useRef<\n Map<string, ReturnType<typeof setTimeout>>\n >(new Map());\n\n const clearUserRenamedThread = useCallback((threadId: string) => {\n const timer = userRenamedClearTimersRef.current.get(threadId);\n if (timer) {\n clearTimeout(timer);\n userRenamedClearTimersRef.current.delete(threadId);\n }\n userRenamedThreadIdsRef.current.delete(threadId);\n }, []);\n\n const markUserRenamedThread = useCallback((threadId: string) => {\n userRenamedThreadIdsRef.current.add(threadId);\n const existingTimer = userRenamedClearTimersRef.current.get(threadId);\n if (existingTimer) clearTimeout(existingTimer);\n const timer = setTimeout(() => {\n userRenamedClearTimersRef.current.delete(threadId);\n userRenamedThreadIdsRef.current.delete(threadId);\n }, 30_000);\n userRenamedClearTimersRef.current.set(threadId, timer);\n }, []);\n\n useEffect(() => {\n return () => {\n for (const timer of userRenamedClearTimersRef.current.values()) {\n clearTimeout(timer);\n }\n userRenamedClearTimersRef.current.clear();\n userRenamedThreadIdsRef.current.clear();\n };\n }, []);\n\n // Latest scope as a ref so `createThread` (a useCallback that we don't\n // want to depend on scope identity) reads the current value at call\n // time. The scope a new chat inherits is the one in effect when the +\n // button is clicked, not when the hook first mounted.\n const scopeRef = useRef<ChatThreadScope | null | undefined>(scope);\n scopeRef.current = scope;\n\n const readKnownThreadScope = useCallback(\n (id: string): ChatThreadScope | null | undefined => {\n const thread = threadsRef.current.find((t) => t.id === id);\n if (thread) return thread.scope ?? null;\n if (optimisticThreadScopesRef.current.has(id)) {\n return optimisticThreadScopesRef.current.get(id) ?? null;\n }\n return undefined;\n },\n [],\n );\n\n // Seed the active thread synchronously so the chat shell can paint\n // immediately. This may restore the saved id or create a local-only fresh id,\n // depending on options. Creating a local id is safe: no row is POSTed here,\n // so empty page loads do not create ghost `chat_threads` rows.\n const [activeThreadId, setActiveThreadId] = useState<string | null>(\n initialActiveThreadRef.current.id,\n );\n const [isLoading, setIsLoading] = useState(true);\n const fetchedRef = useRef(false);\n const activeThreadIdRef = useRef(activeThreadId);\n activeThreadIdRef.current = activeThreadId;\n\n // Persist active thread ID — and rehydrate on scope flips. When the user\n // navigates from deck A to deck B, `activeThreadKey` changes; we re-read B's\n // scoped thread only if the currently visible chat is itself scoped to a\n // different resource. Unscoped chats are global and stay visible.\n const persistedKeyRef = useRef(activeThreadKey);\n useEffect(() => {\n if (persistedKeyRef.current !== activeThreadKey) {\n const currentId = activeThreadIdRef.current;\n if (currentId) {\n const currentThreadScope = readKnownThreadScope(currentId);\n // Thread metadata not yet loaded from the server — we can't tell\n // whether the visible chat is general (stays) or scoped-elsewhere\n // (swaps). Defer until `threads` resolves and this effect re-runs;\n // we intentionally do NOT update `persistedKeyRef` so the next\n // render gets another shot. Without this guard, navigating into a\n // resource before `GET /threads` resolves silently dropped the\n // active general chat the user was just in.\n if (currentThreadScope === undefined) {\n return;\n }\n if (threadCanStayVisibleInScope(currentThreadScope, scopeRef.current)) {\n persistedKeyRef.current = activeThreadKey;\n return;\n }\n }\n persistedKeyRef.current = activeThreadKey;\n try {\n setActiveThreadId(localStorage.getItem(activeThreadKey));\n } catch {\n setActiveThreadId(null);\n }\n return;\n }\n try {\n if (activeThreadId) {\n const threadScope = readKnownThreadScope(activeThreadId);\n if (threadScope === undefined) return;\n const targetKey = activeThreadStorageKey(storageKey, threadScope);\n localStorage.setItem(targetKey, activeThreadId);\n localStorage.setItem(\n activeThreadSeenStorageKey(targetKey),\n String(Date.now()),\n );\n } else {\n localStorage.removeItem(activeThreadKey);\n localStorage.removeItem(activeThreadSeenKey);\n }\n } catch {}\n }, [\n activeThreadId,\n activeThreadKey,\n activeThreadSeenKey,\n readKnownThreadScope,\n storageKey,\n threads,\n ]);\n\n const fetchThreads = useCallback(async () => {\n try {\n const res = await fetch(`${apiUrl}/threads`);\n if (!res.ok) return;\n const data = await res.json();\n setThreads((prev) => {\n const loaded = (data.threads ?? []) as ChatThreadSummary[];\n const loadedIds = new Set(loaded.map((t) => t.id));\n // Preserve any optimistic threads we've created this session that\n // haven't shown up in the server list yet — the server only learns\n // about a thread when the user actually sends a message and the\n // agent run's `persistSubmittedUserMessage` writes the row.\n const optimisticOnly = prev.filter(\n (t) => newlyCreatedRef.current.has(t.id) && !loadedIds.has(t.id),\n );\n // Reconcile each server thread against our local copy. If the local\n // copy has a newer updatedAt or higher messageCount, keep those\n // fields — the server probably hasn't observed the user's latest\n // send yet, and naively replacing makes the recent-chats list\n // visibly jump back to older timestamps right after a send.\n const merged = loaded.map((server) => {\n const local = prev.find((t) => t.id === server.id);\n if (!local) return server;\n const next = { ...server };\n if (local.updatedAt > server.updatedAt) {\n next.updatedAt = local.updatedAt;\n }\n if (userRenamedThreadIdsRef.current.has(server.id) && local.title) {\n next.title = local.title;\n }\n if (pendingPinnedAtRef.current.has(server.id)) {\n next.pinnedAt = pendingPinnedAtRef.current.get(server.id) ?? null;\n }\n if (pendingArchivedAtRef.current.has(server.id)) {\n next.archivedAt =\n pendingArchivedAtRef.current.get(server.id) ?? null;\n }\n if (local.messageCount > server.messageCount) {\n next.messageCount = local.messageCount;\n if (local.preview) next.preview = local.preview;\n if (local.title) next.title = local.title;\n }\n // Preserve optimistic scope: when the server creates the row\n // on first message it does so without scope, and the next PUT\n // (saveThreadData) writes the local scope back. In the brief\n // window between those, the server list returns scope: null\n // while the user is clearly working inside a deck — keep the\n // local value so the tab bar doesn't blink unscoped.\n if (local.scope && !server.scope) {\n next.scope = local.scope;\n }\n return next;\n });\n return [...optimisticOnly, ...merged];\n });\n return data.threads as ChatThreadSummary[];\n } catch {\n return undefined;\n }\n }, [apiUrl]);\n\n // Add a client-generated thread to the local list optimistically.\n //\n // Critically, this does NOT `POST /threads` to the server — that path was\n // creating an empty row in `chat_threads` (message_count=0, no\n // agent_runs) on every page mount and every \"+\" click. The server\n // already creates the row idempotently the moment the user actually\n // sends their first message (`persistSubmittedUserMessage` →\n // `createThread`), so the client doesn't need to pre-create it. This\n // makes the threads table reflect real conversations only.\n const addOptimisticThread = useCallback(\n (\n id: string,\n threadScope: ChatThreadScope | null,\n // When reviving a tab the user left open in a prior session, pass the\n // persisted last-seen time so the 12h stale-tab cleanup can still age\n // it out. Omit for genuinely new tabs (defaults to now).\n seedAt?: number,\n ) => {\n const stamp =\n typeof seedAt === \"number\" && Number.isFinite(seedAt)\n ? seedAt\n : Date.now();\n const optimistic: ChatThreadSummary = {\n id,\n title: \"\",\n preview: \"\",\n messageCount: 0,\n createdAt: stamp,\n updatedAt: stamp,\n scope: threadScope,\n };\n optimisticThreadScopesRef.current.set(id, threadScope);\n setThreads((prev) =>\n prev.some((t) => t.id === id) ? prev : [optimistic, ...prev],\n );\n },\n [],\n );\n\n // Initial load: load threads from server, then reconcile against the\n // saved active thread.\n //\n // - savedId in loadedThreads → keep it (user's last conversation).\n // - savedId in newlyCreatedRef (we just created it this session) → keep\n // it; the server hasn't seen it yet because there's no POST anymore,\n // the row gets written when the user sends a message.\n // - savedId is set but neither on the server nor newly created here →\n // it's an empty tab the user left open. A never-messaged tab is never\n // POSTed (that was the 127-ghost-threads problem), and the only record\n // that it's a deliberately-open tab — newlyCreatedRef — is wiped by the\n // reload. So on refresh we can't tell it apart from a stale ghost.\n // Keep it exactly as the user left it: re-register it as an optimistic\n // empty tab rather than resurrecting an unrelated old conversation. The\n // composer is fully functional with this id (the server writes the row\n // on first message, same as any new tab), so there's no 404 to avoid.\n // This is what makes \"the state you left is the state you see on\n // refresh\" hold — stale (>12h) tabs are still cleared downstream.\n // - No savedId → synthesize a fresh local id (no POST; server creates the\n // row on first message). The server may contain chats from another\n // branch, preview, or project that shares the same user/database, so\n // auto-opening the latest server thread here leaks unrelated context into\n // a fresh surface. Existing threads remain available in History.\n useEffect(() => {\n if (fetchedRef.current) return;\n fetchedRef.current = true;\n\n (async () => {\n setIsLoading(true);\n const loadedThreads = await fetchThreads();\n const savedId = activeThreadIdRef.current;\n if (loadedThreads === undefined) {\n // Thread-list fetch failed. Do not reclassify a saved id as a new\n // optimistic tab; AssistantChat should still get a chance to restore\n // the specific saved thread via /threads/:id.\n setIsLoading(false);\n return;\n }\n const loadedHasSavedId = Boolean(\n savedId && loadedThreads.some((t) => t.id === savedId),\n );\n\n if (\n savedId &&\n newlyCreatedRef.current.has(savedId) &&\n !loadedHasSavedId\n ) {\n addOptimisticThread(savedId, scopeRef.current ?? null);\n } else if (\n savedId &&\n !newlyCreatedRef.current.has(savedId) &&\n !loadedHasSavedId\n ) {\n // The tab the user left open isn't a server thread and we didn't\n // create it this session (newlyCreatedRef was wiped by the\n // reload). Treat it as the empty tab it is — keep its id and\n // surface it as an optimistic thread so the tab bar restores it\n // verbatim instead of yanking in the most-recent old chat.\n newlyCreatedRef.current.add(savedId);\n // Seed from the persisted last-seen time (not now) so a tab the\n // user abandoned >12h ago is correctly recognized as stale and\n // pruned by the downstream cleanup instead of living forever.\n let seenAt: number | undefined;\n try {\n const raw = localStorage.getItem(activeThreadSeenKey);\n const parsed = raw ? Number.parseInt(raw, 10) : NaN;\n if (Number.isFinite(parsed)) seenAt = parsed;\n } catch {\n // localStorage unavailable — fall back to now (current behaviour).\n }\n addOptimisticThread(savedId, scopeRef.current ?? null, seenAt);\n // activeThreadId already === savedId from the localStorage\n // initializer; nothing else to set.\n } else if (!savedId && autoCreate) {\n // Brand new surface — synthesize a local id so the composer has a\n // target. No POST: the server creates the row on first send.\n const id = createLocalThreadId();\n newlyCreatedRef.current.add(id);\n addOptimisticThread(id, scopeRef.current ?? null);\n setActiveThreadId(id);\n }\n setIsLoading(false);\n })();\n }, [fetchThreads, addOptimisticThread, autoCreate]);\n\n const createThread = useCallback(\n (preferredId?: string): Promise<string | null> => {\n // Generate ID client-side for instant UI response. No POST — the\n // server creates the row when the user actually sends a message,\n // which prevents accumulation of empty thread rows when the user\n // clicks \"+\" but never chats.\n const id = preferredId || createLocalThreadId();\n newlyCreatedRef.current.add(id);\n addOptimisticThread(id, scopeRef.current ?? null);\n setActiveThreadId(id);\n return Promise.resolve(id);\n },\n [addOptimisticThread],\n );\n\n // Drop a thread's scope so it becomes a general (cross-resource) chat.\n // This is the \"Detach from <deck>\" escape hatch in the UI. The PUT\n // also bumps the thread's updatedAt so it surfaces in the All Chats\n // list right away.\n const detachThread = useCallback(\n async (threadId: string): Promise<void> => {\n try {\n await fetch(`${apiUrl}/threads/${encodeURIComponent(threadId)}`, {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ scope: null }),\n });\n setThreads((prev) =>\n prev.map((t) => (t.id === threadId ? { ...t, scope: null } : t)),\n );\n optimisticThreadScopesRef.current.set(threadId, null);\n emitThreadsUpdated();\n } catch {}\n },\n [apiUrl],\n );\n\n const pinThread = useCallback(\n async (threadId: string, pinned: boolean): Promise<boolean> => {\n const previousPinnedAt =\n threadsRef.current.find((t) => t.id === threadId)?.pinnedAt ?? null;\n const previousUpdatedAt =\n threadsRef.current.find((t) => t.id === threadId)?.updatedAt ?? null;\n const now = Date.now();\n const pinnedAt = pinned ? now : null;\n pendingPinnedAtRef.current.set(threadId, pinnedAt);\n const rollback = () => {\n if (pendingPinnedAtRef.current.get(threadId) !== pinnedAt) return;\n pendingPinnedAtRef.current.delete(threadId);\n setThreads((prev) =>\n prev.map((t) =>\n t.id === threadId\n ? {\n ...t,\n pinnedAt: previousPinnedAt,\n updatedAt: previousUpdatedAt ?? t.updatedAt,\n }\n : t,\n ),\n );\n };\n setThreads((prev) =>\n prev.map((t) => (t.id === threadId ? { ...t, pinnedAt } : t)),\n );\n try {\n const res = await fetch(\n `${apiUrl}/threads/${encodeURIComponent(threadId)}/pin`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ pinned }),\n },\n );\n if (!res.ok) {\n rollback();\n await fetchThreads();\n return false;\n }\n if (pendingPinnedAtRef.current.get(threadId) === pinnedAt) {\n pendingPinnedAtRef.current.delete(threadId);\n }\n emitThreadsUpdated();\n return true;\n } catch {\n rollback();\n await fetchThreads();\n return false;\n }\n },\n [apiUrl, fetchThreads],\n );\n\n const archiveThread = useCallback(\n async (threadId: string): Promise<boolean> => {\n const previousArchivedAt =\n threadsRef.current.find((t) => t.id === threadId)?.archivedAt ?? null;\n const previousUpdatedAt =\n threadsRef.current.find((t) => t.id === threadId)?.updatedAt ?? null;\n const previousActiveThreadId = activeThreadIdRef.current;\n const archivedAt = Date.now();\n pendingArchivedAtRef.current.set(threadId, archivedAt);\n const rollback = () => {\n if (pendingArchivedAtRef.current.get(threadId) !== archivedAt) return;\n pendingArchivedAtRef.current.delete(threadId);\n setThreads((prev) =>\n prev.map((t) =>\n t.id === threadId\n ? {\n ...t,\n archivedAt: previousArchivedAt,\n updatedAt: previousUpdatedAt ?? t.updatedAt,\n }\n : t,\n ),\n );\n if (\n previousActiveThreadId === threadId &&\n activeThreadIdRef.current === null\n ) {\n setActiveThreadId(threadId);\n }\n };\n setThreads((prev) =>\n prev.map((t) => (t.id === threadId ? { ...t, archivedAt } : t)),\n );\n try {\n const res = await fetch(\n `${apiUrl}/threads/${encodeURIComponent(threadId)}/archive`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ archived: true }),\n },\n );\n if (!res.ok) {\n rollback();\n await fetchThreads();\n return false;\n }\n if (pendingArchivedAtRef.current.get(threadId) === archivedAt) {\n pendingArchivedAtRef.current.delete(threadId);\n }\n if (threadId === activeThreadIdRef.current) {\n setActiveThreadId(null);\n }\n emitThreadsUpdated();\n return true;\n } catch {\n rollback();\n await fetchThreads();\n return false;\n }\n },\n [apiUrl, fetchThreads],\n );\n\n const renameThread = useCallback(\n async (threadId: string, title: string): Promise<boolean> => {\n const nextTitle = title.replace(/\\s+/g, \" \").trim().slice(0, 160);\n if (!nextTitle) return false;\n\n const previousTitle = threadsRef.current.find(\n (t) => t.id === threadId,\n )?.title;\n const rollback = () => {\n const currentTitle = threadsRef.current.find(\n (t) => t.id === threadId,\n )?.title;\n if (currentTitle !== nextTitle) return;\n clearUserRenamedThread(threadId);\n if (previousTitle !== undefined) {\n setThreads((prev) =>\n prev.map((t) =>\n t.id === threadId ? { ...t, title: previousTitle } : t,\n ),\n );\n }\n };\n markUserRenamedThread(threadId);\n setThreads((prev) =>\n prev.map((t) => (t.id === threadId ? { ...t, title: nextTitle } : t)),\n );\n\n try {\n const res = await fetch(\n `${apiUrl}/threads/${encodeURIComponent(threadId)}/rename`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ title: nextTitle }),\n },\n );\n if (!res.ok) {\n rollback();\n await fetchThreads();\n return false;\n }\n emitThreadsUpdated();\n return true;\n } catch {\n rollback();\n await fetchThreads();\n return false;\n }\n },\n [apiUrl, clearUserRenamedThread, fetchThreads, markUserRenamedThread],\n );\n\n const isNewThread = useCallback(\n (id: string) => newlyCreatedRef.current.has(id),\n [],\n );\n\n const switchThread = useCallback((id: string) => {\n setActiveThreadId(id);\n }, []);\n\n const removeThread = useCallback(\n async (id: string) => {\n try {\n await fetch(`${apiUrl}/threads/${encodeURIComponent(id)}`, {\n method: \"DELETE\",\n });\n emitThreadsUpdated();\n } catch {}\n clearUserRenamedThread(id);\n optimisticThreadScopesRef.current.delete(id);\n setThreads((prev) => prev.filter((t) => t.id !== id));\n if (id === activeThreadIdRef.current) {\n // Switch to the next available thread, or create a new one if the\n // list is now empty. Computed outside the setThreads updater so the\n // updater stays pure (StrictMode double-invokes updaters, which would\n // otherwise create duplicate optimistic threads on the empty branch).\n const remaining = threadsRef.current.filter((t) => t.id !== id);\n if (remaining.length > 0) {\n setActiveThreadId(remaining[0].id);\n } else {\n createThread();\n }\n }\n },\n [apiUrl, clearUserRenamedThread, createThread],\n );\n\n // Ref to look up the latest scope of a known thread inside\n // saveThreadData without making the callback re-create on every\n // setThreads. The thread's scope is owned by createThread /\n // detachThread / fetchThreads — saveThreadData just mirrors it on\n // every save so the server eventually catches up after\n // persistSubmittedUserMessage creates the row sans scope.\n const saveThreadData = useCallback(\n async (\n id: string,\n data: {\n threadData: string;\n title: string;\n preview: string;\n messageCount?: number;\n titleSource?: ThreadTitleSource;\n },\n ) => {\n try {\n const { titleSource, ...threadDataPayload } = data;\n const localThread = threadsRef.current.find((t) => t.id === id);\n const localScope = localThread?.scope ?? null;\n const preserveUserTitle = userRenamedThreadIdsRef.current.has(id);\n const title = nextThreadTitle(\n localThread?.title,\n data.title,\n data.preview,\n titleSource,\n { preserveUserTitle },\n );\n await fetch(`${apiUrl}/threads/${encodeURIComponent(id)}`, {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n ...threadDataPayload,\n title,\n scope: localScope,\n }),\n });\n emitThreadsUpdated();\n // Update local thread list metadata. If the thread isn't in our\n // local list yet (an optimistic-only thread that the server just\n // created via persistSubmittedUserMessage), add it so HistoryPopover\n // can show it once it has messages.\n setThreads((prev) => {\n const exists = prev.some((t) => t.id === id);\n if (exists) {\n return prev.map((t) =>\n t.id === id\n ? {\n ...t,\n title: nextThreadTitle(\n t.title,\n data.title,\n data.preview,\n titleSource,\n {\n preserveUserTitle:\n userRenamedThreadIdsRef.current.has(id),\n },\n ),\n preview: data.preview,\n ...(data.messageCount != null && {\n messageCount: data.messageCount,\n }),\n updatedAt: Date.now(),\n }\n : t,\n );\n }\n const now = Date.now();\n return [\n {\n id,\n title,\n preview: data.preview,\n messageCount: data.messageCount ?? 0,\n createdAt: now,\n updatedAt: now,\n scope: scopeRef.current ?? null,\n },\n ...prev,\n ];\n });\n } catch {}\n },\n [apiUrl],\n );\n\n const generateTitle = useCallback(\n async (threadId: string, message: string): Promise<string | null> => {\n try {\n const res = await fetch(`${apiUrl}/generate-title`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ message }),\n });\n if (!res.ok) return null;\n const data = await res.json();\n const title = data.title;\n if (!title) return null;\n if (userRenamedThreadIdsRef.current.has(threadId)) return null;\n // Update the title in local state\n setThreads((prev) =>\n prev.map((t) => (t.id === threadId ? { ...t, title } : t)),\n );\n return title;\n } catch {\n return null;\n }\n },\n [apiUrl],\n );\n\n const forkThread = useCallback(\n async (\n sourceId: string,\n sourceSnapshot?: ChatThreadSnapshot | null,\n ): Promise<string | null> => {\n const id = createLocalThreadId();\n const fallbackForkFromSnapshot = async (\n source: ForkSnapshotWithScope,\n ): Promise<ChatThreadSummary | null> => {\n const title = source.title ? `${source.title} (fork)` : \"\";\n const createdAt = Date.now();\n const createRes = await fetch(`${apiUrl}/threads`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n id,\n title,\n ...(source.scope ? { scope: source.scope } : {}),\n }),\n });\n if (!createRes.ok) return null;\n\n const saveRes = await fetch(\n `${apiUrl}/threads/${encodeURIComponent(id)}`,\n {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n threadData: source.threadData,\n title,\n preview: source.preview,\n messageCount: source.messageCount,\n scope: source.scope,\n }),\n },\n );\n if (!saveRes.ok) return null;\n\n return {\n id,\n title,\n preview: source.preview,\n messageCount: source.messageCount,\n createdAt,\n updatedAt: Date.now(),\n scope: source.scope,\n };\n };\n\n try {\n const localScope =\n threadsRef.current.find((t) => t.id === sourceId)?.scope ?? null;\n const source =\n sourceSnapshot && sourceSnapshot.messageCount > 0\n ? { ...sourceSnapshot, scope: localScope }\n : undefined;\n const res = await fetch(\n `${apiUrl}/threads/${encodeURIComponent(sourceId)}/fork`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ id, ...(source ? { source } : {}) }),\n },\n );\n let thread: ChatThreadSummary | null = null;\n if (!res.ok) {\n // Surface failures so a click on the Fork button isn't a silent\n // no-op when the source thread can't be found or auth has lapsed.\n console.error(\n `[chat] fork failed for ${sourceId}: ${res.status} ${res.statusText}`,\n );\n if (source && (res.status === 404 || res.status === 405)) {\n thread = await fallbackForkFromSnapshot(source);\n }\n if (!thread) return null;\n } else {\n thread = await res.json();\n }\n setThreads((prev) => [\n {\n id: thread.id,\n title: thread.title,\n preview: thread.preview,\n messageCount: thread.messageCount,\n createdAt: thread.createdAt,\n updatedAt: thread.updatedAt,\n scope: thread.scope ?? null,\n },\n ...prev,\n ]);\n emitThreadsUpdated();\n return thread.id;\n } catch (err) {\n console.error(`[chat] fork threw for ${sourceId}:`, err);\n return null;\n }\n },\n [apiUrl],\n );\n\n const searchThreads = useCallback(\n async (query: string): Promise<ChatThreadSummary[]> => {\n try {\n const res = await fetch(\n `${apiUrl}/threads?q=${encodeURIComponent(query)}`,\n );\n if (!res.ok) return [];\n const data = await res.json();\n return data.threads ?? [];\n } catch {\n return [];\n }\n },\n [apiUrl],\n );\n\n const refreshThreads = useCallback(() => {\n fetchThreads();\n }, [fetchThreads]);\n\n return {\n threads,\n activeThreadId,\n isLoading,\n createThread,\n switchThread,\n deleteThread: removeThread,\n detachThread,\n pinThread,\n archiveThread,\n renameThread,\n forkThread,\n saveThreadData,\n generateTitle,\n searchThreads,\n refreshThreads,\n isNewThread,\n };\n}\n"]}
@@ -14,6 +14,7 @@
14
14
  */
15
15
  import { type DiscoveredRoute, type DiscoveredAction } from "./route-discovery.js";
16
16
  import { type WorkspaceCoreExports } from "./workspace-core.js";
17
+ export declare function generateProvidedPluginsNitroPluginSource(pluginStems: string[]): string;
17
18
  type RouteRules = Record<string, {
18
19
  headers?: Record<string, string>;
19
20
  }>;
@@ -27,7 +28,7 @@ export declare function addImmutableAssetRouteRulesForClientBuild(routeRules: Ro
27
28
  * `@agent-native/core/server`. This is the middle layer of the three-layer
28
29
  * inheritance model: app local > workspace core > framework default.
29
30
  */
30
- export declare function generateWorkerEntry(routes: DiscoveredRoute[], pluginPaths: string[], defaultPluginStems?: string[], actions?: DiscoveredAction[], workspaceCore?: WorkspaceCoreExports | null, immutableAssetPaths?: string[]): string;
31
+ export declare function generateWorkerEntry(routes: DiscoveredRoute[], pluginPaths: string[], defaultPluginStems?: string[], actions?: DiscoveredAction[], workspaceCore?: WorkspaceCoreExports | null, immutableAssetPaths?: string[], builtAppBasePath?: string): string;
31
32
  export declare function getNodeBuiltinNames(): string[];
32
33
  /**
33
34
  * Build for any non-Cloudflare preset using Nitro's programmatic build API.
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG;AAOH,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAwC7B,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,CAAC;AAgBvE,wBAAgB,yCAAyC,CACvD,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,SAAK,GACf,IAAI,CAQN;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EAAE,EACzB,WAAW,EAAE,MAAM,EAAE,EACrB,kBAAkB,GAAE,MAAM,EAAO,EACjC,OAAO,GAAE,gBAAgB,EAAO,EAChC,aAAa,GAAE,oBAAoB,GAAG,IAAW,EACjD,mBAAmB,GAAE,MAAM,EAAO,GACjC,MAAM,CAifR;AA4VD,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C;AAmVD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,gBAAgB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,UAAU,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAuBf"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/deploy/build.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG;AAOH,OAAO,EAML,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,qBAAqB,CAAC;AAwC7B,wBAAgB,wCAAwC,CACtD,WAAW,EAAE,MAAM,EAAE,GACpB,MAAM,CAaR;AAgBD,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC,CAAC;AAgBvE,wBAAgB,yCAAyC,CACvD,UAAU,EAAE,UAAU,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,SAAK,GACf,IAAI,CAQN;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EAAE,EACzB,WAAW,EAAE,MAAM,EAAE,EACrB,kBAAkB,GAAE,MAAM,EAAO,EACjC,OAAO,GAAE,gBAAgB,EAAO,EAChC,aAAa,GAAE,oBAAoB,GAAG,IAAW,EACjD,mBAAmB,GAAE,MAAM,EAAO,EAClC,gBAAgB,SAAmC,GAClD,MAAM,CA0hBR;AA4VD,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C;AAmVD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,gBAAgB,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,UAAU,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
@@ -49,6 +49,31 @@ function isNodeOnlyPlugin(filePath) {
49
49
  const basename = path.basename(filePath, path.extname(filePath));
50
50
  return NODE_ONLY_PLUGINS.has(basename);
51
51
  }
52
+ export function generateProvidedPluginsNitroPluginSource(pluginStems) {
53
+ const stems = [...new Set(pluginStems.filter(Boolean))].sort();
54
+ return `// AUTO-GENERATED by @agent-native/core deploy build
55
+ import { markDefaultPluginProvided } from "@agent-native/core/server";
56
+
57
+ const pluginStems = ${JSON.stringify(stems)};
58
+
59
+ export default function markBuildDiscoveredPlugins(nitroApp) {
60
+ for (const stem of pluginStems) {
61
+ markDefaultPluginProvided(nitroApp, stem);
62
+ }
63
+ }
64
+ `;
65
+ }
66
+ async function writeProvidedPluginsNitroPlugin() {
67
+ const plugins = await discoverPlugins(cwd);
68
+ const stems = plugins.map((plugin) => path.basename(plugin, path.extname(plugin)));
69
+ if (stems.length === 0)
70
+ return null;
71
+ const tmpDir = path.join(cwd, ".deploy-tmp");
72
+ fs.mkdirSync(tmpDir, { recursive: true });
73
+ const pluginPath = path.join(tmpDir, "agent-native-provided-plugins.mjs");
74
+ fs.writeFileSync(pluginPath, generateProvidedPluginsNitroPluginSource(stems));
75
+ return pluginPath;
76
+ }
52
77
  function addImmutableAssetRouteRule(routeRules, pathname) {
53
78
  const existing = routeRules[pathname] ?? {};
54
79
  routeRules[pathname] = {
@@ -77,7 +102,7 @@ export function addImmutableAssetRouteRulesForClientBuild(routeRules, clientDir,
77
102
  * `@agent-native/core/server`. This is the middle layer of the three-layer
78
103
  * inheritance model: app local > workspace core > framework default.
79
104
  */
80
- export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = [], actions = [], workspaceCore = null, immutableAssetPaths = []) {
105
+ export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = [], actions = [], workspaceCore = null, immutableAssetPaths = [], builtAppBasePath = normalizeConfiguredAppBasePath()) {
81
106
  const routeImports = [];
82
107
  const routeRegistrations = [];
83
108
  for (let i = 0; i < routes.length; i++) {
@@ -126,8 +151,10 @@ export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = []
126
151
  const edgePlugins = pluginPaths.filter((p) => !isNodeOnlyPlugin(p));
127
152
  const pluginImports = [];
128
153
  const pluginCalls = [];
154
+ const providedPluginStems = new Set();
129
155
  for (let i = 0; i < edgePlugins.length; i++) {
130
156
  const varName = `plugin_${i}`;
157
+ providedPluginStems.add(path.basename(edgePlugins[i], path.extname(edgePlugins[i])));
131
158
  pluginImports.push(`import ${varName} from ${JSON.stringify(edgePlugins[i])};`);
132
159
  pluginCalls.push(` if (typeof ${varName} === "function") {
133
160
  await ${varName}(nitroApp);
@@ -139,6 +166,7 @@ export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = []
139
166
  const edgeDefaultStems = defaultPluginStems.filter((stem) => !NODE_ONLY_PLUGINS.has(stem));
140
167
  for (let i = 0; i < edgeDefaultStems.length; i++) {
141
168
  const stem = edgeDefaultStems[i];
169
+ providedPluginStems.add(stem);
142
170
  const varName = `defaultPlugin_${i}`;
143
171
  const workspaceExportName = workspaceCore?.plugins?.[stem];
144
172
  if (workspaceCore && workspaceExportName) {
@@ -156,6 +184,17 @@ export function generateWorkerEntry(routes, pluginPaths, defaultPluginStems = []
156
184
  await ${varName}(nitroApp);
157
185
  }`);
158
186
  }
187
+ const generatedPluginMarks = providedPluginStems.size > 0
188
+ ? [
189
+ ...new Set([
190
+ ...Object.keys(DEFAULT_PLUGIN_REGISTRY),
191
+ ...providedPluginStems,
192
+ ]),
193
+ ]
194
+ : [];
195
+ if (generatedPluginMarks.length > 0) {
196
+ pluginImports.unshift(`import { markDefaultPluginProvided as markGeneratedPluginProvided } from "@agent-native/core/server";`);
197
+ }
159
198
  return `
160
199
  // Auto-generated worker entry point for ${preset}
161
200
  import { H3, defineEventHandler, readBody, toResponse } from "h3";
@@ -170,9 +209,11 @@ function normalizeAppBasePath(value) {
170
209
  }
171
210
 
172
211
  function getAppBasePath() {
212
+ const builtAppBasePath = ${JSON.stringify(builtAppBasePath)};
173
213
  return normalizeAppBasePath(
174
214
  globalThis.process?.env?.VITE_APP_BASE_PATH ||
175
- globalThis.process?.env?.APP_BASE_PATH,
215
+ globalThis.process?.env?.APP_BASE_PATH ||
216
+ builtAppBasePath,
176
217
  );
177
218
  }
178
219
 
@@ -285,6 +326,8 @@ function injectHeadScript(html, script) {
285
326
  const DEFAULT_SSR_CACHE_CONTROL = ${JSON.stringify(DEFAULT_SSR_CACHE_CONTROL)};
286
327
  const IMMUTABLE_ASSET_CACHE_CONTROL = ${JSON.stringify(IMMUTABLE_ASSET_CACHE_CONTROL)};
287
328
  const IMMUTABLE_ASSET_PATHS = new Set(${JSON.stringify([...new Set(immutableAssetPaths)].sort())});
329
+ const ANONYMOUS_SESSION_COOKIE_NAMES = new Set(["an_docs_session"]);
330
+ const BETTER_AUTH_SESSION_COOKIE_RE = /\\.session_(?:token|data)$/;
288
331
  const AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE = ${JSON.stringify(AGENT_NATIVE_DEFAULT_SOCIAL_IMAGE)};
289
332
  const OG_IMAGE_META_RE = /<meta\\b(?=[^>]*\\bproperty=(["'])og:image\\1)[^>]*>/i;
290
333
  const TWITTER_CARD_META_RE = /<meta\\b(?=[^>]*\\bname=(["'])twitter:card\\1)[^>]*>/i;
@@ -312,24 +355,33 @@ function injectDefaultSocialImageMeta(html) {
312
355
  return html.slice(0, headCloseIdx) + tags.join("") + html.slice(headCloseIdx);
313
356
  }
314
357
 
315
- const ANONYMOUS_SESSION_COOKIE_NAMES = new Set(["an_docs_session"]);
316
- const AUTH_SESSION_COOKIE_RE = /^(?:an_session(?:_[^=;]+)?|an_embed_session|[^=;]+\\.session_(?:token|data))$/;
317
-
318
358
  function requestHasAuthenticatedCookie(cookieHeader) {
319
359
  if (!cookieHeader) return false;
320
360
  return cookieHeader
321
361
  .split(";")
322
- .map((cookie) => cookie.trim().split("=", 1)[0]?.trim())
362
+ .map((cookie) => (cookie.trim().split("=", 1)[0] || "").trim())
323
363
  .filter(Boolean)
324
- .map((name) => name.replace(/^__(?:Secure|Host)-/, ""))
325
- .some((name) => !ANONYMOUS_SESSION_COOKIE_NAMES.has(name) && AUTH_SESSION_COOKIE_RE.test(name));
364
+ .some(isAuthenticatedCookieName);
365
+ }
366
+
367
+ function isAuthenticatedCookieName(name) {
368
+ if (ANONYMOUS_SESSION_COOKIE_NAMES.has(name)) return false;
369
+ const bareName = name.replace(/^__(?:Secure|Host)-/, "");
370
+ return (
371
+ bareName === "an_embed_session" ||
372
+ bareName === "an_session" ||
373
+ bareName === "an_session_workspace" ||
374
+ bareName.startsWith("an_session_") ||
375
+ BETTER_AUTH_SESSION_COOKIE_RE.test(bareName)
376
+ );
326
377
  }
327
378
 
328
379
  function requestHasAuthSignal(request) {
380
+ const headers = request.headers;
329
381
  const url = new URL(request.url);
330
382
  return Boolean(
331
- request.headers.get("authorization") ||
332
- requestHasAuthenticatedCookie(request.headers.get("cookie")) ||
383
+ headers.get("authorization") ||
384
+ requestHasAuthenticatedCookie(headers.get("cookie")) ||
333
385
  url.searchParams.has("__an_embed_token") ||
334
386
  url.searchParams.has("_session")
335
387
  );
@@ -337,6 +389,7 @@ function requestHasAuthSignal(request) {
337
389
 
338
390
  function shouldUseDefaultSsrCacheHeader(headers, status, pathname, hasAuthSignal) {
339
391
  if (status < 200 || status >= 400) return false;
392
+ if (hasAuthSignal) return false;
340
393
 
341
394
  const contentType = (headers.get("content-type") || "").toLowerCase();
342
395
  if (contentType.includes("text/html")) {
@@ -344,9 +397,12 @@ function shouldUseDefaultSsrCacheHeader(headers, status, pathname, hasAuthSignal
344
397
  }
345
398
 
346
399
  if (!pathname.endsWith(".data")) return false;
347
- if (hasAuthSignal) return false;
348
400
  if (!contentType.includes("text/x-script")) return false;
349
401
 
402
+ // React Router marks loader .data responses no-cache by default. Agent-Native
403
+ // default. For public loader responses, replace that default with the same
404
+ // short-fresh/long-SWR policy as HTML so route prefetch warms the CDN. Keep
405
+ // explicit route cache policies and any authenticated request untouched.
350
406
  const cacheControl = headers.get("cache-control");
351
407
  return !cacheControl || cacheControl.trim().toLowerCase() === "no-cache";
352
408
  }
@@ -466,6 +522,12 @@ async function getHandler() {
466
522
 
467
523
  // Run plugins — they call getH3App(nitroApp).use(path, handler) which
468
524
  // pushes path-prefix middleware onto app["~middleware"].
525
+ // Pre-mark every build-time plugin slot before any plugin awaits the runtime
526
+ // default bootstrap. Bundled serverless workers often lack server/plugins/
527
+ // on disk, so runtime discovery would otherwise auto-mount duplicate
528
+ // framework defaults before later custom plugins get a chance to mark
529
+ // themselves as provided.
530
+ ${generatedPluginMarks.map((stem) => ` markGeneratedPluginProvided(nitroApp, ${JSON.stringify(stem)});`).join("\n")}
469
531
  ${pluginCalls.join("\n")}
470
532
 
471
533
  // Register API routes
@@ -490,7 +552,7 @@ ${actionRegistrations.join("\n")}
490
552
  return new Response(null, { status: 404 });
491
553
  }
492
554
  const request = requestWithPathname(event.req, p);
493
- const hasAuthSignal = requestHasAuthSignal(event.req);
555
+ const hasAuthSignal = requestHasAuthSignal(request);
494
556
  if (event.req.method === "HEAD") {
495
557
  const getRequest = requestWithMethod(request, "GET");
496
558
  const response = await rrHandler(getRequest);
@@ -1137,15 +1199,22 @@ function createDanglingOptionalDepStubs() {
1137
1199
  */
1138
1200
  export async function runNitroBuildPipeline(opts) {
1139
1201
  const { nitro, hooks, clientDir, publicOutputDir, appBasePath, cwd } = opts;
1202
+ const hasClientBuild = fs.existsSync(clientDir) && Boolean(publicOutputDir);
1203
+ if (hasClientBuild) {
1204
+ // Install hashed-asset route rules before Nitro prepares platform output.
1205
+ // Some presets materialize headers during prepare/copy phases, not only in
1206
+ // nitroBuild; adding these later leaves Netlify/Vercel static assets without
1207
+ // the one-year immutable CDN policy even though the runtime manifest works.
1208
+ nitro.options.routeRules ??= {};
1209
+ addImmutableAssetRouteRulesForClientBuild(nitro.options.routeRules, clientDir, appBasePath);
1210
+ }
1140
1211
  await hooks.prepare(nitro);
1141
1212
  await hooks.copyPublicAssets(nitro);
1142
- if (fs.existsSync(clientDir) && publicOutputDir) {
1213
+ if (hasClientBuild && publicOutputDir) {
1143
1214
  copyDir(clientDir, publicOutputDir);
1144
1215
  if (appBasePath) {
1145
1216
  copyDir(clientDir, path.join(publicOutputDir, appBasePath.slice(1)));
1146
1217
  }
1147
- nitro.options.routeRules ??= {};
1148
- addImmutableAssetRouteRulesForClientBuild(nitro.options.routeRules, clientDir, appBasePath);
1149
1218
  console.log(`[deploy] Copied client assets to ${path.relative(cwd, publicOutputDir)}`);
1150
1219
  }
1151
1220
  await hooks.nitroBuild(nitro);
@@ -1212,6 +1281,7 @@ export default bundle;
1212
1281
  pathAliases["@"] = appDir;
1213
1282
  if (fs.existsSync(sharedDir))
1214
1283
  pathAliases["@shared"] = sharedDir;
1284
+ const providedPluginsNitroPlugin = await writeProvidedPluginsNitroPlugin();
1215
1285
  const nitro = await createNitro({
1216
1286
  rootDir: cwd,
1217
1287
  dev: false,
@@ -1228,6 +1298,9 @@ export default bundle;
1228
1298
  virtual: {
1229
1299
  "virtual:agents-bundle": agentsBundleModuleSource,
1230
1300
  },
1301
+ ...(providedPluginsNitroPlugin
1302
+ ? { plugins: [providedPluginsNitroPlugin] }
1303
+ : {}),
1231
1304
  routeRules: mcpEmbedStaticAssetRouteRules(appBasePath),
1232
1305
  // For edge presets (cloudflare, deno), bundle all deps — node_modules
1233
1306
  // aren't available at runtime. Netlify/Vercel/Node have node_modules.