@dexto/core 1.6.25 → 1.6.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/dist/agent/DextoAgent.cjs +102 -104
  2. package/dist/agent/DextoAgent.d.ts +11 -10
  3. package/dist/agent/DextoAgent.d.ts.map +1 -1
  4. package/dist/agent/DextoAgent.js +103 -105
  5. package/dist/agent/error-codes.cjs +1 -0
  6. package/dist/agent/error-codes.d.ts +1 -0
  7. package/dist/agent/error-codes.d.ts.map +1 -1
  8. package/dist/agent/error-codes.js +1 -0
  9. package/dist/agent/errors.cjs +13 -0
  10. package/dist/agent/errors.d.ts +6 -0
  11. package/dist/agent/errors.d.ts.map +1 -1
  12. package/dist/agent/errors.js +13 -0
  13. package/dist/agent/index.d.ts +1 -0
  14. package/dist/agent/index.d.ts.map +1 -1
  15. package/dist/agent/schemas.d.ts +2 -2
  16. package/dist/agent/types.d.ts +11 -0
  17. package/dist/agent/types.d.ts.map +1 -1
  18. package/dist/approval/factory.cjs +1 -0
  19. package/dist/approval/factory.d.ts.map +1 -1
  20. package/dist/approval/factory.js +1 -0
  21. package/dist/approval/manager.cjs +345 -182
  22. package/dist/approval/manager.d.ts +45 -31
  23. package/dist/approval/manager.d.ts.map +1 -1
  24. package/dist/approval/manager.js +345 -182
  25. package/dist/approval/schemas.cjs +10 -0
  26. package/dist/approval/schemas.d.ts +305 -0
  27. package/dist/approval/schemas.d.ts.map +1 -1
  28. package/dist/approval/schemas.js +10 -0
  29. package/dist/approval/session-approval-store.cjs +91 -0
  30. package/dist/approval/session-approval-store.d.ts +55 -0
  31. package/dist/approval/session-approval-store.d.ts.map +1 -0
  32. package/dist/approval/session-approval-store.js +68 -0
  33. package/dist/events/index.cjs +210 -75
  34. package/dist/events/index.d.ts +44 -181
  35. package/dist/events/index.d.ts.map +1 -1
  36. package/dist/events/index.js +206 -74
  37. package/dist/hooks/manager.cjs +5 -2
  38. package/dist/hooks/manager.d.ts +2 -0
  39. package/dist/hooks/manager.d.ts.map +1 -1
  40. package/dist/hooks/manager.js +5 -2
  41. package/dist/hooks/types.d.ts +3 -0
  42. package/dist/hooks/types.d.ts.map +1 -1
  43. package/dist/index.browser.d.ts +1 -0
  44. package/dist/index.browser.d.ts.map +1 -1
  45. package/dist/index.cjs +3 -1
  46. package/dist/index.d.ts +1 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +1 -0
  49. package/dist/llm/executor/turn-executor.cjs +15 -7
  50. package/dist/llm/executor/turn-executor.d.ts +3 -1
  51. package/dist/llm/executor/turn-executor.d.ts.map +1 -1
  52. package/dist/llm/executor/turn-executor.js +15 -7
  53. package/dist/llm/services/factory.cjs +10 -4
  54. package/dist/llm/services/factory.d.ts +2 -21
  55. package/dist/llm/services/factory.d.ts.map +1 -1
  56. package/dist/llm/services/factory.js +11 -7
  57. package/dist/llm/services/types.d.ts +33 -2
  58. package/dist/llm/services/types.d.ts.map +1 -1
  59. package/dist/llm/services/vercel.cjs +33 -11
  60. package/dist/llm/services/vercel.d.ts +6 -3
  61. package/dist/llm/services/vercel.d.ts.map +1 -1
  62. package/dist/llm/services/vercel.js +29 -8
  63. package/dist/logger/default-logger-factory.d.ts +12 -12
  64. package/dist/logger/v2/schemas.d.ts +6 -6
  65. package/dist/mcp/manager.cjs +7 -2
  66. package/dist/mcp/manager.d.ts +3 -1
  67. package/dist/mcp/manager.d.ts.map +1 -1
  68. package/dist/mcp/manager.js +7 -2
  69. package/dist/mcp/mcp-client.cjs +71 -62
  70. package/dist/mcp/mcp-client.d.ts +3 -2
  71. package/dist/mcp/mcp-client.d.ts.map +1 -1
  72. package/dist/mcp/mcp-client.js +71 -62
  73. package/dist/mcp/schemas.d.ts +10 -10
  74. package/dist/resources/handlers/filesystem-handler.cjs +22 -3
  75. package/dist/resources/handlers/filesystem-handler.d.ts.map +1 -1
  76. package/dist/resources/handlers/filesystem-handler.js +22 -3
  77. package/dist/runtime/host-runtime.cjs +163 -0
  78. package/dist/runtime/host-runtime.d.ts +23 -0
  79. package/dist/runtime/host-runtime.d.ts.map +1 -0
  80. package/dist/runtime/host-runtime.js +133 -0
  81. package/dist/runtime/index.cjs +42 -0
  82. package/dist/runtime/index.d.ts +2 -0
  83. package/dist/runtime/index.d.ts.map +1 -0
  84. package/dist/runtime/index.js +21 -0
  85. package/dist/runtime/run-context.cjs +53 -0
  86. package/dist/runtime/run-context.d.ts +13 -0
  87. package/dist/runtime/run-context.d.ts.map +1 -0
  88. package/dist/runtime/run-context.js +34 -0
  89. package/dist/session/chat-session.cjs +67 -71
  90. package/dist/session/chat-session.d.ts +25 -25
  91. package/dist/session/chat-session.d.ts.map +1 -1
  92. package/dist/session/chat-session.js +68 -72
  93. package/dist/session/error-codes.cjs +1 -0
  94. package/dist/session/error-codes.d.ts +2 -1
  95. package/dist/session/error-codes.d.ts.map +1 -1
  96. package/dist/session/error-codes.js +1 -0
  97. package/dist/session/errors.cjs +13 -0
  98. package/dist/session/errors.d.ts +6 -0
  99. package/dist/session/errors.d.ts.map +1 -1
  100. package/dist/session/errors.js +13 -0
  101. package/dist/session/message-queue-store.cjs +75 -0
  102. package/dist/session/message-queue-store.d.ts +16 -0
  103. package/dist/session/message-queue-store.d.ts.map +1 -0
  104. package/dist/session/message-queue-store.js +52 -0
  105. package/dist/session/message-queue.cjs +140 -46
  106. package/dist/session/message-queue.d.ts +18 -6
  107. package/dist/session/message-queue.d.ts.map +1 -1
  108. package/dist/session/message-queue.js +140 -46
  109. package/dist/session/session-manager.cjs +130 -25
  110. package/dist/session/session-manager.d.ts +18 -1
  111. package/dist/session/session-manager.d.ts.map +1 -1
  112. package/dist/session/session-manager.js +130 -25
  113. package/dist/session/title-generator.cjs +9 -2
  114. package/dist/session/title-generator.d.ts +2 -0
  115. package/dist/session/title-generator.d.ts.map +1 -1
  116. package/dist/session/title-generator.js +9 -2
  117. package/dist/telemetry/decorators.cjs +75 -57
  118. package/dist/telemetry/decorators.d.ts +2 -0
  119. package/dist/telemetry/decorators.d.ts.map +1 -1
  120. package/dist/telemetry/decorators.js +75 -57
  121. package/dist/telemetry/errors.cjs +2 -2
  122. package/dist/telemetry/errors.js +2 -2
  123. package/dist/telemetry/index.d.ts +1 -1
  124. package/dist/telemetry/index.d.ts.map +1 -1
  125. package/dist/telemetry/index.js +3 -1
  126. package/dist/telemetry/telemetry.cjs +62 -21
  127. package/dist/telemetry/telemetry.d.ts +14 -0
  128. package/dist/telemetry/telemetry.d.ts.map +1 -1
  129. package/dist/telemetry/telemetry.js +62 -21
  130. package/dist/telemetry/utils.cjs +9 -6
  131. package/dist/telemetry/utils.d.ts +3 -0
  132. package/dist/telemetry/utils.d.ts.map +1 -1
  133. package/dist/telemetry/utils.js +9 -6
  134. package/dist/test-utils/session-state-stores.cjs +68 -0
  135. package/dist/test-utils/session-state-stores.js +42 -0
  136. package/dist/tools/session-tool-preferences-store.cjs +86 -0
  137. package/dist/tools/session-tool-preferences-store.d.ts +29 -0
  138. package/dist/tools/session-tool-preferences-store.d.ts.map +1 -0
  139. package/dist/tools/session-tool-preferences-store.js +63 -0
  140. package/dist/tools/tool-manager.cjs +223 -68
  141. package/dist/tools/tool-manager.d.ts +29 -9
  142. package/dist/tools/tool-manager.d.ts.map +1 -1
  143. package/dist/tools/tool-manager.js +223 -68
  144. package/dist/tools/types.d.ts +7 -1
  145. package/dist/tools/types.d.ts.map +1 -1
  146. package/dist/utils/service-initializer.cjs +38 -5
  147. package/dist/utils/service-initializer.d.ts +11 -1
  148. package/dist/utils/service-initializer.d.ts.map +1 -1
  149. package/dist/utils/service-initializer.js +36 -4
  150. package/package.json +1 -1
