diff --git a/packages/cli/src/provider/provider.ts b/packages/cli/src/provider/provider.ts index 9cedb10..a504fe6 100644 --- a/packages/cli/src/provider/provider.ts +++ b/packages/cli/src/provider/provider.ts @@ -578,8 +578,63 @@ export namespace Provider { }, } }, - "zai-coding-plan": async () => { + "zai-coding-plan": async (input) => { const apiKey = Env.get("ZHIPU_API_KEY") + input.models["glm-5.2"] ??= { + id: "glm-5.2", + providerID: input.id, + api: { + id: "glm-5.2", + url: "https://api.z.ai/api/coding/paas/v4", + npm: "@ai-sdk/openai-compatible", + }, + name: "GLM-5.2", + family: "glm", + capabilities: { + temperature: true, + reasoning: true, + attachment: false, + toolcall: true, + input: { + text: true, + audio: false, + image: false, + video: false, + pdf: false, + }, + output: { + text: true, + audio: false, + image: false, + video: false, + pdf: false, + }, + interleaved: { field: "reasoning_content" }, + }, + cost: { + input: 0, + output: 0, + cache: { + read: 0, + write: 0, + }, + }, + limit: { + context: 1_000_000, + output: 131_072, + }, + status: "active", + options: {}, + headers: {}, + release_date: "2026-06-13", + variants: { + low: { reasoningEffort: "high" }, + medium: { reasoningEffort: "high" }, + high: { reasoningEffort: "high" }, + xhigh: { reasoningEffort: "max" }, + max: { reasoningEffort: "max" }, + }, + } return { autoload: !!apiKey, options: { diff --git a/packages/cli/src/provider/transform.ts b/packages/cli/src/provider/transform.ts index 7bd60ff..0716ade 100644 --- a/packages/cli/src/provider/transform.ts +++ b/packages/cli/src/provider/transform.ts @@ -343,6 +343,15 @@ export namespace ProviderTransform { model.api.id.includes(v), ) const adaptiveEfforts = ["low", "medium", "high", "max"] + if (model.providerID === "zai-coding-plan" && model.api.id === "glm-5.2") { + return { + low: { reasoningEffort: "high" }, + medium: { reasoningEffort: "high" }, + high: { reasoningEffort: "high" }, + xhigh: { reasoningEffort: "max" }, + max: { reasoningEffort: "max" }, + } + } if ( id.includes("deepseek") || id.includes("minimax") || diff --git a/packages/cli/test/provider/transform.test.ts b/packages/cli/test/provider/transform.test.ts index 15366fa..df85927 100644 --- a/packages/cli/test/provider/transform.test.ts +++ b/packages/cli/test/provider/transform.test.ts @@ -1614,6 +1614,25 @@ describe("ProviderTransform.variants", () => { expect(result).toEqual({}) }) + test("zai coding plan glm-5.2 maps variants to supported efforts", () => { + const model = createMockModel({ + id: "glm-5.2", + providerID: "zai-coding-plan", + api: { + id: "glm-5.2", + url: "https://api.z.ai/api/coding/paas/v4", + npm: "@ai-sdk/openai-compatible", + }, + }) + const result = ProviderTransform.variants(model) + expect(Object.keys(result)).toEqual(["low", "medium", "high", "xhigh", "max"]) + expect(result.low).toEqual({ reasoningEffort: "high" }) + expect(result.medium).toEqual({ reasoningEffort: "high" }) + expect(result.high).toEqual({ reasoningEffort: "high" }) + expect(result.xhigh).toEqual({ reasoningEffort: "max" }) + expect(result.max).toEqual({ reasoningEffort: "max" }) + }) + test("mistral returns empty object", () => { const model = createMockModel({ id: "mistral/mistral-large", diff --git a/packages/cli/test/session/llm.test.ts b/packages/cli/test/session/llm.test.ts index c28a99a..be7c69e 100644 --- a/packages/cli/test/session/llm.test.ts +++ b/packages/cli/test/session/llm.test.ts @@ -323,6 +323,100 @@ describe("session.llm.stream", () => { }) }) + test("sends Coding Plan payload for GLM-5.2", async () => { + const server = state.server + if (!server) { + throw new Error("Server not initialized") + } + + const providerID = "zai-coding-plan" + const modelID = "glm-5.2" + const fixture = await loadFixture(providerID, modelID) + const model = fixture.model + + const request = waitRequest( + "/chat/completions", + new Response(createChatStream("Hello"), { + status: 200, + headers: { "Content-Type": "text/event-stream" }, + }), + ) + + await using tmp = await tmpdir({ + init: async (dir) => { + await Bun.write( + path.join(dir, "aictrl.json"), + JSON.stringify({ + $schema: "https://aictrl.ai/config.json", + enabled_providers: [providerID], + provider: { + [providerID]: { + options: { + apiKey: "test-zai-key", + baseURL: `${server.url.origin}/v1`, + }, + }, + }, + }), + ) + }, + }) + + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const resolved = await Provider.getModel(providerID, model.id) + const sessionID = "session-test-glm-52" + const agent = { + name: "test", + mode: "primary", + options: {}, + permission: [{ permission: "*", pattern: "*", action: "allow" }], + } satisfies Agent.Info + + const user = { + id: "user-glm-52", + sessionID, + role: "user", + time: { created: Date.now() }, + agent: agent.name, + model: { providerID, modelID: resolved.id }, + variant: "max", + } satisfies MessageV2.User + + const stream = await LLM.stream({ + user, + sessionID, + model: resolved, + agent, + system: ["You are a helpful assistant."], + abort: new AbortController().signal, + messages: [{ role: "user", content: "Hello" }], + tools: {}, + }) + + for await (const _ of stream.fullStream) { + } + + const capture = await request + const body = capture.body + + expect(capture.url.pathname.endsWith("/chat/completions")).toBe(true) + expect(capture.headers.get("Authorization")).toBe("Bearer test-zai-key") + expect(body.model).toBe("glm-5.2") + expect(body.temperature).toBe(1) + expect(body.max_tokens).toBe(ProviderTransform.maxOutputTokens(resolved)) + expect(body.thinking).toEqual({ + type: "enabled", + clear_thinking: false, + }) + + const reasoning = (body.reasoningEffort as string | undefined) ?? (body.reasoning_effort as string | undefined) + expect(reasoning).toBe("max") + }, + }) + }) + test("sends responses API payload for OpenAI models", async () => { const server = state.server if (!server) { diff --git a/packages/cli/test/tool/fixtures/models-api.json b/packages/cli/test/tool/fixtures/models-api.json index 5cf53da..c79d15f 100644 --- a/packages/cli/test/tool/fixtures/models-api.json +++ b/packages/cli/test/tool/fixtures/models-api.json @@ -1747,6 +1747,24 @@ "name": "Z.AI Coding Plan", "doc": "https://docs.z.ai/devpack/overview", "models": { + "glm-5.2": { + "id": "glm-5.2", + "name": "GLM-5.2", + "family": "glm", + "attachment": false, + "reasoning": true, + "reasoning_options": [{ "type": "effort", "values": ["high", "max"] }], + "tool_call": true, + "interleaved": { "field": "reasoning_content" }, + "structured_output": true, + "temperature": true, + "release_date": "2026-06-13", + "last_updated": "2026-06-13", + "modalities": { "input": ["text"], "output": ["text"] }, + "open_weights": false, + "cost": { "input": 0, "output": 0, "cache_read": 0, "cache_write": 0 }, + "limit": { "context": 1000000, "output": 131072 } + }, "glm-5.1": { "id": "glm-5.1", "name": "GLM-5.1",