@agent-native/core 0.95.0 → 0.96.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +35 -0
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +13 -0
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +18 -0
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +16 -0
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +17 -0
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +16 -0
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +17 -0
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +15 -0
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +16 -0
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +11 -0
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +12 -0
- package/corpus/core/docs/content/template-design.mdx +16 -0
- package/corpus/core/package.json +4 -2
- package/corpus/core/src/a2a/client.ts +11 -1
- package/corpus/core/src/agent/production-agent.ts +107 -27
- package/corpus/core/src/agent/thread-data-builder.ts +48 -22
- package/corpus/core/src/chat-threads/store.ts +20 -1
- package/corpus/core/src/cli/code-agent-executor.ts +1 -0
- package/corpus/core/src/cli/code-agent-runs.ts +14 -0
- package/corpus/core/src/client/AgentPanel.tsx +32 -25
- package/corpus/core/src/client/AssistantChat.tsx +286 -45
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +141 -90
- package/corpus/core/src/client/chat/ChatHistoryList.tsx +404 -0
- package/corpus/core/src/client/chat/index.ts +6 -0
- package/corpus/core/src/client/chat/tool-call-display.tsx +38 -4
- package/corpus/core/src/client/chat/use-reconnect-reader-owner.ts +28 -0
- package/corpus/core/src/client/code-agent-chat-adapter.ts +72 -4
- package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +52 -11
- package/corpus/core/src/client/composer/TiptapComposer.tsx +157 -20
- package/corpus/core/src/client/composer/VoiceButton.tsx +28 -0
- package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +5 -0
- package/corpus/core/src/client/conversation/code-agent-transcript.ts +4 -5
- package/corpus/core/src/client/guided-questions.tsx +11 -2
- package/corpus/core/src/client/index.ts +11 -0
- package/corpus/core/src/client/integrations/IntegrationsPanel.tsx +6 -7
- package/corpus/core/src/client/sse-event-processor.ts +90 -21
- package/corpus/core/src/client/use-chat-threads.ts +10 -1
- package/corpus/core/src/client/voice-provider-status.ts +44 -0
- package/corpus/core/src/code-agents/transcript-normalizer.ts +76 -0
- package/corpus/core/src/connections/catalog.ts +2 -2
- package/corpus/core/src/deploy/build.ts +12 -8
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +35 -5
- package/corpus/core/src/integrations/adapters/slack.ts +74 -21
- package/corpus/core/src/integrations/catalog.ts +2 -2
- package/corpus/core/src/integrations/webhook-handler.ts +14 -0
- package/corpus/core/src/localization/default-messages.ts +6 -0
- package/corpus/core/src/observability/hosted-model-experiment.ts +118 -0
- package/corpus/core/src/observability/routes.ts +17 -0
- package/corpus/core/src/observability/store.ts +4 -1
- package/corpus/core/src/observability/traces.ts +41 -2
- package/corpus/core/src/scripts/agent-engines/list-agent-engines.ts +19 -1
- package/corpus/core/src/scripts/call-agent.ts +53 -3
- package/corpus/core/src/scripts/chat/search-chats.ts +11 -8
- package/corpus/core/src/secrets/register-framework-secrets.ts +1 -1
- package/corpus/core/src/server/agent-chat-plugin.ts +41 -6
- package/corpus/core/src/server/auth.ts +1 -1
- package/corpus/core/src/server/core-routes-plugin.ts +15 -0
- package/corpus/core/src/server/credential-provider.ts +7 -3
- package/corpus/core/src/server/realtime-voice.ts +71 -24
- package/corpus/core/src/server/voice-providers-status.ts +4 -3
- package/corpus/core/src/shared/cache-control.ts +4 -4
- package/corpus/core/src/styles/agent-native.css +1 -0
- package/corpus/core/src/styles/chat-history-list.css +313 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
- package/corpus/core/src/vite/client.ts +1 -0
- package/corpus/templates/analytics/AGENTS.md +7 -0
- package/corpus/templates/analytics/actions/bigquery.ts +26 -2
- package/corpus/templates/analytics/actions/data-source-status.ts +18 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +5 -4
- package/corpus/templates/analytics/app/global.css +10 -0
- package/corpus/templates/analytics/app/lib/data-sources.ts +5 -4
- package/corpus/templates/analytics/app/pages/Ask.tsx +25 -2
- package/corpus/templates/analytics/changelog/2026-07-10-analytics-answers-simple-time-bounded-metrics-without-unnece.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-analytics-chat-reliably-uses-connected-data-sources-across-s.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-chat-threads-now-stay-clear-of-top-actions-and-fade-smoothly.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-context-chips-can-now-be-selected-and-removed-one-at-a-time-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-slack-token-setup-marked-legacy.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-the-ask-composer-no-longer-carries-dashboard-or-panel-contex.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-the-ask-section-stays-highlighted-while-its-chat-history-is-.md +6 -0
- package/corpus/templates/analytics/server/lib/bigquery.ts +90 -14
- package/corpus/templates/analytics/server/lib/credential-keys.ts +6 -2
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +82 -7
- package/corpus/templates/brain/changelog/2026-07-10-slack-backfill-token-marked-legacy.md +6 -0
- package/corpus/templates/brain/server/register-secrets.ts +2 -2
- package/corpus/templates/clips/app/components/library/library-layout.tsx +7 -1
- package/corpus/templates/clips/app/components/library/page-header.tsx +19 -3
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +16 -12
- package/corpus/templates/clips/changelog/2026-07-10-new-recording-appears-once-when-the-library-sidebar-is-open.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-slack-token-fallback-guidance.md +6 -0
- package/corpus/templates/clips/server/register-secrets.ts +1 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +0 -66
- package/corpus/templates/content/app/routes/_app.local-files.tsx +7 -47
- package/corpus/templates/content/changelog/2026-07-10-local-folders-now-wait-for-an-explicit-pull-before-content-r.md +6 -0
- package/corpus/templates/content/package.json +1 -1
- package/corpus/templates/design/actions/generate-design.ts +128 -31
- package/corpus/templates/design/actions/present-design-variants.ts +37 -9
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +9 -3
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +32 -10
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +2 -2
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +9 -1
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +7 -5
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +3 -0
- package/corpus/templates/design/app/global.css +10 -0
- package/corpus/templates/design/app/hooks/use-question-flow.ts +9 -2
- package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/design/app/i18n-data.ts +21 -11
- package/corpus/templates/design/changelog/2026-07-10-editor-panels-are-easier-to-distinguish-and-design-intake-qu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-interact-mode-now-stays-on-the-full-canvas-matches-edit-visu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-new-web-designs-open-at-desktop-size-and-adapt-across-mobile.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-tweaks-now-link-to-full-documentation.md +6 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/mail/app/i18n/ar-SA.ts +3 -3
- package/corpus/templates/mail/app/i18n/de-DE.ts +3 -3
- package/corpus/templates/mail/app/i18n/en-US.ts +4 -3
- package/corpus/templates/mail/app/i18n/es-ES.ts +3 -3
- package/corpus/templates/mail/app/i18n/fr-FR.ts +3 -3
- package/corpus/templates/mail/app/i18n/hi-IN.ts +3 -3
- package/corpus/templates/mail/app/i18n/ja-JP.ts +3 -3
- package/corpus/templates/mail/app/i18n/ko-KR.ts +3 -3
- package/corpus/templates/mail/app/i18n/pt-BR.ts +3 -3
- package/corpus/templates/mail/app/i18n/zh-CN.ts +3 -3
- package/corpus/templates/mail/app/i18n/zh-TW.ts +3 -3
- package/corpus/templates/mail/changelog/2026-07-10-slack-intake-marked-legacy.md +6 -0
- package/corpus/templates/mail/server/lib/env-config.ts +5 -4
- package/corpus/templates/plan/package.json +1 -1
- package/dist/a2a/client.d.ts +7 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +2 -1
- package/dist/a2a/client.js.map +1 -1
- package/dist/agent/production-agent.d.ts +6 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +83 -26
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts +1 -0
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +42 -23
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/chat-threads/store.d.ts +10 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +6 -0
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +1 -0
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/code-agent-runs.d.ts +12 -0
- package/dist/cli/code-agent-runs.d.ts.map +1 -1
- package/dist/cli/code-agent-runs.js +1 -0
- package/dist/cli/code-agent-runs.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +3 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +14 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +207 -32
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +83 -10
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/chat/ChatHistoryList.d.ts +88 -0
- package/dist/client/chat/ChatHistoryList.d.ts.map +1 -0
- package/dist/client/chat/ChatHistoryList.js +83 -0
- package/dist/client/chat/ChatHistoryList.js.map +1 -0
- package/dist/client/chat/index.d.ts +1 -0
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +1 -0
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +13 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +11 -3
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat/use-reconnect-reader-owner.d.ts +11 -0
- package/dist/client/chat/use-reconnect-reader-owner.d.ts.map +1 -0
- package/dist/client/chat/use-reconnect-reader-owner.js +21 -0
- package/dist/client/chat/use-reconnect-reader-owner.js.map +1 -0
- package/dist/client/code-agent-chat-adapter.d.ts +17 -1
- package/dist/client/code-agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/code-agent-chat-adapter.js +47 -3
- package/dist/client/code-agent-chat-adapter.js.map +1 -1
- package/dist/client/composer/RealtimeVoiceMode.d.ts +11 -1
- package/dist/client/composer/RealtimeVoiceMode.d.ts.map +1 -1
- package/dist/client/composer/RealtimeVoiceMode.js +5 -3
- package/dist/client/composer/RealtimeVoiceMode.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +25 -2
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +96 -5
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/composer/VoiceButton.d.ts.map +1 -1
- package/dist/client/composer/VoiceButton.js +21 -1
- package/dist/client/composer/VoiceButton.js.map +1 -1
- package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +1 -1
- package/dist/client/composer/useRealtimeVoiceMode.js +5 -0
- package/dist/client/composer/useRealtimeVoiceMode.js.map +1 -1
- package/dist/client/conversation/code-agent-transcript.d.ts +2 -0
- package/dist/client/conversation/code-agent-transcript.d.ts.map +1 -1
- package/dist/client/conversation/code-agent-transcript.js +3 -5
- package/dist/client/conversation/code-agent-transcript.js.map +1 -1
- package/dist/client/guided-questions.d.ts.map +1 -1
- package/dist/client/guided-questions.js +7 -2
- package/dist/client/guided-questions.js.map +1 -1
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.js +5 -7
- package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +67 -20
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +9 -1
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/client/voice-provider-status.d.ts +10 -0
- package/dist/client/voice-provider-status.d.ts.map +1 -0
- package/dist/client/voice-provider-status.js +32 -0
- package/dist/client/voice-provider-status.js.map +1 -0
- package/dist/code-agents/transcript-normalizer.d.ts +29 -0
- package/dist/code-agents/transcript-normalizer.d.ts.map +1 -1
- package/dist/code-agents/transcript-normalizer.js +55 -0
- package/dist/code-agents/transcript-normalizer.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +2 -2
- package/dist/connections/catalog.js +2 -2
- package/dist/connections/catalog.js.map +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +12 -8
- package/dist/deploy/build.js.map +1 -1
- package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -1
- package/dist/integrations/a2a-continuation-processor.js +25 -5
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +55 -21
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/catalog.js +2 -2
- package/dist/integrations/catalog.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +11 -0
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/localization/default-messages.d.ts +5 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +5 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/observability/hosted-model-experiment.d.ts +39 -0
- package/dist/observability/hosted-model-experiment.d.ts.map +1 -0
- package/dist/observability/hosted-model-experiment.js +90 -0
- package/dist/observability/hosted-model-experiment.js.map +1 -0
- package/dist/observability/routes.d.ts.map +1 -1
- package/dist/observability/routes.js +16 -0
- package/dist/observability/routes.js.map +1 -1
- package/dist/observability/store.d.ts.map +1 -1
- package/dist/observability/store.js +4 -1
- package/dist/observability/store.js.map +1 -1
- package/dist/observability/traces.d.ts +6 -0
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +28 -2
- package/dist/observability/traces.js.map +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 +19 -1
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +43 -3
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/scripts/chat/search-chats.d.ts +1 -1
- package/dist/scripts/chat/search-chats.d.ts.map +1 -1
- package/dist/scripts/chat/search-chats.js +11 -8
- package/dist/scripts/chat/search-chats.js.map +1 -1
- package/dist/secrets/register-framework-secrets.js +1 -1
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +11 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +27 -6
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.js +1 -1
- package/dist/server/auth.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +3 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +13 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +5 -3
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +7 -3
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/realtime-voice.d.ts.map +1 -1
- package/dist/server/realtime-voice.js +55 -21
- package/dist/server/realtime-voice.js.map +1 -1
- package/dist/server/voice-providers-status.d.ts.map +1 -1
- package/dist/server/voice-providers-status.js +2 -3
- package/dist/server/voice-providers-status.js.map +1 -1
- package/dist/shared/cache-control.d.ts +6 -6
- package/dist/shared/cache-control.d.ts.map +1 -1
- package/dist/shared/cache-control.js +3 -3
- package/dist/shared/cache-control.js.map +1 -1
- package/dist/styles/agent-native.css +1 -0
- package/dist/styles/chat-history-list.css +313 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +1 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/locales/ar-SA/template-design.mdx +13 -0
- package/docs/content/locales/de-DE/template-design.mdx +18 -0
- package/docs/content/locales/es-ES/template-design.mdx +16 -0
- package/docs/content/locales/fr-FR/template-design.mdx +17 -0
- package/docs/content/locales/hi-IN/template-design.mdx +16 -0
- package/docs/content/locales/ja-JP/template-design.mdx +17 -0
- package/docs/content/locales/ko-KR/template-design.mdx +15 -0
- package/docs/content/locales/pt-BR/template-design.mdx +16 -0
- package/docs/content/locales/zh-CN/template-design.mdx +11 -0
- package/docs/content/locales/zh-TW/template-design.mdx +12 -0
- package/docs/content/template-design.mdx +16 -0
- package/package.json +4 -2
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +8 -4
|
@@ -123,6 +123,7 @@ import {
|
|
|
123
123
|
type ApprovalContextValue,
|
|
124
124
|
ReconnectStreamMessage,
|
|
125
125
|
} from "./chat/tool-call-display.js";
|
|
126
|
+
import { useReconnectReaderOwner } from "./chat/use-reconnect-reader-owner.js";
|
|
126
127
|
import {
|
|
127
128
|
MessageScroller,
|
|
128
129
|
MessageScrollerButton,
|
|
@@ -764,6 +765,20 @@ function toolCallIdsRepresentSameLocalCall(
|
|
|
764
765
|
return renderedId === reconnectId || renderedId.endsWith(`:${reconnectId}`);
|
|
765
766
|
}
|
|
766
767
|
|
|
768
|
+
function toolCallIdIsReaderLocal(id: string): boolean {
|
|
769
|
+
return (
|
|
770
|
+
/^tc_\d+$/.test(id) ||
|
|
771
|
+
/:tc_\d+$/.test(id) ||
|
|
772
|
+
id.startsWith("reconnect-activity:")
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
function toolCallReaderLocalKey(id: string): string | null {
|
|
777
|
+
const counterMatch = id.match(/(?:^|:)(tc_\d+)$/);
|
|
778
|
+
if (counterMatch?.[1]) return counterMatch[1];
|
|
779
|
+
return id.startsWith("reconnect-activity:") ? id : null;
|
|
780
|
+
}
|
|
781
|
+
|
|
767
782
|
function collectRenderedToolCallStates(messages: readonly unknown[]): {
|
|
768
783
|
byId: Map<string, { rank: number }>;
|
|
769
784
|
latestAssistantByFingerprint: Map<string, { rank: number }>;
|
|
@@ -862,7 +877,14 @@ function latestRenderedAssistantText(messages: readonly unknown[]): string {
|
|
|
862
877
|
function dedupePendingToolCallReplaysWithinContent(
|
|
863
878
|
content: ContentPart[],
|
|
864
879
|
): ContentPart[] {
|
|
865
|
-
const
|
|
880
|
+
const laterStatesByFingerprint = new Map<
|
|
881
|
+
string,
|
|
882
|
+
{
|
|
883
|
+
ids: Set<string>;
|
|
884
|
+
readerLocalKeys: Set<string>;
|
|
885
|
+
hasStableId: boolean;
|
|
886
|
+
}
|
|
887
|
+
>();
|
|
866
888
|
let changed = false;
|
|
867
889
|
const nextReversed: ContentPart[] = [];
|
|
868
890
|
|
|
@@ -870,53 +892,153 @@ function dedupePendingToolCallReplaysWithinContent(
|
|
|
870
892
|
const part = content[i];
|
|
871
893
|
if (!part) continue;
|
|
872
894
|
const fingerprint = toolCallFingerprintFromContentPart(part);
|
|
873
|
-
|
|
874
|
-
fingerprint
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
)
|
|
895
|
+
const laterState = fingerprint
|
|
896
|
+
? laterStatesByFingerprint.get(fingerprint)
|
|
897
|
+
: undefined;
|
|
898
|
+
const id = toolCallIdFromContentPart(part);
|
|
899
|
+
const readerLocalKey = id ? toolCallReaderLocalKey(id) : null;
|
|
900
|
+
const isReaderReplay = Boolean(
|
|
901
|
+
id &&
|
|
902
|
+
laterState &&
|
|
903
|
+
(laterState.ids.has(id) ||
|
|
904
|
+
(readerLocalKey && laterState.readerLocalKeys.has(readerLocalKey)) ||
|
|
905
|
+
(toolCallIdIsReaderLocal(id) && laterState.hasStableId)),
|
|
906
|
+
);
|
|
907
|
+
if (fingerprint && !toolCallPartHasResult(part) && isReaderReplay) {
|
|
878
908
|
changed = true;
|
|
879
909
|
continue;
|
|
880
910
|
}
|
|
881
|
-
if (fingerprint)
|
|
911
|
+
if (fingerprint) {
|
|
912
|
+
const state = laterState ?? {
|
|
913
|
+
ids: new Set(),
|
|
914
|
+
readerLocalKeys: new Set(),
|
|
915
|
+
hasStableId: false,
|
|
916
|
+
};
|
|
917
|
+
if (id) {
|
|
918
|
+
state.ids.add(id);
|
|
919
|
+
const key = toolCallReaderLocalKey(id);
|
|
920
|
+
if (key) state.readerLocalKeys.add(key);
|
|
921
|
+
else state.hasStableId = true;
|
|
922
|
+
}
|
|
923
|
+
laterStatesByFingerprint.set(fingerprint, state);
|
|
924
|
+
}
|
|
882
925
|
nextReversed.push(part);
|
|
883
926
|
}
|
|
884
927
|
|
|
885
928
|
return changed ? nextReversed.reverse() : content;
|
|
886
929
|
}
|
|
887
930
|
|
|
931
|
+
function pendingToolCallCountsByName(
|
|
932
|
+
content: readonly ContentPart[],
|
|
933
|
+
): Map<string, number> {
|
|
934
|
+
const counts = new Map<string, number>();
|
|
935
|
+
for (const part of content) {
|
|
936
|
+
const name = toolCallNameFromContentPart(part);
|
|
937
|
+
if (!name || toolCallProgressRank(part) >= 4) continue;
|
|
938
|
+
counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
939
|
+
}
|
|
940
|
+
return counts;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Linear-time longest overlap where a suffix of `renderedText` equals a prefix
|
|
945
|
+
* of `reconnectText`. The reconnect overlay is recalculated during render on
|
|
946
|
+
* every stream tick, so a descending slice/endsWith scan becomes quadratic on
|
|
947
|
+
* large repeated output.
|
|
948
|
+
*/
|
|
949
|
+
function longestSuffixPrefixOverlap(
|
|
950
|
+
renderedText: string,
|
|
951
|
+
reconnectText: string,
|
|
952
|
+
): number {
|
|
953
|
+
const maxOverlap = Math.min(renderedText.length, reconnectText.length);
|
|
954
|
+
if (maxOverlap === 0) return 0;
|
|
955
|
+
|
|
956
|
+
const pattern = reconnectText.slice(0, maxOverlap);
|
|
957
|
+
const prefixLengths = new Array<number>(pattern.length).fill(0);
|
|
958
|
+
for (let index = 1; index < pattern.length; index += 1) {
|
|
959
|
+
let matched = prefixLengths[index - 1] ?? 0;
|
|
960
|
+
while (matched > 0 && pattern[index] !== pattern[matched]) {
|
|
961
|
+
matched = prefixLengths[matched - 1] ?? 0;
|
|
962
|
+
}
|
|
963
|
+
if (pattern[index] === pattern[matched]) matched += 1;
|
|
964
|
+
prefixLengths[index] = matched;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
let matched = 0;
|
|
968
|
+
const renderedStart = renderedText.length - maxOverlap;
|
|
969
|
+
for (let index = renderedStart; index < renderedText.length; index += 1) {
|
|
970
|
+
const character = renderedText[index];
|
|
971
|
+
while (matched > 0 && character !== pattern[matched]) {
|
|
972
|
+
matched = prefixLengths[matched - 1] ?? 0;
|
|
973
|
+
}
|
|
974
|
+
if (character === pattern[matched]) matched += 1;
|
|
975
|
+
if (matched === pattern.length && index < renderedText.length - 1) {
|
|
976
|
+
matched = prefixLengths[matched - 1] ?? 0;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
return matched;
|
|
980
|
+
}
|
|
981
|
+
|
|
888
982
|
function trimReconnectTextAlreadyRendered(
|
|
889
983
|
content: ContentPart[],
|
|
890
984
|
renderedAssistantText: string,
|
|
985
|
+
options?: { trimTailOverlap?: boolean },
|
|
891
986
|
): ContentPart[] {
|
|
892
987
|
if (!renderedAssistantText) return content;
|
|
893
988
|
|
|
894
|
-
|
|
989
|
+
const reconnectText = assistantTextFromContent(content);
|
|
990
|
+
if (!reconnectText) return content;
|
|
991
|
+
|
|
992
|
+
let overlapLength = 0;
|
|
993
|
+
if (reconnectText.startsWith(renderedAssistantText)) {
|
|
994
|
+
overlapLength = renderedAssistantText.length;
|
|
995
|
+
} else if (renderedAssistantText.startsWith(reconnectText)) {
|
|
996
|
+
overlapLength = reconnectText.length;
|
|
997
|
+
} else if (options?.trimTailOverlap) {
|
|
998
|
+
const tailOverlap = longestSuffixPrefixOverlap(
|
|
999
|
+
renderedAssistantText,
|
|
1000
|
+
reconnectText,
|
|
1001
|
+
);
|
|
1002
|
+
if (tailOverlap > 0) {
|
|
1003
|
+
// Tail reconnects begin after the last remembered event, so their first
|
|
1004
|
+
// text can be the final suffix of a thread snapshot imported in parallel.
|
|
1005
|
+
// For a partial overlap, require a whole word/phrase boundary so a
|
|
1006
|
+
// coincidental shared character at the join cannot eat legitimate text.
|
|
1007
|
+
const renderedBeforeOverlap =
|
|
1008
|
+
renderedAssistantText[renderedAssistantText.length - tailOverlap - 1];
|
|
1009
|
+
const reconnectAfterOverlap = reconnectText[tailOverlap];
|
|
1010
|
+
const isWordCharacter = (value: string | undefined) =>
|
|
1011
|
+
value ? /[\p{L}\p{N}_]/u.test(value) : false;
|
|
1012
|
+
const isWholeBoundary =
|
|
1013
|
+
!isWordCharacter(renderedBeforeOverlap) &&
|
|
1014
|
+
!isWordCharacter(reconnectAfterOverlap);
|
|
1015
|
+
if (tailOverlap === reconnectText.length || isWholeBoundary) {
|
|
1016
|
+
overlapLength = tailOverlap;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
if (overlapLength === 0) return content;
|
|
1022
|
+
|
|
1023
|
+
let remainingOverlap = overlapLength;
|
|
895
1024
|
let changed = false;
|
|
896
1025
|
const next: ContentPart[] = [];
|
|
897
1026
|
|
|
898
1027
|
for (const part of content) {
|
|
899
|
-
if (part.type !== "text" || remainingOverlap
|
|
1028
|
+
if (part.type !== "text" || remainingOverlap === 0) {
|
|
900
1029
|
next.push(part);
|
|
901
1030
|
continue;
|
|
902
1031
|
}
|
|
903
1032
|
|
|
904
|
-
if (
|
|
905
|
-
remainingOverlap
|
|
1033
|
+
if (part.text.length <= remainingOverlap) {
|
|
1034
|
+
remainingOverlap -= part.text.length;
|
|
906
1035
|
changed = true;
|
|
907
1036
|
continue;
|
|
908
1037
|
}
|
|
909
1038
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
changed = true;
|
|
914
|
-
if (text) next.push({ ...part, text });
|
|
915
|
-
continue;
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
remainingOverlap = "";
|
|
919
|
-
next.push(part);
|
|
1039
|
+
next.push({ ...part, text: part.text.slice(remainingOverlap) });
|
|
1040
|
+
remainingOverlap = 0;
|
|
1041
|
+
changed = true;
|
|
920
1042
|
}
|
|
921
1043
|
|
|
922
1044
|
return changed ? next : content;
|
|
@@ -925,10 +1047,14 @@ function trimReconnectTextAlreadyRendered(
|
|
|
925
1047
|
export function dedupeReconnectContentAgainstMessages(
|
|
926
1048
|
content: ContentPart[],
|
|
927
1049
|
messages: readonly unknown[],
|
|
928
|
-
options?: {
|
|
1050
|
+
options?: {
|
|
1051
|
+
suppressToolRepeats?: boolean;
|
|
1052
|
+
trimTailTextOverlap?: boolean;
|
|
1053
|
+
},
|
|
929
1054
|
): ContentPart[] {
|
|
930
1055
|
if (content.length === 0) return content;
|
|
931
1056
|
const snapshotDeduped = dedupePendingToolCallReplaysWithinContent(content);
|
|
1057
|
+
const reconnectPendingCounts = pendingToolCallCountsByName(snapshotDeduped);
|
|
932
1058
|
let changed = snapshotDeduped !== content;
|
|
933
1059
|
if (messages.length === 0) return changed ? snapshotDeduped : content;
|
|
934
1060
|
const { byId, latestAssistantByFingerprint, latestAssistantByName } =
|
|
@@ -1009,6 +1135,31 @@ export function dedupeReconnectContentAgainstMessages(
|
|
|
1009
1135
|
const latestByName = name
|
|
1010
1136
|
? latestAssistantByName.get(name)
|
|
1011
1137
|
: undefined;
|
|
1138
|
+
const reconnectPendingCount = name
|
|
1139
|
+
? (reconnectPendingCounts.get(name) ?? 0)
|
|
1140
|
+
: 0;
|
|
1141
|
+
const hasReaderLocalIdentity = Boolean(
|
|
1142
|
+
(id && toolCallIdIsReaderLocal(id)) ||
|
|
1143
|
+
(latestByName &&
|
|
1144
|
+
Array.from(latestByName.pendingIds).some(
|
|
1145
|
+
toolCallIdIsReaderLocal,
|
|
1146
|
+
)),
|
|
1147
|
+
);
|
|
1148
|
+
if (
|
|
1149
|
+
options?.suppressToolRepeats &&
|
|
1150
|
+
latestByName &&
|
|
1151
|
+
latestByName.pendingIds.size === 1 &&
|
|
1152
|
+
reconnectPendingCount === 1 &&
|
|
1153
|
+
hasReaderLocalIdentity &&
|
|
1154
|
+
latestByName.pendingRank >= reconnectRank
|
|
1155
|
+
) {
|
|
1156
|
+
// During reconnect -> live-adapter handoff both accumulators own
|
|
1157
|
+
// the same run. Their pre-tool-start activity cards can have
|
|
1158
|
+
// unrelated reader-local ids and no args fingerprint, so name +
|
|
1159
|
+
// pending progress is the only stable identity available.
|
|
1160
|
+
changed = true;
|
|
1161
|
+
return false;
|
|
1162
|
+
}
|
|
1012
1163
|
const matchesRenderedLocalId =
|
|
1013
1164
|
id && latestByName
|
|
1014
1165
|
? Array.from(latestByName.ids).some((renderedId) =>
|
|
@@ -1037,6 +1188,7 @@ export function dedupeReconnectContentAgainstMessages(
|
|
|
1037
1188
|
const textDeduped = trimReconnectTextAlreadyRendered(
|
|
1038
1189
|
filtered,
|
|
1039
1190
|
renderedAssistantText,
|
|
1191
|
+
{ trimTailOverlap: options?.trimTailTextOverlap },
|
|
1040
1192
|
);
|
|
1041
1193
|
if (textDeduped !== filtered) changed = true;
|
|
1042
1194
|
return changed ? textDeduped : content;
|
|
@@ -1151,19 +1303,40 @@ function contentHasVisibleReasoning(content: unknown): boolean {
|
|
|
1151
1303
|
});
|
|
1152
1304
|
}
|
|
1153
1305
|
|
|
1306
|
+
function contentHasUnresolvedToolCall(
|
|
1307
|
+
content: unknown,
|
|
1308
|
+
toolName?: string | null,
|
|
1309
|
+
): boolean {
|
|
1310
|
+
if (!Array.isArray(content)) return false;
|
|
1311
|
+
return content.some((part) => {
|
|
1312
|
+
if (!part || typeof part !== "object") return false;
|
|
1313
|
+
const candidate = part as {
|
|
1314
|
+
type?: unknown;
|
|
1315
|
+
toolName?: unknown;
|
|
1316
|
+
result?: unknown;
|
|
1317
|
+
};
|
|
1318
|
+
return (
|
|
1319
|
+
candidate.type === "tool-call" &&
|
|
1320
|
+
candidate.result === undefined &&
|
|
1321
|
+
(!toolName || candidate.toolName === toolName)
|
|
1322
|
+
);
|
|
1323
|
+
});
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1154
1326
|
export function shouldShowGlobalRunningStatus({
|
|
1155
1327
|
showRunningInUI,
|
|
1156
1328
|
runningActivityLabel,
|
|
1329
|
+
runningActivityTool,
|
|
1157
1330
|
latestMessage,
|
|
1158
1331
|
reconnectContent,
|
|
1159
1332
|
}: {
|
|
1160
1333
|
showRunningInUI: boolean;
|
|
1161
1334
|
runningActivityLabel: string | null | undefined;
|
|
1335
|
+
runningActivityTool?: string | null;
|
|
1162
1336
|
latestMessage: unknown;
|
|
1163
1337
|
reconnectContent: readonly ContentPart[];
|
|
1164
1338
|
}): boolean {
|
|
1165
1339
|
if (!showRunningInUI) return false;
|
|
1166
|
-
if (runningActivityLabel) return true;
|
|
1167
1340
|
|
|
1168
1341
|
const message =
|
|
1169
1342
|
latestMessage && typeof latestMessage === "object"
|
|
@@ -1172,6 +1345,30 @@ export function shouldShowGlobalRunningStatus({
|
|
|
1172
1345
|
const latestMessageHasReasoning =
|
|
1173
1346
|
message?.role === "assistant" &&
|
|
1174
1347
|
contentHasVisibleReasoning(message.content);
|
|
1348
|
+
const latestMessageHasUnresolvedTool =
|
|
1349
|
+
message?.role === "assistant" &&
|
|
1350
|
+
contentHasUnresolvedToolCall(message.content);
|
|
1351
|
+
const matchingActivityToolIsVisible = Boolean(
|
|
1352
|
+
runningActivityTool &&
|
|
1353
|
+
((message?.role === "assistant" &&
|
|
1354
|
+
contentHasUnresolvedToolCall(message.content, runningActivityTool)) ||
|
|
1355
|
+
contentHasUnresolvedToolCall(reconnectContent, runningActivityTool)),
|
|
1356
|
+
);
|
|
1357
|
+
|
|
1358
|
+
// A pending card for the same tool is already the running indicator.
|
|
1359
|
+
// Rendering its global activity label as well shows the logical call twice
|
|
1360
|
+
// (for example, `generate design` plus `Writing generate design...`).
|
|
1361
|
+
if (runningActivityLabel && matchingActivityToolIsVisible) {
|
|
1362
|
+
return false;
|
|
1363
|
+
}
|
|
1364
|
+
if (
|
|
1365
|
+
!runningActivityLabel &&
|
|
1366
|
+
(latestMessageHasUnresolvedTool ||
|
|
1367
|
+
contentHasUnresolvedToolCall(reconnectContent))
|
|
1368
|
+
) {
|
|
1369
|
+
return false;
|
|
1370
|
+
}
|
|
1371
|
+
if (runningActivityLabel) return true;
|
|
1175
1372
|
|
|
1176
1373
|
return (
|
|
1177
1374
|
!latestMessageHasReasoning && !contentHasVisibleReasoning(reconnectContent)
|
|
@@ -1432,6 +1629,17 @@ export interface AssistantChatProps {
|
|
|
1432
1629
|
historyReloadKey?: string | number | null;
|
|
1433
1630
|
/** Smooth the last assistant message while an external transcript is updating. */
|
|
1434
1631
|
externalStreaming?: boolean;
|
|
1632
|
+
/**
|
|
1633
|
+
* Optional host hooks for the inline `needsApproval` affordance beyond the
|
|
1634
|
+
* built-in Approve. Additive: omit entirely to keep today's default
|
|
1635
|
+
* behavior (Deny is local-only, no "Always allow" button). Code sessions
|
|
1636
|
+
* pass these through to the same `host.controlRun` commands their
|
|
1637
|
+
* standalone approval banner already uses (see CodeAgentsApp).
|
|
1638
|
+
*/
|
|
1639
|
+
approvalActions?: {
|
|
1640
|
+
onDeny?: (approvalKey: string) => void;
|
|
1641
|
+
onAlwaysAllow?: (approvalKey: string) => void;
|
|
1642
|
+
};
|
|
1435
1643
|
}
|
|
1436
1644
|
|
|
1437
1645
|
export const CHAT_STORAGE_PREFIX = "agent-chat:";
|
|
@@ -1655,6 +1863,7 @@ const AssistantChatInner = forwardRef<
|
|
|
1655
1863
|
onSlashCommand,
|
|
1656
1864
|
execMode,
|
|
1657
1865
|
onExecModeChange,
|
|
1866
|
+
approvalActions,
|
|
1658
1867
|
planModeDisabled,
|
|
1659
1868
|
planModeDisabledReason,
|
|
1660
1869
|
selectedModel,
|
|
@@ -2041,6 +2250,10 @@ const AssistantChatInner = forwardRef<
|
|
|
2041
2250
|
const reconnectCanMaterializeRef = useRef(false);
|
|
2042
2251
|
const reconnectAbortRef = useRef<AbortController | null>(null);
|
|
2043
2252
|
const reconnectAutoRecoveryCountRef = useRef(0);
|
|
2253
|
+
const reconnectOwnerMountedRef = useReconnectReaderOwner(
|
|
2254
|
+
reconnectRunIdRef,
|
|
2255
|
+
reconnectAbortRef,
|
|
2256
|
+
);
|
|
2044
2257
|
const [pendingReconnectRecovery, setPendingReconnectRecovery] =
|
|
2045
2258
|
useState<PendingReconnectRecovery | null>(null);
|
|
2046
2259
|
// Nuclear stop: user clicked stop. Clears the stop button/indicator AND
|
|
@@ -2386,6 +2599,7 @@ const AssistantChatInner = forwardRef<
|
|
|
2386
2599
|
const startReconnectToRun = useCallback(
|
|
2387
2600
|
(runInfo: ActiveRunLookup): boolean => {
|
|
2388
2601
|
if (
|
|
2602
|
+
!reconnectOwnerMountedRef.current ||
|
|
2389
2603
|
!threadId ||
|
|
2390
2604
|
!runInfo.runId ||
|
|
2391
2605
|
(runInfo.status !== "running" && !isReplayableTerminalRun(runInfo))
|
|
@@ -2596,6 +2810,12 @@ const AssistantChatInner = forwardRef<
|
|
|
2596
2810
|
rafPending = true;
|
|
2597
2811
|
requestAnimationFrame(() => {
|
|
2598
2812
|
rafPending = false;
|
|
2813
|
+
if (
|
|
2814
|
+
!reconnectOwnerMountedRef.current ||
|
|
2815
|
+
reconnectRunIdRef.current !== runId
|
|
2816
|
+
) {
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2599
2819
|
setReconnectContent(latestSnapshot);
|
|
2600
2820
|
});
|
|
2601
2821
|
};
|
|
@@ -2665,6 +2885,11 @@ const AssistantChatInner = forwardRef<
|
|
|
2665
2885
|
clearInterval(idleCheck);
|
|
2666
2886
|
}
|
|
2667
2887
|
|
|
2888
|
+
// A newer reader, live adapter, stop action, or component unmount took
|
|
2889
|
+
// ownership while this async loop was unwinding. Do not let the stale
|
|
2890
|
+
// generation refresh/import or update reconnect state afterwards.
|
|
2891
|
+
if (reconnectRunIdRef.current !== runId) return;
|
|
2892
|
+
|
|
2668
2893
|
if (noProgressDuringReconnect && reconnectRunIdRef.current === runId) {
|
|
2669
2894
|
const reconnectErrorCode =
|
|
2670
2895
|
reconnectTerminalReason === "run_timeout"
|
|
@@ -3630,6 +3855,7 @@ const AssistantChatInner = forwardRef<
|
|
|
3630
3855
|
const stillNeeded =
|
|
3631
3856
|
dedupeReconnectContentAgainstMessages(reconnectContent, messages, {
|
|
3632
3857
|
suppressToolRepeats: true,
|
|
3858
|
+
trimTailTextOverlap: true,
|
|
3633
3859
|
}).length > 0;
|
|
3634
3860
|
if (!stillNeeded) {
|
|
3635
3861
|
setReconnectContent([]);
|
|
@@ -4236,7 +4462,11 @@ const AssistantChatInner = forwardRef<
|
|
|
4236
4462
|
const visibleReconnectContent = dedupeReconnectContentAgainstMessages(
|
|
4237
4463
|
reconnectContent,
|
|
4238
4464
|
messages,
|
|
4239
|
-
{
|
|
4465
|
+
{
|
|
4466
|
+
suppressToolRepeats: adapterHandoffPending,
|
|
4467
|
+
trimTailTextOverlap:
|
|
4468
|
+
adapterHandoffPending || reconnectTailOnlyRef.current,
|
|
4469
|
+
},
|
|
4240
4470
|
);
|
|
4241
4471
|
const chatScrollResetKey = `${tabId ?? ""}:${threadId ?? ""}`;
|
|
4242
4472
|
|
|
@@ -4262,11 +4492,18 @@ const AssistantChatInner = forwardRef<
|
|
|
4262
4492
|
);
|
|
4263
4493
|
const latestMessage = messages[messages.length - 1];
|
|
4264
4494
|
const latestMessageRole = latestMessage?.role;
|
|
4495
|
+
const reconnectStatusContent =
|
|
4496
|
+
visibleReconnectContent.length > 0
|
|
4497
|
+
? visibleReconnectContent
|
|
4498
|
+
: reconnectContent.length === 0
|
|
4499
|
+
? reconnectActivityContent
|
|
4500
|
+
: [];
|
|
4265
4501
|
const showGlobalRunningStatus = shouldShowGlobalRunningStatus({
|
|
4266
4502
|
showRunningInUI,
|
|
4267
4503
|
runningActivityLabel,
|
|
4504
|
+
runningActivityTool,
|
|
4268
4505
|
latestMessage,
|
|
4269
|
-
reconnectContent:
|
|
4506
|
+
reconnectContent: reconnectStatusContent,
|
|
4270
4507
|
});
|
|
4271
4508
|
const latestAssistantWasPlan =
|
|
4272
4509
|
latestMessageRole === "assistant" &&
|
|
@@ -4415,8 +4652,12 @@ const AssistantChatInner = forwardRef<
|
|
|
4415
4652
|
),
|
|
4416
4653
|
} as Parameters<typeof threadRuntime.append>[0]);
|
|
4417
4654
|
},
|
|
4655
|
+
...(approvalActions?.onDeny ? { onDeny: approvalActions.onDeny } : {}),
|
|
4656
|
+
...(approvalActions?.onAlwaysAllow
|
|
4657
|
+
? { onAlwaysAllow: approvalActions.onAlwaysAllow }
|
|
4658
|
+
: {}),
|
|
4418
4659
|
}),
|
|
4419
|
-
[appendThreadMessage, execMode, markOptimisticRunning],
|
|
4660
|
+
[appendThreadMessage, execMode, markOptimisticRunning, approvalActions],
|
|
4420
4661
|
);
|
|
4421
4662
|
|
|
4422
4663
|
return (
|
|
@@ -4964,33 +5205,33 @@ const AssistantChatInner = forwardRef<
|
|
|
4964
5205
|
onAttachmentError={setComposerError}
|
|
4965
5206
|
extraActionButton={
|
|
4966
5207
|
contextXRayEnabled ||
|
|
4967
|
-
composerExtraActionButton
|
|
4968
|
-
showRunningInUI ? (
|
|
5208
|
+
composerExtraActionButton ? (
|
|
4969
5209
|
<>
|
|
4970
5210
|
{contextXRayEnabled && (
|
|
4971
5211
|
<ContextMeter threadId={threadId} />
|
|
4972
5212
|
)}
|
|
4973
5213
|
{composerExtraActionButton}
|
|
4974
|
-
{showRunningInUI && (
|
|
4975
|
-
<Tooltip>
|
|
4976
|
-
<TooltipTrigger asChild>
|
|
4977
|
-
<button
|
|
4978
|
-
type="button"
|
|
4979
|
-
onClick={() => stopActiveRun()}
|
|
4980
|
-
aria-label="Stop response"
|
|
4981
|
-
className="shrink-0 flex h-7 w-7 cursor-pointer items-center justify-center rounded-full bg-primary text-primary-foreground shadow-sm transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
4982
|
-
>
|
|
4983
|
-
<IconPlayerStopFilled className="h-3 w-3" />
|
|
4984
|
-
</button>
|
|
4985
|
-
</TooltipTrigger>
|
|
4986
|
-
<TooltipContent>
|
|
4987
|
-
Stop response
|
|
4988
|
-
</TooltipContent>
|
|
4989
|
-
</Tooltip>
|
|
4990
|
-
)}
|
|
4991
5214
|
</>
|
|
4992
5215
|
) : undefined
|
|
4993
5216
|
}
|
|
5217
|
+
stopButton={
|
|
5218
|
+
showRunningInUI ? (
|
|
5219
|
+
<Tooltip>
|
|
5220
|
+
<TooltipTrigger asChild>
|
|
5221
|
+
<button
|
|
5222
|
+
type="button"
|
|
5223
|
+
onClick={() => stopActiveRun()}
|
|
5224
|
+
aria-label="Stop response"
|
|
5225
|
+
data-agent-composer-slot="stop-button"
|
|
5226
|
+
className="shrink-0 flex h-7 w-7 cursor-pointer items-center justify-center rounded-full bg-primary text-primary-foreground shadow-sm transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
5227
|
+
>
|
|
5228
|
+
<IconPlayerStopFilled className="h-3 w-3" />
|
|
5229
|
+
</button>
|
|
5230
|
+
</TooltipTrigger>
|
|
5231
|
+
<TooltipContent>Stop response</TooltipContent>
|
|
5232
|
+
</Tooltip>
|
|
5233
|
+
) : undefined
|
|
5234
|
+
}
|
|
4994
5235
|
/>
|
|
4995
5236
|
</>
|
|
4996
5237
|
)}
|