diff --git a/references/ai-chat/src/components/chat-app.tsx b/references/ai-chat/src/components/chat-app.tsx index df0a248c4..2d77ffe94 100644 --- a/references/ai-chat/src/components/chat-app.tsx +++ b/references/ai-chat/src/components/chat-app.tsx @@ -55,7 +55,6 @@ export function ChatApp({ // Model for new chats (before first message is sent) const [newChatModel, setNewChatModel] = useState(DEFAULT_MODEL); - const [preloadEnabled, setPreloadEnabled] = useState(true); const [idleTimeoutInSeconds, setIdleTimeoutInSeconds] = useState(60); const handleSessionChange = useCallback((chatId: string, session: SessionInfo | null) => { @@ -107,14 +106,7 @@ export function ChatApp({ setActiveChatId(id); setMessages([]); setNewChatModel(DEFAULT_MODEL); - if (preloadEnabled) { - // Eagerly create the session + first run before the user types. - // Transport calls `startSession({ chatId: id, taskId: taskMode })`. - // `idleTimeoutInSeconds` lives on the agent definition's - // `idleTimeoutInSeconds`, not per-call. - void transport.preload(id); - void idleTimeoutInSeconds; - } + void idleTimeoutInSeconds; } function handleSelectChat(id: string) { @@ -173,8 +165,6 @@ export function ChatApp({ onNewChat={handleNewChat} onDeleteChat={handleDeleteChat} onWipeAll={handleWipeAll} - preloadEnabled={preloadEnabled} - onPreloadChange={setPreloadEnabled} idleTimeoutInSeconds={idleTimeoutInSeconds} onIdleTimeoutChange={setIdleTimeoutInSeconds} taskMode={taskMode} @@ -193,6 +183,7 @@ export function ChatApp({ onModelChange={isNewChat ? setNewChatModel : undefined} session={activeSession} dashboardUrl={process.env.NEXT_PUBLIC_TRIGGER_DASHBOARD_URL} + projectDashboardPath={process.env.NEXT_PUBLIC_TRIGGER_PROJECT_DASHBOARD_PATH} onFirstMessage={handleFirstMessage} onMessagesChange={handleMessagesChange} /> diff --git a/references/ai-chat/src/components/chat-settings-context.tsx b/references/ai-chat/src/components/chat-settings-context.tsx index 7c8f2087f..0d9e605b5 100644 --- a/references/ai-chat/src/components/chat-settings-context.tsx +++ b/references/ai-chat/src/components/chat-settings-context.tsx @@ -5,8 +5,6 @@ import { createContext, useContext, useState, type ReactNode } from "react"; type ChatSettings = { taskMode: string; setTaskMode: (mode: string) => void; - preloadEnabled: boolean; - setPreloadEnabled: (enabled: boolean) => void; idleTimeoutInSeconds: number; setIdleTimeoutInSeconds: (seconds: number) => void; }; @@ -15,14 +13,11 @@ const ChatSettingsContext = createContext(null); export function ChatSettingsProvider({ children }: { children: ReactNode }) { const [taskMode, setTaskMode] = useState("ai-chat"); - const [preloadEnabled, setPreloadEnabled] = useState(true); const [idleTimeoutInSeconds, setIdleTimeoutInSeconds] = useState(60); const value: ChatSettings = { taskMode, setTaskMode, - preloadEnabled, - setPreloadEnabled, idleTimeoutInSeconds, setIdleTimeoutInSeconds, }; diff --git a/references/ai-chat/src/components/chat-sidebar-wrapper.tsx b/references/ai-chat/src/components/chat-sidebar-wrapper.tsx index ecfcb10e1..2827e901d 100644 --- a/references/ai-chat/src/components/chat-sidebar-wrapper.tsx +++ b/references/ai-chat/src/components/chat-sidebar-wrapper.tsx @@ -26,8 +26,6 @@ export function ChatSidebarWrapper({ const { taskMode, setTaskMode, - preloadEnabled, - setPreloadEnabled, idleTimeoutInSeconds, setIdleTimeoutInSeconds, } = useChatSettings(); @@ -83,8 +81,6 @@ export function ChatSidebarWrapper({ onNewChat={handleNewChat} onDeleteChat={handleDeleteChat} onWipeAll={handleWipeAll} - preloadEnabled={preloadEnabled} - onPreloadChange={setPreloadEnabled} idleTimeoutInSeconds={idleTimeoutInSeconds} onIdleTimeoutChange={setIdleTimeoutInSeconds} taskMode={taskMode} diff --git a/references/ai-chat/src/components/chat-sidebar.tsx b/references/ai-chat/src/components/chat-sidebar.tsx index 588f6bae6..11dd05475 100644 --- a/references/ai-chat/src/components/chat-sidebar.tsx +++ b/references/ai-chat/src/components/chat-sidebar.tsx @@ -25,8 +25,6 @@ type ChatSidebarProps = { onNewChat: () => void; onDeleteChat: (id: string) => void; onWipeAll: () => void; - preloadEnabled: boolean; - onPreloadChange: (enabled: boolean) => void; idleTimeoutInSeconds: number; onIdleTimeoutChange: (seconds: number) => void; taskMode: string; @@ -40,8 +38,6 @@ export function ChatSidebar({ onNewChat, onDeleteChat, onWipeAll, - preloadEnabled, - onPreloadChange, idleTimeoutInSeconds, onIdleTimeoutChange, taskMode, @@ -93,15 +89,6 @@ export function ChatSidebar({
-
Idle timeout diff --git a/references/ai-chat/src/components/chat.tsx b/references/ai-chat/src/components/chat.tsx index 5179a3569..c438955a2 100644 --- a/references/ai-chat/src/components/chat.tsx +++ b/references/ai-chat/src/components/chat.tsx @@ -192,6 +192,7 @@ function DebugPanel({ status, session, dashboardUrl, + projectDashboardPath, messageCount, ttfbHistory, }: { @@ -200,9 +201,14 @@ function DebugPanel({ status: string; session?: { publicAccessToken: string; lastEventId?: string; isStreaming?: boolean }; dashboardUrl?: string; + projectDashboardPath?: string; messageCount: number; ttfbHistory: TtfbEntry[]; }) { + const runsUrl = + dashboardUrl && projectDashboardPath + ? `${dashboardUrl}${projectDashboardPath}/env/dev/runs?tags=${encodeURIComponent(`chat:${chatId}`)}` + : undefined; const [open, setOpen] = useState(false); const latestTtfb = ttfbHistory.length > 0 ? ttfbHistory[ttfbHistory.length - 1]! : undefined; @@ -243,6 +249,7 @@ function DebugPanel({ + {runsUrl && } {session ? ( <> @@ -313,6 +320,7 @@ type ChatProps = { onModelChange?: (model: string) => void; session?: { publicAccessToken: string; lastEventId?: string; isStreaming?: boolean }; dashboardUrl?: string; + projectDashboardPath?: string; onFirstMessage?: (chatId: string, text: string) => void; onMessagesChange?: (chatId: string, messages: ChatUiMessage[]) => void; }; @@ -327,6 +335,7 @@ export function Chat({ onModelChange, session, dashboardUrl, + projectDashboardPath, onFirstMessage, onMessagesChange, }: ChatProps) { @@ -550,6 +559,7 @@ export function Chat({ promote: (id: string) => actionsRef.current.promote(id), send: (text: string) => actionsRef.current.send(text), stop: () => actionsRef.current.stop(), + sendAction: (action: unknown) => transport.sendAction(chatId, action), // ── Waiters ─────────────────────────────────────────────────── waitForStatus: (target: string, timeoutMs = DEFAULT_TIMEOUT_MS) => @@ -844,6 +854,7 @@ export function Chat({ status={status} session={session} dashboardUrl={dashboardUrl} + projectDashboardPath={projectDashboardPath} messageCount={messages.length} ttfbHistory={ttfbHistory} /> @@ -882,6 +893,22 @@ export function Chat({ > Send + {/* Preload — only visible before the first message lands. After + the user sends, the transport creates the session lazily, so + session becomes truthy and this button hides itself. The + transport tracks an in-flight preload internally; double-clicks + are a no-op. */} + {messages.length === 0 && !session && ( + + )} {status === "streaming" && (