@opencode/ai 0.0.0-beta-19289 → 0.0.0-beta-19365
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -0
- package/dist/protocols/anthropic-messages.d.ts +24 -1
- package/dist/protocols/anthropic-messages.js +55 -12
- package/dist/protocols/meta-messages.d.ts +6 -0
- package/dist/protocols/zai-chat.d.ts +202 -0
- package/dist/protocols/zai-chat.js +49 -0
- package/dist/protocols/zai-messages.d.ts +344 -0
- package/dist/protocols/zai-messages.js +27 -0
- package/dist/providers/anthropic-compatible.d.ts +6 -0
- package/dist/providers/anthropic.d.ts +6 -0
- package/dist/providers/google-vertex-messages.d.ts +6 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.js +2 -0
- package/dist/providers/meta.d.ts +6 -0
- package/dist/providers/minimax.d.ts +6 -0
- package/dist/providers/moonshot/chat.d.ts +1 -0
- package/dist/providers/moonshot/chat.js +1 -0
- package/dist/providers/moonshot/messages.d.ts +4 -0
- package/dist/providers/moonshot/messages.js +8 -0
- package/dist/providers/moonshot/responses.d.ts +4 -0
- package/dist/providers/moonshot/responses.js +8 -0
- package/dist/providers/moonshot.d.ts +597 -0
- package/dist/providers/moonshot.js +90 -0
- package/dist/providers/zai/chat.d.ts +1 -0
- package/dist/providers/zai/chat.js +1 -0
- package/dist/providers/zai-coding-plan/chat.d.ts +1 -0
- package/dist/providers/zai-coding-plan/chat.js +1 -0
- package/dist/providers/zai-coding-plan/messages.d.ts +4 -0
- package/dist/providers/zai-coding-plan/messages.js +8 -0
- package/dist/providers/zai-coding-plan/responses.d.ts +4 -0
- package/dist/providers/zai-coding-plan/responses.js +8 -0
- package/dist/providers/zai-coding-plan.d.ts +578 -0
- package/dist/providers/zai-coding-plan.js +63 -0
- package/dist/providers/zai.d.ts +134 -8
- package/dist/providers/zai.js +32 -0
- package/dist/schema/options.d.ts +2 -0
- package/dist/schema/options.js +2 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -29,6 +29,134 @@ await Effect.runPromise(program.pipe(Effect.provide(llmLayer)))
|
|
|
29
29
|
|
|
30
30
|
Run `LLMClient.stream(request)` instead of `generate` when you want incremental `LLMEvent`s. The event stream is provider-neutral — same shape across OpenAI Chat, OpenAI Responses, Anthropic Messages, Gemini, Bedrock Converse, and any OpenAI-compatible deployment.
|
|
31
31
|
|
|
32
|
+
## Z.AI
|
|
33
|
+
|
|
34
|
+
`ZAI` uses the standard API. Chat Completions is the default language-model API;
|
|
35
|
+
the existing `.image(...)` selector provides image generation.
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { LLM } from "@opencode/ai"
|
|
39
|
+
import { ZAI, ZAICodingPlan } from "@opencode/ai/providers"
|
|
40
|
+
|
|
41
|
+
const zai = ZAI.configure({ apiKey: process.env.ZAI_API_KEY })
|
|
42
|
+
const request = LLM.request({
|
|
43
|
+
model: zai.model("glm-5.3"), // also zai.chat("glm-5.3")
|
|
44
|
+
prompt: "Explain this design.",
|
|
45
|
+
providerOptions: {
|
|
46
|
+
reasoningEffort: "high",
|
|
47
|
+
thinking: { type: "enabled", clear_thinking: false },
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const coding = ZAICodingPlan.configure({ apiKey: process.env.ZAI_API_KEY })
|
|
52
|
+
const messages = LLM.request({
|
|
53
|
+
model: coding.messages("glm-5.3"),
|
|
54
|
+
prompt: "Explain this design.",
|
|
55
|
+
providerOptions: { effort: "high" },
|
|
56
|
+
})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The products have distinct provider identities and endpoints:
|
|
60
|
+
|
|
61
|
+
| Provider | Selector | Default base URL |
|
|
62
|
+
| ----------------------------------- | --------------------------- | ------------------------------------- |
|
|
63
|
+
| `ZAI` (`zai`) | `.model`, `.chat`, `.image` | `https://api.z.ai/api/paas/v4` |
|
|
64
|
+
| `ZAICodingPlan` (`zai-coding-plan`) | `.model`, `.chat` | `https://api.z.ai/api/coding/paas/v4` |
|
|
65
|
+
| `ZAICodingPlan` | `.messages` | `https://api.z.ai/api/anthropic/v1` |
|
|
66
|
+
| `ZAICodingPlan` | `.responses` | `https://api.z.ai/api/v1` |
|
|
67
|
+
|
|
68
|
+
Both read `ZAI_API_KEY` when `apiKey` is omitted and support an explicit `auth` override.
|
|
69
|
+
Coding Plan requires an active subscription. `baseURL` overrides the selected API's
|
|
70
|
+
complete base, including its version prefix. Language-model routes use HTTP/SSE.
|
|
71
|
+
|
|
72
|
+
Options retain the selected API's native semantics:
|
|
73
|
+
|
|
74
|
+
- Chat `reasoningEffort` lowers to `reasoning_effort`; Responses lowers it to `reasoning.effort`.
|
|
75
|
+
Messages `effort` lowers to `output_config.effort`. Omission preserves provider defaults.
|
|
76
|
+
- Chat `thinking` passes `type` and `clear_thinking` through unchanged. Set
|
|
77
|
+
`clear_thinking: false` and replay complete `response.message` values to preserve reasoning
|
|
78
|
+
across user messages and tool loops. The standard API defaults to clearing historical thinking;
|
|
79
|
+
Coding Plan documents preservation by default.
|
|
80
|
+
- Messages accepts `thinking: { type: "enabled" | "adaptive" | "disabled" }` without requiring
|
|
81
|
+
an Anthropic token budget. Coding Plan documents a disabled toggle as low-effort thinking
|
|
82
|
+
for GLM-5.3, with explicit effort taking precedence.
|
|
83
|
+
- Chat also offers `toolStream`, `doSample`, `responseFormat`, `requestID`, and `userID`.
|
|
84
|
+
Tool-argument streaming is enabled when tools are present on GLM-4.6/4.7/5.x;
|
|
85
|
+
`toolStream: false` explicitly disables it. Older model families omit the opt-in.
|
|
86
|
+
- Effort and thinking values remain forward-compatible strings. Their meaning is model-specific:
|
|
87
|
+
GLM-5.3 accepts `low`, `high`, and `max` effort and rejects disabled thinking with HTTP 400;
|
|
88
|
+
the direct GLM-5.2 recordings returned reasoning even with `none` and `minimal` effort,
|
|
89
|
+
whereas explicit `thinking.type: "disabled"` disabled it on GLM-5.2 and GLM-4.7.
|
|
90
|
+
|
|
91
|
+
Standard API recordings cover GLM-5.3 efforts and a full preserved-reasoning tool loop with
|
|
92
|
+
a subsequent user follow-up, GLM-5.2 efforts, older-model thinking toggles, GLM-4.5 tool calls,
|
|
93
|
+
GLM-5.3-Flash image input, and JSON output. Coding Plan has unit coverage for routing,
|
|
94
|
+
request options, and reasoning replay; successful live recordings are pending.
|
|
95
|
+
|
|
96
|
+
Package entrypoints are `@opencode/ai/providers/zai`, `zai/chat`, `zai-coding-plan`,
|
|
97
|
+
`zai-coding-plan/chat`, `zai-coding-plan/messages`, and `zai-coding-plan/responses`.
|
|
98
|
+
|
|
99
|
+
## Moonshot
|
|
100
|
+
|
|
101
|
+
Moonshot defaults to Chat Completions, with Messages and Responses selectors for Kimi K3:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import { LLM } from "@opencode/ai"
|
|
105
|
+
import { Moonshot } from "@opencode/ai/providers"
|
|
106
|
+
|
|
107
|
+
const moonshot = Moonshot.configure({ apiKey: process.env.MOONSHOT_API_KEY })
|
|
108
|
+
|
|
109
|
+
const request = LLM.request({
|
|
110
|
+
model: moonshot.model("kimi-k3"), // also moonshot.chat("kimi-k3")
|
|
111
|
+
prompt: "Explain the tradeoffs in this design.",
|
|
112
|
+
providerOptions: { reasoningEffort: "high" },
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
const messages = LLM.request({
|
|
116
|
+
model: moonshot.messages("kimi-k3"),
|
|
117
|
+
prompt: "Explain the tradeoffs in this design.",
|
|
118
|
+
providerOptions: { effort: "high" },
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
const responses = LLM.request({
|
|
122
|
+
model: moonshot.responses("kimi-k3"),
|
|
123
|
+
prompt: "Explain the tradeoffs in this design.",
|
|
124
|
+
providerOptions: { reasoningEffort: "high" },
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
When `apiKey` is omitted, authentication reads `MOONSHOT_API_KEY`, then `MOONSHOTAI_API_KEY`.
|
|
129
|
+
Chat and Responses use `https://api.moonshot.ai/v1`; Messages uses
|
|
130
|
+
`https://api.moonshot.ai/anthropic/v1`. `baseURL` overrides the selected API's complete base,
|
|
131
|
+
including the version prefix, for regional endpoints or gateways. Each endpoint requires its own valid credentials.
|
|
132
|
+
All three routes use HTTP/SSE.
|
|
133
|
+
|
|
134
|
+
Reasoning options stay native to the selected API and model:
|
|
135
|
+
|
|
136
|
+
| Model/API | Provider options |
|
|
137
|
+
| --------------------------- | --------------------------------------------------------------------------------------- |
|
|
138
|
+
| K3 Chat / Responses | `reasoningEffort: "low" \| "high" \| "max"`; default is `max` |
|
|
139
|
+
| K3 Messages | `effort: "low" \| "high" \| "max"`; default is `max` |
|
|
140
|
+
| K2.6 Chat | `thinking: { type: "enabled" \| "disabled", keep?: "all" \| null }`; default is enabled |
|
|
141
|
+
| K2.7 Code / high-speed Chat | Omit `thinking` to use always-on, preserved reasoning |
|
|
142
|
+
|
|
143
|
+
Omitting options preserves the model's defaults. K3 uses effort rather than the K2.x `thinking`
|
|
144
|
+
parameter. Known effort values have autocomplete while future strings remain accepted.
|
|
145
|
+
For K2.6, `thinking.keep: "all"` enables preservation of reasoning across user messages.
|
|
146
|
+
K3 and both K2.7 Code variants always preserve reasoning. Continue with the returned
|
|
147
|
+
`response.message` and matching tool results so reasoning content and any Messages signatures are retained.
|
|
148
|
+
Leave sampling options such as `temperature` unset to use these models' fixed defaults.
|
|
149
|
+
|
|
150
|
+
The recorded suite covers all three K3 APIs, default and explicit efforts, K2.6 thinking modes,
|
|
151
|
+
both K2.7 Code variants, generated tool loops with a subsequent user follow-up, required/disabled
|
|
152
|
+
tool choice, image-byte input, and native structured output through `http.body` overlays.
|
|
153
|
+
K3 Chat and Messages accept required and disabled tool choice. Responses supports automatic tool
|
|
154
|
+
choice only; explicit `required` and `none` produce a provider `InvalidRequest` error, also covered by recordings.
|
|
155
|
+
The provider targets the Moonshot Open Platform; Kimi Code is a separate product and endpoint.
|
|
156
|
+
|
|
157
|
+
Package entrypoints are `@opencode/ai/providers/moonshot`, `moonshot/chat`, `moonshot/messages`,
|
|
158
|
+
and `moonshot/responses`; each exports `model(modelID, settings)`.
|
|
159
|
+
|
|
32
160
|
## MiniMax
|
|
33
161
|
|
|
34
162
|
MiniMax defaults to its Messages API and reads `MINIMAX_API_KEY` when `apiKey` is omitted:
|
|
@@ -10,14 +10,19 @@ export declare const DEFAULT_BASE_URL = "https://api.anthropic.com/v1";
|
|
|
10
10
|
export declare const PATH = "/messages";
|
|
11
11
|
export declare const DEFAULT_MAX_TOKENS = 32000;
|
|
12
12
|
export declare const framing: Framing.Definition<string>;
|
|
13
|
+
export type ThinkingBlockBinding = {
|
|
14
|
+
readonly prefix_mismatch_behavior?: "error" | "drop_block" | (string & {});
|
|
15
|
+
};
|
|
13
16
|
export type ThinkingInput = {
|
|
14
17
|
readonly type: "adaptive";
|
|
15
18
|
readonly display?: "summarized" | "omitted";
|
|
19
|
+
readonly block_binding?: ThinkingBlockBinding;
|
|
16
20
|
} | {
|
|
17
21
|
readonly type: "disabled";
|
|
18
22
|
} | ({
|
|
19
23
|
readonly type: "enabled";
|
|
20
24
|
readonly display?: "summarized" | "omitted";
|
|
25
|
+
readonly block_binding?: ThinkingBlockBinding;
|
|
21
26
|
} & ({
|
|
22
27
|
readonly budgetTokens: number;
|
|
23
28
|
readonly budget_tokens?: number;
|
|
@@ -309,9 +314,15 @@ export declare const AnthropicMessagesBody: Schema.Struct<{
|
|
|
309
314
|
readonly type: Schema.tag<"enabled">;
|
|
310
315
|
readonly budget_tokens: Schema.Number;
|
|
311
316
|
readonly display: Schema.optional<Schema.Literals<readonly ["summarized", "omitted"]>>;
|
|
317
|
+
readonly block_binding: Schema.optional<Schema.Struct<{
|
|
318
|
+
readonly prefix_mismatch_behavior: Schema.optional<Schema.String>;
|
|
319
|
+
}>>;
|
|
312
320
|
}>, Schema.Struct<{
|
|
313
321
|
readonly type: Schema.tag<"adaptive">;
|
|
314
322
|
readonly display: Schema.optional<Schema.Literals<readonly ["summarized", "omitted"]>>;
|
|
323
|
+
readonly block_binding: Schema.optional<Schema.Struct<{
|
|
324
|
+
readonly prefix_mismatch_behavior: Schema.optional<Schema.String>;
|
|
325
|
+
}>>;
|
|
315
326
|
}>, Schema.Struct<{
|
|
316
327
|
readonly type: Schema.tag<"disabled">;
|
|
317
328
|
}>]>>;
|
|
@@ -556,9 +567,15 @@ export declare const protocol: Protocol<{
|
|
|
556
567
|
readonly type: "enabled";
|
|
557
568
|
readonly budget_tokens: number;
|
|
558
569
|
readonly display?: "summarized" | "omitted" | undefined;
|
|
570
|
+
readonly block_binding?: {
|
|
571
|
+
readonly prefix_mismatch_behavior?: string | undefined;
|
|
572
|
+
} | undefined;
|
|
559
573
|
} | {
|
|
560
574
|
readonly type: "adaptive";
|
|
561
575
|
readonly display?: "summarized" | "omitted" | undefined;
|
|
576
|
+
readonly block_binding?: {
|
|
577
|
+
readonly prefix_mismatch_behavior?: string | undefined;
|
|
578
|
+
} | undefined;
|
|
562
579
|
} | {
|
|
563
580
|
readonly type: "disabled";
|
|
564
581
|
} | undefined;
|
|
@@ -684,7 +701,7 @@ export declare const protocol: Protocol<{
|
|
|
684
701
|
reasoningSignatures: {};
|
|
685
702
|
lifecycle: Lifecycle.State;
|
|
686
703
|
}>;
|
|
687
|
-
export declare const transport: <Body extends Pick<AnthropicMessagesBody, "messages" | "context_management">>() => {
|
|
704
|
+
export declare const transport: <Body extends Pick<AnthropicMessagesBody, "messages" | "context_management" | "thinking">>() => {
|
|
688
705
|
prepare: (input: Parameters<(input: import("../route/transport/index.js").TransportPrepareInput<Body>) => Effect.Effect<HttpTransport.HttpPrepared<string>, AIError, never>>[0]) => Effect.Effect<HttpTransport.HttpPrepared<string>, AIError, never>;
|
|
689
706
|
with: (patch: Partial<HttpTransport.HttpJsonInput<Body, string>>) => HttpTransport.HttpJsonTransport<Body, string>;
|
|
690
707
|
id: string;
|
|
@@ -904,9 +921,15 @@ export declare const route: Route<{
|
|
|
904
921
|
readonly type: "enabled";
|
|
905
922
|
readonly budget_tokens: number;
|
|
906
923
|
readonly display?: "summarized" | "omitted" | undefined;
|
|
924
|
+
readonly block_binding?: {
|
|
925
|
+
readonly prefix_mismatch_behavior?: string | undefined;
|
|
926
|
+
} | undefined;
|
|
907
927
|
} | {
|
|
908
928
|
readonly type: "adaptive";
|
|
909
929
|
readonly display?: "summarized" | "omitted" | undefined;
|
|
930
|
+
readonly block_binding?: {
|
|
931
|
+
readonly prefix_mismatch_behavior?: string | undefined;
|
|
932
|
+
} | undefined;
|
|
910
933
|
} | {
|
|
911
934
|
readonly type: "disabled";
|
|
912
935
|
} | undefined;
|
|
@@ -202,15 +202,20 @@ const AnthropicToolChoice = Schema.Union([
|
|
|
202
202
|
disable_parallel_tool_use: Schema.optional(Schema.Boolean),
|
|
203
203
|
}),
|
|
204
204
|
]);
|
|
205
|
+
const AnthropicThinkingBlockBinding = Schema.Struct({
|
|
206
|
+
prefix_mismatch_behavior: Schema.optional(Schema.String),
|
|
207
|
+
});
|
|
205
208
|
const AnthropicThinking = Schema.Union([
|
|
206
209
|
Schema.Struct({
|
|
207
210
|
type: Schema.tag("enabled"),
|
|
208
211
|
budget_tokens: Schema.Number,
|
|
209
212
|
display: Schema.optional(Schema.Literals(["summarized", "omitted"])),
|
|
213
|
+
block_binding: Schema.optional(AnthropicThinkingBlockBinding),
|
|
210
214
|
}),
|
|
211
215
|
Schema.Struct({
|
|
212
216
|
type: Schema.tag("adaptive"),
|
|
213
217
|
display: Schema.optional(Schema.Literals(["summarized", "omitted"])),
|
|
218
|
+
block_binding: Schema.optional(AnthropicThinkingBlockBinding),
|
|
214
219
|
}),
|
|
215
220
|
Schema.Struct({
|
|
216
221
|
type: Schema.tag("disabled"),
|
|
@@ -843,8 +848,9 @@ const resolveOptions = Effect.fn("AnthropicMessages.resolveOptions")(function* (
|
|
|
843
848
|
...(outputConfigEffort === undefined ? {} : { effort: outputConfigEffort }),
|
|
844
849
|
...(outputConfigFormat === undefined ? {} : { format: outputConfigFormat }),
|
|
845
850
|
};
|
|
851
|
+
const thinking = yield* resolveThinking(input?.thinking);
|
|
846
852
|
return {
|
|
847
|
-
thinking:
|
|
853
|
+
thinking: applyThinkingBindingDefault(request.model, thinking),
|
|
848
854
|
effort: outputConfigEffort,
|
|
849
855
|
output_config,
|
|
850
856
|
service_tier,
|
|
@@ -854,18 +860,44 @@ const resolveOptions = Effect.fn("AnthropicMessages.resolveOptions")(function* (
|
|
|
854
860
|
cache_control,
|
|
855
861
|
};
|
|
856
862
|
});
|
|
863
|
+
const supportsThinkingBlockBinding = (model) => {
|
|
864
|
+
const override = model.compatibility?.supportsThinkingBlockBinding;
|
|
865
|
+
if (override !== undefined)
|
|
866
|
+
return override;
|
|
867
|
+
// Accept gateway namespaces and Vertex suffixes without treating a snapshot date as a minor version.
|
|
868
|
+
const version = /(?:^|[./])claude-[a-z]+-(?<major>\d+)(?:[.-](?<minor>\d{1,2}))?(?:$|[-:@])/i.exec(model.id)?.groups;
|
|
869
|
+
if (!version)
|
|
870
|
+
return false;
|
|
871
|
+
const major = Number(version.major);
|
|
872
|
+
const minor = Number(version.minor ?? 0);
|
|
873
|
+
return major > 5 || (major === 5 && minor >= 1);
|
|
874
|
+
};
|
|
875
|
+
const applyThinkingBindingDefault = (model, thinking) => {
|
|
876
|
+
if (thinking?.type === "disabled")
|
|
877
|
+
return thinking;
|
|
878
|
+
if (!supportsThinkingBlockBinding(model))
|
|
879
|
+
return thinking;
|
|
880
|
+
return {
|
|
881
|
+
...(thinking ?? { type: "adaptive" }),
|
|
882
|
+
block_binding: {
|
|
883
|
+
prefix_mismatch_behavior: "drop_block",
|
|
884
|
+
...thinking?.block_binding,
|
|
885
|
+
},
|
|
886
|
+
};
|
|
887
|
+
};
|
|
857
888
|
const resolveThinking = Effect.fn("AnthropicMessages.resolveThinking")(function* (input) {
|
|
858
889
|
if (!ProviderShared.isRecord(input))
|
|
859
890
|
return undefined;
|
|
891
|
+
if (input.type === "disabled")
|
|
892
|
+
return { type: "disabled" };
|
|
893
|
+
if (input.type !== "adaptive" && input.type !== "enabled")
|
|
894
|
+
return undefined;
|
|
895
|
+
const block_binding = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(Schema.UndefinedOr(AnthropicThinkingBlockBinding)))(input.block_binding);
|
|
860
896
|
const display = input.display === "summarized" || input.display === "omitted"
|
|
861
897
|
? input.display
|
|
862
898
|
: undefined;
|
|
863
899
|
if (input.type === "adaptive")
|
|
864
|
-
return { type: "adaptive",
|
|
865
|
-
if (input.type === "disabled")
|
|
866
|
-
return { type: "disabled" };
|
|
867
|
-
if (input.type !== "enabled")
|
|
868
|
-
return undefined;
|
|
900
|
+
return { type: "adaptive", display, block_binding };
|
|
869
901
|
const budget = typeof input.budgetTokens === "number"
|
|
870
902
|
? input.budgetTokens
|
|
871
903
|
: typeof input.budget_tokens === "number"
|
|
@@ -873,7 +905,7 @@ const resolveThinking = Effect.fn("AnthropicMessages.resolveThinking")(function*
|
|
|
873
905
|
: undefined;
|
|
874
906
|
if (budget === undefined)
|
|
875
907
|
return yield* ProviderShared.invalidRequest("Anthropic thinking provider option requires budgetTokens");
|
|
876
|
-
return { type: "enabled", budget_tokens: budget,
|
|
908
|
+
return { type: "enabled", budget_tokens: budget, display, block_binding };
|
|
877
909
|
});
|
|
878
910
|
const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (request) {
|
|
879
911
|
const management = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(Schema.UndefinedOr(ContextManagement)))(request.providerOptions?.contextManagement);
|
|
@@ -1378,15 +1410,15 @@ export const transport = () => {
|
|
|
1378
1410
|
return {
|
|
1379
1411
|
...http,
|
|
1380
1412
|
prepare: (input) => {
|
|
1381
|
-
|
|
1382
|
-
|
|
1413
|
+
const requiredBetas = requiredBetaHeaders(input.body);
|
|
1414
|
+
if (requiredBetas.length === 0)
|
|
1383
1415
|
return http.prepare(input);
|
|
1384
1416
|
const headers = Headers.fromInput(input.request.http?.headers);
|
|
1385
|
-
const
|
|
1417
|
+
const existingBetas = (headers["anthropic-beta"] ?? "")
|
|
1386
1418
|
.split(",")
|
|
1387
1419
|
.map((item) => item.trim())
|
|
1388
|
-
.filter(Boolean)
|
|
1389
|
-
betas
|
|
1420
|
+
.filter(Boolean);
|
|
1421
|
+
const betas = new Set([...existingBetas, ...requiredBetas]);
|
|
1390
1422
|
return http.prepare({
|
|
1391
1423
|
...input,
|
|
1392
1424
|
request: LLMRequest.update(input.request, {
|
|
@@ -1399,6 +1431,17 @@ export const transport = () => {
|
|
|
1399
1431
|
},
|
|
1400
1432
|
};
|
|
1401
1433
|
};
|
|
1434
|
+
function requiredBetaHeaders(body) {
|
|
1435
|
+
const betas = [];
|
|
1436
|
+
const requestsCompaction = (body.context_management?.edits.length ?? 0) > 0;
|
|
1437
|
+
const replaysCompaction = body.messages.some((message) => message.content.some((block) => block.type === "compaction"));
|
|
1438
|
+
if (requestsCompaction || replaysCompaction)
|
|
1439
|
+
betas.push("compact-2026-01-12");
|
|
1440
|
+
const thinking = body.thinking;
|
|
1441
|
+
if (thinking && thinking.type !== "disabled" && thinking.block_binding)
|
|
1442
|
+
betas.push("thinking-binding-controls-2026-08-01");
|
|
1443
|
+
return betas;
|
|
1444
|
+
}
|
|
1402
1445
|
export const route = Route.make({
|
|
1403
1446
|
id: ADAPTER,
|
|
1404
1447
|
provider: "anthropic",
|
|
@@ -219,9 +219,15 @@ export declare const protocol: Protocol<{
|
|
|
219
219
|
readonly type: "enabled";
|
|
220
220
|
readonly budget_tokens: number;
|
|
221
221
|
readonly display?: "summarized" | "omitted" | undefined;
|
|
222
|
+
readonly block_binding?: {
|
|
223
|
+
readonly prefix_mismatch_behavior?: string | undefined;
|
|
224
|
+
} | undefined;
|
|
222
225
|
} | {
|
|
223
226
|
readonly type: "adaptive";
|
|
224
227
|
readonly display?: "summarized" | "omitted" | undefined;
|
|
228
|
+
readonly block_binding?: {
|
|
229
|
+
readonly prefix_mismatch_behavior?: string | undefined;
|
|
230
|
+
} | undefined;
|
|
225
231
|
} | {
|
|
226
232
|
readonly type: "disabled";
|
|
227
233
|
} | undefined;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { Protocol } from "../route/protocol.js";
|
|
2
|
+
import { OpenAIChat } from "./openai-chat.js";
|
|
3
|
+
export type ReasoningEffort = "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" | (string & {});
|
|
4
|
+
export type OptionsInput = {
|
|
5
|
+
readonly reasoningEffort?: ReasoningEffort;
|
|
6
|
+
readonly thinking?: {
|
|
7
|
+
readonly type?: "enabled" | "disabled" | (string & {});
|
|
8
|
+
/** False retains historical reasoning; omission preserves the endpoint's default. */
|
|
9
|
+
readonly clear_thinking?: boolean;
|
|
10
|
+
};
|
|
11
|
+
readonly toolStream?: boolean;
|
|
12
|
+
readonly doSample?: boolean;
|
|
13
|
+
readonly responseFormat?: {
|
|
14
|
+
readonly type: "text" | "json_object" | (string & {});
|
|
15
|
+
};
|
|
16
|
+
readonly requestID?: string;
|
|
17
|
+
readonly userID?: string;
|
|
18
|
+
};
|
|
19
|
+
export declare const compatibility: {
|
|
20
|
+
maxTokensField: "max_tokens";
|
|
21
|
+
supportsStore: false;
|
|
22
|
+
supportsStrictMode: false;
|
|
23
|
+
reasoningField: string;
|
|
24
|
+
zaiToolStream: false;
|
|
25
|
+
};
|
|
26
|
+
export declare const protocol: Protocol<{
|
|
27
|
+
readonly model: string;
|
|
28
|
+
readonly messages: readonly ({
|
|
29
|
+
readonly role: "system";
|
|
30
|
+
readonly content: string | readonly ({
|
|
31
|
+
readonly type: "text";
|
|
32
|
+
readonly text: string;
|
|
33
|
+
readonly cache_control?: {
|
|
34
|
+
readonly type: "ephemeral";
|
|
35
|
+
readonly ttl?: string | undefined;
|
|
36
|
+
} | undefined;
|
|
37
|
+
} | {
|
|
38
|
+
readonly type: "image_url";
|
|
39
|
+
readonly image_url: {
|
|
40
|
+
readonly url: string;
|
|
41
|
+
};
|
|
42
|
+
})[];
|
|
43
|
+
} | {
|
|
44
|
+
readonly role: "user";
|
|
45
|
+
readonly content: string | readonly ({
|
|
46
|
+
readonly type: "text";
|
|
47
|
+
readonly text: string;
|
|
48
|
+
readonly cache_control?: {
|
|
49
|
+
readonly type: "ephemeral";
|
|
50
|
+
readonly ttl?: string | undefined;
|
|
51
|
+
} | undefined;
|
|
52
|
+
} | {
|
|
53
|
+
readonly type: "image_url";
|
|
54
|
+
readonly image_url: {
|
|
55
|
+
readonly url: string;
|
|
56
|
+
};
|
|
57
|
+
})[];
|
|
58
|
+
} | {
|
|
59
|
+
readonly [x: string]: unknown;
|
|
60
|
+
readonly content: string | null;
|
|
61
|
+
readonly role: "assistant";
|
|
62
|
+
readonly reasoning?: string | undefined;
|
|
63
|
+
readonly reasoning_content?: string | undefined;
|
|
64
|
+
readonly reasoning_text?: string | undefined;
|
|
65
|
+
readonly cache_control?: {
|
|
66
|
+
readonly type: "ephemeral";
|
|
67
|
+
readonly ttl?: string | undefined;
|
|
68
|
+
} | undefined;
|
|
69
|
+
readonly tool_calls?: readonly {
|
|
70
|
+
readonly id: string;
|
|
71
|
+
readonly type: "function";
|
|
72
|
+
readonly function: {
|
|
73
|
+
readonly name: string;
|
|
74
|
+
readonly arguments: string;
|
|
75
|
+
};
|
|
76
|
+
}[] | undefined;
|
|
77
|
+
readonly reasoning_details?: unknown;
|
|
78
|
+
} | {
|
|
79
|
+
readonly content: string;
|
|
80
|
+
readonly role: "tool";
|
|
81
|
+
readonly tool_call_id: string;
|
|
82
|
+
readonly cache_control?: {
|
|
83
|
+
readonly type: "ephemeral";
|
|
84
|
+
readonly ttl?: string | undefined;
|
|
85
|
+
} | undefined;
|
|
86
|
+
})[];
|
|
87
|
+
readonly stream: true;
|
|
88
|
+
readonly max_completion_tokens?: number | undefined;
|
|
89
|
+
readonly max_tokens?: number | undefined;
|
|
90
|
+
readonly tools?: readonly {
|
|
91
|
+
readonly function: {
|
|
92
|
+
readonly description: string;
|
|
93
|
+
readonly name: string;
|
|
94
|
+
readonly parameters: {
|
|
95
|
+
readonly [x: string]: unknown;
|
|
96
|
+
};
|
|
97
|
+
readonly strict?: boolean | undefined;
|
|
98
|
+
};
|
|
99
|
+
readonly type: "function";
|
|
100
|
+
readonly cache_control?: {
|
|
101
|
+
readonly type: "ephemeral";
|
|
102
|
+
readonly ttl?: string | undefined;
|
|
103
|
+
} | undefined;
|
|
104
|
+
}[] | undefined;
|
|
105
|
+
readonly stop?: readonly string[] | undefined;
|
|
106
|
+
readonly temperature?: number | undefined;
|
|
107
|
+
readonly seed?: number | undefined;
|
|
108
|
+
readonly thinking?: {
|
|
109
|
+
readonly type?: string | undefined;
|
|
110
|
+
readonly clear_thinking?: boolean | undefined;
|
|
111
|
+
} | undefined;
|
|
112
|
+
readonly user_id?: string | undefined;
|
|
113
|
+
readonly tool_choice?: "required" | "auto" | "none" | {
|
|
114
|
+
readonly type: "function";
|
|
115
|
+
readonly function: {
|
|
116
|
+
readonly name: string;
|
|
117
|
+
};
|
|
118
|
+
} | undefined;
|
|
119
|
+
readonly top_p?: number | undefined;
|
|
120
|
+
readonly frequency_penalty?: number | undefined;
|
|
121
|
+
readonly presence_penalty?: number | undefined;
|
|
122
|
+
readonly prompt_cache_key?: string | undefined;
|
|
123
|
+
readonly reasoning_effort?: import("./utils/open-responses-options.js").ReasoningEffort | undefined;
|
|
124
|
+
readonly store?: boolean | undefined;
|
|
125
|
+
readonly stream_options?: {
|
|
126
|
+
readonly include_usage: boolean;
|
|
127
|
+
} | undefined;
|
|
128
|
+
readonly tool_stream?: boolean | undefined;
|
|
129
|
+
readonly response_format?: {
|
|
130
|
+
readonly type: string;
|
|
131
|
+
} | undefined;
|
|
132
|
+
readonly do_sample?: boolean | undefined;
|
|
133
|
+
readonly request_id?: string | undefined;
|
|
134
|
+
}, string, "[DONE]" | {
|
|
135
|
+
readonly [x: string]: unknown;
|
|
136
|
+
readonly error?: {
|
|
137
|
+
readonly [x: string]: unknown;
|
|
138
|
+
readonly message: string;
|
|
139
|
+
readonly code?: string | number | null | undefined;
|
|
140
|
+
} | null | undefined;
|
|
141
|
+
readonly usage?: {
|
|
142
|
+
readonly [x: string]: unknown;
|
|
143
|
+
readonly cached_tokens?: number | null | undefined;
|
|
144
|
+
readonly prompt_tokens?: number | null | undefined;
|
|
145
|
+
readonly completion_tokens?: number | null | undefined;
|
|
146
|
+
readonly total_tokens?: number | null | undefined;
|
|
147
|
+
readonly prompt_tokens_details?: {
|
|
148
|
+
readonly [x: string]: unknown;
|
|
149
|
+
readonly cached_tokens?: number | null | undefined;
|
|
150
|
+
readonly cache_write_tokens?: number | null | undefined;
|
|
151
|
+
} | null | undefined;
|
|
152
|
+
readonly prompt_cache_hit_tokens?: number | null | undefined;
|
|
153
|
+
readonly completion_tokens_details?: {
|
|
154
|
+
readonly [x: string]: unknown;
|
|
155
|
+
readonly reasoning_tokens?: number | null | undefined;
|
|
156
|
+
readonly accepted_prediction_tokens?: number | null | undefined;
|
|
157
|
+
readonly rejected_prediction_tokens?: number | null | undefined;
|
|
158
|
+
} | null | undefined;
|
|
159
|
+
} | null | undefined;
|
|
160
|
+
readonly choices?: readonly {
|
|
161
|
+
readonly [x: string]: unknown;
|
|
162
|
+
readonly delta?: {
|
|
163
|
+
readonly [x: string]: unknown;
|
|
164
|
+
readonly reasoning?: string | null | undefined;
|
|
165
|
+
readonly reasoning_content?: string | null | undefined;
|
|
166
|
+
readonly reasoning_text?: string | null | undefined;
|
|
167
|
+
readonly content?: string | null | undefined;
|
|
168
|
+
readonly refusal?: string | null | undefined;
|
|
169
|
+
readonly tool_calls?: readonly {
|
|
170
|
+
readonly function?: {
|
|
171
|
+
readonly name?: string | null | undefined;
|
|
172
|
+
readonly arguments?: string | null | undefined;
|
|
173
|
+
} | null | undefined;
|
|
174
|
+
readonly id?: string | null | undefined;
|
|
175
|
+
readonly index?: number | null | undefined;
|
|
176
|
+
}[] | null | undefined;
|
|
177
|
+
readonly reasoning_details?: unknown;
|
|
178
|
+
} | null | undefined;
|
|
179
|
+
readonly usage?: {
|
|
180
|
+
readonly [x: string]: unknown;
|
|
181
|
+
readonly cached_tokens?: number | null | undefined;
|
|
182
|
+
readonly prompt_tokens?: number | null | undefined;
|
|
183
|
+
readonly completion_tokens?: number | null | undefined;
|
|
184
|
+
readonly total_tokens?: number | null | undefined;
|
|
185
|
+
readonly prompt_tokens_details?: {
|
|
186
|
+
readonly [x: string]: unknown;
|
|
187
|
+
readonly cached_tokens?: number | null | undefined;
|
|
188
|
+
readonly cache_write_tokens?: number | null | undefined;
|
|
189
|
+
} | null | undefined;
|
|
190
|
+
readonly prompt_cache_hit_tokens?: number | null | undefined;
|
|
191
|
+
readonly completion_tokens_details?: {
|
|
192
|
+
readonly [x: string]: unknown;
|
|
193
|
+
readonly reasoning_tokens?: number | null | undefined;
|
|
194
|
+
readonly accepted_prediction_tokens?: number | null | undefined;
|
|
195
|
+
readonly rejected_prediction_tokens?: number | null | undefined;
|
|
196
|
+
} | null | undefined;
|
|
197
|
+
} | null | undefined;
|
|
198
|
+
readonly finish_reason?: string | null | undefined;
|
|
199
|
+
readonly native_finish_reason?: string | null | undefined;
|
|
200
|
+
}[] | null | undefined;
|
|
201
|
+
}, OpenAIChat.ParserState>;
|
|
202
|
+
export * as ZAIChat from "./zai-chat.js";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect";
|
|
2
|
+
import { Protocol } from "../route/protocol.js";
|
|
3
|
+
import { OpenAIChat } from "./openai-chat.js";
|
|
4
|
+
import { ProviderShared } from "./shared.js";
|
|
5
|
+
const Options = Schema.Struct({
|
|
6
|
+
reasoningEffort: Schema.optional(Schema.String),
|
|
7
|
+
thinking: Schema.optional(Schema.Struct({ type: Schema.optional(Schema.String), clear_thinking: Schema.optional(Schema.Boolean) })),
|
|
8
|
+
toolStream: Schema.optional(Schema.Boolean),
|
|
9
|
+
doSample: Schema.optional(Schema.Boolean),
|
|
10
|
+
responseFormat: Schema.optional(Schema.Struct({ type: Schema.String })),
|
|
11
|
+
requestID: Schema.optional(Schema.String),
|
|
12
|
+
userID: Schema.optional(Schema.String),
|
|
13
|
+
});
|
|
14
|
+
const Body = Schema.Struct({
|
|
15
|
+
...OpenAIChat.bodyFields,
|
|
16
|
+
thinking: Options.fields.thinking,
|
|
17
|
+
do_sample: Options.fields.doSample,
|
|
18
|
+
response_format: Options.fields.responseFormat,
|
|
19
|
+
request_id: Options.fields.requestID,
|
|
20
|
+
user_id: Options.fields.userID,
|
|
21
|
+
});
|
|
22
|
+
const fromRequest = Effect.fn("ZAIChat.fromRequest")(function* (request) {
|
|
23
|
+
const options = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(Options))(request.providerOptions ?? {});
|
|
24
|
+
const body = yield* OpenAIChat.protocol.body.from(request);
|
|
25
|
+
return {
|
|
26
|
+
...body,
|
|
27
|
+
thinking: options.thinking,
|
|
28
|
+
// Tool streaming was introduced in GLM-4.6; older models must not receive the opt-in.
|
|
29
|
+
tool_stream: options.toolStream ??
|
|
30
|
+
(body.tools?.length && /^glm-(?:4\.[67]|5(?:[.-]|$))/i.test(request.model.id) ? true : undefined),
|
|
31
|
+
do_sample: options.doSample,
|
|
32
|
+
response_format: options.responseFormat,
|
|
33
|
+
request_id: options.requestID,
|
|
34
|
+
user_id: options.userID,
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
export const compatibility = {
|
|
38
|
+
maxTokensField: "max_tokens",
|
|
39
|
+
supportsStore: false,
|
|
40
|
+
supportsStrictMode: false,
|
|
41
|
+
reasoningField: "reasoning_content",
|
|
42
|
+
zaiToolStream: false,
|
|
43
|
+
};
|
|
44
|
+
export const protocol = Protocol.make({
|
|
45
|
+
id: "zai-chat",
|
|
46
|
+
body: { schema: Body, from: fromRequest },
|
|
47
|
+
stream: OpenAIChat.protocol.stream,
|
|
48
|
+
});
|
|
49
|
+
export * as ZAIChat from "./zai-chat.js";
|