@agent-native/core 0.32.2 → 0.32.17
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/README.md +3 -1
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +48 -10
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts +12 -0
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +104 -6
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/cli/app-skill.js +2 -2
- package/dist/cli/app-skill.js.map +1 -1
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +6 -1
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/code-agent-output-smoother.d.ts +7 -0
- package/dist/cli/code-agent-output-smoother.d.ts.map +1 -0
- package/dist/cli/code-agent-output-smoother.js +111 -0
- package/dist/cli/code-agent-output-smoother.js.map +1 -0
- package/dist/cli/connect.d.ts.map +1 -1
- package/dist/cli/connect.js +5 -0
- package/dist/cli/connect.js.map +1 -1
- package/dist/cli/migrate.d.ts.map +1 -1
- package/dist/cli/migrate.js +17 -42
- package/dist/cli/migrate.js.map +1 -1
- package/dist/cli/skills.d.ts +23 -2
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +405 -41
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/templates-meta.d.ts.map +1 -1
- package/dist/cli/templates-meta.js +7 -105
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +41 -7
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AgentTaskCard.d.ts.map +1 -1
- package/dist/client/AgentTaskCard.js +0 -28
- package/dist/client/AgentTaskCard.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +8 -23
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +359 -205
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +254 -14
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +14 -9
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-chat.d.ts +24 -0
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +73 -0
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/assistant-ui-recovery.d.ts +34 -0
- package/dist/client/assistant-ui-recovery.d.ts.map +1 -0
- package/dist/client/assistant-ui-recovery.js +122 -0
- package/dist/client/assistant-ui-recovery.js.map +1 -0
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +7 -1
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +7 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +22 -2
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/frame-protocol.d.ts +6 -2
- package/dist/client/frame-protocol.d.ts.map +1 -1
- package/dist/client/frame-protocol.js.map +1 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +2 -1
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/progress/RunsTray.d.ts +13 -3
- package/dist/client/progress/RunsTray.d.ts.map +1 -1
- package/dist/client/progress/RunsTray.js +105 -36
- package/dist/client/progress/RunsTray.js.map +1 -1
- package/dist/client/route-warmup.d.ts +61 -0
- package/dist/client/route-warmup.d.ts.map +1 -0
- package/dist/client/route-warmup.js +456 -0
- package/dist/client/route-warmup.js.map +1 -0
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +2 -1
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +5 -0
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +10 -4
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/use-action.d.ts +1 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +22 -4
- package/dist/client/use-action.js.map +1 -1
- package/dist/code-agents/background-run.d.ts +2 -0
- package/dist/code-agents/background-run.d.ts.map +1 -1
- package/dist/code-agents/background-run.js.map +1 -1
- package/dist/db/client.d.ts +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +25 -1
- package/dist/db/client.js.map +1 -1
- package/dist/deploy/build.d.ts +4 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +171 -14
- package/dist/deploy/build.js.map +1 -1
- package/dist/deploy/immutable-assets.d.ts +1 -0
- package/dist/deploy/immutable-assets.d.ts.map +1 -1
- package/dist/deploy/immutable-assets.js +1 -0
- package/dist/deploy/immutable-assets.js.map +1 -1
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/connect-route.d.ts.map +1 -1
- package/dist/mcp/connect-route.js +118 -82
- package/dist/mcp/connect-route.js.map +1 -1
- package/dist/progress/routes.d.ts.map +1 -1
- package/dist/progress/routes.js +1 -0
- package/dist/progress/routes.js.map +1 -1
- package/dist/progress/store.d.ts +13 -0
- package/dist/progress/store.d.ts.map +1 -1
- package/dist/progress/store.js +18 -0
- package/dist/progress/store.js.map +1 -1
- package/dist/progress/types.d.ts +2 -0
- package/dist/progress/types.d.ts.map +1 -1
- package/dist/progress/types.js.map +1 -1
- package/dist/scripts/db/wipe-leaked-builder-keys.d.ts +2 -2
- package/dist/scripts/db/wipe-leaked-builder-keys.d.ts.map +1 -1
- package/dist/scripts/db/wipe-leaked-builder-keys.js +14 -3
- package/dist/scripts/db/wipe-leaked-builder-keys.js.map +1 -1
- package/dist/server/action-routes.d.ts +1 -0
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +36 -2
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +123 -25
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-discovery.d.ts.map +1 -1
- package/dist/server/agent-discovery.js +14 -1
- package/dist/server/agent-discovery.js.map +1 -1
- package/dist/server/agent-teams-run-queue.d.ts +80 -0
- package/dist/server/agent-teams-run-queue.d.ts.map +1 -0
- package/dist/server/agent-teams-run-queue.js +208 -0
- package/dist/server/agent-teams-run-queue.js.map +1 -0
- package/dist/server/agent-teams.d.ts +67 -0
- package/dist/server/agent-teams.d.ts.map +1 -1
- package/dist/server/agent-teams.js +607 -180
- package/dist/server/agent-teams.js.map +1 -1
- package/dist/server/auth-marketing.d.ts.map +1 -1
- package/dist/server/auth-marketing.js +0 -64
- package/dist/server/auth-marketing.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +67 -14
- package/dist/server/auth.js.map +1 -1
- package/dist/server/builder-browser.d.ts +12 -2
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +24 -0
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +66 -5
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +10 -0
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +82 -3
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/csrf.d.ts.map +1 -1
- package/dist/server/csrf.js +3 -0
- package/dist/server/csrf.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts +1 -0
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +14 -1
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/self-dispatch.d.ts +44 -0
- package/dist/server/self-dispatch.d.ts.map +1 -0
- package/dist/server/self-dispatch.js +113 -0
- package/dist/server/self-dispatch.js.map +1 -0
- package/dist/server/social-og-image.d.ts +14 -0
- package/dist/server/social-og-image.d.ts.map +1 -0
- package/dist/server/social-og-image.js +251 -0
- package/dist/server/social-og-image.js.map +1 -0
- package/dist/server/ssr-handler.d.ts +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +27 -11
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/shared/cache-control.d.ts +7 -0
- package/dist/shared/cache-control.d.ts.map +1 -1
- package/dist/shared/cache-control.js +7 -0
- package/dist/shared/cache-control.js.map +1 -1
- package/dist/shared/index.d.ts +1 -1
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +1 -1
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/route-warmup-config.d.ts +28 -0
- package/dist/shared/route-warmup-config.d.ts.map +1 -0
- package/dist/shared/route-warmup-config.js +58 -0
- package/dist/shared/route-warmup-config.js.map +1 -0
- package/dist/shared/social-meta.d.ts +5 -0
- package/dist/shared/social-meta.d.ts.map +1 -1
- package/dist/shared/social-meta.js +36 -2
- package/dist/shared/social-meta.js.map +1 -1
- package/dist/shared/streaming-text-smoothing.d.ts +12 -0
- package/dist/shared/streaming-text-smoothing.d.ts.map +1 -0
- package/dist/shared/streaming-text-smoothing.js +52 -0
- package/dist/shared/streaming-text-smoothing.js.map +1 -0
- package/dist/styles/agent-native.css +4 -4
- package/dist/templates/default/AGENTS.md +9 -4
- package/dist/templates/default/DEVELOPING.md +15 -1
- package/dist/templates/workspace-core/AGENTS.md +7 -3
- package/dist/templates/workspace-root/AGENTS.md +7 -3
- package/dist/vite/client.d.ts +13 -0
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +26 -0
- package/dist/vite/client.js.map +1 -1
- package/dist/vite/index.d.ts +1 -0
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js.map +1 -1
- package/docs/content/client.md +62 -1
- package/docs/content/code-agents-ui.md +6 -13
- package/docs/content/context-awareness.md +186 -21
- package/docs/content/deployment.md +8 -11
- package/docs/content/dispatch.md +1 -1
- package/docs/content/external-agents.md +32 -2
- package/docs/content/migration-workbench.md +4 -21
- package/docs/content/multi-app-workspace.md +1 -1
- package/docs/content/recurring-jobs.md +1 -1
- package/docs/content/security.md +0 -1
- package/docs/content/sharing.md +1 -3
- package/docs/content/skills-guide.md +12 -10
- package/docs/content/template-assets.md +21 -1
- package/docs/content/template-design.md +23 -5
- package/docs/content/template-dispatch.md +1 -1
- package/package.json +2 -1
- package/src/templates/default/AGENTS.md +9 -4
- package/src/templates/default/DEVELOPING.md +15 -1
- package/src/templates/workspace-core/AGENTS.md +7 -3
- package/src/templates/workspace-root/AGENTS.md +7 -3
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React, { useState, useRef, useEffect, useCallback, useMemo, forwardRef, useImperativeHandle, } from "react";
|
|
3
|
-
import { AssistantRuntimeProvider, useLocalRuntime, useThreadRuntime, useThread, useAui, useComposer, useComposerRuntime, useMessageRuntime, ThreadPrimitive, MessagePrimitive, } from "@assistant-ui/react";
|
|
3
|
+
import { AssistantRuntimeProvider, useLocalRuntime, useThreadRuntime, useThread, useAui, useComposer, useComposerRuntime, useMessagePartText, useMessageRuntime, ThreadPrimitive, MessagePrimitive, } from "@assistant-ui/react";
|
|
4
4
|
import { CompositeAttachmentAdapter } from "@assistant-ui/react";
|
|
5
|
-
import { MarkdownTextPrimitive } from "@assistant-ui/react-markdown";
|
|
6
5
|
import ReactMarkdown, { defaultUrlTransform } from "react-markdown";
|
|
7
6
|
import remarkGfm from "remark-gfm";
|
|
8
7
|
import { createAgentChatAdapter, } from "./agent-chat-adapter.js";
|
|
8
|
+
import { appendAgentChatContextToMessage, formatAgentChatContextItemsForPrompt, normalizeAgentChatContextItem, } from "./agent-chat.js";
|
|
9
9
|
import { useAgentDynamicSuggestions, } from "./dynamic-suggestions.js";
|
|
10
|
+
import { initialSmoothStreamingGraphemeCount, SMOOTH_STREAMING_COMMIT_INTERVAL_MS, smoothStreamingPunctuationDelayMs, smoothStreamingRevealCount, splitStreamingTextGraphemes, } from "../shared/streaming-text-smoothing.js";
|
|
10
11
|
import { getActiveRun } from "./active-run-state.js";
|
|
11
12
|
import { AgentAutoContinueSignal, readSSEStreamRaw, } from "./sse-event-processor.js";
|
|
12
13
|
import { captureError } from "./analytics.js";
|
|
14
|
+
import { AssistantMessageListErrorBoundary, AssistantUiStaleIndexErrorBoundary, } from "./assistant-ui-recovery.js";
|
|
13
15
|
import { cn } from "./utils.js";
|
|
14
16
|
import { writeClipboardText } from "./clipboard.js";
|
|
15
17
|
import { useNearBottomAutoscroll } from "./conversation/index.js";
|
|
@@ -31,6 +33,7 @@ import { AgentComposerFrame } from "./composer/AgentComposerFrame.js";
|
|
|
31
33
|
import { isPastedTextAttachmentName } from "./composer/pasted-text.js";
|
|
32
34
|
import { PastedTextChip } from "./composer/PastedTextChip.js";
|
|
33
35
|
import { IconMessage, IconX, IconPlayerStop, IconCheck, IconChevronDown, IconCopy, IconTerminal, IconLoader2, IconCircleX, IconSquareFilled, IconClock, IconFile, IconFolder, IconFileText, IconCheckbox, IconMail, IconUser, IconPresentation, IconStack2, IconMessageChatbot, IconLock, IconArrowBackUp, IconExternalLink, IconDots, IconGitFork, IconId, IconQuote, IconGauge, IconArrowRight, IconSettings, IconAlertTriangle, IconRefresh, IconPlayerPlay, IconClipboardList, IconSearch, IconArrowsMaximize, IconArrowsMinimize, IconPlus, } from "@tabler/icons-react";
|
|
36
|
+
export { AssistantMessageListErrorBoundary, AssistantUiStaleIndexErrorBoundary, assistantUiRecoverableRenderErrorKind, isAssistantUiRecoverableRenderError, isAssistantUiStaleIndexError, } from "./assistant-ui-recovery.js";
|
|
34
37
|
class DownscalingImageAttachmentAdapter {
|
|
35
38
|
accept = "image/*";
|
|
36
39
|
async add(state) {
|
|
@@ -340,6 +343,9 @@ const markdownStyles = `
|
|
|
340
343
|
.agent-markdown table { border-collapse: collapse; margin: 0.5em 0; font-size: 0.875em; }
|
|
341
344
|
.agent-markdown th, .agent-markdown td { border: 1px solid hsl(var(--border, 0 0% 20%)); padding: 0.35em 0.65em; text-align: left; }
|
|
342
345
|
.agent-markdown th { font-weight: 600; background: hsl(var(--muted, 0 0% 15%)); color: hsl(var(--foreground, 0 0% 90%)); }
|
|
346
|
+
.agent-markdown[data-streaming="true"] > :last-child:not(pre):not(table)::after { content: ""; display: inline-block; width: 0.42em; height: 1em; margin-left: 0.12em; border-radius: 999px; background: currentColor; opacity: 0.35; transform: translateY(0.16em); animation: agent-markdown-stream-caret 1.15s ease-in-out infinite; }
|
|
347
|
+
@keyframes agent-markdown-stream-caret { 0%, 100% { opacity: 0.2; } 50% { opacity: 0.58; } }
|
|
348
|
+
@media (prefers-reduced-motion: reduce) { .agent-markdown[data-streaming="true"] > :last-child:not(pre):not(table)::after { animation: none; opacity: 0.28; } }
|
|
343
349
|
`;
|
|
344
350
|
/**
|
|
345
351
|
* Pending selection context — written to application_state when the user
|
|
@@ -735,17 +741,171 @@ function markdownUrlTransform(value) {
|
|
|
735
741
|
return value;
|
|
736
742
|
return defaultUrlTransform(value);
|
|
737
743
|
}
|
|
738
|
-
|
|
744
|
+
const TextStreamingContext = React.createContext(false);
|
|
745
|
+
function usePrefersReducedMotion() {
|
|
746
|
+
const [prefersReducedMotion, setPrefersReducedMotion] = useState(() => typeof window !== "undefined" && window.matchMedia
|
|
747
|
+
? window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
748
|
+
: false);
|
|
749
|
+
useEffect(() => {
|
|
750
|
+
if (typeof window === "undefined" || !window.matchMedia)
|
|
751
|
+
return undefined;
|
|
752
|
+
const media = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
753
|
+
const handleChange = () => setPrefersReducedMotion(media.matches);
|
|
754
|
+
handleChange();
|
|
755
|
+
if (typeof media.addEventListener === "function") {
|
|
756
|
+
media.addEventListener("change", handleChange);
|
|
757
|
+
return () => media.removeEventListener("change", handleChange);
|
|
758
|
+
}
|
|
759
|
+
media.addListener(handleChange);
|
|
760
|
+
return () => media.removeListener(handleChange);
|
|
761
|
+
}, []);
|
|
762
|
+
return prefersReducedMotion;
|
|
763
|
+
}
|
|
764
|
+
function sliceGraphemes(targetText, graphemes, count) {
|
|
765
|
+
if (count >= graphemes.length)
|
|
766
|
+
return targetText;
|
|
767
|
+
if (count <= 0)
|
|
768
|
+
return "";
|
|
769
|
+
return graphemes.slice(0, count).join("");
|
|
770
|
+
}
|
|
771
|
+
function useSmoothStreamingText(targetText, streaming, resetKey) {
|
|
772
|
+
const prefersReducedMotion = usePrefersReducedMotion();
|
|
773
|
+
const [visibleText, setVisibleText] = useState(() => {
|
|
774
|
+
if (!streaming || prefersReducedMotion)
|
|
775
|
+
return targetText;
|
|
776
|
+
const graphemes = splitStreamingTextGraphemes(targetText);
|
|
777
|
+
return sliceGraphemes(targetText, graphemes, initialSmoothStreamingGraphemeCount(graphemes));
|
|
778
|
+
});
|
|
779
|
+
const visibleTextRef = useRef(visibleText);
|
|
780
|
+
const visibleCountRef = useRef(splitStreamingTextGraphemes(visibleText).length);
|
|
781
|
+
const targetTextRef = useRef(targetText);
|
|
782
|
+
const targetGraphemesRef = useRef(splitStreamingTextGraphemes(targetText));
|
|
783
|
+
const frameRef = useRef(null);
|
|
784
|
+
const lastCommitAtRef = useRef(0);
|
|
785
|
+
const pauseUntilRef = useRef(0);
|
|
786
|
+
const resetKeyRef = useRef(resetKey);
|
|
787
|
+
const stepRef = useRef(() => { });
|
|
788
|
+
const commitVisibleCount = useCallback((nextCount) => {
|
|
789
|
+
const graphemes = targetGraphemesRef.current;
|
|
790
|
+
const boundedCount = Math.max(0, Math.min(nextCount, graphemes.length));
|
|
791
|
+
const nextText = sliceGraphemes(targetTextRef.current, graphemes, boundedCount);
|
|
792
|
+
visibleCountRef.current = boundedCount;
|
|
793
|
+
if (visibleTextRef.current !== nextText) {
|
|
794
|
+
visibleTextRef.current = nextText;
|
|
795
|
+
setVisibleText(nextText);
|
|
796
|
+
}
|
|
797
|
+
}, []);
|
|
798
|
+
const cancelFrame = useCallback(() => {
|
|
799
|
+
if (frameRef.current != null &&
|
|
800
|
+
typeof window !== "undefined" &&
|
|
801
|
+
typeof window.cancelAnimationFrame === "function") {
|
|
802
|
+
window.cancelAnimationFrame(frameRef.current);
|
|
803
|
+
}
|
|
804
|
+
frameRef.current = null;
|
|
805
|
+
pauseUntilRef.current = 0;
|
|
806
|
+
}, []);
|
|
807
|
+
const scheduleFrame = useCallback(() => {
|
|
808
|
+
if (frameRef.current != null)
|
|
809
|
+
return;
|
|
810
|
+
if (typeof window === "undefined" ||
|
|
811
|
+
typeof window.requestAnimationFrame !== "function") {
|
|
812
|
+
commitVisibleCount(targetGraphemesRef.current.length);
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
frameRef.current = window.requestAnimationFrame((time) => {
|
|
816
|
+
frameRef.current = null;
|
|
817
|
+
stepRef.current(time);
|
|
818
|
+
});
|
|
819
|
+
}, [commitVisibleCount]);
|
|
820
|
+
stepRef.current = (time) => {
|
|
821
|
+
const targetGraphemes = targetGraphemesRef.current;
|
|
822
|
+
const backlog = targetGraphemes.length - visibleCountRef.current;
|
|
823
|
+
if (backlog <= 0) {
|
|
824
|
+
pauseUntilRef.current = 0;
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
if (pauseUntilRef.current > time) {
|
|
828
|
+
scheduleFrame();
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
const lastCommitAt = lastCommitAtRef.current || time - SMOOTH_STREAMING_COMMIT_INTERVAL_MS;
|
|
832
|
+
if (time - lastCommitAt < SMOOTH_STREAMING_COMMIT_INTERVAL_MS &&
|
|
833
|
+
backlog > 1) {
|
|
834
|
+
scheduleFrame();
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
const revealCount = smoothStreamingRevealCount({
|
|
838
|
+
backlog,
|
|
839
|
+
elapsedMs: Math.min(120, Math.max(8, time - lastCommitAt)),
|
|
840
|
+
});
|
|
841
|
+
if (revealCount > 0) {
|
|
842
|
+
const nextCount = visibleCountRef.current + revealCount;
|
|
843
|
+
commitVisibleCount(nextCount);
|
|
844
|
+
lastCommitAtRef.current = time;
|
|
845
|
+
const nextBacklog = targetGraphemes.length - visibleCountRef.current;
|
|
846
|
+
const pauseMs = smoothStreamingPunctuationDelayMs(targetGraphemes[visibleCountRef.current - 1], nextBacklog);
|
|
847
|
+
pauseUntilRef.current = pauseMs > 0 ? time + pauseMs : 0;
|
|
848
|
+
}
|
|
849
|
+
if (visibleCountRef.current < targetGraphemes.length) {
|
|
850
|
+
scheduleFrame();
|
|
851
|
+
}
|
|
852
|
+
else {
|
|
853
|
+
pauseUntilRef.current = 0;
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
useEffect(() => {
|
|
857
|
+
const targetGraphemes = splitStreamingTextGraphemes(targetText);
|
|
858
|
+
targetTextRef.current = targetText;
|
|
859
|
+
targetGraphemesRef.current = targetGraphemes;
|
|
860
|
+
const keyChanged = resetKeyRef.current !== resetKey;
|
|
861
|
+
resetKeyRef.current = resetKey;
|
|
862
|
+
if (!streaming || prefersReducedMotion) {
|
|
863
|
+
cancelFrame();
|
|
864
|
+
commitVisibleCount(targetGraphemes.length);
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
const visibleNoLongerMatchesTarget = visibleTextRef.current.length > 0 &&
|
|
868
|
+
!targetText.startsWith(visibleTextRef.current);
|
|
869
|
+
if (keyChanged ||
|
|
870
|
+
visibleNoLongerMatchesTarget ||
|
|
871
|
+
visibleCountRef.current > targetGraphemes.length) {
|
|
872
|
+
commitVisibleCount(initialSmoothStreamingGraphemeCount(targetGraphemes));
|
|
873
|
+
lastCommitAtRef.current = 0;
|
|
874
|
+
pauseUntilRef.current = 0;
|
|
875
|
+
}
|
|
876
|
+
if (visibleCountRef.current < targetGraphemes.length) {
|
|
877
|
+
scheduleFrame();
|
|
878
|
+
}
|
|
879
|
+
}, [
|
|
880
|
+
targetText,
|
|
881
|
+
streaming,
|
|
882
|
+
prefersReducedMotion,
|
|
883
|
+
resetKey,
|
|
884
|
+
cancelFrame,
|
|
885
|
+
commitVisibleCount,
|
|
886
|
+
scheduleFrame,
|
|
887
|
+
]);
|
|
888
|
+
useEffect(() => cancelFrame, [cancelFrame]);
|
|
889
|
+
return visibleText;
|
|
890
|
+
}
|
|
891
|
+
function SmoothMarkdownText({ text, streaming, resetKey, statusType = "complete", }) {
|
|
739
892
|
useEffect(() => {
|
|
740
893
|
injectMarkdownStyles();
|
|
741
894
|
}, []);
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
895
|
+
const visibleText = useSmoothStreamingText(text, streaming, resetKey);
|
|
896
|
+
const isVisuallyStreaming = streaming && visibleText !== text;
|
|
897
|
+
return (_jsx("div", { className: "agent-markdown break-words", "data-status": statusType, "data-streaming": isVisuallyStreaming ? "true" : undefined, children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], components: markdownComponents, urlTransform: markdownUrlTransform, children: visibleText }) }));
|
|
898
|
+
}
|
|
899
|
+
function MarkdownText() {
|
|
900
|
+
const textPart = useMessagePartText();
|
|
901
|
+
const messageRuntime = useMessageRuntime();
|
|
902
|
+
const message = messageRuntime.getState();
|
|
903
|
+
const thread = useThread();
|
|
904
|
+
const textStreaming = React.useContext(TextStreamingContext);
|
|
905
|
+
const lastMessage = thread.messages[thread.messages.length - 1];
|
|
906
|
+
const isLastAssistantMessage = message.role === "assistant" && lastMessage?.id === message.id;
|
|
907
|
+
const statusType = textPart.status?.type ?? message.status?.type ?? "complete";
|
|
908
|
+
return (_jsx(SmoothMarkdownText, { text: textPart.text, streaming: textStreaming && isLastAssistantMessage, resetKey: `${message.id}:${statusType}`, statusType: statusType }));
|
|
749
909
|
}
|
|
750
910
|
// ─── Composer Attachment Preview ─────────────────────────────────────────────
|
|
751
911
|
function getImageAttachmentSrc(attachment) {
|
|
@@ -1068,7 +1228,7 @@ function ReconnectStreamMessage({ content }) {
|
|
|
1068
1228
|
const chatRunning = React.useContext(ChatRunningContext);
|
|
1069
1229
|
return (_jsx("div", { className: "flex justify-start", children: _jsx("div", { className: "max-w-[95%] text-sm leading-relaxed text-foreground space-y-1", children: content.map((part, i) => {
|
|
1070
1230
|
if (part.type === "text") {
|
|
1071
|
-
return (_jsx(
|
|
1231
|
+
return (_jsx(SmoothMarkdownText, { text: part.text, streaming: chatRunning, resetKey: `reconnect-text-${i}`, statusType: chatRunning ? "running" : "complete" }, `reconnect-text-${i}`));
|
|
1072
1232
|
}
|
|
1073
1233
|
if (part.type === "tool-call") {
|
|
1074
1234
|
return (_jsx(ToolCallDisplay, { toolName: part.toolName, argsText: part.argsText, args: part.args, result: part.result, mcpApp: part.mcpApp, isRunning: part.result === undefined && chatRunning }, `reconnect-tool-${i}`));
|
|
@@ -1151,74 +1311,6 @@ function UserMessageText({ text }) {
|
|
|
1151
1311
|
export function displayableUserMessageText(text) {
|
|
1152
1312
|
return text.replace(/<context>[\s\S]*?<\/context>\n?/g, "").trim();
|
|
1153
1313
|
}
|
|
1154
|
-
export function isAssistantUiStaleIndexError(error) {
|
|
1155
|
-
const message = error instanceof Error ? error.message : String(error ?? "");
|
|
1156
|
-
return /^tapClientLookup: Index \d+ out of bounds \(length: \d+\)$/.test(message);
|
|
1157
|
-
}
|
|
1158
|
-
export class AssistantUiStaleIndexErrorBoundary extends React.Component {
|
|
1159
|
-
state = {
|
|
1160
|
-
error: null,
|
|
1161
|
-
retryToken: 0,
|
|
1162
|
-
};
|
|
1163
|
-
retryTimer = null;
|
|
1164
|
-
static getDerivedStateFromError(error) {
|
|
1165
|
-
return {
|
|
1166
|
-
error: error instanceof Error ? error : new Error(String(error ?? "")),
|
|
1167
|
-
};
|
|
1168
|
-
}
|
|
1169
|
-
componentDidCatch(error, info) {
|
|
1170
|
-
if (!isAssistantUiStaleIndexError(error))
|
|
1171
|
-
return;
|
|
1172
|
-
captureError(error, {
|
|
1173
|
-
tags: {
|
|
1174
|
-
component: this.props.componentName ?? "AssistantChat",
|
|
1175
|
-
recoverable: "assistant-ui-stale-message-index",
|
|
1176
|
-
},
|
|
1177
|
-
extra: {
|
|
1178
|
-
resetKey: this.props.resetKey,
|
|
1179
|
-
componentStack: info.componentStack,
|
|
1180
|
-
},
|
|
1181
|
-
});
|
|
1182
|
-
if (this.retryTimer)
|
|
1183
|
-
return;
|
|
1184
|
-
this.retryTimer = setTimeout(() => {
|
|
1185
|
-
this.retryTimer = null;
|
|
1186
|
-
this.setState((state) => {
|
|
1187
|
-
if (!state.error || !isAssistantUiStaleIndexError(state.error)) {
|
|
1188
|
-
return null;
|
|
1189
|
-
}
|
|
1190
|
-
return { error: null, retryToken: state.retryToken + 1 };
|
|
1191
|
-
});
|
|
1192
|
-
}, 0);
|
|
1193
|
-
}
|
|
1194
|
-
componentDidUpdate(prevProps) {
|
|
1195
|
-
if (this.state.error &&
|
|
1196
|
-
isAssistantUiStaleIndexError(this.state.error) &&
|
|
1197
|
-
prevProps.resetKey !== this.props.resetKey) {
|
|
1198
|
-
this.setState((state) => ({
|
|
1199
|
-
error: null,
|
|
1200
|
-
retryToken: state.retryToken + 1,
|
|
1201
|
-
}));
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
componentWillUnmount() {
|
|
1205
|
-
if (this.retryTimer) {
|
|
1206
|
-
clearTimeout(this.retryTimer);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
render() {
|
|
1210
|
-
if (this.state.error) {
|
|
1211
|
-
if (!isAssistantUiStaleIndexError(this.state.error)) {
|
|
1212
|
-
throw this.state.error;
|
|
1213
|
-
}
|
|
1214
|
-
return null;
|
|
1215
|
-
}
|
|
1216
|
-
return (_jsx(React.Fragment, { children: this.props.children }, `${this.props.resetKey}:${this.state.retryToken}`));
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
export function AssistantMessageListErrorBoundary({ resetKey, children, }) {
|
|
1220
|
-
return (_jsx(AssistantUiStaleIndexErrorBoundary, { resetKey: resetKey, componentName: "AssistantMessageList", children: children }));
|
|
1221
|
-
}
|
|
1222
1314
|
function UserMessageAttachments() {
|
|
1223
1315
|
const messageRuntime = useMessageRuntime();
|
|
1224
1316
|
const msg = messageRuntime.getState();
|
|
@@ -1865,7 +1957,7 @@ function ensureMessageMetadata(repo) {
|
|
|
1865
1957
|
// Re-export for backwards compatibility
|
|
1866
1958
|
import { extractThreadMeta, normalizeThreadRepository, } from "../agent/thread-data-builder.js";
|
|
1867
1959
|
export { extractThreadMeta };
|
|
1868
|
-
const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateText, suggestions, dynamicSuggestions, emptyStateAddon, showHeader = true, onSwitchToCli, className, apiUrl, tabId, browserTabId, threadId, contextScope, onMessageCountChange, onSaveThread, onGenerateTitle, composerSlot, composerAreaClassName, composerPlaceholder, composerLayoutVariant = "default", centerComposerWhenEmpty = false, emptyStateDisplay = "default", composerToolbarSlot, composerExtraActionButton, composerDisabled = false, composerDisabledPlaceholder, isNewThread, onSlashCommand, execMode, onExecModeChange, planModeDisabled, planModeDisabledReason, selectedModel, defaultModel, selectedEngine, selectedEffort, availableModels, onModelChange, onEffortChange, onForkChat, onConnectProvider, plusMenuMode = "full", providerStatusChecksEnabled = true, loadHistoryRepository, historyReloadKey, }, ref) {
|
|
1960
|
+
const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateText, suggestions, dynamicSuggestions, emptyStateAddon, showHeader = true, onSwitchToCli, className, apiUrl, tabId, browserTabId, threadId, contextScope, onMessageCountChange, onSaveThread, onGenerateTitle, composerSlot, composerAreaClassName, composerPlaceholder, composerLayoutVariant = "default", centerComposerWhenEmpty = false, emptyStateDisplay = "default", composerToolbarSlot, composerExtraActionButton, composerDisabled = false, composerDisabledPlaceholder, isNewThread, onSlashCommand, execMode, onExecModeChange, planModeDisabled, planModeDisabledReason, selectedModel, defaultModel, selectedEngine, selectedEffort, availableModels, onModelChange, onEffortChange, onForkChat, onConnectProvider, plusMenuMode = "full", providerStatusChecksEnabled = true, loadHistoryRepository, historyReloadKey, externalStreaming = false, }, ref) {
|
|
1869
1961
|
const thread = useThread();
|
|
1870
1962
|
const threadRuntime = useThreadRuntime();
|
|
1871
1963
|
const composerRuntime = useComposerRuntime();
|
|
@@ -1983,6 +2075,38 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
1983
2075
|
const [authError, setAuthError] = useState(null);
|
|
1984
2076
|
const [authSessionAvailable, setAuthSessionAvailable] = useState(false);
|
|
1985
2077
|
const [queuedMessages, setQueuedMessages] = useState([]);
|
|
2078
|
+
const [composerContextItems, setComposerContextItems] = useState([]);
|
|
2079
|
+
const composerContextItemsRef = useRef([]);
|
|
2080
|
+
const updateComposerContextItems = useCallback((updater) => {
|
|
2081
|
+
setComposerContextItems((previous) => {
|
|
2082
|
+
const next = updater(previous);
|
|
2083
|
+
composerContextItemsRef.current = next;
|
|
2084
|
+
return next;
|
|
2085
|
+
});
|
|
2086
|
+
}, []);
|
|
2087
|
+
const stageComposerContextItem = useCallback((rawItem) => {
|
|
2088
|
+
const item = normalizeAgentChatContextItem(rawItem);
|
|
2089
|
+
if (!item)
|
|
2090
|
+
return;
|
|
2091
|
+
updateComposerContextItems((previous) => {
|
|
2092
|
+
const index = previous.findIndex((current) => current.key === item.key);
|
|
2093
|
+
if (index === -1)
|
|
2094
|
+
return [...previous, item];
|
|
2095
|
+
return previous.map((current, currentIndex) => currentIndex === index ? item : current);
|
|
2096
|
+
});
|
|
2097
|
+
}, [updateComposerContextItems]);
|
|
2098
|
+
const removeComposerContextItem = useCallback((key) => {
|
|
2099
|
+
updateComposerContextItems((previous) => previous.filter((item) => item.key !== key));
|
|
2100
|
+
}, [updateComposerContextItems]);
|
|
2101
|
+
const buildComposerContextSubmission = useCallback((text) => {
|
|
2102
|
+
const context = formatAgentChatContextItemsForPrompt(composerContextItemsRef.current);
|
|
2103
|
+
if (!context)
|
|
2104
|
+
return { text, includesContext: false };
|
|
2105
|
+
return {
|
|
2106
|
+
text: appendAgentChatContextToMessage(text, context),
|
|
2107
|
+
includesContext: true,
|
|
2108
|
+
};
|
|
2109
|
+
}, []);
|
|
1986
2110
|
// Tracks the JSON of the last queue we successfully persisted so the
|
|
1987
2111
|
// debounced save effect can skip no-op writes (e.g. restore-from-server
|
|
1988
2112
|
// on mount, or queue state that hasn't actually changed).
|
|
@@ -2009,6 +2133,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2009
2133
|
// to an active run the same as running, UNLESS the user has explicitly
|
|
2010
2134
|
// clicked stop (forceStopped).
|
|
2011
2135
|
const isRunning = !forceStopped && (isRuntimeRunning || isReconnecting);
|
|
2136
|
+
const textStreaming = isRunning || externalStreaming;
|
|
2012
2137
|
// UI-only running state — drives the stop button and thinking indicator.
|
|
2013
2138
|
const showRunningInUI = isRunning;
|
|
2014
2139
|
const wasRunningRef = useRef(false);
|
|
@@ -2844,7 +2969,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2844
2969
|
threadId,
|
|
2845
2970
|
threadRuntime,
|
|
2846
2971
|
]);
|
|
2847
|
-
const addToQueue = useCallback(async (text, images, references, attachments, requestMode, intent = "queued", recoveryAction) => {
|
|
2972
|
+
const addToQueue = useCallback(async (text, images, references, attachments, requestMode, intent = "queued", recoveryAction, includeComposerContext = false) => {
|
|
2848
2973
|
materializeFrozenReconnectContent();
|
|
2849
2974
|
setShowContinue(false);
|
|
2850
2975
|
setLoopLimitInfo(null);
|
|
@@ -2862,6 +2987,10 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2862
2987
|
// exists to stop streaming from yanking the viewport, not to swallow
|
|
2863
2988
|
// direct sends.
|
|
2864
2989
|
markNearBottom();
|
|
2990
|
+
const submitted = includeComposerContext
|
|
2991
|
+
? buildComposerContextSubmission(text)
|
|
2992
|
+
: { text, includesContext: false };
|
|
2993
|
+
const submittedText = submitted.text;
|
|
2865
2994
|
const queuedAttachments = await serializeQueuedAttachments(attachments);
|
|
2866
2995
|
const imageAttachments = createAgentImageAttachments(images);
|
|
2867
2996
|
const messageAttachments = [
|
|
@@ -2885,7 +3014,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2885
3014
|
id: typeof crypto !== "undefined" && crypto.randomUUID
|
|
2886
3015
|
? crypto.randomUUID()
|
|
2887
3016
|
: `q-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
2888
|
-
text,
|
|
3017
|
+
text: submittedText,
|
|
2889
3018
|
images,
|
|
2890
3019
|
attachments: messageAttachments.length > 0 ? messageAttachments : undefined,
|
|
2891
3020
|
references,
|
|
@@ -2897,19 +3026,37 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2897
3026
|
else {
|
|
2898
3027
|
threadRuntime.append({
|
|
2899
3028
|
role: "user",
|
|
2900
|
-
content: [{ type: "text", text }],
|
|
3029
|
+
content: [{ type: "text", text: submittedText }],
|
|
2901
3030
|
...(messageAttachments.length > 0
|
|
2902
3031
|
? { attachments: messageAttachments }
|
|
2903
3032
|
: {}),
|
|
2904
3033
|
...createUserMessageRunConfig(references, effectiveRequestMode, recoveryAction),
|
|
2905
3034
|
});
|
|
2906
3035
|
}
|
|
2907
|
-
|
|
3036
|
+
if (submitted.includesContext) {
|
|
3037
|
+
updateComposerContextItems(() => []);
|
|
3038
|
+
}
|
|
3039
|
+
}, [
|
|
3040
|
+
buildComposerContextSubmission,
|
|
3041
|
+
execMode,
|
|
3042
|
+
isRunning,
|
|
3043
|
+
materializeFrozenReconnectContent,
|
|
3044
|
+
threadRuntime,
|
|
3045
|
+
updateComposerContextItems,
|
|
3046
|
+
]);
|
|
2908
3047
|
// Expose imperative handle
|
|
2909
3048
|
useImperativeHandle(ref, () => ({
|
|
2910
3049
|
sendMessage(text, images) {
|
|
2911
3050
|
addToQueue(text, images);
|
|
2912
3051
|
},
|
|
3052
|
+
prefillMessage(text) {
|
|
3053
|
+
tiptapRef.current?.setText(text);
|
|
3054
|
+
tiptapRef.current?.focus();
|
|
3055
|
+
},
|
|
3056
|
+
setComposerContextItem(item) {
|
|
3057
|
+
stageComposerContextItem(item);
|
|
3058
|
+
tiptapRef.current?.focus();
|
|
3059
|
+
},
|
|
2913
3060
|
sendRecoveryMessage(text, recoveryAction, images) {
|
|
2914
3061
|
addToQueue(text, images, undefined, undefined, undefined, "queued", recoveryAction);
|
|
2915
3062
|
},
|
|
@@ -2934,7 +3081,13 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2934
3081
|
messageCount: messages.length,
|
|
2935
3082
|
};
|
|
2936
3083
|
},
|
|
2937
|
-
}), [
|
|
3084
|
+
}), [
|
|
3085
|
+
addToQueue,
|
|
3086
|
+
messages.length,
|
|
3087
|
+
stageComposerContextItem,
|
|
3088
|
+
thread.isRunning,
|
|
3089
|
+
threadRuntime,
|
|
3090
|
+
]);
|
|
2938
3091
|
const autoscrollFollowKey = useMemo(() => [
|
|
2939
3092
|
messages.map(messageFollowKey).join(";"),
|
|
2940
3093
|
`q:${queuedMessages.map(queuedMessageFollowKey).join("|")}`,
|
|
@@ -2942,7 +3095,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2942
3095
|
].join(";;"), [messages, queuedMessages, reconnectContent]);
|
|
2943
3096
|
const { scrollRef, isNearBottomRef, showScrollToBottom, markNearBottom, scrollToBottom, scrollToBottomAfterPaint, } = useNearBottomAutoscroll({
|
|
2944
3097
|
followKey: autoscrollFollowKey,
|
|
2945
|
-
streaming:
|
|
3098
|
+
streaming: textStreaming,
|
|
2946
3099
|
});
|
|
2947
3100
|
const scrollToBottomWhileLayoutSettles = useCallback(() => {
|
|
2948
3101
|
scrollToBottomAfterPaint();
|
|
@@ -2977,10 +3130,10 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
2977
3130
|
}
|
|
2978
3131
|
}, [isRestoring, scrollToBottomWhileLayoutSettles]);
|
|
2979
3132
|
useEffect(() => {
|
|
2980
|
-
if (!
|
|
3133
|
+
if (!textStreaming && isNearBottomRef.current) {
|
|
2981
3134
|
scrollToBottomAfterPaint();
|
|
2982
3135
|
}
|
|
2983
|
-
}, [
|
|
3136
|
+
}, [textStreaming, scrollToBottomAfterPaint]);
|
|
2984
3137
|
const { isDevMode: cpDevMode } = useDevMode(apiUrl);
|
|
2985
3138
|
const checkpointCtx = useMemo(() => ({ apiUrl, devMode: cpDevMode, threadId }), [apiUrl, cpDevMode, threadId]);
|
|
2986
3139
|
const messageActionsCtx = useMemo(() => ({ onForkChat }), [onForkChat]);
|
|
@@ -3044,123 +3197,124 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
|
|
|
3044
3197
|
queryKey: ["guided-questions"],
|
|
3045
3198
|
...(browserTabId ? { browserTabId } : {}),
|
|
3046
3199
|
});
|
|
3047
|
-
return (_jsx(CheckpointContext.Provider, { value: checkpointCtx, children: _jsx(MessageActionsContext.Provider, { value: messageActionsCtx, children: _jsx(ChatRunningContext.Provider, { value: isRunning, children: _jsxs("div", { "data-agent-empty-state": centeredEmptyState ? "centered" : undefined, className: cn("relative flex flex-1 flex-col h-full min-h-0 text-foreground", className), onDragEnter: handleChatDragEnter, onDragOver: handleChatDragOver, onDragLeave: handleChatDragLeave, onDropCapture: handleChatDropCapture, onDrop: handleChatDrop, children: [dropActive && (_jsx("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 z-50 flex items-center justify-center rounded-md border-2 border-dashed border-primary/70 bg-primary/5 backdrop-blur-[1px]", children: _jsx("span", { className: "rounded-md bg-background/90 px-3 py-1.5 text-xs font-medium text-foreground shadow-sm", children: "Drop to attach" }) })), showHeader && (_jsxs("div", { className: "flex h-11 shrink-0 items-center justify-between border-b border-border px-4", children: [_jsx("span", { className: "text-[13px] font-medium text-muted-foreground", children: "Agent" }), _jsx("div", { className: "flex items-center gap-1", children: onSwitchToCli && (_jsx(TooltipProvider, { delayDuration: 200, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { onClick: onSwitchToCli, "aria-label": "Switch to CLI", className: "flex items-center gap-1 text-[12px] text-muted-foreground hover:text-foreground px-2 py-1 rounded-md hover:bg-accent", children: [_jsx(IconTerminal, { className: "h-3.5 w-3.5" }), "CLI"] }) }), _jsx(TooltipContent, { children: "Switch to CLI" })] }) })) })] })), _jsx("div", { ref: scrollRef, className: "agent-chat-scroll flex-1 overflow-y-auto overflow-x-hidden min-h-0", children: authError ? (_jsxs("div", { className: "flex flex-col items-center justify-center h-full px-4 gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-destructive/10", children: _jsx(IconLock, { className: "h-5 w-5 text-destructive" }) }), _jsxs("div", { className: "text-center max-w-[280px]", children: [_jsx("p", { className: "text-sm font-medium text-foreground mb-1", children: authSessionAvailable
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3200
|
+
return (_jsx(CheckpointContext.Provider, { value: checkpointCtx, children: _jsx(MessageActionsContext.Provider, { value: messageActionsCtx, children: _jsx(ChatRunningContext.Provider, { value: isRunning, children: _jsx(TextStreamingContext.Provider, { value: textStreaming, children: _jsxs("div", { "data-agent-empty-state": centeredEmptyState ? "centered" : undefined, className: cn("relative flex flex-1 flex-col h-full min-h-0 text-foreground", className), onDragEnter: handleChatDragEnter, onDragOver: handleChatDragOver, onDragLeave: handleChatDragLeave, onDropCapture: handleChatDropCapture, onDrop: handleChatDrop, children: [dropActive && (_jsx("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-0 z-50 flex items-center justify-center rounded-md border-2 border-dashed border-primary/70 bg-primary/5 backdrop-blur-[1px]", children: _jsx("span", { className: "rounded-md bg-background/90 px-3 py-1.5 text-xs font-medium text-foreground shadow-sm", children: "Drop to attach" }) })), showHeader && (_jsxs("div", { className: "flex h-11 shrink-0 items-center justify-between border-b border-border px-4", children: [_jsx("span", { className: "text-[13px] font-medium text-muted-foreground", children: "Agent" }), _jsx("div", { className: "flex items-center gap-1", children: onSwitchToCli && (_jsx(TooltipProvider, { delayDuration: 200, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { onClick: onSwitchToCli, "aria-label": "Switch to CLI", className: "flex items-center gap-1 text-[12px] text-muted-foreground hover:text-foreground px-2 py-1 rounded-md hover:bg-accent", children: [_jsx(IconTerminal, { className: "h-3.5 w-3.5" }), "CLI"] }) }), _jsx(TooltipContent, { children: "Switch to CLI" })] }) })) })] })), _jsx("div", { ref: scrollRef, className: "agent-chat-scroll flex-1 overflow-y-auto overflow-x-hidden min-h-0", children: authError ? (_jsxs("div", { className: "flex flex-col items-center justify-center h-full px-4 gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-destructive/10", children: _jsx(IconLock, { className: "h-5 w-5 text-destructive" }) }), _jsxs("div", { className: "text-center max-w-[280px]", children: [_jsx("p", { className: "text-sm font-medium text-foreground mb-1", children: authSessionAvailable
|
|
3201
|
+
? "Chat session needs refresh"
|
|
3202
|
+
: authError.sessionExpired
|
|
3203
|
+
? "Session expired"
|
|
3204
|
+
: "Authentication required" }), _jsx("p", { className: "text-xs text-muted-foreground leading-relaxed", children: authSessionAvailable
|
|
3205
|
+
? "You're signed in, but this chat connection needs to reconnect."
|
|
3206
|
+
: authError.sessionExpired
|
|
3207
|
+
? "Your session may have expired. Log out and log back in to reconnect."
|
|
3208
|
+
: "You need to log in to use the agent." })] }), _jsxs("div", { className: "flex gap-2", children: [!authError.sessionExpired && !authSessionAvailable && (_jsx("button", { onClick: () => {
|
|
3209
|
+
const ret = window.location.pathname + window.location.search;
|
|
3210
|
+
window.location.href =
|
|
3211
|
+
agentNativePath("/_agent-native/sign-in") +
|
|
3212
|
+
`?return=${encodeURIComponent(ret)}`;
|
|
3213
|
+
}, className: "text-xs text-background bg-foreground hover:opacity-90 px-3 py-1.5 rounded-md", children: "Log in" })), authError.sessionExpired && !authSessionAvailable && (_jsx("button", { onClick: async () => {
|
|
3214
|
+
try {
|
|
3215
|
+
await fetch(agentNativePath("/_agent-native/auth/logout"), {
|
|
3216
|
+
method: "POST",
|
|
3217
|
+
});
|
|
3218
|
+
}
|
|
3219
|
+
catch { }
|
|
3220
|
+
window.location.reload();
|
|
3221
|
+
}, className: "text-xs text-destructive hover:text-destructive/80 px-3 py-1.5 rounded-md border border-destructive/30 hover:bg-destructive/10", children: "Log out" })), _jsx("button", { onClick: () => {
|
|
3222
|
+
setAuthError(null);
|
|
3223
|
+
window.location.reload();
|
|
3224
|
+
}, className: authSessionAvailable
|
|
3225
|
+
? "text-xs text-background bg-foreground hover:opacity-90 px-3 py-1.5 rounded-md"
|
|
3226
|
+
: "text-xs text-muted-foreground hover:text-foreground px-3 py-1.5 rounded-md border border-border hover:bg-accent", children: "Refresh chat" })] })] })) : missingApiKey && messages.length === 0 ? (_jsx("div", { className: "flex flex-col items-center justify-center h-full px-2", children: _jsx(BuilderSetupCard, { onConnected: handleBuilderConnected, bouncePulse: missingKeyBouncePulse }) })) : isRestoring ? (_jsxs("div", { className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "flex justify-end", children: _jsx("div", { className: "h-8 w-32 rounded-lg bg-muted animate-pulse" }) }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx("div", { className: "h-4 w-48 rounded bg-muted animate-pulse" }), _jsx("div", { className: "h-4 w-64 rounded bg-muted animate-pulse" }), _jsx("div", { className: "h-4 w-40 rounded bg-muted animate-pulse" })] })] })) : messages.length === 0 && !isReconnecting ? (_jsxs("div", { className: cn("agent-empty-state", emptyStateDisplay === "hidden"
|
|
3227
|
+
? "sr-only"
|
|
3228
|
+
: "flex h-full flex-col items-center justify-center gap-4 px-4 py-16"), children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-muted", children: _jsx(IconMessage, { className: "h-5 w-5 text-muted-foreground" }) }), _jsx("p", { className: "text-sm text-muted-foreground text-center max-w-[240px]", children: emptyStateText ?? "How can I help you?" }), emptyStateAddon, resolvedSuggestions && resolvedSuggestions.length > 0 && (_jsx("div", { className: "flex flex-col gap-1.5 w-full max-w-[280px]", children: resolvedSuggestions.map((suggestion) => (_jsx("button", { onClick: () => {
|
|
3229
|
+
threadRuntime.append({
|
|
3230
|
+
role: "user",
|
|
3231
|
+
content: [{ type: "text", text: suggestion }],
|
|
3232
|
+
});
|
|
3233
|
+
}, className: "w-full rounded-lg border border-border px-3 py-2 text-left text-[13px] text-muted-foreground hover:bg-accent hover:text-foreground", children: suggestion }, suggestion))) }))] })) : (_jsxs("div", { className: "agent-thread-content flex flex-col gap-4 px-4 py-4", children: [_jsx(AssistantMessageListErrorBoundary, { resetKey: messageListResetKey, children: _jsx(ThreadPrimitive.Messages, { components: {
|
|
3234
|
+
UserMessage,
|
|
3235
|
+
AssistantMessage,
|
|
3236
|
+
} }) }), missingApiKey && (_jsx(BuilderSetupCard, { onConnected: handleBuilderConnected, bouncePulse: missingKeyBouncePulse })), visibleLoopLimit && !showRunningInUI && (_jsx(LoopLimitContinueCard, { info: visibleLoopLimit, onContinue: () => {
|
|
3237
|
+
setShowContinue(false);
|
|
3238
|
+
setLoopLimitInfo(null);
|
|
3239
|
+
addToQueue("Continue from where you left off.", undefined, undefined, undefined, undefined, "queued", "continue");
|
|
3240
|
+
} })), shouldShowRunError && visibleRunError && (_jsx(RunErrorRecoveryCard, { info: visibleRunError, onContinue: () => {
|
|
3241
|
+
setRunErrorInfo(null);
|
|
3242
|
+
addToQueue("Continue from where you stopped. Use the partial work above, verify what succeeded, and finish the original request. Do not rerun the exact same failed tool input unless the failure was transient or the user explicitly asked for an exact rerun. Prefer dedicated app actions over raw database edits when they exist.", undefined, undefined, undefined, undefined, "queued", "continue");
|
|
3243
|
+
}, onRetry: () => {
|
|
3244
|
+
setRunErrorInfo(null);
|
|
3245
|
+
addToQueue(lastUserText
|
|
3246
|
+
? `Retry the previous request from a clean approach. Do not rerun the exact same failed tool input unless the failure was transient or the user explicitly asked for an exact rerun. If a provider query failed because of schema, syntax, or type mismatch, diagnose the error and adjust the query first.\n\nOriginal request:\n\n${lastUserText}`
|
|
3247
|
+
: "Retry the previous request from a clean approach. Do not rerun the exact same failed tool input unless the failure was transient or the user explicitly asked for an exact rerun. If a provider query failed because of schema, syntax, or type mismatch, diagnose the error and adjust the query first.", undefined, undefined, undefined, undefined, "queued", "retry");
|
|
3248
|
+
}, onFork: onForkChat, onDismiss: () => {
|
|
3249
|
+
if (visibleRunErrorKey) {
|
|
3250
|
+
setDismissedRunErrorKey(visibleRunErrorKey);
|
|
3251
|
+
}
|
|
3252
|
+
setRunErrorInfo(null);
|
|
3253
|
+
} })), (isReconnecting || reconnectFrozen) &&
|
|
3254
|
+
reconnectContent.length > 0 && (_jsx(ReconnectStreamMessage, { content: reconnectContent })), queuedMessages.map((msg) => {
|
|
3255
|
+
const displayText = msg.text
|
|
3256
|
+
.replace(/<context>[\s\S]*?<\/context>\n?/g, "")
|
|
3257
|
+
.trim();
|
|
3258
|
+
return (_jsx("div", { className: "flex justify-end group", children: _jsxs("div", { className: "relative max-w-[85%] rounded-lg bg-accent/50 text-foreground/60 px-3 py-2 text-sm leading-relaxed whitespace-pre-wrap break-words", children: [_jsxs("div", { className: "flex items-center gap-1.5 text-[10px] text-muted-foreground mb-1 font-medium uppercase tracking-wide", children: [_jsx(IconClock, { className: "h-3 w-3" }), "Queued"] }), displayText, msg.images && msg.images.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-1.5 mt-1.5", children: msg.images.map((img, j) => (_jsx("img", { src: img, alt: "", className: "h-12 w-12 rounded object-cover border border-border/50" }, j))) })), _jsx("button", { type: "button", onClick: () => setQueuedMessages((prev) => prev.filter((m) => m.id !== msg.id)), "aria-label": "Remove from queue", className: "absolute -top-2 -right-2 flex h-5 w-5 items-center justify-center rounded-full border border-border bg-background text-muted-foreground opacity-0 group-hover:opacity-100 focus-visible:opacity-100 hover:text-foreground hover:bg-accent shadow-sm", children: _jsx(IconX, { className: "h-3 w-3" }) })] }) }, msg.id));
|
|
3259
|
+
})] })) }), showScrollToBottom && (_jsx("div", { className: "shrink-0 flex justify-center -mb-1", children: _jsx("button", { type: "button", onClick: scrollToBottom, className: "flex h-7 w-7 items-center justify-center rounded-full border border-border bg-background shadow-sm hover:bg-accent", "aria-label": "Scroll to bottom", children: _jsx(IconChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" }) }) })), composerSlot, guidedQuestions && guidedQuestions.length > 0 && (_jsx("div", { className: "shrink-0 px-3 pb-2 pt-1", children: _jsx("div", { className: "rounded-lg border border-border bg-card/60 shadow-sm", children: _jsx(GuidedQuestionFlow, { questions: guidedQuestions, onSubmit: handleGuidedQuestionsSubmit, onSkip: handleGuidedQuestionsSkip, ...(guidedQuestionsTitle
|
|
3260
|
+
? { title: guidedQuestionsTitle }
|
|
3261
|
+
: {}), ...(guidedQuestionsDescription
|
|
3262
|
+
? { description: guidedQuestionsDescription }
|
|
3263
|
+
: {}), ...(guidedQuestionsSkipLabel
|
|
3264
|
+
? { skipLabel: guidedQuestionsSkipLabel }
|
|
3265
|
+
: {}), ...(guidedQuestionsSubmitLabel
|
|
3266
|
+
? { submitLabel: guidedQuestionsSubmitLabel }
|
|
3267
|
+
: {}), className: "h-auto items-stretch justify-stretch bg-transparent" }) }) })), showPlanModeCallout && (_jsx(PlanModeCallout, { canImplementPlan: canImplementPlan, onImplementPlan: handleImplementPlan, onSwitchToAct: handleSwitchToAct })), _jsx(SelectionAttachedPill, {}), showRunningInUI && (_jsx(RunningActivityStatus, { steps: activitySteps, label: isReconnecting
|
|
3268
|
+
? "Reconnecting"
|
|
3269
|
+
: SHOW_AGENT_ACTIVITY_STEPS
|
|
3270
|
+
? (activityLabel ?? "Thinking")
|
|
3271
|
+
: "Thinking" })), _jsxs(AgentComposerFrame, { layoutVariant: composerLayoutVariant, className: cn(composerAreaClassName, missingApiKey && "cursor-pointer", isComposerDisabled && "opacity-70"), onClick: missingApiKey
|
|
3272
|
+
? () => setMissingKeyBouncePulse((p) => p + 1)
|
|
3273
|
+
: undefined, children: [_jsx(ComposerAttachmentPreviewStrip, {}), _jsx(TiptapComposer, { focusRef: tiptapRef, disabled: isComposerDisabled, placeholder: missingApiKey
|
|
3274
|
+
? "Connect an AI engine above to start chatting…"
|
|
3275
|
+
: composerDisabled
|
|
3276
|
+
? (composerDisabledPlaceholder ??
|
|
3277
|
+
"Open Desktop to use this chat.")
|
|
3278
|
+
: isRunning
|
|
3279
|
+
? queuedMessages.length > 0
|
|
3280
|
+
? `${queuedMessages.length} queued — send a follow-up...`
|
|
3281
|
+
: "Send a follow-up..."
|
|
3282
|
+
: composerPlaceholder, onSubmit: isRunning || composerContextItems.length > 0
|
|
3283
|
+
? (text, references, attachments, options) => void addToQueue(text, undefined, references.length > 0 ? references : undefined, attachments, undefined, options?.intent ?? "immediate", undefined, true)
|
|
3284
|
+
: undefined, onSlashCommand: onSlashCommand, execMode: execMode, onExecModeChange: onExecModeChange, planModeDisabled: planModeDisabled, planModeDisabledReason: planModeDisabledReason, selectedModel: selectedModel ?? defaultModel, selectedEffort: selectedEffort, availableModels: availableModels, onModelChange: onModelChange, onEffortChange: onEffortChange, onConnectProvider: onConnectProvider, toolbarSlot: composerToolbarSlot, contextItems: composerContextItems, onRemoveContextItem: removeComposerContextItem, plusMenuMode: plusMenuMode, layoutVariant: composerLayoutVariant, providerConnectStatusEnabled: providerStatusChecksEnabled, draftScope: threadId || tabId, interceptBuildRequestsForBuilder: true, extraActionButton: composerExtraActionButton || showRunningInUI ? (_jsxs(_Fragment, { children: [composerExtraActionButton, showRunningInUI && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => {
|
|
3285
|
+
// Nuclear stop: flip forceStopped so isRunning is false
|
|
3286
|
+
// immediately. This unblocks submission even if the
|
|
3287
|
+
// runtime or reconnect state is stuck.
|
|
3288
|
+
setForceStopped(true);
|
|
3289
|
+
const activeRun = getActiveRun();
|
|
3290
|
+
const runIdToAbort = reconnectRunIdRef.current ??
|
|
3291
|
+
activeRun?.runId;
|
|
3292
|
+
userStoppedRunRef.current = {
|
|
3293
|
+
at: Date.now(),
|
|
3294
|
+
...(runIdToAbort
|
|
3295
|
+
? { runId: runIdToAbort }
|
|
3296
|
+
: {}),
|
|
3297
|
+
};
|
|
3298
|
+
setRunErrorInfo(null);
|
|
3299
|
+
setDismissedRunErrorKey(null);
|
|
3300
|
+
if (runIdToAbort) {
|
|
3301
|
+
fetch(`${apiUrl}/runs/${encodeURIComponent(runIdToAbort)}/abort`, { method: "POST" }).catch(() => { });
|
|
3302
|
+
}
|
|
3303
|
+
if (isReconnecting) {
|
|
3304
|
+
reconnectAbortRef.current?.abort();
|
|
3305
|
+
reconnectAbortRef.current = null;
|
|
3306
|
+
reconnectRunIdRef.current = null;
|
|
3307
|
+
setIsReconnecting(false);
|
|
3308
|
+
setReconnectFrozen(reconnectContent.length > 0);
|
|
3309
|
+
}
|
|
3310
|
+
threadRuntime.cancelRun();
|
|
3311
|
+
window.dispatchEvent(new CustomEvent("agentNative.chatRunning", {
|
|
3312
|
+
detail: {
|
|
3313
|
+
isRunning: false,
|
|
3314
|
+
tabId: tabId || threadId,
|
|
3315
|
+
},
|
|
3316
|
+
}));
|
|
3317
|
+
}, className: "shrink-0 flex h-7 w-7 items-center justify-center rounded-md bg-muted text-foreground hover:bg-muted/80", children: _jsx(IconPlayerStop, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Stop generating" })] }))] })) : undefined })] })] }) }) }) }) }));
|
|
3164
3318
|
});
|
|
3165
3319
|
export const AssistantChat = forwardRef(function AssistantChat({ apiUrl = agentNativePath("/_agent-native/agent-chat"), tabId, browserTabId, threadId, contextScope, ...props }, ref) {
|
|
3166
3320
|
const modelRef = useRef(props.selectedModel);
|