@openclaw/amazon-bedrock-provider 2026.7.2-beta.1 → 2026.7.2-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ import { buildTimeoutAbortSignal } from "openclaw/plugin-sdk/extension-shared";
2
+ //#region extensions/amazon-bedrock/control-plane.ts
3
+ const BEDROCK_CONTROL_PLANE_REQUEST_TIMEOUT_MS = 3e4;
4
+ async function loadBedrockControlPlaneSdk() {
5
+ const { BedrockClient, GetInferenceProfileCommand, ListFoundationModelsCommand, ListInferenceProfilesCommand } = await import("@aws-sdk/client-bedrock");
6
+ return {
7
+ createClient: (region) => new BedrockClient(region ? { region } : {}),
8
+ createGetInferenceProfileCommand: (input) => new GetInferenceProfileCommand(input),
9
+ createListFoundationModelsCommand: () => new ListFoundationModelsCommand({}),
10
+ createListInferenceProfilesCommand: (input) => new ListInferenceProfilesCommand(input)
11
+ };
12
+ }
13
+ async function runBedrockControlPlaneRequest(params) {
14
+ const { signal, cleanup } = buildTimeoutAbortSignal({
15
+ timeoutMs: BEDROCK_CONTROL_PLANE_REQUEST_TIMEOUT_MS,
16
+ signal: params.signal,
17
+ operation: params.operation
18
+ });
19
+ try {
20
+ signal?.throwIfAborted();
21
+ const response = await params.send({ abortSignal: signal });
22
+ signal?.throwIfAborted();
23
+ return response;
24
+ } finally {
25
+ cleanup();
26
+ }
27
+ }
28
+ //#endregion
29
+ export { loadBedrockControlPlaneSdk, runBedrockControlPlaneRequest };
package/dist/discovery.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { refreshAwsSharedConfigCacheForBedrock } from "./aws-credential-refresh.js";
2
+ import { loadBedrockControlPlaneSdk, runBedrockControlPlaneRequest } from "./control-plane.js";
2
3
  import { resolveBedrockConfigApiKey } from "./discovery-shared.js";
3
4
  import { resolveBedrockNativeThinkingLevelMap } from "./thinking-policy.js";
4
5
  import { resolveClaudeFable5ModelIdentity, resolveClaudeModelIdentity, resolveClaudeMythos5ModelIdentity, resolveClaudeSonnet5ModelIdentity, supportsClaudeAdaptiveThinking } from "openclaw/plugin-sdk/provider-model-shared";
