feat(providers): add ZAI provider#239
Conversation
Adds providers/zai — a direct single-vendor integration with Z.ai (api.z.ai), serving the GLM model family (glm-5.1, glm-5-turbo, glm-5, glm-4.7, glm-4.6, glm-4.5, glm-4.5-air). Implements core.Provider, core.StreamProvider, core.ProxiableProvider, and core.DiscoveryProvider via the existing internal/openaicompat helpers. Splits out the ZAI portion of PR ferro-labs#230 as requested by @MitulShah1. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
|
@gr3enarr0w holding this PR as i am working on streamline all providers. |
|
@gr3enarr0w thanks for patient but i've completed my provider refactoring and streamline proces can you rebase this branch from main branch? i am planning to release in upcoming release. |
|
@CodeRabbit review |
✅ Action performedReview finished.
|
📝 WalkthroughWalkthroughAdds a new Z.ai (Zhipu AI) provider implementation supporting chat completion, streaming, and model discovery via OpenAI-compatible endpoints, then registers it as ChangesZ.ai Provider Integration
Estimated code review effort: 2 (Simple) | ~15 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant Provider as zai.Provider
participant ZAIAPI as Z.ai API
Caller->>Provider: Complete(ctx, req)
Provider->>ZAIAPI: POST /chat/completions (Bearer auth, JSON)
ZAIAPI-->>Provider: response
Provider-->>Caller: core.Response
Caller->>Provider: CompleteStream(ctx, req)
Provider->>ZAIAPI: POST /chat/completions (stream)
ZAIAPI-->>Provider: SSE chunks
Provider-->>Caller: chan core.StreamChunk
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts
Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@providers/zai/zai.go`:
- Around line 90-109: Both Provider.Complete and Provider.CompleteStream are
duplicating the auth header construction instead of using the shared
Provider.AuthHeaders helper. Update these methods to call p.AuthHeaders() when
building the openaicompat.ChatParams Headers so the Authorization logic stays
centralized and any future auth changes only need to be made in one place.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 7c7a6a65-ef1c-464b-a728-48406a5d69a8
📒 Files selected for processing (5)
providers/names.goproviders/providers_list.goproviders/stability_test.goproviders/zai/zai.goproviders/zai/zai_test.go
| func (p *Provider) Complete(ctx context.Context, req core.Request) (*core.Response, error) { | ||
| return openaicompat.PostChat(ctx, openaicompat.ChatParams{ | ||
| HTTPClient: p.httpClient, | ||
| URL: p.baseURL + "/chat/completions", | ||
| Provider: p.name, | ||
| Label: "zai", | ||
| Headers: map[string]string{"Authorization": "Bearer " + p.apiKey, "Content-Type": "application/json"}, | ||
| }, req) | ||
| } | ||
|
|
||
| // CompleteStream sends a streaming chat completion request to Z.ai. | ||
| func (p *Provider) CompleteStream(ctx context.Context, req core.Request) (<-chan core.StreamChunk, error) { | ||
| return openaicompat.PostStream(ctx, openaicompat.ChatParams{ | ||
| HTTPClient: p.httpClient, | ||
| URL: p.baseURL + "/chat/completions", | ||
| Provider: p.name, | ||
| Label: "zai", | ||
| Headers: map[string]string{"Authorization": "Bearer " + p.apiKey, "Content-Type": "application/json"}, | ||
| }, req) | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Duplicate header-building logic; reuse AuthHeaders().
Complete and CompleteStream each re-construct the Authorization header map instead of calling p.AuthHeaders() (line 59-61). If the auth scheme ever changes, only one of the three call sites is likely to be updated.
♻️ Suggested refactor
+func (p *Provider) requestHeaders() map[string]string {
+ h := p.AuthHeaders()
+ h["Content-Type"] = "application/json"
+ return h
+}
+
func (p *Provider) Complete(ctx context.Context, req core.Request) (*core.Response, error) {
return openaicompat.PostChat(ctx, openaicompat.ChatParams{
HTTPClient: p.httpClient,
URL: p.baseURL + "/chat/completions",
Provider: p.name,
Label: "zai",
- Headers: map[string]string{"Authorization": "Bearer " + p.apiKey, "Content-Type": "application/json"},
+ Headers: p.requestHeaders(),
}, req)
}
func (p *Provider) CompleteStream(ctx context.Context, req core.Request) (<-chan core.StreamChunk, error) {
return openaicompat.PostStream(ctx, openaicompat.ChatParams{
HTTPClient: p.httpClient,
URL: p.baseURL + "/chat/completions",
Provider: p.name,
Label: "zai",
- Headers: map[string]string{"Authorization": "Bearer " + p.apiKey, "Content-Type": "application/json"},
+ Headers: p.requestHeaders(),
}, req)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| func (p *Provider) Complete(ctx context.Context, req core.Request) (*core.Response, error) { | |
| return openaicompat.PostChat(ctx, openaicompat.ChatParams{ | |
| HTTPClient: p.httpClient, | |
| URL: p.baseURL + "/chat/completions", | |
| Provider: p.name, | |
| Label: "zai", | |
| Headers: map[string]string{"Authorization": "Bearer " + p.apiKey, "Content-Type": "application/json"}, | |
| }, req) | |
| } | |
| // CompleteStream sends a streaming chat completion request to Z.ai. | |
| func (p *Provider) CompleteStream(ctx context.Context, req core.Request) (<-chan core.StreamChunk, error) { | |
| return openaicompat.PostStream(ctx, openaicompat.ChatParams{ | |
| HTTPClient: p.httpClient, | |
| URL: p.baseURL + "/chat/completions", | |
| Provider: p.name, | |
| Label: "zai", | |
| Headers: map[string]string{"Authorization": "Bearer " + p.apiKey, "Content-Type": "application/json"}, | |
| }, req) | |
| } | |
| func (p *Provider) requestHeaders() map[string]string { | |
| h := p.AuthHeaders() | |
| h["Content-Type"] = "application/json" | |
| return h | |
| } | |
| func (p *Provider) Complete(ctx context.Context, req core.Request) (*core.Response, error) { | |
| return openaicompat.PostChat(ctx, openaicompat.ChatParams{ | |
| HTTPClient: p.httpClient, | |
| URL: p.baseURL + "/chat/completions", | |
| Provider: p.name, | |
| Label: "zai", | |
| Headers: p.requestHeaders(), | |
| }, req) | |
| } | |
| // CompleteStream sends a streaming chat completion request to Z.ai. | |
| func (p *Provider) CompleteStream(ctx context.Context, req core.Request) (<-chan core.StreamChunk, error) { | |
| return openaicompat.PostStream(ctx, openaicompat.ChatParams{ | |
| HTTPClient: p.httpClient, | |
| URL: p.baseURL + "/chat/completions", | |
| Provider: p.name, | |
| Label: "zai", | |
| Headers: p.requestHeaders(), | |
| }, req) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@providers/zai/zai.go` around lines 90 - 109, Both Provider.Complete and
Provider.CompleteStream are duplicating the auth header construction instead of
using the shared Provider.AuthHeaders helper. Update these methods to call
p.AuthHeaders() when building the openaicompat.ChatParams Headers so the
Authorization logic stays centralized and any future auth changes only need to
be made in one place.
Summary
providers/zai— a direct single-vendor integration with Z.ai (api.z.ai), serving the Zhipu AI GLM model familycore.Provider,core.StreamProvider,core.ProxiableProvider, andcore.DiscoveryProvidervia the existinginternal/openaicompathelpers (same pattern as xAI, Moonshot, etc.)glm-5.1,glm-5-turbo,glm-5,glm-4.7,glm-4.6,glm-4.5,glm-4.5-air— sourced from live/modelsendpoint verificationZAI_API_KEY(+ optionalZAI_BASE_URL)This is a direct single-vendor provider (not an aggregator), so it avoids any aggregator-design concerns raised in the broader review of #226.
Splits the ZAI portion of #230 into its own PR as requested by @MitulShah1.
Test plan
go build ./...passesproviders/zai/zai_test.gocoverNew,SupportedModels,SupportsModel,Models,AuthHeaders, mock SSE streaming, and mock HTTP non-streamingproviders/stability_test.goextended withNameZAIstability case🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes