@openclaw/amazon-bedrock-provider 2026.8.1-beta.2 → 2026.8.1-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.
package/dist/api.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { mergeImplicitBedrockProvider, resolveBedrockConfigApiKey } from "./discovery-shared.js";
2
- import { discoverBedrockModels, resetBedrockDiscoveryCacheForTest, resolveImplicitBedrockProvider } from "./discovery.js";
3
- export { discoverBedrockModels, mergeImplicitBedrockProvider, resetBedrockDiscoveryCacheForTest, resolveBedrockConfigApiKey, resolveImplicitBedrockProvider };
2
+ import { discoverBedrockModels, resolveImplicitBedrockProvider } from "./discovery.js";
3
+ export { discoverBedrockModels, mergeImplicitBedrockProvider, resolveBedrockConfigApiKey, resolveImplicitBedrockProvider };
package/dist/discovery.js CHANGED
@@ -278,11 +278,6 @@ function resolveInferenceProfiles(profiles, defaults, providerFilter, foundation
278
278
  }
279
279
  return discovered;
280
280
  }
281
- /** Reset Bedrock discovery cache for tests. */
282
- function resetBedrockDiscoveryCacheForTest() {
283
- discoveryCache.clear();
284
- hasLoggedBedrockError = false;
285
- }
286
281
  /** Discover Bedrock models and inference profiles for one region/config. */
287
282
  async function discoverBedrockModels(params) {
288
283
  const refreshIntervalSeconds = Math.max(0, Math.floor(params.config?.refreshInterval ?? DEFAULT_REFRESH_INTERVAL_SECONDS));
@@ -400,4 +395,4 @@ async function resolveImplicitBedrockProvider(params) {
400
395
  };
401
396
  }
402
397
  //#endregion
403
- export { discoverBedrockModels, resetBedrockDiscoveryCacheForTest, resolveImplicitBedrockProvider };
398
+ export { discoverBedrockModels, resolveImplicitBedrockProvider };
@@ -5,6 +5,7 @@ import { mergeImplicitBedrockProvider, resolveBedrockConfigApiKey } from "./disc
5
5
  import { bedrockMemoryEmbeddingProviderAdapter } from "./memory-embedding-adapter.js";
6
6
  import { isLatestAdaptiveBedrockModelRef, isOpus47OrNewerBedrockModelRef, resolveBedrockClaudeThinkingProfile, resolveBedrockNativeThinkingLevelMap, supportsBedrockNativeMaxEffort } from "./thinking-policy.js";
7
7
  import { streamSimpleBedrock } from "./stream.runtime.js";
