@agent-native/core 0.167.1 → 0.167.4

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.
Files changed (80) hide show
  1. package/corpus/templates/analytics/.agents/skills/agent-native-docs/SKILL.md +11 -0
  2. package/corpus/templates/assets/.agents/skills/agent-native-docs/SKILL.md +11 -0
  3. package/corpus/templates/brain/.agents/skills/agent-native-docs/SKILL.md +11 -0
  4. package/corpus/templates/calendar/.agents/skills/agent-native-docs/SKILL.md +11 -0
  5. package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +11 -0
  6. package/corpus/templates/clips/.agents/skills/agent-native-docs/SKILL.md +11 -0
  7. package/corpus/templates/clips/app/routes/download.tsx +78 -131
  8. package/corpus/templates/content/.agents/skills/agent-native-docs/SKILL.md +11 -0
  9. package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +11 -0
  10. package/corpus/templates/design/.agents/skills/agent-native-docs/SKILL.md +11 -0
  11. package/corpus/templates/dispatch/.agents/skills/agent-native-docs/SKILL.md +11 -0
  12. package/corpus/templates/factory/.agents/skills/agent-native-docs/SKILL.md +11 -0
  13. package/corpus/templates/forms/.agents/skills/agent-native-docs/SKILL.md +11 -0
  14. package/corpus/templates/macros/.agents/skills/agent-native-docs/SKILL.md +11 -0
  15. package/corpus/templates/mail/.agents/skills/agent-native-docs/SKILL.md +11 -0
  16. package/corpus/templates/plan/.agents/skills/agent-native-docs/SKILL.md +11 -0
  17. package/corpus/templates/slides/.agents/skills/agent-native-docs/SKILL.md +11 -0
  18. package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +11 -0
  19. package/dist/chat-threads/store.d.ts +7 -0
  20. package/dist/chat-threads/store.js +15 -0
  21. package/dist/client/AgentPanel.d.ts +5 -1
  22. package/dist/client/AgentPanel.js +8 -8
  23. package/dist/client/AssistantChat.d.ts +3 -1
  24. package/dist/client/AssistantChat.js +22 -6
  25. package/dist/client/MultiTabAssistantChat.d.ts +3 -1
  26. package/dist/client/MultiTabAssistantChat.js +5 -4
  27. package/dist/client/agent-page/AgentJobsTab.js +39 -6
  28. package/dist/client/agent-page/AutomationScheduleDialog.d.ts +10 -1
  29. package/dist/client/agent-page/AutomationScheduleDialog.js +3 -2
  30. package/dist/client/agent-page/ScheduledTriggerNotice.d.ts +22 -0
  31. package/dist/client/agent-page/ScheduledTriggerNotice.js +84 -0
  32. package/dist/client/agent-page/scheduled-trigger-state.d.ts +28 -0
  33. package/dist/client/agent-page/scheduled-trigger-state.js +10 -0
  34. package/dist/client/agent-page/use-jobs.d.ts +7 -0
  35. package/dist/client/agent-page/use-jobs.js +14 -0
  36. package/dist/client/blocks/library/diagram.config.d.ts +4 -1
  37. package/dist/client/blocks/library/diagram.js +1 -1
  38. package/dist/client/chat/run-recovery.js +15 -7
  39. package/dist/client/use-chat-threads.d.ts +7 -0
  40. package/dist/client/use-chat-threads.js +144 -40
  41. package/dist/collab/awareness.d.ts +2 -2
  42. package/dist/collab/struct-routes.d.ts +1 -1
  43. package/dist/deploy/build.d.ts +5 -0
  44. package/dist/deploy/build.js +12 -1
  45. package/dist/framework-tools.js +1 -0
  46. package/dist/jobs/actions/get-scheduled-trigger-status.d.ts +13 -0
  47. package/dist/jobs/actions/get-scheduled-trigger-status.js +21 -0
  48. package/dist/localization/default-messages.d.ts +14 -0
  49. package/dist/localization/default-messages.js +14 -0
  50. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  51. package/dist/notifications/routes.d.ts +3 -3
  52. package/dist/observability/routes.d.ts +3 -3
  53. package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
  54. package/dist/provider-api/actions/provider-api.d.ts +13 -13
  55. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  56. package/dist/server/action-discovery.js +4 -0
  57. package/dist/server/agent-chat/recurring-jobs-runtime.d.ts +42 -1
  58. package/dist/server/agent-chat/recurring-jobs-runtime.js +102 -9
  59. package/dist/server/agent-chat-plugin.d.ts +3 -1
  60. package/dist/server/agent-chat-plugin.js +115 -24
  61. package/dist/server/attribution.d.ts +29 -0
  62. package/dist/server/attribution.js +68 -0
  63. package/dist/server/auth.js +58 -15
  64. package/dist/server/better-auth-instance.js +16 -4
  65. package/dist/server/identity-sso.js +14 -2
  66. package/dist/server/realtime-token.d.ts +1 -1
  67. package/dist/server/request-context.d.ts +8 -0
  68. package/dist/server/request-context.js +4 -0
  69. package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +11 -0
  70. package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +11 -0
  71. package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +11 -0
  72. package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +11 -0
  73. package/dist/vite/client.js +10 -0
  74. package/docs/content/deployment.mdx +3 -1
  75. package/docs/content/recurring-jobs.mdx +6 -0
  76. package/package.json +2 -2
  77. package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +11 -0
  78. package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +11 -0
  79. package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +11 -0
  80. package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +11 -0
