@opencompress/opencompress 1.1.0 → 1.2.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 CHANGED
@@ -34,12 +34,18 @@ var OPENCOMPRESS_MODELS = [
34
34
  // Mistral
35
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 }
36
36
  ];
37
- function buildProviderModels(baseUrl) {
38
- return {
37
+ function buildProviderModels(baseUrl, upstreamKey, upstreamBaseUrl) {
38
+ const config = {
39
39
  baseUrl: `${baseUrl}/v1`,
40
40
  api: "openai-completions",
41
41
  models: OPENCOMPRESS_MODELS
42
42
  };
43
+ if (upstreamKey || upstreamBaseUrl) {
44
+ config.headers = {};
45
+ if (upstreamKey) config.headers["X-Upstream-Key"] = upstreamKey;
46
+ if (upstreamBaseUrl) config.headers["X-Upstream-Base-Url"] = upstreamBaseUrl;
47
+ }
48
+ return config;
43
49
  }
44
50
  var opencompressProvider = {
45
51
  id: "opencompress",
@@ -103,9 +109,11 @@ var plugin = {
103
109
  version: VERSION,
104
110
  async register(api) {
105
111
  const baseUrl = api.pluginConfig?.baseUrl || DEFAULT_BASE_URL;
106
- if (baseUrl !== DEFAULT_BASE_URL) {
107
- opencompressProvider.models = buildProviderModels(baseUrl);
108
- }
112
+ const existingHeaders = api.config.models?.providers?.opencompress?.headers;
113
+ const existingUpstreamKey = existingHeaders?.["X-Upstream-Key"];
114
+ const existingUpstreamBaseUrl = existingHeaders?.["X-Upstream-Base-Url"];
115
+ const providerModels = buildProviderModels(baseUrl, existingUpstreamKey, existingUpstreamBaseUrl);
116
+ opencompressProvider.models = providerModels;
109
117
  api.registerProvider(opencompressProvider);
110
118
  if (!api.config.models) {
111
119
  api.config.models = { providers: {} };
@@ -113,7 +121,7 @@ var plugin = {
113
121
  if (!api.config.models.providers) {
114
122
  api.config.models.providers = {};
115
123
  }
116
- api.config.models.providers.opencompress = buildProviderModels(baseUrl);
124
+ api.config.models.providers.opencompress = providerModels;
117
125
  api.logger.info("OpenCompress provider registered (20 models, 5-layer compression)");
118
126
  api.registerCommand({
119
127
  name: "compress-stats",
@@ -175,10 +183,10 @@ var plugin = {
175
183
  }
176
184
  const upstreamKey = ctx.args?.trim();
177
185
  if (!upstreamKey) {
178
- const res2 = await fetch(`${baseUrl}/v1/topup`, {
186
+ const res = await fetch(`${baseUrl}/v1/topup`, {
179
187
  headers: { Authorization: `Bearer ${apiKey}` }
180
188
  });
181
- const data2 = res2.ok ? await res2.json() : null;
189
+ const data = res.ok ? await res.json() : null;
182
190
  return {
183
191
  text: [
184
192
  "**BYOK (Bring Your Own Key)**",
@@ -191,19 +199,23 @@ var plugin = {
191
199
  " `/compress-byok sk-or-xxx` \u2014 Connect OpenRouter key",
192
200
  " `/compress-byok off` \u2014 Switch back to router mode",
193
201
  "",
194
- data2 ? `**Balance:** $${data2.balance.toFixed(2)}` : ""
202
+ data ? `**Balance:** $${data.balance.toFixed(2)}` : ""
195
203
  ].join("\n")
196
204
  };
197
205
  }
198
206
  if (upstreamKey === "off" || upstreamKey === "disable" || upstreamKey === "router") {
199
- const res2 = await fetch(`${baseUrl}/v1/byok`, {
200
- method: "DELETE",
201
- headers: { Authorization: `Bearer ${apiKey}` }
202
- });
203
- if (!res2.ok) {
204
- return { text: `Failed to switch: HTTP ${res2.status}` };
207
+ const cleanModels = buildProviderModels(baseUrl);
208
+ if (api.config.models?.providers) {
209
+ api.config.models.providers.opencompress = cleanModels;
210
+ }
211
+ try {
212
+ await fetch(`${baseUrl}/v1/byok`, {
213
+ method: "DELETE",
214
+ headers: { Authorization: `Bearer ${apiKey}` }
215
+ });
216
+ } catch {
205
217
  }
206
- return { text: "Switched back to **router mode**. We handle LLM routing via OpenRouter." };
218
+ return { text: "Switched back to **router mode**. Your upstream key has been removed from local config." };
207
219
  }
208
220
  if (upstreamKey.startsWith("sk-occ-")) {
209
221
  return { text: "That's an OpenCompress key. Provide your LLM provider key (OpenAI, Anthropic, etc.)." };
@@ -211,24 +223,42 @@ var plugin = {
211
223
  if (upstreamKey.length < 10) {
212
224
  return { text: "Key looks too short. Provide your full LLM API key." };
213
225
  }
214
- const res = await fetch(`${baseUrl}/v1/byok`, {
215
- method: "POST",
216
- headers: {
217
- Authorization: `Bearer ${apiKey}`,
218
- "Content-Type": "application/json"
219
- },
220
- body: JSON.stringify({ upstreamApiKey: upstreamKey })
221
- });
222
- if (!res.ok) {
223
- const err = await res.json().catch(() => ({ error: { message: "Unknown error" } }));
224
- return { text: `Failed: ${err.error?.message || res.statusText}` };
226
+ let provider = "unknown";
227
+ let upstreamBaseUrl = "";
228
+ if (upstreamKey.startsWith("sk-proj-") || upstreamKey.startsWith("sk-") && !upstreamKey.startsWith("sk-ant-") && !upstreamKey.startsWith("sk-or-")) {
229
+ provider = "openai";
230
+ upstreamBaseUrl = "https://api.openai.com/v1";
231
+ } else if (upstreamKey.startsWith("sk-ant-")) {
232
+ provider = "anthropic";
233
+ upstreamBaseUrl = "https://api.anthropic.com/v1";
234
+ } else if (upstreamKey.startsWith("sk-or-")) {
235
+ provider = "openrouter";
236
+ upstreamBaseUrl = "https://openrouter.ai/api/v1";
237
+ } else if (upstreamKey.startsWith("AIza")) {
238
+ provider = "google";
239
+ upstreamBaseUrl = "https://generativelanguage.googleapis.com/v1beta/openai";
240
+ }
241
+ const updatedModels = buildProviderModels(baseUrl, upstreamKey, upstreamBaseUrl);
242
+ if (api.config.models?.providers) {
243
+ api.config.models.providers.opencompress = updatedModels;
244
+ }
245
+ try {
246
+ await fetch(`${baseUrl}/v1/byok`, {
247
+ method: "POST",
248
+ headers: {
249
+ Authorization: `Bearer ${apiKey}`,
250
+ "Content-Type": "application/json"
251
+ },
252
+ body: JSON.stringify({ provider, passthrough: true })
253
+ });
254
+ } catch {
225
255
  }
226
- const data = await res.json();
227
256
  return {
228
257
  text: [
229
- `Switched to **BYOK mode** (${data.provider}).`,
258
+ `Switched to **BYOK mode** (${provider}).`,
230
259
  "",
231
- data.billing,
260
+ "Your key is stored **locally only** \u2014 never sent to our server for storage.",
261
+ "It's passed through on each request via header and discarded immediately.",
232
262
  "",
233
263
  "To switch back: `/compress-byok off`"
234
264
  ].join("\n")
@@ -0,0 +1,72 @@
1
+ {
2
+ "id": "opencompress",
3
+ "version": "1.0.0",
4
+ "securityProfile": {
5
+ "dataHandling": {
6
+ "promptContent": "pass-through",
7
+ "promptStorage": "none",
8
+ "responseContent": "pass-through",
9
+ "responseStorage": "none",
10
+ "upstreamApiKeys": "local-only",
11
+ "upstreamApiKeyStorage": "never-server-side"
12
+ },
13
+ "networkAccess": {
14
+ "outbound": [
15
+ {
16
+ "host": "www.opencompress.ai",
17
+ "port": 443,
18
+ "protocol": "https",
19
+ "purpose": "API proxy — compress prompts and forward to upstream LLM provider"
20
+ }
21
+ ],
22
+ "inbound": []
23
+ },
24
+ "localStorage": {
25
+ "authProfiles": {
26
+ "path": "~/.openclaw/agents/*/agent/auth-profiles.json",
27
+ "content": "OpenCompress API key (sk-occ-*)",
28
+ "sensitive": true
29
+ },
30
+ "providerConfig": {
31
+ "path": "~/.openclaw/openclaw.json",
32
+ "content": "Provider config, optional upstream key in headers (BYOK pass-through)",
33
+ "sensitive": true
34
+ }
35
+ },
36
+ "secrets": {
37
+ "required": [
38
+ {
39
+ "name": "OpenCompress API Key",
40
+ "format": "sk-occ-*",
41
+ "purpose": "Authentication and billing for compression service",
42
+ "serverSideStorage": "hashed (SHA-256), never plaintext"
43
+ }
44
+ ],
45
+ "optional": [
46
+ {
47
+ "name": "Upstream LLM API Key",
48
+ "format": "sk-proj-* / sk-ant-* / sk-or-* / AIza*",
49
+ "purpose": "BYOK mode — forwarded to user's LLM provider",
50
+ "serverSideStorage": "NEVER stored. Passed via X-Upstream-Key header per-request, discarded after forwarding."
51
+ }
52
+ ]
53
+ },
54
+ "permissions": {
55
+ "fileSystem": "read/write ~/.openclaw/ config files only",
56
+ "environment": ["OPENCOMPRESS_API_KEY", "OPENCOMPRESS_LLM_KEY"],
57
+ "shell": "none",
58
+ "network": "outbound HTTPS to www.opencompress.ai only"
59
+ }
60
+ },
61
+ "privacyPolicy": {
62
+ "promptsAndResponses": "OpenCompress compresses prompts in-memory and forwards to the upstream LLM provider. Prompt and response content is NEVER stored, logged, or used for training. Only token counts are recorded for billing.",
63
+ "apiKeys": "Your upstream LLM API key (OpenAI, Anthropic, etc.) is stored ONLY on your local machine. It is sent to our server as a per-request header (X-Upstream-Key) and discarded immediately after forwarding. We never persist your upstream keys.",
64
+ "billing": "We record: timestamp, model, original token count, compressed token count, cost. We do NOT record prompt content.",
65
+ "thirdParties": "We do not share any data with third parties. Your requests are forwarded only to the LLM provider you specify."
66
+ },
67
+ "auditability": {
68
+ "pluginSource": "Open source — https://github.com/claw-compactor/openclaw-plugin",
69
+ "serverSource": "Forwarding logic documented in security docs. Core proxy is open for audit.",
70
+ "verification": "Users can inspect all network requests via OpenClaw's diagnostics plugin or standard proxy tools."
71
+ }
72
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencompress/opencompress",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "OpenCompress plugin for OpenClaw — automatic 5-layer prompt compression for any LLM",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -18,7 +18,8 @@
18
18
  },
19
19
  "files": [
20
20
  "dist",
21
- "openclaw.plugin.json"
21
+ "openclaw.plugin.json",
22
+ "openclaw.security.json"
22
23
  ],
23
24
  "keywords": [
24
25
  "openclaw",