@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.
- package/dist/protocols/anthropic-messages.d.ts +259 -17
- package/dist/protocols/anthropic-messages.js +337 -24
- package/dist/protocols/gemini.d.ts +4 -31
- package/dist/protocols/gemini.js +23 -4
- package/dist/protocols/open-responses.d.ts +8 -4
- package/dist/protocols/open-responses.js +73 -38
- package/dist/protocols/openai-chat.d.ts +25 -11
- package/dist/protocols/openai-chat.js +124 -8
- package/dist/protocols/openai-compatible-chat.d.ts +3 -1
- package/dist/protocols/openai-compatible-responses.d.ts +1 -1
- package/dist/protocols/openai-responses.d.ts +5 -5
- package/dist/protocols/openai-responses.js +21 -5
- package/dist/protocols/utils/bedrock-media.d.ts +1 -0
- package/dist/protocols/utils/partial-json-options.d.ts +62 -0
- package/dist/protocols/utils/partial-json-options.js +52 -0
- package/dist/protocols/utils/partial-json.d.ts +8 -0
- package/dist/protocols/utils/partial-json.js +224 -0
- package/dist/protocols/xai-responses.d.ts +1 -1
- package/dist/protocols/xai-responses.js +2 -10
- package/dist/providers/amazon-bedrock-mantle.d.ts +4 -2
- package/dist/providers/anthropic-compatible.d.ts +75 -4
- package/dist/providers/anthropic.d.ts +75 -4
- package/dist/providers/azure.d.ts +4 -2
- package/dist/providers/cloudflare.d.ts +9 -3
- package/dist/providers/google-vertex-chat.d.ts +3 -1
- package/dist/providers/google-vertex-messages.d.ts +75 -4
- package/dist/providers/google-vertex-responses.d.ts +1 -1
- package/dist/providers/google-vertex.d.ts +1 -1
- package/dist/providers/google.d.ts +1 -1
- package/dist/providers/openai-compatible-responses.d.ts +1 -1
- package/dist/providers/openai-compatible.d.ts +3 -1
- package/dist/providers/openai.d.ts +4 -2
- package/dist/providers/openrouter.d.ts +11 -3
- package/dist/providers/xai.d.ts +3 -1
- package/dist/schema/messages.d.ts +4 -0
- package/dist/schema/messages.js +2 -0
- package/dist/schema/options.d.ts +5 -0
- package/dist/schema/options.js +5 -0
- 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:
|
|
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:
|
|
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.
|
|
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({
|
|
143
|
-
|
|
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: () => ({
|
|
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: () => ({
|
|
273
|
-
|
|
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
|
|
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
|
-
//
|
|
441
|
-
//
|
|
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:
|
|
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.
|
|
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;
|
package/dist/protocols/gemini.js
CHANGED
|
@@ -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(
|
|
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
|
|
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: () => ({
|
|
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
|
},
|