From 0dda14103a1710dcaff313ce706fabf7250bea80 Mon Sep 17 00:00:00 2001 From: cpacker Date: Fri, 12 Dec 2025 23:02:16 -0800 Subject: [PATCH] feat: restore /stream command with default OFF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Token streaming is now off by default. Users can toggle it with /stream. 🐾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta --- src/cli/App.tsx | 65 +++++++++++++++++++++++++++++++++++- src/cli/commands/registry.ts | 7 ++++ src/index.ts | 2 ++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/cli/App.tsx b/src/cli/App.tsx index 7171554..1814c2e 100644 --- a/src/cli/App.tsx +++ b/src/cli/App.tsx @@ -220,6 +220,7 @@ export default function App({ startupApproval = null, startupApprovals = [], messageHistory = [], + tokenStreaming = false, agentProvenance = null, }: { agentId: string; @@ -236,6 +237,7 @@ export default function App({ startupApproval?: ApprovalRequest | null; // Deprecated: use startupApprovals startupApprovals?: ApprovalRequest[]; messageHistory?: Message[]; + tokenStreaming?: boolean; agentProvenance?: AgentProvenance | null; }) { // Track current agent (can change when swapping) @@ -331,6 +333,10 @@ export default function App({ const [resumeSelectorOpen, setResumeSelectorOpen] = useState(false); const [messageSearchOpen, setMessageSearchOpen] = useState(false); + // Token streaming preference (can be toggled at runtime) + const [tokenStreamingEnabled, setTokenStreamingEnabled] = + useState(tokenStreaming); + // Live, approximate token counter (resets each turn) const [tokenCount, setTokenCount] = useState(0); @@ -1357,6 +1363,61 @@ export default function App({ return { submitted: true }; } + // Special handling for /stream command - toggle and save + if (msg.trim() === "/stream") { + const newValue = !tokenStreamingEnabled; + + // Immediately add command to transcript with "running" phase and loading message + const cmdId = uid("cmd"); + buffersRef.current.byId.set(cmdId, { + kind: "command", + id: cmdId, + input: msg, + output: `${newValue ? "Enabling" : "Disabling"} token streaming...`, + phase: "running", + }); + buffersRef.current.order.push(cmdId); + refreshDerived(); + + // Lock input during async operation + setCommandRunning(true); + + try { + setTokenStreamingEnabled(newValue); + + // Save to settings + const { settingsManager } = await import("../settings-manager"); + settingsManager.updateSettings({ tokenStreaming: newValue }); + + // Update the same command with final result + buffersRef.current.byId.set(cmdId, { + kind: "command", + id: cmdId, + input: msg, + output: `Token streaming ${newValue ? "enabled" : "disabled"}`, + phase: "finished", + success: true, + }); + refreshDerived(); + } catch (error) { + // Mark command as failed + const errorDetails = formatErrorDetails(error, agentId); + buffersRef.current.byId.set(cmdId, { + kind: "command", + id: cmdId, + input: msg, + output: `Failed: ${errorDetails}`, + phase: "finished", + success: false, + }); + refreshDerived(); + } finally { + // Unlock input + setCommandRunning(false); + } + return { submitted: true }; + } + // Special handling for /clear command - reset conversation if (msg.trim() === "/clear") { const cmdId = uid("cmd"); @@ -2189,6 +2250,7 @@ ${recentCommits} isExecutingTool, queuedApprovalResults, pendingApprovals, + tokenStreamingEnabled, ], ); @@ -3160,9 +3222,10 @@ Plan file path: ${planFilePath}`; // Always show tool calls in progress return ln.phase !== "finished"; } + if (!tokenStreamingEnabled && ln.phase === "streaming") return false; return ln.phase === "streaming"; }); - }, [lines]); + }, [lines, tokenStreamingEnabled]); // Commit welcome snapshot once when ready for fresh sessions (no history) // Wait for agentProvenance to be available for new agents (continueSession=false) diff --git a/src/cli/commands/registry.ts b/src/cli/commands/registry.ts index dc20fab..16e625a 100644 --- a/src/cli/commands/registry.ts +++ b/src/cli/commands/registry.ts @@ -16,6 +16,13 @@ export const commands: Record = { return "Opening model selector..."; }, }, + "/stream": { + desc: "Toggle token streaming on/off", + handler: () => { + // Handled specially in App.tsx for live toggling + return "Toggling token streaming..."; + }, + }, "/exit": { desc: "Exit and show session stats", handler: () => { diff --git a/src/index.ts b/src/index.ts index 609238a..5d2ff1c 100755 --- a/src/index.ts +++ b/src/index.ts @@ -741,6 +741,7 @@ async function main() { startupApproval: resumeData?.pendingApproval ?? null, startupApprovals: resumeData?.pendingApprovals ?? [], messageHistory: resumeData?.messageHistory ?? [], + tokenStreaming: settings.tokenStreaming, agentProvenance, }); } @@ -753,6 +754,7 @@ async function main() { startupApproval: resumeData?.pendingApproval ?? null, startupApprovals: resumeData?.pendingApprovals ?? [], messageHistory: resumeData?.messageHistory ?? [], + tokenStreaming: settings.tokenStreaming, agentProvenance, }); }