@@ -12,14 +12,17 @@ export interface LocalConversationWork {
1212/**
1313 * Run local conversation work in this process and wait for every accepted wake.
1414 *
15- * Delayed and follow-up wakes remain tracked so CLI shutdown cannot abandon
16- * child work that was accepted while an earlier wake was running.
15+ * Wakes start on a later event-loop turn so their producer can persist the
16+ * accepted marker first. Idempotent, delayed, and follow-up wakes remain
17+ * tracked so CLI shutdown cannot abandon accepted child work.
1718 */
1819export function createLocalConversationWork (
1920 processMessage : ( message : ConversationQueueMessage ) => Promise < void > ,
2021) : LocalConversationWork {
22+ const acceptedWakeIds = new Map < string , string > ( ) ;
2123 const pending = new Set < Promise < void > > ( ) ;
2224 let firstError : unknown ;
25+ let nextWakeId = 1 ;
2326
2427 function schedule (
2528 message : ConversationQueueMessage ,
@@ -28,11 +31,9 @@ export function createLocalConversationWork(
2831 const delayMs = Math . max ( 0 , options ?. delayMs ?? 0 ) ;
2932 let work : Promise < void > ;
3033 work = ( async ( ) => {
31- if ( delayMs > 0 ) {
32- await new Promise < void > ( ( resolve ) => {
33- setTimeout ( resolve , delayMs ) ;
34- } ) ;
35- }
34+ await new Promise < void > ( ( resolve ) => {
35+ setTimeout ( resolve , delayMs ) ;
36+ } ) ;
3637 await processMessage ( message ) ;
3738 } ) ( )
3839 . catch ( ( error : unknown ) => {
@@ -47,7 +48,20 @@ export function createLocalConversationWork(
4748 return {
4849 queue : {
4950 async send ( message , options ) {
51+ const idempotencyKey = options ?. idempotencyKey ;
52+ const acceptedWakeId = idempotencyKey
53+ ? acceptedWakeIds . get ( idempotencyKey )
54+ : undefined ;
55+ if ( acceptedWakeId ) {
56+ return { messageId : acceptedWakeId } ;
57+ }
58+ const messageId = `local-conversation-work:${ nextWakeId } ` ;
59+ nextWakeId += 1 ;
60+ if ( idempotencyKey ) {
61+ acceptedWakeIds . set ( idempotencyKey , messageId ) ;
62+ }
5063 schedule ( message , options ) ;
64+ return { messageId } ;
5165 } ,
5266 } ,
5367 async drain ( ) {
0 commit comments