Files
orca/src/main/codex/codex-structured-acquisition-window.ts
T
Brennan BensonandMerge Sim 872bd51d47 fix(native-chat): reland large structured command results (#17720)
* fix(native-chat): preserve large structured command results (#17707)

* fix(native-chat): preserve large structured command results

* chore: place native chat validation artifacts under docs

* chore: drop stale root package config

* fix(native-chat): enforce rebuilt lifecycle append slots

---------

Co-authored-by: Merge Sim <sim@local>

* chore: omit native-chat reland planning docs

* fix(native-chat): remove journal store import cycle

* fix(native-chat): keep journal factory acyclic

---------

Co-authored-by: Merge Sim <sim@local>
2026-08-31 13:12:19 -07:00

58 lines
2.2 KiB
TypeScript

// The gap between spawning `codex app-server` and publishing the session it
// belongs to. Codex talks during that gap — the handshake, an early
// notification, even an approval request — and those events belong to the
// session that is still being acquired, so they wait here instead of arriving
// before anything can route them. The gap is bounded by the thread-open request
// timeout; a failed acquisition discards the buffer along with the child.
import type { CodexAppServerConnection } from './codex-app-server-connection'
import { CodexPromptRegistry } from './codex-structured-prompt-replies'
/** Pre-publication buffering is bounded so a provider cannot pin closures. */
export const MAX_CODEX_ACQUISITION_BUFFER_OPERATIONS = 1024
export const MAX_CODEX_ACQUISITION_BUFFER_BYTES = 4 * 1024 * 1024
export class CodexAcquisitionWindow {
readonly prompts = new CodexPromptRegistry()
/** Null until the spawn resolves; the handshake can already emit events. */
connection: CodexAppServerConnection | null = null
private readonly buffered: (() => void)[] = []
private retainedBytes = 0
private open = true
private overflowed = false
get isOverflowed(): boolean {
return this.overflowed
}
/** Returns false once the session is published, which is the caller's cue to
* deliver live rather than buffer. */
buffer(event: () => void, retainedBytes = 256): boolean {
if (!this.open) {
return false
}
const bytes = Number.isFinite(retainedBytes) && retainedBytes > 0 ? Math.ceil(retainedBytes) : 1
if (
this.buffered.length >= MAX_CODEX_ACQUISITION_BUFFER_OPERATIONS ||
this.retainedBytes + bytes > MAX_CODEX_ACQUISITION_BUFFER_BYTES
) {
// Refuse the acquisition rather than dropping an event and continuing.
this.overflowed = true
this.open = false
this.buffered.length = 0
this.retainedBytes = 0
return false
}
this.buffered.push(event)
this.retainedBytes += bytes
return true
}
/** Closes the window and hands back what arrived while it was open, in order. */
drain(): (() => void)[] {
this.open = false
this.retainedBytes = 0
return this.buffered.splice(0)
}
}