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

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";
@@ -119,33 +120,6 @@ const DEFAULT_COST = {
119
120
  cacheRead: 0,
120
121
  cacheWrite: 0
121
122
  };
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
123
  const discoveryCache = /* @__PURE__ */ new Map();
150
124
  let hasLoggedBedrockError = false;
151
125
  function normalizeProviderFilter(filter) {
@@ -248,7 +222,11 @@ async function fetchInferenceProfileSummaries(client, createListInferenceProfile
248
222
  const profiles = [];
249
223
  let nextToken;
250
224
  do {
251
- const response = await client.send(createListInferenceProfilesCommand({ nextToken }));
225
+ const command = createListInferenceProfilesCommand({ nextToken });
226
+ const response = await runBedrockControlPlaneRequest({
227
+ operation: "Bedrock ListInferenceProfiles",
228
+ send: (options) => client.send(command, options)
229
+ });
252
230
  for (const summary of response.inferenceProfileSummaries ?? []) profiles.push(summary);
253
231
  nextToken = response.nextToken;
254
232
  } while (nextToken);
@@ -328,44 +306,51 @@ async function discoverBedrockModels(params) {
328
306
  }
329
307
  if (cached) discoveryCache.delete(cacheKey);
330
308
  }
331
- const sdk = params.clientFactory ? createInjectedClientDiscoverySdk() : await loadBedrockDiscoverySdk();
309
+ const sdk = await loadBedrockControlPlaneSdk();
332
310
  const clientFactory = params.clientFactory ?? ((region) => sdk.createClient(region));
333
311
  if (!params.clientFactory) await refreshAwsSharedConfigCacheForBedrock();
334
312
  const client = clientFactory(params.region);
335
313
  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, {
314
+ try {
315
+ const foundationCommand = sdk.createListFoundationModelsCommand();
316
+ const [foundationResponse, profileSummaries] = await Promise.all([runBedrockControlPlaneRequest({
317
+ operation: "Bedrock ListFoundationModels",
318
+ send: (options) => client.send(foundationCommand, options)
319
+ }), fetchInferenceProfileSummaries(client, (input) => sdk.createListInferenceProfilesCommand(input))]);
320
+ const discovered = [];
321
+ const seenIds = /* @__PURE__ */ new Set();
322
+ const foundationModels = /* @__PURE__ */ new Map();
323
+ for (const summary of foundationResponse.modelSummaries ?? []) {
324
+ if (!shouldIncludeSummary(summary, providerFilter)) continue;
325
+ const def = toModelDefinition(summary, {
326
+ contextWindow: defaultContextWindow,
327
+ maxTokens: defaultMaxTokens
328
+ });
329
+ discovered.push(def);
330
+ const normalizedId = normalizeLowercaseStringOrEmpty(def.id);
331
+ seenIds.add(normalizedId);
332
+ foundationModels.set(normalizedId, def);
333
+ }
334
+ const inferenceProfiles = resolveInferenceProfiles(profileSummaries, {
344
335
  contextWindow: defaultContextWindow,
345
336
  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);
337
+ }, providerFilter, foundationModels);
338
+ for (const profile of inferenceProfiles) {
339
+ const normalizedId = normalizeLowercaseStringOrEmpty(profile.id);
340
+ if (!seenIds.has(normalizedId)) {
341
+ discovered.push(profile);
342
+ seenIds.add(normalizedId);
343
+ }
361
344
  }
345
+ return discovered.toSorted((a, b) => {
346
+ const aGlobal = a.id.startsWith("global.") ? 0 : 1;
347
+ const bGlobal = b.id.startsWith("global.") ? 0 : 1;
348
+ if (aGlobal !== bGlobal) return aGlobal - bGlobal;
349
+ return a.name.localeCompare(b.name);
350
+ });
351
+ } finally {
352
+ client.destroy();
362
353
  }
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
354
  })();
370
355
  if (refreshIntervalSeconds > 0) {
371
356
  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,
@@ -474,6 +475,21 @@ function normalizeToolCallId(id) {
474
475
  const sanitized = id.replace(/[^a-zA-Z0-9_-]/g, "_");
475
476
  return sanitized.length > 64 ? sanitized.slice(0, 64) : sanitized;
476
477
  }
478
+ function createBedrockToolResult(message) {
479
+ const content = [];
480
+ for (const block of message.content) {
481
+ if (block.type === "text") {
482
+ content.push({ text: sanitizeSurrogates(block.text) });
483
+ continue;
484
+ }
485
+ if (describeToolResultMediaPlaceholder([block])) content.push({ image: createImageBlock(block.mimeType, block.data) });
486
+ }
487
+ return { toolResult: {
488
+ toolUseId: message.toolCallId,
489
+ content: content.length > 0 ? content : [{ text: "(no output)" }],
490
+ status: message.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS
491
+ } };
492
+ }
477
493
  function convertMessages(context, model, cacheRetention) {
478
494
  const result = [];
479
495
  const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);
@@ -541,20 +557,12 @@ function convertMessages(context, model, cacheRetention) {
541
557
  }
542
558
  case "toolResult": {
543
559
  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
- } });
560
+ toolResults.push(createBedrockToolResult(m));
549
561
  let j = i + 1;
550
562
  while (true) {
551
563
  const nextMsg = transformedMessages.at(j);
552
564
  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
- } });
565
+ toolResults.push(createBedrockToolResult(nextMsg));
558
566
  j++;
559
567
  }
560
568
  i = j - 1;
@@ -704,5 +712,6 @@ const testing = {
704
712
  resolveSimpleBedrockOptions,
705
713
  shouldUseExplicitBedrockEndpoint
706
714
  };
715
+ if (process.env.VITEST === "true") Reflect.set(globalThis, Symbol.for("openclaw.amazonBedrockStreamTestApi"), testing);
707
716
  //#endregion
708
- export { streamBedrock, streamSimpleBedrock, testing };
717
+ 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.2",
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.2",
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.2",
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.2"
29
29
  },
30
30
  "build": {
31
- "openclawVersion": "2026.7.2-beta.1",
31
+ "openclawVersion": "2026.7.2-beta.2",
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.2"
50
50
  },
51
51
  "peerDependenciesMeta": {
52
52
  "openclaw": {