@@ -21,15 +21,71 @@ __export(message_queue_exports, {
21
21
  MessageQueueService: () => MessageQueueService
22
22
  });
23
23
  module.exports = __toCommonJS(message_queue_exports);
24
+ class EphemeralMessageQueueStore {
25
+ async load(sessionId) {
26
+ void sessionId;
27
+ return [];
28
+ }
29
+ async save(sessionId, queue) {
30
+ void sessionId;
31
+ void queue;
32
+ }
33
+ async delete(sessionId) {
34
+ void sessionId;
35
+ }
36
+ }
24
37
  function generateId() {
25
38
  return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
26
39
  }
27
40
  class MessageQueueService {
28
- constructor(eventBus, logger) {
41
+ constructor(eventBus, logger, sessionId, store) {
29
42
  this.eventBus = eventBus;
30
43
  this.logger = logger;
44
+ this.sessionId = sessionId;
45
+ this.store = store;
31
46
  }
32
47
  queue = [];
48
+ mutationLock = Promise.resolve();
49
+ initialized = false;
50
+ initializationPromise = null;
51
+ static createEphemeral(eventBus, logger, sessionId) {
52
+ return new MessageQueueService(
53
+ eventBus,
54
+ logger,
55
+ sessionId,
56
+ new EphemeralMessageQueueStore()
57
+ );
58
+ }
59
+ async initialize() {
60
+ this.initializationPromise ??= this.runWithMutationLock(async () => {
61
+ if (this.initialized) {
62
+ return;
63
+ }
64
+ this.queue = await this.store.load(this.sessionId);
65
+ if (this.queue.length > 0) {
66
+ this.logger.debug(
67
+ `Restored ${this.queue.length} queued message(s) for session ${this.sessionId}`
68
+ );
69
+ }
70
+ this.initialized = true;
71
+ }).catch((error) => {
72
+ this.initializationPromise = null;
73
+ throw error;
74
+ });
75
+ await this.initializationPromise;
76
+ }
77
+ async persistQueue() {
78
+ await this.store.save(this.sessionId, this.queue);
79
+ }
80
+ runWithMutationLock(fn) {
81
+ const currentResult = this.mutationLock.catch(() => {
82
+ }).then(() => fn());
83
+ this.mutationLock = currentResult.then(
84
+ () => void 0,
85
+ () => void 0
86
+ );
87
+ return currentResult;
88
+ }
33
89
  /**
34
90
  * Add a message to the queue.
35
91
  * Called by API endpoint - returns immediately with queue position.
@@ -37,25 +93,33 @@ class MessageQueueService {
37
93
  * @param message The user message to queue
38
94
  * @returns Queue position and message ID
39
95
  */
40
- enqueue(message) {
41
- const queuedMsg = {
42
- id: generateId(),
43
- content: message.content,
44
- queuedAt: Date.now(),
45
- ...message.metadata !== void 0 && { metadata: message.metadata },
46
- ...message.kind !== void 0 && { kind: message.kind }
47
- };
48
- this.queue.push(queuedMsg);
49
- this.logger.debug(`Message queued: ${queuedMsg.id}, position: ${this.queue.length}`);
50
- this.eventBus.emit("message:queued", {
51
- position: this.queue.length,
52
- id: queuedMsg.id
96
+ async enqueue(message) {
97
+ return await this.runWithMutationLock(async () => {
98
+ const queuedMsg = {
99
+ id: generateId(),
100
+ content: message.content,
101
+ queuedAt: Date.now(),
102
+ ...message.metadata !== void 0 && { metadata: message.metadata },
103
+ ...message.kind !== void 0 && { kind: message.kind }
104
+ };
105
+ this.queue.push(queuedMsg);
106
+ try {
107
+ await this.persistQueue();
108
+ } catch (error) {
109
+ this.queue.pop();
110
+ throw error;
111
+ }
112
+ this.logger.debug(`Message queued: ${queuedMsg.id}, position: ${this.queue.length}`);
113
+ this.eventBus.emit("message:queued", {
114
+ position: this.queue.length,
115
+ id: queuedMsg.id
116
+ });
117
+ return {
118
+ queued: true,
119
+ position: this.queue.length,
120
+ id: queuedMsg.id
121
+ };
53
122
  });
54
- return {
55
- queued: true,
56
- position: this.queue.length,
57
- id: queuedMsg.id
58
- };
59
123
  }
60
124
  /**
61
125
  * Dequeue ALL pending messages and coalesce into single injection.
@@ -76,22 +140,30 @@ class MessageQueueService {
76
140
  *
77
141
  * @returns Coalesced message or null if queue is empty
78
142
  */
79
- dequeueAll() {
80
- if (this.queue.length === 0) return null;
81
- const messages = [...this.queue];
82
- this.queue = [];
83
- const combined = this.coalesce(messages);
84
- this.logger.debug(
85
- `Dequeued ${messages.length} message(s): ${messages.map((m) => m.id).join(", ")}`
86
- );
87
- this.eventBus.emit("message:dequeued", {
88
- count: messages.length,
89
- ids: messages.map((m) => m.id),
90
- coalesced: messages.length > 1,
91
- content: combined.combinedContent,
92
- messages
143
+ async dequeueAll() {
144
+ return await this.runWithMutationLock(async () => {
145
+ if (this.queue.length === 0) return null;
146
+ const messages = [...this.queue];
147
+ this.queue = [];
148
+ try {
149
+ await this.persistQueue();
150
+ } catch (error) {
151
+ this.queue = messages;
152
+ throw error;
153
+ }
154
+ const combined = this.coalesce(messages);
155
+ this.logger.debug(
156
+ `Dequeued ${messages.length} message(s): ${messages.map((m) => m.id).join(", ")}`
157
+ );
158
+ this.eventBus.emit("message:dequeued", {
159
+ count: messages.length,
160
+ ids: messages.map((m) => m.id),
161
+ coalesced: messages.length > 1,
162
+ content: combined.combinedContent,
163
+ messages
164
+ });
165
+ return combined;
93
166
  });
94
- return combined;
95
167
  }
96
168
  /**
97
169
  * Coalesce multiple messages into one (multimodal-aware).
@@ -187,8 +259,20 @@ class MessageQueueService {
187
259
  * Clear all pending messages without processing.
188
260
  * Used during cleanup/abort.
189
261
  */
190
- clear() {
191
- this.queue = [];
262
+ async clear() {
263
+ await this.runWithMutationLock(async () => {
264
+ if (this.queue.length === 0) {
265
+ return;
266
+ }
267
+ const previousQueue = [...this.queue];
268
+ this.queue = [];
269
+ try {
270
+ await this.persistQueue();
271
+ } catch (error) {
272
+ this.queue = previousQueue;
273
+ throw error;
274
+ }
275
+ });
192
276
  }
193
277
  /**
194
278
  * Get all queued messages (for UI display).
@@ -207,16 +291,26 @@ class MessageQueueService {
207
291
  * Remove a single queued message by ID.
208
292
  * @returns true if message was found and removed; false otherwise
209
293
  */
210
- remove(id) {
211
- const index = this.queue.findIndex((m) => m.id === id);
212
- if (index === -1) {
213
- this.logger.debug(`Remove failed: message ${id} not found in queue`);
214
- return false;
215
- }
216
- this.queue.splice(index, 1);
217
- this.logger.debug(`Message removed: ${id}, remaining: ${this.queue.length}`);
218
- this.eventBus.emit("message:removed", { id });
219
- return true;
294
+ async remove(id) {
295
+ return await this.runWithMutationLock(async () => {
296
+ const index = this.queue.findIndex((m) => m.id === id);
297
+ if (index === -1) {
298
+ this.logger.debug(`Remove failed: message ${id} not found in queue`);
299
+ return false;
300
+ }
301
+ const [removed] = this.queue.splice(index, 1);
302
+ try {
303
+ await this.persistQueue();
304
+ } catch (error) {
305
+ if (removed) {
306
+ this.queue.splice(index, 0, removed);
307
+ }
308
+ throw error;
309
+ }
310
+ this.logger.debug(`Message removed: ${id}, remaining: ${this.queue.length}`);
311
+ this.eventBus.emit("message:removed", { id });
312
+ return true;
313
+ });
220
314
  }
221
315
  }
222
316
  // Annotate the CommonJS export names for ESM import in node:
@@ -2,6 +2,8 @@ import type { SessionEventBus } from '../events/index.js';
2
2
  import type { QueuedMessage, CoalescedMessage } from './types.js';
3
3
  import type { ContentPart } from '../context/types.js';
4
4
  import type { Logger } from '../logger/v2/types.js';
5
+ import type { MessageQueueStore } from './message-queue-store.js';
6
+ type MessageQueueBackingStore = Pick<MessageQueueStore, 'load' | 'save' | 'delete'>;
5
7
  /**
6
8
  * Input for enqueuing a user message to the queue.
7
9
  * (Not to be confused with UserMessage from context/types.ts which represents
@@ -46,8 +48,17 @@ export interface UserMessageInput {
46
48
  export declare class MessageQueueService {
47
49
  private eventBus;
48
50
  private logger;
51
+ private sessionId;
52
+ private store;
49
53
  private queue;
50
- constructor(eventBus: SessionEventBus, logger: Logger);
54
+ private mutationLock;
55
+ private initialized;
56
+ private initializationPromise;
57
+ static createEphemeral(eventBus: SessionEventBus, logger: Logger, sessionId: string): MessageQueueService;
58
+ constructor(eventBus: SessionEventBus, logger: Logger, sessionId: string, store: MessageQueueBackingStore);
59
+ initialize(): Promise<void>;
60
+ private persistQueue;
61
+ private runWithMutationLock;
51
62
  /**
52
63
  * Add a message to the queue.
53
64
  * Called by API endpoint - returns immediately with queue position.
@@ -55,11 +66,11 @@ export declare class MessageQueueService {
55
66
  * @param message The user message to queue
56
67
  * @returns Queue position and message ID
57
68
  */
58
- enqueue(message: UserMessageInput): {
69
+ enqueue(message: UserMessageInput): Promise<{
59
70
  queued: true;
60
71
  position: number;
61
72
  id: string;
62
- };
73
+ }>;
63
74
  /**
64
75
  * Dequeue ALL pending messages and coalesce into single injection.
65
76
  * Called by executor between steps.
@@ -79,7 +90,7 @@ export declare class MessageQueueService {
79
90
  *
80
91
  * @returns Coalesced message or null if queue is empty
81
92
  */
82
- dequeueAll(): CoalescedMessage | null;
93
+ dequeueAll(): Promise<CoalescedMessage | null>;
83
94
  /**
84
95
  * Coalesce multiple messages into one (multimodal-aware).
85
96
  * Strategy: Combine with per-kind formatting, preserve all media.
@@ -97,7 +108,7 @@ export declare class MessageQueueService {
97
108
  * Clear all pending messages without processing.
98
109
  * Used during cleanup/abort.
99
110
  */
100
- clear(): void;
111
+ clear(): Promise<void>;
101
112
  /**
102
113
  * Get all queued messages (for UI display).
103
114
  * Returns a shallow copy to prevent external mutation.
@@ -111,6 +122,7 @@ export declare class MessageQueueService {
111
122
  * Remove a single queued message by ID.
112
123
  * @returns true if message was found and removed; false otherwise
113
124
  */
114
- remove(id: string): boolean;
125
+ remove(id: string): Promise<boolean>;
115
126
  }
127
+ export {};
116
128
  //# sourceMappingURL=message-queue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"message-queue.d.ts","sourceRoot":"","sources":["../../src/session/message-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AASpD;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC7B,2DAA2D;IAC3D,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,sCAAsC;IACtC,IAAI,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,mBAAmB;IAIxB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,MAAM;IAJlB,OAAO,CAAC,KAAK,CAAuB;gBAGxB,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,MAAM;IAG1B;;;;;;OAMG;IACH,OAAO,CAAC,OAAO,EAAE,gBAAgB,GAAG;QAAE,MAAM,EAAE,IAAI,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE;IAyBlF;;;;;;;;;;;;;;;;;;OAkBG;IACH,UAAU,IAAI,gBAAgB,GAAG,IAAI;IAuBrC;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAuGhB;;OAEG;IACH,UAAU,IAAI,OAAO;IAIrB;;OAEG;IACH,YAAY,IAAI,MAAM;IAItB;;;OAGG;IACH,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACH,MAAM,IAAI,aAAa,EAAE;IAIzB;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI1C;;;OAGG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;CAY9B"}
1
+ {"version":3,"file":"message-queue.d.ts","sourceRoot":"","sources":["../../src/session/message-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,KAAK,wBAAwB,GAAG,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC,CAAC;AAyBpF;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC7B,2DAA2D;IAC3D,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,sCAAsC;IACtC,IAAI,CAAC,EAAE,SAAS,GAAG,YAAY,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,mBAAmB;IAoBxB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,KAAK;IAtBjB,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,qBAAqB,CAA8B;IAE3D,MAAM,CAAC,eAAe,CAClB,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAClB,mBAAmB;gBAUV,QAAQ,EAAE,eAAe,EACzB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,wBAAwB;IAGrC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAsBnB,YAAY;IAI1B,OAAO,CAAC,mBAAmB;IAS3B;;;;;;OAMG;IACG,OAAO,CACT,OAAO,EAAE,gBAAgB,GAC1B,OAAO,CAAC;QAAE,MAAM,EAAE,IAAI,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAkC1D;;;;;;;;;;;;;;;;;;OAkBG;IACG,UAAU,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAgCpD;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAuGhB;;OAEG;IACH,UAAU,IAAI,OAAO;IAIrB;;OAEG;IACH,YAAY,IAAI,MAAM;IAItB;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB5B;;;OAGG;IACH,MAAM,IAAI,aAAa,EAAE;IAIzB;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI1C;;;OAGG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAwB7C"}
@@ -1,13 +1,69 @@
1
1
  import "../chunk-PTJYTZNU.js";
2
+ class EphemeralMessageQueueStore {
3
+ async load(sessionId) {
4
+ void sessionId;
5
+ return [];
6
+ }
7
+ async save(sessionId, queue) {
8
+ void sessionId;
9
+ void queue;
10
+ }
11
+ async delete(sessionId) {
12
+ void sessionId;
13
+ }
14
+ }
2
15
  function generateId() {
3
16
  return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
4
17
  }
5
18
  class MessageQueueService {
6
- constructor(eventBus, logger) {
19
+ constructor(eventBus, logger, sessionId, store) {
7
20
  this.eventBus = eventBus;
8
21
  this.logger = logger;
22
+ this.sessionId = sessionId;
23
+ this.store = store;
9
24
  }
10
25
  queue = [];
26
+ mutationLock = Promise.resolve();
27
+ initialized = false;
28
+ initializationPromise = null;
29
+ static createEphemeral(eventBus, logger, sessionId) {
30
+ return new MessageQueueService(
31
+ eventBus,
32
+ logger,
33
+ sessionId,
34
+ new EphemeralMessageQueueStore()
35
+ );
36
+ }
37
+ async initialize() {
38
+ this.initializationPromise ??= this.runWithMutationLock(async () => {
39
+ if (this.initialized) {
40
+ return;
41
+ }
42
+ this.queue = await this.store.load(this.sessionId);
43
+ if (this.queue.length > 0) {
44
+ this.logger.debug(
45
+ `Restored ${this.queue.length} queued message(s) for session ${this.sessionId}`
46
+ );
47
+ }
48
+ this.initialized = true;
49
+ }).catch((error) => {
50
+ this.initializationPromise = null;
51
+ throw error;
52
+ });
53
+ await this.initializationPromise;
54
+ }
55
+ async persistQueue() {
56
+ await this.store.save(this.sessionId, this.queue);
57
+ }
58
+ runWithMutationLock(fn) {
59
+ const currentResult = this.mutationLock.catch(() => {
60
+ }).then(() => fn());
61
+ this.mutationLock = currentResult.then(
62
+ () => void 0,
63
+ () => void 0
64
+ );
65
+ return currentResult;
66
+ }
11
67
  /**
12
68
  * Add a message to the queue.
13
69
  * Called by API endpoint - returns immediately with queue position.
@@ -15,25 +71,33 @@ class MessageQueueService {
15
71
  * @param message The user message to queue
16
72
  * @returns Queue position and message ID
17
73
  */
18
- enqueue(message) {
19
- const queuedMsg = {
20
- id: generateId(),
21
- content: message.content,
22
- queuedAt: Date.now(),
23
- ...message.metadata !== void 0 && { metadata: message.metadata },
24
- ...message.kind !== void 0 && { kind: message.kind }
25
- };
26
- this.queue.push(queuedMsg);
27
- this.logger.debug(`Message queued: ${queuedMsg.id}, position: ${this.queue.length}`);
28
- this.eventBus.emit("message:queued", {
29
- position: this.queue.length,
30
- id: queuedMsg.id
74
+ async enqueue(message) {
75
+ return await this.runWithMutationLock(async () => {
76
+ const queuedMsg = {
77
+ id: generateId(),
78
+ content: message.content,
79
+ queuedAt: Date.now(),
80
+ ...message.metadata !== void 0 && { metadata: message.metadata },
81
+ ...message.kind !== void 0 && { kind: message.kind }
82
+ };
83
+ this.queue.push(queuedMsg);
84
+ try {
85
+ await this.persistQueue();
86
+ } catch (error) {
87
+ this.queue.pop();
88
+ throw error;
89
+ }
90
+ this.logger.debug(`Message queued: ${queuedMsg.id}, position: ${this.queue.length}`);
91
+ this.eventBus.emit("message:queued", {
92
+ position: this.queue.length,
93
+ id: queuedMsg.id
94
+ });
95
+ return {
96
+ queued: true,
97
+ position: this.queue.length,
98
+ id: queuedMsg.id
99
+ };
31
100
  });
32
- return {
33
- queued: true,
34
- position: this.queue.length,
35
- id: queuedMsg.id
36
- };
37
101
  }
38
102
  /**
39
103
  * Dequeue ALL pending messages and coalesce into single injection.
@@ -54,22 +118,30 @@ class MessageQueueService {
54
118
  *
55
119
  * @returns Coalesced message or null if queue is empty
56
120
  */
57
- dequeueAll() {
58
- if (this.queue.length === 0) return null;
59
- const messages = [...this.queue];
60
- this.queue = [];
61
- const combined = this.coalesce(messages);
62
- this.logger.debug(
63
- `Dequeued ${messages.length} message(s): ${messages.map((m) => m.id).join(", ")}`
64
- );
65
- this.eventBus.emit("message:dequeued", {
66
- count: messages.length,
67
- ids: messages.map((m) => m.id),
68
- coalesced: messages.length > 1,
69
- content: combined.combinedContent,
70
- messages
121
+ async dequeueAll() {
122
+ return await this.runWithMutationLock(async () => {
123
+ if (this.queue.length === 0) return null;
124
+ const messages = [...this.queue];
125
+ this.queue = [];
126
+ try {
127
+ await this.persistQueue();
128
+ } catch (error) {
129
+ this.queue = messages;
130
+ throw error;
131
+ }
132
+ const combined = this.coalesce(messages);
133
+ this.logger.debug(
134
+ `Dequeued ${messages.length} message(s): ${messages.map((m) => m.id).join(", ")}`
135
+ );
136
+ this.eventBus.emit("message:dequeued", {
137
+ count: messages.length,
138
+ ids: messages.map((m) => m.id),
139
+ coalesced: messages.length > 1,
140
+ content: combined.combinedContent,
141
+ messages
142
+ });
143
+ return combined;
71
144
  });
72
- return combined;
73
145
  }
74
146
  /**
75
147
  * Coalesce multiple messages into one (multimodal-aware).
@@ -165,8 +237,20 @@ class MessageQueueService {
165
237
  * Clear all pending messages without processing.
166
238
  * Used during cleanup/abort.
167
239
  */
168
- clear() {
169
- this.queue = [];
240
+ async clear() {
241
+ await this.runWithMutationLock(async () => {
242
+ if (this.queue.length === 0) {
243
+ return;
244
+ }
245
+ const previousQueue = [...this.queue];
246
+ this.queue = [];
247
+ try {
248
+ await this.persistQueue();
249
+ } catch (error) {
250
+ this.queue = previousQueue;
251
+ throw error;
252
+ }
253
+ });
170
254
  }
171
255
  /**
172
256
  * Get all queued messages (for UI display).
@@ -185,16 +269,26 @@ class MessageQueueService {
185
269
  * Remove a single queued message by ID.
186
270
  * @returns true if message was found and removed; false otherwise
187
271
  */
188
- remove(id) {
189
- const index = this.queue.findIndex((m) => m.id === id);
190
- if (index === -1) {
191
- this.logger.debug(`Remove failed: message ${id} not found in queue`);
192
- return false;
193
- }
194
- this.queue.splice(index, 1);
195
- this.logger.debug(`Message removed: ${id}, remaining: ${this.queue.length}`);
196
- this.eventBus.emit("message:removed", { id });
197
- return true;
272
+ async remove(id) {
273
+ return await this.runWithMutationLock(async () => {
274
+ const index = this.queue.findIndex((m) => m.id === id);
275
+ if (index === -1) {
276
+ this.logger.debug(`Remove failed: message ${id} not found in queue`);
277
+ return false;
278
+ }
279
+ const [removed] = this.queue.splice(index, 1);
280
+ try {
281
+ await this.persistQueue();
282
+ } catch (error) {
283
+ if (removed) {
284
+ this.queue.splice(index, 0, removed);
285
+ }
286
+ throw error;
287
+ }
288
+ this.logger.debug(`Message removed: ${id}, remaining: ${this.queue.length}`);
289
+ this.eventBus.emit("message:removed", { id });
290
+ return true;
291
+ });
198
292
  }
199
293
  }
200
294
  export {