@opencode/ai 0.0.0-dev-19297 → 0.0.0-dev-19298

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.
@@ -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: yield* resolveThinking(input?.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", ...(display === undefined ? {} : { display }) };
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, ...(display === undefined ? {} : { display }) };
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
- if (!input.body.context_management?.edits.length &&
1382
- !input.body.messages.some((message) => message.content.some((block) => block.type === "compaction")))
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 betas = new Set((headers["anthropic-beta"] ?? "")
1417
+ const existingBetas = (headers["anthropic-beta"] ?? "")
1386
1418
  .split(",")
1387
1419
  .map((item) => item.trim())
1388
- .filter(Boolean));
1389
- betas.add("compact-2026-01-12");
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;
@@ -237,9 +237,15 @@ export declare const routes: import("../route/client.js").Route<{
237
237
  readonly type: "enabled";
238
238
  readonly budget_tokens: number;
239
239
  readonly display?: "summarized" | "omitted" | undefined;
240
+ readonly block_binding?: {
241
+ readonly prefix_mismatch_behavior?: string | undefined;
242
+ } | undefined;
240
243
  } | {
241
244
  readonly type: "adaptive";
242
245
  readonly display?: "summarized" | "omitted" | undefined;
246
+ readonly block_binding?: {
247
+ readonly prefix_mismatch_behavior?: string | undefined;
248
+ } | undefined;
243
249
  } | {
244
250
  readonly type: "disabled";
245
251
  } | undefined;
@@ -221,9 +221,15 @@ export declare const routes: import("../route/client.js").Route<{
221
221
  readonly type: "enabled";
222
222
  readonly budget_tokens: number;
223
223
  readonly display?: "summarized" | "omitted" | undefined;
224
+ readonly block_binding?: {
225
+ readonly prefix_mismatch_behavior?: string | undefined;
226
+ } | undefined;
224
227
  } | {
225
228
  readonly type: "adaptive";
226
229
  readonly display?: "summarized" | "omitted" | undefined;
230
+ readonly block_binding?: {
231
+ readonly prefix_mismatch_behavior?: string | undefined;
232
+ } | undefined;
227
233
  } | {
228
234
  readonly type: "disabled";
229
235
  } | undefined;
@@ -235,9 +235,15 @@ export declare const routes: Route<{
235
235
  readonly type: "enabled";
236
236
  readonly budget_tokens: number;
237
237
  readonly display?: "summarized" | "omitted" | undefined;
238
+ readonly block_binding?: {
239
+ readonly prefix_mismatch_behavior?: string | undefined;
240
+ } | undefined;
238
241
  } | {
239
242
  readonly type: "adaptive";
240
243
  readonly display?: "summarized" | "omitted" | undefined;
244
+ readonly block_binding?: {
245
+ readonly prefix_mismatch_behavior?: string | undefined;
246
+ } | undefined;
241
247
  } | {
242
248
  readonly type: "disabled";
243
249
  } | undefined;
@@ -545,9 +545,15 @@ export declare const routes: (Route<{
545
545
  readonly type: "enabled";
546
546
  readonly budget_tokens: number;
547
547
  readonly display?: "summarized" | "omitted" | undefined;
548
+ readonly block_binding?: {
549
+ readonly prefix_mismatch_behavior?: string | undefined;
550
+ } | undefined;
548
551
  } | {
549
552
  readonly type: "adaptive";
550
553
  readonly display?: "summarized" | "omitted" | undefined;
554
+ readonly block_binding?: {
555
+ readonly prefix_mismatch_behavior?: string | undefined;
556
+ } | undefined;
551
557
  } | {
552
558
  readonly type: "disabled";
553
559
  } | undefined;
@@ -248,9 +248,15 @@ export declare const routes: (Route<{
248
248
  readonly type: "enabled";
249
249
  readonly budget_tokens: number;
250
250
  readonly display?: "summarized" | "omitted" | undefined;
251
+ readonly block_binding?: {
252
+ readonly prefix_mismatch_behavior?: string | undefined;
253
+ } | undefined;
251
254
  } | {
252
255
  readonly type: "adaptive";
253
256
  readonly display?: "summarized" | "omitted" | undefined;
257
+ readonly block_binding?: {
258
+ readonly prefix_mismatch_behavior?: string | undefined;
259
+ } | undefined;
254
260
  } | {
255
261
  readonly type: "disabled";
256
262
  } | undefined;
@@ -246,9 +246,15 @@ export declare const routes: (Route<{
246
246
  readonly type: "enabled";
247
247
  readonly budget_tokens: number;
248
248
  readonly display?: "summarized" | "omitted" | undefined;
249
+ readonly block_binding?: {
250
+ readonly prefix_mismatch_behavior?: string | undefined;
251
+ } | undefined;
249
252
  } | {
250
253
  readonly type: "adaptive";
251
254
  readonly display?: "summarized" | "omitted" | undefined;
255
+ readonly block_binding?: {
256
+ readonly prefix_mismatch_behavior?: string | undefined;
257
+ } | undefined;
252
258
  } | {
253
259
  readonly type: "disabled";
254
260
  } | undefined;
@@ -82,6 +82,8 @@ declare const LanguageModelCompatibility_base: Schema.Class<LanguageModelCompati
82
82
  readonly supportsStrictMode: Schema.optional<Schema.Boolean>;
83
83
  readonly zaiToolStream: Schema.optional<Schema.Boolean>;
84
84
  readonly requireSignature: Schema.optional<Schema.Boolean>;
85
+ /** Supports Anthropic's thinking-prefix mismatch controls. Overrides model-ID detection. */
86
+ readonly supportsThinkingBlockBinding: Schema.optional<Schema.Boolean>;
85
87
  }>, {}>;
86
88
  export declare class LanguageModelCompatibility extends LanguageModelCompatibility_base {
87
89
  }
@@ -109,6 +109,8 @@ export class LanguageModelCompatibility extends Schema.Class("LLM.LanguageModelC
109
109
  supportsStrictMode: Schema.optional(Schema.Boolean),
110
110
  zaiToolStream: Schema.optional(Schema.Boolean),
111
111
  requireSignature: Schema.optional(Schema.Boolean),
112
+ /** Supports Anthropic's thinking-prefix mismatch controls. Overrides model-ID detection. */
113
+ supportsThinkingBlockBinding: Schema.optional(Schema.Boolean),
112
114
  }) {
113
115
  }
114
116
  (function (LanguageModelCompatibility) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "0.0.0-dev-19297",
3
+ "version": "0.0.0-dev-19298",
4
4
  "name": "@opencode/ai",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  "devDependencies": {
31
31
  "@clack/prompts": "1.0.0-alpha.1",
32
32
  "@effect/platform-node": "4.0.0-rc.112",
33
- "@opencode/http-recorder": "0.0.0-dev-19297",
33
+ "@opencode/http-recorder": "0.0.0-dev-19298",
34
34
  "@tsconfig/bun": "1.0.9",
35
35
  "@types/bun": "1.4.0",
36
36
  "@typescript/native-preview": "7.0.0-dev.20251207.1",
@@ -40,7 +40,7 @@
40
40
  "@aws-sdk/credential-providers": "3.1057.0",
41
41
  "@smithy/eventstream-codec": "4.2.14",
42
42
  "@smithy/util-utf8": "4.2.2",
43
- "@opencode/schema": "0.0.0-dev-19297",
43
+ "@opencode/schema": "0.0.0-dev-19298",
44
44
  "aws4fetch": "1.0.20",
45
45
  "effect": "4.0.0-rc.112",
46
46
  "google-auth-library": "10.5.0"