@opencode-ai/ai 0.0.0-bootstrap.0 → 0.0.0-dev-17472

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 (195) hide show
  1. package/README.md +390 -1
  2. package/dist/cache-policy.d.ts +2 -0
  3. package/dist/cache-policy.js +121 -0
  4. package/dist/image-client.d.ts +19 -0
  5. package/dist/image-client.js +19 -0
  6. package/dist/image.d.ts +110 -0
  7. package/dist/image.js +102 -0
  8. package/dist/index.d.ts +18 -0
  9. package/dist/index.js +12 -0
  10. package/dist/llm.d.ts +230 -0
  11. package/dist/llm.js +77 -0
  12. package/dist/protocols/anthropic-messages.d.ts +633 -0
  13. package/dist/protocols/anthropic-messages.js +860 -0
  14. package/dist/protocols/bedrock-converse.d.ts +533 -0
  15. package/dist/protocols/bedrock-converse.js +584 -0
  16. package/dist/protocols/bedrock-event-stream.d.ts +9 -0
  17. package/dist/protocols/bedrock-event-stream.js +73 -0
  18. package/dist/protocols/gemini.d.ts +300 -0
  19. package/dist/protocols/gemini.js +512 -0
  20. package/dist/protocols/google-images.d.ts +30 -0
  21. package/dist/protocols/google-images.js +191 -0
  22. package/dist/protocols/index.d.ts +10 -0
  23. package/dist/protocols/index.js +10 -0
  24. package/dist/protocols/open-responses-channel.d.ts +26 -0
  25. package/dist/protocols/open-responses-channel.js +120 -0
  26. package/dist/protocols/open-responses.d.ts +951 -0
  27. package/dist/protocols/open-responses.js +873 -0
  28. package/dist/protocols/openai-chat.d.ts +795 -0
  29. package/dist/protocols/openai-chat.js +718 -0
  30. package/dist/protocols/openai-compatible-chat.d.ts +107 -0
  31. package/dist/protocols/openai-compatible-chat.js +20 -0
  32. package/dist/protocols/openai-compatible-responses.d.ts +96 -0
  33. package/dist/protocols/openai-compatible-responses.js +17 -0
  34. package/dist/protocols/openai-images.d.ts +32 -0
  35. package/dist/protocols/openai-images.js +188 -0
  36. package/dist/protocols/openai-responses-channel.d.ts +12 -0
  37. package/dist/protocols/openai-responses-channel.js +142 -0
  38. package/dist/protocols/openai-responses.d.ts +596 -0
  39. package/dist/protocols/openai-responses.js +208 -0
  40. package/dist/protocols/shared.d.ts +194 -0
  41. package/dist/protocols/shared.js +238 -0
  42. package/dist/protocols/utils/bedrock-auth.d.ts +21 -0
  43. package/dist/protocols/utils/bedrock-auth.js +43 -0
  44. package/dist/protocols/utils/bedrock-cache.d.ts +15 -0
  45. package/dist/protocols/utils/bedrock-cache.js +29 -0
  46. package/dist/protocols/utils/bedrock-media.d.ts +49 -0
  47. package/dist/protocols/utils/bedrock-media.js +70 -0
  48. package/dist/protocols/utils/cache.d.ts +6 -0
  49. package/dist/protocols/utils/cache.js +8 -0
  50. package/dist/protocols/utils/gemini-tool-schema.d.ts +2 -0
  51. package/dist/protocols/utils/gemini-tool-schema.js +103 -0
  52. package/dist/protocols/utils/image-input.d.ts +21 -0
  53. package/dist/protocols/utils/image-input.js +22 -0
  54. package/dist/protocols/utils/lifecycle.d.ts +20 -0
  55. package/dist/protocols/utils/lifecycle.js +68 -0
  56. package/dist/protocols/utils/open-responses-options.d.ts +21 -0
  57. package/dist/protocols/utils/open-responses-options.js +41 -0
  58. package/dist/protocols/utils/openai-image.d.ts +5 -0
  59. package/dist/protocols/utils/openai-image.js +18 -0
  60. package/dist/protocols/utils/openai-options.d.ts +14 -0
  61. package/dist/protocols/utils/openai-options.js +14 -0
  62. package/dist/protocols/utils/tool-schema.d.ts +8 -0
  63. package/dist/protocols/utils/tool-schema.js +81 -0
  64. package/dist/protocols/utils/tool-stream.d.ts +639 -0
  65. package/dist/protocols/utils/tool-stream.js +141 -0
  66. package/dist/protocols/xai-images.d.ts +26 -0
  67. package/dist/protocols/xai-images.js +111 -0
  68. package/dist/protocols/zai-images.d.ts +22 -0
  69. package/dist/protocols/zai-images.js +84 -0
  70. package/dist/protocols.d.ts +1 -0
  71. package/dist/protocols.js +1 -0
  72. package/dist/provider-error.d.ts +14 -0
  73. package/dist/provider-error.js +130 -0
  74. package/dist/provider-package.d.ts +15 -0
  75. package/dist/provider-package.js +1 -0
  76. package/dist/provider.d.ts +23 -0
  77. package/dist/provider.js +2 -0
  78. package/dist/providers/amazon-bedrock/mantle/chat.d.ts +2 -0
  79. package/dist/providers/amazon-bedrock/mantle/chat.js +1 -0
  80. package/dist/providers/amazon-bedrock/mantle/responses.d.ts +2 -0
  81. package/dist/providers/amazon-bedrock/mantle/responses.js +1 -0
  82. package/dist/providers/amazon-bedrock/mantle.d.ts +2 -0
  83. package/dist/providers/amazon-bedrock/mantle.js +1 -0
  84. package/dist/providers/amazon-bedrock-mantle.d.ts +247 -0
  85. package/dist/providers/amazon-bedrock-mantle.js +68 -0
  86. package/dist/providers/amazon-bedrock.d.ts +172 -0
  87. package/dist/providers/amazon-bedrock.js +41 -0
  88. package/dist/providers/anthropic-compatible.d.ts +218 -0
  89. package/dist/providers/anthropic-compatible.js +45 -0
  90. package/dist/providers/anthropic.d.ts +216 -0
  91. package/dist/providers/anthropic.js +40 -0
  92. package/dist/providers/azure/chat.d.ts +2 -0
  93. package/dist/providers/azure/chat.js +1 -0
  94. package/dist/providers/azure/responses.d.ts +2 -0
  95. package/dist/providers/azure/responses.js +1 -0
  96. package/dist/providers/azure.d.ts +248 -0
  97. package/dist/providers/azure.js +90 -0
  98. package/dist/providers/cloudflare.d.ts +338 -0
  99. package/dist/providers/cloudflare.js +87 -0
  100. package/dist/providers/google-vertex/chat.d.ts +2 -0
  101. package/dist/providers/google-vertex/chat.js +1 -0
  102. package/dist/providers/google-vertex/gemini.d.ts +2 -0
  103. package/dist/providers/google-vertex/gemini.js +1 -0
  104. package/dist/providers/google-vertex/messages.d.ts +2 -0
  105. package/dist/providers/google-vertex/messages.js +1 -0
  106. package/dist/providers/google-vertex/responses.d.ts +2 -0
  107. package/dist/providers/google-vertex/responses.js +1 -0
  108. package/dist/providers/google-vertex-chat.d.ts +131 -0
  109. package/dist/providers/google-vertex-chat.js +50 -0
  110. package/dist/providers/google-vertex-messages.d.ts +215 -0
  111. package/dist/providers/google-vertex-messages.js +75 -0
  112. package/dist/providers/google-vertex-responses.d.ts +122 -0
  113. package/dist/providers/google-vertex-responses.js +51 -0
  114. package/dist/providers/google-vertex-shared.d.ts +22 -0
  115. package/dist/providers/google-vertex-shared.js +61 -0
  116. package/dist/providers/google-vertex.d.ts +115 -0
  117. package/dist/providers/google-vertex.js +64 -0
  118. package/dist/providers/google.d.ts +112 -0
  119. package/dist/providers/google.js +43 -0
  120. package/dist/providers/index.d.ts +18 -0
  121. package/dist/providers/index.js +18 -0
  122. package/dist/providers/open-responses-options.d.ts +16 -0
  123. package/dist/providers/open-responses-options.js +1 -0
  124. package/dist/providers/openai/chat.d.ts +2 -0
  125. package/dist/providers/openai/chat.js +1 -0
  126. package/dist/providers/openai/responses.d.ts +2 -0
  127. package/dist/providers/openai/responses.js +1 -0
  128. package/dist/providers/openai-compatible/responses.d.ts +1 -0
  129. package/dist/providers/openai-compatible/responses.js +1 -0
  130. package/dist/providers/openai-compatible-profile.d.ts +43 -0
  131. package/dist/providers/openai-compatible-profile.js +12 -0
  132. package/dist/providers/openai-compatible-responses.d.ts +120 -0
  133. package/dist/providers/openai-compatible-responses.js +33 -0
  134. package/dist/providers/openai-compatible.d.ts +167 -0
  135. package/dist/providers/openai-compatible.js +55 -0
  136. package/dist/providers/openai-options.d.ts +21 -0
  137. package/dist/providers/openai-options.js +41 -0
  138. package/dist/providers/openai.d.ts +264 -0
  139. package/dist/providers/openai.js +83 -0
  140. package/dist/providers/openrouter.d.ts +537 -0
  141. package/dist/providers/openrouter.js +117 -0
  142. package/dist/providers/xai.d.ts +249 -0
  143. package/dist/providers/xai.js +79 -0
  144. package/dist/providers/zai.d.ts +24 -0
  145. package/dist/providers/zai.js +21 -0
  146. package/dist/providers.d.ts +1 -0
  147. package/dist/providers.js +1 -0
  148. package/dist/route/auth-options.d.ts +34 -0
  149. package/dist/route/auth-options.js +14 -0
  150. package/dist/route/auth.d.ts +51 -0
  151. package/dist/route/auth.js +89 -0
  152. package/dist/route/client.d.ts +348 -0
  153. package/dist/route/client.js +214 -0
  154. package/dist/route/endpoint.d.ts +28 -0
  155. package/dist/route/endpoint.js +21 -0
  156. package/dist/route/executor.d.ts +23 -0
  157. package/dist/route/executor.js +227 -0
  158. package/dist/route/framing.d.ts +23 -0
  159. package/dist/route/framing.js +4 -0
  160. package/dist/route/index.d.ts +16 -0
  161. package/dist/route/index.js +9 -0
  162. package/dist/route/protocol.d.ts +77 -0
  163. package/dist/route/protocol.js +17 -0
  164. package/dist/route/transport/http.d.ts +34 -0
  165. package/dist/route/transport/http.js +63 -0
  166. package/dist/route/transport/index.d.ts +39 -0
  167. package/dist/route/transport/index.js +4 -0
  168. package/dist/route/transport/websocket-channel.d.ts +56 -0
  169. package/dist/route/transport/websocket-channel.js +1 -0
  170. package/dist/route/transport/websocket.d.ts +55 -0
  171. package/dist/route/transport/websocket.js +326 -0
  172. package/dist/route.d.ts +1 -0
  173. package/dist/route.js +1 -0
  174. package/dist/schema/errors.d.ts +159 -0
  175. package/dist/schema/errors.js +155 -0
  176. package/dist/schema/events.d.ts +4587 -0
  177. package/dist/schema/events.js +492 -0
  178. package/dist/schema/ids.d.ts +30 -0
  179. package/dist/schema/ids.js +19 -0
  180. package/dist/schema/index.d.ts +5 -0
  181. package/dist/schema/index.js +5 -0
  182. package/dist/schema/messages.d.ts +402 -0
  183. package/dist/schema/messages.js +244 -0
  184. package/dist/schema/options.d.ts +159 -0
  185. package/dist/schema/options.js +202 -0
  186. package/dist/testing.d.ts +1493 -0
  187. package/dist/testing.js +88 -0
  188. package/dist/tool-runtime.d.ts +15 -0
  189. package/dist/tool-runtime.js +54 -0
  190. package/dist/tool.d.ts +135 -0
  191. package/dist/tool.js +66 -0
  192. package/dist/utils/record.d.ts +2 -0
  193. package/dist/utils/record.js +2 -0
  194. package/package.json +40 -9
  195. package/index.js +0 -1
