@agent-native/core 0.98.3 → 0.98.5
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.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +29 -0
- package/corpus/core/docs/content/durable-background-runs.mdx +37 -0
- package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/de-DE/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/es-ES/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +4 -2
- package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/zh-TW/durable-background-runs.mdx +14 -0
- package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +2 -0
- package/corpus/core/docs/content/tracking.mdx +2 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/durable-background.ts +16 -16
- package/corpus/core/src/agent/engine/ai-sdk-engine.ts +25 -8
- package/corpus/core/src/agent/engine/anthropic-engine.ts +17 -3
- package/corpus/core/src/agent/engine/output-tokens.ts +6 -6
- package/corpus/core/src/agent/production-agent.ts +200 -27
- package/corpus/core/src/agent/run-manager.ts +81 -1
- package/corpus/core/src/agent/run-store.ts +301 -41
- package/corpus/core/src/client/AgentPanel.tsx +6 -2
- package/corpus/core/src/client/AssistantChat.tsx +364 -69
- package/corpus/core/src/client/agent-chat-adapter.ts +169 -1
- package/corpus/core/src/client/analytics.ts +12 -0
- package/corpus/core/src/client/chat/message-components.tsx +3 -0
- package/corpus/core/src/client/chat/tool-call-display.tsx +20 -36
- package/corpus/core/src/client/conversation/use-near-bottom-autoscroll.ts +7 -0
- package/corpus/core/src/client/extensions/AgentNativeExtensionFrame.tsx +2 -0
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +2 -0
- package/corpus/core/src/client/extensions/ExtensionEditor.tsx +9 -2
- package/corpus/core/src/client/extensions/ExtensionViewer.tsx +2 -0
- package/corpus/core/src/client/extensions/InlineExtensionFrame.tsx +2 -0
- package/corpus/core/src/client/extensions/portable-extension.ts +2 -0
- package/corpus/core/src/client/session-replay.ts +971 -53
- package/corpus/core/src/client/settings/DemoModeSection.tsx +3 -3
- package/corpus/core/src/client/sse-event-processor.ts +43 -1
- package/corpus/core/src/demo/actions/toggle-demo-mode.ts +2 -2
- package/corpus/core/src/demo/config.ts +6 -6
- package/corpus/core/src/demo/fetch-interceptor.ts +34 -2
- package/corpus/core/src/demo/redact.ts +71 -158
- package/corpus/core/src/extensions/html-shell.ts +3 -0
- package/corpus/core/src/extensions/session-replay-iframe.ts +131 -0
- package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +1 -20
- package/corpus/core/src/session-replay-iframe-protocol.ts +58 -0
- package/corpus/core/src/shared/reasoning-effort.ts +35 -0
- package/corpus/core/src/styles/agent-conversation.css +26 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +67 -16
- package/corpus/templates/analytics/AGENTS.md +12 -0
- package/corpus/templates/analytics/actions/get-error-issue.ts +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-events.ts +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-summary.ts +1 -0
- package/corpus/templates/analytics/actions/list-error-issues.ts +1 -0
- package/corpus/templates/analytics/actions/list-session-recordings.ts +1 -0
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +2 -1
- package/corpus/templates/analytics/app/global.css +6 -64
- package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +41 -4
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +143 -121
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +34 -12
- package/corpus/templates/analytics/changelog/2026-07-12-analytics-chat-retries-before-showing-a-generic-no-data-mess.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-analytics-sessions-search-no-longer-loses-fast-keystrokes-an.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-chart-selection-respects-chat-state.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-demo-mode-anonymizes-error-reporting-emails.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-fixed-session-replays-that-appeared-ultra-wide-hid-recorded-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-session-replays-load-faster-in-demo-mode-while-visitor-email.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-session-replays-show-iframe-content.md +6 -0
- package/corpus/templates/analytics/netlify.toml +0 -3
- package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +14 -0
- package/corpus/templates/analytics/server/lib/error-capture.ts +59 -2
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +24 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +2 -9
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +39 -6
- package/corpus/templates/assets/app/global.css +1 -1
- package/corpus/templates/brain/app/global.css +2 -2
- package/corpus/templates/brain/changelog/2026-07-12-fix-long-response-progress.md +6 -0
- package/corpus/templates/calendar/app/components/calendar/DeleteEventDialog.tsx +11 -2
- package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +14 -2
- package/corpus/templates/calendar/changelog/2026-07-12-calendar-responses-can-now-be-saved-with-command-enter-or-ct.md +6 -0
- package/corpus/templates/forms/app/components/CloudUpgrade.tsx +1 -1
- package/corpus/templates/forms/app/components/ThemeToggle.tsx +22 -6
- package/corpus/templates/forms/app/components/builder/FieldPropertiesPanel.tsx +5 -5
- package/corpus/templates/forms/app/components/builder/FieldRenderer.tsx +3 -3
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +16 -16
- package/corpus/templates/forms/app/global.css +110 -5
- package/corpus/templates/forms/app/pages/AskPage.tsx +3 -3
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +134 -52
- package/corpus/templates/forms/app/pages/FormFillPage.tsx +44 -11
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +42 -24
- package/corpus/templates/forms/app/pages/ResponseInsightsPage.tsx +28 -15
- package/corpus/templates/forms/app/pages/ResponsesPage.tsx +38 -15
- package/corpus/templates/forms/app/routes/_app.settings.tsx +1 -1
- package/corpus/templates/forms/changelog/2026-07-12-form-builder-surfaces-are-calmer-fields-stay-stable-on-hover.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-12-smoother-more-tactile-controls-throughout-animated-icon-and-.md +6 -0
- package/corpus/templates/mail/app/components/email/EmailThread.tsx +21 -13
- package/corpus/templates/mail/app/components/email/email-iframe-document.ts +18 -0
- package/dist/agent/durable-background.d.ts +10 -10
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +16 -16
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
- package/dist/agent/engine/ai-sdk-engine.js +19 -8
- package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
- package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
- package/dist/agent/engine/anthropic-engine.js +11 -3
- package/dist/agent/engine/anthropic-engine.js.map +1 -1
- package/dist/agent/engine/output-tokens.js +6 -6
- package/dist/agent/engine/output-tokens.js.map +1 -1
- package/dist/agent/production-agent.d.ts +52 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +154 -26
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +9 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +71 -1
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +9 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +243 -48
- package/dist/agent/run-store.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +6 -2
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +21 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +298 -67
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +146 -1
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +11 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +2 -1
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +3 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +13 -37
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/conversation/use-near-bottom-autoscroll.d.ts +1 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.d.ts.map +1 -1
- package/dist/client/conversation/use-near-bottom-autoscroll.js +6 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.js.map +1 -1
- package/dist/client/extensions/AgentNativeExtensionFrame.d.ts.map +1 -1
- package/dist/client/extensions/AgentNativeExtensionFrame.js +2 -1
- package/dist/client/extensions/AgentNativeExtensionFrame.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +2 -1
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionEditor.js +5 -2
- package/dist/client/extensions/ExtensionEditor.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +2 -1
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/InlineExtensionFrame.d.ts.map +1 -1
- package/dist/client/extensions/InlineExtensionFrame.js +2 -1
- package/dist/client/extensions/InlineExtensionFrame.js.map +1 -1
- package/dist/client/extensions/portable-extension.d.ts.map +1 -1
- package/dist/client/extensions/portable-extension.js +2 -0
- package/dist/client/extensions/portable-extension.js.map +1 -1
- package/dist/client/session-replay.d.ts +12 -3
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +793 -49
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/DemoModeSection.js +1 -1
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +5 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +37 -1
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/demo/actions/toggle-demo-mode.js +2 -2
- package/dist/demo/actions/toggle-demo-mode.js.map +1 -1
- package/dist/demo/config.js +6 -6
- package/dist/demo/config.js.map +1 -1
- package/dist/demo/fetch-interceptor.d.ts +1 -0
- package/dist/demo/fetch-interceptor.d.ts.map +1 -1
- package/dist/demo/fetch-interceptor.js +28 -2
- package/dist/demo/fetch-interceptor.js.map +1 -1
- package/dist/demo/redact.d.ts +14 -7
- package/dist/demo/redact.d.ts.map +1 -1
- package/dist/demo/redact.js +27 -155
- package/dist/demo/redact.js.map +1 -1
- package/dist/extensions/html-shell.d.ts.map +1 -1
- package/dist/extensions/html-shell.js +2 -0
- package/dist/extensions/html-shell.js.map +1 -1
- package/dist/extensions/session-replay-iframe.d.ts +10 -0
- package/dist/extensions/session-replay-iframe.d.ts.map +1 -0
- package/dist/extensions/session-replay-iframe.js +121 -0
- package/dist/extensions/session-replay-iframe.js.map +1 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +1 -19
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/session-replay-iframe-protocol.d.ts +36 -0
- package/dist/session-replay-iframe-protocol.d.ts.map +1 -0
- package/dist/session-replay-iframe-protocol.js +24 -0
- package/dist/session-replay-iframe-protocol.js.map +1 -0
- package/dist/shared/reasoning-effort.d.ts +11 -0
- package/dist/shared/reasoning-effort.d.ts.map +1 -1
- package/dist/shared/reasoning-effort.js +36 -0
- package/dist/shared/reasoning-effort.js.map +1 -1
- package/dist/styles/agent-conversation.css +26 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
- package/docs/content/durable-background-runs.mdx +37 -0
- package/docs/content/locales/ar-SA/tracking.mdx +2 -0
- package/docs/content/locales/de-DE/tracking.mdx +2 -0
- package/docs/content/locales/es-ES/tracking.mdx +2 -0
- package/docs/content/locales/fr-FR/tracking.mdx +4 -2
- package/docs/content/locales/hi-IN/tracking.mdx +2 -0
- package/docs/content/locales/ja-JP/tracking.mdx +2 -0
- package/docs/content/locales/ko-KR/tracking.mdx +2 -0
- package/docs/content/locales/pt-BR/tracking.mdx +2 -0
- package/docs/content/locales/zh-CN/tracking.mdx +2 -0
- package/docs/content/locales/zh-TW/durable-background-runs.mdx +14 -0
- package/docs/content/locales/zh-TW/tracking.mdx +2 -0
- package/docs/content/tracking.mdx +2 -0
- package/package.json +2 -2
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
- package/corpus/core/src/observability/hosted-model-experiment.ts +0 -118
- package/dist/observability/hosted-model-experiment.d.ts +0 -39
- package/dist/observability/hosted-model-experiment.d.ts.map +0 -1
- package/dist/observability/hosted-model-experiment.js +0 -90
- package/dist/observability/hosted-model-experiment.js.map +0 -1
|
@@ -15,8 +15,6 @@ import {
|
|
|
15
15
|
normalizeModelForEngine,
|
|
16
16
|
} from "../../agent/engine/index.js";
|
|
17
17
|
import type { ActionTool } from "../../agent/types.js";
|
|
18
|
-
import { resolveHostedDefaultModelExperiment } from "../../observability/hosted-model-experiment.js";
|
|
19
|
-
import { getRequestUserEmail } from "../../server/request-context.js";
|
|
20
18
|
import { getSetting } from "../../settings/index.js";
|
|
21
19
|
|
|
22
20
|
export const tool: ActionTool = {
|
|
@@ -84,24 +82,13 @@ export async function run(args: Record<string, string> = {}): Promise<string> {
|
|
|
84
82
|
? current?.model
|
|
85
83
|
: undefined;
|
|
86
84
|
const currentEngineName = currentEntry?.name ?? "anthropic";
|
|
87
|
-
|
|
85
|
+
const currentModel =
|
|
88
86
|
currentEntry && !envUnavailable
|
|
89
87
|
? normalizeModelForEngine(
|
|
90
88
|
currentEntry,
|
|
91
89
|
currentModelCandidate ?? currentEntry.defaultModel,
|
|
92
90
|
)
|
|
93
91
|
: (currentModelCandidate ?? DEFAULT_MODEL);
|
|
94
|
-
const hostedExperiment =
|
|
95
|
-
currentEntry && !currentModelCandidate
|
|
96
|
-
? resolveHostedDefaultModelExperiment({
|
|
97
|
-
userId: getRequestUserEmail(),
|
|
98
|
-
engineName: currentEntry.name,
|
|
99
|
-
isDefaultModelSelection: true,
|
|
100
|
-
supportedModels: currentEntry.supportedModels,
|
|
101
|
-
})
|
|
102
|
-
: null;
|
|
103
|
-
if (hostedExperiment) currentModel = hostedExperiment.model;
|
|
104
|
-
|
|
105
92
|
const result = {
|
|
106
93
|
engines: engines.map((e) => ({
|
|
107
94
|
name: e.name,
|
|
@@ -119,12 +106,6 @@ export async function run(args: Record<string, string> = {}): Promise<string> {
|
|
|
119
106
|
: {
|
|
120
107
|
engine: currentEngineName,
|
|
121
108
|
model: currentModel,
|
|
122
|
-
...(hostedExperiment
|
|
123
|
-
? {
|
|
124
|
-
modelSelectionSource: "experiment",
|
|
125
|
-
experimentAssignment: hostedExperiment.assignment,
|
|
126
|
-
}
|
|
127
|
-
: {}),
|
|
128
109
|
},
|
|
129
110
|
};
|
|
130
111
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export const SESSION_REPLAY_IFRAME_ATTRIBUTE =
|
|
2
|
+
"data-agent-native-session-replay";
|
|
3
|
+
export const SESSION_REPLAY_IFRAME_PROBE = "agent-native-session-replay:probe";
|
|
4
|
+
export const SESSION_REPLAY_IFRAME_START = "agent-native-session-replay:start";
|
|
5
|
+
export const SESSION_REPLAY_IFRAME_STOP = "agent-native-session-replay:stop";
|
|
6
|
+
|
|
7
|
+
export interface SessionReplayIframePrivacyOptions {
|
|
8
|
+
blockSelector: string;
|
|
9
|
+
ignoreSelector: string;
|
|
10
|
+
maskTextClass?: string | RegExp;
|
|
11
|
+
maskTextSelector: string;
|
|
12
|
+
maskAllInputs: boolean;
|
|
13
|
+
maskInputOptions?: Record<string, boolean>;
|
|
14
|
+
recordCanvas: boolean;
|
|
15
|
+
collectFonts: boolean;
|
|
16
|
+
inlineImages: boolean;
|
|
17
|
+
sampling: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SessionReplayIframeProbeMessage {
|
|
21
|
+
type: typeof SESSION_REPLAY_IFRAME_PROBE;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SessionReplayIframeStartMessage {
|
|
25
|
+
type: typeof SESSION_REPLAY_IFRAME_START;
|
|
26
|
+
options: SessionReplayIframePrivacyOptions;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface SessionReplayIframeStopMessage {
|
|
30
|
+
type: typeof SESSION_REPLAY_IFRAME_STOP;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type SessionReplayIframeMessage =
|
|
34
|
+
| SessionReplayIframeProbeMessage
|
|
35
|
+
| SessionReplayIframeStartMessage
|
|
36
|
+
| SessionReplayIframeStopMessage;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* `srcdoc` HTML came from the immediate parent, so that parent already owns the
|
|
40
|
+
* document being rendered. Server-rendered extension URLs are stricter: only a
|
|
41
|
+
* parent on the render URL's origin may activate recording. That supports
|
|
42
|
+
* custom app domains without allowing an external embed host to make an opaque
|
|
43
|
+
* extension frame disclose its DOM through rrweb's postMessage transport.
|
|
44
|
+
*/
|
|
45
|
+
export function isTrustedSessionReplayIframeParentOrigin(
|
|
46
|
+
parentOrigin: string,
|
|
47
|
+
frameHref: string,
|
|
48
|
+
): boolean {
|
|
49
|
+
if (frameHref === "about:srcdoc") {
|
|
50
|
+
return parentOrigin !== "null" && parentOrigin !== "";
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const frameOrigin = new URL(frameHref).origin;
|
|
54
|
+
return frameOrigin !== "null" && parentOrigin === frameOrigin;
|
|
55
|
+
} catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -170,6 +170,41 @@ function isClaudeReasoningModel(model: string) {
|
|
|
170
170
|
return opusMatch ? parseInt(opusMatch[1], 10) >= 6 : false;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Anthropic's adaptive-thinking API is only available on the newer Claude
|
|
175
|
+
* model families. Claude Haiku 4.5 is reasoning-capable, but it still
|
|
176
|
+
* requires the legacy manual `budget_tokens` configuration.
|
|
177
|
+
*/
|
|
178
|
+
export function supportsClaudeAdaptiveThinking(model: string | undefined) {
|
|
179
|
+
if (!model) return false;
|
|
180
|
+
const id = model.toLowerCase().replace(/^anthropic\//, "");
|
|
181
|
+
if (id.includes("fable-5") || id.includes("mythos-5")) return true;
|
|
182
|
+
if (id.includes("sonnet-5") || id.includes("sonnet-4-6")) return true;
|
|
183
|
+
const opusMatch = id.match(/opus-4[-.](\d+)/);
|
|
184
|
+
return opusMatch ? parseInt(opusMatch[1], 10) >= 6 : false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Map the shared reasoning ladder to Anthropic's manual thinking budgets for
|
|
189
|
+
* models that do not support adaptive thinking (currently Claude Haiku 4.5).
|
|
190
|
+
*/
|
|
191
|
+
export function anthropicManualThinkingBudget(effort: ReasoningEffort) {
|
|
192
|
+
switch (effort) {
|
|
193
|
+
case "low":
|
|
194
|
+
return 1_024;
|
|
195
|
+
case "medium":
|
|
196
|
+
return 4_096;
|
|
197
|
+
case "high":
|
|
198
|
+
return 8_000;
|
|
199
|
+
case "xhigh":
|
|
200
|
+
return 16_000;
|
|
201
|
+
case "max":
|
|
202
|
+
return 32_000;
|
|
203
|
+
default:
|
|
204
|
+
return 4_096;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
173
208
|
function supportsClaudeXHigh(model: string) {
|
|
174
209
|
const id = model.toLowerCase().replace(/^anthropic\//, "");
|
|
175
210
|
// Models that support the xhigh effort tier (built-in extended thinking via
|
|
@@ -493,6 +493,32 @@
|
|
|
493
493
|
-webkit-mask-image: linear-gradient(to bottom, transparent, black 1.5rem);
|
|
494
494
|
}
|
|
495
495
|
|
|
496
|
+
.agent-chat-collapse {
|
|
497
|
+
display: grid;
|
|
498
|
+
grid-template-rows: 1fr;
|
|
499
|
+
opacity: 1;
|
|
500
|
+
transition:
|
|
501
|
+
grid-template-rows 200ms var(--ease-collapse),
|
|
502
|
+
opacity 150ms ease-out;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.agent-chat-collapse[data-state="closed"] {
|
|
506
|
+
grid-template-rows: 0fr;
|
|
507
|
+
opacity: 0;
|
|
508
|
+
pointer-events: none;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.agent-chat-collapse__content {
|
|
512
|
+
min-height: 0;
|
|
513
|
+
overflow: hidden;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
@media (prefers-reduced-motion: reduce) {
|
|
517
|
+
.agent-chat-collapse {
|
|
518
|
+
transition-duration: 0.01ms;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
496
522
|
/* ─── Agent-Markdown (AssistantChat react-markdown render surface) ─────────── */
|
|
497
523
|
/* These classes are applied by the SmoothMarkdownText/MarkdownText components */
|
|
498
524
|
/* in the AssistantChat/AssistantChatInner tree. The shiki dual-theme rules */
|
|
@@ -158,21 +158,6 @@ The agent loop reads active experiments via `resolveActiveExperimentConfig()` an
|
|
|
158
158
|
|
|
159
159
|
Compute results with `POST /_agent-native/observability/experiments/:id/results`.
|
|
160
160
|
|
|
161
|
-
#### First-party hosted default-model rollout
|
|
162
|
-
|
|
163
|
-
First-party apps on `agent-native.com` automatically run the July 2026
|
|
164
|
-
default-model experiment for authenticated users on the Builder engine:
|
|
165
|
-
|
|
166
|
-
- 80% `claude-sonnet-5`
|
|
167
|
-
- 20% `gpt-5-6-luna`
|
|
168
|
-
- Assignment is sticky by normalized user email and shared across templates.
|
|
169
|
-
- The rollout applies only when the user, app, and deployment have not selected
|
|
170
|
-
a model. Explicit model choices and BYO provider engines always win.
|
|
171
|
-
- Set `AGENT_NATIVE_HOSTED_MODEL_EXPERIMENT=off` for an emergency rollback, or
|
|
172
|
-
`true` to exercise the rollout on a non-first-party preview.
|
|
173
|
-
- `$ai_generation` tracking includes `experiment_id`,
|
|
174
|
-
`experiment_variant`, and `model_selection_source` for central analysis.
|
|
175
|
-
|
|
176
161
|
In production, experiment management routes require the caller's email in the
|
|
177
162
|
comma-separated `AGENT_NATIVE_EXPERIMENT_ADMIN_EMAILS` allowlist. This gate is
|
|
178
163
|
separate from normal app/org admin roles because an experiment affects every
|
|
@@ -102,9 +102,9 @@ agent answers about browser recordings in the Analytics template.
|
|
|
102
102
|
- Wait for all replay chunks (`isComplete`) before constructing the rrweb
|
|
103
103
|
`Replayer`. Progressive chunk publishes should only update the loading bar;
|
|
104
104
|
rebuilding the player mid-load desyncs the scrubber and playhead.
|
|
105
|
-
- Pass events to `Replayer` untouched. rrweb rebuilds them in a sandboxed
|
|
106
|
-
pre-processing DOM, stylesheet, resource, or mutation payloads makes
|
|
107
|
-
diverge from the captured page. In particular, never rewrite `href`, `src`,
|
|
105
|
+
- Pass normal events to `Replayer` untouched. rrweb rebuilds them in a sandboxed
|
|
106
|
+
iframe; pre-processing DOM, stylesheet, resource, or mutation payloads makes
|
|
107
|
+
playback diverge from the captured page. In particular, never rewrite `href`, `src`,
|
|
108
108
|
`_cssText`, CSS `url()`, or Meta URLs to `about:blank`; that exact remediation
|
|
109
109
|
broke historical replay CSS in PR #2040. Handle request privacy at capture or
|
|
110
110
|
the sandbox boundary instead of mutating stored rrweb events. Historical
|
|
@@ -112,19 +112,59 @@ agent answers about browser recordings in the Analytics template.
|
|
|
112
112
|
requests for accurate rendering; the viewer accepts that fidelity tradeoff,
|
|
113
113
|
uses rrweb's script-disabled sandbox plus `referrerpolicy="no-referrer"`, and
|
|
114
114
|
must never add credentials or proxy those URLs through a privileged server.
|
|
115
|
-
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
115
|
+
- Capture-time URL scrubbing must preserve load-bearing DOM resource attributes:
|
|
116
|
+
`src`, `srcset`, `poster`, `data`, and `href` only on resource links such as
|
|
117
|
+
stylesheets, preloads, and icons. Signed CDN query parameters are part of the
|
|
118
|
+
resource identity; redacting them produces missing CSS, fonts, images, and
|
|
119
|
+
oversized fallback icons. Keep scrubbing Meta/navigation URLs, anchor hrefs,
|
|
120
|
+
and console/network diagnostics. Captured `_cssText` and CSS `@import`/`url()`
|
|
121
|
+
values must remain byte-identical.
|
|
122
|
+
- rrweb rebuilds into an `about:srcdoc` iframe, which inherits the Analytics
|
|
123
|
+
document's CSP. Analytics currently sends no CSP header; if a future change
|
|
124
|
+
adds restrictive `style-src`, `font-src`, or `img-src` directives, verify
|
|
125
|
+
historical replays and resolve external imports/fonts at capture before
|
|
126
|
+
blocking the recorded resource origins. Do not diagnose current font loss as
|
|
127
|
+
CSP without checking the deployed response headers first.
|
|
128
|
+
- Let rrweb own iframe sizing entirely via Meta / ViewportResize, and keep the
|
|
129
|
+
outer wrapper on the exact same raw dimensions for fit-to-stage scaling.
|
|
130
|
+
Player geometry and pointer coordinates are fully stock and untouched — do
|
|
131
|
+
not add width/aspect-ratio "recovery" heuristics or pointer-coordinate
|
|
132
|
+
projection. There is no such thing as a stored recording with corrupt
|
|
133
|
+
viewport geometry: a census of all production recordings found zero stored
|
|
134
|
+
widths >= 3,000px. The 2026-07 "ultra-wide replay" bugs (stages rendered
|
|
135
|
+
3,000–9,500px wide, frozen/teleporting cursors, giant icons) were caused
|
|
136
|
+
entirely by demo mode's fetch interceptor: its number redactor faked any
|
|
137
|
+
integer >= 1000 inside raw replay JSON at *view* time, corrupting Meta /
|
|
138
|
+
ViewportResize widths, pointer x/y coordinates, and numeric values inside
|
|
139
|
+
`_cssText` and SVG attributes before rrweb ever saw the payload (heights
|
|
140
|
+
below 1000 stayed real, which is why the symptom looked like a viewport
|
|
141
|
+
problem rather than a redaction bug — two different sessions that both
|
|
142
|
+
stored a 1,152px width read back as the same 4,491px, a deterministic
|
|
143
|
+
salted-hash fingerprint of the redactor, not two coincidentally identical
|
|
144
|
+
malformed recordings). This is fixed in
|
|
145
|
+
`packages/core/src/demo/fetch-interceptor.ts`: raw replay payload and
|
|
146
|
+
manifest URLs are skipped from demo number redaction entirely, and must
|
|
147
|
+
never be routed through it again. Do not reintroduce viewport clamping or
|
|
148
|
+
pointer-coordinate projection in the player — they can now only corrupt
|
|
149
|
+
genuine future recordings (for example, a real 3440x900 ultrawide browser
|
|
150
|
+
window, or a short vertical window under 1,000px tall).
|
|
151
|
+
- Keep rrweb's stock cursor stylesheet and its hotspot transform. During
|
|
152
|
+
playback, hide the viewer's native pointer over Analytics' transparent
|
|
153
|
+
click-to-pause overlay so it cannot masquerade as a frozen recorded cursor.
|
|
154
|
+
- Keep rrweb's recorded focus handling enabled. Focus and focus-visible state
|
|
155
|
+
affect menus, forms, and keyboard UX; disabling `triggerFocus` makes a valid
|
|
156
|
+
snapshot diverge from the source page.
|
|
157
|
+
- `insertStyleRules` may suppress known toast/snackbar containers only. Never
|
|
158
|
+
hide generic framework primitives such as
|
|
159
|
+
`[data-radix-popper-content-wrapper]`: Radix dropdowns, selects, tooltips,
|
|
160
|
+
and other real recorded product UI all share that wrapper.
|
|
161
|
+
- Keep the realistic-fidelity purity/pass-through tests in
|
|
162
|
+
`SessionDetailPage.spec.ts` — raw event identity, raw viewport dimensions,
|
|
163
|
+
and raw resize-state derivation (including the 3,189x885 tripwire against
|
|
164
|
+
reintroducing a clamp) — as regression guards against reintroducing any
|
|
165
|
+
viewport "recovery" or pointer-projection heuristic. Do not change their
|
|
166
|
+
expectations merely to bless a new sanitizer or clamp; validate the affected
|
|
167
|
+
replay in a browser first.
|
|
128
168
|
- The event timeline soft-highlights the active marker, auto-scrolls it into
|
|
129
169
|
view (pausing briefly after manual scroll), and supports search. It appears
|
|
130
170
|
beside the player from ~880px content width upward.
|
|
@@ -161,3 +201,14 @@ agent answers about browser recordings in the Analytics template.
|
|
|
161
201
|
`.an-mask` or `data-an-mask`.
|
|
162
202
|
- Use `.an-block`, `.an-ignore`, `data-an-block`, or `data-an-ignore` for
|
|
163
203
|
sensitive zones that should not be captured.
|
|
204
|
+
- A definitive upload `409` abandons only the conflicted replay identity and
|
|
205
|
+
immediately starts rrweb again under a fresh per-tab id, producing a new
|
|
206
|
+
Meta + FullSnapshot for long-lived SPA tabs. Recovery is limited to one
|
|
207
|
+
restart until an upload succeeds so a misconfigured endpoint cannot loop;
|
|
208
|
+
Analytics tracks the content-free `session replay upload rejected` lifecycle
|
|
209
|
+
event so conflicts and recovery success are measurable.
|
|
210
|
+
- Do not label an old recording "corrupt" from pointer coordinates, unknown
|
|
211
|
+
mutation node ids, or changing Meta geometry alone. Those shapes can be
|
|
212
|
+
legitimate with scrolling, iframes/shadow DOM, navigation, and resize. A
|
|
213
|
+
historical-artifact notice needs a durable capture/ingest marker or another
|
|
214
|
+
low-false-positive invariant; do not guess from playback heuristics.
|
|
@@ -106,6 +106,18 @@ details live in `.agents/skills/`.
|
|
|
106
106
|
/ `$ai_latency`, `status`, `tool_calls`, `successful_tools`, `failed_tools`,
|
|
107
107
|
and `$ai_error` / `error_message`. Do not expect prompts, tool args, or model
|
|
108
108
|
responses in these tracked events by default.
|
|
109
|
+
- External MCP callers should use `ask_app` as the default for multi-step
|
|
110
|
+
Analytics work. It can resolve a person's known email, correlate sessions
|
|
111
|
+
with captured errors, mint a temporary replay-context link, and inspect the
|
|
112
|
+
timeline, page navigation, console diagnostics, failed network requests, and
|
|
113
|
+
clicks when needed. The authenticated connector catalog is the fast fallback
|
|
114
|
+
and exposes only bounded, user/org-scoped read actions for incident triage:
|
|
115
|
+
`list-session-recordings`, `get-session-replay-summary`,
|
|
116
|
+
`get-session-replay-events`, `query-agent-native-analytics`,
|
|
117
|
+
`list-error-issues`, and `get-error-issue`. Fetch the summary before raw
|
|
118
|
+
events, use the event filters/limits to keep the response bounded, and do not
|
|
119
|
+
add replay blob or dashboard mutation actions to this catalog without an
|
|
120
|
+
explicit security review.
|
|
109
121
|
- `/agents` is the Analytics home for admin surfaces. The default Monitoring
|
|
110
122
|
view embeds the shared observability dashboard for traces, conversations,
|
|
111
123
|
evals, experiments, and feedback. `/agents?view=dashboards` shows the
|
|
@@ -28,6 +28,7 @@ export default defineAction({
|
|
|
28
28
|
}),
|
|
29
29
|
http: { method: "GET" },
|
|
30
30
|
readOnly: true,
|
|
31
|
+
publicAgent: { expose: true, readOnly: true, requiresAuth: true },
|
|
31
32
|
run: async (args) => {
|
|
32
33
|
return getErrorIssue(resolveScope(), args.id, {
|
|
33
34
|
eventsLimit: args.eventsLimit,
|
|
@@ -40,6 +40,7 @@ export default defineAction({
|
|
|
40
40
|
}),
|
|
41
41
|
http: { method: "GET" },
|
|
42
42
|
readOnly: true,
|
|
43
|
+
publicAgent: { expose: true, readOnly: true, requiresAuth: true },
|
|
43
44
|
run: async (args) => {
|
|
44
45
|
return getSessionReplayEvents(args.recordingId, resolveScope(), {
|
|
45
46
|
startSeq: args.startSeq,
|
|
@@ -33,7 +33,8 @@ export default defineAction({
|
|
|
33
33
|
),
|
|
34
34
|
}),
|
|
35
35
|
readOnly: true,
|
|
36
|
-
http:
|
|
36
|
+
http: { method: "GET" },
|
|
37
|
+
publicAgent: { expose: true, readOnly: true, requiresAuth: true },
|
|
37
38
|
run: async (args) => {
|
|
38
39
|
return queryFirstPartyAnalytics(args.sql, resolveScope());
|
|
39
40
|
},
|
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
.analytics-chat-intro {
|
|
187
187
|
display: grid;
|
|
188
188
|
width: 100%;
|
|
189
|
-
max-width: min(
|
|
189
|
+
max-width: min(684px, 90%);
|
|
190
190
|
gap: 0.5rem;
|
|
191
191
|
margin: 0 auto 1rem;
|
|
192
192
|
text-align: center;
|
|
@@ -223,7 +223,7 @@
|
|
|
223
223
|
[data-agent-empty-state="centered"]
|
|
224
224
|
.agent-plan-mode-callout {
|
|
225
225
|
width: 100%;
|
|
226
|
-
max-width: min(
|
|
226
|
+
max-width: min(684px, 90%);
|
|
227
227
|
padding: 0;
|
|
228
228
|
}
|
|
229
229
|
|
|
@@ -245,72 +245,14 @@
|
|
|
245
245
|
transform-origin: top left;
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
/*
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
inside `.replayer-wrapper`, so it scales with the fit-to-stage transform. */
|
|
253
|
-
.an-replay-stage-root .replayer-mouse {
|
|
254
|
-
position: absolute;
|
|
255
|
-
z-index: 2;
|
|
256
|
-
width: 1.125rem;
|
|
257
|
-
height: 1.5rem;
|
|
258
|
-
border-radius: 0;
|
|
259
|
-
background: transparent;
|
|
260
|
-
background-image: none;
|
|
261
|
-
box-shadow: none;
|
|
262
|
-
transform: none;
|
|
263
|
-
transition:
|
|
264
|
-
left 80ms linear,
|
|
265
|
-
top 80ms linear;
|
|
266
|
-
pointer-events: none;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
.an-replay-stage-root .replayer-mouse::before {
|
|
270
|
-
content: "";
|
|
271
|
-
position: absolute;
|
|
272
|
-
inset: 0;
|
|
273
|
-
background: hsl(0 0% 100%);
|
|
274
|
-
clip-path: polygon(0 0, 0 77%, 30% 57%, 48% 100%, 68% 92%, 50% 51%, 92% 51%);
|
|
275
|
-
filter: drop-shadow(0 0 1px hsl(0 0% 0% / 0.95))
|
|
276
|
-
drop-shadow(0 1px 3px hsl(0 0% 0% / 0.35));
|
|
277
|
-
}
|
|
278
|
-
|
|
248
|
+
/* IMPORTANT: Keep rrweb's stock SVG arrow. Only suppress its permanently
|
|
249
|
+
visible purple ::after disc, which can otherwise read as the cursor itself
|
|
250
|
+
when the arrow is small. The stock .active animation still supplies the
|
|
251
|
+
brief click halo. Do not replace the arrow with an app-colored dot. */
|
|
279
252
|
.an-replay-stage-root .replayer-mouse::after {
|
|
280
|
-
content: "";
|
|
281
|
-
position: absolute;
|
|
282
|
-
left: -0.5rem;
|
|
283
|
-
top: -0.5rem;
|
|
284
|
-
width: 1rem;
|
|
285
|
-
height: 1rem;
|
|
286
|
-
border-radius: 9999px;
|
|
287
|
-
border: 2px solid hsl(217 91% 60%);
|
|
288
|
-
background: transparent;
|
|
289
253
|
opacity: 0;
|
|
290
254
|
}
|
|
291
255
|
|
|
292
|
-
/* rrweb toggles `.active` on mouse interactions; pulse a click ripple. */
|
|
293
|
-
.an-replay-stage-root .replayer-mouse.active::after {
|
|
294
|
-
animation: an-replay-mouse-click 0.4s ease-out 1;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
@keyframes an-replay-mouse-click {
|
|
298
|
-
0% {
|
|
299
|
-
opacity: 0.5;
|
|
300
|
-
transform: scale(1);
|
|
301
|
-
}
|
|
302
|
-
100% {
|
|
303
|
-
opacity: 0;
|
|
304
|
-
transform: scale(3.5);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
.an-replay-stage-root .replayer-mouse-tail {
|
|
309
|
-
position: absolute;
|
|
310
|
-
inset: 0;
|
|
311
|
-
pointer-events: none;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
256
|
.analytics-session-snippet .plan-code-surface {
|
|
315
257
|
border: 0;
|
|
316
258
|
border-radius: 0;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
+
SIDEBAR_STATE_CHANGE_EVENT,
|
|
2
3
|
deleteClientAppState,
|
|
3
4
|
readClientAppState,
|
|
4
5
|
removeAgentChatContextItem,
|
|
5
6
|
setAgentChatContextItem,
|
|
6
7
|
setClientAppState,
|
|
8
|
+
type AgentSidebarStateChangeDetail,
|
|
7
9
|
useAgentChatContext,
|
|
8
10
|
} from "@agent-native/core/client";
|
|
9
|
-
import { useCallback, useEffect } from "react";
|
|
11
|
+
import { useCallback, useEffect, useState } from "react";
|
|
10
12
|
|
|
11
13
|
import { TAB_ID } from "@/lib/tab-id";
|
|
12
14
|
|
|
@@ -120,10 +122,22 @@ function parsePanelSelection(
|
|
|
120
122
|
}
|
|
121
123
|
}
|
|
122
124
|
|
|
125
|
+
function isAgentSidebarOpenInDocument(): boolean {
|
|
126
|
+
if (typeof document === "undefined") return false;
|
|
127
|
+
return Boolean(
|
|
128
|
+
document.querySelector(
|
|
129
|
+
'.agent-sidebar-panel[data-agent-sidebar-state="open"]',
|
|
130
|
+
),
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
123
134
|
export function useDashboardChatContext(
|
|
124
135
|
args: DashboardChatContextArgs,
|
|
125
136
|
): DashboardChatContextResult {
|
|
126
137
|
const { id, kind, title, panelCount, canEdit } = args;
|
|
138
|
+
const [isAgentSidebarOpen, setIsAgentSidebarOpen] = useState(
|
|
139
|
+
isAgentSidebarOpenInDocument,
|
|
140
|
+
);
|
|
127
141
|
const { items } = useAgentChatContext();
|
|
128
142
|
const panelContext = items.find(
|
|
129
143
|
(item) => item.key === DASHBOARD_PANEL_CONTEXT_KEY,
|
|
@@ -132,7 +146,9 @@ export function useDashboardChatContext(
|
|
|
132
146
|
? parsePanelSelection(panelContext.context)
|
|
133
147
|
: null;
|
|
134
148
|
const selectedPanelId =
|
|
135
|
-
id && panelSelection?.dashboardId === id
|
|
149
|
+
isAgentSidebarOpen && id && panelSelection?.dashboardId === id
|
|
150
|
+
? panelSelection.panelId
|
|
151
|
+
: null;
|
|
136
152
|
const hasSelectedPanel = selectedPanelId !== null;
|
|
137
153
|
|
|
138
154
|
const selectPanelForChat = useCallback(
|
|
@@ -141,6 +157,7 @@ export function useDashboardChatContext(
|
|
|
141
157
|
options: SelectDashboardPanelOptions = {},
|
|
142
158
|
) => {
|
|
143
159
|
if (!id) return;
|
|
160
|
+
if (options.openSidebar !== true && !isAgentSidebarOpen) return;
|
|
144
161
|
const displayDashboardTitle = title?.trim() || id;
|
|
145
162
|
const displayPanelTitle = panel.panelTitle.trim() || panel.panelId;
|
|
146
163
|
const contextLines = [
|
|
@@ -166,7 +183,7 @@ export function useDashboardChatContext(
|
|
|
166
183
|
key: DASHBOARD_PANEL_CONTEXT_KEY,
|
|
167
184
|
title: displayPanelTitle,
|
|
168
185
|
context: contextLines.join("\n"),
|
|
169
|
-
openSidebar: options.openSidebar
|
|
186
|
+
openSidebar: options.openSidebar === true,
|
|
170
187
|
focus: options.focus ?? false,
|
|
171
188
|
});
|
|
172
189
|
setClientAppState(
|
|
@@ -191,9 +208,29 @@ export function useDashboardChatContext(
|
|
|
191
208
|
},
|
|
192
209
|
).catch(() => {});
|
|
193
210
|
},
|
|
194
|
-
[id, kind, title],
|
|
211
|
+
[id, isAgentSidebarOpen, kind, title],
|
|
195
212
|
);
|
|
196
213
|
|
|
214
|
+
useEffect(() => {
|
|
215
|
+
const handleSidebarStateChange = (event: Event) => {
|
|
216
|
+
const detail = (event as CustomEvent<AgentSidebarStateChangeDetail>)
|
|
217
|
+
.detail;
|
|
218
|
+
if (typeof detail?.open === "boolean") {
|
|
219
|
+
setIsAgentSidebarOpen(detail.open);
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
window.addEventListener(
|
|
224
|
+
SIDEBAR_STATE_CHANGE_EVENT,
|
|
225
|
+
handleSidebarStateChange,
|
|
226
|
+
);
|
|
227
|
+
return () =>
|
|
228
|
+
window.removeEventListener(
|
|
229
|
+
SIDEBAR_STATE_CHANGE_EVENT,
|
|
230
|
+
handleSidebarStateChange,
|
|
231
|
+
);
|
|
232
|
+
}, []);
|
|
233
|
+
|
|
197
234
|
useEffect(() => {
|
|
198
235
|
if (!id) return;
|
|
199
236
|
const displayTitle = title?.trim() || id;
|