import test from "node:test"; import assert from "node:assert/strict"; import { getExecutor } from "../../open-sse/executors/index.ts"; import { GlmExecutor } from "../../open-sse/executors/glm.ts"; function makeSseResponse(lines: string[]): Response { return new Response(lines.join("\n\n") + "\n\n", { headers: { "Content-Type": "text/event-stream" }, }); } test("GlmExecutor normalizes GLM coding and Anthropic URLs without duplicating endpoints", () => { const executor = new GlmExecutor("glm"); assert.equal( executor.buildUrl("glm-5.1", true, 0, { providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4" }, }), "https://api.z.ai/api/coding/paas/v4/chat/completions" ); assert.equal( executor.buildUrl("glm-5.1", true, 0, { providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4/" }, }), "https://api.z.ai/api/coding/paas/v4/chat/completions" ); assert.equal( executor.buildUrl("glm-5.1", true, 0, { providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4/chat/completions", }, }), "https://api.z.ai/api/coding/paas/v4/chat/completions" ); assert.equal( executor.buildUrl("glm-5.1", true, 0, { providerSpecificData: { baseUrl: "https://proxy.example.com/api/coding/paas/v4/v1/messages", }, }), "https://proxy.example.com/api/coding/paas/v4/chat/completions" ); assert.equal( executor.buildUrl("glm-5.1", true, 0, { providerSpecificData: { baseUrl: "https://api.z.ai/api/anthropic" }, }), "https://api.z.ai/api/anthropic/v1/messages?beta=true" ); assert.equal( executor.buildUrl("glm-5.1", true, 0, { providerSpecificData: { baseUrl: "https://api.z.ai/api/anthropic/v1" }, }), "https://api.z.ai/api/anthropic/v1/messages?beta=true" ); assert.equal( new GlmExecutor("glm-cn").buildUrl("glm-5.1", true, 0, { providerSpecificData: { anthropicBaseUrl: "https://open.bigmodel.cn/api/anthropic/v1", primaryTransport: "anthropic", }, }), "https://open.bigmodel.cn/api/anthropic/v1/messages?beta=true" ); assert.equal( executor.buildUrl("glm-5.1", true, 1, { providerSpecificData: { baseUrl: "https://api.z.ai/api/anthropic" }, }), "https://api.z.ai/api/coding/paas/v4/chat/completions" ); assert.equal( executor.buildUrl("glm-5.1", true, 0, { providerSpecificData: { baseUrl: "https://api.z.ai/api/anthropic/v1/messages" }, }), "https://api.z.ai/api/anthropic/v1/messages?beta=true" ); assert.equal( executor.buildUrl("glm-5.1", true, 1, { providerSpecificData: { baseUrl: "https://api.z.ai/api/anthropic/v1/messages" }, }), "https://api.z.ai/api/coding/paas/v4/chat/completions" ); assert.equal( executor.buildUrl("glm-5.1", true, 0, { providerSpecificData: { baseUrl: "https://api.z.ai/api/anthropic/v1/messages?beta=true", }, }), "https://api.z.ai/api/anthropic/v1/messages?beta=true" ); assert.equal( executor.buildCountTokensUrl("glm-5.1", { providerSpecificData: { baseUrl: "https://proxy.example.com/api/anthropic/v1/messages/count_tokens", }, }), "https://proxy.example.com/api/anthropic/v1/messages/count_tokens?beta=true" ); assert.equal( executor.buildUrl("glm-5.1", true, 0, { providerSpecificData: { baseUrl: "https://proxy.example.com/api/coding/paas/v4/chat/completions?tenant=alpha&route=glm", }, }), "https://proxy.example.com/api/coding/paas/v4/chat/completions?tenant=alpha&route=glm" ); assert.equal( executor.buildCountTokensUrl("glm-5.1", { providerSpecificData: { anthropicBaseUrl: "https://proxy.example.com/api/anthropic/v1/messages/count_tokens?tenant=alpha&route=glm", }, }), "https://proxy.example.com/api/anthropic/v1/messages/count_tokens?tenant=alpha&route=glm&beta=true" ); }); test("GlmExecutor separates OpenAI-compatible coding headers from Anthropic headers", () => { assert.equal(getExecutor("glm") instanceof GlmExecutor, true); assert.equal(getExecutor("glm-cn") instanceof GlmExecutor, true); assert.equal(getExecutor("glmt") instanceof GlmExecutor, true); const executor = new GlmExecutor("glm"); const codingHeaders = executor.buildHeaders( { apiKey: "glm-key", providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4" }, }, true ); assert.equal(codingHeaders.Authorization, "Bearer glm-key"); assert.equal(codingHeaders["x-api-key"], undefined); assert.equal(codingHeaders["anthropic-version"], undefined); assert.equal(codingHeaders["anthropic-beta"], undefined); assert.equal(codingHeaders["anthropic-dangerous-direct-browser-access"], undefined); assert.equal(codingHeaders.Accept, "text/event-stream"); const countTokensHeaders = executor.buildHeaders( { apiKey: "glm-key", providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4" }, }, false, null, undefined, "anthropic" ); assert.equal(countTokensHeaders["x-api-key"], "glm-key"); assert.equal(countTokensHeaders.Authorization, undefined); assert.equal(countTokensHeaders["anthropic-version"], "2023-06-01"); const anthropicHeaders = executor.buildHeaders( { apiKey: "glm-key", providerSpecificData: { baseUrl: "https://api.z.ai/api/anthropic/v1/messages" }, }, true, null, undefined, "anthropic" ); assert.equal(anthropicHeaders["x-api-key"], "glm-key"); assert.equal(anthropicHeaders.Authorization, undefined); assert.equal(anthropicHeaders.Accept, "text/event-stream"); assert.equal(anthropicHeaders["anthropic-version"], "2023-06-01"); assert.match(anthropicHeaders["anthropic-beta"], /claude-code-20250219/); assert.equal(anthropicHeaders["anthropic-dangerous-direct-browser-access"], "true"); assert.match(anthropicHeaders["User-Agent"], /^claude-cli\/2\.1\.195 \(external, sdk-cli\)$/); assert.equal(anthropicHeaders["X-Stainless-Lang"], "js"); assert.equal(anthropicHeaders["X-Stainless-Runtime"], "node"); }); test("GlmExecutor preserves extra API key rotation", () => { const executor = new GlmExecutor("glm"); const headers = executor.buildHeaders( { apiKey: "primary-key", connectionId: "glm-rotation-test", providerSpecificData: { baseUrl: "https://api.z.ai/api/anthropic/v1/messages", extraApiKeys: ["extra-key"], }, }, true, null, undefined, "anthropic" ); assert.ok(["primary-key", "extra-key"].includes(headers["x-api-key"])); assert.equal(headers.Authorization, undefined); }); test("GlmExecutor applies GLMT adaptive thinking defaults without mutating caller body", () => { const executor = new GlmExecutor("glmt"); const body = { messages: [{ role: "user", content: "hi" }] }; const transformed = executor.transformRequest("glm-5.1", body, true, { apiKey: "glm-key", }) as any; assert.notEqual(transformed, body); assert.equal((body as any).max_tokens, undefined); assert.equal(transformed.max_tokens, 65_536); assert.equal(transformed.temperature, 0.2); assert.deepEqual(transformed.thinking, { type: "adaptive", budget_tokens: 24_576 }); }); test("GlmExecutor applies conservative GLM defaults without mutating caller body", () => { const executor = new GlmExecutor("glm"); const body = { messages: [{ role: "user", content: "hi" }] }; const transformed = executor.transformRequest("glm-5.1", body, false, { apiKey: "glm-key", }) as any; assert.notEqual(transformed, body); assert.equal((body as any).max_tokens, undefined); assert.equal(transformed.max_tokens, 16_384); assert.equal(transformed.temperature, undefined); assert.equal(transformed.thinking, undefined); }); test("GlmExecutor preserves caller max token settings over GLM defaults", () => { const executor = new GlmExecutor("glm"); const body = { messages: [{ role: "user", content: "hi" }], max_output_tokens: 512, }; const transformed = executor.transformRequest("glm-5.1", body, false, { apiKey: "glm-key", }) as any; assert.deepEqual(transformed, body); assert.equal((transformed as any).max_tokens, undefined); assert.equal((transformed as any).max_output_tokens, 512); }); test("GlmExecutor count_tokens is best-effort and timeout bounded", async () => { const executor = new GlmExecutor("glm"); assert.equal( executor.buildCountTokensUrl("glm-5.1", { providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4" }, }), "https://api.z.ai/api/anthropic/v1/messages/count_tokens?beta=true" ); assert.equal(executor.getCountTokensTimeoutMs(), 3_000); const originalFetch = globalThis.fetch; let captured: { url: string; body: any; headers: any } | null = null; globalThis.fetch = async (url, init: RequestInit = {}) => { captured = { url: String(url), body: JSON.parse(String(init.body || "{}")), headers: init.headers, }; return Response.json({ input_tokens: 42 }); }; try { const result = await executor.countTokens({ model: "glm-5.1", body: { messages: [{ role: "user", content: "hello" }] }, credentials: { apiKey: "glm-key", providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4" }, }, }); assert.equal(result?.input_tokens, 42); assert.ok(captured); assert.equal(captured.url, "https://api.z.ai/api/anthropic/v1/messages/count_tokens?beta=true"); assert.equal(captured.body.model, "glm-5.1"); assert.equal(captured.headers["x-api-key"], "glm-key"); } finally { globalThis.fetch = originalFetch; } }); test("GlmExecutor translates Anthropic streaming fallback to OpenAI SSE", async () => { const executor = new GlmExecutor("glm"); const originalFetch = globalThis.fetch; globalThis.fetch = async () => { return new Response( 'event: message_start\ndata: {"type":"message_start","message":{"id":"msg_1","type":"message","role":"assistant","model":"glm-5.1","content":[],"stop_reason":null,"usage":{"input_tokens":1,"output_tokens":0}}}\n\nevent: content_block_delta\ndata: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"hi"}}\n\nevent: message_stop\ndata: {"type":"message_stop"}\n\n', { headers: { "Content-Type": "text/event-stream" }, } ); }; try { const result = await executor.execute({ model: "glm-5.1", body: { messages: [{ role: "user", content: "hello" }] }, stream: true, credentials: { apiKey: "glm-key", providerSpecificData: { baseUrl: "https://api.z.ai/api/anthropic/v1/messages", primaryTransport: "anthropic", }, }, }); assert.equal(result.targetFormat, "openai"); assert.equal(result.response.headers.get("content-type"), "text/event-stream"); const text = await result.response.text(); assert.match(text, /chat\.completion\.chunk/); assert.doesNotMatch(text, /message_start/); } finally { globalThis.fetch = originalFetch; } }); test("GlmExecutor sends OpenAI coding payload first and enables streaming tool chunks", async () => { const executor = new GlmExecutor("glm"); const originalFetch = globalThis.fetch; let captured: { url: string; body: any; headers: any } | null = null; globalThis.fetch = async (url, init: RequestInit = {}) => { captured = { url: String(url), body: JSON.parse(String(init.body || "{}")), headers: init.headers, }; return makeSseResponse([ 'data: {"id":"chatcmpl-glm","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":"ok"}}]}', "data: [DONE]", ]); }; try { const result = await executor.execute({ model: "glm-5.1", body: { messages: [{ role: "user", content: "weather" }], tools: [ { type: "function", function: { name: "get_weather", parameters: { type: "object", properties: {} }, }, }, ], }, stream: true, credentials: { apiKey: "glm-key", providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4" }, }, }); assert.equal(result.response.status, 200); assert.equal(captured?.url, "https://api.z.ai/api/coding/paas/v4/chat/completions"); assert.equal(captured?.headers.Authorization, "Bearer glm-key"); assert.equal(captured?.headers["x-api-key"], undefined); assert.equal(captured?.headers["anthropic-version"], undefined); assert.equal(captured?.body.tool_stream, true); assert.equal(captured?.body.tools[0].function.name, "get_weather"); assert.match(await result.response.text(), /chatcmpl-glm/); } finally { globalThis.fetch = originalFetch; } }); test("GlmExecutor falls back internally to Anthropic transport and returns OpenAI JSON", async () => { const executor = new GlmExecutor("glm"); const originalFetch = globalThis.fetch; const calls: Array<{ url: string; body: any; headers: any }> = []; globalThis.fetch = async (url, init: RequestInit = {}) => { calls.push({ url: String(url), body: JSON.parse(String(init.body || "{}")), headers: init.headers, }); if (calls.length === 1) { return new Response(JSON.stringify({ error: "not found" }), { status: 404, headers: { "Content-Type": "application/json" }, }); } return Response.json({ id: "msg_glm", type: "message", role: "assistant", model: "glm-5.1", content: [{ type: "text", text: "fallback ok" }], stop_reason: "end_turn", usage: { input_tokens: 3, output_tokens: 2 }, }); }; try { const result = await executor.execute({ model: "glm-5.1", body: { messages: [{ role: "user", content: "hello" }] }, stream: false, credentials: { apiKey: "glm-key", providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4" }, }, }); assert.equal(calls.length, 2); assert.equal(calls[0].url, "https://api.z.ai/api/coding/paas/v4/chat/completions"); assert.equal(calls[0].headers.Authorization, "Bearer glm-key"); assert.equal(calls[1].url, "https://api.z.ai/api/anthropic/v1/messages?beta=true"); assert.equal(calls[1].headers["x-api-key"], "glm-key"); assert.equal(calls[1].headers.Authorization, undefined); assert.equal(calls[1].body.messages[0].role, "user"); assert.equal(calls[1].body._disableToolPrefix, undefined); assert.equal(result.targetFormat, "openai"); const json = await result.response.json(); assert.equal(json.object, "chat.completion"); assert.equal(json.choices[0].message.content, "fallback ok"); } finally { globalThis.fetch = originalFetch; } }); test("GlmExecutor falls back when primary stream ends before useful content", async () => { const executor = new GlmExecutor("glm"); const originalFetch = globalThis.fetch; const calls: string[] = []; globalThis.fetch = async (url) => { calls.push(String(url)); if (calls.length === 1) { return makeSseResponse(["event: ping", "data: {}"]); } return makeSseResponse([ 'event: message_start\ndata: {"type":"message_start","message":{"id":"msg_1","type":"message","role":"assistant","model":"glm-5.1","content":[],"stop_reason":null,"usage":{"input_tokens":1,"output_tokens":0}}}', 'event: content_block_delta\ndata: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"fallback stream ok"}}', 'event: message_stop\ndata: {"type":"message_stop"}', ]); }; try { const result = await executor.execute({ model: "glm-5.1", body: { messages: [{ role: "user", content: "hello" }] }, stream: true, credentials: { apiKey: "glm-key", providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4" }, }, }); assert.deepEqual(calls, [ "https://api.z.ai/api/coding/paas/v4/chat/completions", "https://api.z.ai/api/anthropic/v1/messages?beta=true", ]); assert.equal(result.response.status, 200); assert.equal(result.targetFormat, "openai"); const text = await result.response.text(); assert.match(text, /chat\.completion\.chunk/); assert.match(text, /fallback stream ok/); } finally { globalThis.fetch = originalFetch; } }); test("GlmExecutor uses readiness timeout for OpenAI-compatible stream handoff", async () => { const executor = new GlmExecutor("glm"); const originalFetch = globalThis.fetch; globalThis.fetch = async () => makeSseResponse(["event: ping", "data: {}"]); try { const result = await executor.execute({ model: "glm-5.1", body: { messages: [{ role: "user", content: "hello" }] }, stream: true, credentials: { apiKey: "glm-key", providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4" }, }, }); assert.equal(result.response.status, 502); assert.match(await result.response.text(), /STREAM_EARLY_EOF/); } finally { globalThis.fetch = originalFetch; } }); test("GlmExecutor preserves non-OK streaming upstream status before readiness", async () => { const executor = new GlmExecutor("glm"); const originalFetch = globalThis.fetch; const calls: string[] = []; globalThis.fetch = async (url) => { calls.push(String(url)); return new Response(JSON.stringify({ error: "invalid api key" }), { status: 401, headers: { "Content-Type": "application/json" }, }); }; try { const result = await executor.execute({ model: "glm-5.1", body: { messages: [{ role: "user", content: "hello" }] }, stream: true, credentials: { apiKey: "bad-key", providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4" }, }, }); assert.deepEqual(calls, ["https://api.z.ai/api/coding/paas/v4/chat/completions"]); assert.equal(result.response.status, 401); assert.match(await result.response.text(), /invalid api key/); } finally { globalThis.fetch = originalFetch; } }); test("GlmExecutor translates Anthropic JSON errors to OpenAI-shaped fallback responses", async () => { const executor = new GlmExecutor("glm"); const originalFetch = globalThis.fetch; globalThis.fetch = async () => { return new Response( JSON.stringify({ type: "error", error: { type: "invalid_request_error", message: "bad anthropic fallback" }, }), { status: 400, headers: { "Content-Type": "application/json" }, } ); }; try { const result = await executor.execute({ model: "glm-5.1", body: { messages: [{ role: "user", content: "hello" }] }, stream: false, credentials: { apiKey: "glm-key", providerSpecificData: { baseUrl: "https://api.z.ai/api/anthropic/v1/messages", primaryTransport: "anthropic", }, }, }); assert.equal(result.targetFormat, "openai"); assert.equal(result.response.status, 400); const json = await result.response.json(); assert.equal(json.error.message, "bad anthropic fallback"); } finally { globalThis.fetch = originalFetch; } }); test("GlmExecutor Anthropic fallback keeps tool names unprefixed", async () => { const executor = new GlmExecutor("glm"); const originalFetch = globalThis.fetch; const calls: Array<{ url: string; body: any; headers: any }> = []; globalThis.fetch = async (url, init: RequestInit = {}) => { calls.push({ url: String(url), body: JSON.parse(String(init.body || "{}")), headers: init.headers, }); if (calls.length === 1) return new Response("upstream down", { status: 502 }); return Response.json({ id: "msg_tool", type: "message", role: "assistant", model: "glm-5.1", content: [ { type: "tool_use", id: "toolu_1", name: "get_weather", input: { location: "Madrid" } }, ], stop_reason: "tool_use", usage: { input_tokens: 4, output_tokens: 1 }, }); }; try { const result = await executor.execute({ model: "glm-5.1", body: { messages: [{ role: "user", content: "weather" }], tools: [ { type: "function", function: { name: "get_weather", parameters: { type: "object", properties: {} }, }, }, ], }, stream: false, credentials: { apiKey: "glm-key", providerSpecificData: { baseUrl: "https://api.z.ai/api/coding/paas/v4" }, }, }); assert.equal(calls.length, 2); assert.equal(calls[1].body.tools[0].name, "get_weather"); assert.equal(calls[1].body.tools[0].name.startsWith("proxy_"), false); assert.equal(calls[1].body._disableToolPrefix, undefined); const json = await result.response.json(); assert.equal(json.choices[0].finish_reason, "tool_calls"); assert.equal(json.choices[0].message.tool_calls[0].function.name, "get_weather"); } finally { globalThis.fetch = originalFetch; } }); // Regression for #4255 — GLM-5.2+ thinking models share a single max_tokens // budget for reasoning + response. When the client omits max_tokens, the // executor must default to the model's full output capacity (131072) so deep // reasoning isn't truncated by the generic GLM default (16_384). Scoped to // GLM-5.2+ via transformForTransport — non-thinking GLM models are untouched. test("GlmExecutor defaults GLM-5.2+ max_tokens to 131072 when the client omits it", () => { const executor = new GlmExecutor("glm"); const body = { messages: [{ role: "user", content: "hi" }] }; const transformed = executor.transformForTransport( "glm-5.2", body, false, { apiKey: "glm-key", }, "openai" ) as any; assert.equal((body as any).max_tokens, undefined, "caller body must not be mutated"); assert.equal(transformed.max_tokens, 131072); }); test("GlmExecutor preserves a client-supplied max_tokens for GLM-5.2+ (no override)", () => { const executor = new GlmExecutor("glm"); const body = { messages: [{ role: "user", content: "hi" }], max_tokens: 4096 }; const transformed = executor.transformForTransport( "glm-5.2", body, false, { apiKey: "glm-key", }, "openai" ) as any; assert.equal(transformed.max_tokens, 4096); }); test("GlmExecutor does NOT bump max_tokens for non-thinking GLM (glm-4.6)", () => { const executor = new GlmExecutor("glm"); const body = { messages: [{ role: "user", content: "hi" }] }; const transformed = executor.transformForTransport( "glm-4.6", body, false, { apiKey: "glm-key", }, "openai" ) as any; // Stays at the generic GLM default (16_384) — never the 131072 thinking budget. assert.notEqual(transformed.max_tokens, 131072); assert.equal(transformed.max_tokens, 16_384); });