@agent-native/core 0.98.4 → 0.98.6
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 +28 -0
- package/corpus/core/docs/content/durable-background-runs.mdx +37 -0
- package/corpus/core/docs/content/external-agents.mdx +62 -7
- package/corpus/core/docs/content/locales/ar-SA/external-agents.mdx +38 -7
- package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/de-DE/external-agents.mdx +39 -7
- package/corpus/core/docs/content/locales/de-DE/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/es-ES/external-agents.mdx +39 -7
- package/corpus/core/docs/content/locales/es-ES/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/fr-FR/external-agents.mdx +39 -7
- package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +4 -2
- package/corpus/core/docs/content/locales/hi-IN/external-agents.mdx +38 -7
- package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/ja-JP/external-agents.mdx +38 -7
- package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/ko-KR/external-agents.mdx +38 -7
- package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/pt-BR/external-agents.mdx +39 -7
- package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +2 -0
- package/corpus/core/docs/content/locales/zh-CN/external-agents.mdx +37 -7
- 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/external-agents.mdx +37 -7
- 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/a2a/handlers.ts +95 -21
- package/corpus/core/src/a2a/task-store.ts +65 -3
- 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/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 +361 -29
- package/corpus/core/src/client/sse-event-processor.ts +43 -1
- package/corpus/core/src/demo/actions/toggle-demo-mode.ts +1 -1
- package/corpus/core/src/demo/config.ts +6 -6
- package/corpus/core/src/demo/fetch-interceptor.ts +13 -4
- package/corpus/core/src/demo/redact.ts +13 -149
- 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/integrations/adapters/slack.ts +123 -13
- package/corpus/core/src/integrations/identity-links-store.ts +210 -0
- package/corpus/core/src/integrations/identity.ts +132 -0
- package/corpus/core/src/integrations/index.ts +6 -0
- package/corpus/core/src/integrations/plugin.ts +58 -1
- package/corpus/core/src/integrations/types.ts +7 -0
- package/corpus/core/src/mcp/build-server.ts +127 -22
- package/corpus/core/src/mcp/external-agent-policy.ts +18 -0
- package/corpus/core/src/mcp/index.ts +1 -0
- package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +1 -20
- package/corpus/core/src/server/agent-chat/plugin-options.ts +12 -1
- package/corpus/core/src/server/agent-chat/script-entries.ts +20 -3
- package/corpus/core/src/server/agent-chat-plugin.ts +3 -0
- 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/external-agents/SKILL.md +34 -5
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +30 -21
- package/corpus/templates/analytics/AGENTS.md +27 -0
- package/corpus/templates/analytics/actions/create-session-replay-agent-link.ts +0 -1
- package/corpus/templates/analytics/actions/get-error-issue.ts +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-summary.ts +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-timeline.ts +40 -0
- package/corpus/templates/analytics/actions/list-error-issues.ts +13 -0
- package/corpus/templates/analytics/actions/list-session-recordings.ts +1 -0
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +4 -0
- package/corpus/templates/analytics/app/global.css +2 -2
- package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +41 -4
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +52 -203
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +69 -16
- 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-connected-external-agents-can-now-look-up-sessions-error-iss.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-session-identities-stay-visible-when-demo-mode-is-off.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 +101 -2
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +24 -0
- package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +49 -17
- package/corpus/templates/analytics/server/lib/session-replay.ts +18 -16
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +43 -6
- package/corpus/templates/analytics/server/plugins/db.ts +15 -0
- 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/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 +164 -13
- package/corpus/templates/forms/app/pages/AskPage.tsx +35 -13
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +143 -67
- 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 +46 -20
- package/corpus/templates/forms/app/routes/_app.settings.tsx +1 -1
- package/corpus/templates/forms/changelog/2026-07-12-ask-forms-suggestions-now-sit-beneath-the-composer-for-a-tig.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-12-builder-response-tables-now-fill-the-view-without-a-redundan.md +6 -0
- 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-response-tables-now-fill-the-available-pane-with-a-flexible-.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/AGENTS.md +3 -1
- 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/corpus/templates/mail/server/lib/mail-integrations.ts +3 -0
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +84 -15
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/task-store.d.ts +20 -1
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/a2a/task-store.js +57 -4
- package/dist/a2a/task-store.js.map +1 -1
- 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/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.map +1 -1
- package/dist/client/session-replay.js +308 -29
- package/dist/client/session-replay.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/collab/routes.d.ts +1 -1
- package/dist/demo/actions/toggle-demo-mode.js +1 -1
- 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.map +1 -1
- package/dist/demo/fetch-interceptor.js +13 -4
- package/dist/demo/fetch-interceptor.js.map +1 -1
- package/dist/demo/redact.d.ts +7 -7
- package/dist/demo/redact.d.ts.map +1 -1
- package/dist/demo/redact.js +8 -145
- 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/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +98 -13
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/identity-links-store.d.ts +23 -0
- package/dist/integrations/identity-links-store.d.ts.map +1 -0
- package/dist/integrations/identity-links-store.js +158 -0
- package/dist/integrations/identity-links-store.js.map +1 -0
- package/dist/integrations/identity.d.ts +11 -0
- package/dist/integrations/identity.d.ts.map +1 -0
- package/dist/integrations/identity.js +100 -0
- package/dist/integrations/identity.js.map +1 -0
- package/dist/integrations/index.d.ts +2 -0
- package/dist/integrations/index.d.ts.map +1 -1
- package/dist/integrations/index.js +2 -0
- package/dist/integrations/index.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +43 -1
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/integrations/types.d.ts +6 -0
- package/dist/integrations/types.d.ts.map +1 -1
- package/dist/integrations/types.js.map +1 -1
- package/dist/mcp/build-server.d.ts +9 -2
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +97 -20
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/external-agent-policy.d.ts +19 -0
- package/dist/mcp/external-agent-policy.d.ts.map +1 -0
- package/dist/mcp/external-agent-policy.js +2 -0
- package/dist/mcp/external-agent-policy.js.map +1 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- 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-chat/plugin-options.d.ts +11 -1
- package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
- package/dist/server/agent-chat/plugin-options.js.map +1 -1
- package/dist/server/agent-chat/script-entries.d.ts.map +1 -1
- package/dist/server/agent-chat/script-entries.js +16 -2
- package/dist/server/agent-chat/script-entries.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +3 -0
- package/dist/server/agent-chat-plugin.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/external-agents/SKILL.md +34 -5
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +0 -15
- package/docs/content/durable-background-runs.mdx +37 -0
- package/docs/content/external-agents.mdx +62 -7
- package/docs/content/locales/ar-SA/external-agents.mdx +38 -7
- package/docs/content/locales/ar-SA/tracking.mdx +2 -0
- package/docs/content/locales/de-DE/external-agents.mdx +39 -7
- package/docs/content/locales/de-DE/tracking.mdx +2 -0
- package/docs/content/locales/es-ES/external-agents.mdx +39 -7
- package/docs/content/locales/es-ES/tracking.mdx +2 -0
- package/docs/content/locales/fr-FR/external-agents.mdx +39 -7
- package/docs/content/locales/fr-FR/tracking.mdx +4 -2
- package/docs/content/locales/hi-IN/external-agents.mdx +38 -7
- package/docs/content/locales/hi-IN/tracking.mdx +2 -0
- package/docs/content/locales/ja-JP/external-agents.mdx +38 -7
- package/docs/content/locales/ja-JP/tracking.mdx +2 -0
- package/docs/content/locales/ko-KR/external-agents.mdx +38 -7
- package/docs/content/locales/ko-KR/tracking.mdx +2 -0
- package/docs/content/locales/pt-BR/external-agents.mdx +39 -7
- package/docs/content/locales/pt-BR/tracking.mdx +2 -0
- package/docs/content/locales/zh-CN/external-agents.mdx +37 -7
- 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/external-agents.mdx +37 -7
- 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/external-agents/SKILL.md +34 -5
- 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
|
@@ -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;
|
|
@@ -166,16 +166,6 @@ type ReplayViewportChange = ReplayViewportDimensions & {
|
|
|
166
166
|
|
|
167
167
|
const DEFAULT_PLAYER_WIDTH = 1024;
|
|
168
168
|
const DEFAULT_PLAYER_HEIGHT = 640;
|
|
169
|
-
const MALFORMED_REPLAY_MIN_WIDTH = 4000;
|
|
170
|
-
const MALFORMED_REPLAY_MIN_ASPECT_RATIO = 4;
|
|
171
|
-
// Evidence-backed exception for the one pre-fix viewport shape observed in a
|
|
172
|
-
// stored recording. Do not broaden this to an aspect-ratio range: valid
|
|
173
|
-
// 3440x900 ultrawide browser viewports occupy the same range.
|
|
174
|
-
const LEGACY_MALFORMED_REPLAY_WIDTH = 3189;
|
|
175
|
-
const LEGACY_MALFORMED_REPLAY_HEIGHT = 885;
|
|
176
|
-
const MIN_REPLAY_DISPLAY_DIMENSION = 240;
|
|
177
|
-
const RECOVERED_REPLAY_DISPLAY_ASPECT_RATIO =
|
|
178
|
-
DEFAULT_PLAYER_WIDTH / DEFAULT_PLAYER_HEIGHT;
|
|
179
169
|
const DEFAULT_SPEED = 2;
|
|
180
170
|
const SPEED_OPTIONS = [0.5, 1, 2, 4, 8];
|
|
181
171
|
const SKIP_STEP_MS = 5000;
|
|
@@ -509,7 +499,7 @@ function ReplayPlayer({
|
|
|
509
499
|
} | null>(null);
|
|
510
500
|
const [fitScale, setFitScale] = useState(1);
|
|
511
501
|
const initialDims = useMemo(
|
|
512
|
-
() =>
|
|
502
|
+
() => replayInitialViewportDimensions(events),
|
|
513
503
|
[events],
|
|
514
504
|
);
|
|
515
505
|
const viewportTimeline = useMemo(
|
|
@@ -531,17 +521,14 @@ function ReplayPlayer({
|
|
|
531
521
|
const scrubbingRef = useRef(false);
|
|
532
522
|
const scrubResumePlayingRef = useRef(false);
|
|
533
523
|
|
|
534
|
-
//
|
|
535
|
-
//
|
|
536
|
-
//
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
const displayDims = clampReplayDisplayDimensions(streamedDims ?? initialDims);
|
|
543
|
-
const playerWidth = displayDims?.width ?? DEFAULT_PLAYER_WIDTH;
|
|
544
|
-
const playerHeight = displayDims?.height ?? DEFAULT_PLAYER_HEIGHT;
|
|
524
|
+
// Fall back to the default player size only when the viewport is unknown;
|
|
525
|
+
// otherwise render the raw recorded dimensions untouched. See the Replayer
|
|
526
|
+
// construction below for why "recovery" heuristics were removed here.
|
|
527
|
+
const displayDims = resolveReplayDisplayDimensions(
|
|
528
|
+
streamedDims ?? initialDims,
|
|
529
|
+
);
|
|
530
|
+
const playerWidth = displayDims.width;
|
|
531
|
+
const playerHeight = displayDims.height;
|
|
545
532
|
const skipRanges = useMemo(() => buildIdleSkipRanges(events), [events]);
|
|
546
533
|
const skipRangesRef = useLiveRef(skipRanges);
|
|
547
534
|
const skipInactiveRef = useLiveRef(skipInactive);
|
|
@@ -671,18 +658,16 @@ function ReplayPlayer({
|
|
|
671
658
|
clamped,
|
|
672
659
|
);
|
|
673
660
|
if (seekDims) {
|
|
674
|
-
// rrweb 2.1 does not reliably re-emit
|
|
675
|
-
//
|
|
676
|
-
//
|
|
677
|
-
const correctedSeekDims = clampReplayDisplayDimensions(seekDims);
|
|
661
|
+
// rrweb 2.1 does not reliably re-emit its resize event when seeking
|
|
662
|
+
// backwards, so mirror the raw viewport-timeline lookup onto both
|
|
663
|
+
// rrweb's iframe and the outer stage state to keep them in sync.
|
|
678
664
|
const currentDims = streamedDimsRef.current;
|
|
679
665
|
if (
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
currentDims?.height !== correctedSeekDims.height)
|
|
666
|
+
currentDims?.width !== seekDims.width ||
|
|
667
|
+
currentDims?.height !== seekDims.height
|
|
683
668
|
) {
|
|
684
|
-
replayer.handleResize?.(
|
|
685
|
-
setStreamedDims(
|
|
669
|
+
replayer.handleResize?.(seekDims);
|
|
670
|
+
setStreamedDims(seekDims);
|
|
686
671
|
}
|
|
687
672
|
}
|
|
688
673
|
updateTime(clamped);
|
|
@@ -748,24 +733,18 @@ function ReplayPlayer({
|
|
|
748
733
|
if (cancelled || !stageRootRef.current) return;
|
|
749
734
|
|
|
750
735
|
stageRootRef.current.innerHTML = "";
|
|
751
|
-
//
|
|
752
|
-
//
|
|
753
|
-
//
|
|
754
|
-
//
|
|
755
|
-
//
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
//
|
|
761
|
-
//
|
|
762
|
-
|
|
763
|
-
// with each malformed Meta/resize while retaining every other raw field.
|
|
764
|
-
const playerEvents = projectReplayPointerCoordinates(replayEvents);
|
|
765
|
-
// Keep this loosely typed because the legacy viewport recovery below
|
|
766
|
-
// intentionally calls rrweb's runtime handleResize hook, which its
|
|
767
|
-
// TypeScript declaration marks private.
|
|
768
|
-
localReplayer = new Replayer(playerEvents as any[], {
|
|
736
|
+
// Viewport and pointer events must pass through to rrweb untouched.
|
|
737
|
+
// The 2026-07 "ultra-wide replay" bugs (e.g. a stored 1,152px-wide
|
|
738
|
+
// recording rendering as a 4,491px Meta width) were caused by demo
|
|
739
|
+
// mode's fetch redaction faking numbers >= 1000 in raw replay JSON at
|
|
740
|
+
// view time, not by malformed stored geometry — fixed in
|
|
741
|
+
// packages/core/src/demo/fetch-interceptor.ts. Stored recordings were
|
|
742
|
+
// always sane, so never add viewport "recovery" heuristics here; they
|
|
743
|
+
// can only corrupt genuine recordings (e.g. a real ultrawide window).
|
|
744
|
+
setStreamedDims(replayInitialViewportDimensions(replayEvents));
|
|
745
|
+
// Keep this loosely typed: our internal AnyReplayEvent shape doesn't
|
|
746
|
+
// exactly match rrweb's declared eventWithTime type.
|
|
747
|
+
localReplayer = new Replayer(replayEvents as any[], {
|
|
769
748
|
root: stageRootRef.current,
|
|
770
749
|
speed: speedRef.current,
|
|
771
750
|
skipInactive: false,
|
|
@@ -778,17 +757,6 @@ function ReplayPlayer({
|
|
|
778
757
|
triggerFocus: true,
|
|
779
758
|
insertStyleRules: REPLAY_OVERLAY_STYLE_RULES,
|
|
780
759
|
});
|
|
781
|
-
// IMPORTANT: rrweb constructs its iframe from the raw initial Meta event.
|
|
782
|
-
// When that legacy Meta width is malformed, correcting only streamedDims
|
|
783
|
-
// fixes the outer stage but leaves CSS breakpoints and clicks ultra-wide.
|
|
784
|
-
// Apply the same correction to rrweb immediately, before first playback.
|
|
785
|
-
if (
|
|
786
|
-
correctedInitialDims &&
|
|
787
|
-
(rawInitialDims?.width !== correctedInitialDims.width ||
|
|
788
|
-
rawInitialDims?.height !== correctedInitialDims.height)
|
|
789
|
-
) {
|
|
790
|
-
(localReplayer as any).handleResize?.(correctedInitialDims);
|
|
791
|
-
}
|
|
792
760
|
// rrweb already sandboxes the replay document without script execution.
|
|
793
761
|
// Do not mutate recorded URLs/CSS; suppress viewer-page referrer leakage
|
|
794
762
|
// at the iframe boundary while retaining historical visual resources.
|
|
@@ -821,30 +789,17 @@ function ReplayPlayer({
|
|
|
821
789
|
width: Math.round(dims.width),
|
|
822
790
|
height: Math.round(dims.height),
|
|
823
791
|
};
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
//
|
|
827
|
-
// impossible legacy geometry so its iframe and our stage stay equal.
|
|
828
|
-
// DO NOT clamp just one layer; that breaks responsive CSS and clicks.
|
|
829
|
-
if (
|
|
830
|
-
correctedDims.width !== rawDims.width ||
|
|
831
|
-
correctedDims.height !== rawDims.height
|
|
832
|
-
) {
|
|
833
|
-
// rrweb applies the raw Meta/ViewportResize to its iframe before
|
|
834
|
-
// emitting this callback. Re-apply the correction every time the
|
|
835
|
-
// raw event is malformed, even when React already stores the same
|
|
836
|
-
// corrected dimensions. Returning early here recreates the exact
|
|
837
|
-
// bug where the outer stage is normal but the iframe is ultra-wide.
|
|
838
|
-
(localReplayer as any).handleResize?.(correctedDims);
|
|
839
|
-
}
|
|
792
|
+
// rrweb owns its iframe geometry from raw Meta/ViewportResize
|
|
793
|
+
// events. Only mirror the raw dims into React state here, for the
|
|
794
|
+
// outer stage's fit-to-container scaling.
|
|
840
795
|
const currentDims = streamedDimsRef.current;
|
|
841
796
|
if (
|
|
842
|
-
currentDims?.width ===
|
|
843
|
-
currentDims?.height ===
|
|
797
|
+
currentDims?.width === rawDims.width &&
|
|
798
|
+
currentDims?.height === rawDims.height
|
|
844
799
|
) {
|
|
845
800
|
return;
|
|
846
801
|
}
|
|
847
|
-
setStreamedDims(
|
|
802
|
+
setStreamedDims(rawDims);
|
|
848
803
|
}
|
|
849
804
|
});
|
|
850
805
|
updateTime(startAt);
|
|
@@ -1994,102 +1949,6 @@ export function normalizeReplayEvents(events: unknown[]): AnyReplayEvent[] {
|
|
|
1994
1949
|
.sort((a, b) => Number(a.timestamp ?? 0) - Number(b.timestamp ?? 0));
|
|
1995
1950
|
}
|
|
1996
1951
|
|
|
1997
|
-
/**
|
|
1998
|
-
* Pair pointer coordinates with the narrowly gated legacy viewport recovery.
|
|
1999
|
-
*
|
|
2000
|
-
* IMPORTANT: do not apply this to normal recordings and do not rewrite the
|
|
2001
|
-
* Meta/resize events themselves. rrweb must still rebuild the captured DOM
|
|
2002
|
-
* from raw events; only pointer coordinates need projection into the corrected
|
|
2003
|
-
* iframe camera. Returning original references for untouched events keeps this
|
|
2004
|
-
* compatible with stock rrweb and avoids cloning large snapshots.
|
|
2005
|
-
*/
|
|
2006
|
-
export function projectReplayPointerCoordinates(
|
|
2007
|
-
events: AnyReplayEvent[],
|
|
2008
|
-
): AnyReplayEvent[] {
|
|
2009
|
-
let rawDims: ReplayViewportDimensions | null = null;
|
|
2010
|
-
let displayDims: ReplayViewportDimensions | null = null;
|
|
2011
|
-
|
|
2012
|
-
return events.map((event) => {
|
|
2013
|
-
const nextDims = dimensionsFromReplayEvent(event);
|
|
2014
|
-
if (nextDims) {
|
|
2015
|
-
rawDims = nextDims;
|
|
2016
|
-
displayDims = clampReplayDisplayDimensions(nextDims);
|
|
2017
|
-
return event;
|
|
2018
|
-
}
|
|
2019
|
-
if (
|
|
2020
|
-
!rawDims ||
|
|
2021
|
-
!displayDims ||
|
|
2022
|
-
(rawDims.width === displayDims.width &&
|
|
2023
|
-
rawDims.height === displayDims.height) ||
|
|
2024
|
-
event.type !== RRWEB_EVENT_TYPE.IncrementalSnapshot
|
|
2025
|
-
) {
|
|
2026
|
-
return event;
|
|
2027
|
-
}
|
|
2028
|
-
|
|
2029
|
-
const source = event.data?.source;
|
|
2030
|
-
if (source === INCREMENTAL_SOURCE.MouseInteraction) {
|
|
2031
|
-
const data = projectReplayPointerData(event.data, rawDims, displayDims);
|
|
2032
|
-
return data === event.data ? event : { ...event, data };
|
|
2033
|
-
}
|
|
2034
|
-
if (
|
|
2035
|
-
source !== INCREMENTAL_SOURCE.MouseMove &&
|
|
2036
|
-
source !== INCREMENTAL_SOURCE.TouchMove &&
|
|
2037
|
-
source !== INCREMENTAL_SOURCE.Drag
|
|
2038
|
-
) {
|
|
2039
|
-
return event;
|
|
2040
|
-
}
|
|
2041
|
-
const positions = Array.isArray(event.data?.positions)
|
|
2042
|
-
? event.data.positions
|
|
2043
|
-
: [];
|
|
2044
|
-
let changed = false;
|
|
2045
|
-
const projectedPositions = positions.map((position: unknown) => {
|
|
2046
|
-
if (!isRecord(position)) return position;
|
|
2047
|
-
const projected = projectReplayPointerData(
|
|
2048
|
-
position,
|
|
2049
|
-
rawDims!,
|
|
2050
|
-
displayDims!,
|
|
2051
|
-
);
|
|
2052
|
-
if (projected !== position) changed = true;
|
|
2053
|
-
return projected;
|
|
2054
|
-
});
|
|
2055
|
-
return changed
|
|
2056
|
-
? { ...event, data: { ...event.data, positions: projectedPositions } }
|
|
2057
|
-
: event;
|
|
2058
|
-
});
|
|
2059
|
-
}
|
|
2060
|
-
|
|
2061
|
-
function projectReplayPointerData(
|
|
2062
|
-
data: AnyReplayEvent,
|
|
2063
|
-
rawDims: ReplayViewportDimensions,
|
|
2064
|
-
displayDims: ReplayViewportDimensions,
|
|
2065
|
-
): AnyReplayEvent {
|
|
2066
|
-
const projectedX = projectReplayCoordinate(
|
|
2067
|
-
data.x,
|
|
2068
|
-
displayDims.width / rawDims.width,
|
|
2069
|
-
displayDims.width,
|
|
2070
|
-
);
|
|
2071
|
-
const projectedY = projectReplayCoordinate(
|
|
2072
|
-
data.y,
|
|
2073
|
-
displayDims.height / rawDims.height,
|
|
2074
|
-
displayDims.height,
|
|
2075
|
-
);
|
|
2076
|
-
if (projectedX === data.x && projectedY === data.y) return data;
|
|
2077
|
-
return {
|
|
2078
|
-
...data,
|
|
2079
|
-
...(projectedX !== undefined ? { x: projectedX } : {}),
|
|
2080
|
-
...(projectedY !== undefined ? { y: projectedY } : {}),
|
|
2081
|
-
};
|
|
2082
|
-
}
|
|
2083
|
-
|
|
2084
|
-
function projectReplayCoordinate(
|
|
2085
|
-
value: unknown,
|
|
2086
|
-
scale: number,
|
|
2087
|
-
maximum: number,
|
|
2088
|
-
): number | undefined {
|
|
2089
|
-
if (typeof value !== "number" || !Number.isFinite(value)) return undefined;
|
|
2090
|
-
return clamp(value * scale, 0, Math.max(0, maximum - 1));
|
|
2091
|
-
}
|
|
2092
|
-
|
|
2093
1952
|
export function buildReplayMarkers(events: AnyReplayEvent[]): ReplayMarker[] {
|
|
2094
1953
|
const startedAt = replayStartedAt(events);
|
|
2095
1954
|
const markers: ReplayMarker[] = [];
|
|
@@ -2447,14 +2306,6 @@ export function replayInitialViewportDimensions(
|
|
|
2447
2306
|
return null;
|
|
2448
2307
|
}
|
|
2449
2308
|
|
|
2450
|
-
export function replayInitialDisplayDimensions(
|
|
2451
|
-
events: AnyReplayEvent[],
|
|
2452
|
-
): ReplayViewportDimensions | null {
|
|
2453
|
-
// Keep the initial outer stage and rrweb iframe on one corrected camera.
|
|
2454
|
-
// DO NOT use the raw initial Meta dimensions for only one of those layers.
|
|
2455
|
-
return clampReplayDisplayDimensions(replayInitialViewportDimensions(events));
|
|
2456
|
-
}
|
|
2457
|
-
|
|
2458
2309
|
export function buildReplayViewportTimeline(
|
|
2459
2310
|
events: AnyReplayEvent[],
|
|
2460
2311
|
): ReplayViewportChange[] {
|
|
@@ -2540,30 +2391,28 @@ export function normalizeReplayDimensions(
|
|
|
2540
2391
|
};
|
|
2541
2392
|
}
|
|
2542
2393
|
|
|
2543
|
-
|
|
2394
|
+
/**
|
|
2395
|
+
* Fall back to the default player size only when the viewport is entirely
|
|
2396
|
+
* unknown (no Meta/ViewportResize event yet). This is not a "recovery"
|
|
2397
|
+
* heuristic for real recorded geometry — it never rewrites valid dims, no
|
|
2398
|
+
* matter how wide, narrow, or unusual the aspect ratio. See the Replayer
|
|
2399
|
+
* construction in ReplayPlayer for why viewport "correction" was removed:
|
|
2400
|
+
* the 2026-07 ultra-wide replay bugs were caused by demo mode's fetch
|
|
2401
|
+
* redaction faking numbers at view time, not by malformed stored geometry.
|
|
2402
|
+
*/
|
|
2403
|
+
export function resolveReplayDisplayDimensions(
|
|
2544
2404
|
dims: ReplayViewportDimensions | null,
|
|
2545
|
-
): ReplayViewportDimensions
|
|
2546
|
-
if (!dims) return null;
|
|
2405
|
+
): ReplayViewportDimensions {
|
|
2547
2406
|
if (
|
|
2548
|
-
dims
|
|
2549
|
-
dims.
|
|
2407
|
+
dims &&
|
|
2408
|
+
Number.isFinite(dims.width) &&
|
|
2409
|
+
Number.isFinite(dims.height) &&
|
|
2410
|
+
dims.width > 0 &&
|
|
2411
|
+
dims.height > 0
|
|
2550
2412
|
) {
|
|
2551
|
-
return
|
|
2552
|
-
}
|
|
2553
|
-
const aspect = dims.width / dims.height;
|
|
2554
|
-
const hasMalformedWideGeometry =
|
|
2555
|
-
dims.width >= MALFORMED_REPLAY_MIN_WIDTH &&
|
|
2556
|
-
aspect > MALFORMED_REPLAY_MIN_ASPECT_RATIO;
|
|
2557
|
-
const hasLegacyMalformedWideGeometry =
|
|
2558
|
-
dims.width === LEGACY_MALFORMED_REPLAY_WIDTH &&
|
|
2559
|
-
dims.height === LEGACY_MALFORMED_REPLAY_HEIGHT;
|
|
2560
|
-
if (hasMalformedWideGeometry || hasLegacyMalformedWideGeometry) {
|
|
2561
|
-
return {
|
|
2562
|
-
width: Math.round(dims.height * RECOVERED_REPLAY_DISPLAY_ASPECT_RATIO),
|
|
2563
|
-
height: dims.height,
|
|
2564
|
-
};
|
|
2413
|
+
return dims;
|
|
2565
2414
|
}
|
|
2566
|
-
return
|
|
2415
|
+
return { width: DEFAULT_PLAYER_WIDTH, height: DEFAULT_PLAYER_HEIGHT };
|
|
2567
2416
|
}
|
|
2568
2417
|
|
|
2569
2418
|
export function filterReplayMarkers(
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
IconSettings,
|
|
22
22
|
} from "@tabler/icons-react";
|
|
23
23
|
import { useQuery } from "@tanstack/react-query";
|
|
24
|
-
import { useMemo, useState } from "react";
|
|
24
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
25
25
|
import { Link, useNavigate, useSearchParams } from "react-router";
|
|
26
26
|
import { toast } from "sonner";
|
|
27
27
|
|
|
@@ -167,6 +167,41 @@ type SessionRecordingIdentity = Pick<
|
|
|
167
167
|
type SessionRecordingDevice = Pick<SessionRecordingSummary, "metadata">;
|
|
168
168
|
|
|
169
169
|
const RANGE_OPTIONS: ReplayRange[] = ["24h", "7d", "30d", "90d", "all"];
|
|
170
|
+
const SESSION_QUERY_DEBOUNCE_MS = 250;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Local input state for a URL-backed filter, debounced into the URL.
|
|
174
|
+
*
|
|
175
|
+
* `urlValue` only resyncs local state when it changes for a reason other
|
|
176
|
+
* than this hook's own debounced write (back/forward navigation, an agent
|
|
177
|
+
* driven URL change, etc). React Router commits `setSearchParams` inside a
|
|
178
|
+
* transition, so without this guard the echo of our own write can land
|
|
179
|
+
* after a newer keystroke and clobber it.
|
|
180
|
+
*/
|
|
181
|
+
export function useDebouncedUrlFilter(
|
|
182
|
+
urlValue: string,
|
|
183
|
+
onCommit: (value: string) => void,
|
|
184
|
+
): [string, (value: string) => void] {
|
|
185
|
+
const [input, setInput] = useState(urlValue);
|
|
186
|
+
const lastPushedRef = useRef(urlValue);
|
|
187
|
+
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
if (urlValue === lastPushedRef.current) return;
|
|
190
|
+
lastPushedRef.current = urlValue;
|
|
191
|
+
setInput(urlValue);
|
|
192
|
+
}, [urlValue]);
|
|
193
|
+
|
|
194
|
+
useEffect(() => {
|
|
195
|
+
if (input === urlValue) return;
|
|
196
|
+
const timeout = window.setTimeout(() => {
|
|
197
|
+
lastPushedRef.current = input;
|
|
198
|
+
onCommit(input);
|
|
199
|
+
}, SESSION_QUERY_DEBOUNCE_MS);
|
|
200
|
+
return () => window.clearTimeout(timeout);
|
|
201
|
+
}, [input, urlValue, onCommit]);
|
|
202
|
+
|
|
203
|
+
return [input, setInput];
|
|
204
|
+
}
|
|
170
205
|
|
|
171
206
|
export default function SessionsPage() {
|
|
172
207
|
const t = useT();
|
|
@@ -177,6 +212,35 @@ export default function SessionsPage() {
|
|
|
177
212
|
const query = searchParams.get("q") ?? "";
|
|
178
213
|
const from = useMemo(() => rangeToFrom(range), [range]);
|
|
179
214
|
|
|
215
|
+
const updateFilter = useCallback(
|
|
216
|
+
(key: string, value: string) => {
|
|
217
|
+
setSearchParams(
|
|
218
|
+
(current) => {
|
|
219
|
+
const next = new URLSearchParams(current);
|
|
220
|
+
const emptyDefault =
|
|
221
|
+
(key === "range" && value === "30d") || value.trim() === "";
|
|
222
|
+
if (emptyDefault) next.delete(key);
|
|
223
|
+
else next.set(key, value);
|
|
224
|
+
return next;
|
|
225
|
+
},
|
|
226
|
+
{ replace: true },
|
|
227
|
+
);
|
|
228
|
+
},
|
|
229
|
+
[setSearchParams],
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
const commitQuery = useCallback(
|
|
233
|
+
(value: string) => updateFilter("q", value),
|
|
234
|
+
[updateFilter],
|
|
235
|
+
);
|
|
236
|
+
const [queryInput, setQueryInput] = useDebouncedUrlFilter(query, commitQuery);
|
|
237
|
+
|
|
238
|
+
const commitApp = useCallback(
|
|
239
|
+
(value: string) => updateFilter("app", value),
|
|
240
|
+
[updateFilter],
|
|
241
|
+
);
|
|
242
|
+
const [appInput, setAppInput] = useDebouncedUrlFilter(app, commitApp);
|
|
243
|
+
|
|
180
244
|
const { data, isLoading, isFetching, refetch, error } = useActionQuery<
|
|
181
245
|
SessionRecordingSummary[]
|
|
182
246
|
>(
|
|
@@ -192,15 +256,6 @@ export default function SessionsPage() {
|
|
|
192
256
|
|
|
193
257
|
const recordings = data ?? [];
|
|
194
258
|
|
|
195
|
-
function updateFilter(key: string, value: string) {
|
|
196
|
-
const next = new URLSearchParams(searchParams);
|
|
197
|
-
const emptyDefault =
|
|
198
|
-
(key === "range" && value === "30d") || value.trim() === "";
|
|
199
|
-
if (emptyDefault) next.delete(key);
|
|
200
|
-
else next.set(key, value);
|
|
201
|
-
setSearchParams(next, { replace: true });
|
|
202
|
-
}
|
|
203
|
-
|
|
204
259
|
return (
|
|
205
260
|
<div className="analytics-sessions-page mx-auto flex w-full max-w-7xl flex-col gap-4 px-4 py-5">
|
|
206
261
|
<Card>
|
|
@@ -213,8 +268,8 @@ export default function SessionsPage() {
|
|
|
213
268
|
<div className="analytics-sessions-filter-search relative min-w-0">
|
|
214
269
|
<IconSearch className="pointer-events-none absolute start-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
|
215
270
|
<Input
|
|
216
|
-
value={
|
|
217
|
-
onChange={(event) =>
|
|
271
|
+
value={queryInput}
|
|
272
|
+
onChange={(event) => setQueryInput(event.target.value)}
|
|
218
273
|
placeholder={t("sessions.searchPlaceholder")}
|
|
219
274
|
className="h-9 ps-9"
|
|
220
275
|
/>
|
|
@@ -269,10 +324,8 @@ export default function SessionsPage() {
|
|
|
269
324
|
{t("sessions.userFilters")}
|
|
270
325
|
</div>
|
|
271
326
|
<Input
|
|
272
|
-
value={
|
|
273
|
-
onChange={(event) =>
|
|
274
|
-
updateFilter("app", event.target.value)
|
|
275
|
-
}
|
|
327
|
+
value={appInput}
|
|
328
|
+
onChange={(event) => setAppInput(event.target.value)}
|
|
276
329
|
placeholder={t("sessions.appPlaceholder")}
|
|
277
330
|
className="h-9"
|
|
278
331
|
/>
|
|
@@ -9,14 +9,11 @@ GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
|
|
|
9
9
|
NITRO_PRESET = "netlify"
|
|
10
10
|
NPM_CONFIG_PRODUCTION = "false"
|
|
11
11
|
AGENT_PROD_CODE_EXECUTION = "sandboxed"
|
|
12
|
-
AGENT_CHAT_DURABLE_BACKGROUND = "true"
|
|
13
12
|
|
|
14
13
|
# A2A delegation calls run a full agent loop (LLM + tool calls + DB queries).
|
|
15
14
|
# Hosted agent chat uses a soft timeout before this function timeout so the
|
|
16
15
|
# hidden auto-continuation path can hand off before Netlify kills the function.
|
|
17
16
|
# If AGENT_RUN_SOFT_TIMEOUT_MS is customized, keep it below this timeout.
|
|
18
|
-
# Agent chat runs are dispatched to the emitted Netlify background function;
|
|
19
|
-
# the normal server timeout still protects non-background HTTP handlers.
|
|
20
17
|
[functions."*"]
|
|
21
18
|
timeout = 75
|
|
22
19
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The deliberately small authenticated MCP surface for Analytics.
|
|
3
|
+
*
|
|
4
|
+
* Keep this list read-only and incident-focused. In particular, do not add
|
|
5
|
+
* raw replay-event/blob actions or dashboard/data mutation actions here.
|
|
6
|
+
*/
|
|
7
|
+
export const ANALYTICS_CONNECTOR_CATALOG = [
|
|
8
|
+
"list-session-recordings",
|
|
9
|
+
"get-session-replay-summary",
|
|
10
|
+
"get-session-replay-timeline",
|
|
11
|
+
"query-agent-native-analytics",
|
|
12
|
+
"list-error-issues",
|
|
13
|
+
"get-error-issue",
|
|
14
|
+
] as const;
|