| 1 | import { |
| 2 | latestProviderTurnForAttempt, |
| 3 | type MessageId, |
| 4 | type OrchestrationV2ConversationMessage, |
| 5 | type OrchestrationV2ThreadProjection, |
| 6 | } from "@t3tools/contracts"; |
| 7 | |
| 8 | /** A wake attaches to output held in provider memory, which Stop or process loss discards. */ |
| 9 | export function isBufferedProviderNotification( |
| 10 | message: OrchestrationV2ConversationMessage, |
| 11 | ): boolean { |
| 12 | return ( |
| 13 | message.createdBy === "agent" && |
| 14 | message.creationSource === "provider" && |
| 15 | message.notification !== undefined && |
| 16 | message.delegatedCompletion === undefined |
| 17 | ); |
| 18 | } |
| 19 | |
| 20 | /** |
| 21 | * A persisted steer without an acceptance receipt can be retried as a continuation. |
| 22 | * Delivery is at least once: provider acceptance and our receipt cannot commit |
| 23 | * atomically. Reusing the message ID keeps recovery from duplicating timeline items. |
| 24 | */ |
| 25 | export function isUndeliveredMailboxSteer( |
| 26 | projection: Pick<OrchestrationV2ThreadProjection, "messages" | "runs" | "providerTurns">, |
| 27 | messageId: MessageId, |
| 28 | ): boolean { |
| 29 | const message = projection.messages.find((candidate) => candidate.id === messageId); |
| 30 | if (message?.delegatedCompletion === undefined) return false; |
| 31 | const run = projection.runs.find((candidate) => candidate.id === message.runId); |
| 32 | return ( |
| 33 | run !== undefined && |
| 34 | run.userMessageId !== message.id && |
| 35 | (["completed", "failed", "interrupted", "cancelled", "rolled_back"].includes(run.status) || |
| 36 | latestProviderTurnForAttempt(projection.providerTurns, run.activeAttemptId)?.status === |
| 37 | "completed") |
| 38 | ); |
| 39 | } |