@goodandready/dsh-subscriptions 0.6.20 → 0.6.21
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/lib/adapter.js +5 -4
- package/lib/messages.js +221 -45
- package/lib/vendors/codex.js +5 -1
- package/package.json +1 -1
package/lib/adapter.js
CHANGED
|
@@ -43,15 +43,16 @@ export class SubscriptionAdapter extends LlmAdapter {
|
|
|
43
43
|
|
|
44
44
|
async listModels(provider) {
|
|
45
45
|
const accounts = await this.deps.listAccounts(provider)
|
|
46
|
-
|
|
46
|
+
const targetAccount = accounts.find((a) => a.hasToken)
|
|
47
|
+
if (!targetAccount) return []
|
|
47
48
|
const cfg = this.deps.vendorConfig(provider)
|
|
48
|
-
const fetchImpl = this.deps.
|
|
49
|
+
const fetchImpl = pickFetch(this.deps, targetAccount.ref)
|
|
49
50
|
let models = null
|
|
50
51
|
try {
|
|
51
52
|
const blob = await this.deps.ensureFresh(
|
|
52
53
|
provider,
|
|
53
|
-
await this.deps.loadBlob(
|
|
54
|
-
|
|
54
|
+
await this.deps.loadBlob(targetAccount.ref),
|
|
55
|
+
targetAccount.ref,
|
|
55
56
|
)
|
|
56
57
|
const live = await getVendor(provider).listModels(blob, cfg, fetchImpl)
|
|
57
58
|
if (Array.isArray(live) && live.length) models = live
|
package/lib/messages.js
CHANGED
|
@@ -10,11 +10,13 @@ function flattenText(content) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
function toolResults(content) {
|
|
13
|
-
|
|
13
|
+
if (!Array.isArray(content)) return []
|
|
14
|
+
return content.filter((b) => b && (b.type === 'tool-result' || b.type === 'tool_result' || b.type === 'function_call_output'))
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
function toolCalls(content) {
|
|
17
|
-
|
|
18
|
+
if (!Array.isArray(content)) return []
|
|
19
|
+
return content.filter((b) => b && (b.type === 'tool-call' || b.type === 'tool_use' || b.type === 'function_call'))
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export function openaiMessages(options) {
|
|
@@ -26,11 +28,21 @@ export function openaiMessages(options) {
|
|
|
26
28
|
continue
|
|
27
29
|
}
|
|
28
30
|
if (message.role === 'assistant') {
|
|
29
|
-
const calls =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const calls = [
|
|
32
|
+
...toolCalls(message.content).map((block) => ({
|
|
33
|
+
id: block.id,
|
|
34
|
+
type: 'function',
|
|
35
|
+
function: { name: block.name, arguments: block.arguments || '{}' },
|
|
36
|
+
})),
|
|
37
|
+
...((message.tool_calls || message.toolCalls || []).map((c) => ({
|
|
38
|
+
id: c.id || c.call_id,
|
|
39
|
+
type: 'function',
|
|
40
|
+
function: {
|
|
41
|
+
name: c.name || (c.function && c.function.name),
|
|
42
|
+
arguments: typeof c.arguments === 'string' ? c.arguments : (c.function && c.function.arguments) || '{}',
|
|
43
|
+
},
|
|
44
|
+
}))),
|
|
45
|
+
]
|
|
34
46
|
out.push({
|
|
35
47
|
role: 'assistant',
|
|
36
48
|
content: flattenText(message.content) || (calls.length ? null : ''),
|
|
@@ -38,14 +50,26 @@ export function openaiMessages(options) {
|
|
|
38
50
|
})
|
|
39
51
|
continue
|
|
40
52
|
}
|
|
53
|
+
if (message.role === 'tool') {
|
|
54
|
+
const toolCallId = String(message.toolCallId || message.tool_call_id || message.call_id || message.id || '')
|
|
55
|
+
const content = typeof message.content === 'string'
|
|
56
|
+
? message.content
|
|
57
|
+
: (flattenText(message.content) || JSON.stringify(message.content || ''))
|
|
58
|
+
out.push({
|
|
59
|
+
role: 'tool',
|
|
60
|
+
tool_call_id: toolCallId,
|
|
61
|
+
content: content || '(no output)',
|
|
62
|
+
})
|
|
63
|
+
continue
|
|
64
|
+
}
|
|
41
65
|
const results = toolResults(message.content)
|
|
42
66
|
const text = flattenText(message.content)
|
|
43
67
|
if (text || !results.length) out.push({ role: 'user', content: text })
|
|
44
68
|
for (const result of results) {
|
|
45
69
|
out.push({
|
|
46
70
|
role: 'tool',
|
|
47
|
-
tool_call_id: result.toolCallId,
|
|
48
|
-
content: flattenText(result.content) || '(no output)',
|
|
71
|
+
tool_call_id: String(result.toolCallId || result.tool_call_id || result.call_id || result.id || ''),
|
|
72
|
+
content: typeof result.content === 'string' ? result.content : (flattenText(result.content) || '(no output)'),
|
|
49
73
|
})
|
|
50
74
|
}
|
|
51
75
|
}
|
|
@@ -65,16 +89,74 @@ export function openaiTools(options) {
|
|
|
65
89
|
}))
|
|
66
90
|
}
|
|
67
91
|
|
|
92
|
+
export function reconcileResponsesInput(items) {
|
|
93
|
+
const result = []
|
|
94
|
+
const callsSeen = new Set()
|
|
95
|
+
const outputsSeen = new Set()
|
|
96
|
+
|
|
97
|
+
for (const it of items) {
|
|
98
|
+
if (it && it.type === 'function_call_output' && it.call_id) {
|
|
99
|
+
outputsSeen.add(it.call_id)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const pendingCalls = []
|
|
104
|
+
for (const it of items) {
|
|
105
|
+
if (!it) continue
|
|
106
|
+
if (it.type === 'function_call') {
|
|
107
|
+
if (it.call_id) {
|
|
108
|
+
callsSeen.add(it.call_id)
|
|
109
|
+
if (!outputsSeen.has(it.call_id)) {
|
|
110
|
+
pendingCalls.push(it.call_id)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
result.push(it)
|
|
114
|
+
continue
|
|
115
|
+
}
|
|
116
|
+
if (it.type === 'function_call_output') {
|
|
117
|
+
// Drop orphan output if no matching preceding call
|
|
118
|
+
if (it.call_id && callsSeen.has(it.call_id)) {
|
|
119
|
+
result.push(it)
|
|
120
|
+
}
|
|
121
|
+
continue
|
|
122
|
+
}
|
|
123
|
+
// Flush synthetic outputs for any calls that did not get output before user/assistant turn
|
|
124
|
+
while (pendingCalls.length) {
|
|
125
|
+
const orphanId = pendingCalls.shift()
|
|
126
|
+
result.push({
|
|
127
|
+
type: 'function_call_output',
|
|
128
|
+
call_id: orphanId,
|
|
129
|
+
output: '{"status":"interrupted"}',
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
result.push(it)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
while (pendingCalls.length) {
|
|
136
|
+
const orphanId = pendingCalls.shift()
|
|
137
|
+
result.push({
|
|
138
|
+
type: 'function_call_output',
|
|
139
|
+
call_id: orphanId,
|
|
140
|
+
output: '{"status":"interrupted"}',
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!result.length) {
|
|
145
|
+
result.push({ role: 'user', content: [{ type: 'input_text', text: '' }] })
|
|
146
|
+
}
|
|
147
|
+
return result
|
|
148
|
+
}
|
|
149
|
+
|
|
68
150
|
export function codexResponsesBody(options, fallbackInstructions, vendorCfg) {
|
|
69
151
|
const systemParts = []
|
|
70
152
|
if (options.system) systemParts.push(options.system)
|
|
71
|
-
const
|
|
153
|
+
const rawInput = []
|
|
72
154
|
let pendingRole = null
|
|
73
155
|
let pendingContent = []
|
|
74
156
|
function flush() {
|
|
75
157
|
if (!pendingRole) return
|
|
76
158
|
const type = pendingRole === 'assistant' ? 'output_text' : 'input_text'
|
|
77
|
-
|
|
159
|
+
rawInput.push({
|
|
78
160
|
role: pendingRole,
|
|
79
161
|
content: pendingContent.length ? pendingContent : [{ type, text: '' }],
|
|
80
162
|
})
|
|
@@ -95,30 +177,61 @@ export function codexResponsesBody(options, fallbackInstructions, vendorCfg) {
|
|
|
95
177
|
if (message.role === 'assistant') {
|
|
96
178
|
const text = flattenText(message.content)
|
|
97
179
|
if (text) addText('assistant', text)
|
|
98
|
-
|
|
180
|
+
const calls = [
|
|
181
|
+
...toolCalls(message.content),
|
|
182
|
+
...((message.tool_calls || message.toolCalls || []).map((c) => ({
|
|
183
|
+
id: c.id || c.call_id,
|
|
184
|
+
name: c.name || (c.function && c.function.name),
|
|
185
|
+
arguments: typeof c.arguments === 'string' ? c.arguments : (c.function && c.function.arguments) || c.arguments || '{}',
|
|
186
|
+
}))),
|
|
187
|
+
]
|
|
188
|
+
for (const call of calls) {
|
|
189
|
+
if (!call.id) continue
|
|
99
190
|
flush()
|
|
100
|
-
|
|
191
|
+
rawInput.push({
|
|
101
192
|
type: 'function_call',
|
|
102
|
-
call_id: String(call.id
|
|
193
|
+
call_id: String(call.id),
|
|
103
194
|
name: call.name,
|
|
104
195
|
arguments: typeof call.arguments === 'string' ? call.arguments : JSON.stringify(call.arguments || {}),
|
|
105
196
|
})
|
|
106
197
|
}
|
|
107
198
|
continue
|
|
108
199
|
}
|
|
200
|
+
if (message.role === 'tool') {
|
|
201
|
+
flush()
|
|
202
|
+
const callId = String(message.toolCallId || message.tool_call_id || message.call_id || message.id || '')
|
|
203
|
+
const outText = typeof message.content === 'string'
|
|
204
|
+
? message.content
|
|
205
|
+
: (flattenText(message.content) || JSON.stringify(message.content || ''))
|
|
206
|
+
if (callId) {
|
|
207
|
+
rawInput.push({
|
|
208
|
+
type: 'function_call_output',
|
|
209
|
+
call_id: callId,
|
|
210
|
+
output: outText,
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
continue
|
|
214
|
+
}
|
|
215
|
+
const results = toolResults(message.content)
|
|
109
216
|
const text = flattenText(message.content)
|
|
110
217
|
if (text) addText('user', text)
|
|
111
|
-
for (const result of
|
|
218
|
+
for (const result of results) {
|
|
112
219
|
flush()
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
220
|
+
const callId = String(result.toolCallId || result.tool_call_id || result.call_id || result.id || '')
|
|
221
|
+
const outText = typeof result.content === 'string'
|
|
222
|
+
? result.content
|
|
223
|
+
: (flattenText(result.content) || (result.output != null ? (typeof result.output === 'string' ? result.output : JSON.stringify(result.output)) : ''))
|
|
224
|
+
if (callId) {
|
|
225
|
+
rawInput.push({
|
|
226
|
+
type: 'function_call_output',
|
|
227
|
+
call_id: callId,
|
|
228
|
+
output: outText,
|
|
229
|
+
})
|
|
230
|
+
}
|
|
118
231
|
}
|
|
119
232
|
}
|
|
120
233
|
flush()
|
|
121
|
-
|
|
234
|
+
const input = reconcileResponsesInput(rawInput)
|
|
122
235
|
const tools = openaiTools(options)
|
|
123
236
|
const responsesTools = tools && tools.map((tool) => ({
|
|
124
237
|
type: 'function',
|
|
@@ -160,7 +273,16 @@ export function anthropicPayload(options, extraSystem) {
|
|
|
160
273
|
const blocks = []
|
|
161
274
|
const text = flattenText(message.content)
|
|
162
275
|
if (text) blocks.push({ type: 'text', text })
|
|
163
|
-
|
|
276
|
+
const calls = [
|
|
277
|
+
...toolCalls(message.content),
|
|
278
|
+
...((message.tool_calls || message.toolCalls || []).map((c) => ({
|
|
279
|
+
id: c.id || c.call_id,
|
|
280
|
+
name: c.name || (c.function && c.function.name),
|
|
281
|
+
arguments: c.arguments || (c.function && c.function.arguments) || '{}',
|
|
282
|
+
}))),
|
|
283
|
+
]
|
|
284
|
+
for (const call of calls) {
|
|
285
|
+
if (!call.id) continue
|
|
164
286
|
blocks.push({
|
|
165
287
|
type: 'tool_use',
|
|
166
288
|
id: call.id,
|
|
@@ -171,14 +293,33 @@ export function anthropicPayload(options, extraSystem) {
|
|
|
171
293
|
messages.push({ role: 'assistant', content: blocks.length ? blocks : [{ type: 'text', text: '' }] })
|
|
172
294
|
continue
|
|
173
295
|
}
|
|
296
|
+
if (message.role === 'tool') {
|
|
297
|
+
const toolUseId = String(message.toolCallId || message.tool_call_id || message.tool_use_id || message.id || '')
|
|
298
|
+
const content = typeof message.content === 'string'
|
|
299
|
+
? message.content
|
|
300
|
+
: (flattenText(message.content) || JSON.stringify(message.content || ''))
|
|
301
|
+
messages.push({
|
|
302
|
+
role: 'user',
|
|
303
|
+
content: [{
|
|
304
|
+
type: 'tool_result',
|
|
305
|
+
tool_use_id: toolUseId,
|
|
306
|
+
content: content || '',
|
|
307
|
+
}],
|
|
308
|
+
})
|
|
309
|
+
continue
|
|
310
|
+
}
|
|
174
311
|
const blocks = []
|
|
175
312
|
const text = flattenText(message.content)
|
|
176
313
|
if (text) blocks.push({ type: 'text', text })
|
|
177
314
|
for (const result of toolResults(message.content)) {
|
|
315
|
+
const toolUseId = String(result.toolCallId || result.tool_call_id || result.tool_use_id || result.id || '')
|
|
316
|
+
const content = typeof result.content === 'string'
|
|
317
|
+
? result.content
|
|
318
|
+
: (flattenText(result.content) || (result.output != null ? (typeof result.output === 'string' ? result.output : JSON.stringify(result.output)) : ''))
|
|
178
319
|
blocks.push({
|
|
179
320
|
type: 'tool_result',
|
|
180
|
-
tool_use_id:
|
|
181
|
-
content:
|
|
321
|
+
tool_use_id: toolUseId,
|
|
322
|
+
content: content || '',
|
|
182
323
|
})
|
|
183
324
|
}
|
|
184
325
|
messages.push({ role: 'user', content: blocks.length ? blocks : [{ type: 'text', text: '' }] })
|
|
@@ -210,18 +351,45 @@ export function googleContents(options) {
|
|
|
210
351
|
systemParts.push({ text: flattenText(message.content) })
|
|
211
352
|
continue
|
|
212
353
|
}
|
|
354
|
+
if (message.role === 'tool') {
|
|
355
|
+
const name = message.toolName || message.name || 'tool'
|
|
356
|
+
const output = typeof message.content === 'string'
|
|
357
|
+
? message.content
|
|
358
|
+
: (flattenText(message.content) || JSON.stringify(message.content || ''))
|
|
359
|
+
contents.push({
|
|
360
|
+
role: 'user',
|
|
361
|
+
parts: [{
|
|
362
|
+
functionResponse: {
|
|
363
|
+
name,
|
|
364
|
+
response: { output },
|
|
365
|
+
},
|
|
366
|
+
}],
|
|
367
|
+
})
|
|
368
|
+
continue
|
|
369
|
+
}
|
|
213
370
|
const role = message.role === 'assistant' ? 'model' : 'user'
|
|
214
371
|
const parts = []
|
|
215
372
|
const text = flattenText(message.content)
|
|
216
373
|
if (text) parts.push({ text })
|
|
217
|
-
|
|
374
|
+
const calls = [
|
|
375
|
+
...toolCalls(message.content),
|
|
376
|
+
...((message.tool_calls || message.toolCalls || []).map((c) => ({
|
|
377
|
+
name: c.name || (c.function && c.function.name),
|
|
378
|
+
arguments: c.arguments || (c.function && c.function.arguments) || '{}',
|
|
379
|
+
}))),
|
|
380
|
+
]
|
|
381
|
+
for (const call of calls) {
|
|
218
382
|
parts.push({ functionCall: { name: call.name, args: safeJson(call.arguments) } })
|
|
219
383
|
}
|
|
220
384
|
for (const result of toolResults(message.content)) {
|
|
385
|
+
const name = result.toolName || result.name || 'tool'
|
|
386
|
+
const output = typeof result.content === 'string'
|
|
387
|
+
? result.content
|
|
388
|
+
: (flattenText(result.content) || (result.output != null ? (typeof result.output === 'string' ? result.output : JSON.stringify(result.output)) : ''))
|
|
221
389
|
parts.push({
|
|
222
390
|
functionResponse: {
|
|
223
|
-
name
|
|
224
|
-
response: { output
|
|
391
|
+
name,
|
|
392
|
+
response: { output },
|
|
225
393
|
},
|
|
226
394
|
})
|
|
227
395
|
}
|
|
@@ -242,24 +410,32 @@ export function googleContents(options) {
|
|
|
242
410
|
}
|
|
243
411
|
|
|
244
412
|
function safeJson(text) {
|
|
245
|
-
if (
|
|
246
|
-
try { return JSON.parse(text
|
|
413
|
+
if (typeof text === 'object' && text !== null) return text
|
|
414
|
+
try { return JSON.parse(text) } catch { return {} }
|
|
247
415
|
}
|
|
248
416
|
|
|
249
|
-
export function modelCatalog(provider,
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if (
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
id,
|
|
258
|
-
name: entry.name || entry.display_name || id,
|
|
259
|
-
...(entry.description ? { description: entry.description } : {}),
|
|
260
|
-
...(entry.contextWindow ? { contextWindow: entry.contextWindow } : {}),
|
|
261
|
-
...(entry.inputModalities ? { inputModalities: entry.inputModalities } : {}),
|
|
262
|
-
...(entry.reasoning ? { reasoning: entry.reasoning } : {}),
|
|
417
|
+
export function modelCatalog(provider, list) {
|
|
418
|
+
if (!Array.isArray(list)) return []
|
|
419
|
+
const out = []
|
|
420
|
+
for (const entry of list) {
|
|
421
|
+
if (!entry) continue
|
|
422
|
+
if (typeof entry === 'string') {
|
|
423
|
+
out.push({ provider, id: entry, name: entry })
|
|
424
|
+
continue
|
|
263
425
|
}
|
|
264
|
-
|
|
265
|
-
|
|
426
|
+
if (typeof entry === 'object') {
|
|
427
|
+
const id = entry.id || entry.slug || entry.name
|
|
428
|
+
if (!id) continue
|
|
429
|
+
out.push({
|
|
430
|
+
provider,
|
|
431
|
+
id,
|
|
432
|
+
name: entry.name || entry.display_name || id,
|
|
433
|
+
...(entry.description ? { description: entry.description } : {}),
|
|
434
|
+
...(entry.contextWindow || entry.context_window ? { contextWindow: entry.contextWindow || entry.context_window } : {}),
|
|
435
|
+
...(entry.reasoning != null ? { reasoning: entry.reasoning } : {}),
|
|
436
|
+
...(entry.inputModalities || entry.input_modalities ? { inputModalities: entry.inputModalities || entry.input_modalities } : {}),
|
|
437
|
+
})
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return out
|
|
441
|
+
}
|
package/lib/vendors/codex.js
CHANGED
|
@@ -30,6 +30,9 @@ export function defaults() {
|
|
|
30
30
|
baseUrl: 'https://chatgpt.com/backend-api/codex',
|
|
31
31
|
originator: 'codex_cli_rs',
|
|
32
32
|
models: [
|
|
33
|
+
{ id: 'gpt-5.6-luna', name: 'GPT-5.6 Luna' },
|
|
34
|
+
{ id: 'gpt-5.3-codex', name: 'GPT-5.3 Codex' },
|
|
35
|
+
{ id: 'gpt-5.2-codex', name: 'GPT-5.2 Codex' },
|
|
33
36
|
{ id: 'gpt-5.1-codex', name: 'GPT-5.1 Codex' },
|
|
34
37
|
{ id: 'gpt-5.1-codex-mini', name: 'GPT-5.1 Codex Mini' },
|
|
35
38
|
{ id: 'gpt-5.1', name: 'GPT-5.1' },
|
|
@@ -141,7 +144,8 @@ export async function refresh(cfg, blob, fetchImpl) {
|
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
export async function listModels(blob, cfg, fetchImpl) {
|
|
144
|
-
const
|
|
147
|
+
const rawModels = (cfg && cfg.models && cfg.models.length) ? cfg.models : defaults().models
|
|
148
|
+
const catalog = modelCatalog(id, rawModels)
|
|
145
149
|
const impl = fetchImpl || fetch
|
|
146
150
|
try {
|
|
147
151
|
const base = (cfg.baseUrl || defaults().baseUrl).replace(/\/$/, '')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-subscriptions",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.21",
|
|
4
4
|
"description": "Use ChatGPT Codex, Claude, Grok, Antigravity, Kimi, GLM, Cursor, Kiro, Copilot, Qwen, ERNIE, Spark, JetBrains, Perplexity, Replit, and Cody subscriptions as DeepSeek Harness LLM providers via OAuth.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|