@@ -35,9 +36,7 @@ const KNOWN_CONTEXT_WINDOWS = {
35
36
  "anthropic.claude-opus-4-8": 1e6,
36
37
  "anthropic.claude-opus-4-7": 1e6,
37
38
  "anthropic.claude-opus-4-6-v1": 1e6,
38
- "anthropic.claude-opus-4-6-v1:0": 1e6,
39
39
  "anthropic.claude-sonnet-4-6": 1e6,
40
- "anthropic.claude-sonnet-4-6-v1:0": 1e6,
41
40
  "anthropic.claude-sonnet-4-5-20250929-v1:0": 2e5,
42
41
  "anthropic.claude-sonnet-4-20250514-v1:0": 2e5,
43
42
  "anthropic.claude-opus-4-5-20251101-v1:0": 2e5,
@@ -119,33 +118,6 @@ const DEFAULT_COST = {
119
118
  cacheRead: 0,
120
119
  cacheWrite: 0
121
120
  };
122
- async function loadBedrockDiscoverySdk() {
123
- const { BedrockClient, ListFoundationModelsCommand, ListInferenceProfilesCommand } = await import("@aws-sdk/client-bedrock");
124
- return {
125
- createClient: (region) => new BedrockClient({ region }),
126
- createListFoundationModelsCommand: () => new ListFoundationModelsCommand({}),
127
- createListInferenceProfilesCommand: (input) => new ListInferenceProfilesCommand(input)
128
- };
129
- }
130
- function createInjectedClientDiscoverySdk() {
131
- class ListFoundationModelsCommand {
132
- constructor(input = {}) {
133
- this.input = input;
134
- }
135
- }
136
- class ListInferenceProfilesCommand {
137
- constructor(input = {}) {
138
- this.input = input;
139
- }
140
- }
141
- return {
142
- createClient() {
143
- throw new Error("clientFactory is required for injected Bedrock discovery commands");
144
- },
145
- createListFoundationModelsCommand: () => new ListFoundationModelsCommand({}),
146
- createListInferenceProfilesCommand: (input) => new ListInferenceProfilesCommand(input)
147
- };
148
- }
149
121
  const discoveryCache = /* @__PURE__ */ new Map();
150
122
  let hasLoggedBedrockError = false;
151
123
  function normalizeProviderFilter(filter) {
@@ -248,7 +220,11 @@ async function fetchInferenceProfileSummaries(client, createListInferenceProfile
248
220
  const profiles = [];
249
221
  let nextToken;
250
222
  do {
251
- const response = await client.send(createListInferenceProfilesCommand({ nextToken }));
223
+ const command = createListInferenceProfilesCommand({ nextToken });
224
+ const response = await runBedrockControlPlaneRequest({
225
+ operation: "Bedrock ListInferenceProfiles",
226
+ send: (options) => client.send(command, options)
227
+ });
252
228
  for (const summary of response.inferenceProfileSummaries ?? []) profiles.push(summary);
253
229
  nextToken = response.nextToken;
254
230
  } while (nextToken);
@@ -328,44 +304,51 @@ async function discoverBedrockModels(params) {
328
304
  }
329
305
  if (cached) discoveryCache.delete(cacheKey);
330
306
  }
331
- const sdk = params.clientFactory ? createInjectedClientDiscoverySdk() : await loadBedrockDiscoverySdk();
307
+ const sdk = await loadBedrockControlPlaneSdk();
332
308
  const clientFactory = params.clientFactory ?? ((region) => sdk.createClient(region));
333
309
  if (!params.clientFactory) await refreshAwsSharedConfigCacheForBedrock();
334
310
  const client = clientFactory(params.region);
335
311
  const discoveryPromise = (async () => {
336
- const [rawFoundationResponse, profileSummaries] = await Promise.all([client.send(sdk.createListFoundationModelsCommand()), fetchInferenceProfileSummaries(client, (input) => sdk.createListInferenceProfilesCommand(input))]);
337
- const foundationResponse = rawFoundationResponse;
338
- const discovered = [];
339
- const seenIds = /* @__PURE__ */ new Set();
340
- const foundationModels = /* @__PURE__ */ new Map();
341
- for (const summary of foundationResponse.modelSummaries ?? []) {
342
- if (!shouldIncludeSummary(summary, providerFilter)) continue;
343
- const def = toModelDefinition(summary, {
312
+ try {
313
+ const foundationCommand = sdk.createListFoundationModelsCommand();
314
+ const [foundationResponse, profileSummaries] = await Promise.all([runBedrockControlPlaneRequest({
315
+ operation: "Bedrock ListFoundationModels",
316
+ send: (options) => client.send(foundationCommand, options)
317
+ }), fetchInferenceProfileSummaries(client, (input) => sdk.createListInferenceProfilesCommand(input))]);
318
+ const discovered = [];
319
+ const seenIds = /* @__PURE__ */ new Set();
320
+ const foundationModels = /* @__PURE__ */ new Map();
321
+ for (const summary of foundationResponse.modelSummaries ?? []) {
322
+ if (!shouldIncludeSummary(summary, providerFilter)) continue;
323
+ const def = toModelDefinition(summary, {
324
+ contextWindow: defaultContextWindow,
325
+ maxTokens: defaultMaxTokens
326
+ });
327
+ discovered.push(def);
328
+ const normalizedId = normalizeLowercaseStringOrEmpty(def.id);
329
+ seenIds.add(normalizedId);
330
+ foundationModels.set(normalizedId, def);
331
+ }
332
+ const inferenceProfiles = resolveInferenceProfiles(profileSummaries, {
344
333
  contextWindow: defaultContextWindow,
345
334
  maxTokens: defaultMaxTokens
346
- });
347
- discovered.push(def);
348
- const normalizedId = normalizeLowercaseStringOrEmpty(def.id);
349
- seenIds.add(normalizedId);
350
- foundationModels.set(normalizedId, def);
351
- }
352
- const inferenceProfiles = resolveInferenceProfiles(profileSummaries, {
353
- contextWindow: defaultContextWindow,
354
- maxTokens: defaultMaxTokens
355
- }, providerFilter, foundationModels);
356
- for (const profile of inferenceProfiles) {
357
- const normalizedId = normalizeLowercaseStringOrEmpty(profile.id);
358
- if (!seenIds.has(normalizedId)) {
359
- discovered.push(profile);
360
- seenIds.add(normalizedId);
335
+ }, providerFilter, foundationModels);
336
+ for (const profile of inferenceProfiles) {
337
+ const normalizedId = normalizeLowercaseStringOrEmpty(profile.id);
338
+ if (!seenIds.has(normalizedId)) {
339
+ discovered.push(profile);
340
+ seenIds.add(normalizedId);
341
+ }
361
342
  }
343
+ return discovered.toSorted((a, b) => {
344
+ const aGlobal = a.id.startsWith("global.") ? 0 : 1;
345
+ const bGlobal = b.id.startsWith("global.") ? 0 : 1;
346
+ if (aGlobal !== bGlobal) return aGlobal - bGlobal;
347
+ return a.name.localeCompare(b.name);
348
+ });
349
+ } finally {
350
+ client.destroy();
362
351
  }
363
- return discovered.toSorted((a, b) => {
364
- const aGlobal = a.id.startsWith("global.") ? 0 : 1;
365
- const bGlobal = b.id.startsWith("global.") ? 0 : 1;
366
- if (aGlobal !== bGlobal) return aGlobal - bGlobal;
367
- return a.name.localeCompare(b.name);
368
- });
369
352
  })();
370
353
  if (refreshIntervalSeconds > 0) {
371
354
  const expiresAt = resolveExpiresAtMsFromDurationSeconds(refreshIntervalSeconds, { nowMs: now });
@@ -216,6 +216,7 @@ const testing = {
216
216
  parseSingle,
217
217
  stripInferenceProfilePrefix
218
218
  };
219
+ if (process.env.VITEST === "true") Reflect.set(globalThis, Symbol.for("openclaw.amazonBedrockEmbeddingTestApi"), testing);
219
220
  async function createBedrockEmbeddingProvider(options) {
220
221
  const client = resolveBedrockEmbeddingClient(options);
221
222
  const { BedrockRuntimeClient, InvokeModelCommand } = await loadSdk();
@@ -304,4 +305,4 @@ async function hasAwsCredentials(env = process.env, loadCredentialProvider = loa
304
305
  }
305
306
  }
306
307
  //#endregion
307
- export { DEFAULT_BEDROCK_EMBEDDING_MODEL, testing as __testing, testing, createBedrockEmbeddingProvider, hasAwsCredentials };
308
+ export { DEFAULT_BEDROCK_EMBEDDING_MODEL, createBedrockEmbeddingProvider, hasAwsCredentials };
@@ -1,12 +1,13 @@
1
1
  import { refreshAwsSharedConfigCacheForBedrock } from "./aws-credential-refresh.js";
2
2
  import { supportsBedrockPromptCaching } from "./bedrock-options.js";
3
+ import { loadBedrockControlPlaneSdk, runBedrockControlPlaneRequest } from "./control-plane.js";
3
4
  import { mergeImplicitBedrockProvider, resolveBedrockConfigApiKey } from "./discovery-shared.js";
4
5
  import { bedrockMemoryEmbeddingProviderAdapter } from "./memory-embedding-adapter.js";
5
6
  import { isLatestAdaptiveBedrockModelRef, isOpus47OrNewerBedrockModelRef, resolveBedrockClaudeThinkingProfile, resolveBedrockNativeThinkingLevelMap, supportsBedrockNativeMaxEffort } from "./thinking-policy.js";
6
7
  import { streamBedrock, streamSimpleBedrock } from "./stream.runtime.js";
7
8
  import { registerApiProvider, streamSimple } from "openclaw/plugin-sdk/llm";
8
9
  import { resolvePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
9
- import { ANTHROPIC_BY_MODEL_REPLAY_HOOKS, normalizeProviderId, resolveClaudeFable5ModelIdentity, resolveClaudeModelIdentity, resolveClaudeMythos5ModelIdentity, resolveClaudeSonnet5ModelIdentity } from "openclaw/plugin-sdk/provider-model-shared";
10
+ import { buildProviderReplayFamilyHooks, normalizeProviderId, resolveClaudeFable5ModelIdentity, resolveClaudeModelIdentity, resolveClaudeMythos5ModelIdentity, resolveClaudeSonnet5ModelIdentity } from "openclaw/plugin-sdk/provider-model-shared";
10
11
  import { streamWithPayloadPatch } from "openclaw/plugin-sdk/provider-stream-shared";
11
12
  //#region extensions/amazon-bedrock/register.sync.runtime.ts
12
13
  function normalizeBedrockResolvedModel({ modelId, model }) {
@@ -129,14 +130,23 @@ function resolvedModelSupportsCaching(modelArn) {
129
130
  return supportsBedrockPromptCaching(modelArn);
130
131
  }
131
132
  const appProfileTraitsCache = /* @__PURE__ */ new Map();
132
- async function resolveAppProfileTraits(modelId, fallbackRegion) {
133
+ async function resolveAppProfileTraits(modelId, fallbackRegion, signal) {
133
134
  const cached = appProfileTraitsCache.get(modelId);
134
135
  if (cached) return cached;
136
+ let client;
135
137
  try {
138
+ signal?.throwIfAborted();
136
139
  const region = extractRegionFromArn(modelId) ?? fallbackRegion;
137
- await refreshAwsSharedConfigCacheForBedrock();
138
- const { BedrockClient, GetInferenceProfileCommand } = await import("@aws-sdk/client-bedrock");
139
- const models = (await new BedrockClient(region ? { region } : {}).send(new GetInferenceProfileCommand({ inferenceProfileIdentifier: modelId }))).models ?? [];
140
+ const sdk = await loadBedrockControlPlaneSdk();
141
+ signal?.throwIfAborted();
142
+ const controlPlaneClient = sdk.createClient(region);
143
+ client = controlPlaneClient;
144
+ const command = sdk.createGetInferenceProfileCommand({ inferenceProfileIdentifier: modelId });
145
+ const models = (await runBedrockControlPlaneRequest({
146
+ operation: "Bedrock GetInferenceProfile",
147
+ signal,
148
+ send: (options) => controlPlaneClient.send(command, options)
149
+ })).models ?? [];
140
150
  const modelArns = models.map((model) => model.modelArn ?? "");
141
151
  const traits = {
142
152
  cacheEligible: models.length > 0 && modelArns.every((modelArn) => resolvedModelSupportsCaching(modelArn)),
@@ -145,10 +155,13 @@ async function resolveAppProfileTraits(modelId, fallbackRegion) {
145
155
  appProfileTraitsCache.set(modelId, traits);
146
156
  return traits;
147
157
  } catch {
158
+ signal?.throwIfAborted();
148
159
  return {
149
160
  cacheEligible: isAnthropicBedrockModel(modelId),
150
161
  omitTemperature: isOpus47OrNewerBedrockModelRef(modelId)
151
162
  };
163
+ } finally {
164
+ client?.destroy();
152
165
  }
153
166
  }
154
167
  function hasCachePoint(blocks) {
@@ -196,7 +209,7 @@ function registerAmazonBedrockPlugin(api) {
196
209
  /ModelStreamErrorException.*(?:Input is too long|too many input tokens)/i
197
210
  ];
198
211
  const deprecatedTemperatureValidationRe = /ValidationException[\s\S]*(?:invalid_request_error[\s\S]*)?temperature[\s\S]*deprecated|ValidationException[\s\S]*deprecated[\s\S]*temperature/i;
199
- const anthropicByModelReplayHooks = ANTHROPIC_BY_MODEL_REPLAY_HOOKS;
212
+ const anthropicByModelReplayHooks = buildProviderReplayFamilyHooks({ family: "anthropic-by-model" });
200
213
  const startupPluginConfig = api.pluginConfig ?? {};
201
214
  registerApiProvider({
202
215
  api: "bedrock-converse-stream",
@@ -233,7 +246,10 @@ function registerAmazonBedrockPlugin(api) {
233
246
  return {
234
247
  ...options,
235
248
  onPayload: async (payload, payloadModel) => {
249
+ const signal = options.signal;
250
+ signal?.throwIfAborted();
236
251
  await refreshAwsSharedConfigCacheForBedrock();
252
+ signal?.throwIfAborted();
237
253
  return originalOnPayload?.(payload, payloadModel);
238
254
  }
239
255
  };
@@ -347,7 +363,7 @@ function registerAmazonBedrockPlugin(api) {
347
363
  if (shouldPatchMaxThinking) patchMaxThinkingEffort(payloadRecord);
348
364
  if (shouldOmitTemperature) omitUnsupportedClaudePayloadTemperature(payloadRecord);
349
365
  else if (mayNeedTemperatureTrait) {
350
- if ((await resolveAppProfileTraits(modelId, region)).omitTemperature) omitUnsupportedClaudePayloadTemperature(payloadRecord);
366
+ if ((await resolveAppProfileTraits(modelId, region, merged.signal)).omitTemperature) omitUnsupportedClaudePayloadTemperature(payloadRecord);
351
367
  }
352
368
  }
353
369
  return originalOnPayload?.(payload, payloadModel);
@@ -357,7 +373,7 @@ function registerAmazonBedrockPlugin(api) {
357
373
  return underlying(streamModel, context, withAwsCredentialRefreshOnPayload({
358
374
  ...merged,
359
375
  onPayload: async (payload, payloadModel) => {
360
- const traits = await resolveAppProfileTraits(modelId, region);
376
+ const traits = await resolveAppProfileTraits(modelId, region, merged.signal);
361
377
  if (payload && typeof payload === "object") {
362
378
  const payloadRecord = payload;
363
379
  if (traits.cacheEligible) injectBedrockCachePoints(payloadRecord, cacheRetention);
@@ -6,6 +6,7 @@ import { applyAnthropicRefusal, createDeferredEventBuffer, notifyLlmRequestActiv
6
6
  import { BedrockRuntimeClient, BedrockRuntimeServiceException, CachePointType, CacheTTL, ConversationRole, ConverseStreamCommand, ImageFormat, StopReason, ToolResultStatus } from "@aws-sdk/client-bedrock-runtime";
7
7
  import { NodeHttpHandler } from "@smithy/node-http-handler";
8
8
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
9
+ import { describeToolResultMediaPlaceholder } from "openclaw/plugin-sdk/provider-transport-runtime";
9
10
  //#region extensions/amazon-bedrock/stream.runtime.ts
10
11
  /**
11
12
  * Amazon Bedrock Converse streaming runtime. It maps OpenClaw messages/tools,
@@ -71,14 +72,15 @@ const streamBedrock = (model, context, options = {}) => {
71
72
  const eventSink = refusalBuffer ?? stream;
72
73
  const config = { profile: options.profile };
73
74
  const configuredRegion = getConfiguredBedrockRegion(options);
75
+ const requestRegion = options.region || getBedrockModelArnRegion(model.id) || configuredRegion;
74
76
  const hasConfiguredProfile = hasConfiguredBedrockProfile(options);
75
77
  const endpointRegion = getStandardBedrockEndpointRegion(model.baseUrl);
76
- const useExplicitEndpoint = shouldUseExplicitBedrockEndpoint(model.baseUrl, configuredRegion, hasConfiguredProfile);
78
+ const useExplicitEndpoint = shouldUseExplicitBedrockEndpoint(model.baseUrl, requestRegion, hasConfiguredProfile);
77
79
  if (useExplicitEndpoint) config.endpoint = model.baseUrl;
78
80
  const bearerToken = options.bearerToken || process.env.AWS_BEARER_TOKEN_BEDROCK || void 0;
79
81
  const useBearerToken = bearerToken !== void 0 && process.env.AWS_BEDROCK_SKIP_AUTH !== "1";
80
82
  if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
81
- if (configuredRegion) config.region = configuredRegion;
83
+ if (requestRegion) config.region = requestRegion;
82
84
  else if (endpointRegion && useExplicitEndpoint) config.region = endpointRegion;
83
85
  else if (!hasConfiguredProfile) config.region = "us-east-1";
84
86
  if (process.env.AWS_BEDROCK_SKIP_AUTH === "1") config.credentials = {
@@ -88,7 +90,7 @@ const streamBedrock = (model, context, options = {}) => {
88
90
  const proxyAgents = createHttpProxyAgentsForTarget(model.baseUrl);
89
91
  if (proxyAgents) config.requestHandler = new NodeHttpHandler(proxyAgents);
90
92
  else if (process.env.AWS_BEDROCK_FORCE_HTTP1 === "1") config.requestHandler = new NodeHttpHandler();
91
- } else config.region = configuredRegion || (endpointRegion && useExplicitEndpoint ? endpointRegion : void 0) || "us-east-1";
93
+ } else config.region = requestRegion || (endpointRegion && useExplicitEndpoint ? endpointRegion : void 0) || "us-east-1";
92
94
  if (useBearerToken) {
93
95
  config.token = { token: bearerToken };
94
96
  config.authSchemePreference = ["httpBearerAuth"];
@@ -137,7 +139,11 @@ const streamBedrock = (model, context, options = {}) => {
137
139
  else if (item.messageStop) {
138
140
  sawMessageStop = true;
139
141
  if (item.messageStop.stopReason === "refusal") applyAnthropicRefusal(output, readBedrockStopDetails(item.messageStop.additionalModelResponseFields), model.provider);
140
- else output.stopReason = mapStopReason(item.messageStop.stopReason);
142
+ else {
143
+ const mappedStop = mapStopReason(item.messageStop.stopReason);
144
+ output.stopReason = mappedStop.stopReason;
145
+ if (mappedStop.errorMessage) output.errorMessage = mappedStop.errorMessage;
146
+ }
141
147
  } else if (item.metadata) handleMetadata(item.metadata, model, output);
142
148
  else if (item.internalServerException) throw item.internalServerException;
143
149
  else if (item.modelStreamErrorException) throw item.modelStreamErrorException;
@@ -474,6 +480,21 @@ function normalizeToolCallId(id) {
474
480
  const sanitized = id.replace(/[^a-zA-Z0-9_-]/g, "_");
475
481
  return sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;
476
482
  }
483
+ function createBedrockToolResult(message) {
484
+ const content = [];
485
+ for (const block of message.content) {
486
+ if (block.type === "text") {
487
+ content.push({ text: sanitizeSurrogates(block.text) });
488
+ continue;
489
+ }
490
+ if (describeToolResultMediaPlaceholder([block])) content.push({ image: createImageBlock(block.mimeType, block.data) });
491
+ }
492
+ return { toolResult: {
493
+ toolUseId: message.toolCallId,
494
+ content: content.length > 0 ? content : [{ text: "(no output)" }],
495
+ status: message.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS
496
+ } };
497
+ }
477
498
  function convertMessages(context, model, cacheRetention) {
478
499
  const result = [];
479
500
  const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);
@@ -541,20 +562,12 @@ function convertMessages(context, model, cacheRetention) {
541
562
  }
542
563
  case "toolResult": {
543
564
  const toolResults = [];
544
- toolResults.push({ toolResult: {
545
- toolUseId: m.toolCallId,
546
- content: m.content.map((c) => c.type === "image" ? { image: createImageBlock(c.mimeType, c.data) } : { text: sanitizeSurrogates(c.text) }),
547
- status: m.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS
548
- } });
565
+ toolResults.push(createBedrockToolResult(m));
549
566
  let j = i + 1;
550
567
  while (true) {
551
568
  const nextMsg = transformedMessages.at(j);
552
569
  if (nextMsg?.role !== "toolResult") break;
553
- toolResults.push({ toolResult: {
554
- toolUseId: nextMsg.toolCallId,
555
- content: nextMsg.content.map((c) => c.type === "image" ? { image: createImageBlock(c.mimeType, c.data) } : { text: sanitizeSurrogates(c.text) }),
556
- status: nextMsg.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS
557
- } });
570
+ toolResults.push(createBedrockToolResult(nextMsg));
558
571
  j++;
559
572
  }
560
573
  i = j - 1;
@@ -601,13 +614,26 @@ function convertToolConfig(tools, toolChoice) {
601
614
  function mapStopReason(reason) {
602
615
  switch (reason) {
603
616
  case StopReason.END_TURN:
604
- case StopReason.STOP_SEQUENCE: return "stop";
617
+ case StopReason.STOP_SEQUENCE: return { stopReason: "stop" };
605
618
  case StopReason.MAX_TOKENS:
606
- case StopReason.MODEL_CONTEXT_WINDOW_EXCEEDED: return "length";
607
- case StopReason.TOOL_USE: return "toolUse";
608
- default: return "error";
619
+ case StopReason.MODEL_CONTEXT_WINDOW_EXCEEDED: return { stopReason: "length" };
620
+ case StopReason.TOOL_USE: return { stopReason: "toolUse" };
621
+ case StopReason.CONTENT_FILTERED:
622
+ case StopReason.GUARDRAIL_INTERVENED:
623
+ case StopReason.MALFORMED_MODEL_OUTPUT:
624
+ case StopReason.MALFORMED_TOOL_USE: return {
625
+ stopReason: "error",
626
+ errorMessage: reason
627
+ };
628
+ default: return reason ? {
629
+ stopReason: "error",
630
+ errorMessage: reason
631
+ } : { stopReason: "error" };
609
632
  }
610
633
  }
634
+ function getBedrockModelArnRegion(modelId) {
635
+ return /^arn:aws(?:-[a-z0-9-]+)?:bedrock:([a-z0-9-]+):/.exec(modelId)?.[1];
636
+ }
611
637
  function getConfiguredBedrockRegion(options) {
612
638
  if (typeof process === "undefined") return options.region;
613
639
  return options.region || process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || void 0;
@@ -704,5 +730,6 @@ const testing = {
704
730
  resolveSimpleBedrockOptions,
705
731
  shouldUseExplicitBedrockEndpoint
706
732
  };
733
+ if (process.env.VITEST === "true") Reflect.set(globalThis, Symbol.for("openclaw.amazonBedrockStreamTestApi"), testing);
707
734
  //#endregion
708
- export { streamBedrock, streamSimpleBedrock, testing };
735
+ export { streamBedrock, streamSimpleBedrock };
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@openclaw/amazon-bedrock-provider",
3
- "version": "2026.7.2-beta.1",
3
+ "version": "2026.7.2-beta.3",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/amazon-bedrock-provider",
9
- "version": "2026.7.2-beta.1",
9
+ "version": "2026.7.2-beta.3",
10
10
  "dependencies": {
11
11
  "@aws-sdk/client-bedrock": "3.1078.0",
12
12
  "@aws-sdk/client-bedrock-runtime": "3.1078.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/amazon-bedrock-provider",
3
- "version": "2026.7.2-beta.1",
3
+ "version": "2026.7.2-beta.3",
4
4
  "description": "OpenClaw Amazon Bedrock provider plugin with model discovery, embeddings, and guardrail support.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,10 +25,10 @@
25
25
  "minHostVersion": ">=2026.5.12-beta.1"
26
26
  },
27
27
  "compat": {
28
- "pluginApi": ">=2026.7.2-beta.1"
28
+ "pluginApi": ">=2026.7.2-beta.3"
29
29
  },
30
30
  "build": {
31
- "openclawVersion": "2026.7.2-beta.1",
31
+ "openclawVersion": "2026.7.2-beta.3",
32
32
  "bundledDist": false
33
33
  },
34
34
  "release": {
@@ -46,7 +46,7 @@
46
46
  "README.md"
47
47
  ],
48
48
  "peerDependencies": {
49
- "openclaw": ">=2026.7.2-beta.1"
49
+ "openclaw": ">=2026.7.2-beta.3"
50
50
  },
51
51
  "peerDependenciesMeta": {
52
52
  "openclaw": {