mirror of
https://github.com/stablyai/orca.git
synced 2026-10-20 00:03:45 +00:00
fix(native-chat): never let the pre-stop snapshot hold a chat's stop
Eviction now drains delivered events before quit's resume-offer snapshot. An unbounded wait there sits ahead of the provider stop, so a sink whose journal write stalls kept the child running until the step deadline aborted the eviction. The offer is advisory: bound the drain and stop the child regardless. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -94,6 +94,31 @@ describe('structured agent session eviction', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it('still stops the child when the pre-stop snapshot cannot drain the sink', async () => {
|
||||
vi.useFakeTimers({ toFake: ['setTimeout', 'clearTimeout'] })
|
||||
try {
|
||||
const ctx = context()
|
||||
const snapshot = vi.fn()
|
||||
ctx.beforeProviderChildStop = snapshot
|
||||
// A journal write that never settles, then a healthy sink once the child is stopped.
|
||||
ctx.eventSink.drained = vi
|
||||
.fn()
|
||||
.mockReturnValueOnce(new Promise(() => {}))
|
||||
.mockResolvedValue({
|
||||
ok: true
|
||||
}) as unknown as StructuredAgentSessionEvictionContext['eventSink']['drained']
|
||||
|
||||
const eviction = evictStructuredAgentSession(ctx)
|
||||
await vi.advanceTimersByTimeAsync(1_000)
|
||||
|
||||
expect(snapshot).toHaveBeenCalledOnce()
|
||||
expect(ctx.adapter.closeSession).toHaveBeenCalledOnce()
|
||||
await eviction
|
||||
} finally {
|
||||
vi.useRealTimers()
|
||||
}
|
||||
})
|
||||
|
||||
it('aborts after a failed drain barrier without unbinding or forgetting the session', async () => {
|
||||
const ctx = context()
|
||||
ctx.eventSink.drained = vi.fn(async () => {
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
type StructuredAgentSessionAdapter
|
||||
} from './structured-agent-session-adapter'
|
||||
import type { DeferredStructuredAgentSessionEventSink } from './structured-agent-session-event-sink'
|
||||
import { withTimeout } from '../../../shared/promise-timeout-fallback'
|
||||
|
||||
export type StructuredAgentSessionEvictionContext = {
|
||||
sessionId: string
|
||||
@@ -50,6 +51,9 @@ export type StructuredAgentSessionEvictionContext = {
|
||||
releaseLease: () => Promise<void>
|
||||
}
|
||||
|
||||
/** The resume offer is advisory; a stalled sink must not hold the child's stop behind it. */
|
||||
const SNAPSHOT_DRAIN_TIMEOUT_MS = 1_000
|
||||
|
||||
export type StructuredAgentSessionEvictionStep = {
|
||||
name: string
|
||||
run: (context: StructuredAgentSessionEvictionContext) => Promise<void> | void
|
||||
@@ -65,7 +69,7 @@ export const STRUCTURED_AGENT_SESSION_EVICTION_STEPS: readonly StructuredAgentSe
|
||||
return
|
||||
}
|
||||
// Events the provider already delivered are part of what the sidebar showed at the stop.
|
||||
await context.eventSink.drained()
|
||||
await withTimeout<unknown>(context.eventSink.drained(), SNAPSHOT_DRAIN_TIMEOUT_MS, null)
|
||||
try {
|
||||
context.beforeProviderChildStop()
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user