dsh-subscriptions 0.1.5 → 0.2.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/README.md +212 -154
- package/lib/auth/claude-code-creds.js +31 -9
- package/lib/auth/device-flow.js +16 -9
- package/lib/auth/oauth-flow.js +13 -10
- package/lib/auth/rpc.d.ts +73 -2
- package/lib/auth/rpc.js +124 -23
- package/lib/auth/store.js +80 -31
- package/lib/client/CursorCard.d.ts +1 -1
- package/lib/client/CursorCard.js +50 -16
- package/lib/client/ExternalUsageCards.d.ts +1 -1
- package/lib/client/ExternalUsageCards.js +37 -16
- package/lib/client/ImageGallery.d.ts +2 -2
- package/lib/client/ImageGallery.js +92 -33
- package/lib/client/ImageGenerateToolview.js +50 -14
- package/lib/client/OllamaCard.d.ts +13 -0
- package/lib/client/OllamaCard.js +94 -0
- package/lib/client/OllamaSettingsManager.d.ts +24 -0
- package/lib/client/OllamaSettingsManager.js +329 -0
- package/lib/client/ProviderAccountManager.d.ts +1 -1
- package/lib/client/ProviderAccountManager.js +164 -49
- package/lib/client/ProviderModelEditor.js +109 -26
- package/lib/client/SpeedSelect.d.ts +62 -14
- package/lib/client/SpeedSelect.js +257 -46
- package/lib/client/SubscriptionUsageBadge.d.ts +5 -11
- package/lib/client/SubscriptionUsageBadge.js +301 -112
- package/lib/client/SubscriptionsSection.d.ts +2 -0
- package/lib/client/SubscriptionsSection.js +259 -85
- package/lib/client/UsageBadgeDisplaySetting.js +35 -12
- package/lib/client/UsageMeter.d.ts +1 -1
- package/lib/client/UsageMeter.js +69 -27
- package/lib/client/VideoGenerateToolview.js +69 -17
- package/lib/client/account-preferences.d.ts +8 -0
- package/lib/client/account-preferences.js +20 -5
- package/lib/client/host-contract.d.ts +11 -2
- package/lib/client/host-contract.js +20 -3
- package/lib/client/index.d.ts +5 -5
- package/lib/client/index.js +34 -12
- package/lib/client/locales.d.ts +78 -0
- package/lib/client/locales.js +121 -34
- package/lib/client/ollama-draft.d.ts +229 -0
- package/lib/client/ollama-draft.js +255 -0
- package/lib/client/reset-action.js +6 -4
- package/lib/client/reset-credits-view.d.ts +1 -1
- package/lib/client/reset-credits-view.js +66 -17
- package/lib/client/subscription-card-styles.js +94 -24
- package/lib/client/usage-color-preferences.js +4 -2
- package/lib/client/usage-pace.d.ts +7 -0
- package/lib/client/usage-pace.js +43 -10
- package/lib/client.js +1647 -266
- package/lib/client.js.map +1 -1
- package/lib/http.js +1 -1
- package/lib/index.d.ts +28 -3
- package/lib/index.js +9329 -8217
- package/lib/model-defaults.js +4 -2
- package/lib/provider-settings.d.ts +14 -1
- package/lib/provider-settings.js +64 -20
- package/lib/providers/account-preferences.js +51 -22
- package/lib/providers/accounts.js +15 -9
- package/lib/providers/antigravity-oauth-client.js +2 -2
- package/lib/providers/antigravity.js +141 -68
- package/lib/providers/catalog-store.js +120 -41
- package/lib/providers/claude-cli-version.js +3 -3
- package/lib/providers/claude.d.ts +23 -3
- package/lib/providers/claude.js +167 -92
- package/lib/providers/codex-client-version.js +3 -3
- package/lib/providers/codex-search.js +40 -13
- package/lib/providers/codex.js +196 -112
- package/lib/providers/common.d.ts +14 -0
- package/lib/providers/common.js +118 -38
- package/lib/providers/copilot.js +143 -82
- package/lib/providers/cursor-adapter.js +42 -18
- package/lib/providers/cursor-auth.d.ts +1 -1
- package/lib/providers/cursor-auth.js +69 -24
- package/lib/providers/cursor-model-settings.js +14 -5
- package/lib/providers/cursor-usage.js +27 -13
- package/lib/providers/external-usage-controller.d.ts +9 -2
- package/lib/providers/external-usage-controller.js +30 -7
- package/lib/providers/external-usage.d.ts +8 -0
- package/lib/providers/external-usage.js +140 -20
- package/lib/providers/grok.js +152 -89
- package/lib/providers/image-pool.js +29 -11
- package/lib/providers/minimax-usage.js +31 -11
- package/lib/providers/npm-cli-version.js +10 -3
- package/lib/providers/ollama-settings.d.ts +90 -0
- package/lib/providers/ollama-settings.js +213 -0
- package/lib/providers/ollama-web.d.ts +46 -0
- package/lib/providers/ollama-web.js +231 -0
- package/lib/providers/ollama.d.ts +107 -0
- package/lib/providers/ollama.js +608 -0
- package/lib/providers/pool-family.js +11 -3
- package/lib/providers/pool-health.js +28 -8
- package/lib/providers/pool-usage.js +16 -9
- package/lib/providers/pool.d.ts +8 -0
- package/lib/providers/pool.js +81 -42
- package/lib/providers/rate-limit.js +8 -2
- package/lib/providers/replay.js +40 -17
- package/lib/providers/reset-redemption.js +18 -6
- package/lib/tools/image-generate.js +123 -65
- package/lib/tools/registration.js +5 -2
- package/lib/tools/video-generate.js +51 -31
- package/lib/tools/x-search.js +50 -22
- package/lib/translate/anthropic.js +85 -37
- package/lib/translate/antigravity-schema.js +71 -28
- package/lib/translate/antigravity-thinking.js +22 -9
- package/lib/translate/antigravity.js +141 -50
- package/lib/translate/chat-completions.js +67 -23
- package/lib/translate/resolved.js +55 -21
- package/lib/translate/responses.js +69 -29
- package/lib/translate/sse.js +4 -1
- package/package.json +26 -4
|
@@ -22,37 +22,54 @@ import { antigravityToolParameters } from './antigravity-schema.js';
|
|
|
22
22
|
* successful results retain their existing serialized shape.
|
|
23
23
|
*/
|
|
24
24
|
function toolResultValue(block) {
|
|
25
|
-
const text = block.content
|
|
25
|
+
const text = block.content
|
|
26
|
+
.map((part) => (part.type === 'text' ? part.text : ''))
|
|
27
|
+
.join('');
|
|
26
28
|
let parsed;
|
|
27
29
|
try {
|
|
28
30
|
parsed = JSON.parse(text);
|
|
29
31
|
}
|
|
30
32
|
catch {
|
|
31
|
-
return {
|
|
33
|
+
return {
|
|
34
|
+
output: text,
|
|
35
|
+
...(block.isError === true ? { isError: true } : {}),
|
|
36
|
+
};
|
|
32
37
|
}
|
|
33
38
|
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
34
39
|
const value = parsed;
|
|
35
40
|
return block.isError === true ? { ...value, isError: true } : value;
|
|
36
41
|
}
|
|
37
|
-
return {
|
|
42
|
+
return {
|
|
43
|
+
output: parsed,
|
|
44
|
+
...(block.isError === true ? { isError: true } : {}),
|
|
45
|
+
};
|
|
38
46
|
}
|
|
39
47
|
/** Safely read per-block replay metadata emitted by this adapter. */
|
|
40
48
|
function replayBlocks(message, model) {
|
|
41
49
|
const source = message.source;
|
|
42
|
-
if (model !== undefined &&
|
|
43
|
-
|
|
50
|
+
if (model !== undefined &&
|
|
51
|
+
(message.source?.kind !== 'model' ||
|
|
52
|
+
message.source.provider !== 'antigravity' ||
|
|
53
|
+
message.source.model !== model))
|
|
44
54
|
return [];
|
|
45
|
-
if (source?.kind !== 'model' ||
|
|
55
|
+
if (source?.kind !== 'model' ||
|
|
56
|
+
typeof source.replayState !== 'object' ||
|
|
57
|
+
source.replayState === null)
|
|
46
58
|
return [];
|
|
47
59
|
const envelope = source.replayState;
|
|
48
60
|
const response = envelope.response;
|
|
49
|
-
if (response === null ||
|
|
61
|
+
if (response === null ||
|
|
62
|
+
response?.kind !== 'antigravity' ||
|
|
63
|
+
response.version !== 1 ||
|
|
64
|
+
!Array.isArray(envelope.blocks))
|
|
50
65
|
return [];
|
|
51
66
|
return envelope.blocks.map((entry) => {
|
|
52
67
|
if (typeof entry !== 'object' || entry === null)
|
|
53
68
|
return {};
|
|
54
69
|
const signature = entry.thoughtSignature;
|
|
55
|
-
return typeof signature === 'string' && signature.length > 0
|
|
70
|
+
return typeof signature === 'string' && signature.length > 0
|
|
71
|
+
? { thoughtSignature: signature }
|
|
72
|
+
: {};
|
|
56
73
|
});
|
|
57
74
|
}
|
|
58
75
|
/** Map harness tool schemas to Gemini function declarations. */
|
|
@@ -60,13 +77,15 @@ export function toAntigravityTools(tools, model = 'gemini') {
|
|
|
60
77
|
if (tools.length === 0)
|
|
61
78
|
return [];
|
|
62
79
|
const legacy = /^(claude-|gpt-oss-)/.test(model);
|
|
63
|
-
return [
|
|
64
|
-
|
|
80
|
+
return [
|
|
81
|
+
{
|
|
82
|
+
functionDeclarations: tools.map((tool) => ({
|
|
65
83
|
name: tool.name,
|
|
66
84
|
description: tool.description,
|
|
67
85
|
[legacy ? 'parameters' : 'parametersJsonSchema']: antigravityToolParameters(tool.parameters, legacy),
|
|
68
86
|
})),
|
|
69
|
-
}
|
|
87
|
+
},
|
|
88
|
+
];
|
|
70
89
|
}
|
|
71
90
|
const SKIP_THOUGHT_SIGNATURE_VALIDATOR = 'skip_thought_signature_validator';
|
|
72
91
|
/** Gemini 3 validates the first function call in every model tool-call step. */
|
|
@@ -85,18 +104,27 @@ export function toAntigravityContents(messages, model) {
|
|
|
85
104
|
if (message.role === 'system')
|
|
86
105
|
continue;
|
|
87
106
|
if (message.role === 'tool') {
|
|
88
|
-
const id = message.toolCallId ??
|
|
89
|
-
|
|
107
|
+
const id = message.toolCallId ??
|
|
108
|
+
message.tool_call_id ??
|
|
109
|
+
(message.source?.kind === 'tool'
|
|
110
|
+
? String(message.source.callId)
|
|
111
|
+
: undefined);
|
|
90
112
|
if (id === undefined)
|
|
91
113
|
throw new LlmError('tool result has no call id', 'INVALID_REQUEST');
|
|
92
|
-
const part = {
|
|
114
|
+
const part = {
|
|
115
|
+
functionResponse: {
|
|
93
116
|
id,
|
|
94
117
|
name: callNames.get(id) ?? '',
|
|
95
118
|
response: toolResultValue({
|
|
96
|
-
type: 'tool-result',
|
|
97
|
-
|
|
119
|
+
type: 'tool-result',
|
|
120
|
+
toolCallId: ToolCallId(id),
|
|
121
|
+
content: message.content,
|
|
122
|
+
...(message.isError === undefined
|
|
123
|
+
? {}
|
|
124
|
+
: { isError: message.isError }),
|
|
98
125
|
}),
|
|
99
|
-
}
|
|
126
|
+
},
|
|
127
|
+
};
|
|
100
128
|
const previous = out.at(-1);
|
|
101
129
|
if (previous?.role === 'user')
|
|
102
130
|
previous.parts.push(part);
|
|
@@ -115,7 +143,9 @@ export function toAntigravityContents(messages, model) {
|
|
|
115
143
|
// Antigravity's Claude-backed models reject empty text parts.
|
|
116
144
|
parts.push({
|
|
117
145
|
text: block.text.trim().length > 0 ? block.text : '.',
|
|
118
|
-
...metadata[index]?.thoughtSignature === undefined
|
|
146
|
+
...(metadata[index]?.thoughtSignature === undefined
|
|
147
|
+
? {}
|
|
148
|
+
: { thoughtSignature: metadata[index].thoughtSignature }),
|
|
119
149
|
});
|
|
120
150
|
break;
|
|
121
151
|
case 'reasoning': {
|
|
@@ -126,7 +156,9 @@ export function toAntigravityContents(messages, model) {
|
|
|
126
156
|
}
|
|
127
157
|
case 'image':
|
|
128
158
|
if ('dataBase64' in block) {
|
|
129
|
-
parts.push({
|
|
159
|
+
parts.push({
|
|
160
|
+
inlineData: { mimeType: block.mediaType, data: block.dataBase64 },
|
|
161
|
+
});
|
|
130
162
|
}
|
|
131
163
|
break;
|
|
132
164
|
case 'tool-call': {
|
|
@@ -139,12 +171,13 @@ export function toAntigravityContents(messages, model) {
|
|
|
139
171
|
args = {};
|
|
140
172
|
}
|
|
141
173
|
const replaySignature = metadata[index]?.thoughtSignature;
|
|
142
|
-
const thoughtSignature = replaySignature ??
|
|
143
|
-
|
|
144
|
-
|
|
174
|
+
const thoughtSignature = replaySignature ??
|
|
175
|
+
(!sawFunctionCall && requiresThoughtSignatures(model)
|
|
176
|
+
? SKIP_THOUGHT_SIGNATURE_VALIDATOR
|
|
177
|
+
: undefined);
|
|
145
178
|
parts.push({
|
|
146
179
|
functionCall: { id: String(block.id), name: block.name, args },
|
|
147
|
-
...thoughtSignature === undefined ? {} : { thoughtSignature },
|
|
180
|
+
...(thoughtSignature === undefined ? {} : { thoughtSignature }),
|
|
148
181
|
});
|
|
149
182
|
sawFunctionCall = true;
|
|
150
183
|
break;
|
|
@@ -186,19 +219,29 @@ export function toAntigravityRequest(options, messages, projectId, forStreaming
|
|
|
186
219
|
const thinkingConfig = antigravityThinking(options.model, options.reasoningEffort, options.maxTokens);
|
|
187
220
|
let maxOutputTokens = options.maxTokens;
|
|
188
221
|
// Claude models on the streaming path reject maxOutputTokens >= 65535
|
|
189
|
-
if (forStreaming &&
|
|
222
|
+
if (forStreaming &&
|
|
223
|
+
maxOutputTokens !== undefined &&
|
|
224
|
+
/^claude-/.test(options.model) &&
|
|
225
|
+
maxOutputTokens >= 65535) {
|
|
190
226
|
maxOutputTokens = 64000;
|
|
191
227
|
}
|
|
192
228
|
const generationConfig = {
|
|
193
|
-
...maxOutputTokens === undefined ? {} : { maxOutputTokens },
|
|
194
|
-
...options.temperature === undefined
|
|
195
|
-
|
|
196
|
-
|
|
229
|
+
...(maxOutputTokens === undefined ? {} : { maxOutputTokens }),
|
|
230
|
+
...(options.temperature === undefined
|
|
231
|
+
? {}
|
|
232
|
+
: { temperature: options.temperature }),
|
|
233
|
+
...(options.stop === undefined || options.stop.length === 0
|
|
234
|
+
? {}
|
|
235
|
+
: { stopSequences: options.stop }),
|
|
236
|
+
...(thinkingConfig === undefined ? {} : { thinkingConfig }),
|
|
197
237
|
};
|
|
198
|
-
const systemTexts = messages.flatMap(message => message.role === 'system'
|
|
199
|
-
? message.content
|
|
238
|
+
const systemTexts = messages.flatMap((message) => message.role === 'system'
|
|
239
|
+
? message.content
|
|
240
|
+
.filter((block) => block.type === 'text')
|
|
241
|
+
.map((block) => block.text)
|
|
200
242
|
: []);
|
|
201
|
-
const system = options.system ??
|
|
243
|
+
const system = options.system ??
|
|
244
|
+
(systemTexts.length > 0 ? systemTexts.join('\n\n') : undefined);
|
|
202
245
|
const sessionId = options.sessionId === undefined ? randomUUID() : String(options.sessionId);
|
|
203
246
|
return {
|
|
204
247
|
project: projectId,
|
|
@@ -209,12 +252,20 @@ export function toAntigravityRequest(options, messages, projectId, forStreaming
|
|
|
209
252
|
request: {
|
|
210
253
|
contents: toAntigravityContents(messages, options.model),
|
|
211
254
|
sessionId,
|
|
212
|
-
...system === undefined || system.length === 0
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
255
|
+
...(system === undefined || system.length === 0
|
|
256
|
+
? {}
|
|
257
|
+
: { systemInstruction: { parts: [{ text: system }] } }),
|
|
258
|
+
...(tools.length === 0
|
|
259
|
+
? {}
|
|
260
|
+
: {
|
|
261
|
+
tools,
|
|
262
|
+
toolConfig: {
|
|
263
|
+
functionCallingConfig: { mode: 'VALIDATED' },
|
|
264
|
+
},
|
|
265
|
+
}),
|
|
266
|
+
...(Object.keys(generationConfig).length === 0
|
|
267
|
+
? {}
|
|
268
|
+
: { generationConfig }),
|
|
218
269
|
},
|
|
219
270
|
};
|
|
220
271
|
}
|
|
@@ -224,8 +275,10 @@ export function mapAntigravityUsage(metadata) {
|
|
|
224
275
|
return {
|
|
225
276
|
inputTokens: Math.max(0, (metadata.promptTokenCount ?? 0) - cached),
|
|
226
277
|
outputTokens: metadata.candidatesTokenCount ?? 0,
|
|
227
|
-
...cached > 0 ? { cacheReadTokens: cached } : {},
|
|
228
|
-
...metadata.thoughtsTokenCount === undefined
|
|
278
|
+
...(cached > 0 ? { cacheReadTokens: cached } : {}),
|
|
279
|
+
...(metadata.thoughtsTokenCount === undefined
|
|
280
|
+
? {}
|
|
281
|
+
: { reasoningTokens: metadata.thoughtsTokenCount }),
|
|
229
282
|
};
|
|
230
283
|
}
|
|
231
284
|
/** Push translator for both parsed SSE events and one non-stream response. */
|
|
@@ -237,7 +290,12 @@ export class AntigravityStreamTranslator {
|
|
|
237
290
|
sawToolCall = false;
|
|
238
291
|
terminated = false;
|
|
239
292
|
open(key, kind, chunks, values = {}) {
|
|
240
|
-
const block = {
|
|
293
|
+
const block = {
|
|
294
|
+
index: this.nextIndex++,
|
|
295
|
+
kind,
|
|
296
|
+
text: '',
|
|
297
|
+
...values,
|
|
298
|
+
};
|
|
241
299
|
this.blocks.set(key, block);
|
|
242
300
|
chunks.push({ type: 'block-start', index: block.index, blockType: kind });
|
|
243
301
|
return block;
|
|
@@ -259,7 +317,10 @@ export class AntigravityStreamTranslator {
|
|
|
259
317
|
name: block.name ?? '',
|
|
260
318
|
arguments: block.text,
|
|
261
319
|
};
|
|
262
|
-
this.closed[block.index] =
|
|
320
|
+
this.closed[block.index] =
|
|
321
|
+
block.thoughtSignature === undefined
|
|
322
|
+
? {}
|
|
323
|
+
: { thoughtSignature: block.thoughtSignature };
|
|
263
324
|
chunks.push({ type: 'block-end', index: block.index, block: content });
|
|
264
325
|
}
|
|
265
326
|
closeAll(chunks) {
|
|
@@ -268,24 +329,45 @@ export class AntigravityStreamTranslator {
|
|
|
268
329
|
}
|
|
269
330
|
finish(reason) {
|
|
270
331
|
const replayState = {
|
|
271
|
-
response: {
|
|
332
|
+
response: {
|
|
333
|
+
kind: 'antigravity',
|
|
334
|
+
version: 1,
|
|
335
|
+
},
|
|
272
336
|
blocks: this.closed,
|
|
273
337
|
};
|
|
274
338
|
if (!this.sawContent) {
|
|
275
339
|
return {
|
|
276
340
|
type: 'finish',
|
|
277
|
-
reason: {
|
|
341
|
+
reason: {
|
|
342
|
+
kind: 'error',
|
|
343
|
+
failure: {
|
|
344
|
+
message: 'Antigravity returned no content',
|
|
345
|
+
code: EMPTY_RESPONSE_CODE,
|
|
346
|
+
},
|
|
347
|
+
},
|
|
278
348
|
};
|
|
279
349
|
}
|
|
280
350
|
if (reason === 'MAX_TOKENS')
|
|
281
351
|
return { type: 'finish', reason: { kind: 'max-tokens' }, replayState };
|
|
282
|
-
if (reason === 'SAFETY' ||
|
|
352
|
+
if (reason === 'SAFETY' ||
|
|
353
|
+
reason === 'RECITATION' ||
|
|
354
|
+
reason === 'BLOCKLIST') {
|
|
283
355
|
return {
|
|
284
356
|
type: 'finish',
|
|
285
|
-
reason: {
|
|
357
|
+
reason: {
|
|
358
|
+
kind: 'error',
|
|
359
|
+
failure: {
|
|
360
|
+
message: `Antigravity blocked the response (${reason})`,
|
|
361
|
+
code: 'CONTENT_FILTER',
|
|
362
|
+
},
|
|
363
|
+
},
|
|
286
364
|
};
|
|
287
365
|
}
|
|
288
|
-
return {
|
|
366
|
+
return {
|
|
367
|
+
type: 'finish',
|
|
368
|
+
reason: { kind: this.sawToolCall ? 'tool-calls' : 'stop' },
|
|
369
|
+
replayState,
|
|
370
|
+
};
|
|
289
371
|
}
|
|
290
372
|
/** Process one decoded Antigravity response frame. */
|
|
291
373
|
push(event) {
|
|
@@ -294,13 +376,20 @@ export class AntigravityStreamTranslator {
|
|
|
294
376
|
const chunks = [];
|
|
295
377
|
const candidate = event.response?.candidates?.[0];
|
|
296
378
|
for (const [partIndex, part] of (candidate?.content?.parts ?? []).entries()) {
|
|
297
|
-
if (part.thought === true &&
|
|
298
|
-
|
|
379
|
+
if (part.thought === true &&
|
|
380
|
+
typeof part.text === 'string' &&
|
|
381
|
+
part.text.length > 0) {
|
|
382
|
+
const block = this.blocks.get('reasoning') ??
|
|
383
|
+
this.open('reasoning', 'reasoning', chunks);
|
|
299
384
|
block.text += part.text;
|
|
300
385
|
if (part.thoughtSignature !== undefined)
|
|
301
386
|
block.thoughtSignature = part.thoughtSignature;
|
|
302
387
|
this.sawContent = true;
|
|
303
|
-
chunks.push({
|
|
388
|
+
chunks.push({
|
|
389
|
+
type: 'reasoning-delta',
|
|
390
|
+
index: block.index,
|
|
391
|
+
text: part.text,
|
|
392
|
+
});
|
|
304
393
|
}
|
|
305
394
|
else if (typeof part.text === 'string' && part.text.length > 0) {
|
|
306
395
|
const block = this.blocks.get('text') ?? this.open('text', 'text', chunks);
|
|
@@ -320,7 +409,9 @@ export class AntigravityStreamTranslator {
|
|
|
320
409
|
const block = this.open(key, 'tool-call', chunks, {
|
|
321
410
|
id,
|
|
322
411
|
name: call.name ?? '',
|
|
323
|
-
...part.thoughtSignature === undefined
|
|
412
|
+
...(part.thoughtSignature === undefined
|
|
413
|
+
? {}
|
|
414
|
+
: { thoughtSignature: part.thoughtSignature }),
|
|
324
415
|
});
|
|
325
416
|
block.text = args;
|
|
326
417
|
this.sawContent = true;
|
|
@@ -11,7 +11,9 @@ import { parseSse } from './sse.js';
|
|
|
11
11
|
import { withToolResultImages } from './resolved.js';
|
|
12
12
|
/** Flatten a tool result's content to plain text for a `tool` message. */
|
|
13
13
|
function toolResultText(block) {
|
|
14
|
-
return block.content
|
|
14
|
+
return block.content
|
|
15
|
+
.map((part) => (part.type === 'text' ? part.text : ''))
|
|
16
|
+
.join('');
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
17
19
|
* Convert harness messages into chat completions `messages`. System-role
|
|
@@ -37,15 +39,27 @@ export function toChatMessages(messages, system) {
|
|
|
37
39
|
continue;
|
|
38
40
|
}
|
|
39
41
|
if (message.role === 'tool') {
|
|
40
|
-
const callId = message.toolCallId ??
|
|
41
|
-
|
|
42
|
+
const callId = message.toolCallId ??
|
|
43
|
+
message.tool_call_id ??
|
|
44
|
+
(message.source?.kind === 'tool'
|
|
45
|
+
? String(message.source.callId)
|
|
46
|
+
: undefined);
|
|
42
47
|
if (callId === undefined)
|
|
43
48
|
throw new LlmError('tool result has no call id', 'INVALID_REQUEST');
|
|
44
|
-
out.push({
|
|
49
|
+
out.push({
|
|
50
|
+
role: 'tool',
|
|
51
|
+
tool_call_id: callId,
|
|
52
|
+
content: message.content
|
|
53
|
+
.map((block) => (block.type === 'text' ? block.text : ''))
|
|
54
|
+
.join(''),
|
|
55
|
+
});
|
|
45
56
|
continue;
|
|
46
57
|
}
|
|
47
58
|
if (message.role === 'developer') {
|
|
48
|
-
const content = message.content
|
|
59
|
+
const content = message.content
|
|
60
|
+
.filter((block) => block.type === 'text')
|
|
61
|
+
.map((block) => block.text)
|
|
62
|
+
.join('');
|
|
49
63
|
if (content.length > 0)
|
|
50
64
|
out.push({ role: 'developer', content });
|
|
51
65
|
continue;
|
|
@@ -79,7 +93,9 @@ export function toChatMessages(messages, system) {
|
|
|
79
93
|
if ('dataBase64' in block) {
|
|
80
94
|
parts.push({
|
|
81
95
|
type: 'image_url',
|
|
82
|
-
image_url: {
|
|
96
|
+
image_url: {
|
|
97
|
+
url: `data:${block.mediaType};base64,${block.dataBase64}`,
|
|
98
|
+
},
|
|
83
99
|
});
|
|
84
100
|
}
|
|
85
101
|
break;
|
|
@@ -123,7 +139,7 @@ export function toChatMessages(messages, system) {
|
|
|
123
139
|
out.push({
|
|
124
140
|
role: 'assistant',
|
|
125
141
|
content: texts.join('\n'),
|
|
126
|
-
...toolCalls.length > 0 ? { tool_calls: toolCalls } : {},
|
|
142
|
+
...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),
|
|
127
143
|
});
|
|
128
144
|
}
|
|
129
145
|
const systemText = system ?? (systemTexts.length > 0 ? systemTexts.join('\n\n') : undefined);
|
|
@@ -137,7 +153,7 @@ export function toChatMessages(messages, system) {
|
|
|
137
153
|
* @returns the wire `tools` array.
|
|
138
154
|
*/
|
|
139
155
|
export function toChatTools(tools) {
|
|
140
|
-
return tools.map(tool => ({
|
|
156
|
+
return tools.map((tool) => ({
|
|
141
157
|
type: 'function',
|
|
142
158
|
function: {
|
|
143
159
|
name: tool.name,
|
|
@@ -158,8 +174,8 @@ export function mapChatCompletionsUsage(usage) {
|
|
|
158
174
|
return {
|
|
159
175
|
inputTokens: usage.prompt_tokens - (cached ?? 0),
|
|
160
176
|
outputTokens: usage.completion_tokens,
|
|
161
|
-
...cached !== undefined ? { cacheReadTokens: cached } : {},
|
|
162
|
-
...reasoning !== undefined ? { reasoningTokens: reasoning } : {},
|
|
177
|
+
...(cached !== undefined ? { cacheReadTokens: cached } : {}),
|
|
178
|
+
...(reasoning !== undefined ? { reasoningTokens: reasoning } : {}),
|
|
163
179
|
};
|
|
164
180
|
}
|
|
165
181
|
/** Assemble the final ContentBlock for one open block. */
|
|
@@ -208,7 +224,7 @@ export class ChatCompletionsStreamTranslator {
|
|
|
208
224
|
kind,
|
|
209
225
|
text: '',
|
|
210
226
|
callId,
|
|
211
|
-
...name === undefined ? {} : { name },
|
|
227
|
+
...(name === undefined ? {} : { name }),
|
|
212
228
|
};
|
|
213
229
|
this.blocks.set(key, block);
|
|
214
230
|
this.order.push(block);
|
|
@@ -220,7 +236,11 @@ export class ChatCompletionsStreamTranslator {
|
|
|
220
236
|
if (block === undefined)
|
|
221
237
|
return;
|
|
222
238
|
this.blocks.delete(key);
|
|
223
|
-
chunks.push({
|
|
239
|
+
chunks.push({
|
|
240
|
+
type: 'block-end',
|
|
241
|
+
index: block.index,
|
|
242
|
+
block: closeBlock(block),
|
|
243
|
+
});
|
|
224
244
|
}
|
|
225
245
|
closeAll(chunks) {
|
|
226
246
|
for (const key of [...this.blocks.keys()])
|
|
@@ -233,7 +253,10 @@ export class ChatCompletionsStreamTranslator {
|
|
|
233
253
|
type: 'finish',
|
|
234
254
|
reason: {
|
|
235
255
|
kind: 'error',
|
|
236
|
-
failure: {
|
|
256
|
+
failure: {
|
|
257
|
+
message: 'model returned a completed response with no content',
|
|
258
|
+
code: EMPTY_RESPONSE_CODE,
|
|
259
|
+
},
|
|
237
260
|
},
|
|
238
261
|
};
|
|
239
262
|
}
|
|
@@ -247,17 +270,26 @@ export class ChatCompletionsStreamTranslator {
|
|
|
247
270
|
type: 'finish',
|
|
248
271
|
reason: {
|
|
249
272
|
kind: 'error',
|
|
250
|
-
failure: {
|
|
273
|
+
failure: {
|
|
274
|
+
message: 'the response was blocked by the provider content filter',
|
|
275
|
+
code: 'CONTENT_FILTER',
|
|
276
|
+
},
|
|
251
277
|
},
|
|
252
278
|
};
|
|
253
279
|
default:
|
|
254
|
-
return {
|
|
280
|
+
return {
|
|
281
|
+
type: 'finish',
|
|
282
|
+
reason: { kind: this.sawToolCall ? 'tool-calls' : 'stop' },
|
|
283
|
+
};
|
|
255
284
|
}
|
|
256
285
|
}
|
|
257
286
|
/** Usage, then the armed finish: the only order the harness accepts. */
|
|
258
287
|
drainTerminal(chunks) {
|
|
259
288
|
if (this.pendingUsage !== undefined) {
|
|
260
|
-
chunks.push({
|
|
289
|
+
chunks.push({
|
|
290
|
+
type: 'usage',
|
|
291
|
+
usage: mapChatCompletionsUsage(this.pendingUsage),
|
|
292
|
+
});
|
|
261
293
|
this.pendingUsage = undefined;
|
|
262
294
|
}
|
|
263
295
|
if (this.armedFinish !== undefined) {
|
|
@@ -285,15 +317,26 @@ export class ChatCompletionsStreamTranslator {
|
|
|
285
317
|
if (typeof delta.content === 'string' && delta.content.length > 0) {
|
|
286
318
|
const block = this.blocks.get('content') ?? this.open('content', 'text', chunks);
|
|
287
319
|
block.text += delta.content;
|
|
288
|
-
chunks.push({
|
|
320
|
+
chunks.push({
|
|
321
|
+
type: 'text-delta',
|
|
322
|
+
index: block.index,
|
|
323
|
+
text: delta.content,
|
|
324
|
+
});
|
|
289
325
|
}
|
|
290
|
-
const reasoning = typeof delta.reasoning_content === 'string'
|
|
291
|
-
|
|
326
|
+
const reasoning = typeof delta.reasoning_content === 'string'
|
|
327
|
+
? delta.reasoning_content
|
|
328
|
+
: typeof delta.reasoning_text === 'string'
|
|
329
|
+
? delta.reasoning_text
|
|
292
330
|
: undefined;
|
|
293
331
|
if (reasoning !== undefined && reasoning.length > 0) {
|
|
294
|
-
const block = this.blocks.get('reasoning') ??
|
|
332
|
+
const block = this.blocks.get('reasoning') ??
|
|
333
|
+
this.open('reasoning', 'reasoning', chunks);
|
|
295
334
|
block.text += reasoning;
|
|
296
|
-
chunks.push({
|
|
335
|
+
chunks.push({
|
|
336
|
+
type: 'reasoning-delta',
|
|
337
|
+
index: block.index,
|
|
338
|
+
text: reasoning,
|
|
339
|
+
});
|
|
297
340
|
}
|
|
298
341
|
for (const call of delta.tool_calls ?? []) {
|
|
299
342
|
const key = `call:${String(call.index ?? 0)}`;
|
|
@@ -305,11 +348,12 @@ export class ChatCompletionsStreamTranslator {
|
|
|
305
348
|
type: 'tool-call-delta',
|
|
306
349
|
index: block.index,
|
|
307
350
|
id: ToolCallId(block.callId),
|
|
308
|
-
...block.name === undefined ? {} : { name: block.name },
|
|
351
|
+
...(block.name === undefined ? {} : { name: block.name }),
|
|
309
352
|
argumentsDelta: '',
|
|
310
353
|
});
|
|
311
354
|
}
|
|
312
|
-
if (call.function?.arguments !== undefined &&
|
|
355
|
+
if (call.function?.arguments !== undefined &&
|
|
356
|
+
call.function.arguments.length > 0) {
|
|
313
357
|
block.text += call.function.arguments;
|
|
314
358
|
chunks.push({
|
|
315
359
|
type: 'tool-call-delta',
|