@opencode-ai/ai 0.0.0-beta-18050 → 0.0.0-beta-18138

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.
Files changed (39) hide show
  1. package/dist/protocols/anthropic-messages.d.ts +259 -17
  2. package/dist/protocols/anthropic-messages.js +337 -24
  3. package/dist/protocols/gemini.d.ts +4 -31
  4. package/dist/protocols/gemini.js +23 -4
  5. package/dist/protocols/open-responses.d.ts +8 -4
  6. package/dist/protocols/open-responses.js +73 -38
  7. package/dist/protocols/openai-chat.d.ts +25 -11
  8. package/dist/protocols/openai-chat.js +124 -8
  9. package/dist/protocols/openai-compatible-chat.d.ts +3 -1
  10. package/dist/protocols/openai-compatible-responses.d.ts +1 -1
  11. package/dist/protocols/openai-responses.d.ts +5 -5
  12. package/dist/protocols/openai-responses.js +21 -5
  13. package/dist/protocols/utils/bedrock-media.d.ts +1 -0
  14. package/dist/protocols/utils/partial-json-options.d.ts +62 -0
  15. package/dist/protocols/utils/partial-json-options.js +52 -0
  16. package/dist/protocols/utils/partial-json.d.ts +8 -0
  17. package/dist/protocols/utils/partial-json.js +224 -0
  18. package/dist/protocols/xai-responses.d.ts +1 -1
  19. package/dist/protocols/xai-responses.js +2 -10
  20. package/dist/providers/amazon-bedrock-mantle.d.ts +4 -2
  21. package/dist/providers/anthropic-compatible.d.ts +75 -4
  22. package/dist/providers/anthropic.d.ts +75 -4
  23. package/dist/providers/azure.d.ts +4 -2
  24. package/dist/providers/cloudflare.d.ts +9 -3
  25. package/dist/providers/google-vertex-chat.d.ts +3 -1
  26. package/dist/providers/google-vertex-messages.d.ts +75 -4
  27. package/dist/providers/google-vertex-responses.d.ts +1 -1
  28. package/dist/providers/google-vertex.d.ts +1 -1
  29. package/dist/providers/google.d.ts +1 -1
  30. package/dist/providers/openai-compatible-responses.d.ts +1 -1
  31. package/dist/providers/openai-compatible.d.ts +3 -1
  32. package/dist/providers/openai.d.ts +4 -2
  33. package/dist/providers/openrouter.d.ts +11 -3
  34. package/dist/providers/xai.d.ts +3 -1
  35. package/dist/schema/messages.d.ts +4 -0
  36. package/dist/schema/messages.js +2 -0
  37. package/dist/schema/options.d.ts +5 -0
  38. package/dist/schema/options.js +5 -0
  39. package/package.json +3 -3
@@ -1,3 +1,4 @@
1
+ import { Buffer } from "node:buffer";
1
2
  import { Effect, Schema } from "effect";
2
3
  import { Tool } from "@opencode-ai/schema/tool";
3
4
  import { Route } from "../route/client.js";
@@ -40,28 +41,62 @@ const AnthropicTextBlock = Schema.Struct({
40
41
  text: Schema.String,
41
42
  cache_control: Schema.optional(AnthropicCacheControl),
42
43
  });
44
+ // SDK: Base64ImageSource:201 {type:"base64", media_type:"image/jpeg"|... , data}, URLImageSource:3817 {type:"url", url}, FileImageSource:2350 {type:"file", file_id}
45
+ // SDK: ImageBlockParam:2356 {source: Base64|URL|File, cache_control, transformations:2381 {oversized_image?}}
46
+ const AnthropicBase64ImageSource = Schema.Struct({
47
+ type: Schema.tag("base64"),
48
+ media_type: Schema.String,
49
+ data: Schema.String,
50
+ });
51
+ const AnthropicURLImageSource = Schema.Struct({ type: Schema.tag("url"), url: Schema.String });
52
+ const AnthropicFileImageSource = Schema.Struct({ type: Schema.tag("file"), file_id: Schema.String });
53
+ const AnthropicImageSource = Schema.Union([
54
+ AnthropicBase64ImageSource,
55
+ AnthropicURLImageSource,
56
+ AnthropicFileImageSource,
57
+ ]);
58
+ const AnthropicImageTransformations = Schema.Struct({
59
+ oversized_image: Schema.optional(Schema.Literals(["downsize", "error"])),
60
+ });
43
61
  const AnthropicImageBlock = Schema.Struct({
44
62
  type: Schema.tag("image"),
45
- source: Schema.Struct({
46
- type: Schema.tag("base64"),
47
- media_type: Schema.String,
48
- data: Schema.String,
49
- }),
63
+ source: AnthropicImageSource,
50
64
  cache_control: Schema.optional(AnthropicCacheControl),
65
+ transformations: Schema.optional(AnthropicImageTransformations),
66
+ });
67
+ // SDK: Base64PDFSource:209 {type:"base64", media_type:"application/pdf", data}, PlainTextSource:2716 {type:"text", media_type:"text/plain", data},
68
+ // SDK: URLPDFSource:3823 {type:"url", url}, FileDocumentSource:2344 {type:"file", file_id}, ContentBlockSource:2266 {type:"content", content}
69
+ // SDK: DocumentBlockParam:2297 {source: 5-way union, cache_control, citations, context, title}
70
+ const AnthropicBase64PDFSource = Schema.Struct({
71
+ type: Schema.tag("base64"),
72
+ media_type: Schema.Literal("application/pdf"),
73
+ data: Schema.String,
74
+ });
75
+ const AnthropicPlainTextSource = Schema.Struct({
76
+ type: Schema.tag("text"),
77
+ media_type: Schema.Literal("text/plain"),
78
+ data: Schema.String,
51
79
  });
