Keep unexpected provider loss failed while retaining input fallback

This commit is contained in:
Dotta committed 2026-10-05 17:07:08 -05:00
1 parent 1998fd7ae9
commit bb7ab1cbfa
5 files changed
+65 -15

No files matched your search

@@ -4813,6 +4813,16 @@ describe("native governed waits", () => {
payload: { kind: "dynamicToolCall" },
};
// The durable fallback preserves the question after provider loss, but
// cannot turn that lost execution into a successful governed wait.
const providerLost = { ...replayedEvent, eventType: "runtime_request.expired" as const,
payload: { reason: "provider_process_lost", replayAllowed: false } };
const lostObservation = createGovernedWaitEventObservation(async () => waitResult);
await lostObservation.observe(providerLost, true);
expect(lostObservation.consume(providerLost)).toBeNull();
await lostObservation.observe(replayedEvent, true);
expect(lostObservation.consume(replayedEvent)).toBeNull();
// The event consumer can lag the provider: a commentary event emitted
// before the tool began may be processed after its approval exists in DB.
// It is not proof that the approval-creating tool response has settled.
@@ -1213,6 +1213,7 @@ export function createGovernedWaitEventObservation(
resolvePending: () => Promise<PrpStructuredRunResult | null>,
) {
const pendingTools = new Set<string>();
let providerLost = false;
let generation = 0;
let observation: {
sourceInstanceId: string;
@@ -1226,6 +1227,7 @@ export function createGovernedWaitEventObservation(
const currentGeneration = ++generation;
observation = null;
const payload = record(event.payload);
providerLost ||= event.eventType === "runtime_request.expired" && payload.reason === "provider_process_lost";
const kind = payload.kind;
const tool = ["dynamicToolCall", "mcpToolCall", "commandExecution"].includes(String(kind));
if (event.itemId) {
@@ -1241,7 +1243,9 @@ export function createGovernedWaitEventObservation(
if (event.eventType === "item.completed" && (
pendingTools.size > 0 || (!tool && !(kind === "agentMessage" && payload.channel === "final"))
)) return;
if (!eligible) return;
// A replacement question preserves human input after a provider crash;
// it does not authorize a successful suspension of the failed execution.
if (providerLost || !eligible) return;
const result = await resolvePending();
if (generation !== currentGeneration || result === null) return;
// If the interaction is answered after this read, parking remains the