@@ -37,7 +37,10 @@ export interface DiagramData {
37
37
  */
38
38
  html?: string;
39
39
  css?: string;
40
- /** `design` forces clean HTML/CSS rendering without the sketch overlay. */
40
+ /**
41
+ * `design` forces clean HTML/CSS rendering without the sketch overlay. Use it
42
+ * for UI-like blocks such as cards, logo walls, tables, and controls.
43
+ */
41
44
  renderMode?: "wireframe" | "design";
42
45
  caption?: string;
43
46
  /** Outer surface frame. `auto` lets the host choose the right default. */
@@ -393,7 +393,7 @@ export const diagramBlock = defineBlock({
393
393
  // edit from a corner button + panel rather than inline.
394
394
  editSurface: "panel",
395
395
  label: "Diagram",
396
- description: "A flexible inline architecture/code diagram. Prefer html/css with SVG or semantic HTML for polished two-dimensional layouts; use renderMode design for clean presentation or .diagram-* primitives and --wf-* tokens for theme/sketch compatibility. Legacy nodes/edges are only for simple previews.",
396
+ description: "A flexible inline architecture/code diagram. Prefer html/css with SVG or semantic HTML for polished two-dimensional layouts; use renderMode design for UI-like blocks such as cards, logo walls, tables, and controls, or .diagram-* primitives and --wf-* tokens for actual diagrams that need theme/sketch compatibility. Legacy nodes/edges are only for simple previews.",
397
397
  // Seed the legacy fallback shape so a fresh block validates while agents can
398
398
  // replace it with html/css when layout quality matters.
399
399
  empty: () => ({ nodes: [{ id: "n1", label: "Module" }], edges: [] }),
@@ -298,17 +298,25 @@ export function RunErrorRecoveryCard({ info, onContinue, onRetry, onFork, onDism
298
298
  return (_jsxs("div", { className: "rounded-lg border border-amber-500/25 bg-amber-500/[0.06] p-3 text-sm", children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("span", { className: "mt-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-amber-500/10 text-amber-700 dark:text-amber-300", children: _jsx(IconAlertTriangle, { size: 14 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "font-medium text-foreground", children: runErrorHeadline(info, {
299
299
  recoverable: t("agentChat.error.stopped"),
300
300
  terminal: t("agentChat.error.failed"),
301
- }) }), _jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: localizeKnownChatErrorText(info.message, t) }), isProviderAuthError && (_jsx("div", { className: "mt-3 rounded-md border border-border/70 bg-background/60 p-2.5", children: _jsx(BuilderSetupContent, { layout: "sidebar", onConnected: handleProviderConnected }) })), shouldShowBuilderReconnect && !builderReconnectResolved && (_jsx("p", { className: "mt-2 text-xs leading-relaxed text-muted-foreground", children: t("agentChat.recovery.credentialRejected") })), isConnectionRecoveryError && (_jsx("p", { className: "mt-2 text-xs leading-relaxed text-muted-foreground", children: t("agentChat.recovery.newChatHint") })), (info.runId || info.errorCode || info.details) && (_jsxs("button", { type: "button", onClick: () => setDetailsOpen((v) => !v), className: "mt-2 inline-flex items-center gap-1 text-[11px] font-medium text-muted-foreground hover:text-foreground", children: [_jsx(IconChevronDown, { size: 12, className: cn("transition-transform", detailsOpen && "rotate-180") }), t("agentChat.common.details")] })), detailsOpen && (_jsxs("div", { className: "mt-2 rounded-md border border-border/60 bg-background/70 p-2 font-mono text-[11px] leading-relaxed text-muted-foreground", children: [info.runId && _jsxs("div", { children: ["run: ", info.runId] }), info.errorCode && _jsxs("div", { children: ["code: ", info.errorCode] }), info.details && (_jsx("pre", { className: "mt-2 max-h-28 overflow-auto whitespace-pre-wrap break-words font-mono", children: info.details }))] }))] }), _jsx("button", { type: "button", onClick: onDismiss, "aria-label": t("agentChat.common.dismiss"), className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-background/80 hover:text-foreground", children: _jsx(IconX, { size: 14 }) })] }), _jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [shouldShowBuilderReconnect && !builderReconnectResolved && (_jsxs("button", { type: "button", onClick: () => builderReconnect.start(), disabled: builderReconnect.connecting, className: "inline-flex h-8 items-center gap-1.5 rounded-md bg-foreground px-3 text-xs font-medium text-background hover:opacity-90 disabled:cursor-wait disabled:opacity-70", children: [builderReconnect.connecting ? (_jsx(IconLoader2, { size: 13, className: "animate-spin" })) : null, builderReconnect.connecting
301
+ }) }), _jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: localizeKnownChatErrorText(info.message, t) }), isProviderAuthError && (_jsx("div", { className: "mt-3 rounded-md border border-border/70 bg-background/60 p-2.5", children: _jsx(BuilderSetupContent, { layout: "sidebar", onConnected: handleProviderConnected }) })), shouldShowBuilderReconnect && !builderReconnectResolved && (_jsx("p", { className: "mt-2 text-xs leading-relaxed text-muted-foreground", children: t("agentChat.recovery.credentialRejected") })), isConnectionRecoveryError && (_jsx("p", { className: "mt-2 text-xs leading-relaxed text-muted-foreground", children: t("agentChat.recovery.newChatHint") })), (info.runId || info.errorCode || info.details) && (_jsxs("button", { type: "button", onClick: () => setDetailsOpen((v) => !v), className: "mt-2 inline-flex items-center gap-1 text-[11px] font-medium text-muted-foreground hover:text-foreground", children: [_jsx(IconChevronDown, { size: 12, className: cn("transition-transform", detailsOpen && "rotate-180") }), t("agentChat.common.details")] })), detailsOpen && (_jsxs("div", { className: "mt-2 rounded-md border border-border/60 bg-background/70 p-2 font-mono text-[11px] leading-relaxed text-muted-foreground", children: [info.runId && _jsxs("div", { children: ["run: ", info.runId] }), info.errorCode && _jsxs("div", { children: ["code: ", info.errorCode] }), info.details && (_jsx("pre", { className: "mt-2 max-h-28 overflow-auto whitespace-pre-wrap break-words font-mono", children: info.details }))] }))] }), _jsx("button", { type: "button", onClick: onDismiss, "aria-label": t("agentChat.common.dismiss"), className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-background/80 hover:text-foreground", children: _jsx(IconX, { size: 14 }) })] }), _jsxs("div", { className: "mt-3 flex min-w-0 items-center gap-2", children: [shouldShowBuilderReconnect && !builderReconnectResolved && (_jsxs("button", { type: "button", onClick: () => builderReconnect.start(), disabled: builderReconnect.connecting, className: "inline-flex h-8 items-center gap-1.5 rounded-md bg-foreground px-3 text-xs font-medium text-background hover:opacity-90 disabled:cursor-wait disabled:opacity-70", children: [builderReconnect.connecting ? (_jsx(IconLoader2, { size: 13, className: "animate-spin" })) : null, builderReconnect.connecting
302
302
  ? t("agentChat.recovery.connectingBuilder")
303
- : t("agentChat.recovery.reconnectBuilder")] })), canRecover && (_jsx(_Fragment, { children: _jsxs("button", { type: "button", onClick: onContinue, className: "inline-flex h-8 items-center gap-1.5 rounded-md bg-foreground px-3 text-xs font-medium text-background hover:opacity-90", children: [_jsx(IconPlayerPlay, { size: 13 }), t("agentChat.common.continue")] }) })), canRetry && (_jsxs("button", { type: "button", onClick: onRetry, className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background px-3 text-xs font-medium text-foreground hover:bg-accent", children: [_jsx(IconRefresh, { size: 13 }), isQueryError
304
- ? t("agentChat.recovery.diagnoseRetry")
305
- : t("agentChat.common.retry")] })), canRecover && isConnectionRecoveryError && (_jsxs("button", { type: "button", onClick: startNewChat, className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background px-3 text-xs font-medium text-foreground hover:bg-accent", children: [_jsx(IconPlus, { size: 13 }), t("agentChat.tabs.newChat")] })), canRecover && onFork && !isConnectionRecoveryError && (_jsxs("button", { type: "button", onClick: handleFork, disabled: forking, title: t("agentChat.recovery.forkDescription"), "aria-label": t("agentChat.recovery.forkDescription"), className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background px-3 text-xs font-medium text-foreground hover:bg-accent disabled:cursor-wait disabled:opacity-70", children: [forking ? (_jsx(IconLoader2, { size: 13, className: "animate-spin" })) : (_jsx(IconGitFork, { size: 13 })), forking
306
- ? t("agentChat.recovery.forking")
307
- : t("agentChat.message.forkChat")] })), _jsxs("button", { type: "button", onClick: copyDetails, className: "ms-auto inline-flex h-8 items-center gap-1.5 rounded-md px-2.5 text-xs font-medium text-muted-foreground hover:bg-background/80 hover:text-foreground", children: [copyState === "copied" ? (_jsx(IconCheck, { size: 13 })) : copyState === "failed" ? (_jsx(IconX, { size: 13 })) : (_jsx(IconCopy, { size: 13 })), _jsx("span", { "aria-live": "polite", children: copyState === "copied"
303
+ : t("agentChat.recovery.reconnectBuilder")] })), canRecover && (_jsxs("button", { type: "button", onClick: onContinue, className: "inline-flex min-w-0 flex-1 items-center justify-center gap-1.5 rounded-md bg-foreground px-3 text-xs font-medium text-background hover:opacity-90", children: [_jsx(IconPlayerPlay, { size: 13 }), _jsx("span", { className: "truncate", children: t("agentChat.common.continue") })] })), _jsxs("div", { className: "flex shrink-0 items-center gap-0.5 rounded-md border border-border/70 bg-background/60 p-0.5", children: [canRetry && (_jsx("button", { type: "button", onClick: onRetry, title: isQueryError
304
+ ? t("agentChat.recovery.diagnoseRetry")
305
+ : t("agentChat.common.retry"), "aria-label": isQueryError
306
+ ? t("agentChat.recovery.diagnoseRetry")
307
+ : t("agentChat.common.retry"), className: "inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground", children: _jsx(IconRefresh, { size: 14 }) })), canRecover && isConnectionRecoveryError && (_jsx("button", { type: "button", onClick: startNewChat, title: t("agentChat.tabs.newChat"), "aria-label": t("agentChat.tabs.newChat"), className: "inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground", children: _jsx(IconPlus, { size: 14 }) })), canRecover && onFork && !isConnectionRecoveryError && (_jsx("button", { type: "button", onClick: handleFork, disabled: forking, title: t("agentChat.recovery.forkDescription"), "aria-label": t("agentChat.recovery.forkDescription"), className: "inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground disabled:cursor-wait disabled:opacity-70", children: forking ? (_jsx(IconLoader2, { size: 14, className: "animate-spin" })) : (_jsx(IconGitFork, { size: 14 })) })), _jsxs("button", { type: "button", onClick: copyDetails, title: copyState === "copied"
308
308
  ? t("agentChat.common.copied")
309
309
  : copyState === "failed"
310
310
  ? t("agentChat.recovery.copyFailed")
311
- : copyLabel })] })] }), shouldShowBuilderReconnect && builderReconnect.error && (_jsx("p", { className: "mt-2 text-xs leading-relaxed text-red-500", children: builderReconnect.error })), forkError && (_jsx("p", { className: "mt-2 text-xs leading-relaxed text-red-500", children: forkError }))] }));
311
+ : copyLabel, "aria-label": copyState === "copied"
312
+ ? t("agentChat.common.copied")
313
+ : copyState === "failed"
314
+ ? t("agentChat.recovery.copyFailed")
315
+ : copyLabel, className: "inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground", children: [copyState === "copied" ? (_jsx(IconCheck, { size: 14 })) : copyState === "failed" ? (_jsx(IconX, { size: 14 })) : (_jsx(IconCopy, { size: 14 })), _jsx("span", { className: "sr-only", "aria-live": "polite", children: copyState === "copied"
316
+ ? t("agentChat.common.copied")
317
+ : copyState === "failed"
318
+ ? t("agentChat.recovery.copyFailed")
319
+ : copyLabel })] })] })] }), shouldShowBuilderReconnect && builderReconnect.error && (_jsx("p", { className: "mt-2 text-xs leading-relaxed text-red-500", children: builderReconnect.error })), forkError && (_jsx("p", { className: "mt-2 text-xs leading-relaxed text-red-500", children: forkError }))] }));
312
320
  }
