@opencompress/opencompress 1.3.0 → 1.4.0
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/dist/index.js +81 -43
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,40 +5,66 @@ function getApiKey(api) {
|
|
|
5
5
|
const auth = api.config.auth;
|
|
6
6
|
return auth?.profiles?.opencompress?.credentials?.["api-key"]?.apiKey;
|
|
7
7
|
}
|
|
8
|
-
var
|
|
9
|
-
|
|
10
|
-
{ id: "gpt-4o", name: "GPT-4o
|
|
11
|
-
{ id: "gpt-
|
|
12
|
-
{ id: "gpt-4.1", name: "GPT-4.1
|
|
13
|
-
{ id: "
|
|
14
|
-
{ id: "
|
|
15
|
-
{ id: "
|
|
16
|
-
{ id: "
|
|
17
|
-
|
|
18
|
-
{ id: "
|
|
19
|
-
{ id: "claude-opus-4-6", name: "Claude Opus 4.6 (Compressed)", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 128e3 },
|
|
20
|
-
{ id: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5 (Compressed)", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 128e3 },
|
|
21
|
-
// Google
|
|
22
|
-
{ id: "gemini-2.5-pro", name: "Gemini 2.5 Pro (Compressed)", reasoning: true, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 },
|
|
23
|
-
{ id: "gemini-2.5-flash", name: "Gemini 2.5 Flash (Compressed)", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 },
|
|
24
|
-
{ id: "google/gemini-2.5-pro-preview", name: "Gemini 2.5 Pro Preview (Compressed)", reasoning: true, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 },
|
|
25
|
-
// DeepSeek
|
|
26
|
-
{ id: "deepseek/deepseek-chat-v3-0324", name: "DeepSeek V3 (Compressed)", reasoning: false, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 8192 },
|
|
27
|
-
{ id: "deepseek/deepseek-reasoner", name: "DeepSeek Reasoner (Compressed)", reasoning: true, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 8192 },
|
|
28
|
-
// Meta
|
|
29
|
-
{ id: "meta-llama/llama-4-maverick", name: "Llama 4 Maverick (Compressed)", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 },
|
|
30
|
-
{ id: "meta-llama/llama-4-scout", name: "Llama 4 Scout (Compressed)", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 524288, maxTokens: 65536 },
|
|
31
|
-
// Qwen
|
|
32
|
-
{ id: "qwen/qwen3-235b-a22b", name: "Qwen3 235B (Compressed)", reasoning: true, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 8192 },
|
|
33
|
-
{ id: "qwen/qwen3-32b", name: "Qwen3 32B (Compressed)", reasoning: true, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 8192 },
|
|
34
|
-
// Mistral
|
|
35
|
-
{ id: "mistralai/mistral-large-2411", name: "Mistral Large (Compressed)", reasoning: false, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 8192 }
|
|
8
|
+
var FALLBACK_MODELS = [
|
|
9
|
+
{ id: "gpt-4o", name: "GPT-4o", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384 },
|
|
10
|
+
{ id: "gpt-4o-mini", name: "GPT-4o Mini", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128e3, maxTokens: 16384 },
|
|
11
|
+
{ id: "gpt-4.1", name: "GPT-4.1", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768 },
|
|
12
|
+
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1047576, maxTokens: 32768 },
|
|
13
|
+
{ id: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 128e3 },
|
|
14
|
+
{ id: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 2e5, maxTokens: 128e3 },
|
|
15
|
+
{ id: "gemini-2.5-pro", name: "Gemini 2.5 Pro", reasoning: true, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 },
|
|
16
|
+
{ id: "gemini-2.5-flash", name: "Gemini 2.5 Flash", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 1048576, maxTokens: 65536 },
|
|
17
|
+
{ id: "deepseek/deepseek-chat-v3-0324", name: "DeepSeek V3", reasoning: false, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 8192 },
|
|
18
|
+
{ id: "deepseek/deepseek-reasoner", name: "DeepSeek Reasoner", reasoning: true, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 131072, maxTokens: 8192 }
|
|
36
19
|
];
|
|
37
|
-
function
|
|
20
|
+
function upstreamToModels(data) {
|
|
21
|
+
return data.map((m) => {
|
|
22
|
+
const promptPrice = m.pricing?.prompt ? parseFloat(m.pricing.prompt) * 1e6 : 0;
|
|
23
|
+
const completionPrice = m.pricing?.completion ? parseFloat(m.pricing.completion) * 1e6 : 0;
|
|
24
|
+
const isReasoning = /\bo[34]\b|reasoner|thinking|deepthink/i.test(m.id);
|
|
25
|
+
const inputMods = ["text"];
|
|
26
|
+
const archInputs = m.architecture?.input_modalities || [];
|
|
27
|
+
if (archInputs.includes("image") || /vision|4o|gemini|claude-.*[34]/i.test(m.id)) {
|
|
28
|
+
inputMods.push("image");
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
id: m.id,
|
|
32
|
+
name: m.id,
|
|
33
|
+
reasoning: isReasoning,
|
|
34
|
+
input: inputMods,
|
|
35
|
+
cost: {
|
|
36
|
+
input: promptPrice,
|
|
37
|
+
output: completionPrice,
|
|
38
|
+
cacheRead: 0,
|
|
39
|
+
cacheWrite: 0
|
|
40
|
+
},
|
|
41
|
+
contextWindow: m.context_length || 128e3,
|
|
42
|
+
maxTokens: Math.min(m.context_length || 128e3, 65536)
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async function fetchUpstreamModels(baseUrl, apiKey, upstreamKey, upstreamBaseUrl) {
|
|
47
|
+
try {
|
|
48
|
+
const headers = {
|
|
49
|
+
Authorization: `Bearer ${apiKey}`
|
|
50
|
+
};
|
|
51
|
+
if (upstreamKey) headers["X-Upstream-Key"] = upstreamKey;
|
|
52
|
+
if (upstreamBaseUrl) headers["X-Upstream-Base-Url"] = upstreamBaseUrl;
|
|
53
|
+
const res = await fetch(`${baseUrl}/v1/models`, { headers });
|
|
54
|
+
if (!res.ok) return null;
|
|
55
|
+
const data = await res.json();
|
|
56
|
+
const models = data.data || [];
|
|
57
|
+
if (models.length === 0) return null;
|
|
58
|
+
return upstreamToModels(models);
|
|
59
|
+
} catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function buildProviderModels(baseUrl, upstreamKey, upstreamBaseUrl, models) {
|
|
38
64
|
const config = {
|
|
39
65
|
baseUrl: `${baseUrl}/v1`,
|
|
40
66
|
api: "openai-completions",
|
|
41
|
-
models:
|
|
67
|
+
models: models || FALLBACK_MODELS
|
|
42
68
|
};
|
|
43
69
|
if (upstreamKey || upstreamBaseUrl) {
|
|
44
70
|
config.headers = {};
|
|
@@ -115,6 +141,8 @@ var opencompressProvider = {
|
|
|
115
141
|
});
|
|
116
142
|
} catch {
|
|
117
143
|
}
|
|
144
|
+
const upstreamModels = await fetchUpstreamModels(DEFAULT_BASE_URL, data.apiKey, llmKey, upstreamBaseUrl);
|
|
145
|
+
const modelCount = upstreamModels ? upstreamModels.length : FALLBACK_MODELS.length;
|
|
118
146
|
return {
|
|
119
147
|
profiles: [
|
|
120
148
|
{
|
|
@@ -125,13 +153,13 @@ var opencompressProvider = {
|
|
|
125
153
|
configPatch: {
|
|
126
154
|
models: {
|
|
127
155
|
providers: {
|
|
128
|
-
opencompress: buildProviderModels(DEFAULT_BASE_URL, llmKey, upstreamBaseUrl)
|
|
156
|
+
opencompress: buildProviderModels(DEFAULT_BASE_URL, llmKey, upstreamBaseUrl, upstreamModels || void 0)
|
|
129
157
|
}
|
|
130
158
|
}
|
|
131
159
|
},
|
|
132
160
|
defaultModel: "gpt-4o-mini",
|
|
133
161
|
notes: [
|
|
134
|
-
`OpenCompress is ready! Connected to ${provider}.`,
|
|
162
|
+
`OpenCompress is ready! Connected to ${provider} (${modelCount} models).`,
|
|
135
163
|
"Your LLM key is stored locally only \u2014 never on our server.",
|
|
136
164
|
`Free credit: ${data.freeCredit}. Dashboard: opencompress.ai/dashboard`
|
|
137
165
|
]
|
|
@@ -154,7 +182,12 @@ var plugin = {
|
|
|
154
182
|
const existingHeaders = api.config.models?.providers?.opencompress?.headers;
|
|
155
183
|
const existingUpstreamKey = existingHeaders?.["X-Upstream-Key"];
|
|
156
184
|
const existingUpstreamBaseUrl = existingHeaders?.["X-Upstream-Base-Url"];
|
|
157
|
-
const
|
|
185
|
+
const apiKey = getApiKey(api);
|
|
186
|
+
let dynamicModels = null;
|
|
187
|
+
if (apiKey && existingUpstreamKey) {
|
|
188
|
+
dynamicModels = await fetchUpstreamModels(baseUrl, apiKey, existingUpstreamKey, existingUpstreamBaseUrl);
|
|
189
|
+
}
|
|
190
|
+
const providerModels = buildProviderModels(baseUrl, existingUpstreamKey, existingUpstreamBaseUrl, dynamicModels || void 0);
|
|
158
191
|
opencompressProvider.models = providerModels;
|
|
159
192
|
api.registerProvider(opencompressProvider);
|
|
160
193
|
if (!api.config.models) {
|
|
@@ -164,22 +197,24 @@ var plugin = {
|
|
|
164
197
|
api.config.models.providers = {};
|
|
165
198
|
}
|
|
166
199
|
api.config.models.providers.opencompress = providerModels;
|
|
167
|
-
|
|
200
|
+
const modelCount = dynamicModels ? dynamicModels.length : FALLBACK_MODELS.length;
|
|
201
|
+
const source = dynamicModels ? "upstream" : "fallback";
|
|
202
|
+
api.logger.info(`OpenCompress provider registered (${modelCount} ${source} models, 5-layer compression)`);
|
|
168
203
|
api.registerCommand({
|
|
169
204
|
name: "compress-stats",
|
|
170
205
|
description: "Show OpenCompress usage statistics and savings",
|
|
171
206
|
acceptsArgs: true,
|
|
172
207
|
requireAuth: false,
|
|
173
208
|
handler: async () => {
|
|
174
|
-
const
|
|
175
|
-
if (!
|
|
209
|
+
const apiKey2 = getApiKey(api);
|
|
210
|
+
if (!apiKey2) {
|
|
176
211
|
return {
|
|
177
212
|
text: "No API key found. Run `openclaw onboard opencompress` to set up."
|
|
178
213
|
};
|
|
179
214
|
}
|
|
180
215
|
try {
|
|
181
216
|
const res = await fetch(`${baseUrl}/user/stats`, {
|
|
182
|
-
headers: { Authorization: `Bearer ${
|
|
217
|
+
headers: { Authorization: `Bearer ${apiKey2}` }
|
|
183
218
|
});
|
|
184
219
|
if (!res.ok) {
|
|
185
220
|
return { text: `Failed to fetch stats: HTTP ${res.status}` };
|
|
@@ -219,14 +254,14 @@ var plugin = {
|
|
|
219
254
|
acceptsArgs: true,
|
|
220
255
|
requireAuth: false,
|
|
221
256
|
handler: async (ctx) => {
|
|
222
|
-
const
|
|
223
|
-
if (!
|
|
257
|
+
const apiKey2 = getApiKey(api);
|
|
258
|
+
if (!apiKey2) {
|
|
224
259
|
return { text: "Not set up. Run `openclaw onboard opencompress` first." };
|
|
225
260
|
}
|
|
226
261
|
const upstreamKey = ctx.args?.trim();
|
|
227
262
|
if (!upstreamKey) {
|
|
228
263
|
const res = await fetch(`${baseUrl}/v1/topup`, {
|
|
229
|
-
headers: { Authorization: `Bearer ${
|
|
264
|
+
headers: { Authorization: `Bearer ${apiKey2}` }
|
|
230
265
|
});
|
|
231
266
|
const data = res.ok ? await res.json() : null;
|
|
232
267
|
return {
|
|
@@ -253,7 +288,7 @@ var plugin = {
|
|
|
253
288
|
try {
|
|
254
289
|
await fetch(`${baseUrl}/v1/byok`, {
|
|
255
290
|
method: "DELETE",
|
|
256
|
-
headers: { Authorization: `Bearer ${
|
|
291
|
+
headers: { Authorization: `Bearer ${apiKey2}` }
|
|
257
292
|
});
|
|
258
293
|
} catch {
|
|
259
294
|
}
|
|
@@ -280,7 +315,8 @@ var plugin = {
|
|
|
280
315
|
provider = "google";
|
|
281
316
|
upstreamBaseUrl = "https://generativelanguage.googleapis.com/v1beta/openai";
|
|
282
317
|
}
|
|
283
|
-
const
|
|
318
|
+
const upstreamModels = await fetchUpstreamModels(baseUrl, apiKey2, upstreamKey, upstreamBaseUrl);
|
|
319
|
+
const updatedModels = buildProviderModels(baseUrl, upstreamKey, upstreamBaseUrl, upstreamModels || void 0);
|
|
284
320
|
if (api.config.models?.providers) {
|
|
285
321
|
api.config.models.providers.opencompress = updatedModels;
|
|
286
322
|
}
|
|
@@ -288,16 +324,18 @@ var plugin = {
|
|
|
288
324
|
await fetch(`${baseUrl}/v1/byok`, {
|
|
289
325
|
method: "POST",
|
|
290
326
|
headers: {
|
|
291
|
-
Authorization: `Bearer ${
|
|
327
|
+
Authorization: `Bearer ${apiKey2}`,
|
|
292
328
|
"Content-Type": "application/json"
|
|
293
329
|
},
|
|
294
330
|
body: JSON.stringify({ provider, passthrough: true })
|
|
295
331
|
});
|
|
296
332
|
} catch {
|
|
297
333
|
}
|
|
334
|
+
const modelCount2 = upstreamModels ? upstreamModels.length : FALLBACK_MODELS.length;
|
|
298
335
|
return {
|
|
299
336
|
text: [
|
|
300
337
|
`Switched to **BYOK mode** (${provider}).`,
|
|
338
|
+
`Loaded **${modelCount2} models** from your ${provider} account.`,
|
|
301
339
|
"",
|
|
302
340
|
"Your key is stored **locally only** \u2014 never sent to our server for storage.",
|
|
303
341
|
"It's passed through on each request via header and discarded immediately.",
|