coding-tool-x 3.8.1 → 3.8.2
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/CHANGELOG.md +2 -0
- package/dist/web/assets/{Analytics-8dRv1aYW.js → Analytics-COEUXmd4.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-BQRXSICO.js → ConfigTemplates-DLLkS53H.js} +1 -1
- package/dist/web/assets/{Home-BtzWhKIa.js → Home-DCEyLzwX.js} +1 -1
- package/dist/web/assets/{PluginManager-BTa-Ygf6.js → PluginManager-Oe1ZHoMO.js} +1 -1
- package/dist/web/assets/{ProjectList-F_cB8ldA.js → ProjectList-CWjuAFof.js} +1 -1
- package/dist/web/assets/{SessionList-LOrbPQvu.js → SessionList-v3ehGg9U.js} +1 -1
- package/dist/web/assets/{SkillManager-BzI_t-yV.js → SkillManager-DUF_qP5S.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-Db9RGiz7.js → WorkspaceManager-CjAWBosO.js} +1 -1
- package/dist/web/assets/index-D5hyHPj7.js +2 -0
- package/dist/web/index.html +1 -1
- package/docs/superpowers/plans/2026-08-10-codex-conversion-compatibility.md +251 -0
- package/docs/superpowers/plans/2026-08-11-windows-command-window-hiding.md +90 -0
- package/docs/superpowers/specs/2026-08-10-codex-conversion-compatibility-design.md +61 -0
- package/docs/superpowers/specs/2026-08-11-windows-command-window-hiding-design.md +44 -0
- package/package.json +1 -1
- package/src/commands/update.js +1 -1
- package/src/server/opencode-proxy-server.js +55 -1037
- package/src/server/services/claude-wire.js +694 -0
- package/src/server/services/codex-wire.js +219 -0
- package/src/server/services/gemini-wire.js +759 -0
- package/src/server/services/model-detector.js +49 -131
- package/src/server/services/omp-channels.js +23 -4
- package/src/server/services/omp-gateway.js +29 -1
- package/src/server/services/omp-settings-manager.js +27 -3
- package/src/server/services/opencode-gateway-adapters.js +22 -1147
- package/src/server/services/opencode-normalization.js +546 -0
- package/src/server/services/session-history-index.js +1 -1
- package/src/server/services/session-history-worker.js +2 -1
- package/src/server/services/speed-test.js +85 -303
- package/dist/web/assets/index-DIWJmyL6.js +0 -2
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Neutral OpenCode normalization primitives
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Shared by claude-wire and gemini-wire. Provider-specific conversion,
|
|
7
|
+
// auth, envelope, and URL construction remain in each wire module.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
function extractTextFragments(value, fragments) {
|
|
11
|
+
if (value === null || value === undefined) return;
|
|
12
|
+
if (typeof value === 'string') {
|
|
13
|
+
if (value.trim()) fragments.push(value);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (typeof value === 'number' || typeof value === 'boolean') {
|
|
17
|
+
fragments.push(String(value));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
value.forEach(item => extractTextFragments(item, fragments));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (typeof value !== 'object') return;
|
|
25
|
+
|
|
26
|
+
if (typeof value.text === 'string') {
|
|
27
|
+
extractTextFragments(value.text, fragments);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (typeof value.input_text === 'string') {
|
|
31
|
+
extractTextFragments(value.input_text, fragments);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (typeof value.output_text === 'string') {
|
|
35
|
+
extractTextFragments(value.output_text, fragments);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (value.content !== undefined) {
|
|
39
|
+
extractTextFragments(value.content, fragments);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(value.parts)) {
|
|
43
|
+
extractTextFragments(value.parts, fragments);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function extractText(value) {
|
|
48
|
+
const fragments = [];
|
|
49
|
+
extractTextFragments(value, fragments);
|
|
50
|
+
return fragments.join('\n').trim();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function parseBase64DataUrl(dataUrl = '') {
|
|
54
|
+
const value = typeof dataUrl === 'string' ? dataUrl.trim() : '';
|
|
55
|
+
if (!value) return null;
|
|
56
|
+
const matched = value.match(/^data:([^;,]+)?;base64,(.+)$/i);
|
|
57
|
+
if (!matched) return null;
|
|
58
|
+
return {
|
|
59
|
+
mediaType: String(matched[1] || '').trim(),
|
|
60
|
+
data: String(matched[2] || '')
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function normalizeOpenAiImageBlock(value) {
|
|
65
|
+
let imageUrl = '';
|
|
66
|
+
if (typeof value === 'string') {
|
|
67
|
+
imageUrl = value;
|
|
68
|
+
} else if (value && typeof value === 'object') {
|
|
69
|
+
if (typeof value.url === 'string') {
|
|
70
|
+
imageUrl = value.url;
|
|
71
|
+
} else if (typeof value.image_url === 'string') {
|
|
72
|
+
imageUrl = value.image_url;
|
|
73
|
+
} else if (
|
|
74
|
+
value.image_url &&
|
|
75
|
+
typeof value.image_url === 'object' &&
|
|
76
|
+
typeof value.image_url.url === 'string'
|
|
77
|
+
) {
|
|
78
|
+
imageUrl = value.image_url.url;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!imageUrl || typeof imageUrl !== 'string') return null;
|
|
83
|
+
const trimmed = imageUrl.trim();
|
|
84
|
+
if (!trimmed) return null;
|
|
85
|
+
|
|
86
|
+
const dataUrl = parseBase64DataUrl(trimmed);
|
|
87
|
+
if (dataUrl) {
|
|
88
|
+
return {
|
|
89
|
+
type: 'image',
|
|
90
|
+
source: {
|
|
91
|
+
type: 'base64',
|
|
92
|
+
media_type: dataUrl.mediaType || 'image/png',
|
|
93
|
+
data: dataUrl.data
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
type: 'image',
|
|
100
|
+
source: {
|
|
101
|
+
type: 'url',
|
|
102
|
+
url: trimmed
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function normalizeOpenAiFileBlock(value) {
|
|
108
|
+
if (!value || typeof value !== 'object') return null;
|
|
109
|
+
|
|
110
|
+
const fileNode =
|
|
111
|
+
value.file && typeof value.file === 'object' ? value.file : value;
|
|
112
|
+
const fileData =
|
|
113
|
+
typeof fileNode.file_data === 'string' ? fileNode.file_data.trim() : '';
|
|
114
|
+
const fileUrl =
|
|
115
|
+
typeof fileNode.file_url === 'string' ? fileNode.file_url.trim() : '';
|
|
116
|
+
const fileId =
|
|
117
|
+
typeof fileNode.file_id === 'string' ? fileNode.file_id.trim() : '';
|
|
118
|
+
|
|
119
|
+
if (fileData) {
|
|
120
|
+
const dataUrl = parseBase64DataUrl(fileData);
|
|
121
|
+
if (dataUrl) {
|
|
122
|
+
return {
|
|
123
|
+
type: 'document',
|
|
124
|
+
source: {
|
|
125
|
+
type: 'base64',
|
|
126
|
+
media_type: dataUrl.mediaType || 'application/octet-stream',
|
|
127
|
+
data: dataUrl.data
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
type: 'document',
|
|
134
|
+
source: {
|
|
135
|
+
type: 'base64',
|
|
136
|
+
media_type: 'application/octet-stream',
|
|
137
|
+
data: fileData
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (fileUrl) {
|
|
143
|
+
return {
|
|
144
|
+
type: 'document',
|
|
145
|
+
source: {
|
|
146
|
+
type: 'url',
|
|
147
|
+
url: fileUrl
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (fileId) {
|
|
153
|
+
return {
|
|
154
|
+
type: 'text',
|
|
155
|
+
text: `[input_file:${fileId}]`
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function normalizeOpenAiContentItemToClaudeBlocks(item) {
|
|
163
|
+
if (item === null || item === undefined) return [];
|
|
164
|
+
|
|
165
|
+
if (
|
|
166
|
+
typeof item === 'string' ||
|
|
167
|
+
typeof item === 'number' ||
|
|
168
|
+
typeof item === 'boolean'
|
|
169
|
+
) {
|
|
170
|
+
const text = String(item);
|
|
171
|
+
return text.trim() ? [{ type: 'text', text }] : [];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (Array.isArray(item)) {
|
|
175
|
+
return item.flatMap(normalizeOpenAiContentItemToClaudeBlocks);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (typeof item !== 'object') return [];
|
|
179
|
+
|
|
180
|
+
const itemType = String(item.type || '').trim().toLowerCase();
|
|
181
|
+
if (itemType === 'tool_use') {
|
|
182
|
+
return [item];
|
|
183
|
+
}
|
|
184
|
+
if (itemType === 'tool_result') {
|
|
185
|
+
return [item];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (itemType === 'image' && item.source && typeof item.source === 'object') {
|
|
189
|
+
return [item];
|
|
190
|
+
}
|
|
191
|
+
if (
|
|
192
|
+
itemType === 'document' &&
|
|
193
|
+
item.source &&
|
|
194
|
+
typeof item.source === 'object'
|
|
195
|
+
) {
|
|
196
|
+
return [item];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (
|
|
200
|
+
itemType === 'text' ||
|
|
201
|
+
itemType === 'input_text' ||
|
|
202
|
+
itemType === 'output_text'
|
|
203
|
+
) {
|
|
204
|
+
const text = typeof item.text === 'string' ? item.text : '';
|
|
205
|
+
if (!text.trim()) return [];
|
|
206
|
+
const block = { type: 'text', text };
|
|
207
|
+
if (item.cache_control && typeof item.cache_control === 'object') {
|
|
208
|
+
block.cache_control = item.cache_control;
|
|
209
|
+
}
|
|
210
|
+
return [block];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (itemType === 'image_url' || itemType === 'input_image') {
|
|
214
|
+
const imageBlock = normalizeOpenAiImageBlock(item);
|
|
215
|
+
return imageBlock ? [imageBlock] : [];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (itemType === 'file' || itemType === 'input_file') {
|
|
219
|
+
const fileBlock = normalizeOpenAiFileBlock(item);
|
|
220
|
+
return fileBlock ? [fileBlock] : [];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (item.image_url !== undefined || item.url !== undefined) {
|
|
224
|
+
const imageBlock = normalizeOpenAiImageBlock(item);
|
|
225
|
+
if (imageBlock) return [imageBlock];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (
|
|
229
|
+
item.file !== undefined ||
|
|
230
|
+
item.file_data !== undefined ||
|
|
231
|
+
item.file_url !== undefined ||
|
|
232
|
+
item.file_id !== undefined
|
|
233
|
+
) {
|
|
234
|
+
const fileBlock = normalizeOpenAiFileBlock(item);
|
|
235
|
+
if (fileBlock) return [fileBlock];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const fallbackText = extractText(item);
|
|
239
|
+
return fallbackText ? [{ type: 'text', text: fallbackText }] : [];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function normalizeOpenAiContentToClaudeBlocks(content) {
|
|
243
|
+
return normalizeOpenAiContentItemToClaudeBlocks(content);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function normalizeOpenAiRole(role) {
|
|
247
|
+
const value = String(role || '').trim().toLowerCase();
|
|
248
|
+
if (value === 'assistant' || value === 'model') return 'assistant';
|
|
249
|
+
if (value === 'system' || value === 'developer') return 'system';
|
|
250
|
+
if (value === 'tool') return 'tool';
|
|
251
|
+
return 'user';
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function isResponsesPath(pathname) {
|
|
255
|
+
const normalized =
|
|
256
|
+
String(pathname || '').trim().replace(/\/+$/, '') || '/';
|
|
257
|
+
return (
|
|
258
|
+
normalized.endsWith('/v1/responses') || normalized.endsWith('/responses')
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function isChatCompletionsPath(pathname) {
|
|
263
|
+
const normalized =
|
|
264
|
+
String(pathname || '').trim().replace(/\/+$/, '') || '/';
|
|
265
|
+
return (
|
|
266
|
+
normalized.endsWith('/v1/chat/completions') ||
|
|
267
|
+
normalized.endsWith('/chat/completions')
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function generateToolCallId() {
|
|
272
|
+
return `toolu_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function parseToolArguments(value) {
|
|
276
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
277
|
+
return value;
|
|
278
|
+
}
|
|
279
|
+
if (typeof value === 'string') {
|
|
280
|
+
const trimmed = value.trim();
|
|
281
|
+
if (!trimmed) return {};
|
|
282
|
+
try {
|
|
283
|
+
const parsed = JSON.parse(trimmed);
|
|
284
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
285
|
+
return parsed;
|
|
286
|
+
}
|
|
287
|
+
} catch {
|
|
288
|
+
return {};
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return {};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function normalizeToolResultContent(value) {
|
|
295
|
+
if (typeof value === 'string') return value;
|
|
296
|
+
if (value === null || value === undefined) return '';
|
|
297
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
298
|
+
return String(value);
|
|
299
|
+
try {
|
|
300
|
+
return JSON.stringify(value);
|
|
301
|
+
} catch {
|
|
302
|
+
return String(value);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function normalizeStopSequences(stopValue) {
|
|
307
|
+
if (!stopValue) return undefined;
|
|
308
|
+
if (typeof stopValue === 'string') {
|
|
309
|
+
const normalized = String(stopValue).trim();
|
|
310
|
+
if (normalized) return [normalized];
|
|
311
|
+
return undefined;
|
|
312
|
+
}
|
|
313
|
+
if (Array.isArray(stopValue)) {
|
|
314
|
+
const sequences = stopValue
|
|
315
|
+
.filter(item => typeof item === 'string')
|
|
316
|
+
.map(item => String(item).trim())
|
|
317
|
+
.filter(Boolean);
|
|
318
|
+
return sequences.length > 0 ? sequences : undefined;
|
|
319
|
+
}
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function buildAssistantToolUseMessageFromFunctionCall(item) {
|
|
324
|
+
const functionPayload =
|
|
325
|
+
item?.function && typeof item.function === 'object'
|
|
326
|
+
? item.function
|
|
327
|
+
: item;
|
|
328
|
+
const rawName = functionPayload?.name || item?.name;
|
|
329
|
+
if (!rawName) return null;
|
|
330
|
+
|
|
331
|
+
const callId =
|
|
332
|
+
functionPayload?.call_id ||
|
|
333
|
+
item?.call_id ||
|
|
334
|
+
functionPayload?.id ||
|
|
335
|
+
item?.id ||
|
|
336
|
+
generateToolCallId();
|
|
337
|
+
const argumentsSource =
|
|
338
|
+
functionPayload?.arguments ??
|
|
339
|
+
item?.arguments ??
|
|
340
|
+
functionPayload?.input ??
|
|
341
|
+
item?.input;
|
|
342
|
+
const input = parseToolArguments(argumentsSource);
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
role: 'assistant',
|
|
346
|
+
content: [
|
|
347
|
+
{
|
|
348
|
+
type: 'tool_use',
|
|
349
|
+
id: callId,
|
|
350
|
+
name: rawName,
|
|
351
|
+
input
|
|
352
|
+
}
|
|
353
|
+
]
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function buildUserToolResultMessage(item) {
|
|
358
|
+
const callId =
|
|
359
|
+
item?.call_id || item?.tool_call_id || item?.id || generateToolCallId();
|
|
360
|
+
const outputSource = item?.output ?? item?.content ?? '';
|
|
361
|
+
const content = normalizeToolResultContent(outputSource);
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
role: 'user',
|
|
365
|
+
content: [
|
|
366
|
+
{
|
|
367
|
+
type: 'tool_result',
|
|
368
|
+
tool_use_id: callId,
|
|
369
|
+
content
|
|
370
|
+
}
|
|
371
|
+
]
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function normalizeOpenCodeMessages(pathname, payload = {}) {
|
|
376
|
+
const systemBlocks = [];
|
|
377
|
+
const messages = [];
|
|
378
|
+
|
|
379
|
+
if (
|
|
380
|
+
isResponsesPath(pathname) &&
|
|
381
|
+
typeof payload.instructions === 'string' &&
|
|
382
|
+
payload.instructions.trim()
|
|
383
|
+
) {
|
|
384
|
+
systemBlocks.push({
|
|
385
|
+
type: 'text',
|
|
386
|
+
text: payload.instructions.trim()
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const appendMessage = (role, content, topLevelCacheControl) => {
|
|
391
|
+
const normalizedRole = normalizeOpenAiRole(role);
|
|
392
|
+
const contentBlocks = normalizeOpenAiContentToClaudeBlocks(content);
|
|
393
|
+
if (normalizedRole === 'system') {
|
|
394
|
+
const blocks = contentBlocks.filter(
|
|
395
|
+
block =>
|
|
396
|
+
block &&
|
|
397
|
+
block.type === 'text' &&
|
|
398
|
+
typeof block.text === 'string' &&
|
|
399
|
+
block.text.trim()
|
|
400
|
+
);
|
|
401
|
+
blocks.forEach((block, idx) => {
|
|
402
|
+
const systemBlock = { type: 'text', text: block.text };
|
|
403
|
+
if (block.cache_control && typeof block.cache_control === 'object') {
|
|
404
|
+
systemBlock.cache_control = block.cache_control;
|
|
405
|
+
} else if (
|
|
406
|
+
topLevelCacheControl &&
|
|
407
|
+
typeof topLevelCacheControl === 'object' &&
|
|
408
|
+
idx === blocks.length - 1
|
|
409
|
+
) {
|
|
410
|
+
systemBlock.cache_control = topLevelCacheControl;
|
|
411
|
+
}
|
|
412
|
+
systemBlocks.push(systemBlock);
|
|
413
|
+
});
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (!Array.isArray(contentBlocks) || contentBlocks.length === 0) return;
|
|
418
|
+
if (
|
|
419
|
+
topLevelCacheControl &&
|
|
420
|
+
typeof topLevelCacheControl === 'object' &&
|
|
421
|
+
contentBlocks.length > 0
|
|
422
|
+
) {
|
|
423
|
+
const lastBlock = contentBlocks[contentBlocks.length - 1];
|
|
424
|
+
if (!lastBlock.cache_control)
|
|
425
|
+
lastBlock.cache_control = topLevelCacheControl;
|
|
426
|
+
}
|
|
427
|
+
messages.push({
|
|
428
|
+
role: normalizedRole === 'assistant' ? 'assistant' : 'user',
|
|
429
|
+
content: contentBlocks
|
|
430
|
+
});
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
if (isResponsesPath(pathname)) {
|
|
434
|
+
if (typeof payload.input === 'string') {
|
|
435
|
+
appendMessage('user', payload.input);
|
|
436
|
+
} else if (Array.isArray(payload.input)) {
|
|
437
|
+
payload.input.forEach(item => {
|
|
438
|
+
if (!item || typeof item !== 'object') return;
|
|
439
|
+
if (item.type === 'function_call') {
|
|
440
|
+
const assistantToolUse =
|
|
441
|
+
buildAssistantToolUseMessageFromFunctionCall(item);
|
|
442
|
+
if (assistantToolUse) {
|
|
443
|
+
messages.push(assistantToolUse);
|
|
444
|
+
}
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
if (item.type === 'function_call_output') {
|
|
448
|
+
messages.push(buildUserToolResultMessage(item));
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
if (item.type === 'message' || item.role) {
|
|
452
|
+
appendMessage(item.role, item.content, item.cache_control);
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Chat-completions conversion also applies to generic non-Responses paths
|
|
459
|
+
// (e.g. probe payloads sent against /v1/messages), so wire callers keep a
|
|
460
|
+
// single conversion path.
|
|
461
|
+
if (
|
|
462
|
+
Array.isArray(payload.messages) &&
|
|
463
|
+
(isChatCompletionsPath(pathname) || !isResponsesPath(pathname))
|
|
464
|
+
) {
|
|
465
|
+
payload.messages.forEach(message => {
|
|
466
|
+
if (!message || typeof message !== 'object') return;
|
|
467
|
+
if (message.role === 'tool') {
|
|
468
|
+
messages.push(buildUserToolResultMessage(message));
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (
|
|
472
|
+
message.role === 'assistant' &&
|
|
473
|
+
Array.isArray(message.tool_calls) &&
|
|
474
|
+
message.tool_calls.length > 0
|
|
475
|
+
) {
|
|
476
|
+
const assistantContent = normalizeOpenAiContentToClaudeBlocks(
|
|
477
|
+
message.content
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
message.tool_calls.forEach(toolCall => {
|
|
481
|
+
if (!toolCall || typeof toolCall !== 'object') return;
|
|
482
|
+
const functionPayload =
|
|
483
|
+
toolCall.function && typeof toolCall.function === 'object'
|
|
484
|
+
? toolCall.function
|
|
485
|
+
: toolCall;
|
|
486
|
+
const rawName = functionPayload.name || toolCall.name;
|
|
487
|
+
if (!rawName) return;
|
|
488
|
+
assistantContent.push({
|
|
489
|
+
type: 'tool_use',
|
|
490
|
+
id:
|
|
491
|
+
toolCall.id || functionPayload.call_id || generateToolCallId(),
|
|
492
|
+
name: rawName,
|
|
493
|
+
input: parseToolArguments(
|
|
494
|
+
functionPayload.arguments ?? functionPayload.input
|
|
495
|
+
)
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
if (assistantContent.length > 0) {
|
|
500
|
+
messages.push({
|
|
501
|
+
role: 'assistant',
|
|
502
|
+
content: assistantContent
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
appendMessage(
|
|
508
|
+
message.role,
|
|
509
|
+
message.content,
|
|
510
|
+
message.cache_control
|
|
511
|
+
);
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (messages.length === 0) {
|
|
516
|
+
messages.push({
|
|
517
|
+
role: 'user',
|
|
518
|
+
content: [{ type: 'text', text: 'Hello' }]
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return {
|
|
523
|
+
systemBlocks,
|
|
524
|
+
messages
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
module.exports = {
|
|
529
|
+
extractTextFragments,
|
|
530
|
+
extractText,
|
|
531
|
+
parseBase64DataUrl,
|
|
532
|
+
normalizeOpenAiImageBlock,
|
|
533
|
+
normalizeOpenAiFileBlock,
|
|
534
|
+
normalizeOpenAiContentItemToClaudeBlocks,
|
|
535
|
+
normalizeOpenAiContentToClaudeBlocks,
|
|
536
|
+
normalizeOpenAiRole,
|
|
537
|
+
isResponsesPath,
|
|
538
|
+
isChatCompletionsPath,
|
|
539
|
+
generateToolCallId,
|
|
540
|
+
parseToolArguments,
|
|
541
|
+
normalizeToolResultContent,
|
|
542
|
+
normalizeStopSequences,
|
|
543
|
+
buildAssistantToolUseMessageFromFunctionCall,
|
|
544
|
+
buildUserToolResultMessage,
|
|
545
|
+
normalizeOpenCodeMessages
|
|
546
|
+
};
|
|
@@ -10,7 +10,7 @@ const path = require('path');
|
|
|
10
10
|
// ---------------------------------------------------------------------------
|
|
11
11
|
|
|
12
12
|
/** @type {number} Maximum time a source inventory is considered fresh */
|
|
13
|
-
const INDEX_INVENTORY_TTL_MS =
|
|
13
|
+
const INDEX_INVENTORY_TTL_MS = 30000;
|
|
14
14
|
|
|
15
15
|
/** @type {number} Max wait for stale-ok on a cold source */
|
|
16
16
|
const COLD_STALE_WAIT_MS = 2500;
|
|
@@ -20,7 +20,8 @@ function runInventoryWorker(source, indexDbPath, options = {}) {
|
|
|
20
20
|
CC_TOOL_SESSION_HISTORY_CHILD: '1'
|
|
21
21
|
},
|
|
22
22
|
silent: true,
|
|
23
|
-
stdio: ['pipe', 'pipe', 'pipe', 'ipc']
|
|
23
|
+
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
|
|
24
|
+
windowsHide: true
|
|
24
25
|
});
|
|
25
26
|
|
|
26
27
|
let settled = false;
|