codemini-cli 0.5.7 → 0.5.8
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/codemini-web/dist/assets/{highlighted-body-OFNGDK62-Dp1CwQdI.js → highlighted-body-OFNGDK62-CCcxtQK_.js} +1 -1
- package/codemini-web/dist/assets/index-CMISAOFr.css +2 -0
- package/codemini-web/dist/assets/{index-Bvd2jj3t.js → index-Cy4HN-FS.js} +90 -90
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-BWFzYc7A.js +1 -0
- package/codemini-web/dist/index.html +2 -2
- package/codemini-web/lib/runtime-bridge.js +2 -2
- package/codemini-web/server.js +59 -17
- package/package.json +1 -1
- package/src/core/chat-runtime.js +21 -1
- package/src/core/provider/anthropic.js +137 -24
- package/codemini-web/dist/assets/index-Csjkc1MY.css +0 -2
- package/codemini-web/dist/assets/mermaid-GHXKKRXX-DSVp--w4.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{i as e}from"./index-Cy4HN-FS.js";export{e as Mermaid};
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
document.documentElement.dataset.palette = palette;
|
|
15
15
|
})();
|
|
16
16
|
</script>
|
|
17
|
-
<script type="module" crossorigin src="/assets/index-
|
|
17
|
+
<script type="module" crossorigin src="/assets/index-Cy4HN-FS.js"></script>
|
|
18
18
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-S-ySWqyJ.js">
|
|
19
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
19
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CMISAOFr.css">
|
|
20
20
|
</head>
|
|
21
21
|
<body class="font-sans antialiased">
|
|
22
22
|
<div id="root"></div>
|
|
@@ -442,8 +442,8 @@ export class RuntimeBridge {
|
|
|
442
442
|
return ok;
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
-
async reloadConfig() {
|
|
446
|
-
return this.#runtime.reloadConfig?.();
|
|
445
|
+
async reloadConfig(options = {}) {
|
|
446
|
+
return this.#runtime.reloadConfig?.(options);
|
|
447
447
|
}
|
|
448
448
|
|
|
449
449
|
handleApproval(id, approved) {
|
package/codemini-web/server.js
CHANGED
|
@@ -20,6 +20,41 @@ const GENERAL_PROJECT_DIR = (() => {
|
|
|
20
20
|
return path.join(base, 'workspace');
|
|
21
21
|
})();
|
|
22
22
|
|
|
23
|
+
async function listProjectRoots() {
|
|
24
|
+
if (process.platform === 'win32') {
|
|
25
|
+
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
|
|
26
|
+
const roots = [];
|
|
27
|
+
await Promise.all(letters.map(async (letter) => {
|
|
28
|
+
const drivePath = `${letter}:\\`;
|
|
29
|
+
try {
|
|
30
|
+
await fs.access(drivePath);
|
|
31
|
+
roots.push({ name: `${letter}:`, path: drivePath, isGit: false, isDrive: true });
|
|
32
|
+
} catch {}
|
|
33
|
+
}));
|
|
34
|
+
return roots.sort((a, b) => a.name.localeCompare(b.name));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const candidates = [
|
|
38
|
+
{ name: '/', path: path.resolve('/') },
|
|
39
|
+
{ name: 'Home', path: process.env.HOME || process.env.USERPROFILE || '' },
|
|
40
|
+
{ name: 'Current', path: process.cwd() },
|
|
41
|
+
];
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
const roots = [];
|
|
44
|
+
for (const candidate of candidates) {
|
|
45
|
+
if (!candidate.path) continue;
|
|
46
|
+
const resolved = path.resolve(candidate.path);
|
|
47
|
+
if (seen.has(resolved)) continue;
|
|
48
|
+
try {
|
|
49
|
+
const stat = await fs.stat(resolved);
|
|
50
|
+
if (!stat.isDirectory()) continue;
|
|
51
|
+
seen.add(resolved);
|
|
52
|
+
roots.push({ name: candidate.name, path: resolved, isGit: false, isDrive: false });
|
|
53
|
+
} catch {}
|
|
54
|
+
}
|
|
55
|
+
return roots;
|
|
56
|
+
}
|
|
57
|
+
|
|
23
58
|
function isGeneralProjectDir(value) {
|
|
24
59
|
if (!value) return false;
|
|
25
60
|
return path.resolve(value) === path.resolve(GENERAL_PROJECT_DIR);
|
|
@@ -725,14 +760,19 @@ async function main() {
|
|
|
725
760
|
jsonResponse(res, { error: true, message: err.message }, 400);
|
|
726
761
|
}
|
|
727
762
|
return;
|
|
728
|
-
}
|
|
729
|
-
if (req.method === 'POST' && url.pathname === '/api/project/browse') {
|
|
730
|
-
const { dir } = await readBody(req);
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
763
|
+
}
|
|
764
|
+
if (req.method === 'POST' && url.pathname === '/api/project/browse') {
|
|
765
|
+
const { dir } = await readBody(req);
|
|
766
|
+
const roots = await listProjectRoots();
|
|
767
|
+
if (!dir && roots.length) {
|
|
768
|
+
jsonResponse(res, { path: '', roots, dirs: [] });
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
const base = dir ? path.resolve(dir) : path.resolve('/');
|
|
772
|
+
try {
|
|
773
|
+
const entries = await fs.readdir(base, { withFileTypes: true });
|
|
774
|
+
const dirs = entries
|
|
775
|
+
.filter(e => e.isDirectory() && !e.name.startsWith('.'))
|
|
736
776
|
.sort((a, b) => a.name.localeCompare(b.name))
|
|
737
777
|
.map(e => ({
|
|
738
778
|
name: e.name,
|
|
@@ -741,14 +781,14 @@ async function main() {
|
|
|
741
781
|
}));
|
|
742
782
|
// Check for .git directories asynchronously
|
|
743
783
|
await Promise.all(dirs.map(async (d) => {
|
|
744
|
-
try { await fs.access(path.join(d.path, '.git')); d.isGit = true; } catch {}
|
|
745
|
-
}));
|
|
746
|
-
jsonResponse(res, { path: base, dirs });
|
|
747
|
-
} catch (err) {
|
|
748
|
-
jsonResponse(res, { path: base, dirs: [], error: err.message });
|
|
749
|
-
}
|
|
750
|
-
return;
|
|
751
|
-
}
|
|
784
|
+
try { await fs.access(path.join(d.path, '.git')); d.isGit = true; } catch {}
|
|
785
|
+
}));
|
|
786
|
+
jsonResponse(res, { path: base, roots, dirs });
|
|
787
|
+
} catch (err) {
|
|
788
|
+
jsonResponse(res, { path: base, roots, dirs: [], error: err.message });
|
|
789
|
+
}
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
752
792
|
|
|
753
793
|
// ── Config management ──
|
|
754
794
|
if (req.method === 'GET' && url.pathname === '/api/config/status') {
|
|
@@ -767,7 +807,9 @@ async function main() {
|
|
|
767
807
|
try {
|
|
768
808
|
await setConfigValue(key, value);
|
|
769
809
|
const config = await loadConfig();
|
|
770
|
-
await bridge.reloadConfig(
|
|
810
|
+
await bridge.reloadConfig(
|
|
811
|
+
key === 'model.name' ? { model: config.model?.name } : {}
|
|
812
|
+
);
|
|
771
813
|
bridge.broadcastRuntimeState();
|
|
772
814
|
jsonResponse(res, { ok: true, config });
|
|
773
815
|
} catch (err) {
|
package/package.json
CHANGED
package/src/core/chat-runtime.js
CHANGED
|
@@ -4242,6 +4242,21 @@ export async function createChatRuntime({
|
|
|
4242
4242
|
if (hasPendingPlanApproval(currentSession)) {
|
|
4243
4243
|
executionMode = 'plan';
|
|
4244
4244
|
}
|
|
4245
|
+
const syncRuntimeFromConfig = async ({ model: nextModel } = {}) => {
|
|
4246
|
+
const configuredMode = String(config.execution?.mode || 'normal');
|
|
4247
|
+
executionMode = hasPendingPlanApproval(currentSession)
|
|
4248
|
+
? 'plan'
|
|
4249
|
+
: (['normal', 'auto', 'plan'].includes(configuredMode) ? configuredMode : 'normal');
|
|
4250
|
+
|
|
4251
|
+
const resolvedModel = String(nextModel || '').trim();
|
|
4252
|
+
if (resolvedModel) {
|
|
4253
|
+
model = resolvedModel;
|
|
4254
|
+
if (currentSession && typeof currentSession === 'object') {
|
|
4255
|
+
currentSession.model = model;
|
|
4256
|
+
await saveSession(currentSession).catch(() => {});
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
};
|
|
4245
4260
|
const commands = await loadCommandsAndSkills();
|
|
4246
4261
|
const reloadCommandsAndSkills = async () => {
|
|
4247
4262
|
const next = await loadCommandsAndSkills();
|
|
@@ -5708,6 +5723,9 @@ export async function createChatRuntime({
|
|
|
5708
5723
|
if (!key || !value) return { type: 'system', text: 'Usage: /config set <key> <value>' };
|
|
5709
5724
|
await setConfigValue(key, value);
|
|
5710
5725
|
config = await loadConfig();
|
|
5726
|
+
await syncRuntimeFromConfig(
|
|
5727
|
+
key === 'model.name' ? { model: config.model?.name } : {}
|
|
5728
|
+
);
|
|
5711
5729
|
const text = `Set ${key}=${value}`;
|
|
5712
5730
|
await persistLocalExchange(line, text);
|
|
5713
5731
|
return { type: 'system', text };
|
|
@@ -5716,6 +5734,7 @@ export async function createChatRuntime({
|
|
|
5716
5734
|
if (sub === 'reset') {
|
|
5717
5735
|
await resetConfig();
|
|
5718
5736
|
config = await loadConfig();
|
|
5737
|
+
await syncRuntimeFromConfig({ model: resolveDefaultModel(config) });
|
|
5719
5738
|
compactState.threshold = 60;
|
|
5720
5739
|
compactState.mode = 'conservative';
|
|
5721
5740
|
compactState.autoEnabled = true;
|
|
@@ -6135,8 +6154,9 @@ export async function createChatRuntime({
|
|
|
6135
6154
|
getCurrentSessionId: () => currentSession.id,
|
|
6136
6155
|
getSessionMessages: () => currentSession.messages || [],
|
|
6137
6156
|
getSessionCompact: () => currentSession.compact || null,
|
|
6138
|
-
reloadConfig: async () => {
|
|
6157
|
+
reloadConfig: async (options = {}) => {
|
|
6139
6158
|
config = await loadConfig();
|
|
6159
|
+
await syncRuntimeFromConfig(options);
|
|
6140
6160
|
return config;
|
|
6141
6161
|
},
|
|
6142
6162
|
setExecutionMode: async (next) => {
|
|
@@ -12,6 +12,72 @@ function extractTextContent(content) {
|
|
|
12
12
|
return '';
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
function cloneAnthropicContentBlock(block) {
|
|
16
|
+
if (!block || typeof block !== 'object') return null;
|
|
17
|
+
if (block.type === 'thinking') {
|
|
18
|
+
const thinking = String(block.thinking || block.text || '');
|
|
19
|
+
if (!thinking) return null;
|
|
20
|
+
return {
|
|
21
|
+
type: 'thinking',
|
|
22
|
+
thinking,
|
|
23
|
+
...(block.signature ? { signature: String(block.signature) } : {})
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (block.type === 'redacted_thinking') {
|
|
27
|
+
const data = block.data != null ? String(block.data) : '';
|
|
28
|
+
if (!data) return null;
|
|
29
|
+
return { type: 'redacted_thinking', data };
|
|
30
|
+
}
|
|
31
|
+
if (block.type === 'text') {
|
|
32
|
+
const text = String(block.text || '');
|
|
33
|
+
return text ? { type: 'text', text } : null;
|
|
34
|
+
}
|
|
35
|
+
if (block.type === 'tool_use') {
|
|
36
|
+
const name = String(block.name || '').trim();
|
|
37
|
+
if (!name) return null;
|
|
38
|
+
return {
|
|
39
|
+
type: 'tool_use',
|
|
40
|
+
id: String(block.id || ''),
|
|
41
|
+
name,
|
|
42
|
+
input: block.input && typeof block.input === 'object' && !Array.isArray(block.input) ? block.input : {}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function extractThinkingBlocks(message) {
|
|
49
|
+
const source = [
|
|
50
|
+
...(Array.isArray(message?.reasoning_details) ? message.reasoning_details : []),
|
|
51
|
+
...(Array.isArray(message?.content) ? message.content : [])
|
|
52
|
+
];
|
|
53
|
+
return source
|
|
54
|
+
.filter((block) => block?.type === 'thinking' || block?.type === 'redacted_thinking')
|
|
55
|
+
.map(cloneAnthropicContentBlock)
|
|
56
|
+
.filter(Boolean);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function buildAssistantMessage({ text = '', toolCalls = [], thinkingBlocks = [] }) {
|
|
60
|
+
const assistantMessage = {
|
|
61
|
+
role: 'assistant',
|
|
62
|
+
content: text
|
|
63
|
+
};
|
|
64
|
+
const reasoningDetails = Array.isArray(thinkingBlocks)
|
|
65
|
+
? thinkingBlocks.map(cloneAnthropicContentBlock).filter(Boolean)
|
|
66
|
+
: [];
|
|
67
|
+
if (reasoningDetails.length > 0) assistantMessage.reasoning_details = reasoningDetails;
|
|
68
|
+
if (Array.isArray(toolCalls) && toolCalls.length > 0) {
|
|
69
|
+
assistantMessage.tool_calls = toolCalls.map((tc) => ({
|
|
70
|
+
id: tc.id,
|
|
71
|
+
type: 'function',
|
|
72
|
+
function: {
|
|
73
|
+
name: tc.name,
|
|
74
|
+
arguments: tc.arguments || '{}'
|
|
75
|
+
}
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
return assistantMessage;
|
|
79
|
+
}
|
|
80
|
+
|
|
15
81
|
function normalizeIncomingToolCallArguments(argumentsValue) {
|
|
16
82
|
if (typeof argumentsValue === 'string') return argumentsValue;
|
|
17
83
|
if (argumentsValue == null) return '{}';
|
|
@@ -41,7 +107,8 @@ function normalizeMessages(messages) {
|
|
|
41
107
|
const systemParts = [];
|
|
42
108
|
const out = [];
|
|
43
109
|
|
|
44
|
-
for (
|
|
110
|
+
for (let i = 0; i < source.length; i += 1) {
|
|
111
|
+
const message = source[i];
|
|
45
112
|
if (!message || typeof message !== 'object') continue;
|
|
46
113
|
if (message.role === 'system') {
|
|
47
114
|
const text = extractTextContent(message.content);
|
|
@@ -50,35 +117,45 @@ function normalizeMessages(messages) {
|
|
|
50
117
|
}
|
|
51
118
|
|
|
52
119
|
if (message.role === 'tool') {
|
|
120
|
+
const toolResults = [];
|
|
121
|
+
while (i < source.length) {
|
|
122
|
+
const toolMessage = source[i];
|
|
123
|
+
if (!toolMessage || typeof toolMessage !== 'object' || toolMessage.role !== 'tool') break;
|
|
124
|
+
toolResults.push({
|
|
125
|
+
type: 'tool_result',
|
|
126
|
+
tool_use_id: String(toolMessage.tool_call_id || ''),
|
|
127
|
+
content: extractTextContent(toolMessage.content)
|
|
128
|
+
});
|
|
129
|
+
i += 1;
|
|
130
|
+
}
|
|
131
|
+
i -= 1;
|
|
53
132
|
out.push({
|
|
54
133
|
role: 'user',
|
|
55
|
-
content:
|
|
56
|
-
{
|
|
57
|
-
type: 'tool_result',
|
|
58
|
-
tool_use_id: String(message.tool_call_id || ''),
|
|
59
|
-
content: extractTextContent(message.content)
|
|
60
|
-
}
|
|
61
|
-
]
|
|
134
|
+
content: toolResults
|
|
62
135
|
});
|
|
63
136
|
continue;
|
|
64
137
|
}
|
|
65
138
|
|
|
66
|
-
const contentBlocks = [];
|
|
139
|
+
const contentBlocks = message.role === 'assistant' ? extractThinkingBlocks(message) : [];
|
|
67
140
|
const text = extractTextContent(message.content);
|
|
68
141
|
if (text) {
|
|
69
142
|
contentBlocks.push({ type: 'text', text });
|
|
70
143
|
}
|
|
71
144
|
|
|
145
|
+
const hasContentToolUse = Array.isArray(message.content)
|
|
146
|
+
&& message.content.some((block) => block?.type === 'tool_use');
|
|
72
147
|
if (message.role === 'assistant' && Array.isArray(message.tool_calls)) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
148
|
+
if (!hasContentToolUse) {
|
|
149
|
+
for (const toolCall of message.tool_calls) {
|
|
150
|
+
const name = String(toolCall?.function?.name || toolCall?.name || '').trim();
|
|
151
|
+
if (!name) continue;
|
|
152
|
+
contentBlocks.push({
|
|
153
|
+
type: 'tool_use',
|
|
154
|
+
id: String(toolCall?.id || ''),
|
|
155
|
+
name,
|
|
156
|
+
input: tryParseJsonObject(toolCall?.function?.arguments ?? toolCall?.arguments)
|
|
157
|
+
});
|
|
158
|
+
}
|
|
82
159
|
}
|
|
83
160
|
}
|
|
84
161
|
|
|
@@ -142,6 +219,10 @@ function hasTrailingToolContext(messages) {
|
|
|
142
219
|
|
|
143
220
|
function extractAssistantResult(data, messages) {
|
|
144
221
|
const content = Array.isArray(data?.content) ? data.content : [];
|
|
222
|
+
const thinkingBlocks = content
|
|
223
|
+
.filter((block) => block?.type === 'thinking' || block?.type === 'redacted_thinking')
|
|
224
|
+
.map(cloneAnthropicContentBlock)
|
|
225
|
+
.filter(Boolean);
|
|
145
226
|
const text = content
|
|
146
227
|
.filter((block) => block?.type === 'text')
|
|
147
228
|
.map((block) => block.text || '')
|
|
@@ -163,7 +244,8 @@ function extractAssistantResult(data, messages) {
|
|
|
163
244
|
toolCalls: [],
|
|
164
245
|
usage: data?.usage || null,
|
|
165
246
|
incomplete: true,
|
|
166
|
-
content
|
|
247
|
+
content,
|
|
248
|
+
assistantMessage: buildAssistantMessage({ text: '', toolCalls: [], thinkingBlocks })
|
|
167
249
|
};
|
|
168
250
|
}
|
|
169
251
|
throw new Error('Anthropic gateway returned empty assistant response');
|
|
@@ -173,7 +255,8 @@ function extractAssistantResult(data, messages) {
|
|
|
173
255
|
text,
|
|
174
256
|
toolCalls,
|
|
175
257
|
usage: data?.usage || null,
|
|
176
|
-
content
|
|
258
|
+
content,
|
|
259
|
+
assistantMessage: buildAssistantMessage({ text, toolCalls, thinkingBlocks })
|
|
177
260
|
};
|
|
178
261
|
}
|
|
179
262
|
|
|
@@ -214,7 +297,7 @@ function emptyToolCall(index) {
|
|
|
214
297
|
};
|
|
215
298
|
}
|
|
216
299
|
|
|
217
|
-
function buildFinalStreamResult(text, toolCallsByIndex, usage, messages) {
|
|
300
|
+
function buildFinalStreamResult(text, toolCallsByIndex, usage, messages, thinkingBlocks = []) {
|
|
218
301
|
const toolCalls = Array.from(toolCallsByIndex.entries())
|
|
219
302
|
.sort((a, b) => a[0] - b[0])
|
|
220
303
|
.map(([, tc], i) => ({
|
|
@@ -225,6 +308,10 @@ function buildFinalStreamResult(text, toolCallsByIndex, usage, messages) {
|
|
|
225
308
|
.filter((tc) => tc.name);
|
|
226
309
|
const normalizedText = String(text || '').trim();
|
|
227
310
|
const content = [];
|
|
311
|
+
for (const block of thinkingBlocks) {
|
|
312
|
+
const cloned = cloneAnthropicContentBlock(block);
|
|
313
|
+
if (cloned) content.push(cloned);
|
|
314
|
+
}
|
|
228
315
|
if (text) content.push({ type: 'text', text });
|
|
229
316
|
for (const toolCall of toolCalls) {
|
|
230
317
|
content.push({
|
|
@@ -242,7 +329,8 @@ function buildFinalStreamResult(text, toolCallsByIndex, usage, messages) {
|
|
|
242
329
|
toolCalls: [],
|
|
243
330
|
usage,
|
|
244
331
|
incomplete: true,
|
|
245
|
-
content: []
|
|
332
|
+
content: [],
|
|
333
|
+
assistantMessage: buildAssistantMessage({ text: '', toolCalls: [], thinkingBlocks })
|
|
246
334
|
};
|
|
247
335
|
}
|
|
248
336
|
throw new Error('Anthropic gateway stream returned empty assistant response');
|
|
@@ -253,7 +341,8 @@ function buildFinalStreamResult(text, toolCallsByIndex, usage, messages) {
|
|
|
253
341
|
toolCalls,
|
|
254
342
|
usage,
|
|
255
343
|
incomplete: false,
|
|
256
|
-
content
|
|
344
|
+
content,
|
|
345
|
+
assistantMessage: buildAssistantMessage({ text, toolCalls, thinkingBlocks })
|
|
257
346
|
};
|
|
258
347
|
}
|
|
259
348
|
|
|
@@ -349,6 +438,7 @@ export async function createChatCompletionStream({
|
|
|
349
438
|
let text = '';
|
|
350
439
|
let usage = null;
|
|
351
440
|
const toolCallsByIndex = new Map();
|
|
441
|
+
const thinkingBlocksByIndex = new Map();
|
|
352
442
|
|
|
353
443
|
for await (const chunk of iterateSseEvents(response.body)) {
|
|
354
444
|
usage = mergeUsage(usage, chunk?.data?.usage);
|
|
@@ -366,6 +456,10 @@ export async function createChatCompletionStream({
|
|
|
366
456
|
: '';
|
|
367
457
|
current.arguments = current.arguments || initialInput;
|
|
368
458
|
toolCallsByIndex.set(index, current);
|
|
459
|
+
} else if (contentBlock.type === 'thinking' || contentBlock.type === 'redacted_thinking') {
|
|
460
|
+
const current = cloneAnthropicContentBlock(contentBlock) || { type: contentBlock.type };
|
|
461
|
+
if (current.type === 'thinking' && current.thinking == null) current.thinking = '';
|
|
462
|
+
thinkingBlocksByIndex.set(index, current);
|
|
369
463
|
}
|
|
370
464
|
continue;
|
|
371
465
|
}
|
|
@@ -382,6 +476,20 @@ export async function createChatCompletionStream({
|
|
|
382
476
|
continue;
|
|
383
477
|
}
|
|
384
478
|
|
|
479
|
+
if (delta.type === 'thinking_delta') {
|
|
480
|
+
const current = thinkingBlocksByIndex.get(index) || { type: 'thinking', thinking: '' };
|
|
481
|
+
current.thinking = `${current.thinking || ''}${String(delta.thinking || '')}`;
|
|
482
|
+
thinkingBlocksByIndex.set(index, current);
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (delta.type === 'signature_delta') {
|
|
487
|
+
const current = thinkingBlocksByIndex.get(index) || { type: 'thinking', thinking: '' };
|
|
488
|
+
current.signature = String(delta.signature || '');
|
|
489
|
+
thinkingBlocksByIndex.set(index, current);
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
|
|
385
493
|
if (delta.type === 'input_json_delta') {
|
|
386
494
|
const current = toolCallsByIndex.get(index) || emptyToolCall(index);
|
|
387
495
|
current.arguments = `${current.arguments || ''}${String(delta.partial_json || '')}`;
|
|
@@ -397,5 +505,10 @@ export async function createChatCompletionStream({
|
|
|
397
505
|
}
|
|
398
506
|
}
|
|
399
507
|
|
|
400
|
-
|
|
508
|
+
const thinkingBlocks = Array.from(thinkingBlocksByIndex.entries())
|
|
509
|
+
.sort((a, b) => a[0] - b[0])
|
|
510
|
+
.map(([, block]) => cloneAnthropicContentBlock(block))
|
|
511
|
+
.filter(Boolean);
|
|
512
|
+
|
|
513
|
+
return buildFinalStreamResult(text, toolCallsByIndex, usage, messages, thinkingBlocks);
|
|
401
514
|
}
|