@@ -0,0 +1,584 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { Route } from "../route/client.js";
3
+ import { Endpoint } from "../route/endpoint.js";
4
+ import { Protocol } from "../route/protocol.js";
5
+ import { AIError, LLMEvent, Usage, } from "../schema/index.js";
6
+ import { BedrockEventStream } from "./bedrock-event-stream.js";
7
+ import { classifyProviderFailure } from "../provider-error.js";
8
+ import { JsonObject, optionalArray, ProviderShared } from "./shared.js";
9
+ import { BedrockAuth } from "./utils/bedrock-auth.js";
10
+ import { BedrockCache } from "./utils/bedrock-cache.js";
11
+ import { BedrockMedia } from "./utils/bedrock-media.js";
12
+ import { Lifecycle } from "./utils/lifecycle.js";
13
+ import { ToolSchemaProjection } from "./utils/tool-schema.js";
14
+ import { ToolStream } from "./utils/tool-stream.js";
15
+ const ADAPTER = "bedrock-converse";
16
+ // =============================================================================
17
+ // Request Body Schema
18
+ // =============================================================================
19
+ const BedrockTextBlock = Schema.Struct({
20
+ text: Schema.String,
21
+ });
22
+ const BedrockToolUseBlock = Schema.Struct({
23
+ toolUse: Schema.Struct({
24
+ toolUseId: Schema.String,
25
+ name: Schema.String,
26
+ input: Schema.Unknown,
27
+ }),
28
+ });
29
+ const BedrockToolResultContentItem = Schema.Union([
30
+ Schema.Struct({ text: Schema.String }),
31
+ Schema.Struct({ json: Schema.Unknown }),
32
+ BedrockMedia.ImageBlock,
33
+ BedrockMedia.DocumentBlock,
34
+ ]);
35
+ const BedrockToolResultBlock = Schema.Struct({
36
+ toolResult: Schema.Struct({
37
+ toolUseId: Schema.String,
38
+ content: Schema.Array(BedrockToolResultContentItem),
39
+ status: Schema.optional(Schema.Literals(["success", "error"])),
40
+ }),
41
+ });
42
+ const BedrockReasoningBlock = Schema.Struct({
43
+ reasoningContent: Schema.Union([
44
+ Schema.Struct({
45
+ reasoningText: Schema.Struct({
46
+ text: Schema.String,
47
+ signature: Schema.optional(Schema.String),
48
+ }),
49
+ }),
50
+ Schema.Struct({ redactedContent: Schema.String }),
51
+ ]),
52
+ });
53
+ const BedrockUserBlock = Schema.Union([
54
+ BedrockTextBlock,
55
+ BedrockMedia.ImageBlock,
56
+ BedrockMedia.DocumentBlock,
57
+ BedrockToolResultBlock,
58
+ BedrockCache.CachePointBlock,
59
+ ]);
60
+ const BedrockAssistantBlock = Schema.Union([
61
+ BedrockTextBlock,
62
+ BedrockReasoningBlock,
63
+ BedrockToolUseBlock,
64
+ BedrockCache.CachePointBlock,
65
+ ]);
66
+ const BedrockMessage = Schema.Union([
67
+ Schema.Struct({ role: Schema.Literal("user"), content: Schema.Array(BedrockUserBlock) }),
68
+ Schema.Struct({ role: Schema.Literal("assistant"), content: Schema.Array(BedrockAssistantBlock) }),
69
+ ]).pipe(Schema.toTaggedUnion("role"));
70
+ const BedrockSystemBlock = Schema.Union([BedrockTextBlock, BedrockCache.CachePointBlock]);
71
+ const BedrockToolSpec = Schema.Struct({
72
+ toolSpec: Schema.Struct({
73
+ name: Schema.String,
74
+ description: Schema.String,
75
+ inputSchema: Schema.Struct({
76
+ json: JsonObject,
77
+ }),
78
+ }),
79
+ });
80
+ const BedrockTool = Schema.Union([BedrockToolSpec, BedrockCache.CachePointBlock]);
81
+ const BedrockToolChoice = Schema.Union([
82
+ Schema.Struct({ auto: Schema.Struct({}) }),
83
+ Schema.Struct({ any: Schema.Struct({}) }),
84
+ Schema.Struct({ tool: Schema.Struct({ name: Schema.String }) }),
85
+ ]);
86
+ const BedrockBodyFields = {
87
+ modelId: Schema.String,
88
+ messages: Schema.Array(BedrockMessage),
89
+ system: optionalArray(BedrockSystemBlock),
90
+ inferenceConfig: Schema.optional(Schema.Struct({
91
+ maxTokens: Schema.optional(Schema.Number),
92
+ temperature: Schema.optional(Schema.Number),
93
+ topP: Schema.optional(Schema.Number),
94
+ stopSequences: optionalArray(Schema.String),
95
+ })),
96
+ toolConfig: Schema.optional(Schema.Struct({
97
+ tools: Schema.Array(BedrockTool),
98
+ toolChoice: Schema.optional(BedrockToolChoice),
99
+ })),
100
+ additionalModelRequestFields: Schema.optional(JsonObject),
101
+ };
102
+ const BedrockConverseBody = Schema.Struct(BedrockBodyFields);
103
+ const BedrockUsageSchema = Schema.Struct({
104
+ inputTokens: Schema.optional(Schema.Number),
105
+ outputTokens: Schema.optional(Schema.Number),
106
+ totalTokens: Schema.optional(Schema.Number),
107
+ cacheReadInputTokens: Schema.optional(Schema.Number),
108
+ cacheWriteInputTokens: Schema.optional(Schema.Number),
109
+ });
110
+ const BedrockStreamException = Schema.Struct({
111
+ message: Schema.optional(Schema.String),
112
+ originalMessage: Schema.optional(Schema.String),
113
+ originalStatusCode: Schema.optional(Schema.Number),
114
+ });
115
+ // Streaming event shape — the AWS event stream wraps each JSON payload by its
116
+ // `:event-type` header (e.g. `messageStart`, `contentBlockDelta`). We
117
+ // reconstruct that wrapping in `decodeFrames` below so the event schema can
118
+ // stay a plain discriminated record.
119
+ const BedrockEvent = Schema.Struct({
120
+ messageStart: Schema.optional(Schema.Struct({ role: Schema.String })),
121
+ contentBlockStart: Schema.optional(Schema.Struct({
122
+ contentBlockIndex: Schema.Number,
123
+ start: Schema.optional(Schema.Struct({
124
+ toolUse: Schema.optional(Schema.Struct({ toolUseId: Schema.String, name: Schema.String })),
125
+ })),
126
+ })),
127
+ contentBlockDelta: Schema.optional(Schema.Struct({
128
+ contentBlockIndex: Schema.Number,
129
+ delta: Schema.optional(Schema.Struct({
130
+ text: Schema.optional(Schema.String),
131
+ toolUse: Schema.optional(Schema.Struct({ input: Schema.String })),
132
+ reasoningContent: Schema.optional(Schema.Struct({
133
+ text: Schema.optional(Schema.String),
134
+ signature: Schema.optional(Schema.String),
135
+ // Blob fields in Bedrock's JSON event stream are base64 strings.
136
+ redactedContent: Schema.optional(Schema.String),
137
+ // Vercel's Bedrock provider exposes the same delta under
138
+ // Anthropic's shorter `data` spelling.
139
+ data: Schema.optional(Schema.String),
140
+ })),
141
+ })),
142
+ })),
143
+ contentBlockStop: Schema.optional(Schema.Struct({ contentBlockIndex: Schema.Number })),
144
+ messageStop: Schema.optional(Schema.Struct({
145
+ stopReason: Schema.String,
146
+ additionalModelResponseFields: Schema.optional(Schema.Unknown),
147
+ })),
148
+ metadata: Schema.optional(Schema.Struct({
149
+ usage: Schema.optional(BedrockUsageSchema),
150
+ metrics: Schema.optional(Schema.Unknown),
151
+ })),
152
+ internalServerException: Schema.optional(BedrockStreamException),
153
+ modelStreamErrorException: Schema.optional(BedrockStreamException),
154
+ validationException: Schema.optional(BedrockStreamException),
155
+ throttlingException: Schema.optional(BedrockStreamException),
156
+ serviceUnavailableException: Schema.optional(BedrockStreamException),
157
+ });
158
+ // =============================================================================
159
+ // Request Lowering
160
+ // =============================================================================
161
+ const lowerToolSpec = (tool, inputSchema) => ({
162
+ toolSpec: {
163
+ name: tool.name,
164
+ description: tool.description,
165
+ inputSchema: { json: inputSchema },
166
+ },
167
+ });
168
+ const lowerTools = (compatibility, breakpoints, tools) => {
169
+ const result = [];
170
+ for (const tool of tools) {
171
+ result.push(lowerToolSpec(tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema, compatibility)));
172
+ const cachePoint = BedrockCache.block(breakpoints, tool.cache);
173
+ if (cachePoint)
174
+ result.push(cachePoint);
175
+ }
176
+ return result;
177
+ };
178
+ const textWithCache = (breakpoints, text, cache) => {
179
+ const cachePoint = BedrockCache.block(breakpoints, cache);
180
+ return cachePoint ? [{ text }, cachePoint] : [{ text }];
181
+ };
182
+ const lowerToolChoice = (toolChoice) => ProviderShared.matchToolChoice("Bedrock Converse", toolChoice, {
183
+ auto: () => ({ auto: {} }),
184
+ none: () => undefined,
185
+ required: () => ({ any: {} }),
186
+ tool: (name) => ({ tool: { name } }),
187
+ });
188
+ const bedrockMetadata = (metadata) => ({ bedrock: metadata });
189
+ const reasoningSignature = (part) => {
190
+ const bedrock = part.providerMetadata?.bedrock;
191
+ return (part.encrypted ??
192
+ (ProviderShared.isRecord(bedrock) && typeof bedrock.signature === "string" ? bedrock.signature : undefined));
193
+ };
194
+ const reasoningRedactedData = (part) => {
195
+ const bedrock = part.providerMetadata?.bedrock;
196
+ return ProviderShared.isRecord(bedrock) && typeof bedrock.redactedData === "string" ? bedrock.redactedData : undefined;
197
+ };
198
+ const lowerToolCall = (part) => ({
199
+ toolUse: {
200
+ toolUseId: part.id,
201
+ name: part.name,
202
+ input: part.input,
203
+ },
204
+ });
205
+ const lowerToolResultContent = Effect.fn("BedrockConverse.lowerToolResultContent")(function* (part) {
206
+ if (part.result.type === "text" || part.result.type === "error")
207
+ return [{ text: ProviderShared.toolResultText(part) }];
208
+ if (part.result.type === "json")
209
+ return [{ json: part.result.value }];
210
+ const content = [];
211
+ for (const item of part.result.value) {
212
+ if (item.type === "text") {
213
+ content.push({ text: item.text });
214
+ continue;
215
+ }
216
+ const media = yield* BedrockMedia.lower({
217
+ type: "media",
218
+ mediaType: item.mime,
219
+ data: item.uri,
220
+ filename: item.name,
221
+ });
222
+ content.push(media);
223
+ }
224
+ return content;
225
+ });
226
+ const lowerToolResult = Effect.fn("BedrockConverse.lowerToolResult")(function* (part) {
227
+ return {
228
+ toolResult: {
229
+ toolUseId: part.id,
230
+ content: yield* lowerToolResultContent(part),
231
+ status: part.result.type === "error" ? "error" : "success",
232
+ },
233
+ };
234
+ });
235
+ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (request, breakpoints) {
236
+ const messages = [];
237
+ for (const message of request.messages) {
238
+ if (message.role === "system") {
239
+ const part = yield* ProviderShared.wrappedSystemUpdate("Bedrock Converse", message);
240
+ const content = textWithCache(breakpoints, part.text, part.cache);
241
+ const previous = messages.at(-1);
242
+ if (previous?.role === "user")
243
+ messages[messages.length - 1] = { role: "user", content: [...previous.content, ...content] };
244
+ else
245
+ messages.push({ role: "user", content });
246
+ continue;
247
+ }
248
+ if (message.role === "user") {
249
+ const content = [];
250
+ for (const part of message.content) {
251
+ if (!ProviderShared.supportsContent(part, ["text", "media"]))
252
+ return yield* ProviderShared.unsupportedContent("Bedrock Converse", "user", ["text", "media"]);
253
+ if (part.type === "text") {
254
+ content.push(...textWithCache(breakpoints, part.text, part.cache));
255
+ continue;
256
+ }
257
+ if (part.type === "media") {
258
+ content.push(yield* BedrockMedia.lower(part));
259
+ continue;
260
+ }
261
+ }
262
+ const previous = messages.at(-1);
263
+ if (previous?.role === "user")
264
+ messages[messages.length - 1] = { role: "user", content: [...previous.content, ...content] };
265
+ else
266
+ messages.push({ role: "user", content });
267
+ continue;
268
+ }
269
+ if (message.role === "assistant") {
270
+ const content = [];
271
+ for (const part of message.content) {
272
+ if (!ProviderShared.supportsContent(part, ["text", "reasoning", "tool-call"]))
273
+ return yield* ProviderShared.unsupportedContent("Bedrock Converse", "assistant", [
274
+ "text",
275
+ "reasoning",
276
+ "tool-call",
277
+ ]);
278
+ if (part.type === "text") {
279
+ content.push(...textWithCache(breakpoints, part.text, part.cache));
280
+ continue;
281
+ }
282
+ if (part.type === "reasoning") {
283
+ const signature = reasoningSignature(part);
284
+ const redactedData = reasoningRedactedData(part);
285
+ if (signature === undefined && redactedData !== undefined) {
286
+ content.push({ reasoningContent: { redactedContent: redactedData } });
287
+ continue;
288
+ }
289
+ content.push({ reasoningContent: { reasoningText: { text: part.text, signature } } });
290
+ continue;
291
+ }
292
+ if (part.type === "tool-call") {
293
+ content.push(lowerToolCall(part));
294
+ continue;
295
+ }
296
+ }
297
+ messages.push({ role: "assistant", content });
298
+ continue;
299
+ }
300
+ const content = [];
301
+ for (const part of message.content) {
302
+ if (!ProviderShared.supportsContent(part, ["tool-result"]))
303
+ return yield* ProviderShared.unsupportedContent("Bedrock Converse", "tool", ["tool-result"]);
304
+ content.push(yield* lowerToolResult(part));
305
+ const cachePoint = BedrockCache.block(breakpoints, part.cache);
306
+ if (cachePoint)
307
+ content.push(cachePoint);
308
+ }
309
+ const previous = messages.at(-1);
310
+ if (previous?.role === "user")
311
+ messages[messages.length - 1] = { role: "user", content: [...previous.content, ...content] };
312
+ else
313
+ messages.push({ role: "user", content });
314
+ }
315
+ return messages;
316
+ });
317
+ // System prompts share the cache-point convention: emit the text block, then
318
+ // optionally a positional `cachePoint` marker.
319
+ const lowerSystem = (breakpoints, system) => system.flatMap((part) => textWithCache(breakpoints, part.text, part.cache));
320
+ const fromRequest = Effect.fn("BedrockConverse.fromRequest")(function* (request) {
321
+ const toolChoice = request.toolChoice ? yield* lowerToolChoice(request.toolChoice) : undefined;
322
+ const generation = request.generation;
323
+ // Bedrock-Claude shares Anthropic's 4-breakpoint cap. Spend the budget in
324
+ // tools → system → messages order to favour the highest-impact prefixes.
325
+ const breakpoints = BedrockCache.breakpoints();
326
+ const toolConfig = request.tools.length > 0
327
+ ? {
328
+ tools: lowerTools(request.model.compatibility?.toolSchema, breakpoints, request.tools),
329
+ // Converse has no native "none". Keep definitions stable for prompt
330
+ // caching and omit only the unsupported choice.
331
+ toolChoice,
332
+ }
333
+ : undefined;
334
+ const system = request.system.length === 0 ? undefined : lowerSystem(breakpoints, request.system);
335
+ const messages = yield* lowerMessages(request, breakpoints);
336
+ if (breakpoints.dropped > 0) {
337
+ yield* Effect.logWarning(`Bedrock Converse: dropped ${breakpoints.dropped} cache breakpoint(s); the API allows at most ${BedrockCache.BEDROCK_BREAKPOINT_CAP} per request.`);
338
+ }
339
+ return {
340
+ modelId: request.model.id,
341
+ messages,
342
+ system,
343
+ inferenceConfig: generation?.maxTokens === undefined &&
344
+ generation?.temperature === undefined &&
345
+ generation?.topP === undefined &&
346
+ (generation?.stop === undefined || generation.stop.length === 0)
347
+ ? undefined
348
+ : {
349
+ maxTokens: generation?.maxTokens,
350
+ temperature: generation?.temperature,
351
+ topP: generation?.topP,
352
+ stopSequences: generation?.stop,
353
+ },
354
+ toolConfig,
355
+ // Converse's base inferenceConfig has no topK; Anthropic/Nova accept it
356
+ // as a model-specific field, so it goes through additionalModelRequestFields.
357
+ additionalModelRequestFields: generation?.topK === undefined ? undefined : { top_k: generation.topK },
358
+ };
359
+ });
360
+ // =============================================================================
361
+ // Stream Parsing
362
+ // =============================================================================
363
+ const mapFinishReason = (reason) => {
364
+ if (reason === "end_turn" || reason === "stop_sequence")
365
+ return "stop";
366
+ if (reason === "max_tokens" || reason === "model_context_window_exceeded")
367
+ return "length";
368
+ if (reason === "tool_use")
369
+ return "tool-calls";
370
+ if (reason === "content_filtered" || reason === "guardrail_intervened")
371
+ return "content-filter";
372
+ if (reason === "malformed_model_output" || reason === "malformed_tool_use")
373
+ return "error";
374
+ return "unknown";
375
+ };
376
+ // AWS reports inputTokens separately from cache reads and writes.
377
+ // Bedrock does not break reasoning out of outputTokens for current models.
378
+ const mapUsage = (usage) => {
379
+ if (!usage)
380
+ return undefined;
381
+ const inputTokens = ProviderShared.sumTokens(usage.inputTokens, usage.cacheReadInputTokens, usage.cacheWriteInputTokens);
382
+ return new Usage({
383
+ inputTokens,
384
+ outputTokens: usage.outputTokens,
385
+ nonCachedInputTokens: usage.inputTokens,
386
+ cacheReadInputTokens: usage.cacheReadInputTokens,
387
+ cacheWriteInputTokens: usage.cacheWriteInputTokens,
388
+ totalTokens: ProviderShared.totalTokens(inputTokens, usage.outputTokens, usage.totalTokens),
389
+ providerMetadata: { bedrock: usage },
390
+ });
391
+ };
392
+ const step = (state, event) => Effect.gen(function* () {
393
+ if (event.contentBlockStart?.start?.toolUse) {
394
+ const index = event.contentBlockStart.contentBlockIndex;
395
+ const events = [];
396
+ const lifecycle = Lifecycle.stepStart(state.lifecycle, events);
397
+ return [
398
+ {
399
+ ...state,
400
+ lifecycle,
401
+ tools: ToolStream.start(state.tools, index, {
402
+ id: event.contentBlockStart.start.toolUse.toolUseId,
403
+ name: event.contentBlockStart.start.toolUse.name,
404
+ }),
405
+ },
406
+ [
407
+ ...events,
408
+ LLMEvent.toolInputStart({
409
+ id: event.contentBlockStart.start.toolUse.toolUseId,
410
+ name: event.contentBlockStart.start.toolUse.name,
411
+ }),
412
+ ],
413
+ ];
414
+ }
415
+ if (event.contentBlockDelta?.delta?.text) {
416
+ const events = [];
417
+ return [
418
+ {
419
+ ...state,
420
+ lifecycle: Lifecycle.textDelta(state.lifecycle, events, `text-${event.contentBlockDelta.contentBlockIndex}`, event.contentBlockDelta.delta.text),
421
+ },
422
+ events,
423
+ ];
424
+ }
425
+ if (event.contentBlockDelta?.delta?.reasoningContent) {
426
+ const index = event.contentBlockDelta.contentBlockIndex;
427
+ const reasoning = event.contentBlockDelta.delta.reasoningContent;
428
+ const events = [];
429
+ const redactedData = reasoning.redactedContent ?? reasoning.data;
430
+ const providerMetadata = reasoning.signature
431
+ ? bedrockMetadata({ signature: reasoning.signature })
432
+ : redactedData !== undefined
433
+ ? bedrockMetadata({ redactedData })
434
+ : undefined;
435
+ const lifecycle = reasoning.text !== undefined || providerMetadata !== undefined
436
+ ? Lifecycle.reasoningDelta(state.lifecycle, events, `reasoning-${index}`, reasoning.text ?? "", providerMetadata)
437
+ : state.lifecycle;
438
+ return [
439
+ {
440
+ ...state,
441
+ lifecycle,
442
+ reasoningSignatures: reasoning.signature
443
+ ? { ...state.reasoningSignatures, [index]: reasoning.signature }
444
+ : state.reasoningSignatures,
445
+ },
446
+ events,
447
+ ];
448
+ }
449
+ if (event.contentBlockDelta?.delta?.toolUse) {
450
+ const index = event.contentBlockDelta.contentBlockIndex;
451
+ const result = ToolStream.appendExisting(ADAPTER, state.tools, index, event.contentBlockDelta.delta.toolUse.input, "Bedrock Converse tool delta is missing its tool call");
452
+ if (ToolStream.isError(result))
453
+ return yield* result;
454
+ const events = [];
455
+ const lifecycle = result.events.length ? Lifecycle.stepStart(state.lifecycle, events) : state.lifecycle;
456
+ events.push(...result.events);
457
+ return [{ ...state, lifecycle, tools: result.tools }, events];
458
+ }
459
+ if (event.contentBlockStop) {
460
+ const index = event.contentBlockStop.contentBlockIndex;
461
+ const result = yield* ToolStream.finish(ADAPTER, state.tools, index);
462
+ const events = [];
463
+ const resultEvents = result.events ?? [];
464
+ const lifecycle = resultEvents.length
465
+ ? Lifecycle.stepStart(state.lifecycle, events)
466
+ : Lifecycle.reasoningEnd(Lifecycle.textEnd(state.lifecycle, events, `text-${index}`), events, `reasoning-${index}`, state.reasoningSignatures[index]
467
+ ? bedrockMetadata({ signature: state.reasoningSignatures[index] })
468
+ : undefined);
469
+ events.push(...resultEvents);
470
+ return [
471
+ {
472
+ ...state,
473
+ hasToolCalls: resultEvents.some((event) => LLMEvent.is.toolCall(event) || LLMEvent.is.toolInputError(event)) ||
474
+ state.hasToolCalls,
475
+ lifecycle,
476
+ tools: result.tools,
477
+ reasoningSignatures: Object.fromEntries(Object.entries(state.reasoningSignatures).filter(([key]) => key !== String(index))),
478
+ },
479
+ events,
480
+ ];
481
+ }
482
+ if (event.messageStop) {
483
+ return [
484
+ {
485
+ ...state,
486
+ pendingFinish: {
487
+ reason: {
488
+ normalized: mapFinishReason(event.messageStop.stopReason),
489
+ raw: event.messageStop.stopReason,
490
+ },
491
+ usage: state.pendingFinish?.usage,
492
+ },
493
+ },
494
+ [],
495
+ ];
496
+ }
497
+ if (event.metadata) {
498
+ const usage = mapUsage(event.metadata.usage) ?? state.pendingFinish?.usage;
499
+ return [
500
+ {
501
+ ...state,
502
+ pendingFinish: {
503
+ reason: state.pendingFinish?.reason ?? { normalized: "stop" },
504
+ usage,
505
+ },
506
+ },
507
+ [],
508
+ ];
509
+ }
510
+ const exception = [
511
+ ["internalServerException", event.internalServerException],
512
+ ["modelStreamErrorException", event.modelStreamErrorException],
513
+ ["serviceUnavailableException", event.serviceUnavailableException],
514
+ ["throttlingException", event.throttlingException],
515
+ ["validationException", event.validationException],
516
+ ].find((entry) => entry[1] !== undefined);
517
+ if (exception) {
518
+ return yield* new AIError({
519
+ module: ADAPTER,
520
+ method: "stream",
521
+ reason: classifyProviderFailure({
522
+ message: exception[1]?.message ?? exception[1]?.originalMessage ?? "Bedrock Converse stream error",
523
+ code: exception[0],
524
+ }),
525
+ });
526
+ }
527
+ return [state, []];
528
+ });
529
+ const framing = BedrockEventStream.framing(ADAPTER);
530
+ const onHalt = (state) => state.pendingFinish
531
+ ? (() => {
532
+ const events = [];
533
+ Lifecycle.finish(state.lifecycle, events, {
534
+ reason: {
535
+ ...state.pendingFinish.reason,
536
+ normalized: state.pendingFinish.reason.normalized === "stop" && state.hasToolCalls
537
+ ? "tool-calls"
538
+ : state.pendingFinish.reason.normalized,
539
+ },
540
+ usage: state.pendingFinish.usage,
541
+ });
542
+ return events;
543
+ })()
544
+ : [];
545
+ // =============================================================================
546
+ // Protocol And Bedrock Route
547
+ // =============================================================================
548
+ /**
549
+ * The Bedrock Converse protocol — request body construction, body schema, and
550
+ * the streaming-event state machine.
551
+ */
552
+ export const protocol = Protocol.make({
553
+ id: ADAPTER,
554
+ body: {
555
+ schema: BedrockConverseBody,
556
+ from: fromRequest,
557
+ },
558
+ stream: {
559
+ event: BedrockEvent,
560
+ initial: () => ({
561
+ tools: ToolStream.empty(),
562
+ pendingFinish: undefined,
563
+ hasToolCalls: false,
564
+ lifecycle: Lifecycle.initial(),
565
+ reasoningSignatures: {},
566
+ }),
567
+ step,
568
+ onHalt,
569
+ },
570
+ });
571
+ export const route = Route.make({
572
+ id: ADAPTER,
573
+ provider: "bedrock",
574
+ providerMetadataKey: "bedrock",
575
+ protocol,
576
+ // Bedrock's URL embeds the region in the route endpoint host and the
577
+ // validated modelId in the path. We read the validated body so the URL
578
+ // matches the body that gets signed.
579
+ endpoint: Endpoint.path(({ body }) => `/model/${encodeURIComponent(body.modelId)}/converse-stream`),
580
+ auth: BedrockAuth.auth,
581
+ framing,
582
+ });
583
+ export const sigV4Auth = BedrockAuth.sigV4;
584
+ export * as BedrockConverse from "./bedrock-converse.js";
@@ -0,0 +1,9 @@
1
+ import { Framing } from "../route/framing.js";
2
+ /**
3
+ * AWS event-stream framing for Bedrock Converse. Each frame is decoded by
4
+ * `@smithy/eventstream-codec` (length + header + payload + CRC) and rewrapped
5
+ * under its `:event-type` header so the chunk schema can match the JSON
6
+ * payload directly.
7
+ */
8
+ export declare const framing: (route: string) => Framing.Definition<object>;
9
+ export * as BedrockEventStream from "./bedrock-event-stream.js";
@@ -0,0 +1,73 @@
1
+ import { EventStreamCodec } from "@smithy/eventstream-codec";
2
+ import { fromUtf8, toUtf8 } from "@smithy/util-utf8";
3
+ import { Effect, Stream } from "effect";
4
+ import { Framing } from "../route/framing.js";
5
+ import { ProviderShared } from "./shared.js";
6
+ // Bedrock streams responses using the AWS event stream binary protocol — each
7
+ // frame is `[length:4][headers-length:4][prelude-crc:4][headers][payload][crc:4]`.
8
+ // We use `@smithy/eventstream-codec` to validate framing and CRCs, then
9
+ // reconstruct the JSON wrapping by `:event-type` so the chunk schema can match.
10
+ const eventCodec = new EventStreamCodec(toUtf8, fromUtf8);
11
+ const utf8 = new TextDecoder();
12
+ const initialFrameBuffer = { buffer: new Uint8Array(0), offset: 0 };
13
+ const appendChunk = (state, chunk) => {
14
+ const remaining = state.buffer.length - state.offset;
15
+ // Compact: drop the consumed prefix and append the new chunk in one alloc.
16
+ // This bounds buffer growth to at most one network chunk past the live
17
+ // window, regardless of stream length.
18
+ const next = new Uint8Array(remaining + chunk.length);
19
+ next.set(state.buffer.subarray(state.offset), 0);
20
+ next.set(chunk, remaining);
21
+ return { buffer: next, offset: 0 };
22
+ };
23
+ const consumeFrames = (route) => (state, chunk) => Effect.gen(function* () {
24
+ let cursor = appendChunk(state, chunk);
25
+ const out = [];
26
+ while (cursor.buffer.length - cursor.offset >= 4) {
27
+ const view = cursor.buffer.subarray(cursor.offset);
28
+ const totalLength = new DataView(view.buffer, view.byteOffset, view.byteLength).getUint32(0, false);
29
+ if (view.length < totalLength)
30
+ break;
31
+ const decoded = yield* Effect.try({
32
+ try: () => eventCodec.decode(view.subarray(0, totalLength)),
33
+ catch: (error) => ProviderShared.eventError(route, `Failed to decode Bedrock Converse event-stream frame: ${error instanceof Error ? error.message : String(error)}`),
34
+ });
35
+ cursor = { buffer: cursor.buffer, offset: cursor.offset + totalLength };
36
+ const messageType = decoded.headers[":message-type"]?.value;
37
+ if (messageType === "error") {
38
+ const code = decoded.headers[":error-code"]?.value;
39
+ const message = decoded.headers[":error-message"]?.value;
40
+ return yield* ProviderShared.eventError(route, [code, message].filter((value) => typeof value === "string").join(": ") ||
41
+ "Bedrock Converse event-stream error");
42
+ }
43
+ const eventType = messageType === "event"
44
+ ? decoded.headers[":event-type"]?.value
45
+ : messageType === "exception"
46
+ ? decoded.headers[":exception-type"]?.value
47
+ : undefined;
48
+ if (typeof eventType !== "string")
49
+ continue;
50
+ const payload = utf8.decode(decoded.body);
51
+ if (!payload)
52
+ continue;
53
+ // The AWS event stream pads short payloads with a `p` field. Drop it
54
+ // before handing the object to the chunk schema. JSON decode goes
55
+ // through the shared Schema-driven codec to satisfy the package rule
56
+ // against ad-hoc `JSON.parse` calls.
57
+ const parsed = (yield* ProviderShared.parseJson(route, payload, "Failed to parse Bedrock Converse event-stream payload"));
58
+ delete parsed.p;
59
+ out.push({ [eventType]: parsed });
60
+ }
61
+ return [cursor, out];
62
+ });
63
+ /**
64
+ * AWS event-stream framing for Bedrock Converse. Each frame is decoded by
65
+ * `@smithy/eventstream-codec` (length + header + payload + CRC) and rewrapped
66
+ * under its `:event-type` header so the chunk schema can match the JSON
67
+ * payload directly.
68
+ */
69
+ export const framing = (route) => ({
70
+ id: "aws-event-stream",
71
+ frame: (bytes) => bytes.pipe(Stream.mapAccumEffect(() => initialFrameBuffer, consumeFrames(route))),
72
+ });
73
+ export * as BedrockEventStream from "./bedrock-event-stream.js";