Add ZhipuClient for Z.ai GLM models with thinking control#1677
Add ZhipuClient for Z.ai GLM models with thinking control#1677
Conversation
Z.ai's GLM-4.7 uses a proprietary `thinking` parameter that isn't part of the OpenAI spec. This adds a dedicated example client that uses the OpenAI SDK's extra body API to control it, so users don't need to fork CustomOpenAIClient. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 02030f8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Greptile OverviewGreptile SummaryAdds
Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant Stagehand
participant ZhipuOpenAIClient
participant OpenAI SDK
participant Z.ai API
User->>Stagehand: new Stagehand({ llmClient: ZhipuOpenAIClient })
User->>Stagehand: act() or extract()
Stagehand->>ZhipuOpenAIClient: createChatCompletion(options)
ZhipuOpenAIClient->>ZhipuOpenAIClient: Format messages & build request body
ZhipuOpenAIClient->>OpenAI SDK: client.chat.completions.create(body, { body: { thinking: { type } } })
OpenAI SDK->>Z.ai API: POST /api/coding/paas/v4/chat/completions<br/>(with thinking parameter in extra_body)
Z.ai API-->>OpenAI SDK: ChatCompletion response
OpenAI SDK-->>ZhipuOpenAIClient: response
ZhipuOpenAIClient->>ZhipuOpenAIClient: Parse & validate response
ZhipuOpenAIClient-->>Stagehand: Formatted response with usage
Stagehand-->>User: Result
|
There was a problem hiding this comment.
2 issues found across 3 files
Confidence score: 3/5
- Two concrete issues in
packages/core/examples/external_clients/zhipuOpenAI.tscan break tool calling and message role handling, so there is some user-impacting risk. inputSchemais used instead ofparametersin the tool definition, which can cause function/tool calling to silently fail at runtime.- Non-array message content is always mapped to
role: "user", so system/assistant messages with string content lose their role and can distort conversation behavior. - Pay close attention to
packages/core/examples/external_clients/zhipuOpenAI.ts- tool schema field and message role mapping.
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/core/examples/external_clients/zhipuOpenAI.ts">
<violation number="1" location="packages/core/examples/external_clients/zhipuOpenAI.ts:147">
P1: Non-array message content always gets mapped to `role: "user"`, discarding the original role. System and assistant messages with string content will be sent as user messages, breaking the conversation structure. Preserve the original `message.role`.</violation>
<violation number="2" location="packages/core/examples/external_clients/zhipuOpenAI.ts:196">
P1: `inputSchema` is not a valid field in the OpenAI function tool definition — it should be `parameters`. This will cause tool/function calling to silently fail because the API won't receive the parameter schema.</violation>
</file>
Architecture diagram
sequenceDiagram
participant User as Example/User Script
participant SH as Stagehand (Core)
participant ZC as NEW: ZhipuOpenAIClient
participant OAI as OpenAI SDK
participant API as Zhipu AI API (z.ai)
Note over User,API: Initialization with ZH_API_KEY and enableThinking toggle
User->>SH: act() / extract()
SH->>ZC: createChatCompletion(options)
ZC->>ZC: Format messages (User/Assistant/System)
opt If options.response_model
ZC->>ZC: Convert Zod schema to JSON Schema string
ZC->>ZC: Append schema prompt to messages
end
ZC->>OAI: chat.completions.create(body, request_options)
Note right of ZC: NEW: Injects "thinking" param<br/>via extra_body in request_options
OAI->>API: POST /chat/completions (with thinking: {type: "enabled|disabled"})
API-->>OAI: ChatCompletion Response
OAI-->>ZC: ChatCompletion Response
alt If options.response_model (Structured Output)
ZC->>ZC: JSON.parse(content)
alt Validation Success
ZC-->>SH: Return parsed data + usage
else Validation Failure (Retry logic)
Note over ZC: CHANGED: Validates against Zod schema
ZC->>ZC: retry (decrement retries)
ZC-->>User: Throw CreateChatCompletionResponseError (after 3 attempts)
end
else Simple String Output
ZC-->>SH: Return string content + usage
end
SH-->>User: Return action result / extracted data
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
- Preserve original role for string-content system/assistant messages instead of always mapping to "user" - Use `parameters` instead of `inputSchema` in tool definitions to match the OpenAI API spec - Add changeset for version bump Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add `extraBody` option to CustomOpenAIClient so subclasses can inject provider-specific request body params via the OpenAI SDK's extra body API - Rewrite ZhipuOpenAIClient as a thin subclass (~15 lines vs ~250 cloned) - Fix pre-existing bugs in CustomOpenAIClient: - `inputSchema` → `parameters` in tool definitions (OpenAI API spec) - Preserve original role for string-content system/assistant messages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The OpenAI-compatible API is an implementation detail, not part of the user-facing name. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
inputSchema was intentional for backwards compatibility with OpenAI-compatible providers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/core/examples/external_clients/customOpenAI.ts">
<violation number="1">
P0: Bug: This change renames `parameters` to `inputSchema`, but the OpenAI **Chat Completions** API expects `parameters` in function tool definitions. `inputSchema` is used by the separate **Responses API** — since this code calls `client.chat.completions.create()`, this will break tool/function calling. The PR description says the fix should be `inputSchema → parameters`, but the diff goes the wrong direction.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| // Note added for revisiting this scaffold for an improved version based on llm/aisdk.ts | ||
| export { AISdkClient } from "../../../../examples/external_clients/aisdk"; | ||
| export { CustomOpenAIClient } from "../../../../examples/external_clients/customOpenAI"; | ||
| export { ZhipuClient } from "../../../../examples/external_clients/zhipuOpenAI"; |
There was a problem hiding this comment.
Blocker: We shouldn't be exporting example clients from the public API — it implies a maintenance commitment for what are meant to be copy-and-customize templates. Discussed live with @seanmcguire12 — need to figure out the right pattern before merging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
84d9c90 to
02030f8
Compare
Summary
extraBodyoption toCustomOpenAIClientso subclasses can inject provider-specific request body params via the OpenAI SDK's extra body APIZhipuClientas a thin subclass (~15 lines) for Z.ai (Zhipu AI) GLM models (e.g. GLM-4.7), withenableThinkingtoggleCustomOpenAIClient: preserves original role for string-content system/assistant messages instead of forcing all to "user"ZhipuClientfrom@browserbasehq/stagehandexamples/custom_client_zhipu.tsContext
A community user was trying to disable thinking/reasoning for GLM-4.7 via
CustomOpenAIClientbut had no way to inject the Z.ai-specificthinkingparameter without forking the client. This gives them a drop-in solution:The
extraBodyoption onCustomOpenAIClientalso enables the same pattern for any other OpenAI-compatible provider with non-standard params — no cloning needed.Test plan
pnpm buildpasses —ZhipuClientappears indist/index.d.ts🤖 Generated with Claude Code