@tanstack/ai-bedrock 0.0.1

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 (64) hide show
  1. package/README.md +95 -0
  2. package/dist/esm/adapters/converse-text.d.ts +93 -0
  3. package/dist/esm/adapters/converse-text.js +430 -0
  4. package/dist/esm/adapters/converse-text.js.map +1 -0
  5. package/dist/esm/adapters/responses-text.d.ts +23 -0
  6. package/dist/esm/adapters/responses-text.js +22 -0
  7. package/dist/esm/adapters/responses-text.js.map +1 -0
  8. package/dist/esm/adapters/text.d.ts +30 -0
  9. package/dist/esm/adapters/text.js +38 -0
  10. package/dist/esm/adapters/text.js.map +1 -0
  11. package/dist/esm/converse/message-converter.d.ts +14 -0
  12. package/dist/esm/converse/message-converter.js +181 -0
  13. package/dist/esm/converse/message-converter.js.map +1 -0
  14. package/dist/esm/converse/provider-options.d.ts +19 -0
  15. package/dist/esm/converse/stream-processor.d.ts +46 -0
  16. package/dist/esm/converse/stream-processor.js +203 -0
  17. package/dist/esm/converse/stream-processor.js.map +1 -0
  18. package/dist/esm/converse/structured-output.d.ts +8 -0
  19. package/dist/esm/converse/structured-output.js +20 -0
  20. package/dist/esm/converse/structured-output.js.map +1 -0
  21. package/dist/esm/converse/tool-converter.d.ts +11 -0
  22. package/dist/esm/converse/tool-converter.js +21 -0
  23. package/dist/esm/converse/tool-converter.js.map +1 -0
  24. package/dist/esm/index.d.ts +29 -0
  25. package/dist/esm/index.js +62 -0
  26. package/dist/esm/index.js.map +1 -0
  27. package/dist/esm/message-types.d.ts +25 -0
  28. package/dist/esm/model-catalog.generated.d.ts +127 -0
  29. package/dist/esm/model-catalog.generated.js +90 -0
  30. package/dist/esm/model-catalog.generated.js.map +1 -0
  31. package/dist/esm/model-meta.d.ts +38 -0
  32. package/dist/esm/model-meta.js +14 -0
  33. package/dist/esm/model-meta.js.map +1 -0
  34. package/dist/esm/text/responses-provider-options.d.ts +29 -0
  35. package/dist/esm/text/text-provider-options.d.ts +36 -0
  36. package/dist/esm/utils/auth.d.ts +20 -0
  37. package/dist/esm/utils/auth.js +49 -0
  38. package/dist/esm/utils/auth.js.map +1 -0
  39. package/dist/esm/utils/client.d.ts +19 -0
  40. package/dist/esm/utils/client.js +35 -0
  41. package/dist/esm/utils/client.js.map +1 -0
  42. package/dist/esm/utils/index.d.ts +1 -0
  43. package/dist/esm/utils/openai-sigv4-fetch.d.ts +10 -0
  44. package/dist/esm/utils/openai-sigv4-fetch.js +35 -0
  45. package/dist/esm/utils/openai-sigv4-fetch.js.map +1 -0
  46. package/package.json +67 -0
  47. package/src/adapters/converse-text.ts +603 -0
  48. package/src/adapters/responses-text.ts +73 -0
  49. package/src/adapters/text.ts +97 -0
  50. package/src/converse/message-converter.ts +268 -0
  51. package/src/converse/provider-options.ts +19 -0
  52. package/src/converse/stream-processor.ts +309 -0
  53. package/src/converse/structured-output.ts +24 -0
  54. package/src/converse/tool-converter.ts +49 -0
  55. package/src/index.ts +190 -0
  56. package/src/message-types.ts +24 -0
  57. package/src/model-catalog.generated.ts +88 -0
  58. package/src/model-meta.ts +69 -0
  59. package/src/text/responses-provider-options.ts +28 -0
  60. package/src/text/text-provider-options.ts +33 -0
  61. package/src/utils/auth.ts +80 -0
  62. package/src/utils/client.ts +62 -0
  63. package/src/utils/index.ts +7 -0
  64. package/src/utils/openai-sigv4-fetch.ts +55 -0
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # @tanstack/ai-bedrock
2
+
3
+ Amazon Bedrock adapter for TanStack AI — the native Converse API (default) plus the OpenAI-compatible Chat Completions and Responses APIs, with streaming, tool calling, and reasoning.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @tanstack/ai-bedrock
9
+ # or
10
+ npm install @tanstack/ai-bedrock
11
+ # or
12
+ yarn add @tanstack/ai-bedrock
13
+ ```
14
+
15
+ ## Setup
16
+
17
+ Get a Bedrock API key from the [Amazon Bedrock console](https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys.html) and set it as an environment variable:
18
+
19
+ ```bash
20
+ BEDROCK_API_KEY=your-bedrock-api-key
21
+ ```
22
+
23
+ Alternatively, configure AWS credentials for SigV4 auth (see below).
24
+
25
+ ## Usage
26
+
27
+ ```typescript
28
+ import { bedrockText } from '@tanstack/ai-bedrock'
29
+ import { chat } from '@tanstack/ai'
30
+
31
+ const adapter = bedrockText('us.anthropic.claude-haiku-4-5-20251001-v1:0', {
32
+ region: 'us-east-1',
33
+ })
34
+
35
+ for await (const chunk of chat({
36
+ adapter,
37
+ messages: [{ role: 'user', content: 'Hello from Bedrock!' }],
38
+ })) {
39
+ if (chunk.type === 'TEXT_MESSAGE_CONTENT')
40
+ process.stdout.write(chunk.delta ?? '')
41
+ }
42
+ ```
43
+
44
+ ### Responses API
45
+
46
+ ```typescript
47
+ import { bedrockText } from '@tanstack/ai-bedrock'
48
+
49
+ const adapter = bedrockText('openai.gpt-oss-120b-1:0', {
50
+ region: 'us-east-1',
51
+ api: 'responses',
52
+ })
53
+ ```
54
+
55
+ ### With Explicit API Key
56
+
57
+ ```typescript
58
+ import { createBedrockText } from '@tanstack/ai-bedrock'
59
+
60
+ const adapter = createBedrockText(
61
+ 'us.amazon.nova-pro-v1:0',
62
+ 'your-bedrock-api-key',
63
+ { region: 'us-west-2' },
64
+ )
65
+ ```
66
+
67
+ ## Authentication
68
+
69
+ Auth is resolved in this order:
70
+
71
+ 1. Explicit `apiKey` passed to the factory
72
+ 2. `BEDROCK_API_KEY` environment variable
73
+ 3. `AWS_BEARER_TOKEN_BEDROCK` environment variable
74
+ 4. SigV4 via the AWS credential chain
75
+
76
+ SigV4 signing is built in — no additional packages required. On the Converse
77
+ (default) path the `@aws-sdk/client-bedrock-runtime` client signs requests
78
+ itself; the OpenAI-compatible chat/responses paths sign via the bundled
79
+ `@smithy/signature-v4`. Set `auth: 'sigv4'` and provide AWS credentials through
80
+ the standard credential chain (env vars, shared config, instance role):
81
+
82
+ ```typescript
83
+ const adapter = bedrockText('us.anthropic.claude-haiku-4-5-20251001-v1:0', {
84
+ auth: 'sigv4',
85
+ region: 'us-east-1',
86
+ })
87
+ ```
88
+
89
+ ## Documentation
90
+
91
+ Full documentation: [TanStack AI — Amazon Bedrock adapter](https://tanstack.com/ai/latest/docs/adapters/bedrock)
92
+
93
+ ## License
94
+
95
+ MIT
@@ -0,0 +1,93 @@
1
+ import { BaseTextAdapter, StructuredOutputOptions, StructuredOutputResult } from '@tanstack/ai/adapters';
2
+ import { ResolvedBedrockAuth } from '../utils/auth.js';
3
+ import { BedrockRuntimeClient, BedrockRuntimeClientConfig, ConverseCommandInput, ConverseCommandOutput, ConverseStreamCommandInput, ConverseStreamOutput } from '@aws-sdk/client-bedrock-runtime';
4
+ import { Modality, StreamChunk, TextOptions } from '@tanstack/ai';
5
+ import { BedrockClientConfig } from '../utils/client.js';
6
+ import { BedrockMessageMetadataByModality } from '../message-types.js';
7
+ import { BedrockConverseModels, ResolveConverseProviderOptions, ResolveInputModalities } from '../model-meta.js';
8
+ import type * as BedrockRuntime from '@aws-sdk/client-bedrock-runtime';
9
+ /** Config for the Converse adapter — same client config as the chat adapter. */
10
+ export interface BedrockConverseConfig extends BedrockClientConfig {
11
+ }
12
+ /**
13
+ * Bedrock Converse text adapter. Wires the Converse translation modules (message
14
+ * converter, tool converter, stream processor, structured-output forced-tool
15
+ * builder) onto `@tanstack/ai`'s `BaseTextAdapter` and the
16
+ * `@aws-sdk/client-bedrock-runtime` `BedrockRuntimeClient`.
17
+ *
18
+ * The success-path AG-UI lifecycle (`RUN_STARTED`..`RUN_FINISHED`) is owned by
19
+ * `processConverseStream`; this adapter only owns the catch/`RUN_ERROR` path,
20
+ * mirroring openai-base's `chatStream`.
21
+ *
22
+ * The actual SDK calls live behind two protected seams (`sendStream` / `send`)
23
+ * so tests can subclass and inject canned Converse SDK shapes without a real
24
+ * AWS request.
25
+ */
26
+ export declare class BedrockConverseTextAdapter<TModel extends BedrockConverseModels, TProviderOptions extends Record<string, any> = ResolveConverseProviderOptions<TModel>, TInputModalities extends ReadonlyArray<Modality> = ResolveInputModalities<TModel>> extends BaseTextAdapter<TModel, TProviderOptions, TInputModalities, BedrockMessageMetadataByModality> {
27
+ readonly kind: "text";
28
+ readonly name: "bedrock-converse";
29
+ private clientPromise?;
30
+ private readonly clientConfig;
31
+ constructor(config: BedrockConverseConfig, model: TModel);
32
+ /**
33
+ * Dynamically import `@aws-sdk/client-bedrock-runtime`. The specifier is held
34
+ * in a variable (not a string literal) so bundler dep scanners (e.g. Vite/
35
+ * esbuild optimizeDeps) cannot statically discover the AWS SDK and try to
36
+ * pre-bundle it for the browser — it would fail on the SDK's Node-only
37
+ * `fromTokenFile` export chain. The SDK is Node/server-only and is only
38
+ * reached on a real request. `typeof import(...)` is a type-only reference
39
+ * (erased at emit) so the imported members keep full typing.
40
+ */
41
+ protected importBedrockRuntime(): Promise<typeof BedrockRuntime>;
42
+ /**
43
+ * Lazily construct the `BedrockRuntimeClient`. The dynamic import keeps
44
+ * `@aws-sdk/client-bedrock-runtime` out of the static/browser graph and
45
+ * defers `resolveBedrockAuth` until a real request is made.
46
+ */
47
+ protected getClient(): Promise<BedrockRuntimeClient>;
48
+ /**
49
+ * Map resolved auth + endpoint to a `BedrockRuntimeClientConfig`.
50
+ *
51
+ * Recent `@aws-sdk/client-bedrock-runtime` exposes a first-class `token`
52
+ * config field for Bedrock API-key bearer auth. But the client's default
53
+ * auth-scheme order is SigV4 first, then bearer — so passing `token` alone is
54
+ * not enough: the SDK still resolves SigV4 and throws "Could not load
55
+ * credentials from any providers". Pinning `authSchemePreference` to the
56
+ * bearer scheme makes the API key actually get used. SigV4 uses the AWS
57
+ * credential provider chain and the default scheme order.
58
+ */
59
+ protected buildClientConfig(resolved: ResolvedBedrockAuth, region: string, endpoint: string | undefined): BedrockRuntimeClientConfig;
60
+ protected sendStream(input: ConverseStreamCommandInput): Promise<AsyncIterable<ConverseStreamOutput>>;
61
+ protected send(input: ConverseCommandInput): Promise<ConverseCommandOutput>;
62
+ chatStream(options: TextOptions<TProviderOptions>): AsyncIterable<StreamChunk>;
63
+ /**
64
+ * Structured output via the forced-tool strategy. Converse has no native
65
+ * json_schema response_format, so we force a single tool whose input schema
66
+ * is the requested output schema and read the model's `toolUse.input` back as
67
+ * the structured result.
68
+ */
69
+ structuredOutput(options: StructuredOutputOptions<TProviderOptions>): Promise<StructuredOutputResult<unknown>>;
70
+ /**
71
+ * Streaming structured output. Same forced-tool strategy as
72
+ * `structuredOutput`, but streamed: the forced tool's `toolUse.input` JSON
73
+ * fragments are accumulated from the Converse stream and a terminal
74
+ * `CUSTOM 'structured-output.complete'` event carries `{ object, raw }`,
75
+ * mirroring openai-base's `structuredOutputStream` contract exactly.
76
+ */
77
+ structuredOutputStream(options: StructuredOutputOptions<TProviderOptions>): AsyncIterable<StreamChunk>;
78
+ /**
79
+ * Converse sends `tools` and a forced structured-output tool via two separate
80
+ * mechanisms, never together. Declaring `false` makes the engine run the
81
+ * agent loop without `outputSchema` and finalize via `structuredOutput` /
82
+ * `structuredOutputStream`.
83
+ */
84
+ supportsCombinedToolsAndSchema(): boolean;
85
+ /**
86
+ * Translate `TextOptions` into a `ConverseCommandInput`. Shared by chatStream,
87
+ * structuredOutput, and structuredOutputStream (the latter two override
88
+ * `toolConfig` with the forced structured tool afterwards).
89
+ */
90
+ protected buildInput(options: TextOptions<TProviderOptions>): ConverseCommandInput;
91
+ }
92
+ /** Converse adapter with an explicit API key (low-level; mirrors createBedrockChat). */
93
+ export declare function createBedrockConverse<TModel extends BedrockConverseModels>(model: TModel, apiKey: string, config?: Omit<BedrockConverseConfig, 'apiKey'>): BedrockConverseTextAdapter<TModel>;
@@ -0,0 +1,430 @@
1
+ import { EventType, convertSchemaToJsonSchema } from "@tanstack/ai";
2
+ import { BaseTextAdapter } from "@tanstack/ai/adapters";
3
+ import { toRunErrorPayload } from "@tanstack/ai/adapter-internals";
4
+ import { resolveBedrockAuth } from "../utils/auth.js";
5
+ import { toConverseMessages } from "../converse/message-converter.js";
6
+ import { toToolConfig } from "../converse/tool-converter.js";
7
+ import { processConverseStream, throwIfConverseStreamError } from "../converse/stream-processor.js";
8
+ import { buildStructuredToolConfig, STRUCTURED_TOOL_NAME } from "../converse/structured-output.js";
9
+ class BedrockConverseTextAdapter extends BaseTextAdapter {
10
+ kind = "text";
11
+ name = "bedrock-converse";
12
+ clientPromise;
13
+ clientConfig;
14
+ constructor(config, model) {
15
+ super({}, model);
16
+ this.clientConfig = config;
17
+ }
18
+ /**
19
+ * Dynamically import `@aws-sdk/client-bedrock-runtime`. The specifier is held
20
+ * in a variable (not a string literal) so bundler dep scanners (e.g. Vite/
21
+ * esbuild optimizeDeps) cannot statically discover the AWS SDK and try to
22
+ * pre-bundle it for the browser — it would fail on the SDK's Node-only
23
+ * `fromTokenFile` export chain. The SDK is Node/server-only and is only
24
+ * reached on a real request. `typeof import(...)` is a type-only reference
25
+ * (erased at emit) so the imported members keep full typing.
26
+ */
27
+ importBedrockRuntime() {
28
+ const mod = "@aws-sdk/client-bedrock-runtime";
29
+ return import(
30
+ /* @vite-ignore */
31
+ mod
32
+ );
33
+ }
34
+ /**
35
+ * Lazily construct the `BedrockRuntimeClient`. The dynamic import keeps
36
+ * `@aws-sdk/client-bedrock-runtime` out of the static/browser graph and
37
+ * defers `resolveBedrockAuth` until a real request is made.
38
+ */
39
+ async getClient() {
40
+ if (!this.clientPromise) {
41
+ this.clientPromise = (async () => {
42
+ const { BedrockRuntimeClient } = await this.importBedrockRuntime();
43
+ const region = this.clientConfig.region ?? "us-east-1";
44
+ const resolved = resolveBedrockAuth(
45
+ {
46
+ apiKey: this.clientConfig.apiKey,
47
+ region,
48
+ auth: this.clientConfig.auth
49
+ },
50
+ "runtime"
51
+ );
52
+ return new BedrockRuntimeClient(
53
+ this.buildClientConfig(resolved, region, this.clientConfig.baseURL)
54
+ );
55
+ })().catch((error) => {
56
+ this.clientPromise = void 0;
57
+ throw error;
58
+ });
59
+ }
60
+ return this.clientPromise;
61
+ }
62
+ /**
63
+ * Map resolved auth + endpoint to a `BedrockRuntimeClientConfig`.
64
+ *
65
+ * Recent `@aws-sdk/client-bedrock-runtime` exposes a first-class `token`
66
+ * config field for Bedrock API-key bearer auth. But the client's default
67
+ * auth-scheme order is SigV4 first, then bearer — so passing `token` alone is
68
+ * not enough: the SDK still resolves SigV4 and throws "Could not load
69
+ * credentials from any providers". Pinning `authSchemePreference` to the
70
+ * bearer scheme makes the API key actually get used. SigV4 uses the AWS
71
+ * credential provider chain and the default scheme order.
72
+ */
73
+ buildClientConfig(resolved, region, endpoint) {
74
+ if (resolved.kind === "bearer") {
75
+ return {
76
+ region,
77
+ token: { token: resolved.token },
78
+ authSchemePreference: ["httpBearerAuth"],
79
+ ...endpoint ? { endpoint } : {}
80
+ };
81
+ }
82
+ return {
83
+ region: resolved.region,
84
+ credentials: resolved.credentials,
85
+ ...endpoint ? { endpoint } : {}
86
+ };
87
+ }
88
+ // ---------------------------------------------------------------------------
89
+ // SDK seams (overridden in tests so no real AWS call happens)
90
+ // ---------------------------------------------------------------------------
91
+ async sendStream(input) {
92
+ const { ConverseStreamCommand } = await this.importBedrockRuntime();
93
+ const client = await this.getClient();
94
+ const res = await client.send(new ConverseStreamCommand(input));
95
+ if (!res.stream) {
96
+ throw new Error("Bedrock Converse: empty stream response");
97
+ }
98
+ return res.stream;
99
+ }
100
+ async send(input) {
101
+ const { ConverseCommand } = await this.importBedrockRuntime();
102
+ const client = await this.getClient();
103
+ return client.send(new ConverseCommand(input));
104
+ }
105
+ // ---------------------------------------------------------------------------
106
+ // Public adapter surface
107
+ // ---------------------------------------------------------------------------
108
+ async *chatStream(options) {
109
+ try {
110
+ options.logger.request(
111
+ `activity=chat provider=${this.name} model=${this.model} messages=${options.messages.length} tools=${options.tools?.length ?? 0} stream=true`,
112
+ { provider: this.name, model: this.model }
113
+ );
114
+ const input = this.buildInput(options);
115
+ const stream = await this.sendStream(input);
116
+ yield* processConverseStream(stream, () => this.generateId(), {
117
+ threadId: options.threadId,
118
+ parentRunId: options.parentRunId,
119
+ model: options.model
120
+ });
121
+ } catch (error) {
122
+ const errorPayload = toRunErrorPayload(
123
+ error,
124
+ `${this.name}.chatStream failed`
125
+ );
126
+ options.logger.errors(`${this.name}.chatStream fatal`, {
127
+ error: errorPayload,
128
+ source: `${this.name}.chatStream`
129
+ });
130
+ yield {
131
+ type: EventType.RUN_ERROR,
132
+ model: options.model,
133
+ timestamp: Date.now(),
134
+ message: errorPayload.message,
135
+ ...errorPayload.code !== void 0 && { code: errorPayload.code },
136
+ error: {
137
+ message: errorPayload.message,
138
+ ...errorPayload.code !== void 0 && { code: errorPayload.code }
139
+ }
140
+ };
141
+ }
142
+ }
143
+ /**
144
+ * Structured output via the forced-tool strategy. Converse has no native
145
+ * json_schema response_format, so we force a single tool whose input schema
146
+ * is the requested output schema and read the model's `toolUse.input` back as
147
+ * the structured result.
148
+ */
149
+ async structuredOutput(options) {
150
+ const { chatOptions, outputSchema } = options;
151
+ try {
152
+ chatOptions.logger.request(
153
+ `activity=structuredOutput provider=${this.name} model=${this.model} messages=${chatOptions.messages.length}`,
154
+ { provider: this.name, model: this.model }
155
+ );
156
+ const input = {
157
+ ...this.buildInput(chatOptions),
158
+ toolConfig: buildStructuredToolConfig(outputSchema)
159
+ };
160
+ const res = await this.send(input);
161
+ const structured = extractStructuredToolInput(res);
162
+ if (structured === void 0) {
163
+ throw new Error(
164
+ `${this.name}.structuredOutput: response contained no forced-tool output`
165
+ );
166
+ }
167
+ return {
168
+ data: structured,
169
+ rawText: JSON.stringify(structured)
170
+ };
171
+ } catch (error) {
172
+ chatOptions.logger.errors(`${this.name}.structuredOutput fatal`, {
173
+ error: toRunErrorPayload(error, `${this.name}.structuredOutput failed`),
174
+ source: `${this.name}.structuredOutput`
175
+ });
176
+ throw error;
177
+ }
178
+ }
179
+ /**
180
+ * Streaming structured output. Same forced-tool strategy as
181
+ * `structuredOutput`, but streamed: the forced tool's `toolUse.input` JSON
182
+ * fragments are accumulated from the Converse stream and a terminal
183
+ * `CUSTOM 'structured-output.complete'` event carries `{ object, raw }`,
184
+ * mirroring openai-base's `structuredOutputStream` contract exactly.
185
+ */
186
+ async *structuredOutputStream(options) {
187
+ const { chatOptions, outputSchema } = options;
188
+ const timestamp = Date.now();
189
+ const runId = this.generateId();
190
+ const threadId = chatOptions.threadId ?? this.generateId();
191
+ const messageId = this.generateId();
192
+ let hasEmittedRunStarted = false;
193
+ let hasEmittedTextMessageStart = false;
194
+ let accumulatedRaw = "";
195
+ let finishReason = "stop";
196
+ try {
197
+ chatOptions.logger.request(
198
+ `activity=structuredOutputStream provider=${this.name} model=${this.model} messages=${chatOptions.messages.length}`,
199
+ { provider: this.name, model: this.model }
200
+ );
201
+ const input = {
202
+ ...this.buildInput(chatOptions),
203
+ toolConfig: buildStructuredToolConfig(outputSchema)
204
+ };
205
+ const stream = await this.sendStream(input);
206
+ for await (const ev of stream) {
207
+ if (!hasEmittedRunStarted) {
208
+ hasEmittedRunStarted = true;
209
+ yield {
210
+ type: EventType.RUN_STARTED,
211
+ runId,
212
+ threadId,
213
+ model: chatOptions.model,
214
+ timestamp,
215
+ parentRunId: chatOptions.parentRunId
216
+ };
217
+ }
218
+ throwIfConverseStreamError(ev);
219
+ if ("contentBlockDelta" in ev) {
220
+ const delta = ev.contentBlockDelta?.delta;
221
+ const fragment = delta && "toolUse" in delta ? delta.toolUse?.input : void 0;
222
+ if (fragment !== void 0) {
223
+ if (!hasEmittedTextMessageStart) {
224
+ hasEmittedTextMessageStart = true;
225
+ yield {
226
+ type: EventType.TEXT_MESSAGE_START,
227
+ messageId,
228
+ role: "assistant",
229
+ model: chatOptions.model,
230
+ timestamp
231
+ };
232
+ }
233
+ accumulatedRaw += fragment;
234
+ yield {
235
+ type: EventType.TEXT_MESSAGE_CONTENT,
236
+ messageId,
237
+ delta: fragment,
238
+ content: accumulatedRaw,
239
+ model: chatOptions.model,
240
+ timestamp
241
+ };
242
+ }
243
+ continue;
244
+ }
245
+ if ("messageStop" in ev) {
246
+ const stopReason = ev.messageStop?.stopReason;
247
+ finishReason = stopReason === "max_tokens" ? "length" : stopReason === "content_filtered" ? "content_filter" : "stop";
248
+ continue;
249
+ }
250
+ }
251
+ if (!hasEmittedRunStarted) {
252
+ hasEmittedRunStarted = true;
253
+ yield {
254
+ type: EventType.RUN_STARTED,
255
+ runId,
256
+ threadId,
257
+ model: chatOptions.model,
258
+ timestamp,
259
+ parentRunId: chatOptions.parentRunId
260
+ };
261
+ }
262
+ if (hasEmittedTextMessageStart) {
263
+ yield {
264
+ type: EventType.TEXT_MESSAGE_END,
265
+ messageId,
266
+ model: chatOptions.model,
267
+ timestamp
268
+ };
269
+ }
270
+ if (accumulatedRaw.length === 0) {
271
+ yield {
272
+ type: EventType.RUN_ERROR,
273
+ runId,
274
+ model: chatOptions.model,
275
+ timestamp,
276
+ message: `${this.name}.structuredOutputStream: response contained no content`,
277
+ code: "empty-response",
278
+ error: {
279
+ message: `${this.name}.structuredOutputStream: response contained no content`,
280
+ code: "empty-response"
281
+ }
282
+ };
283
+ return;
284
+ }
285
+ let parsed;
286
+ try {
287
+ parsed = JSON.parse(accumulatedRaw);
288
+ } catch {
289
+ yield {
290
+ type: EventType.RUN_ERROR,
291
+ runId,
292
+ model: chatOptions.model,
293
+ timestamp,
294
+ message: `Failed to parse structured output as JSON. Content: ${accumulatedRaw.slice(0, 200)}${accumulatedRaw.length > 200 ? "..." : ""}`,
295
+ code: "parse-error",
296
+ error: {
297
+ message: "Failed to parse structured output as JSON",
298
+ code: "parse-error"
299
+ }
300
+ };
301
+ return;
302
+ }
303
+ yield {
304
+ type: EventType.CUSTOM,
305
+ name: "structured-output.complete",
306
+ value: {
307
+ object: parsed,
308
+ raw: accumulatedRaw
309
+ },
310
+ model: chatOptions.model,
311
+ timestamp
312
+ };
313
+ yield {
314
+ type: EventType.RUN_FINISHED,
315
+ runId,
316
+ threadId,
317
+ model: chatOptions.model,
318
+ timestamp,
319
+ finishReason
320
+ };
321
+ } catch (error) {
322
+ if (!hasEmittedRunStarted) {
323
+ hasEmittedRunStarted = true;
324
+ yield {
325
+ type: EventType.RUN_STARTED,
326
+ runId,
327
+ threadId,
328
+ model: chatOptions.model,
329
+ timestamp,
330
+ parentRunId: chatOptions.parentRunId
331
+ };
332
+ }
333
+ const errorPayload = toRunErrorPayload(
334
+ error,
335
+ `${this.name}.structuredOutputStream failed`
336
+ );
337
+ chatOptions.logger.errors(`${this.name}.structuredOutputStream fatal`, {
338
+ error: errorPayload,
339
+ source: `${this.name}.structuredOutputStream`
340
+ });
341
+ yield {
342
+ type: EventType.RUN_ERROR,
343
+ runId,
344
+ model: chatOptions.model,
345
+ timestamp,
346
+ message: errorPayload.message,
347
+ ...errorPayload.code !== void 0 && { code: errorPayload.code },
348
+ error: {
349
+ message: errorPayload.message,
350
+ ...errorPayload.code !== void 0 && { code: errorPayload.code }
351
+ }
352
+ };
353
+ }
354
+ }
355
+ /**
356
+ * Converse sends `tools` and a forced structured-output tool via two separate
357
+ * mechanisms, never together. Declaring `false` makes the engine run the
358
+ * agent loop without `outputSchema` and finalize via `structuredOutput` /
359
+ * `structuredOutputStream`.
360
+ */
361
+ supportsCombinedToolsAndSchema() {
362
+ return false;
363
+ }
364
+ // ---------------------------------------------------------------------------
365
+ // Request construction
366
+ // ---------------------------------------------------------------------------
367
+ /**
368
+ * Translate `TextOptions` into a `ConverseCommandInput`. Shared by chatStream,
369
+ * structuredOutput, and structuredOutputStream (the latter two override
370
+ * `toolConfig` with the forced structured tool afterwards).
371
+ */
372
+ buildInput(options) {
373
+ const { system, messages } = toConverseMessages(
374
+ options.messages,
375
+ options.systemPrompts
376
+ );
377
+ const toolConfig = options.tools ? toToolConfig(convertTools(options.tools)) : void 0;
378
+ const modelOptions = options.modelOptions;
379
+ const temperature = modelOptions?.temperature;
380
+ const topP = modelOptions?.top_p;
381
+ const maxTokens = modelOptions?.max_completion_tokens;
382
+ const stop = modelOptions?.stop;
383
+ const stopSequences = stop == null ? void 0 : Array.isArray(stop) ? stop : [stop];
384
+ const inferenceConfig = temperature != null || topP != null || maxTokens != null || stopSequences != null ? {
385
+ ...temperature != null && { temperature },
386
+ ...topP != null && { topP },
387
+ ...maxTokens != null && { maxTokens },
388
+ ...stopSequences != null && { stopSequences }
389
+ } : void 0;
390
+ return {
391
+ modelId: this.model,
392
+ messages,
393
+ ...system.length > 0 && { system },
394
+ ...toolConfig && { toolConfig },
395
+ ...inferenceConfig && { inferenceConfig }
396
+ };
397
+ }
398
+ }
399
+ function convertTools(tools) {
400
+ return tools.map((tool) => {
401
+ const inputSchema = convertSchemaToJsonSchema(
402
+ tool.inputSchema
403
+ ) ?? { type: "object", properties: {}, required: [] };
404
+ return {
405
+ name: tool.name,
406
+ description: tool.description,
407
+ inputSchema
408
+ };
409
+ });
410
+ }
411
+ function extractStructuredToolInput(res) {
412
+ const message = res.output && "message" in res.output ? res.output.message : void 0;
413
+ const content = message?.content ?? [];
414
+ for (const block of content) {
415
+ if ("toolUse" in block && block.toolUse) {
416
+ if (block.toolUse.name === STRUCTURED_TOOL_NAME || block.toolUse.name === void 0) {
417
+ return block.toolUse.input;
418
+ }
419
+ }
420
+ }
421
+ return void 0;
422
+ }
423
+ function createBedrockConverse(model, apiKey, config) {
424
+ return new BedrockConverseTextAdapter({ ...config, apiKey }, model);
425
+ }
426
+ export {
427
+ BedrockConverseTextAdapter,
428
+ createBedrockConverse
429
+ };
430
+ //# sourceMappingURL=converse-text.js.map