@meistrari/chat-nuxt 3.12.0-rc.0 → 3.12.0
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.
- package/dist/module.json +1 -1
- package/dist/runtime/embed/components/chat-embed-inner.vue +1 -2
- package/dist/runtime/embed/composables/use-agent-wake.d.ts +1 -0
- package/dist/runtime/embed/composables/use-agent-wake.js +10 -1
- package/dist/runtime/messages/composables/chat.js +52 -9
- package/dist/runtime/messages/composables/use-direct-stream.d.ts +1 -0
- package/dist/runtime/messages/composables/use-direct-stream.js +48 -12
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -286,6 +286,7 @@ async function ensureConversationLoaded(conversationId) {
|
|
|
286
286
|
}
|
|
287
287
|
function resetConversation(shouldEmit = true) {
|
|
288
288
|
clearConversation();
|
|
289
|
+
agentWake.consume();
|
|
289
290
|
void agentWake.wake(void 0, selectedModel.value);
|
|
290
291
|
activeTab.value = "chat";
|
|
291
292
|
closeFilesPanel();
|
|
@@ -481,8 +482,6 @@ async function handleSend(content, files, agentInputs) {
|
|
|
481
482
|
await agentWake.waitUntilSettled(signal);
|
|
482
483
|
if (agentWake.state.value === "idle")
|
|
483
484
|
await agentWake.wake(void 0, selectedModel.value);
|
|
484
|
-
else if (agentWake.state.value === "ready")
|
|
485
|
-
await agentWake.wake(void 0, selectedModel.value);
|
|
486
485
|
}
|
|
487
486
|
claimedWakeSessionId = claimableWakeSessionId();
|
|
488
487
|
if (!conversation.threadSessionId && !claimedWakeSessionId)
|
|
@@ -5,6 +5,7 @@ export type AgentWakeSnapshot = {
|
|
|
5
5
|
};
|
|
6
6
|
export declare function pollAgentWake(options: {
|
|
7
7
|
request: () => Promise<TelaAgentWakeResponse>;
|
|
8
|
+
requestStatus?: (sessionId: string) => Promise<TelaAgentWakeResponse>;
|
|
8
9
|
onResponse?: (response: TelaAgentWakeResponse) => void;
|
|
9
10
|
signal?: AbortSignal;
|
|
10
11
|
pollIntervalMs?: number;
|
|
@@ -22,9 +22,11 @@ export async function pollAgentWake(options) {
|
|
|
22
22
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
23
23
|
}));
|
|
24
24
|
let unavailableAttempts = 0;
|
|
25
|
+
let wakeSessionId;
|
|
25
26
|
while (!options.signal?.aborted && now() <= deadline) {
|
|
26
27
|
try {
|
|
27
|
-
const response = await options.request();
|
|
28
|
+
const response = wakeSessionId && options.requestStatus ? await options.requestStatus(wakeSessionId) : await options.request();
|
|
29
|
+
wakeSessionId = response.sessionId ?? wakeSessionId;
|
|
28
30
|
options.onResponse?.(response);
|
|
29
31
|
if (response.status === "unavailable" && unavailableAttempts < 2) {
|
|
30
32
|
unavailableAttempts += 1;
|
|
@@ -107,6 +109,13 @@ export function useAgentWake() {
|
|
|
107
109
|
}
|
|
108
110
|
})
|
|
109
111
|
),
|
|
112
|
+
requestStatus: (sessionId2) => $fetch(
|
|
113
|
+
chatApi.path(`/agent/wake/${encodeURIComponent(sessionId2)}/status`),
|
|
114
|
+
chatApi.withChatHeaders({
|
|
115
|
+
method: "GET",
|
|
116
|
+
signal: controller.signal
|
|
117
|
+
})
|
|
118
|
+
),
|
|
110
119
|
onResponse: (response) => {
|
|
111
120
|
if (currentGeneration !== generation)
|
|
112
121
|
return;
|
|
@@ -129,18 +129,16 @@ export function useChat(options = {}) {
|
|
|
129
129
|
return null;
|
|
130
130
|
return agentSessionStatus.value === "waiting_messages" && agentSessionExecutable.value;
|
|
131
131
|
});
|
|
132
|
-
const composerLocked = computed(() => hasPendingMessage.value || outbound.occupied.value);
|
|
133
|
-
const queuedMessageContent = computed(() => outbound.slot.value?.content ?? null);
|
|
134
132
|
const streamingMessageId = ref(null);
|
|
135
133
|
const pendingStreamReconciliationIds = ref(/* @__PURE__ */ new Set());
|
|
134
|
+
const pendingRealResultIds = ref(/* @__PURE__ */ new Set());
|
|
135
|
+
const composerLocked = computed(
|
|
136
|
+
() => hasPendingMessage.value || pendingRealResultIds.value.size > 0 || outbound.occupied.value
|
|
137
|
+
);
|
|
138
|
+
const queuedMessageContent = computed(() => outbound.slot.value?.content ?? null);
|
|
136
139
|
let requestDurableRecovery = () => {
|
|
137
140
|
};
|
|
138
141
|
function optimisticallyCompleteStreamedMessage(result) {
|
|
139
|
-
if (result.status === "waiting_messages") {
|
|
140
|
-
agentSessionStatus.value = "waiting_messages";
|
|
141
|
-
agentSessionExecutable.value = true;
|
|
142
|
-
agentSessionRewakeable.value = false;
|
|
143
|
-
}
|
|
144
142
|
const messageId = streamingMessageId.value;
|
|
145
143
|
if (!messageId)
|
|
146
144
|
return;
|
|
@@ -153,6 +151,10 @@ export function useChat(options = {}) {
|
|
|
153
151
|
...pendingStreamReconciliationIds.value,
|
|
154
152
|
messageId
|
|
155
153
|
]);
|
|
154
|
+
pendingRealResultIds.value = /* @__PURE__ */ new Set([
|
|
155
|
+
...pendingRealResultIds.value,
|
|
156
|
+
messageId
|
|
157
|
+
]);
|
|
156
158
|
messages.value = messages.value.map((message) => message.id === messageId ? {
|
|
157
159
|
...message,
|
|
158
160
|
content: resolveStreamingContent(message.content, result.text),
|
|
@@ -164,8 +166,22 @@ export function useChat(options = {}) {
|
|
|
164
166
|
status: ChatMessageStatus.Completed
|
|
165
167
|
});
|
|
166
168
|
}
|
|
169
|
+
function confirmStreamedResult(result) {
|
|
170
|
+
if (result.status === "waiting_messages") {
|
|
171
|
+
agentSessionStatus.value = "waiting_messages";
|
|
172
|
+
agentSessionExecutable.value = true;
|
|
173
|
+
agentSessionRewakeable.value = false;
|
|
174
|
+
}
|
|
175
|
+
const messageId = streamingMessageId.value;
|
|
176
|
+
if (!messageId || !pendingRealResultIds.value.has(messageId))
|
|
177
|
+
return;
|
|
178
|
+
const remaining = new Set(pendingRealResultIds.value);
|
|
179
|
+
remaining.delete(messageId);
|
|
180
|
+
pendingRealResultIds.value = remaining;
|
|
181
|
+
}
|
|
167
182
|
const directStream = useDirectStream({
|
|
168
|
-
|
|
183
|
+
onOptimisticResult: optimisticallyCompleteStreamedMessage,
|
|
184
|
+
onResult: confirmStreamedResult,
|
|
169
185
|
onTerminal: () => requestDurableRecovery(),
|
|
170
186
|
onDisconnect: () => requestDurableRecovery()
|
|
171
187
|
});
|
|
@@ -207,16 +223,20 @@ export function useChat(options = {}) {
|
|
|
207
223
|
return;
|
|
208
224
|
const currentMessagesById = new Map(messages.value.map((message) => [message.id, message]));
|
|
209
225
|
const remainingReconciliationIds = new Set(pendingStreamReconciliationIds.value);
|
|
226
|
+
const remainingRealResultIds = new Set(pendingRealResultIds.value);
|
|
210
227
|
const durableMessageIds = new Set(response.messages.map((message) => message.id));
|
|
211
228
|
for (const messageId of remainingReconciliationIds) {
|
|
212
|
-
if (!durableMessageIds.has(messageId))
|
|
229
|
+
if (!durableMessageIds.has(messageId)) {
|
|
213
230
|
remainingReconciliationIds.delete(messageId);
|
|
231
|
+
remainingRealResultIds.delete(messageId);
|
|
232
|
+
}
|
|
214
233
|
}
|
|
215
234
|
const reconciledMessages = response.messages.map((message) => {
|
|
216
235
|
if (!remainingReconciliationIds.has(message.id))
|
|
217
236
|
return message;
|
|
218
237
|
if (message.status === ChatMessageStatus.Completed || message.status === ChatMessageStatus.Failed) {
|
|
219
238
|
remainingReconciliationIds.delete(message.id);
|
|
239
|
+
remainingRealResultIds.delete(message.id);
|
|
220
240
|
return message;
|
|
221
241
|
}
|
|
222
242
|
const optimisticMessage = currentMessagesById.get(message.id);
|
|
@@ -224,6 +244,7 @@ export function useChat(options = {}) {
|
|
|
224
244
|
});
|
|
225
245
|
const terminalMessages = terminalMessageTransitions(messages.value, reconciledMessages);
|
|
226
246
|
pendingStreamReconciliationIds.value = remainingReconciliationIds;
|
|
247
|
+
pendingRealResultIds.value = remainingRealResultIds;
|
|
227
248
|
messages.value = reconciledMessages;
|
|
228
249
|
const latestSessionId = reconciledMessages.findLast((message) => message.agentSessionId)?.agentSessionId;
|
|
229
250
|
if (latestSessionId && currentConversation.value.threadSessionId === null) {
|
|
@@ -265,6 +286,7 @@ export function useChat(options = {}) {
|
|
|
265
286
|
});
|
|
266
287
|
const terminalMessages = terminalMessageTransitions(previousMessages, failedMessages);
|
|
267
288
|
pendingStreamReconciliationIds.value = /* @__PURE__ */ new Set();
|
|
289
|
+
pendingRealResultIds.value = /* @__PURE__ */ new Set();
|
|
268
290
|
messages.value = failedMessages;
|
|
269
291
|
for (const terminalMessage of terminalMessages)
|
|
270
292
|
chatMessageTerminal.emit(terminalMessage);
|
|
@@ -286,6 +308,11 @@ export function useChat(options = {}) {
|
|
|
286
308
|
pollGeneration++;
|
|
287
309
|
endPolling();
|
|
288
310
|
}
|
|
311
|
+
function suspendPollingForSend() {
|
|
312
|
+
pollGeneration++;
|
|
313
|
+
if (isPolling.value)
|
|
314
|
+
endPolling();
|
|
315
|
+
}
|
|
289
316
|
requestDurableRecovery = () => {
|
|
290
317
|
startPolling();
|
|
291
318
|
void pollMessages();
|
|
@@ -322,6 +349,7 @@ export function useChat(options = {}) {
|
|
|
322
349
|
currentConversation.value = { ...conv, messages: conversationMessages };
|
|
323
350
|
messages.value = conversationMessages;
|
|
324
351
|
pendingStreamReconciliationIds.value = /* @__PURE__ */ new Set();
|
|
352
|
+
pendingRealResultIds.value = /* @__PURE__ */ new Set();
|
|
325
353
|
agentSessionStatus.value = null;
|
|
326
354
|
agentSessionExecutable.value = false;
|
|
327
355
|
agentSessionRewakeable.value = false;
|
|
@@ -340,6 +368,7 @@ export function useChat(options = {}) {
|
|
|
340
368
|
currentConversation.value = data;
|
|
341
369
|
messages.value = data.messages;
|
|
342
370
|
pendingStreamReconciliationIds.value = /* @__PURE__ */ new Set();
|
|
371
|
+
pendingRealResultIds.value = /* @__PURE__ */ new Set();
|
|
343
372
|
if (shouldTreatLoadedConversationTitleAsGenerated(data.messages)) {
|
|
344
373
|
titleGenerated.value = true;
|
|
345
374
|
}
|
|
@@ -367,6 +396,9 @@ export function useChat(options = {}) {
|
|
|
367
396
|
return null;
|
|
368
397
|
if (outboundQueueEnabled.value && outbound.occupied.value && !queuedSend)
|
|
369
398
|
return null;
|
|
399
|
+
if (!queuedSend && (sending.value || hasPendingMessage.value || pendingRealResultIds.value.size > 0))
|
|
400
|
+
return null;
|
|
401
|
+
suspendPollingForSend();
|
|
370
402
|
sending.value = true;
|
|
371
403
|
error.value = null;
|
|
372
404
|
sendStartedAt = Date.now();
|
|
@@ -463,6 +495,11 @@ export function useChat(options = {}) {
|
|
|
463
495
|
return msg;
|
|
464
496
|
});
|
|
465
497
|
streamingMessageId.value = response2.assistantMessage.id;
|
|
498
|
+
if (currentConversation.value?.threadSessionId) {
|
|
499
|
+
agentSessionStatus.value = "running";
|
|
500
|
+
agentSessionExecutable.value = false;
|
|
501
|
+
agentSessionRewakeable.value = false;
|
|
502
|
+
}
|
|
466
503
|
};
|
|
467
504
|
let response;
|
|
468
505
|
let acceptedByStream = false;
|
|
@@ -481,6 +518,10 @@ export function useChat(options = {}) {
|
|
|
481
518
|
const statusCode = getChatApiErrorStatus(streamError);
|
|
482
519
|
if (statusCode !== null && statusCode >= 400 && statusCode < 500)
|
|
483
520
|
throw streamError;
|
|
521
|
+
if (outboundQueueEnabled.value) {
|
|
522
|
+
startPolling();
|
|
523
|
+
return optimisticUserMessage;
|
|
524
|
+
}
|
|
484
525
|
response = await $fetch(
|
|
485
526
|
chatApi.path(`/conversations/${currentConversation.value.id}/messages`),
|
|
486
527
|
chatApi.withChatHeaders({ method: "POST", body })
|
|
@@ -592,6 +633,7 @@ export function useChat(options = {}) {
|
|
|
592
633
|
currentConversation.value = null;
|
|
593
634
|
messages.value = [];
|
|
594
635
|
pendingStreamReconciliationIds.value = /* @__PURE__ */ new Set();
|
|
636
|
+
pendingRealResultIds.value = /* @__PURE__ */ new Set();
|
|
595
637
|
error.value = null;
|
|
596
638
|
agentSessionStatus.value = null;
|
|
597
639
|
agentSessionExecutable.value = false;
|
|
@@ -660,6 +702,7 @@ export function useChat(options = {}) {
|
|
|
660
702
|
};
|
|
661
703
|
messages.value = [];
|
|
662
704
|
pendingStreamReconciliationIds.value = /* @__PURE__ */ new Set();
|
|
705
|
+
pendingRealResultIds.value = /* @__PURE__ */ new Set();
|
|
663
706
|
streamingMessageId.value = null;
|
|
664
707
|
directStream.disconnect();
|
|
665
708
|
return true;
|
|
@@ -33,6 +33,7 @@ export declare function applyMessagePartsEvent(accumulator: MessagePartsAccumula
|
|
|
33
33
|
changed: boolean;
|
|
34
34
|
};
|
|
35
35
|
export declare function useDirectStream(options?: {
|
|
36
|
+
onOptimisticResult?: (result: DirectStreamResult) => void;
|
|
36
37
|
onResult?: (result: DirectStreamResult) => void;
|
|
37
38
|
onTerminal?: () => void;
|
|
38
39
|
onDisconnect?: () => void;
|
|
@@ -178,18 +178,51 @@ export function useDirectStream(options = {}) {
|
|
|
178
178
|
rejectAccepted = reject;
|
|
179
179
|
});
|
|
180
180
|
let accepted = false;
|
|
181
|
-
let
|
|
182
|
-
|
|
183
|
-
|
|
181
|
+
let optimisticResultReported = false;
|
|
182
|
+
let terminalEventObserved = false;
|
|
183
|
+
let terminalReported = false;
|
|
184
|
+
let recoveryRequested = false;
|
|
185
|
+
function requestRecovery() {
|
|
186
|
+
if (recoveryRequested)
|
|
184
187
|
return;
|
|
185
|
-
|
|
188
|
+
recoveryRequested = true;
|
|
189
|
+
options.onDisconnect?.();
|
|
190
|
+
}
|
|
191
|
+
function reportTerminal() {
|
|
192
|
+
if (terminalReported)
|
|
193
|
+
return;
|
|
194
|
+
terminalReported = true;
|
|
195
|
+
recoveryRequested = true;
|
|
196
|
+
options.onTerminal?.();
|
|
197
|
+
}
|
|
198
|
+
function reportOptimisticResult(status) {
|
|
186
199
|
if (status === "completed" || status === "waiting_messages") {
|
|
187
|
-
|
|
200
|
+
const result = {
|
|
188
201
|
status,
|
|
189
202
|
text: streamingText.value
|
|
190
|
-
}
|
|
203
|
+
};
|
|
204
|
+
if (!optimisticResultReported) {
|
|
205
|
+
optimisticResultReported = true;
|
|
206
|
+
options.onOptimisticResult?.(result);
|
|
207
|
+
}
|
|
208
|
+
return result;
|
|
191
209
|
}
|
|
192
|
-
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
function settleResult(status) {
|
|
213
|
+
if (terminalEventObserved)
|
|
214
|
+
return;
|
|
215
|
+
terminalEventObserved = true;
|
|
216
|
+
const result = reportOptimisticResult(status);
|
|
217
|
+
if (result)
|
|
218
|
+
options.onResult?.(result);
|
|
219
|
+
reportTerminal();
|
|
220
|
+
}
|
|
221
|
+
function settleTerminal() {
|
|
222
|
+
if (terminalEventObserved)
|
|
223
|
+
return;
|
|
224
|
+
terminalEventObserved = true;
|
|
225
|
+
reportTerminal();
|
|
193
226
|
}
|
|
194
227
|
void (async () => {
|
|
195
228
|
try {
|
|
@@ -231,15 +264,18 @@ export function useDirectStream(options = {}) {
|
|
|
231
264
|
continue;
|
|
232
265
|
activity.value = "active";
|
|
233
266
|
if (event.kind === "result") {
|
|
234
|
-
|
|
267
|
+
settleResult(event.status);
|
|
235
268
|
continue;
|
|
236
269
|
}
|
|
237
270
|
if (event.kind === "steps" && (event.status === "completed" || event.status === "waiting_messages")) {
|
|
238
|
-
|
|
271
|
+
reportOptimisticResult(event.status);
|
|
272
|
+
reportTerminal();
|
|
239
273
|
continue;
|
|
240
274
|
}
|
|
241
275
|
if (event.kind === "error") {
|
|
242
|
-
if (event.recoverable
|
|
276
|
+
if (event.recoverable === true) {
|
|
277
|
+
requestRecovery();
|
|
278
|
+
} else {
|
|
243
279
|
settleTerminal();
|
|
244
280
|
}
|
|
245
281
|
continue;
|
|
@@ -267,8 +303,8 @@ export function useDirectStream(options = {}) {
|
|
|
267
303
|
} finally {
|
|
268
304
|
if (abortController === controller)
|
|
269
305
|
abortController = null;
|
|
270
|
-
if (accepted && !
|
|
271
|
-
|
|
306
|
+
if (accepted && !terminalEventObserved && !controller.signal.aborted)
|
|
307
|
+
requestRecovery();
|
|
272
308
|
}
|
|
273
309
|
})();
|
|
274
310
|
return acceptedPromise;
|