fix: remove terminal stream backpressure that caused 14MB snapshot thrashing

The high water mark (256KB) was triggering snapshot mode during normal
output bursts, replacing incremental output with full terminal state
snapshots (~14MB). This made the terminal feel laggy even on localhost.

Snapshots still fire on initial attach and tab switch where they're
semantically needed.
This commit is contained in:
Mohamed Boudra
2026-04-10 15:12:32 +07:00
parent 033c4bcbf2
commit 120c1b46a4
-37
View File
@@ -231,8 +231,6 @@ function clientSupportsFlexibleEditorIds(appVersion: string | null): boolean {
const WORKSPACE_GIT_WATCH_DEBOUNCE_MS = 500; const WORKSPACE_GIT_WATCH_DEBOUNCE_MS = 500;
const WORKSPACE_GIT_WATCH_REMOVED_FINGERPRINT = "__removed__"; const WORKSPACE_GIT_WATCH_REMOVED_FINGERPRINT = "__removed__";
const TERMINAL_STREAM_HIGH_WATER_BYTES = 256 * 1024;
const TERMINAL_STREAM_LOW_WATER_BYTES = 16 * 1024;
const MAX_TERMINAL_STREAM_SLOTS = 256; const MAX_TERMINAL_STREAM_SLOTS = 256;
function deriveInitialAgentTitle(prompt: string): string | null { function deriveInitialAgentTitle(prompt: string): string | null {
@@ -296,7 +294,6 @@ type ActiveTerminalStream = {
slot: number; slot: number;
unsubscribe: () => void; unsubscribe: () => void;
needsSnapshot: boolean; needsSnapshot: boolean;
snapshotRetryTimer: ReturnType<typeof setTimeout> | null;
}; };
export type SessionRuntimeMetrics = { export type SessionRuntimeMetrics = {
@@ -8424,7 +8421,6 @@ export class Session {
slot, slot,
unsubscribe: () => {}, unsubscribe: () => {},
needsSnapshot: true, needsSnapshot: true,
snapshotRetryTimer: null,
}; };
this.activeTerminalStreams.set(slot, activeStream); this.activeTerminalStreams.set(slot, activeStream);
@@ -8441,10 +8437,6 @@ export class Session {
if (activeStream.needsSnapshot || message.data.length === 0) { if (activeStream.needsSnapshot || message.data.length === 0) {
return; return;
} }
if (this.getCurrentBinaryBufferedAmount() >= TERMINAL_STREAM_HIGH_WATER_BYTES) {
this.markAllActiveTerminalStreamsForSnapshot();
return;
}
this.emitBinary( this.emitBinary(
encodeTerminalStreamFrame({ encodeTerminalStreamFrame({
opcode: TerminalStreamOpcode.Output, opcode: TerminalStreamOpcode.Output,
@@ -8452,9 +8444,6 @@ export class Session {
payload: new Uint8Array(Buffer.from(message.data, "utf8")), payload: new Uint8Array(Buffer.from(message.data, "utf8")),
}), }),
); );
if (this.getCurrentBinaryBufferedAmount() >= TERMINAL_STREAM_HIGH_WATER_BYTES) {
this.markAllActiveTerminalStreamsForSnapshot();
}
}); });
return slot; return slot;
} }
@@ -8467,21 +8456,6 @@ export class Session {
return; return;
} }
if (this.getCurrentBinaryBufferedAmount() > TERMINAL_STREAM_LOW_WATER_BYTES) {
if (!activeStream.snapshotRetryTimer) {
activeStream.snapshotRetryTimer = setTimeout(() => {
activeStream.snapshotRetryTimer = null;
this.trySendTerminalSnapshot(activeStream);
}, 33);
}
return;
}
if (activeStream.snapshotRetryTimer) {
clearTimeout(activeStream.snapshotRetryTimer);
activeStream.snapshotRetryTimer = null;
}
const terminal = this.terminalManager?.getTerminal(activeStream.terminalId); const terminal = this.terminalManager?.getTerminal(activeStream.terminalId);
if (!terminal) { if (!terminal) {
this.detachTerminalStream(activeStream.terminalId, { emitExit: true }); this.detachTerminalStream(activeStream.terminalId, { emitExit: true });
@@ -8498,13 +8472,6 @@ export class Session {
); );
} }
private markAllActiveTerminalStreamsForSnapshot(): void {
for (const activeStream of this.activeTerminalStreams.values()) {
activeStream.needsSnapshot = true;
this.trySendTerminalSnapshot(activeStream);
}
}
private allocateTerminalSlot(): number | null { private allocateTerminalSlot(): number | null {
for (let attempt = 0; attempt < MAX_TERMINAL_STREAM_SLOTS; attempt += 1) { for (let attempt = 0; attempt < MAX_TERMINAL_STREAM_SLOTS; attempt += 1) {
const slot = (this.nextTerminalSlot + attempt) % MAX_TERMINAL_STREAM_SLOTS; const slot = (this.nextTerminalSlot + attempt) % MAX_TERMINAL_STREAM_SLOTS;
@@ -8529,10 +8496,6 @@ export class Session {
} }
this.activeTerminalStreams.delete(slot); this.activeTerminalStreams.delete(slot);
this.terminalIdToSlot.delete(terminalId); this.terminalIdToSlot.delete(terminalId);
if (activeStream.snapshotRetryTimer) {
clearTimeout(activeStream.snapshotRetryTimer);
activeStream.snapshotRetryTimer = null;
}
try { try {
activeStream.unsubscribe(); activeStream.unsubscribe();
} catch (error) { } catch (error) {