80
+ const AnthropicURLPDFSource = Schema.Struct({ type: Schema.tag("url"), url: Schema.String });
81
+ const AnthropicFileDocumentSource = Schema.Struct({ type: Schema.tag("file"), file_id: Schema.String });
82
+ const AnthropicDocumentSource = Schema.Union([
83
+ AnthropicBase64PDFSource,
84
+ AnthropicPlainTextSource,
85
+ AnthropicURLPDFSource,
86
+ AnthropicFileDocumentSource,
87
+ ]);
52
88
  const AnthropicDocumentBlock = Schema.Struct({
53
89
  type: Schema.tag("document"),
54
- source: Schema.Struct({
55
- type: Schema.tag("base64"),
56
- media_type: Schema.Literal("application/pdf"),
57
- data: Schema.String,
58
- }),
90
+ source: AnthropicDocumentSource,
59
91
  cache_control: Schema.optional(AnthropicCacheControl),
92
+ title: Schema.optional(Schema.String),
93
+ context: Schema.optional(Schema.String),
94
+ citations: Schema.optional(Schema.Struct({ enabled: Schema.Boolean })),
60
95
  });
61
96
  const AnthropicThinkingBlock = Schema.Struct({
62
97
  type: Schema.tag("thinking"),
63
98
  thinking: Schema.String,
64
- signature: Schema.optional(Schema.String),
99
+ signature: Schema.String,
65
100
  cache_control: Schema.optional(AnthropicCacheControl),
66
101
  });
67
102
  // Safety-filtered thinking arrives as an opaque encrypted `data` payload with
@@ -139,8 +174,11 @@ const AnthropicTool = Schema.Struct({
139
174
  cache_control: Schema.optional(AnthropicCacheControl),
140
175
  });
141
176
  const AnthropicToolChoice = Schema.Union([
142
- Schema.Struct({ type: Schema.Literals(["auto", "any", "none"]) }),
143
- Schema.Struct({ type: Schema.tag("tool"), name: Schema.String }),
177
+ Schema.Struct({
178
+ type: Schema.Literals(["auto", "any", "none"]),
179
+ disable_parallel_tool_use: Schema.optional(Schema.Boolean),
180
+ }),
181
+ Schema.Struct({ type: Schema.tag("tool"), name: Schema.String, disable_parallel_tool_use: Schema.optional(Schema.Boolean) }),
144
182
  ]);
