@meistrari/chat-nuxt 3.16.0-rc.0 → 3.16.0-rc.1
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/messages/components/chat-message-bubble.vue +4 -5
- package/dist/runtime/messages/composables/chat.js +3 -8
- package/dist/runtime/messages/composables/use-direct-stream.js +7 -7
- package/dist/runtime/messages/message-reasoning.d.ts +9 -2
- package/dist/runtime/messages/message-reasoning.js +30 -13
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -180,13 +180,12 @@ const hasDetectedFiles = computed(() => contentSegments.value.some((s) => s.type
|
|
|
180
180
|
|
|
181
181
|
<template v-else>
|
|
182
182
|
<!--
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
exactly what they cover.
|
|
183
|
+
Mounted for the whole pending turn so activity remains visible
|
|
184
|
+
while the current streamed chunk is empty between assistant
|
|
185
|
+
messages or tool phases.
|
|
187
186
|
-->
|
|
188
187
|
<ChatReasoningThought
|
|
189
|
-
v-if="hasReasoning ||
|
|
188
|
+
v-if="hasReasoning || isPending"
|
|
190
189
|
:reasoning-data="message.reasoningData ?? []"
|
|
191
190
|
:completed="!isPending"
|
|
192
191
|
:preparing-steps="preparingSteps"
|
|
@@ -207,12 +207,10 @@ export function useChat(options = {}) {
|
|
|
207
207
|
);
|
|
208
208
|
const reasoningCache = createReasoningCache();
|
|
209
209
|
const processedMessages = computed(() => {
|
|
210
|
-
const resolved = resolveReasoningDisplayMessages(messages.value, reasoningCache);
|
|
211
210
|
const messageId = streamingMessageId.value;
|
|
212
211
|
const content = directStream.streamingText.value;
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
return resolved.map((message) => message.id === messageId && (message.status === "pending" || pendingStreamReconciliationIds.value.has(message.id)) ? { ...message, content: resolveStreamingContent(message.content, content) } : message);
|
|
212
|
+
const overlaid = !messageId || content === null ? messages.value : messages.value.map((message) => message.id === messageId && (message.status === "pending" || pendingStreamReconciliationIds.value.has(message.id)) ? { ...message, content } : message);
|
|
213
|
+
return resolveReasoningDisplayMessages(overlaid, reasoningCache);
|
|
216
214
|
});
|
|
217
215
|
const stopCondition = computed(
|
|
218
216
|
() => !hasPendingMessage.value && pendingStreamReconciliationIds.value.size === 0
|
|
@@ -529,9 +527,9 @@ export function useChat(options = {}) {
|
|
|
529
527
|
agentSessionExecutable.value = false;
|
|
530
528
|
agentSessionRewakeable.value = false;
|
|
531
529
|
}
|
|
530
|
+
startPolling();
|
|
532
531
|
};
|
|
533
532
|
let response;
|
|
534
|
-
let acceptedByStream = false;
|
|
535
533
|
try {
|
|
536
534
|
response = await directStream.connectMessage(
|
|
537
535
|
chatApi.path(`/conversations/${currentConversation.value.id}/messages/stream`),
|
|
@@ -542,7 +540,6 @@ export function useChat(options = {}) {
|
|
|
542
540
|
}),
|
|
543
541
|
acceptMessagePair
|
|
544
542
|
);
|
|
545
|
-
acceptedByStream = true;
|
|
546
543
|
} catch (streamError) {
|
|
547
544
|
const statusCode = getChatApiErrorStatus(streamError);
|
|
548
545
|
if (statusCode !== null && statusCode >= 400 && statusCode < 500)
|
|
@@ -565,8 +562,6 @@ export function useChat(options = {}) {
|
|
|
565
562
|
"user"
|
|
566
563
|
);
|
|
567
564
|
}
|
|
568
|
-
if (!acceptedByStream)
|
|
569
|
-
startPolling();
|
|
570
565
|
return response.userMessage;
|
|
571
566
|
} catch (err) {
|
|
572
567
|
const code = getChatApiErrorCode(err);
|
|
@@ -115,7 +115,7 @@ function reviveMessagePair(input) {
|
|
|
115
115
|
}
|
|
116
116
|
export function useDirectStream(options = {}) {
|
|
117
117
|
const activity = ref("idle");
|
|
118
|
-
const streamingText = ref(
|
|
118
|
+
const streamingText = ref(null);
|
|
119
119
|
const streamingThinking = ref("");
|
|
120
120
|
const activeRunId = ref(null);
|
|
121
121
|
let accumulator = createMessagePartsAccumulator();
|
|
@@ -123,7 +123,7 @@ export function useDirectStream(options = {}) {
|
|
|
123
123
|
function resetAccumulator(runId = null) {
|
|
124
124
|
accumulator = createMessagePartsAccumulator(runId);
|
|
125
125
|
activeRunId.value = runId;
|
|
126
|
-
streamingText.value =
|
|
126
|
+
streamingText.value = null;
|
|
127
127
|
streamingThinking.value = "";
|
|
128
128
|
}
|
|
129
129
|
function beginMessage() {
|
|
@@ -199,7 +199,7 @@ export function useDirectStream(options = {}) {
|
|
|
199
199
|
if (status === "completed" || status === "waiting_messages") {
|
|
200
200
|
const result = {
|
|
201
201
|
status,
|
|
202
|
-
text: streamingText.value
|
|
202
|
+
text: streamingText.value ?? ""
|
|
203
203
|
};
|
|
204
204
|
if (!optimisticResultReported) {
|
|
205
205
|
optimisticResultReported = true;
|
|
@@ -287,11 +287,11 @@ export function useDirectStream(options = {}) {
|
|
|
287
287
|
if (event.kind !== "message-parts" || typeof event.runId !== "string" || typeof event.deltaSeq !== "number" || !Number.isInteger(event.deltaSeq) || event.deltaSeq < 0 || !isRecord(event.event)) {
|
|
288
288
|
continue;
|
|
289
289
|
}
|
|
290
|
-
const
|
|
290
|
+
const current = applyMessagePartsEvent(accumulator, event);
|
|
291
291
|
activeRunId.value = accumulator.runId;
|
|
292
|
-
if (
|
|
293
|
-
streamingText.value =
|
|
294
|
-
streamingThinking.value =
|
|
292
|
+
if (current.changed) {
|
|
293
|
+
streamingText.value = current.text;
|
|
294
|
+
streamingThinking.value = current.thinking;
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
297
|
}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { Message } from '../types/schemas/chat/conversations.js';
|
|
2
2
|
import type { ReasoningStep } from './reasoning.js';
|
|
3
|
+
type ParsedReasoning = {
|
|
4
|
+
steps: ReasoningStep[];
|
|
5
|
+
thinkingTexts: Set<string>;
|
|
6
|
+
currentAnswerParts: string[];
|
|
7
|
+
currentAnswerStepTexts: Set<string>;
|
|
8
|
+
};
|
|
3
9
|
export type ReasoningCache = {
|
|
4
|
-
bySignature: Map<string,
|
|
10
|
+
bySignature: Map<string, ParsedReasoning>;
|
|
5
11
|
byReference: WeakMap<unknown[], {
|
|
6
12
|
messageId: string;
|
|
7
|
-
|
|
13
|
+
parsed: ParsedReasoning;
|
|
8
14
|
}>;
|
|
9
15
|
};
|
|
10
16
|
export declare function createReasoningCache(): ReasoningCache;
|
|
11
17
|
export declare function resolveReasoningDisplayMessages(messages: Message[], cache?: ReasoningCache): Message[];
|
|
18
|
+
export {};
|
|
@@ -46,27 +46,30 @@ function groupReasoningSteps(parsedSteps) {
|
|
|
46
46
|
function getReasoningCacheKey(messageId, reasoningData) {
|
|
47
47
|
return `${messageId}:${JSON.stringify(reasoningData)}`;
|
|
48
48
|
}
|
|
49
|
-
function
|
|
49
|
+
function getParsedReasoning(cache, messageId, reasoningData) {
|
|
50
50
|
const referenceHit = cache.byReference.get(reasoningData);
|
|
51
51
|
if (referenceHit?.messageId === messageId)
|
|
52
|
-
return referenceHit.
|
|
52
|
+
return referenceHit.parsed;
|
|
53
53
|
const cacheKey = getReasoningCacheKey(messageId, reasoningData);
|
|
54
|
-
let
|
|
55
|
-
if (!
|
|
56
|
-
|
|
54
|
+
let parsed = cache.bySignature.get(cacheKey);
|
|
55
|
+
if (!parsed) {
|
|
56
|
+
parsed = parseReasoningFromPolling(reasoningData);
|
|
57
57
|
for (const staleKey of cache.bySignature.keys()) {
|
|
58
58
|
if (staleKey.startsWith(`${messageId}:`))
|
|
59
59
|
cache.bySignature.delete(staleKey);
|
|
60
60
|
}
|
|
61
|
-
cache.bySignature.set(cacheKey,
|
|
61
|
+
cache.bySignature.set(cacheKey, parsed);
|
|
62
62
|
}
|
|
63
|
-
cache.byReference.set(reasoningData, { messageId,
|
|
64
|
-
return
|
|
63
|
+
cache.byReference.set(reasoningData, { messageId, parsed });
|
|
64
|
+
return parsed;
|
|
65
65
|
}
|
|
66
66
|
function parseReasoningFromPolling(reasoning) {
|
|
67
67
|
const allSteps = [];
|
|
68
68
|
const seenContentIds = /* @__PURE__ */ new Set();
|
|
69
69
|
const seenTexts = /* @__PURE__ */ new Set();
|
|
70
|
+
const thinkingTexts = /* @__PURE__ */ new Set();
|
|
71
|
+
let currentAnswerParts = [];
|
|
72
|
+
let currentAnswerStepTexts = /* @__PURE__ */ new Set();
|
|
70
73
|
for (const item of reasoning) {
|
|
71
74
|
if (!item || typeof item !== "object")
|
|
72
75
|
continue;
|
|
@@ -98,15 +101,23 @@ function parseReasoningFromPolling(reasoning) {
|
|
|
98
101
|
const message = itemObj.message;
|
|
99
102
|
if (!Array.isArray(message.content))
|
|
100
103
|
continue;
|
|
104
|
+
const answerParts = [];
|
|
105
|
+
const answerStepTexts = /* @__PURE__ */ new Set();
|
|
101
106
|
for (const contentPart of message.content) {
|
|
102
107
|
if (!contentPart || typeof contentPart !== "object")
|
|
103
108
|
continue;
|
|
104
109
|
const part = contentPart;
|
|
105
|
-
if (part.type === "text" && typeof part.text === "string") {
|
|
110
|
+
if ((part.type === "text" || part.type === "thinking") && typeof part.text === "string") {
|
|
111
|
+
if (part.type === "text")
|
|
112
|
+
answerParts.push(part.text);
|
|
113
|
+
if (part.type === "thinking")
|
|
114
|
+
thinkingTexts.add(part.text);
|
|
106
115
|
if (seenTexts.has(part.text))
|
|
107
116
|
continue;
|
|
108
117
|
seenTexts.add(part.text);
|
|
109
118
|
allSteps.push(part.text);
|
|
119
|
+
if (part.type === "text")
|
|
120
|
+
answerStepTexts.add(part.text);
|
|
110
121
|
} else if (part.type === "tool_use" && part.id && part.name) {
|
|
111
122
|
const toolId = part.id;
|
|
112
123
|
if (seenContentIds.has(`tool_use:${toolId}`))
|
|
@@ -130,6 +141,10 @@ function parseReasoningFromPolling(reasoning) {
|
|
|
130
141
|
});
|
|
131
142
|
}
|
|
132
143
|
}
|
|
144
|
+
if (!itemObj.parent_tool_use_id && answerParts.length > 0) {
|
|
145
|
+
currentAnswerParts = answerParts;
|
|
146
|
+
currentAnswerStepTexts = answerStepTexts;
|
|
147
|
+
}
|
|
133
148
|
} else if (itemObj.type === "text" && typeof itemObj.text === "string") {
|
|
134
149
|
if (seenTexts.has(itemObj.text))
|
|
135
150
|
continue;
|
|
@@ -158,21 +173,23 @@ function parseReasoningFromPolling(reasoning) {
|
|
|
158
173
|
});
|
|
159
174
|
}
|
|
160
175
|
}
|
|
161
|
-
return groupReasoningSteps(allSteps);
|
|
176
|
+
return { steps: groupReasoningSteps(allSteps), thinkingTexts, currentAnswerParts, currentAnswerStepTexts };
|
|
162
177
|
}
|
|
163
178
|
export function resolveReasoningDisplayMessages(messages, cache = createReasoningCache()) {
|
|
164
179
|
const renderedSteps = /* @__PURE__ */ new Set();
|
|
165
180
|
return messages.map((message) => {
|
|
166
181
|
if (message.role !== "assistant" || !message.reasoningData || !Array.isArray(message.reasoningData))
|
|
167
182
|
return message;
|
|
168
|
-
const
|
|
183
|
+
const parsed = getParsedReasoning(cache, message.id, message.reasoningData);
|
|
169
184
|
const displaySteps = [];
|
|
170
|
-
|
|
185
|
+
const currentAnswerMatches = message.content === parsed.currentAnswerParts.join("");
|
|
186
|
+
for (const step of parsed.steps) {
|
|
171
187
|
const key = getReasoningStepKey(step);
|
|
172
188
|
if (renderedSteps.has(key))
|
|
173
189
|
continue;
|
|
174
|
-
if (typeof step === "string" &&
|
|
190
|
+
if (typeof step === "string" && currentAnswerMatches && parsed.currentAnswerStepTexts.has(step) && !parsed.thinkingTexts.has(step)) {
|
|
175
191
|
continue;
|
|
192
|
+
}
|
|
176
193
|
renderedSteps.add(key);
|
|
177
194
|
displaySteps.push(step);
|
|
178
195
|
}
|