Skip to content

Conversation

@shrey150
Copy link
Contributor

@shrey150 shrey150 commented Feb 11, 2026

Summary

  • Adds extraBody option to CustomOpenAIClient so subclasses can inject provider-specific request body params via the OpenAI SDK's extra body API
  • Adds ZhipuClient as a thin subclass (~15 lines) for Z.ai (Zhipu AI) GLM models (e.g. GLM-4.7), with enableThinking toggle
  • Fixes pre-existing bug in CustomOpenAIClient: preserves original role for string-content system/assistant messages instead of forcing all to "user"
  • Exports ZhipuClient from @browserbasehq/stagehand
  • Adds usage example in examples/custom_client_zhipu.ts

Context

A community user was trying to disable thinking/reasoning for GLM-4.7 via CustomOpenAIClient but had no way to inject the Z.ai-specific thinking parameter without forking the client. This gives them a drop-in solution:

import { ZhipuClient } from '@browserbasehq/stagehand';
import OpenAI from 'openai';

const stagehand = new Stagehand({
  env: 'LOCAL',
  llmClient: new ZhipuClient({
    modelName: 'glm-4.7',
    client: new OpenAI({
      apiKey: process.env.ZHIPU_API_KEY,
      baseURL: 'https://api.z.ai/api/coding/paas/v4',
    }),
    enableThinking: false, // defaults to false
  }),
});

The extraBody option on CustomOpenAIClient also enables the same pattern for any other OpenAI-compatible provider with non-standard params — no cloning needed.

Test plan

  • pnpm build passes — ZhipuClient appears in dist/index.d.ts
  • Export surface test passes (56/56)
  • No new type errors

🤖 Generated with Claude Code

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-bot
Copy link

changeset-bot bot commented Feb 11, 2026

🦋 Changeset detected

Latest commit: 02030f8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@browserbasehq/stagehand Patch
@browserbasehq/stagehand-evals Patch
@browserbasehq/stagehand-server Patch

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-apps
Copy link
Contributor

greptile-apps bot commented Feb 11, 2026

Greptile Overview

Greptile Summary

Adds ZhipuOpenAIClient to support Z.ai (Zhipu AI) GLM models with proprietary thinking control parameter. The implementation closely follows the existing CustomOpenAIClient pattern, extending it to inject the Z.ai-specific thinking parameter via OpenAI SDK's extra_body API.

  • Implements ZhipuOpenAIClient with enableThinking option (defaults to false for lower latency/cost)
  • Exports the client from @browserbasehq/stagehand package for direct user import
  • Includes working example with GLM-4.7 model
  • Uses OpenAI SDK's second parameter to pass non-standard thinking: { type: "enabled" | "disabled" } field in request body

Confidence Score: 4/5

  • Safe to merge with minor considerations about OpenAI SDK compatibility
  • The implementation closely follows the proven CustomOpenAIClient pattern with minimal changes. The key addition is the thinking parameter injection via extra_body, which relies on OpenAI SDK's documented API. Code is well-structured and includes clear documentation. Confidence reduced by 1 point only because the extra_body parameter structure isn't type-safe (passed as generic object) and manual testing wasn't completed per the PR description.
  • No files require special attention

Important Files Changed

Filename Overview
packages/core/examples/custom_client_zhipu.ts Adds example demonstrating ZhipuOpenAIClient usage with GLM-4.7 model and thinking control
packages/core/examples/external_clients/zhipuOpenAI.ts Implements ZhipuOpenAIClient extending LLMClient, adds enableThinking parameter passed via OpenAI SDK's extra_body
packages/core/lib/v3/types/public/index.ts Exports ZhipuOpenAIClient from public API, making it available for import from @browserbasehq/stagehand

Sequence Diagram

sequenceDiagram
    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
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 3 files

Confidence score: 3/5

  • Two concrete issues in packages/core/examples/external_clients/zhipuOpenAI.ts can break tool calling and message role handling, so there is some user-impacting risk.
  • inputSchema is used instead of parameters in 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
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

shrey150 and others added 3 commits February 10, 2026 17:08
- 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>
@shrey150 shrey150 changed the title Add ZhipuOpenAIClient for Z.ai GLM models with thinking control Add ZhipuClient for Z.ai GLM models with thinking control Feb 11, 2026
inputSchema was intentional for backwards compatibility with
OpenAI-compatible providers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@shrey150 shrey150 marked this pull request as draft February 11, 2026 01:29
// 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";
Copy link
Contributor Author

@shrey150 shrey150 Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
@shrey150 shrey150 force-pushed the examples/zhipu-openai-client branch from 84d9c90 to 02030f8 Compare February 11, 2026 02:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant