claude-glm 1.3.1 → 1.3.3

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.
@@ -19,7 +19,7 @@ const PORT = Number(process.env.CLAUDE_PROXY_PORT || 17870);
19
19
 
20
20
  let active: ProviderModel | null = null;
21
21
 
22
- const fastify = Fastify({ logger: false });
22
+ const fastify = Fastify({ logger: false, bodyLimit: 100 * 1024 * 1024 });
23
23
 
24
24
  // Health check endpoint
25
25
  fastify.get("/healthz", async () => ({
@@ -1,10 +1,23 @@
1
1
  // Vision preprocessing: converts image blocks to text descriptions for non-vision models
2
+ import { createHash } from "crypto";
2
3
  import type { AnthropicRequest } from "./types.js";
3
4
 
4
5
  const DEFAULT_VISION_MODEL = "google/gemini-2.5-flash";
5
6
  const DESCRIBE_PROMPT =
6
7
  "Describe this image in granular detail — layout, text, colors, objects, spatial relationships, any code or data visible.";
7
8
 
9
+ // In-memory cache: hash of image data → description text
10
+ const descriptionCache = new Map<string, string>();
11
+
12
+ function imageKey(block: ImageBlock): string {
13
+ if (block.source.type === "url" && block.source.url) {
14
+ return "url:" + block.source.url;
15
+ }
16
+ // Hash first 2048 chars of base64 + length for a fast, collision-resistant key
17
+ const data = block.source.data;
18
+ return createHash("sha256").update(data.slice(0, 2048) + ":" + data.length).digest("hex");
19
+ }
20
+
8
21
  interface ImageBlock {
9
22
  type: "image";
10
23
  source: { type: string; media_type: string; data: string; url?: string };
@@ -89,18 +102,29 @@ export async function preprocessImages(
89
102
 
90
103
  if (tasks.length === 0) return;
91
104
 
92
- console.log(`[ccx] Describing ${tasks.length} image(s) via ${model}...`);
105
+ // Split into cached hits and new images that need describing
106
+ const uncached = tasks.filter((t) => !descriptionCache.has(imageKey(t.block)));
107
+ const cached = tasks.length - uncached.length;
93
108
 
94
- const descriptions = await Promise.all(
95
- tasks.map((t) => describeImage(t.block, model, apiKey))
96
- );
109
+ if (uncached.length > 0) {
110
+ console.log(`[ccx] Describing ${uncached.length} new image(s) via ${model} (${cached} cached)...`);
111
+ const descriptions = await Promise.all(
112
+ uncached.map((t) => describeImage(t.block, model, apiKey))
113
+ );
114
+ for (let i = 0; i < uncached.length; i++) {
115
+ descriptionCache.set(imageKey(uncached[i].block), descriptions[i]);
116
+ }
117
+ } else {
118
+ console.log(`[ccx] All ${tasks.length} image(s) served from cache`);
119
+ }
97
120
 
98
121
  // Replace image blocks with text descriptions (reverse order to preserve indices)
99
122
  for (let i = tasks.length - 1; i >= 0; i--) {
100
123
  const { msg, idx } = tasks[i];
124
+ const desc = descriptionCache.get(imageKey(tasks[i].block))!;
101
125
  msg.content[idx] = {
102
126
  type: "text",
103
- text: `[Image Description: ${descriptions[i]}]`,
127
+ text: `[Image Description: ${desc}]`,
104
128
  };
105
129
  }
106
130
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-glm",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "Cross-platform installer for Claude Code with Z.AI GLM models, multi-provider proxy, and dangerously-skip-permissions shortcuts. Run with: npx claude-glm",
5
5
  "keywords": [
6
6
  "claude",