8
+ import { adaptMemoryEmbeddingProviderAdapter } from "openclaw/plugin-sdk/memory-core-host-engine-embeddings";
8
9
  import { resolvePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
9
10
  import { buildProviderReplayFamilyHooks, normalizeProviderId, resolveClaudeFable5ModelIdentity, resolveClaudeModelIdentity, resolveClaudeMythos5ModelIdentity, resolveClaudeOpus5ModelIdentity, resolveClaudeSonnet5ModelIdentity } from "openclaw/plugin-sdk/provider-model-shared";
10
11
  import { createPayloadPatchStreamWrapper } from "openclaw/plugin-sdk/provider-stream-shared";
@@ -215,7 +216,7 @@ function registerAmazonBedrockPlugin(api) {
215
216
  function resolveCurrentPluginConfig(config) {
216
217
  return resolvePluginConfigObject(config, providerId) ?? (config ? void 0 : startupPluginConfig);
217
218
  }
218
- api.registerMemoryEmbeddingProvider(bedrockMemoryEmbeddingProviderAdapter);
219
+ api.registerEmbeddingProvider(adaptMemoryEmbeddingProviderAdapter(bedrockMemoryEmbeddingProviderAdapter));
219
220
  const baseWrapStreamFn = ({ modelId, model, streamFn }) => {
220
221
  const modelRef = {
221
222
  id: modelId,
@@ -2,13 +2,13 @@ import { supportsBedrockPromptCaching } from "./bedrock-options.js";
2
2
  import { supportsBedrockNativeMaxEffort } from "./thinking-policy.js";
3
3
  import { requiresClaudeMandatoryAdaptiveThinking, resolveClaudeFable5ModelIdentity, resolveClaudeModelIdentity, resolveClaudeMythos5ModelIdentity, resolveClaudeOpus5ModelIdentity, resolveClaudeSonnet5ModelIdentity, supportsClaudeAdaptiveThinking, supportsClaudeNativeXhighEffort } from "openclaw/plugin-sdk/provider-model-shared";
4
4
  import { applyAnthropicRefusal, createDeferredEventBuffer, notifyLlmRequestActivity } from "openclaw/plugin-sdk/provider-stream-shared";
5
- import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
+ import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
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
9
  import { AssistantMessageEventStream, adjustMaxTokensForThinking, buildBaseOptions, calculateCost, clampReasoning, createHttpProxyAgentsForTarget, parseStreamingJson, sanitizeSurrogates, transformMessages } from "openclaw/plugin-sdk/llm";
10
10
  import { canonicalizeBase64 } from "openclaw/plugin-sdk/media-runtime";
11
- import { describeToolResultMediaPlaceholder } from "openclaw/plugin-sdk/provider-transport-runtime";
11
+ import { describeToolResultMediaPlaceholder, finalizeTerminalToolCallArguments, notifyProviderHttpMetadata } from "openclaw/plugin-sdk/provider-transport-runtime";
12
12
  //#region extensions/amazon-bedrock/stream.runtime.ts
13
13
  /**
14
14
  * Amazon Bedrock Converse streaming runtime. It maps OpenClaw messages/tools,
@@ -72,6 +72,7 @@ const streamBedrock = (model, context, options = {}) => {
72
72
  timestamp: Date.now()
73
73
  };
74
74
  const blocks = output.content;
75
+ const pendingToolCallEnds = [];
75
76
  const redactedReasoningChunks = /* @__PURE__ */ new Map();
76
77
  const fable5 = usesClaudeFable5BedrockContract(model);
77
78
  const refusalBuffer = usesClaudeStreamingRefusalBedrockContract(model) ? createDeferredEventBuffer(stream, () => notifyLlmRequestActivity(options.signal)) : void 0;
@@ -125,16 +126,24 @@ const streamBedrock = (model, context, options = {}) => {
125
126
  if (nextCommandInput !== void 0) commandInput = nextCommandInput;
126
127
  const command = new ConverseStreamCommand(commandInput);
127
128
  const response = await client.send(command, { abortSignal: options.signal });
129
+ const responseIterator = response.stream[Symbol.asyncIterator]();
128
130
  if (response.$metadata.httpStatusCode !== void 0) {
129
131
  const responseHeaders = {};
130
132
  if (response.$metadata.requestId) responseHeaders["x-amzn-requestid"] = response.$metadata.requestId;
131
- await options?.onResponse?.({
132
- status: response.$metadata.httpStatusCode,
133
- headers: responseHeaders
134
- }, model);
133
+ await notifyProviderHttpMetadata({
134
+ options,
135
+ response: {
136
+ status: response.$metadata.httpStatusCode,
137
+ headers: responseHeaders
138
+ },
139
+ model,
140
+ cancelStream: async () => {
141
+ await responseIterator.return?.();
142
+ }
143
+ });
135
144
  }
136
145
  let sawMessageStop = false;
137
- for await (const item of response.stream) if (item.messageStart) {
146
+ for await (const item of { [Symbol.asyncIterator]: () => responseIterator }) if (item.messageStart) {
138
147
  if (item.messageStart.role !== ConversationRole.ASSISTANT) throw new Error("Unexpected assistant message start but got user message start instead");
139
148
  eventSink.push({
140
149
  type: "start",
@@ -142,7 +151,7 @@ const streamBedrock = (model, context, options = {}) => {
142
151
  });
143
152
  } else if (item.contentBlockStart) handleContentBlockStart(item.contentBlockStart, blocks, output, eventSink);
144
153
  else if (item.contentBlockDelta) handleContentBlockDelta(item.contentBlockDelta, blocks, output, eventSink, redactedReasoningChunks);
145
- else if (item.contentBlockStop) handleContentBlockStop(item.contentBlockStop, blocks, output, eventSink, redactedReasoningChunks);
154
+ else if (item.contentBlockStop) handleContentBlockStop(item.contentBlockStop, blocks, output, eventSink, redactedReasoningChunks, pendingToolCallEnds);
146
155
  else if (item.messageStop) {
147
156
  sawMessageStop = true;
148
157
  if (item.messageStop.stopReason === "refusal") applyAnthropicRefusal(output, readBedrockStopDetails(item.messageStop.additionalModelResponseFields), model.provider);
@@ -160,7 +169,8 @@ const streamBedrock = (model, context, options = {}) => {
160
169
  if (!sawMessageStop) throw new Error("Bedrock stream ended before messageStop");
161
170
  if (options.signal?.aborted) throw new Error("Request was aborted");
162
171
  if (output.stopReason === "error" || output.stopReason === "aborted") throw new Error(output.errorMessage ?? "An unknown error occurred");
163
- for (const block of blocks) if (block.index !== void 0) handleContentBlockStop({ contentBlockIndex: block.index }, blocks, output, eventSink, redactedReasoningChunks);
172
+ for (const block of blocks) if (block.index !== void 0 && block.type !== "toolCall") handleContentBlockStop({ contentBlockIndex: block.index }, blocks, output, eventSink, redactedReasoningChunks, pendingToolCallEnds);
173
+ flushPendingBedrockToolCalls(pendingToolCallEnds, blocks, output, eventSink);
164
174
  refusalBuffer?.flush();
165
175
  stream.push({
166
176
  type: "done",
@@ -169,6 +179,7 @@ const streamBedrock = (model, context, options = {}) => {
169
179
  });
170
180
  stream.end();
171
181
  } catch (error) {
182
+ output.content = output.content.filter((block) => block.type !== "toolCall");
172
183
  for (const block of output.content) {
173
184
  delete block.index;
174
185
  delete block.partialJson;
@@ -274,11 +285,12 @@ function handleContentBlockStart(event, blocks, output, stream) {
274
285
  const index = event.contentBlockIndex;
275
286
  const start = event.start;
276
287
  if (start?.toolUse) {
288
+ const startArguments = isRecord(start.toolUse) ? start.toolUse.input : void 0;
277
289
  const block = {
278
290
  type: "toolCall",
279
291
  id: start.toolUse.toolUseId || "",
280
292
  name: start.toolUse.name || "",
281
- arguments: {},
293
+ arguments: isRecord(startArguments) ? startArguments : {},
282
294
  partialJson: "",
283
295
  index
284
296
  };
@@ -387,13 +399,13 @@ function handleMetadata(event, model, output) {
387
399
  calculateCost(model, output.usage);
388
400
  }
389
401
  }
390
- function handleContentBlockStop(event, blocks, output, stream, redactedReasoningChunks) {
402
+ function handleContentBlockStop(event, blocks, output, stream, redactedReasoningChunks, pendingToolCallEnds) {
391
403
  const index = blocks.findIndex((b) => b.index === event.contentBlockIndex);
392
404
  const block = blocks[index];
393
405
  if (!block) return;
394
- delete block.index;
395
406
  switch (block.type) {
396
407
  case "text":
408
+ delete block.index;
397
409
  stream.push({
398
410
  type: "text_end",
399
411
  contentIndex: index,
@@ -402,6 +414,7 @@ function handleContentBlockStop(event, blocks, output, stream, redactedReasoning
402
414
  });
403
415
  break;
404
416
  case "thinking":
417
+ delete block.index;
405
418
  if (block.redacted) {
406
419
  const chunks = redactedReasoningChunks.get(event.contentBlockIndex);
407
420
  if (chunks) {
@@ -419,16 +432,27 @@ function handleContentBlockStop(event, blocks, output, stream, redactedReasoning
419
432
  });
420
433
  break;
421
434
  case "toolCall":
422
- delete block.partialJson;
423
- stream.push({
424
- type: "toolcall_end",
425
- contentIndex: index,
426
- toolCall: block,
427
- partial: output
435
+ delete block.index;
436
+ pendingToolCallEnds.push({
437
+ block,
438
+ contentIndex: index
428
439
  });
429
440
  break;
430
441
  }
431
442
  }
443
+ function flushPendingBedrockToolCalls(pending, blocks, output, stream) {
444
+ if (blocks.some((block) => block.type === "toolCall" && block.index !== void 0)) throw new Error("Provider completed stream with an incomplete tool call");
445
+ finalizeTerminalToolCallArguments(pending.map(({ block }) => block), (block) => block.partialJson && block.partialJson.length > 0 ? block.partialJson : block.arguments);
446
+ for (const toolCall of pending) {
447
+ delete toolCall.block.partialJson;
448
+ stream.push({
449
+ type: "toolcall_end",
450
+ contentIndex: toolCall.contentIndex,
451
+ toolCall: toolCall.block,
452
+ partial: output
453
+ });
454
+ }
455
+ }
432
456
  function resolveClaudeProfileNameModelId(modelName) {
433
457
  const normalized = modelName?.trim().toLowerCase().replace(/[\s_.:]+/g, "-") ?? "";
434
458
  if (!normalized.includes("claude")) return;
@@ -639,7 +663,7 @@ function convertToolConfig(tools, toolChoice) {
639
663
  const bedrockTools = tools.map((tool) => ({ toolSpec: {
640
664
  name: tool.name,
641
665
  description: tool.description,
642
- inputSchema: { json: tool.parameters }
666
+ inputSchema: { json: { ...tool.parameters } }
643
667
  } }));
644
668
  let bedrockToolChoice;
645
669
  switch (toolChoice) {
@@ -13,7 +13,7 @@
13
13
  }
14
14
  },
15
15
  "contracts": {
16
- "memoryEmbeddingProviders": ["bedrock"]
16
+ "embeddingProviders": ["bedrock"]
17
17
  },
18
18
  "configSchema": {
19
19
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/amazon-bedrock-provider",
3
- "version": "2026.8.1-beta.2",
3
+ "version": "2026.8.1-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.8.1-beta.2"
28
+ "pluginApi": ">=2026.8.1-beta.3"
29
29
  },
30
30
  "build": {
31
- "openclawVersion": "2026.8.1-beta.2",
31
+ "openclawVersion": "2026.8.1-beta.3",
32
32
  "bundledDist": false
33
33
  },
34
34
  "release": {
@@ -45,7 +45,7 @@
45
45
  "README.md"
46
46
  ],
47
47
  "peerDependencies": {
48
- "openclaw": ">=2026.8.1-beta.2"
48
+ "openclaw": ">=2026.8.1-beta.3"
49
49
  },
50
50
  "peerDependenciesMeta": {
51
51
  "openclaw": {