145
183
  const AnthropicThinking = Schema.Union([
146
184
  Schema.Struct({
@@ -156,9 +194,25 @@ const AnthropicThinking = Schema.Union([
156
194
  type: Schema.tag("disabled"),
157
195
  }),
158
196
  ]);
197
+ // SDK OutputConfig:2684 {effort?: "low"|"medium"|"high"|"xhigh"|"max"|null, format?: JSONOutputFormat:2399}
198
+ const AnthropicJsonOutputFormat = Schema.Struct({
199
+ type: Schema.Literal("json_schema"),
200
+ schema: JsonObject,
201
+ });
159
202
  const AnthropicOutputConfig = Schema.Struct({
160
203
  effort: Schema.optional(Schema.String),
204
+ format: Schema.optional(Schema.NullOr(AnthropicJsonOutputFormat)),
161
205
  });
206
+ // SDK Metadata:2649 {user_id?: string|null}
207
+ const AnthropicMetadata = Schema.Struct({ user_id: optionalNull(Schema.String) });
208
+ // SDK MessageCreateParamsContainer:2596 ContainerParams|string; ContainerParams:2172 {id?, skills?}
209
+ const AnthropicContainer = Schema.Union([
210
+ Schema.String,
211
+ Schema.Struct({
212
+ id: optionalNull(Schema.String),
213
+ skills: optionalNull(Schema.Array(JsonObject)),
214
+ }),
215
+ ]);
162
216
  const AnthropicBodyFields = {
163
217
  model: Schema.String,
164
218
  system: optionalArray(AnthropicTextBlock),
@@ -173,6 +227,12 @@ const AnthropicBodyFields = {
173
227
  stop_sequences: optionalArray(Schema.String),
174
228
  thinking: Schema.optional(AnthropicThinking),
175
229
  output_config: Schema.optional(AnthropicOutputConfig),
230
+ // SDK top-level passthrough: cache_control:4638, container:4643, inference_geo:4649, metadata:4654, service_tier:4670
231
+ cache_control: Schema.optional(AnthropicCacheControl),
232
+ container: Schema.optional(Schema.NullOr(AnthropicContainer)),
233
+ inference_geo: Schema.optional(Schema.NullOr(Schema.String)),
234
+ metadata: Schema.optional(AnthropicMetadata),
235
+ service_tier: Schema.optional(Schema.Literals(["auto", "standard_only"])),
176
236
  };
177
237
  export const AnthropicMessagesBody = Schema.Struct(AnthropicBodyFields);
178
238
  const AnthropicUsage = Schema.StructWithRest(Schema.Struct({
@@ -267,10 +327,26 @@ const lowerTool = (breakpoints, tool, inputSchema) => ({
267
327
  cache_control: cacheControl(breakpoints, tool.cache),
268
328
  });
269
329
  const lowerToolChoice = (toolChoice) => ProviderShared.matchToolChoice("Anthropic Messages", toolChoice, {
270
- auto: () => ({ type: "auto" }),
330
+ auto: () => ({
331
+ type: "auto",
332
+ ...(toolChoice.disableParallelToolUse === undefined
333
+ ? {}
334
+ : { disable_parallel_tool_use: toolChoice.disableParallelToolUse }),
335
+ }),
271
336
  none: () => ({ type: "none" }),
272
- required: () => ({ type: "any" }),
273
- tool: (name) => ({ type: "tool", name }),
337
+ required: () => ({
338
+ type: "any",
339
+ ...(toolChoice.disableParallelToolUse === undefined
340
+ ? {}
341
+ : { disable_parallel_tool_use: toolChoice.disableParallelToolUse }),
342
+ }),
343
+ tool: (name) => ({
344
+ type: "tool",
345
+ name,
346
+ ...(toolChoice.disableParallelToolUse === undefined
347
+ ? {}
348
+ : { disable_parallel_tool_use: toolChoice.disableParallelToolUse }),
349
+ }),
274
350
  });
275
351
  const scrubToolCallID = (id) => id.replace(/[^a-zA-Z0-9_-]/g, "_");
276
352
  const lowerToolCall = (part) => ({
@@ -306,7 +382,149 @@ const lowerServerToolResult = Effect.fn("AnthropicMessages.lowerServerToolResult
306
382
  const payload = part.providerMetadata?.anthropic?.["result"] ?? part.result.value;
307
383
  return { type: wireType, tool_use_id: scrubToolCallID(part.id), content: payload };
308
384
  });
309
- const lowerMedia = Effect.fn("AnthropicMessages.lowerMedia")(function* (part) {
385
+ const fileIdFromMetadata = (metadata) => {
386
+ if (!ProviderShared.isRecord(metadata))
387
+ return undefined;
388
+ const anthropic = metadata.anthropic;
389
+ if (ProviderShared.isRecord(anthropic)) {
390
+ if (typeof anthropic.file_id === "string")
391
+ return anthropic.file_id;
392
+ if (typeof anthropic.fileId === "string")
393
+ return anthropic.fileId;
394
+ }
395
+ if (typeof metadata.file_id === "string")
396
+ return metadata.file_id;
397
+ if (typeof metadata.fileId === "string")
398
+ return metadata.fileId;
399
+ return undefined;
400
+ };
401
+ const transformationsFromMetadata = (metadata) => {
402
+ if (!ProviderShared.isRecord(metadata))
403
+ return undefined;
404
+ const anthropic = ProviderShared.isRecord(metadata.anthropic) ? metadata.anthropic : undefined;
405
+ const raw = anthropic?.transformations ?? metadata.transformations;
406
+ if (ProviderShared.isRecord(raw)) {
407
+ const value = raw.oversized_image;
408
+ if (value === "downsize" || value === "error")
409
+ return { oversized_image: value };
410
+ }
411
+ if (anthropic && (anthropic.oversized_image === "downsize" || anthropic.oversized_image === "error"))
412
+ return { oversized_image: anthropic.oversized_image };
413
+ return undefined;
414
+ };
415
+ const documentTitleFromPart = (part) => {
416
+ if (ProviderShared.isRecord(part.metadata)) {
417
+ const anthropic = part.metadata.anthropic;
418
+ if (ProviderShared.isRecord(anthropic) && typeof anthropic.title === "string")
419
+ return anthropic.title;
420
+ if (typeof part.metadata.title === "string")
421
+ return part.metadata.title;
422
+ }
423
+ if (typeof part.filename === "string" && part.filename.length > 0)
424
+ return part.filename;
425
+ return undefined;
426
+ };
427
+ const documentContextFromMetadata = (metadata) => {
428
+ if (!ProviderShared.isRecord(metadata))
429
+ return undefined;
430
+ const anthropic = ProviderShared.isRecord(metadata.anthropic) ? metadata.anthropic : undefined;
431
+ if (anthropic && typeof anthropic.context === "string")
432
+ return anthropic.context;
433
+ if (typeof metadata.context === "string")
434
+ return metadata.context;
435
+ return undefined;
436
+ };
437
+ const citationsFromMetadata = (metadata) => {
438
+ if (!ProviderShared.isRecord(metadata))
439
+ return undefined;
440
+ const raw = ProviderShared.isRecord(metadata.anthropic)
441
+ ? (metadata.anthropic.citations ?? metadata.citations)
442
+ : metadata.citations;
443
+ if (ProviderShared.isRecord(raw) && typeof raw.enabled === "boolean")
444
+ return { enabled: raw.enabled };
445
+ return undefined;
446
+ };
447
+ const isHttpUrl = (value) => /^https?:\/\//i.test(value.trim());
448
+ const lowerMedia = Effect.fn("AnthropicMessages.lowerMedia")(function* (part, breakpoints) {
449
+ const mime = part.mediaType.toLowerCase();
450
+ const cacheControlValue = breakpoints ? cacheControl(breakpoints, part.cache) : undefined;
451
+ const fileId = fileIdFromMetadata(part.metadata);
452
+ // SDK file sources: FileImageSource:2350 / FileDocumentSource:2344 {type:"file", file_id}
453
+ if (fileId) {
454
+ if (mime.startsWith("image/"))
455
+ return {
456
+ type: "image",
457
+ source: { type: "file", file_id: fileId },
458
+ ...(cacheControlValue === undefined ? {} : { cache_control: cacheControlValue }),
459
+ ...(transformationsFromMetadata(part.metadata) === undefined
460
+ ? {}
461
+ : { transformations: transformationsFromMetadata(part.metadata) }),
462
+ };
463
+ return {
464
+ type: "document",
465
+ source: { type: "file", file_id: fileId },
466
+ ...(cacheControlValue === undefined ? {} : { cache_control: cacheControlValue }),
467
+ ...(documentTitleFromPart(part) === undefined ? {} : { title: documentTitleFromPart(part) }),
468
+ ...(documentContextFromMetadata(part.metadata) === undefined
469
+ ? {}
470
+ : { context: documentContextFromMetadata(part.metadata) }),
471
+ ...(citationsFromMetadata(part.metadata) === undefined
472
+ ? {}
473
+ : { citations: citationsFromMetadata(part.metadata) }),
474
+ };
475
+ }
476
+ const rawString = typeof part.data === "string" ? part.data.trim() : undefined;
477
+ // SDK URL sources: URLImageSource:3817 / URLPDFSource:3823 {type:"url", url}
478
+ if (rawString && isHttpUrl(rawString) && !rawString.startsWith("data:")) {
479
+ if (mime.startsWith("image/"))
480
+ return {
481
+ type: "image",
482
+ source: { type: "url", url: rawString },
483
+ ...(cacheControlValue === undefined ? {} : { cache_control: cacheControlValue }),
484
+ ...(transformationsFromMetadata(part.metadata) === undefined
485
+ ? {}
486
+ : { transformations: transformationsFromMetadata(part.metadata) }),
487
+ };
488
+ if (mime === "application/pdf")
489
+ return {
490
+ type: "document",
491
+ source: { type: "url", url: rawString },
492
+ ...(cacheControlValue === undefined ? {} : { cache_control: cacheControlValue }),
493
+ ...(documentTitleFromPart(part) === undefined ? {} : { title: documentTitleFromPart(part) }),
494
+ ...(documentContextFromMetadata(part.metadata) === undefined
495
+ ? {}
496
+ : { context: documentContextFromMetadata(part.metadata) }),
497
+ ...(citationsFromMetadata(part.metadata) === undefined
498
+ ? {}
499
+ : { citations: citationsFromMetadata(part.metadata) }),
500
+ };
501
+ }
502
+ // SDK PlainTextSource:2716 {type:"text", media_type:"text/plain", data}
503
+ if (mime === "text/plain") {
504
+ const textData = typeof part.data !== "string"
505
+ ? Buffer.from(part.data).toString("utf8")
506
+ : part.data.startsWith("data:")
507
+ ? (() => {
508
+ const comma = part.data.indexOf(",");
509
+ const payload = comma >= 0 ? part.data.slice(comma + 1) : part.data;
510
+ return part.data.includes(";base64")
511
+ ? Buffer.from(payload, "base64").toString("utf8")
512
+ : decodeURIComponent(payload);
513
+ })()
514
+ : part.data;
515
+ return {
516
+ type: "document",
517
+ source: { type: "text", media_type: "text/plain", data: textData },
518
+ ...(cacheControlValue === undefined ? {} : { cache_control: cacheControlValue }),
519
+ ...(documentTitleFromPart(part) === undefined ? {} : { title: documentTitleFromPart(part) }),
520
+ ...(documentContextFromMetadata(part.metadata) === undefined
521
+ ? {}
522
+ : { context: documentContextFromMetadata(part.metadata) }),
523
+ ...(citationsFromMetadata(part.metadata) === undefined
524
+ ? {}
525
+ : { citations: citationsFromMetadata(part.metadata) }),
526
+ };
527
+ }
310
528
  const media = ProviderShared.normalizeMedia(part);
311
529
  if (media.mime === "application/pdf")
312
530
  return {
@@ -316,6 +534,14 @@ const lowerMedia = Effect.fn("AnthropicMessages.lowerMedia")(function* (part) {
316
534
  media_type: "application/pdf",
317
535
  data: media.base64,
318
536
  },
537
+ ...(cacheControlValue === undefined ? {} : { cache_control: cacheControlValue }),
538
+ ...(documentTitleFromPart(part) === undefined ? {} : { title: documentTitleFromPart(part) }),
539
+ ...(documentContextFromMetadata(part.metadata) === undefined
540
+ ? {}
541
+ : { context: documentContextFromMetadata(part.metadata) }),
542
+ ...(citationsFromMetadata(part.metadata) === undefined
543
+ ? {}
544
+ : { citations: citationsFromMetadata(part.metadata) }),
319
545
  };
320
546
  if (!media.mime.startsWith("image/"))
321
547
  return yield* invalid(`Anthropic Messages does not support media type ${part.mediaType}`);
@@ -326,6 +552,10 @@ const lowerMedia = Effect.fn("AnthropicMessages.lowerMedia")(function* (part) {
326
552
  media_type: media.mime,
327
553
  data: media.base64,
328
554
  },
555
+ ...(cacheControlValue === undefined ? {} : { cache_control: cacheControlValue }),
556
+ ...(transformationsFromMetadata(part.metadata) === undefined
557
+ ? {}
558
+ : { transformations: transformationsFromMetadata(part.metadata) }),
329
559
  };
330
560
  });
331
561
  // Tool results may carry structured text, images, and documents. Keep media as provider-native
@@ -344,6 +574,24 @@ const lowerToolResultContent = Effect.fnUntraced(function* (part) {
344
574
  const content = part.result.value;
345
575
  return yield* Effect.forEach(content, lowerToolResultContentItem);
346
576
  });
577
+ const requireThinkingSignature = (request) => {
578
+ if (request.model.compatibility?.requireSignature !== undefined)
579
+ return request.model.compatibility.requireSignature;
580
+ const provider = request.model.provider.toLowerCase();
581
+ const model = request.model.id.toLowerCase();
582
+ const baseURL = (request.model.route.endpoint.baseURL ?? "").toLowerCase();
583
+ if (provider === "kimi-for-coding" ||
584
+ provider === "moonshotai" ||
585
+ provider === "moonshotai-cn" ||
586
+ model.startsWith("kimi-") ||
587
+ baseURL.includes("api.kimi.com/coding") ||
588
+ baseURL.includes("api.moonshot.ai/anthropic") ||
589
+ baseURL.includes("api.moonshot.cn/anthropic"))
590
+ return false;
591
+ if (provider.includes("xiaomi") || model.includes("mimo") || baseURL.includes("xiaomimimo.com"))
592
+ return false;
593
+ return true;
594
+ };
347
595
  // Mid-conversation system messages became available with Opus 4.8 and version
348
596
  // 5 of the other supported Claude families. Treat later family versions as
349
597
  // compatible without assuming that every Anthropic Messages model is Claude.
@@ -421,7 +669,7 @@ const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* (re
421
669
  continue;
422
670
  }
423
671
  if (part.type === "media") {
424
- content.push(yield* lowerMedia(part));
672
+ content.push(yield* lowerMedia(part, breakpoints));
425
673
  continue;
426
674
  }
427
675
  return yield* ProviderShared.unsupportedContent("Anthropic Messages", "user", ["text", "media"]);
@@ -437,15 +685,31 @@ const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* (re
437
685
  continue;
438
686
  }
439
687
  if (part.type === "reasoning") {
440
- // Mirrors Vercel's @ai-sdk/anthropic: a signature marks visible
441
- // thinking; only signature-less parts carrying redactedData
442
- // round-trip as opaque redacted_thinking blocks.
688
+ // A signature marks visible thinking; only signature-less parts carrying
689
+ // redactedData round-trip as opaque redacted_thinking blocks.
443
690
  const signature = part.encrypted ?? signatureFromMetadata(part.providerMetadata);
444
691
  const redactedData = redactedDataFromMetadata(part.providerMetadata);
445
692
  if (signature === undefined && redactedData !== undefined) {
446
693
  content.push({ type: "redacted_thinking", data: redactedData });
447
694
  continue;
448
695
  }
696
+ if (typeof signature !== "string" || signature.trim().length === 0) {
697
+ if (part.text.trim().length === 0)
698
+ continue;
699
+ if (!requireThinkingSignature(request)) {
700
+ content.push({ type: "thinking", thinking: part.text, signature: "" });
701
+ continue;
702
+ }
703
+ // Without a signature this cannot be a valid thinking block per
704
+ // the SDK ThinkingBlockParam:3217 — demote to text so the
705
+ // conversation remains sendable.
706
+ content.push({
707
+ type: "text",
708
+ text: part.text,
709
+ cache_control: cacheControl(breakpoints, part.cache),
710
+ });
711
+ continue;
712
+ }
449
713
  content.push({ type: "thinking", thinking: part.text, signature });
450
714
  continue;
451
715
  }
@@ -484,9 +748,52 @@ const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* (re
484
748
  });
485
749
  const resolveOptions = Effect.fn("AnthropicMessages.resolveOptions")(function* (request) {
486
750
  const input = request.providerOptions;
751
+ const rawServiceTier = input?.service_tier ?? input?.serviceTier;
752
+ const service_tier = rawServiceTier === "auto" || rawServiceTier === "standard_only"
753
+ ? rawServiceTier
754
+ : undefined;
755
+ const rawMetadata = input?.metadata;
756
+ const metadata = ProviderShared.isRecord(rawMetadata) &&
757
+ (typeof rawMetadata.user_id === "string" || rawMetadata.user_id === null)
758
+ ? { user_id: rawMetadata.user_id }
759
+ : undefined;
760
+ const container = typeof input?.container === "string" ||
761
+ ProviderShared.isRecord(input?.container)
762
+ ? input.container
763
+ : undefined;
764
+ const rawInferenceGeo = input?.inference_geo ??
765
+ input?.inferenceGeo;
766
+ const inference_geo = typeof rawInferenceGeo === "string" ? rawInferenceGeo : undefined;
767
+ const rawCacheControl = input?.cache_control ??
768
+ input?.cacheControl;
769
+ const cache_control = ProviderShared.isRecord(rawCacheControl) && rawCacheControl.type === "ephemeral"
770
+ ? rawCacheControl
771
+ : undefined;
772
+ const rawOutputConfig = input?.output_config ??
773
+ input?.outputConfig;
774
+ const outputConfigEffort = typeof input?.effort === "string"
775
+ ? input.effort
776
+ : ProviderShared.isRecord(rawOutputConfig) && typeof rawOutputConfig.effort === "string"
777
+ ? rawOutputConfig.effort
778
+ : undefined;
779
+ const outputConfigFormat = ProviderShared.isRecord(rawOutputConfig) && ProviderShared.isRecord(rawOutputConfig.format)
780
+ ? rawOutputConfig.format
781
+ : undefined;
782
+ const output_config = outputConfigEffort === undefined && outputConfigFormat === undefined
783
+ ? undefined
784
+ : {
785
+ ...(outputConfigEffort === undefined ? {} : { effort: outputConfigEffort }),
786
+ ...(outputConfigFormat === undefined ? {} : { format: outputConfigFormat }),
787
+ };
487
788
  return {
488
789
  thinking: yield* resolveThinking(input?.thinking),
489
- effort: typeof input?.effort === "string" ? input.effort : undefined,
790
+ effort: outputConfigEffort,
791
+ output_config,
792
+ service_tier,
793
+ metadata,
794
+ container,
795
+ inference_geo,
796
+ cache_control,
490
797
  };
491
798
  });
492
799
  const resolveThinking = Effect.fn("AnthropicMessages.resolveThinking")(function* (input) {
@@ -547,7 +854,13 @@ const fromRequest = Effect.fn("AnthropicMessages.fromRequest")(function* (reques
547
854
  top_k: generation?.topK,
548
855
  stop_sequences: generation?.stop,
549
856
  thinking: options.thinking,
550
- output_config: options.effort === undefined ? undefined : { effort: options.effort },
857
+ output_config: options.output_config,
858
+ // top-level passthrough per SDK MessageCreateParamsBase:4638,4643,4649,4654,4670
859
+ cache_control: options.cache_control,
860
+ container: options.container,
861
+ inference_geo: options.inference_geo,
862
+ metadata: options.metadata,
863
+ service_tier: options.service_tier,
551
864
  };
552
865
  });
553
866
  // =============================================================================
@@ -889,7 +1202,7 @@ export const route = Route.make({
889
1202
  provider: "anthropic",
890
1203
  providerMetadataKey: "anthropic",
891
1204
  protocol,
892
- endpoint: Endpoint.path(PATH, { baseURL: DEFAULT_BASE_URL }),
1205
+ endpoint: Endpoint.path((input) => (input.request.model.provider === "anthropic" ? `${PATH}?beta=true` : PATH), { baseURL: DEFAULT_BASE_URL }),
893
1206
  auth: Auth.none,
894
1207
  framing,
895
1208
  headers: () => ({ "anthropic-version": "2023-06-01" }),
@@ -139,6 +139,7 @@ export declare const protocol: Protocol<{
139
139
  } | undefined;
140
140
  }[];
141
141
  }[] | undefined;
142
+ readonly serviceTier?: string | undefined;
142
143
  readonly toolConfig?: {
143
144
  readonly functionCallingConfig: {
144
145
  readonly mode: "AUTO" | "NONE" | "ANY";
@@ -150,7 +151,6 @@ export declare const protocol: Protocol<{
150
151
  readonly category: string;
151
152
  readonly threshold: string;
152
153
  }[] | undefined;
153
- readonly serviceTier?: string | undefined;
154
154
  readonly labels?: {
155
155
  readonly [x: string]: string;
156
156
  } | undefined;
@@ -177,35 +177,7 @@ export declare const protocol: Protocol<{
177
177
  }, string, {
178
178
  readonly candidates?: readonly {
179
179
  readonly content?: {
180
- readonly parts?: readonly ({
181
- readonly inlineData: {
182
- readonly mimeType: string;
183
- readonly data: string;
184
- };
185
- } | {
186
- readonly text: string;
187
- readonly thought?: boolean | null | undefined;
188
- readonly thoughtSignature?: string | null | undefined;
189
- } | {
190
- readonly functionCall: {
191
- readonly name: string;
192
- readonly id?: string | null | undefined;
193
- readonly args?: unknown;
194
- };
195
- readonly thoughtSignature?: string | null | undefined;
196
- } | {
197
- readonly functionResponse: {
198
- readonly name: string;
199
- readonly response: unknown;
200
- readonly id?: string | undefined;
201
- readonly parts?: readonly {
202
- readonly inlineData: {
203
- readonly mimeType: string;
204
- readonly data: string;
205
- };
206
- }[] | undefined;
207
- };
208
- })[] | null | undefined;
180
+ readonly parts?: readonly unknown[] | null | undefined;
209
181
  readonly role?: "model" | "user" | null | undefined;
210
182
  } | null | undefined;
211
183
  readonly finishReason?: string | null | undefined;
@@ -224,6 +196,7 @@ export declare const protocol: Protocol<{
224
196
  readonly totalTokenCount?: number | null | undefined;
225
197
  } | null | undefined;
226
198
  }, {
199
+ route: string;
227
200
  hasToolCalls: boolean;
228
201
  lifecycle: Lifecycle.State;
229
202
  }>;
@@ -269,6 +242,7 @@ export declare const route: Route<{
269
242
  } | undefined;
270
243
  }[];
271
244
  }[] | undefined;
245
+ readonly serviceTier?: string | undefined;
272
246
  readonly toolConfig?: {
273
247
  readonly functionCallingConfig: {
274
248
  readonly mode: "AUTO" | "NONE" | "ANY";
@@ -280,7 +254,6 @@ export declare const route: Route<{
280
254
  readonly category: string;
281
255
  readonly threshold: string;
282
256
  }[] | undefined;
283
- readonly serviceTier?: string | undefined;
284
257
  readonly labels?: {
285
258
  readonly [x: string]: string;
286
259
  } | undefined;
@@ -1,4 +1,4 @@
1
- import { Effect, Schema } from "effect";
1
+ import { Effect, Option, Schema } from "effect";
2
2
  import { Tool } from "@opencode-ai/schema/tool";
3
3
  import { Route } from "../route/client.js";
4
4
  import { Auth } from "../route/auth.js";
@@ -76,10 +76,15 @@ const GeminiContentPart = Schema.Union([
76
76
  GeminiFunctionCallPart,
77
77
  GeminiFunctionResponsePart,
78
78
  ]);
79
+ const decodeGeminiContentPart = Schema.decodeUnknownOption(GeminiContentPart);
79
80
  const GeminiContent = Schema.Struct({
80
81
  role: optionalNull(Schema.Literals(["user", "model"])),
81
82
  parts: optionalNull(Schema.Array(GeminiContentPart)),
82
83
  });
84
+ const GeminiResponseContent = Schema.Struct({
85
+ role: optionalNull(Schema.Literals(["user", "model"])),
86
+ parts: optionalNull(Schema.Array(Schema.Unknown)),
87
+ });
83
88
  const GeminiSystemInstruction = Schema.Struct({
84
89
  parts: Schema.Array(Schema.Struct({ text: Schema.String })),
85
90
  });
@@ -137,7 +142,7 @@ const GeminiUsage = Schema.Struct({
137
142
  totalTokenCount: optionalNull(Schema.Number),
138
143
  });
139
144
  const GeminiCandidate = Schema.Struct({
140
- content: optionalNull(GeminiContent),
145
+ content: optionalNull(GeminiResponseContent),
141
146
  finishReason: optionalNull(Schema.String),
142
147
  });
143
148
  const GeminiPromptFeedback = Schema.StructWithRest(Schema.Struct({
@@ -485,7 +490,17 @@ const step = (state, event) => {
485
490
  let textSignature = nextState.textSignature;
486
491
  // Supplier ids must be tracked across chunks of the same response, not just within one event's parts.
487
492
  const seenCallIds = new Set(nextState.seenCallIds);
488
- for (const part of candidate.content.parts ?? []) {
493
+ for (const input of candidate.content.parts ?? []) {
494
+ if (ProviderShared.isRecord(input) &&
495
+ !("text" in input) &&
496
+ !("inlineData" in input) &&
497
+ !("functionCall" in input) &&
498
+ !("functionResponse" in input))
499
+ continue;
500
+ const decoded = decodeGeminiContentPart(input);
501
+ if (Option.isNone(decoded))
502
+ return Effect.fail(ProviderShared.eventError(ADAPTER, `Invalid ${state.route} stream event`, ProviderShared.encodeJson(event)));
503
+ const part = decoded.value;
489
504
  const signature = "thoughtSignature" in part && part.thoughtSignature ? part.thoughtSignature : undefined;
490
505
  // Gemini attaches replay signatures to thought parts, visible text, or function calls;
491
506
  // each block kind must retain the signature attached to its own parts.
@@ -553,7 +568,11 @@ export const protocol = Protocol.make({
553
568
  },
554
569
  stream: {
555
570
  event: Protocol.jsonEvent(GeminiEvent),
556
- initial: () => ({ hasToolCalls: false, lifecycle: Lifecycle.initial() }),
571
+ initial: (request) => ({
572
+ route: `${request.model.provider}/${request.model.route.id}`,
573
+ hasToolCalls: false,
574
+ lifecycle: Lifecycle.initial(),
575
+ }),
557
576
  step,
558
577
  onHalt: finish,
559
578
  },