313
321
  // ─── LoopLimitContinueCard ────────────────────────────────────────────────────
314
322
  export function LoopLimitContinueCard({ info, onContinue, }) {
@@ -66,7 +66,14 @@ export interface UseChatThreadsOptions {
66
66
  routeThreadId?: string | null;
67
67
  /** Include connected and other-app chats in list/search results. */
68
68
  includeExternal?: boolean;
69
+ /**
70
+ * Restrict history to the supplied scope. App-owned chat rails use this to
71
+ * keep one app's conversations out of another app's history; ordinary
72
+ * resource scopes intentionally continue to show general chats.
73
+ */
74
+ isolateHistoryByScope?: boolean;
69
75
  }
76
+ export declare function appendChatThreadScopeParams(params: URLSearchParams, scope?: ChatThreadScope | null): void;
70
77
  export declare function useChatThreads(apiUrl?: string, storageKey?: string, scope?: ChatThreadScope | null, options?: UseChatThreadsOptions): {
71
78
  threads: ChatThreadSummary[];
72
79
  activeThreadId: string | null;
@@ -3,12 +3,13 @@ import { agentNativePath } from "./api-path.js";
3
3
  const ACTIVE_THREAD_KEY = "agent-chat-active-thread";
4
4
  const THREADS_UPDATED_EVENT = "agent-chat:threads-updated";
5
5
  const THREADS_PAGE_SIZE = 50;
6
- async function fetchThreadListPage(apiUrl, offset, includeExternal) {
6
+ async function fetchThreadListPage(apiUrl, offset, includeExternal, scope) {
7
7
  const params = new URLSearchParams();
8
8
  if (offset > 0)
9
9
  params.set("offset", String(offset));
10
10
  if (includeExternal)
11
11
  params.set("includeExternal", "1");
12
+ appendChatThreadScopeParams(params, scope);
12
13
  const query = params.toString();
13
14
  return fetch(`${apiUrl}/threads${query ? `?${query}` : ""}`).then(async (res) => {
14
15
  if (!res.ok)
@@ -22,9 +23,12 @@ async function fetchThreadListPage(apiUrl, offset, includeExternal) {
22
23
  * the caller must not collapse: the thread (found), `null` (the server denies it
23
24
  * exists), and `undefined` (unreachable — nothing was learned).
24
25
  */
25
- async function fetchThreadById(apiUrl, id) {
26
+ async function fetchThreadById(apiUrl, id, scope) {
26
27
  try {
27
- const res = await fetch(`${apiUrl}/threads/${encodeURIComponent(id)}`);
28
+ const params = new URLSearchParams();
29
+ appendChatThreadScopeParams(params, scope);
30
+ const query = params.toString();
31
+ const res = await fetch(`${apiUrl}/threads/${encodeURIComponent(id)}${query ? `?${query}` : ""}`);
28
32
  if (res.status === 404)
29
33
  return null;
30
34
  if (!res.ok)
@@ -35,6 +39,20 @@ async function fetchThreadById(apiUrl, id) {
35
39
  return undefined;
36
40
  }
37
41
  }
42
+ export function appendChatThreadScopeParams(params, scope) {
43
+ if (!scope)
44
+ return;
45
+ params.set("scopeType", scope.type);
46
+ params.set("scopeId", scope.id);
47
+ }
48
+ function withChatThreadScope(url, scope) {
49
+ const params = new URLSearchParams();
50
+ appendChatThreadScopeParams(params, scope);
51
+ const query = params.toString();
52
+ if (!query)
53
+ return url;
54
+ return `${url}${url.includes("?") ? "&" : "?"}${query}`;
55
+ }
38
56
  function emitThreadsUpdated() {
39
57
  if (typeof window === "undefined")
40
58
  return;
@@ -91,6 +109,12 @@ function threadCanStayVisibleInScope(threadScope, currentScope) {
91
109
  return true;
92
110
  return scopesMatch(threadScope, currentScope);
93
111
  }
112
+ function threadCanStayVisibleInHistory(threadScope, currentScope, isolateHistoryByScope = false) {
113
+ if (!isolateHistoryByScope) {
114
+ return threadCanStayVisibleInScope(threadScope, currentScope);
115
+ }
116
+ return scopesMatch(threadScope, currentScope);
117
+ }
94
118
  function nextThreadTitle(currentTitle, incomingTitle, incomingPreview, source = "extracted", options = {}) {
95
119
  if (options.preserveUserTitle && currentTitle)
96
120
  return currentTitle;
@@ -109,6 +133,12 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
109
133
  const autoCreate = options?.autoCreate !== false;
110
134
  const restoreActiveThread = options?.restoreActiveThread !== false;
111
135
  const includeExternal = options?.includeExternal === true;
136
+ const isolateHistoryByScope = options?.isolateHistoryByScope === true;
137
+ const isolateHistory = isolateHistoryByScope && Boolean(scope);
138
+ const historyScope = useMemo(() => (isolateHistory && scope ? { type: scope.type, id: scope.id } : null), [isolateHistory, scope?.id, scope?.type]);
139
+ const historyScopeKey = historyScope
140
+ ? `${historyScope.type}:${historyScope.id}`
141
+ : null;
112
142
  const routeControlsActiveThread = options?.routeThreadId !== undefined;
113
143
  const routeThreadId = normalizeThreadId(options?.routeThreadId);
114
144
  // Each (storageKey, scope) pair gets its own active-thread localStorage key
@@ -170,6 +200,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
170
200
  ? new Set([initialActiveThreadRef.current.id])
171
201
  : new Set());
172
202
  const optimisticThreadScopesRef = useRef(new Map());
203
+ const knownThreadScopesRef = useRef(new Map());
173
204
  const pendingPinnedAtRef = useRef(new Map());
174
205
  const pendingArchivedAtRef = useRef(new Map());
175
206
  const userRenamedThreadIdsRef = useRef(new Set());
@@ -215,6 +246,9 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
215
246
  if (optimisticThreadScopesRef.current.has(id)) {
216
247
  return optimisticThreadScopesRef.current.get(id) ?? null;
217
248
  }
249
+ if (knownThreadScopesRef.current.has(id)) {
250
+ return knownThreadScopesRef.current.get(id) ?? null;
251
+ }
218
252
  return undefined;
219
253
  }, []);
220
254
  // Add a client-generated thread to the local list optimistically.
@@ -290,7 +324,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
290
324
  if (currentThreadScope === undefined) {
291
325
  return;
292
326
  }
293
- if (threadCanStayVisibleInScope(currentThreadScope, scopeRef.current)) {
327
+ if (threadCanStayVisibleInHistory(currentThreadScope, scopeRef.current, isolateHistory)) {
294
328
  persistedKeyRef.current = activeThreadKey;
295
329
  return;
296
330
  }
@@ -308,7 +342,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
308
342
  if (nextActiveThreadId) {
309
343
  const savedScope = readKnownThreadScope(nextActiveThreadId);
310
344
  if (savedScope !== undefined &&
311
- !threadCanStayVisibleInScope(savedScope, scopeRef.current)) {
345
+ !threadCanStayVisibleInHistory(savedScope, scopeRef.current, isolateHistory)) {
312
346
  nextActiveThreadId = null;
313
347
  }
314
348
  }
@@ -356,7 +390,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
356
390
  const requestId = ++latestFetchRequestRef.current;
357
391
  try {
358
392
  const offset = options?.append ? nextThreadsOffsetRef.current : 0;
359
- const loaded = await fetchThreadListPage(apiUrl, offset, includeExternal);
393
+ const loaded = await fetchThreadListPage(apiUrl, offset, includeExternal, historyScope);
360
394
  if (requestId !== latestFetchRequestRef.current)
361
395
  return undefined;
362
396
  if (!loaded) {
@@ -365,6 +399,9 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
365
399
  }
366
400
  return;
367
401
  }
402
+ for (const thread of loaded) {
403
+ knownThreadScopesRef.current.set(thread.id, thread.scope ?? null);
404
+ }
368
405
  setThreadsLoadError(null);
369
406
  if (!options?.append) {
370
407
  nextThreadsOffsetRef.current = loaded.length;
@@ -373,8 +410,11 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
373
410
  nextThreadsOffsetRef.current += loaded.length;
374
411
  }
375
412
  setHasMoreThreads(loaded.length >= THREADS_PAGE_SIZE);
413
+ const visibleLoaded = isolateHistory
414
+ ? loaded.filter((thread) => threadCanStayVisibleInHistory(thread.scope, historyScope, isolateHistory))
415
+ : loaded;
376
416
  setThreads((prev) => {
377
- const loadedIds = new Set(loaded.map((t) => t.id));
417
+ const loadedIds = new Set(visibleLoaded.map((t) => t.id));
378
418
  // Preserve any optimistic threads we've created this session that
379
419
  // haven't shown up in the server list yet — the server only learns
380
420
  // about a thread when the user actually sends a message and the
@@ -387,13 +427,15 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
387
427
  // and get preserved forever instead of disappearing once archived.
388
428
  const optimisticOnly = prev.filter((t) => newlyCreatedRef.current.has(t.id) &&
389
429
  !loadedIds.has(t.id) &&
390
- !t.archivedAt);
430
+ !t.archivedAt &&
431
+ (!isolateHistory ||
432
+ threadCanStayVisibleInHistory(t.scope, historyScope, isolateHistory)));
391
433
  // Reconcile each server thread against our local copy. If the local
392
434
  // copy has a newer updatedAt or higher messageCount, keep those
393
435
  // fields — the server probably hasn't observed the user's latest
394
436
  // send yet, and naively replacing makes the recent-chats list
395
437
  // visibly jump back to older timestamps right after a send.
396
- const merged = loaded.map((server) => {
438
+ const merged = visibleLoaded.map((server) => {
397
439
  const local = prev.find((t) => t.id === server.id);
398
440
  if (!local)
399
441
  return server;
@@ -438,7 +480,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
438
480
  }
439
481
  return [...optimisticOnly, ...merged];
440
482
  });
441
- return loaded;
483
+ return visibleLoaded;
442
484
  }
443
485
  catch {
444
486
  if (requestId !== latestFetchRequestRef.current)
@@ -448,7 +490,28 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
448
490
  }
449
491
  return undefined;
450
492
  }
451
- }, [apiUrl, includeExternal]);
493
+ }, [apiUrl, historyScope, includeExternal, isolateHistory]);
494
+ const loadedHistoryScopeKeyRef = useRef(historyScopeKey);
495
+ useEffect(() => {
496
+ if (loadedHistoryScopeKeyRef.current === historyScopeKey)
497
+ return;
498
+ loadedHistoryScopeKeyRef.current = historyScopeKey;
499
+ if (!isolateHistoryByScope)
500
+ return;
501
+ nextThreadsOffsetRef.current = 0;
502
+ setHasMoreThreads(false);
503
+ setThreadsLoadError(null);
504
+ setThreads((prev) => prev.filter((thread) => !isolateHistory ||
505
+ threadCanStayVisibleInHistory(thread.scope, historyScope, isolateHistory)));
506
+ setIsLoading(true);
507
+ void fetchThreads().finally(() => setIsLoading(false));
508
+ }, [
509
+ fetchThreads,
510
+ historyScope,
511
+ historyScopeKey,
512
+ isolateHistory,
513
+ isolateHistoryByScope,
514
+ ]);
452
515
  const loadMoreThreads = useCallback(async () => {
453
516
  if (isLoadingMoreThreads || !hasMoreThreads)
454
517
  return;
@@ -509,8 +572,11 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
509
572
  // One page, so absence from it is not absence from the server — this is what
510
573
  // separates an older real thread from an unavailable saved id below.
511
574
  const restoredThread = lookupRestored && !restoredOnPage
512
- ? await fetchThreadById(apiUrl, restoredId)
575
+ ? await fetchThreadById(apiUrl, restoredId, historyScope)
513
576
  : restoredOnPage;
577
+ if (restoredThread) {
578
+ knownThreadScopesRef.current.set(restoredThread.id, restoredThread.scope ?? null);
579
+ }
514
580
  if (restoredThread === undefined && lookupRestored && !restoredOnPage) {
515
581
  // Lookup unreachable. Reclassifying now would stamp this thread with the
516
582
  // current scope on a guess; leave it untouched for the next mount.
@@ -519,7 +585,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
519
585
  }
520
586
  const restoredIsUnavailable = restoredThread === null && lookupRestored && !restoredOnPage;
521
587
  const restoredBelongsElsewhere = Boolean(restoredThread &&
522
- !threadCanStayVisibleInScope(restoredThread.scope ?? null, scopeRef.current));
588
+ !threadCanStayVisibleInHistory(restoredThread.scope ?? null, scopeRef.current, isolateHistory));
523
589
  // A missing saved id is stale local UI state on a normal home surface,
524
590
  // not a reason to show an error above a fresh composer. Preserve it for
525
591
  // explicit routes and list-only readers, where the caller still owns
@@ -587,6 +653,8 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
587
653
  fetchThreads,
588
654
  addOptimisticThread,
589
655
  autoCreate,
656
+ historyScope,
657
+ isolateHistory,
590
658
  routeControlsActiveThread,
591
659
  routeThreadId,
592
660
  ]);
@@ -641,7 +709,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
641
709
  // list right away.
642
710
  const detachThread = useCallback(async (threadId) => {
643
711
  try {
644
- const res = await fetch(`${apiUrl}/threads/${encodeURIComponent(threadId)}`, {
712
+ const res = await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(threadId)}`, historyScope), {
645
713
  method: "PUT",
646
714
  headers: { "Content-Type": "application/json" },
647
715
  body: JSON.stringify({ scope: null }),
@@ -652,14 +720,42 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
652
720
  await fetchThreads();
653
721
  return;
654
722
  }
655
- setThreads((prev) => prev.map((t) => (t.id === threadId ? { ...t, scope: null } : t)));
723
+ knownThreadScopesRef.current.set(threadId, null);
656
724
  optimisticThreadScopesRef.current.set(threadId, null);
725
+ const wasActive = activeThreadIdRef.current === threadId;
726
+ if (isolateHistory) {
727
+ setThreads((prev) => prev.filter((thread) => thread.id !== threadId &&
728
+ threadCanStayVisibleInHistory(thread.scope, historyScope, isolateHistory)));
729
+ if (wasActive) {
730
+ const remaining = threadsRef.current.filter((thread) => thread.id !== threadId &&
731
+ threadCanStayVisibleInHistory(thread.scope, historyScope, isolateHistory));
732
+ if (remaining.length > 0) {
733
+ setActiveThreadId(remaining[0].id);
734
+ }
735
+ else if (autoCreate) {
736
+ void createThread();
737
+ }
738
+ else {
739
+ setActiveThreadId(null);
740
+ }
741
+ }
742
+ }
743
+ else {
744
+ setThreads((prev) => prev.map((t) => (t.id === threadId ? { ...t, scope: null } : t)));
745
+ }
657
746
  emitThreadsUpdated();
658
747
  }
659
748
  catch {
660
749
  await fetchThreads().catch(() => { });
661
750
  }
662
- }, [apiUrl, fetchThreads]);
751
+ }, [
752
+ apiUrl,
753
+ autoCreate,
754
+ createThread,
755
+ fetchThreads,
756
+ historyScope,
757
+ isolateHistory,
758
+ ]);
663
759
  const pinThread = useCallback(async (threadId, pinned) => {
664
760
  const previousPinnedAt = threadsRef.current.find((t) => t.id === threadId)?.pinnedAt ?? null;
665
761
  const previousUpdatedAt = threadsRef.current.find((t) => t.id === threadId)?.updatedAt ?? null;
@@ -680,7 +776,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
680
776
  };
681
777
  setThreads((prev) => prev.map((t) => (t.id === threadId ? { ...t, pinnedAt } : t)));
682
778
  try {
683
- const res = await fetch(`${apiUrl}/threads/${encodeURIComponent(threadId)}/pin`, {
779
+ const res = await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(threadId)}/pin`, historyScope), {
684
780
  method: "POST",
685
781
  headers: { "Content-Type": "application/json" },
686
782
  body: JSON.stringify({ pinned }),
@@ -701,7 +797,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
701
797
  await fetchThreads();
702
798
  return false;
703
799
  }
704
- }, [apiUrl, fetchThreads]);
800
+ }, [apiUrl, fetchThreads, historyScope]);
705
801
  const archiveThread = useCallback(async (threadId) => {
706
802
  const previousArchivedAt = threadsRef.current.find((t) => t.id === threadId)?.archivedAt ?? null;
707
803
  const previousUpdatedAt = threadsRef.current.find((t) => t.id === threadId)?.updatedAt ?? null;
@@ -726,7 +822,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
726
822
  };
727
823
  setThreads((prev) => prev.map((t) => (t.id === threadId ? { ...t, archivedAt } : t)));
728
824
  try {
729
- const res = await fetch(`${apiUrl}/threads/${encodeURIComponent(threadId)}/archive`, {
825
+ const res = await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(threadId)}/archive`, historyScope), {
730
826
  method: "POST",
731
827
  headers: { "Content-Type": "application/json" },
732
828
  body: JSON.stringify({ archived: true }),
@@ -750,7 +846,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
750
846
  await fetchThreads();
751
847
  return false;
752
848
  }
753
- }, [apiUrl, fetchThreads]);
849
+ }, [apiUrl, fetchThreads, historyScope]);
754
850
  const renameThread = useCallback(async (threadId, title) => {
755
851
  const nextTitle = title.replace(/\s+/g, " ").trim().slice(0, 160);
756
852
  if (!nextTitle)
@@ -768,7 +864,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
768
864
  markUserRenamedThread(threadId);
769
865
  setThreads((prev) => prev.map((t) => (t.id === threadId ? { ...t, title: nextTitle } : t)));
770
866
  try {
771
- const res = await fetch(`${apiUrl}/threads/${encodeURIComponent(threadId)}/rename`, {
867
+ const res = await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(threadId)}/rename`, historyScope), {
772
868
  method: "POST",
773
869
  headers: { "Content-Type": "application/json" },
774
870
  body: JSON.stringify({ title: nextTitle }),
@@ -786,7 +882,13 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
786
882
  await fetchThreads();
787
883
  return false;
788
884
  }
789
- }, [apiUrl, clearUserRenamedThread, fetchThreads, markUserRenamedThread]);
885
+ }, [
886
+ apiUrl,
887
+ clearUserRenamedThread,
888
+ fetchThreads,
889
+ historyScope,
890
+ markUserRenamedThread,
891
+ ]);
790
892
  const isNewThread = useCallback((id) => newlyCreatedRef.current.has(id), []);
791
893
  const switchThread = useCallback((id) => {
792
894
  persistActiveThreadId(id);
@@ -794,7 +896,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
794
896
  }, [persistActiveThreadId]);
795
897
  const removeThread = useCallback(async (id) => {
796
898
  try {
797
- await fetch(`${apiUrl}/threads/${encodeURIComponent(id)}`, {
899
+ await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(id)}`, historyScope), {
798
900
  method: "DELETE",
799
901
  });
800
902
  emitThreadsUpdated();
@@ -816,7 +918,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
816
918
  createThread();
817
919
  }
818
920
  }
819
- }, [apiUrl, clearUserRenamedThread, createThread]);
921
+ }, [apiUrl, clearUserRenamedThread, createThread, historyScope]);
820
922
  // Reads scope through refs so this callback survives every setThreads. Scope
821
923
  // rides only on creation: a periodic save must never move an existing thread
822
924
  // between resources, however stale this client's guess is.
@@ -828,7 +930,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
828
930
  const preserveUserTitle = userRenamedThreadIdsRef.current.has(id);
829
931
  const title = nextThreadTitle(localThread?.title, data.title, data.preview, titleSource, { preserveUserTitle });
830
932
  const payload = { ...threadDataPayload, title };
831
- let response = await fetch(`${apiUrl}/threads/${encodeURIComponent(id)}`, {
933
+ let response = await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(id)}`, historyScope), {
832
934
  method: "PUT",
833
935
  headers: { "Content-Type": "application/json" },
834
936
  body: JSON.stringify(payload),
@@ -837,7 +939,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
837
939
  // client-created thread, so no agent run has created its SQL row yet.
838
940
  // Materialize that row idempotently and retry the same full save.
839
941
  if (response.status === 404) {
840
- const created = await fetch(`${apiUrl}/threads`, {
942
+ const created = await fetch(withChatThreadScope(`${apiUrl}/threads`, historyScope), {
841
943
  method: "POST",
842
944
  headers: { "Content-Type": "application/json" },
843
945
  body: JSON.stringify({
@@ -848,7 +950,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
848
950
  });
849
951
  if (!created.ok)
850
952
  return;
851
- response = await fetch(`${apiUrl}/threads/${encodeURIComponent(id)}`, {
953
+ response = await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(id)}`, historyScope), {
852
954
  method: "PUT",
853
955
  headers: { "Content-Type": "application/json" },
854
956
  body: JSON.stringify(payload),
@@ -894,7 +996,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
894
996
  });
895
997
  }
896
998
  catch { }
897
- }, [apiUrl, readKnownThreadScope]);
999
+ }, [apiUrl, historyScope, readKnownThreadScope]);
898
1000
  const generateTitle = useCallback(async (threadId, message) => {
899
1001
  try {
900
1002
  const res = await fetch(`${apiUrl}/generate-title`, {
@@ -923,7 +1025,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
923
1025
  const fallbackForkFromSnapshot = async (source) => {
924
1026
  const title = source.title ? `${source.title} (fork)` : "";
925
1027
  const createdAt = Date.now();
926
- const createRes = await fetch(`${apiUrl}/threads`, {
1028
+ const createRes = await fetch(withChatThreadScope(`${apiUrl}/threads`, historyScope), {
927
1029
  method: "POST",
928
1030
  headers: { "Content-Type": "application/json" },
929
1031
  body: JSON.stringify({
@@ -934,7 +1036,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
934
1036
  });
935
1037
  if (!createRes.ok)
936
1038
  return null;
937
- const saveRes = await fetch(`${apiUrl}/threads/${encodeURIComponent(id)}`, {
1039
+ const saveRes = await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(id)}`, historyScope), {
938
1040
  method: "PUT",
939
1041
  headers: { "Content-Type": "application/json" },
940
1042
  body: JSON.stringify({
@@ -962,7 +1064,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
962
1064
  const source = sourceSnapshot && sourceSnapshot.messageCount > 0
963
1065
  ? { ...sourceSnapshot, scope: localScope }
964
1066
  : undefined;
965
- const res = await fetch(`${apiUrl}/threads/${encodeURIComponent(sourceId)}/fork`, {
1067
+ const res = await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(sourceId)}/fork`, historyScope), {
966
1068
  method: "POST",
967
1069
  headers: { "Content-Type": "application/json" },
968
1070
  body: JSON.stringify({ id, ...(source ? { source } : {}) }),
@@ -1003,25 +1105,27 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
1003
1105
  console.error(`[chat] fork threw for ${sourceId}:`, err);
1004
1106
  return null;
1005
1107
  }
1006
- }, [apiUrl]);
1108
+ }, [apiUrl, historyScope]);
1007
1109
  const searchThreads = useCallback(async (query) => {
1008
1110
  try {
1009
1111
  const params = new URLSearchParams({ q: query });
1010
1112
  if (includeExternal)
1011
1113
  params.set("includeExternal", "1");
1114
+ appendChatThreadScopeParams(params, historyScope);
1012
1115
  const res = await fetch(`${apiUrl}/threads?${params.toString()}`);
1013
1116
  if (!res.ok)
1014
1117
  return [];
1015
1118
  const data = await res.json();
1016
- return data.threads ?? [];
1119
+ return (data.threads ?? []).filter((thread) => !isolateHistory ||
1120
+ threadCanStayVisibleInHistory(thread.scope, historyScope, isolateHistory));
1017
1121
  }
1018
1122
  catch {
1019
1123
  return [];
1020
1124
  }
1021
- }, [apiUrl, includeExternal]);
1125
+ }, [apiUrl, historyScope, includeExternal, isolateHistory]);
1022
1126
  const getThreadShareState = useCallback(async (threadId) => {
1023
1127
  try {
1024
- const res = await fetch(`${apiUrl}/threads/${encodeURIComponent(threadId)}/share`);
1128
+ const res = await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(threadId)}/share`, historyScope));
1025
1129
  if (!res.ok)
1026
1130
  return null;
1027
1131
  const data = await res.json();
@@ -1030,10 +1134,10 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
1030
1134
  catch {
1031
1135
  return null;
1032
1136
  }
1033
- }, [apiUrl]);
1137
+ }, [apiUrl, historyScope]);
1034
1138
  const createThreadShareLink = useCallback(async (threadId) => {
1035
1139
  try {
1036
- const res = await fetch(`${apiUrl}/threads/${encodeURIComponent(threadId)}/share`, { method: "POST" });
1140
+ const res = await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(threadId)}/share`, historyScope), { method: "POST" });
1037
1141
  if (!res.ok)
1038
1142
  return null;
1039
1143
  const data = await res.json();
@@ -1044,10 +1148,10 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
1044
1148
  catch {
1045
1149
  return null;
1046
1150
  }
1047
- }, [apiUrl]);
1151
+ }, [apiUrl, historyScope]);
1048
1152
  const revokeThreadShareLink = useCallback(async (threadId) => {
1049
1153
  try {
1050
- const res = await fetch(`${apiUrl}/threads/${encodeURIComponent(threadId)}/share`, { method: "DELETE" });
1154
+ const res = await fetch(withChatThreadScope(`${apiUrl}/threads/${encodeURIComponent(threadId)}/share`, historyScope), { method: "DELETE" });
1051
1155
  if (!res.ok)
1052
1156
  return null;
1053
1157
  const data = await res.json();
@@ -1056,7 +1160,7 @@ export function useChatThreads(apiUrl = agentNativePath("/_agent-native/agent-ch
1056
1160
  catch {
1057
1161
  return null;
1058
1162
  }
1059
- }, [apiUrl]);
1163
+ }, [apiUrl, historyScope]);
1060
1164
  const refreshThreads = useCallback(() => {
1061
1165
  fetchThreads();
1062
1166
  }, [fetchThreads]);
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
62
62
  error: string;
63
63
  states?: undefined;
64
64
  } | {
65
+ error?: undefined;
65
66
  states: {
66
67
  clientId: number;
67
68
  state: string;
68
69
  }[];
69
- error?: undefined;
70
70
  }>>;
71
71
  /**
72
72
  * GET /_agent-native/collab/:docId/users
@@ -77,9 +77,9 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
77
77
  error: string;
78
78
  users?: undefined;
79
79
  } | {
80
+ error?: undefined;
80
81
  users: {
81
82
  clientId: number;
82
83
  lastSeen: number;
83
84
  }[];
84
- error?: undefined;
85
85
  }>>;
@@ -13,8 +13,8 @@
13
13
  * Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
14
14
  */
15
15
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- error: string;
17
16
  ok?: undefined;
17
+ error: string;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -101,6 +101,11 @@ export declare function isDurableBackgroundDeployEnabled(): boolean;
101
101
  export declare const NETLIFY_INTEGRATION_RECOVERY_FUNCTION_NAME = "server-integration-recovery";
102
102
  export declare function isIntegrationDurableDispatchDeployEnabled(): boolean;
103
103
  export declare const NETLIFY_RECURRING_JOBS_FUNCTION_NAME = "agent-native-recurring-jobs";
104
+ /**
105
+ * Routed through the same resolver that produces the runtime marker, so the gate
106
+ * that emits the scheduled function and the value the deployed app reports
107
+ * cannot drift: a build that skips the emit always ships `"disabled"`.
108
+ */
104
109
  export declare function isRecurringJobsDeployEnabled(): boolean;
105
110
  /**
106
111
  * Keep-warm is opt-in because a once-a-minute wake prevents autosuspend on