37 lines
2.7 KiB
TypeScript
37 lines
2.7 KiB
TypeScript
import { expect, it, mock } from "bun:test";
|
|
import type { InteractionRequest } from "../../src/chat/interaction-request-contract.js";
|
|
import { reconcileInteractionDelivery } from "../../src/sessions/interaction-delivery-reconciliation.js";
|
|
import { InteractionRequestError } from "../../src/sessions/interaction-request-store.js";
|
|
|
|
const context = { actorKey: "actor", projectKey: "project", sessionId: "session" };
|
|
const record = { interaction_id: "question", status: "answered", delivery: { native_message_id: "native", revision: 2, status: "blocked", response_id: "response" } } as InteractionRequest;
|
|
|
|
it("recovers a lost acknowledgement only from consumed input and completed output without inference", async () => {
|
|
const recovered = { ...record, delivery: { ...record.delivery!, revision: 3, status: "delivered" as const } };
|
|
const updateDelivery = mock(async () => recovered);
|
|
const store = { updateDelivery } as never;
|
|
const runtime = { agentMessageState: mock(async () => "delivered" as const), readInteractionResult: mock(async () => "complete result") };
|
|
expect(await reconcileInteractionDelivery(context, record, store, runtime)).toEqual(recovered);
|
|
expect(updateDelivery).toHaveBeenCalledWith(context, "question", { expected_revision: 2, status: "delivered", response_id: "response" });
|
|
});
|
|
|
|
it("retains waiting, running, incomplete and unavailable native state", async () => {
|
|
const updateDelivery = mock(async () => record);
|
|
const store = { updateDelivery } as never;
|
|
const complete = { agentMessageState: async () => "delivered" as const, readInteractionResult: async () => "result" };
|
|
for (const runtime of [
|
|
{ ...complete, agentMessageState: async () => "enqueued" as const },
|
|
{ ...complete, agentMessageState: async () => "missing" as const },
|
|
{ ...complete, readInteractionResult: async () => { throw new Error("partial output"); } },
|
|
{ ...complete, agentMessageState: async () => { throw new Error("offline"); } }
|
|
]) expect(await reconcileInteractionDelivery(context, record, store, runtime)).toEqual(record);
|
|
expect(await reconcileInteractionDelivery(context, record, store, complete, true)).toEqual(record);
|
|
expect(updateDelivery).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("keeps concurrent cancellation instead of overwriting a newer delivery revision", async () => {
|
|
const cancelled = { ...record, delivery: { ...record.delivery!, revision: 3, status: "cancelled" as const } };
|
|
const store = { updateDelivery: async () => { throw new InteractionRequestError("revision_conflict"); }, get: async () => cancelled } as never;
|
|
expect(await reconcileInteractionDelivery(context, record, store, { agentMessageState: async () => "delivered", readInteractionResult: async () => "result" })).toEqual(cancelled);
|
|
});
|