Files
orca/src/shared/agent-session-current-requests-reader.ts
T
Brennan Benson 8c1ade9e44 Keep pending chat decisions available outside loaded history (#29121)
* fix(native-chat): retire acknowledged send echoes after catch-up

* test: follow phone lint rules in reconnect regression

* test: format reconnect message expectation

* Keep current chat requests independent of loaded history

* Read current chat requests in bounded cursor pieces

* Fix current request subscription static checks

* Match generated request schema import ordering

* fix(native-chat): correct current request type boundaries

* Exercise current request reads in wire compatibility inventory

* Align current request fixtures with provider commit and RPC surface

* test(native-chat): include current request browser capability

* Keep the mobile chat session hook within its line budget

* Format mobile current request readers

* fix(native-chat): reopen once for a current-request version whose read keeps failing

A deterministic read failure reopened the subscription, whose first frame re-read the same version and reset the backoff, so the pane resubscribed every 750 ms forever.

* test(native-chat): type the current-request snapshot fixture

* test(native-chat): wait for the hydrated open before driving the subscription
2026-10-16 16:01:58 -07:00

121 lines
4.0 KiB
TypeScript

import { AGENT_SESSION_CURRENT_REQUESTS_CLIENT_CAPABILITY } from './agent-session-current-requests-capability'
import type { AgentJournalRenderItem } from './agent-session-journal-types'
import { isAdmissibleAgentJournalRenderItem } from './agent-session-journal-schemas'
import type {
AgentSessionCurrentRequestsMarker,
AgentSessionCurrentRequestsPiece,
AgentSessionCurrentRequestsRead
} from './agent-session-current-requests-wire'
/** One in-flight piece per owner, including replacement subscriptions awaiting an old reply. */
export function createAgentSessionCurrentRequestsReader(args: {
read: (request: AgentSessionCurrentRequestsRead) => Promise<AgentSessionCurrentRequestsPiece>
complete: (marker: AgentSessionCurrentRequestsMarker, items: AgentJournalRenderItem[]) => void
replaceMarker: (marker: AgentSessionCurrentRequestsMarker) => void
error: (error: unknown, marker: AgentSessionCurrentRequestsMarker) => void
}) {
let generation = 0
let desired: AgentSessionCurrentRequestsMarker | undefined
let running = false
let attempted: string | undefined
async function pump(): Promise<void> {
if (running || !desired || attempted === desired.version) {
return
}
running = true
const ownedGeneration = generation
let marker = desired
attempted = marker.version
let cursor = 0
const chunks: string[] = []
const current = () => generation === ownedGeneration && desired?.version === marker.version
try {
while (current()) {
const piece = await args.read({
sessionId: marker.sessionId,
version: marker.version,
cursor
})
if (!current()) {
return
}
if (piece.restart) {
if (
piece.marker.sessionId !== marker.sessionId ||
piece.marker.version === marker.version ||
piece.marker.contract !== AGENT_SESSION_CURRENT_REQUESTS_CLIENT_CAPABILITY
) {
throw new Error('Invalid request owner')
}
desired = marker = piece.marker
attempted = marker.version
args.replaceMarker(marker)
chunks.length = 0
cursor = 0
continue
}
if (
piece.marker.version !== marker.version ||
piece.marker.owner !== marker.owner ||
piece.marker.epoch !== marker.epoch ||
piece.marker.sessionId !== marker.sessionId
) {
throw new Error('Current-request version changed')
}
chunks.push(piece.json)
if (piece.nextCursor === null) {
const value: unknown = JSON.parse(chunks.join(''))
if (
!Array.isArray(value) ||
!value.every(isAdmissibleAgentJournalRenderItem) ||
!value.every(
(item) =>
(item.body.kind === 'approval' || item.body.kind === 'question') &&
item.body.resolution.state === 'pending'
)
) {
throw new Error('Invalid current requests')
}
args.complete(marker, value)
return
}
if (!Number.isSafeInteger(piece.nextCursor) || piece.nextCursor <= cursor) {
throw new Error('Invalid current-request cursor')
}
cursor = piece.nextCursor
}
} catch (error) {
if (current()) {
args.error(error, marker)
}
} finally {
running = false
void pump()
}
}
return {
observe(marker: AgentSessionCurrentRequestsMarker | undefined): void {
if (marker && marker.contract !== AGENT_SESSION_CURRENT_REQUESTS_CLIENT_CAPABILITY) {
return
}
if (desired?.version === marker?.version) {
return
}
if (
marker &&
desired?.publisher === marker.publisher &&
marker.revision <= desired.revision
) {
return
}
desired = marker
void pump()
},
invalidate(): void {
generation += 1
desired = undefined
attempted = undefined
}
}
}