@opencode/ai 0.0.0-beta-19296 → 0.0.0-beta-19378

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.
@@ -0,0 +1,80 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { Protocol } from "../route/protocol.js";
3
+ import { OpenResponses } from "./open-responses.js";
4
+ import { JsonObject, optionalArray, ProviderShared } from "./shared.js";
5
+ import { OpenResponsesOptions } from "./utils/open-responses-options.js";
6
+ import { ResponsesHostedTools } from "./utils/responses-hosted-tools.js";
7
+ const Options = Schema.Struct({
8
+ reasoningEffort: OpenResponsesOptions.Options.fields.reasoningEffort,
9
+ enableThinking: Schema.optional(Schema.Boolean),
10
+ store: OpenResponsesOptions.Options.fields.store,
11
+ previousResponseId: Schema.optional(Schema.String),
12
+ conversation: Schema.optional(Schema.String),
13
+ });
14
+ const NativeTool = Schema.Struct({ type: Schema.Literals(["web_search", "web_extractor", "code_interpreter"]) });
15
+ const WebExtractorItem = Schema.StructWithRest(Schema.Struct({
16
+ type: Schema.Literal("web_extractor_call"),
17
+ id: Schema.String,
18
+ urls: Schema.optional(Schema.Array(Schema.String)),
19
+ goal: Schema.optional(Schema.String),
20
+ }), [JsonObject]);
21
+ const Body = Schema.Struct({
22
+ ...OpenResponses.coreFields,
23
+ input: Schema.Array(Schema.Union([OpenResponses.InputItem, WebExtractorItem])),
24
+ tools: optionalArray(Schema.Union([OpenResponses.Tool, NativeTool])),
25
+ enable_thinking: Options.fields.enableThinking,
26
+ previous_response_id: Options.fields.previousResponseId,
27
+ conversation: Options.fields.conversation,
28
+ stream: Schema.Literal(true),
29
+ });
30
+ const adapter = {
31
+ id: "alibaba-responses",
32
+ name: "Alibaba Responses",
33
+ nativeTool: (native) => ProviderShared.validateWith(Schema.decodeUnknownEffect(NativeTool))(native.alibaba),
34
+ restoreHostedToolItem: (item) => (Schema.is(WebExtractorItem)(item) ? item : undefined),
35
+ };
36
+ const tools = {
37
+ web_search_call: { name: "web_search", input: (item) => item.action ?? {} },
38
+ code_interpreter_call: { name: "code_interpreter", input: (item) => ({ code: item.code }) },
39
+ };
40
+ export const protocol = Protocol.make({
41
+ id: adapter.id,
42
+ body: {
43
+ schema: Body,
44
+ from: Effect.fn("AlibabaResponses.fromRequest")(function* (req) {
45
+ const opts = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(Options))(req.providerOptions ?? {});
46
+ const body = yield* OpenResponses.fromRequestWithAdapter(req, adapter);
47
+ const choice = body.tool_choice;
48
+ return yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(Body))({
49
+ ...body,
50
+ enable_thinking: opts.enableThinking,
51
+ previous_response_id: opts.previousResponseId,
52
+ conversation: opts.conversation,
53
+ // Model Studio expresses named selection through allowed_tools.
54
+ tool_choice: typeof choice === "object" && choice.type === "function"
55
+ ? { type: "allowed_tools", mode: "required", tools: [choice] }
56
+ : choice,
57
+ });
58
+ }),
59
+ },
60
+ stream: {
61
+ event: OpenResponses.protocol.stream.event,
62
+ initial: (req) => OpenResponses.initial(req, adapter),
63
+ step: (state, input) => Effect.gen(function* () {
64
+ const event = OpenResponses.normalize(state, input);
65
+ if (event.type !== "response.output_item.done" || !event.item)
66
+ return yield* OpenResponses.step(state, event);
67
+ if (event.item.type === "web_extractor_call") {
68
+ const item = yield* Schema.decodeUnknownEffect(WebExtractorItem)(event.item).pipe(Effect.mapError((cause) => ProviderShared.eventError(adapter.id, "Alibaba returned an invalid web extraction item", ProviderShared.encodeJson(event), cause)));
69
+ return yield* ResponsesHostedTools.onDone(state, item, {
70
+ web_extractor_call: { name: "web_extractor", input: () => ({ urls: item.urls, goal: item.goal }) },
71
+ });
72
+ }
73
+ if (ResponsesHostedTools.isItem(event.item, tools))
74
+ return yield* ResponsesHostedTools.onDone(state, event.item, tools);
75
+ return yield* OpenResponses.step(state, event);
76
+ }),
77
+ terminal: OpenResponses.terminal,
78
+ },
79
+ });
80
+ export * as AlibabaResponses from "./alibaba-responses.js";
@@ -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;
@@ -656,6 +656,9 @@ export type NormalizedEvent = Event & {
656
656
  export interface ProviderAdapter {
657
657
  readonly id: string;
658
658
  readonly name: string;
659
+ readonly nativeTool?: (native: NonNullable<ToolDefinition["native"]>) => Effect.Effect<{
660
+ readonly type: string;
661
+ }, AIError>;
659
662
  readonly lowerMedia?: (input: {
660
663
  readonly part: MediaPart;
661
664
  readonly media: ProviderShared.NormalizedMedia;
@@ -750,13 +753,7 @@ export declare const fromRequestWithAdapter: (request: LLMRequest<import("../sch
750
753
  readonly [x: string]: unknown;
751
754
  }, import("../route.js").CompactionOperations | undefined>>, adapter: ProviderAdapter) => Effect.Effect<{
752
755
  tools: {
753
- type: "function";
754
- name: string;
755
- description: string;
756
- parameters: {
757
- readonly [x: string]: unknown;
758
- };
759
- strict: boolean;
756
+ readonly type: string;
760
757
  }[] | undefined;
761
758
  tool_choice: "required" | "auto" | "none" | {
762
759
  type: "allowed_tools";
@@ -597,7 +597,9 @@ export const fromRequestWithAdapter = Effect.fn("OpenResponses.fromRequestWithAd
597
597
  ...lowerGeneration(request),
598
598
  tools: projected.tools.length === 0
599
599
  ? undefined
600
- : yield* Effect.forEach(projected.tools, (tool) => lowerTool(adapter.name, tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema, toolSchemaCompatibility))),
600
+ : yield* Effect.forEach(projected.tools, (tool) => tool.native !== undefined && adapter.nativeTool
601
+ ? adapter.nativeTool(tool.native)
602
+ : lowerTool(adapter.name, tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema, toolSchemaCompatibility))),
601
603
  tool_choice: allowedToolChoice(request) ??
602
604
  (request.toolChoice ? yield* lowerToolChoice(adapter.name, request.toolChoice) : undefined),
603
605
  };
@@ -0,0 +1 @@
1
+ export { model, type Settings } from "../alibaba.js";
@@ -0,0 +1 @@
1
+ export { model } from "../alibaba.js";
@@ -0,0 +1,3 @@
1
+ import type { Alibaba } from "../alibaba.js";
2
+ export { messagesModel as model } from "../alibaba.js";
3
+ export type Settings = Alibaba.Settings<Alibaba.MessagesOptionsInput>;
@@ -0,0 +1 @@
1
+ export { messagesModel as model } from "../alibaba.js";
@@ -0,0 +1,3 @@
1
+ import type { Alibaba } from "../alibaba.js";
2
+ export { responsesModel as model } from "../alibaba.js";
3
+ export type Settings = Alibaba.Settings<Alibaba.ResponsesOptionsInput>;
@@ -0,0 +1 @@
1
+ export { responsesModel as model } from "../alibaba.js";