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
|
@@ -28,7 +28,10 @@ export function withToolResultImages(messages) {
|
|
|
28
28
|
if (message.role === 'tool') {
|
|
29
29
|
const parts = message.content.filter((part) => part.type === 'image' && 'dataBase64' in part);
|
|
30
30
|
if (parts.length > 0) {
|
|
31
|
-
images.push({
|
|
31
|
+
images.push({
|
|
32
|
+
type: 'text',
|
|
33
|
+
text: `Images from tool result ${String(message.toolCallId)}:`,
|
|
34
|
+
}, ...parts);
|
|
32
35
|
}
|
|
33
36
|
}
|
|
34
37
|
for (const block of message.content) {
|
|
@@ -36,7 +39,10 @@ export function withToolResultImages(messages) {
|
|
|
36
39
|
continue;
|
|
37
40
|
const parts = block.content.filter((part) => part.type === 'image' && 'dataBase64' in part);
|
|
38
41
|
if (parts.length > 0) {
|
|
39
|
-
images.push({
|
|
42
|
+
images.push({
|
|
43
|
+
type: 'text',
|
|
44
|
+
text: `Images from tool result ${String(block.toolCallId)}:`,
|
|
45
|
+
}, ...parts);
|
|
40
46
|
}
|
|
41
47
|
}
|
|
42
48
|
}
|
|
@@ -59,8 +65,8 @@ export const IMAGE_OFFLOAD_REQUIRED = 'IMAGE_OFFLOAD_REQUIRED';
|
|
|
59
65
|
*/
|
|
60
66
|
export function hostSupportsImageOffload() {
|
|
61
67
|
const exports = llm;
|
|
62
|
-
return exports['IMAGE_OFFLOAD_REQUIRED_CODE'] === IMAGE_OFFLOAD_REQUIRED
|
|
63
|
-
|
|
68
|
+
return (exports['IMAGE_OFFLOAD_REQUIRED_CODE'] === IMAGE_OFFLOAD_REQUIRED &&
|
|
69
|
+
typeof exports['offloadedImageText'] === 'function');
|
|
64
70
|
}
|
|
65
71
|
/**
|
|
66
72
|
* How many of the oldest images still sent inline must be offloaded before
|
|
@@ -102,7 +108,7 @@ export function imageRequestTarget(ref, limit) {
|
|
|
102
108
|
const longEdge = Math.max(ref.width, ref.height);
|
|
103
109
|
if (!(longEdge > limit.maxEdge))
|
|
104
110
|
return undefined;
|
|
105
|
-
const short = (edge) => Math.max(1, Math.floor(edge * limit.maxEdge / longEdge));
|
|
111
|
+
const short = (edge) => Math.max(1, Math.floor((edge * limit.maxEdge) / longEdge));
|
|
106
112
|
const width = ref.width >= ref.height ? limit.maxEdge : short(ref.width);
|
|
107
113
|
const height = ref.width >= ref.height ? short(ref.height) : limit.maxEdge;
|
|
108
114
|
return { width, height, maxPixels: width * height, maxBytes: limit.maxBytes };
|
|
@@ -123,10 +129,10 @@ export async function resolveImages(messages, attachments, signal, limit) {
|
|
|
123
129
|
const hasRetainedImage = (block) => block.type === 'image'
|
|
124
130
|
? !('offloaded' in block && block.offloaded === true)
|
|
125
131
|
: block.type === 'tool-result' && block.content.some(hasRetainedImage);
|
|
126
|
-
if (attachments === undefined
|
|
127
|
-
|
|
128
|
-
throw new LlmError('dsh-subscriptions: the request carries an image but no attachments service is mounted; '
|
|
129
|
-
|
|
132
|
+
if (attachments === undefined &&
|
|
133
|
+
messages.some((message) => message.content.some(hasRetainedImage))) {
|
|
134
|
+
throw new LlmError('dsh-subscriptions: the request carries an image but no attachments service is mounted; ' +
|
|
135
|
+
'image input requires the harness attachment store', 'UNSUPPORTED');
|
|
130
136
|
}
|
|
131
137
|
const readForRequest = async (ref) => {
|
|
132
138
|
if (attachments === undefined)
|
|
@@ -135,7 +141,11 @@ export async function resolveImages(messages, attachments, signal, limit) {
|
|
|
135
141
|
if (target !== undefined) {
|
|
136
142
|
try {
|
|
137
143
|
const version = await attachments.readImageRequest(ref, target, signal);
|
|
138
|
-
return {
|
|
144
|
+
return {
|
|
145
|
+
data: version.data,
|
|
146
|
+
mediaType: version.mediaType,
|
|
147
|
+
ref: version.attachment,
|
|
148
|
+
};
|
|
139
149
|
}
|
|
140
150
|
catch (error) {
|
|
141
151
|
// A host that cannot derive request images keeps sending the stored bytes, as before.
|
|
@@ -144,11 +154,20 @@ export async function resolveImages(messages, attachments, signal, limit) {
|
|
|
144
154
|
}
|
|
145
155
|
}
|
|
146
156
|
const stored = await attachments.readImage(ref, signal);
|
|
147
|
-
return {
|
|
157
|
+
return {
|
|
158
|
+
data: stored.data,
|
|
159
|
+
mediaType: stored.ref.mediaType,
|
|
160
|
+
ref: stored.ref,
|
|
161
|
+
};
|
|
148
162
|
};
|
|
149
163
|
const resolveBlock = async (block) => {
|
|
150
164
|
if (block.type === 'tool-result') {
|
|
151
|
-
return [
|
|
165
|
+
return [
|
|
166
|
+
{
|
|
167
|
+
...block,
|
|
168
|
+
content: (await Promise.all(block.content.map(resolveBlock))).flat(),
|
|
169
|
+
},
|
|
170
|
+
];
|
|
152
171
|
}
|
|
153
172
|
if (block.type !== 'image' || 'dataBase64' in block)
|
|
154
173
|
return [block];
|
|
@@ -156,26 +175,41 @@ export async function resolveImages(messages, attachments, signal, limit) {
|
|
|
156
175
|
// The host owns omission decisions. Never restore offloaded bytes, even
|
|
157
176
|
// when the original attachment is unreadable or no store is mounted.
|
|
158
177
|
const format = llm.offloadedImageText;
|
|
159
|
-
return [
|
|
160
|
-
|
|
178
|
+
return [
|
|
179
|
+
{
|
|
180
|
+
type: 'text',
|
|
181
|
+
text: format?.(block.attachment) ??
|
|
182
|
+
`[image omitted to fit request image limits; ${block.attachment.attachmentId}]`,
|
|
183
|
+
},
|
|
184
|
+
];
|
|
161
185
|
}
|
|
162
|
-
const { data, mediaType: sentType, ref } = await readForRequest(block.attachment);
|
|
186
|
+
const { data, mediaType: sentType, ref, } = await readForRequest(block.attachment);
|
|
163
187
|
const { attachmentId, mediaType, bytes, width, height, name } = ref;
|
|
164
|
-
return [
|
|
188
|
+
return [
|
|
189
|
+
{
|
|
165
190
|
type: 'image',
|
|
166
191
|
mediaType: sentType,
|
|
167
192
|
dataBase64: Buffer.from(data).toString('base64'),
|
|
168
|
-
},
|
|
193
|
+
},
|
|
194
|
+
{
|
|
169
195
|
type: 'text',
|
|
170
196
|
text: `Image reference (for image_generate.referenceImages): ${JSON.stringify({
|
|
171
|
-
attachmentId,
|
|
197
|
+
attachmentId,
|
|
198
|
+
mediaType,
|
|
199
|
+
bytes,
|
|
200
|
+
width,
|
|
201
|
+
height,
|
|
202
|
+
...(name === undefined ? {} : { name }),
|
|
172
203
|
})}`,
|
|
173
|
-
}
|
|
204
|
+
},
|
|
205
|
+
];
|
|
174
206
|
};
|
|
175
207
|
return Promise.all(messages.map(async (message) => ({
|
|
176
208
|
role: message.role,
|
|
177
|
-
...message.source === undefined ? {} : { source: message.source },
|
|
178
|
-
...message.role === 'tool'
|
|
209
|
+
...(message.source === undefined ? {} : { source: message.source }),
|
|
210
|
+
...(message.role === 'tool'
|
|
211
|
+
? { toolCallId: message.toolCallId, isError: message.isError }
|
|
212
|
+
: {}),
|
|
179
213
|
content: (await Promise.all(message.content.map(resolveBlock))).flat(),
|
|
180
214
|
})));
|
|
181
215
|
}
|
|
@@ -10,7 +10,9 @@ import { parseSse } from './sse.js';
|
|
|
10
10
|
import { withToolResultImages } from './resolved.js';
|
|
11
11
|
/** Flatten a tool result's content to plain text for `function_call_output`. */
|
|
12
12
|
function toolResultText(block) {
|
|
13
|
-
return block.content
|
|
13
|
+
return block.content
|
|
14
|
+
.map((part) => (part.type === 'text' ? part.text : ''))
|
|
15
|
+
.join('');
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Convert harness messages into Responses `instructions` + `input` items.
|
|
@@ -49,14 +51,19 @@ export function toResponsesInput(messages, system, reasoningFor) {
|
|
|
49
51
|
// Current harness tool results are first-class role=tool messages.
|
|
50
52
|
// Responses represents their text as function_call_output items.
|
|
51
53
|
if (message.role === 'tool') {
|
|
52
|
-
const callId = message.toolCallId ??
|
|
53
|
-
|
|
54
|
+
const callId = message.toolCallId ??
|
|
55
|
+
message.tool_call_id ??
|
|
56
|
+
(message.source?.kind === 'tool'
|
|
57
|
+
? String(message.source.callId)
|
|
58
|
+
: undefined);
|
|
54
59
|
if (callId === undefined)
|
|
55
60
|
throw new LlmError('tool result has no call id', 'INVALID_REQUEST');
|
|
56
61
|
input.push({
|
|
57
62
|
type: 'function_call_output',
|
|
58
63
|
call_id: callId,
|
|
59
|
-
output: message.content
|
|
64
|
+
output: message.content
|
|
65
|
+
.map((block) => (block.type === 'text' ? block.text : ''))
|
|
66
|
+
.join(''),
|
|
60
67
|
});
|
|
61
68
|
continue;
|
|
62
69
|
}
|
|
@@ -71,7 +78,10 @@ export function toResponsesInput(messages, system, reasoningFor) {
|
|
|
71
78
|
for (const block of message.content) {
|
|
72
79
|
switch (block.type) {
|
|
73
80
|
case 'text':
|
|
74
|
-
content.push({
|
|
81
|
+
content.push({
|
|
82
|
+
type: role === 'assistant' ? 'output_text' : 'input_text',
|
|
83
|
+
text: block.text,
|
|
84
|
+
});
|
|
75
85
|
break;
|
|
76
86
|
case 'tool-call': {
|
|
77
87
|
flushMessage();
|
|
@@ -80,9 +90,11 @@ export function toResponsesInput(messages, system, reasoningFor) {
|
|
|
80
90
|
for (const item of encrypted) {
|
|
81
91
|
input.push({
|
|
82
92
|
type: 'reasoning',
|
|
83
|
-
...item.id === undefined ? {} : { id: item.id },
|
|
84
|
-
...item.summary === undefined
|
|
85
|
-
|
|
93
|
+
...(item.id === undefined ? {} : { id: item.id }),
|
|
94
|
+
...(item.summary === undefined
|
|
95
|
+
? {}
|
|
96
|
+
: { summary: item.summary }),
|
|
97
|
+
...(item.status === undefined ? {} : { status: item.status }),
|
|
86
98
|
encrypted_content: item.encrypted_content,
|
|
87
99
|
});
|
|
88
100
|
}
|
|
@@ -123,7 +135,7 @@ export function toResponsesInput(messages, system, reasoningFor) {
|
|
|
123
135
|
flushMessage();
|
|
124
136
|
}
|
|
125
137
|
const instructions = system ?? (systemTexts.length > 0 ? systemTexts.join('\n\n') : undefined);
|
|
126
|
-
return { ...instructions === undefined ? {} : { instructions }, input };
|
|
138
|
+
return { ...(instructions === undefined ? {} : { instructions }), input };
|
|
127
139
|
}
|
|
128
140
|
/**
|
|
129
141
|
* Map harness tool schemas to Responses function tools.
|
|
@@ -137,12 +149,12 @@ export function toResponsesInput(messages, system, reasoningFor) {
|
|
|
137
149
|
* @returns Responses `tools` array entries.
|
|
138
150
|
*/
|
|
139
151
|
export function toResponsesTools(tools, options = {}) {
|
|
140
|
-
return tools.map(tool => ({
|
|
152
|
+
return tools.map((tool) => ({
|
|
141
153
|
type: 'function',
|
|
142
154
|
name: tool.name,
|
|
143
155
|
description: tool.description,
|
|
144
156
|
parameters: tool.parameters,
|
|
145
|
-
...options.strict === undefined ? {} : { strict: options.strict },
|
|
157
|
+
...(options.strict === undefined ? {} : { strict: options.strict }),
|
|
146
158
|
}));
|
|
147
159
|
}
|
|
148
160
|
/**
|
|
@@ -157,8 +169,8 @@ export function mapResponsesUsage(usage) {
|
|
|
157
169
|
return {
|
|
158
170
|
inputTokens: usage.input_tokens - (cached ?? 0),
|
|
159
171
|
outputTokens: usage.output_tokens,
|
|
160
|
-
...cached !== undefined ? { cacheReadTokens: cached } : {},
|
|
161
|
-
...reasoning !== undefined ? { reasoningTokens: reasoning } : {},
|
|
172
|
+
...(cached !== undefined ? { cacheReadTokens: cached } : {}),
|
|
173
|
+
...(reasoning !== undefined ? { reasoningTokens: reasoning } : {}),
|
|
162
174
|
};
|
|
163
175
|
}
|
|
164
176
|
/**
|
|
@@ -172,10 +184,12 @@ export function responsesFailure(code, message) {
|
|
|
172
184
|
// not that no secret can exist anywhere. Raw values remain local classification inputs.
|
|
173
185
|
const detail = `${code ?? ''} ${message ?? ''}`;
|
|
174
186
|
let classification = 'SERVER';
|
|
175
|
-
if (code === 'context_window_exceeded' ||
|
|
187
|
+
if (code === 'context_window_exceeded' ||
|
|
188
|
+
isContextWindowExceededError(detail)) {
|
|
176
189
|
classification = CONTEXT_WINDOW_EXCEEDED_CODE;
|
|
177
190
|
}
|
|
178
|
-
else if ((code !== undefined && /insufficient|quota/i.test(code)) ||
|
|
191
|
+
else if ((code !== undefined && /insufficient|quota/i.test(code)) ||
|
|
192
|
+
isQuotaExceededError(detail)) {
|
|
179
193
|
classification = QUOTA_EXCEEDED_CODE;
|
|
180
194
|
}
|
|
181
195
|
return new LlmError(`Responses failure (${classification}): [provider response body omitted]`, classification);
|
|
@@ -216,7 +230,7 @@ export class ResponsesStreamTranslator {
|
|
|
216
230
|
kind,
|
|
217
231
|
text: '',
|
|
218
232
|
callId,
|
|
219
|
-
...name === undefined ? {} : { name },
|
|
233
|
+
...(name === undefined ? {} : { name }),
|
|
220
234
|
};
|
|
221
235
|
this.blocks.set(key, block);
|
|
222
236
|
this.order.push(block);
|
|
@@ -234,7 +248,11 @@ export class ResponsesStreamTranslator {
|
|
|
234
248
|
if (block === undefined)
|
|
235
249
|
return;
|
|
236
250
|
this.blocks.delete(key);
|
|
237
|
-
chunks.push({
|
|
251
|
+
chunks.push({
|
|
252
|
+
type: 'block-end',
|
|
253
|
+
index: block.index,
|
|
254
|
+
block: closeBlock(block),
|
|
255
|
+
});
|
|
238
256
|
}
|
|
239
257
|
/** Close every still-open block for one output item (prefix match on the key). */
|
|
240
258
|
closeItem(itemId, chunks) {
|
|
@@ -252,7 +270,11 @@ export class ResponsesStreamTranslator {
|
|
|
252
270
|
for (const [key, candidate] of this.blocks) {
|
|
253
271
|
if (candidate === block) {
|
|
254
272
|
this.blocks.delete(key);
|
|
255
|
-
chunks.push({
|
|
273
|
+
chunks.push({
|
|
274
|
+
type: 'block-end',
|
|
275
|
+
index: block.index,
|
|
276
|
+
block: closeBlock(block),
|
|
277
|
+
});
|
|
256
278
|
return;
|
|
257
279
|
}
|
|
258
280
|
}
|
|
@@ -277,7 +299,7 @@ export class ResponsesStreamTranslator {
|
|
|
277
299
|
type: 'tool-call-delta',
|
|
278
300
|
index: block.index,
|
|
279
301
|
id: ToolCallId(callId),
|
|
280
|
-
...item.name === undefined ? {} : { name: item.name },
|
|
302
|
+
...(item.name === undefined ? {} : { name: item.name }),
|
|
281
303
|
argumentsDelta: '',
|
|
282
304
|
});
|
|
283
305
|
}
|
|
@@ -287,7 +309,11 @@ export class ResponsesStreamTranslator {
|
|
|
287
309
|
const key = `${event.item_id ?? ''}:text:${String(event.content_index ?? 0)}`;
|
|
288
310
|
const block = this.textBlock(key, chunks);
|
|
289
311
|
block.text += event.delta ?? '';
|
|
290
|
-
chunks.push({
|
|
312
|
+
chunks.push({
|
|
313
|
+
type: 'text-delta',
|
|
314
|
+
index: block.index,
|
|
315
|
+
text: event.delta ?? '',
|
|
316
|
+
});
|
|
291
317
|
return chunks;
|
|
292
318
|
}
|
|
293
319
|
case 'response.reasoning_summary_text.delta':
|
|
@@ -296,7 +322,11 @@ export class ResponsesStreamTranslator {
|
|
|
296
322
|
const key = `${event.item_id ?? ''}:reason:${String(sub)}`;
|
|
297
323
|
const block = this.reasoningBlock(key, chunks);
|
|
298
324
|
block.text += event.delta ?? '';
|
|
299
|
-
chunks.push({
|
|
325
|
+
chunks.push({
|
|
326
|
+
type: 'reasoning-delta',
|
|
327
|
+
index: block.index,
|
|
328
|
+
text: event.delta ?? '',
|
|
329
|
+
});
|
|
300
330
|
return chunks;
|
|
301
331
|
}
|
|
302
332
|
case 'response.function_call_arguments.delta': {
|
|
@@ -312,7 +342,7 @@ export class ResponsesStreamTranslator {
|
|
|
312
342
|
type: 'tool-call-delta',
|
|
313
343
|
index: block.index,
|
|
314
344
|
id: ToolCallId(block.callId),
|
|
315
|
-
...block.name === undefined ? {} : { name: block.name },
|
|
345
|
+
...(block.name === undefined ? {} : { name: block.name }),
|
|
316
346
|
argumentsDelta: event.delta ?? '',
|
|
317
347
|
});
|
|
318
348
|
return chunks;
|
|
@@ -325,16 +355,20 @@ export class ResponsesStreamTranslator {
|
|
|
325
355
|
const key = `${item.id}:call`;
|
|
326
356
|
// The provider may deliver the complete arguments only on done.
|
|
327
357
|
const block = this.blocks.get(key);
|
|
328
|
-
if (block !== undefined &&
|
|
358
|
+
if (block !== undefined &&
|
|
359
|
+
block.text.length === 0 &&
|
|
360
|
+
item.arguments !== undefined) {
|
|
329
361
|
block.text = item.arguments;
|
|
330
362
|
}
|
|
331
363
|
this.close(key, chunks);
|
|
332
364
|
}
|
|
333
365
|
else if (item.type === 'message') {
|
|
334
|
-
if (![...this.blocks.keys()].some(key => key.startsWith(`${item.id}:text:`))) {
|
|
366
|
+
if (![...this.blocks.keys()].some((key) => key.startsWith(`${item.id}:text:`))) {
|
|
335
367
|
// No deltas arrived for this item; synthesize blocks from the done payload.
|
|
336
368
|
for (const [partIndex, part] of (item.content ?? []).entries()) {
|
|
337
|
-
if (part?.type !== 'output_text' ||
|
|
369
|
+
if (part?.type !== 'output_text' ||
|
|
370
|
+
typeof part.text !== 'string' ||
|
|
371
|
+
part.text.length === 0)
|
|
338
372
|
continue;
|
|
339
373
|
const block = this.open(`${item.id}:text:${partIndex}`, 'text', chunks);
|
|
340
374
|
block.text = part.text;
|
|
@@ -359,20 +393,26 @@ export class ResponsesStreamTranslator {
|
|
|
359
393
|
type: 'finish',
|
|
360
394
|
reason: {
|
|
361
395
|
kind: 'error',
|
|
362
|
-
failure: {
|
|
396
|
+
failure: {
|
|
397
|
+
message: 'model returned a completed response with no content',
|
|
398
|
+
code: EMPTY_RESPONSE_CODE,
|
|
399
|
+
},
|
|
363
400
|
},
|
|
364
401
|
});
|
|
365
402
|
}
|
|
366
403
|
else {
|
|
367
|
-
chunks.push({
|
|
404
|
+
chunks.push({
|
|
405
|
+
type: 'finish',
|
|
406
|
+
reason: { kind: this.sawToolCall ? 'tool-calls' : 'stop' },
|
|
407
|
+
});
|
|
368
408
|
}
|
|
369
409
|
return chunks;
|
|
370
410
|
}
|
|
371
411
|
case 'response.failed':
|
|
372
412
|
throw responsesFailure(event.response?.error?.code, event.response?.error?.message);
|
|
373
413
|
case 'response.incomplete':
|
|
374
|
-
throw responsesFailure(event.response?.incomplete_details?.reason, event.response?.error?.message
|
|
375
|
-
|
|
414
|
+
throw responsesFailure(event.response?.incomplete_details?.reason, event.response?.error?.message ??
|
|
415
|
+
`the provider reported an incomplete response (${event.response?.incomplete_details?.reason ?? 'unknown reason'})`);
|
|
376
416
|
case 'error':
|
|
377
417
|
throw responsesFailure(event.code, event.message);
|
|
378
418
|
default:
|
package/lib/translate/sse.js
CHANGED
|
@@ -33,7 +33,10 @@ export async function* parseSse(stream, onActivity) {
|
|
|
33
33
|
line = line.slice(0, -1);
|
|
34
34
|
if (line.length === 0) {
|
|
35
35
|
if (dataLines.length > 0) {
|
|
36
|
-
yield {
|
|
36
|
+
yield {
|
|
37
|
+
data: dataLines.join('\n'),
|
|
38
|
+
...(eventName === undefined ? {} : { event: eventName }),
|
|
39
|
+
};
|
|
37
40
|
}
|
|
38
41
|
dataLines = [];
|
|
39
42
|
eventName = undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-subscriptions",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Unified subscription providers and usage dashboard for DeepSeek Harness",
|
|
5
5
|
"icon": "./icon.svg",
|
|
6
6
|
"license": "MIT",
|
|
@@ -71,8 +71,12 @@
|
|
|
71
71
|
"build": "tsc && tsdown",
|
|
72
72
|
"test": "tsc -p tsconfig.test.json && node --import ./test/hermetic.mjs --test \"lib-test/test/**/*.spec.js\"",
|
|
73
73
|
"test:mutation": "stryker run",
|
|
74
|
-
"prepare": "tsdown -c tsdown.prepare.config.ts",
|
|
75
|
-
"prepublishOnly": "pnpm build && pnpm test"
|
|
74
|
+
"prepare": "node scripts/install-dev-hooks.mjs && tsdown -c tsdown.prepare.config.ts",
|
|
75
|
+
"prepublishOnly": "pnpm build && pnpm test",
|
|
76
|
+
"format": "prettier --write .",
|
|
77
|
+
"format:check": "prettier --check .",
|
|
78
|
+
"lint": "eslint . --max-warnings 0",
|
|
79
|
+
"lint:fix": "eslint . --fix --max-warnings 0"
|
|
76
80
|
},
|
|
77
81
|
"peerDependencies": {
|
|
78
82
|
"@deepseek-ai/cordis": "~4.0.4",
|
|
@@ -102,17 +106,35 @@
|
|
|
102
106
|
"@deepseek-ai/dsh-tools": "0.1.7-rc.2",
|
|
103
107
|
"@deepseek-ai/dsh-web": "0.1.7-rc.2",
|
|
104
108
|
"@deepseek-ai/schemastery": "3.18.4",
|
|
109
|
+
"@eslint/js": "^10.0.1",
|
|
105
110
|
"@stryker-mutator/core": "^10.0.0",
|
|
106
111
|
"@types/node": "^24.0.0",
|
|
107
112
|
"@types/react": "~18.3.1",
|
|
108
113
|
"@types/react-dom": "~18.3.7",
|
|
114
|
+
"eslint": "^10.13.0",
|
|
115
|
+
"eslint-config-prettier": "^10.1.8",
|
|
116
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
109
117
|
"fast-check": "^4.10.2",
|
|
118
|
+
"globals": "^17.13.0",
|
|
119
|
+
"husky": "^9.1.7",
|
|
120
|
+
"lint-staged": "^17.6.0",
|
|
121
|
+
"prettier": "^3.9.10",
|
|
110
122
|
"react": "^18.2.0",
|
|
111
123
|
"react-dom": "^18.2.0",
|
|
112
124
|
"tsdown": "^0.15.0",
|
|
113
|
-
"typescript": "^5.8.0"
|
|
125
|
+
"typescript": "^5.8.0",
|
|
126
|
+
"typescript-eslint": "^8.71.2"
|
|
114
127
|
},
|
|
115
128
|
"publishConfig": {
|
|
116
129
|
"access": "public"
|
|
130
|
+
},
|
|
131
|
+
"lint-staged": {
|
|
132
|
+
"*.{js,mjs,cjs,ts,tsx}": [
|
|
133
|
+
"eslint --fix --max-warnings 0 --no-warn-ignored",
|
|
134
|
+
"prettier --write"
|
|
135
|
+
],
|
|
136
|
+
"*.{json,yml,yaml,css,md}": [
|
|
137
|
+
"prettier --write"
|
|
138
|
+
]
|
|
117
139
|
}
|
|
118
140
|
}
|