Z.ai plugin
The zai plugin gives Genkit access to Z.ai’s GLM models through Z.ai’s
OpenAI-compatible chat completions endpoint. Models are named under the zai/ provider prefix.
Installation
Section titled “Installation”go get github.com/firebase/genkit/goConfiguration
Section titled “Configuration”Add &zai.ZAI{} to your plugin list. The plugin reads the API key from the ZAI_API_KEY
environment variable.
package main
import ( "context" "fmt" "log"
"github.com/firebase/genkit/go/ai" "github.com/firebase/genkit/go/genkit" "github.com/firebase/genkit/go/plugins/compat_oai/zai")
func main() { ctx := context.Background()
g := genkit.Init(ctx, genkit.WithPlugins(&zai.ZAI{}), genkit.WithDefaultModel("zai/glm-5.1"), )
text, err := genkit.GenerateText(ctx, g, ai.WithPrompt("Share a joke about bananas.")) if err != nil { log.Fatalf("could not generate: %v", err) }
fmt.Println(text)}You must provide an API key from Z.ai. You can get one from the
Z.ai platform. Set ZAI_API_KEY, or set the APIKey field. Extra OpenAI
client request options ride in Opts, applied after the plugin defaults so they win on overlap;
option is github.com/openai/openai-go/option.
g := genkit.Init(ctx, genkit.WithPlugins(&zai.ZAI{ APIKey: os.Getenv("MY_ZAI_KEY"), Opts: []option.RequestOption{ option.WithBaseURL("https://api.z.ai/api/paas/v4"), },}))genkit.Init panics when neither the APIKey field nor ZAI_API_KEY is set. The endpoint defaults
to https://api.z.ai/api/paas/v4; override it with the ZAI_BASE_URL environment variable or with
option.WithBaseURL in Opts.
As always, avoid embedding API keys directly in your code.
Models
Section titled “Models”The plugin registers these GLM models when it initializes:
glm-5.1,glm-5-turbo,glm-5glm-4.7,glm-4.7-flash,glm-4.7-flashxglm-4.6glm-4.5,glm-4.5-air,glm-4.5-x,glm-4.5-airx,glm-4.5-flashglm-4-32b-0414-128k
The vision models, which take images as well as text:
glm-5v-turbo,glm-4.6v,glm-4.6v-flash,glm-4.6v-flashx,glm-4.5v
That list is a starting point rather than a limit. Any other GLM model ID resolves on demand and takes the plugin’s text-only defaults, so a model Z.ai releases later works without a Genkit upgrade.
No GLM model advertises tool choice, so tool selection is always automatic and a forced tool choice
is refused before the request goes out. Constrained generation is unclaimed too: Z.ai’s
response_format takes text or json_object only, not json_schema, so an output schema reaches
the model as prompt instructions and comes back as the same typed result.
zai.ModelRef pairs a model ID with a typed zai.ChatConfig, so the config is checked where you
write it and validated against the model’s schema before the request goes out.
resp, err := genkit.Generate(ctx, g, ai.WithModel(zai.ModelRef("glm-5.1", &zai.ChatConfig{ Thinking: &zai.ThinkingConfig{Type: zai.ThinkingTypeDisabled}, MaxOutputTokens: 1024, })), ai.WithPrompt("Share a joke about bananas."),)if err != nil { log.Fatalf("could not generate: %v", err)}
fmt.Println(resp.Text())The ID passed to ModelRef works bare or provider-prefixed. You can also name a model as a string
with ai.WithModelName("zai/glm-5.1") or genkit.WithDefaultModel, and pass the config separately
with ai.WithConfig(&zai.ChatConfig{...}). The
Z.ai sample runs this as a
streaming flow you can call from the Dev UI.
Generation config
Section titled “Generation config”zai.ChatConfig carries the generation fields Z.ai accepts plus its own controls:
| Field | Type | Notes |
|---|---|---|
Temperature | *float64 | Randomness of token selection, 0 to 1, not the 2 OpenAI allows. The default varies by model. |
TopP | *float64 | Nucleus sampling threshold, 0.01 to 1. |
MaxOutputTokens | int | Sent as the API’s max_tokens, up to 131072. |
StopSequences | []string | Up to four. |
Thinking | *zai.ThinkingConfig | Type is zai.ThinkingTypeEnabled, the Z.ai default, or zai.ThinkingTypeDisabled. ClearThinking decides whether the reasoning is cleared from the response, and Z.ai defaults it to true. |
DoSample | *bool | false turns sampling off, which makes Temperature and TopP inert. |
Z.ai documents no penalties, no log probabilities, and no seed, so those fields are deliberately absent. Pointer fields separate unset from a deliberate zero.
ChatConfig also embeds compat_oai.RequestConfig, which every plugin in the family shares: a
per-request APIKey, a Version pin, and an Extra map whose keys ride to the wire verbatim under
Z.ai’s own names. See the
OpenAI-compatible plugin page.
Correcting what the plugin knows about a model
Section titled “Correcting what the plugin knows about a model”Every GLM model works without an entry in Models. Supply one only to correct or extend the
capabilities the plugin resolves, most often for a model released after your Genkit version. Keys are
the model ID, bare or provider-prefixed, and fields left at their zero value keep what the plugin
resolved.
g := genkit.Init(ctx, genkit.WithPlugins(&zai.ZAI{ Models: map[string]ai.ModelOptions{ // A model the plugin does not curate resolves with the text-only // defaults, so an entry is how you tell Genkit it takes images. "glm-4.7v": { Supports: &ai.ModelSupports{ Multiturn: true, Tools: true, SystemRole: true, Media: true, }, }, },}))Response behavior
Section titled “Response behavior”Reasoning text, streamed token usage, cached prompt tokens, and mid-generation provider failures are handled the same way for every plugin in this family. See the OpenAI-compatible plugin page.