fix(omp): drop a prompt's client correlation when its dispatch fails

This commit is contained in:
paseo-bot
2026-09-22 20:13:33 +02:00
parent 163b6df4b3
commit bcb9724907
3 changed files with 46 additions and 0 deletions
@@ -754,6 +754,34 @@ describe("OMP agent client and session", () => {
]);
});
test("a prompt that never reaches OMP leaves no correlation for a later submission", async () => {
const omp = new OmpHarness();
await omp.start();
const runtime = omp.runtime();
runtime.promptError = new Error("OMP prompt dispatch failed");
await omp.requireStartTurnFromClient("retry me", "client-a");
await settle();
expect(omp.eventTypes()).toContain("turn_failed");
runtime.promptError = null;
await omp.requireStartTurnFromClient("retry me", "client-b");
runtime.beginTurn();
runtime.acceptPrompt("retry me", "omp-user-b");
runtime.streamAssistantText("done", "omp-assistant-b");
runtime.finishTurn();
await settle();
expect(omp.timeline().filter((item) => item.type === "user_message")).toEqual([
{
type: "user_message",
text: "retry me",
messageId: "omp-user-b",
clientMessageId: "client-b",
},
]);
});
test("the same prompt text on two turns correlates to its own submission", async () => {
const omp = new OmpHarness();
await omp.start();
@@ -999,6 +999,8 @@ export class OmpAgentSession implements AgentSession {
return;
}
} catch (error) {
// The prompt never reached OMP, so no echo will ever claim it.
this.forgetClientCorrelation(options?.clientMessageId);
if (this.activeTurnId !== turnId) {
return;
}
@@ -1305,6 +1307,18 @@ export class OmpAgentSession implements AgentSession {
}
}
private forgetClientCorrelation(clientMessageId: string | undefined): void {
if (!clientMessageId) {
return;
}
const index = this.pendingClientCorrelations.findIndex(
(entry) => entry.clientMessageId === clientMessageId,
);
if (index !== -1) {
this.pendingClientCorrelations.splice(index, 1);
}
}
private takeClientCorrelation(text: string): string | null {
const index = this.pendingClientCorrelations.findIndex((entry) => entry.text === text);
if (index === -1) {
@@ -131,6 +131,7 @@ export class FakeOmpSession implements OmpRuntimeSession {
compactError: Error | null = null;
emitCompactEnd = true;
getStateError: Error | null = null;
promptError: Error | null = null;
promptAck: OmpPromptAck = {};
branchResponse: { text?: string; cancelled?: boolean } = { text: "" };
branchMessages: Array<{ entryId: string; text: string }> = [];
@@ -180,6 +181,9 @@ export class FakeOmpSession implements OmpRuntimeSession {
}
this.prompts.push({ message, imageCount: images?.length ?? 0 });
this.promptWaiters.shift()?.();
if (this.promptError) {
throw this.promptError;
}
const heldPrompt = this.nextHeldPrompt;
if (heldPrompt) {
this.nextHeldPrompt = null;