@goodandready/dsh-subscriptions 0.7.20 → 0.7.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-manager.js +1 -0
- package/lib/adapter.js +10 -1
- package/lib/images.js +32 -0
- package/lib/messages.js +11 -1
- package/lib/vendors/claude.js +9 -7
- package/package.json +1 -1
package/lib/adapter-manager.js
CHANGED
|
@@ -68,6 +68,7 @@ export function createAdapterManager({
|
|
|
68
68
|
recordHistory,
|
|
69
69
|
fetchImpl: fetch,
|
|
70
70
|
fetchForRef,
|
|
71
|
+
attachments: () => (typeof ctx.get === 'function' ? ctx.get('attachments') : null),
|
|
71
72
|
hideDeprecatedModels: () => Boolean(live().hideDeprecatedModels),
|
|
72
73
|
cascadingFallback: (...args) => cascadeFallbackStream(...args),
|
|
73
74
|
ollamaFallback: typeof ollamaFallback === 'function' ? ollamaFallback : async function* ({ err }) { yield { type: 'finish', reason: { kind: 'error', failure: { code: err?.code || 'RATE_LIMIT', message: err?.message || 'all subscription accounts exhausted' } } } },
|
package/lib/adapter.js
CHANGED
|
@@ -13,6 +13,7 @@ import { pickFetch } from './proxy.js'
|
|
|
13
13
|
import { quotaSnapshot, parseBody } from './ratelimit.js'
|
|
14
14
|
import { toTokenUsage } from './wire.js'
|
|
15
15
|
import { isSwitchableError } from './rotate.js'
|
|
16
|
+
import { hydrateAttachmentImages } from './images.js'
|
|
16
17
|
|
|
17
18
|
// #94: isDeprecatedId imported from ./models-catalog.js
|
|
18
19
|
|
|
@@ -156,8 +157,16 @@ export class SubscriptionAdapter extends LlmAdapter {
|
|
|
156
157
|
const sessionId = options.sessionId || options.session_id || options.conversationId
|
|
157
158
|
const effectiveReasoning = resolveEffectiveReasoning(sessionId, options)
|
|
158
159
|
const decisionTrace = {}
|
|
159
|
-
const
|
|
160
|
+
const hydratedOptions = {
|
|
160
161
|
...options,
|
|
162
|
+
messages: await hydrateAttachmentImages(
|
|
163
|
+
options.messages,
|
|
164
|
+
typeof deps.attachments === 'function' ? deps.attachments() : null,
|
|
165
|
+
options.signal,
|
|
166
|
+
),
|
|
167
|
+
}
|
|
168
|
+
const streamOptions = {
|
|
169
|
+
...hydratedOptions,
|
|
161
170
|
...(provider === 'codex' && getSpeedMode(sessionId) === 'fast' ? { service_tier: 'priority' } : {}),
|
|
162
171
|
...(effectiveReasoning.effort ? { reasoningEffort: effectiveReasoning.effort } : {}),
|
|
163
172
|
...(effectiveReasoning.budgetTokens ? { thinkingBudget: effectiveReasoning.budgetTokens } : {}),
|
package/lib/images.js
CHANGED
|
@@ -174,6 +174,38 @@ export function normalizeImage(item) {
|
|
|
174
174
|
return null
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
export async function hydrateAttachmentImages(messages, attachments, signal) {
|
|
178
|
+
if (!attachments || typeof attachments.readImageRequest !== 'function' || !Array.isArray(messages)) return messages
|
|
179
|
+
return Promise.all(messages.map(async (message) => {
|
|
180
|
+
if (!message || !Array.isArray(message.content)) return message
|
|
181
|
+
const content = await Promise.all(message.content.map(async (block) => {
|
|
182
|
+
if (!block || block.type !== 'image' || !block.attachment) return block
|
|
183
|
+
try {
|
|
184
|
+
const ref = block.attachment
|
|
185
|
+
const version = await attachments.readImageRequest(ref, {
|
|
186
|
+
width: Number(ref.width) || 1568,
|
|
187
|
+
height: Number(ref.height) || 1568,
|
|
188
|
+
maxBytes: 5 * 1024 * 1024,
|
|
189
|
+
}, signal)
|
|
190
|
+
return {
|
|
191
|
+
type: 'image',
|
|
192
|
+
source: {
|
|
193
|
+
type: 'base64',
|
|
194
|
+
media_type: version.mediaType || ref.mediaType || 'image/jpeg',
|
|
195
|
+
data: Buffer.from(version.data).toString('base64'),
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
} catch {
|
|
199
|
+
return {
|
|
200
|
+
type: 'text',
|
|
201
|
+
text: '[image attachment unavailable: ' + String(block.attachment.attachmentId || block.attachment.name || 'unknown') + ']',
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}))
|
|
205
|
+
return { ...message, content }
|
|
206
|
+
}))
|
|
207
|
+
}
|
|
208
|
+
|
|
177
209
|
export function extractImages(content) {
|
|
178
210
|
if (!Array.isArray(content)) {
|
|
179
211
|
const norm = normalizeImage(content)
|
package/lib/messages.js
CHANGED
|
@@ -343,9 +343,19 @@ export function anthropicPayload(options, extraSystem) {
|
|
|
343
343
|
}
|
|
344
344
|
if (message.role === "tool") {
|
|
345
345
|
const toolUseId = String(message.toolCallId || message.tool_call_id || message.tool_use_id || message.id || "")
|
|
346
|
-
const
|
|
346
|
+
const images = extractImages(message.content)
|
|
347
|
+
let content = typeof message.content === "string"
|
|
347
348
|
? message.content
|
|
348
349
|
: (flattenText(message.content) || JSON.stringify(message.content || ""))
|
|
350
|
+
if (images.length) {
|
|
351
|
+
const blocks = []
|
|
352
|
+
if (content) blocks.push({ type: "text", text: content })
|
|
353
|
+
for (const img of images) {
|
|
354
|
+
const blk = toAnthropicImage(img)
|
|
355
|
+
if (blk) blocks.push(blk)
|
|
356
|
+
}
|
|
357
|
+
if (blocks.length) content = blocks
|
|
358
|
+
}
|
|
349
359
|
messages.push({
|
|
350
360
|
role: "user",
|
|
351
361
|
content: [{
|
package/lib/vendors/claude.js
CHANGED
|
@@ -73,10 +73,10 @@ export function defaults() {
|
|
|
73
73
|
redirectUri: 'https://console.anthropic.com/oauth/code/callback',
|
|
74
74
|
claudeCcVersion: '2.1.289.7e2',
|
|
75
75
|
models: [
|
|
76
|
-
{ id: 'claude-opus-5', name: 'Claude Opus 5' },
|
|
77
|
-
{ id: 'claude-sonnet-5', name: 'Claude Sonnet 5' },
|
|
78
|
-
{ id: 'claude-fable-5', name: 'Claude Fable 5' },
|
|
79
|
-
{ id: 'claude-haiku-4-5-20251001', name: 'Claude Haiku 4.5' },
|
|
76
|
+
{ id: 'claude-opus-5', name: 'Claude Opus 5', inputModalities: ['text', 'image'] },
|
|
77
|
+
{ id: 'claude-sonnet-5', name: 'Claude Sonnet 5', inputModalities: ['text', 'image'] },
|
|
78
|
+
{ id: 'claude-fable-5', name: 'Claude Fable 5', inputModalities: ['text', 'image'] },
|
|
79
|
+
{ id: 'claude-haiku-4-5-20251001', name: 'Claude Haiku 4.5', inputModalities: ['text', 'image'] },
|
|
80
80
|
],
|
|
81
81
|
systemPrefix: IDENTITY,
|
|
82
82
|
}
|
|
@@ -189,9 +189,10 @@ export async function listModels(blob, cfg, fetchImpl) {
|
|
|
189
189
|
const rawDefault = (cfg && cfg.models && cfg.models.length) ? cfg.models : defaults().models
|
|
190
190
|
const defaultCatalog = modelCatalog(id, rawDefault.map((entry) => {
|
|
191
191
|
const model = typeof entry === "string" ? { id: entry, name: entry } : { ...entry }
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
192
|
+
const withVision = { ...model, inputModalities: model.inputModalities || ['text', 'image'] }
|
|
193
|
+
const levels = effortLevelsForModel(withVision.id || withVision.name)
|
|
194
|
+
if (!levels) return withVision
|
|
195
|
+
return { ...withVision, reasoning: { efforts: levels.map((level) => ({ id: level, name: level })) } }
|
|
195
196
|
}))
|
|
196
197
|
|
|
197
198
|
if (!blob || !blob.accessToken) return defaultCatalog
|
|
@@ -223,6 +224,7 @@ export async function listModels(blob, cfg, fetchImpl) {
|
|
|
223
224
|
id: modelId,
|
|
224
225
|
name: item.display_name || modelId,
|
|
225
226
|
...(levels ? { reasoning: { efforts: levels.map((level) => ({ id: level, name: level })) } } : {}),
|
|
227
|
+
inputModalities: ['text', 'image'],
|
|
226
228
|
})
|
|
227
229
|
}
|
|
228
230
|
if (!rows.length) return defaultCatalog
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-subscriptions",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.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",
|