@openclaw/amazon-bedrock-provider 2026.7.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.
- package/dist/aws-credential-refresh.js +6 -4
- package/dist/control-plane.js +29 -0
- package/dist/discovery.js +43 -58
- package/dist/embedding-provider.js +12 -18
- package/dist/register.sync.runtime.js +28 -16
- package/dist/stream.runtime.js +27 -17
- package/npm-shrinkwrap.json +2 -2
- package/package.json +4 -4
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
//#region extensions/amazon-bedrock/aws-credential-refresh.ts
|
|
2
|
+
/**
|
|
3
|
+
* AWS shared config cache refresh helpers for Bedrock. They nudge the AWS SDK
|
|
4
|
+
* to re-read profile/SSO config when no static credentials are present.
|
|
5
|
+
*/
|
|
2
6
|
function hasStaticAwsCredentialEnv(env) {
|
|
3
7
|
return Boolean(env.AWS_ACCESS_KEY_ID && env.AWS_SECRET_ACCESS_KEY);
|
|
4
8
|
}
|
|
@@ -7,13 +11,11 @@ function shouldRefreshAwsSharedConfigCacheForBedrock(env) {
|
|
|
7
11
|
if (env.AWS_BEDROCK_SKIP_AUTH === "1" || env.AWS_BEARER_TOKEN_BEDROCK) return false;
|
|
8
12
|
return !hasStaticAwsCredentialEnv(env);
|
|
9
13
|
}
|
|
10
|
-
async function loadSharedIniFileLoader() {
|
|
11
|
-
return await import("@smithy/shared-ini-file-loader");
|
|
12
|
-
}
|
|
13
14
|
/** Refresh Smithy shared config files when Bedrock needs default-chain credentials. */
|
|
14
15
|
async function refreshAwsSharedConfigCacheForBedrock(env = process.env) {
|
|
15
16
|
if (!shouldRefreshAwsSharedConfigCacheForBedrock(env)) return;
|
|
16
|
-
|
|
17
|
+
const { loadSharedConfigFiles } = await import("@smithy/shared-ini-file-loader");
|
|
18
|
+
await loadSharedConfigFiles({ ignoreCache: true });
|
|
17
19
|
}
|
|
18
20
|
//#endregion
|
|
19
21
|
export { refreshAwsSharedConfigCacheForBedrock };
|
|
@@ -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
|
|
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 =
|
|
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
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const
|
|
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
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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 });
|
|
@@ -104,25 +104,18 @@ function inferFamily(modelId) {
|
|
|
104
104
|
if (id.startsWith("twelvelabs.")) return "twelvelabs";
|
|
105
105
|
return "titan-v1";
|
|
106
106
|
}
|
|
107
|
-
let
|
|
108
|
-
let
|
|
107
|
+
let sdkPromise = null;
|
|
108
|
+
let credentialProviderPromise = null;
|
|
109
109
|
async function loadSdk() {
|
|
110
|
-
if (sdkCache) return sdkCache;
|
|
111
110
|
try {
|
|
112
|
-
|
|
113
|
-
return sdkCache;
|
|
111
|
+
return await (sdkPromise ??= import("@aws-sdk/client-bedrock-runtime"));
|
|
114
112
|
} catch {
|
|
113
|
+
sdkPromise = null;
|
|
115
114
|
throw new Error("No API key found for provider bedrock: @aws-sdk/client-bedrock-runtime is not installed. Install it with: npm install @aws-sdk/client-bedrock-runtime");
|
|
116
115
|
}
|
|
117
116
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
try {
|
|
121
|
-
credentialProviderSdkCache = await import("@aws-sdk/credential-provider-node");
|
|
122
|
-
} catch {
|
|
123
|
-
credentialProviderSdkCache = null;
|
|
124
|
-
}
|
|
125
|
-
return credentialProviderSdkCache;
|
|
117
|
+
function loadDefaultCredentialProvider() {
|
|
118
|
+
return credentialProviderPromise ??= import("@aws-sdk/credential-provider-node").then(({ defaultProvider }) => defaultProvider).catch(() => null);
|
|
126
119
|
}
|
|
127
120
|
const MODEL_PREFIX_RE = /^(?:bedrock|amazon-bedrock|aws)\//;
|
|
128
121
|
const REGION_RE = /bedrock-runtime\.([a-z0-9-]+)\./;
|
|
@@ -223,6 +216,7 @@ const testing = {
|
|
|
223
216
|
parseSingle,
|
|
224
217
|
stripInferenceProfilePrefix
|
|
225
218
|
};
|
|
219
|
+
if (process.env.VITEST === "true") Reflect.set(globalThis, Symbol.for("openclaw.amazonBedrockEmbeddingTestApi"), testing);
|
|
226
220
|
async function createBedrockEmbeddingProvider(options) {
|
|
227
221
|
const client = resolveBedrockEmbeddingClient(options);
|
|
228
222
|
const { BedrockRuntimeClient, InvokeModelCommand } = await loadSdk();
|
|
@@ -295,13 +289,13 @@ function resolveBedrockEmbeddingClient(options) {
|
|
|
295
289
|
dimensions
|
|
296
290
|
};
|
|
297
291
|
}
|
|
298
|
-
async function hasAwsCredentials(env = process.env, loadCredentialProvider =
|
|
292
|
+
async function hasAwsCredentials(env = process.env, loadCredentialProvider = loadDefaultCredentialProvider) {
|
|
299
293
|
if (env.AWS_ACCESS_KEY_ID?.trim() && env.AWS_SECRET_ACCESS_KEY?.trim()) return true;
|
|
300
294
|
if (env.AWS_BEARER_TOKEN_BEDROCK?.trim()) return true;
|
|
301
|
-
const
|
|
302
|
-
if (!
|
|
295
|
+
const defaultProvider = await loadCredentialProvider();
|
|
296
|
+
if (!defaultProvider) return false;
|
|
303
297
|
try {
|
|
304
|
-
const credentials = await
|
|
298
|
+
const credentials = await defaultProvider({
|
|
305
299
|
timeout: 1e3,
|
|
306
300
|
maxRetries: 0
|
|
307
301
|
})();
|
|
@@ -311,4 +305,4 @@ async function hasAwsCredentials(env = process.env, loadCredentialProvider = loa
|
|
|
311
305
|
}
|
|
312
306
|
}
|
|
313
307
|
//#endregion
|
|
314
|
-
export { DEFAULT_BEDROCK_EMBEDDING_MODEL,
|
|
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 {
|
|
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,18 +130,24 @@ function resolvedModelSupportsCaching(modelArn) {
|
|
|
129
130
|
return supportsBedrockPromptCaching(modelArn);
|
|
130
131
|
}
|
|
131
132
|
const appProfileTraitsCache = /* @__PURE__ */ new Map();
|
|
132
|
-
async function
|
|
133
|
-
await refreshAwsSharedConfigCacheForBedrock();
|
|
134
|
-
const { BedrockClient, GetInferenceProfileCommand } = await import("@aws-sdk/client-bedrock");
|
|
135
|
-
const client = new BedrockClient(region ? { region } : {});
|
|
136
|
-
return { getInferenceProfile: async (input) => await client.send(new GetInferenceProfileCommand(input)) };
|
|
137
|
-
}
|
|
138
|
-
async function resolveAppProfileTraits(modelId, fallbackRegion) {
|
|
133
|
+
async function resolveAppProfileTraits(modelId, fallbackRegion, signal) {
|
|
139
134
|
const cached = appProfileTraitsCache.get(modelId);
|
|
140
135
|
if (cached) return cached;
|
|
136
|
+
let client;
|
|
141
137
|
try {
|
|
142
|
-
|
|
143
|
-
const
|
|
138
|
+
signal?.throwIfAborted();
|
|
139
|
+
const region = extractRegionFromArn(modelId) ?? fallbackRegion;
|
|
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 ?? [];
|
|
150
|
+
const modelArns = models.map((model) => model.modelArn ?? "");
|
|
144
151
|
const traits = {
|
|
145
152
|
cacheEligible: models.length > 0 && modelArns.every((modelArn) => resolvedModelSupportsCaching(modelArn)),
|
|
146
153
|
omitTemperature: modelArns.some(isOpus47OrNewerBedrockModelRef)
|
|
@@ -148,10 +155,13 @@ async function resolveAppProfileTraits(modelId, fallbackRegion) {
|
|
|
148
155
|
appProfileTraitsCache.set(modelId, traits);
|
|
149
156
|
return traits;
|
|
150
157
|
} catch {
|
|
158
|
+
signal?.throwIfAborted();
|
|
151
159
|
return {
|
|
152
160
|
cacheEligible: isAnthropicBedrockModel(modelId),
|
|
153
161
|
omitTemperature: isOpus47OrNewerBedrockModelRef(modelId)
|
|
154
162
|
};
|
|
163
|
+
} finally {
|
|
164
|
+
client?.destroy();
|
|
155
165
|
}
|
|
156
166
|
}
|
|
157
167
|
function hasCachePoint(blocks) {
|
|
@@ -173,9 +183,8 @@ function injectBedrockCachePoints(payload, cacheRetention) {
|
|
|
173
183
|
const system = payload.system;
|
|
174
184
|
if (Array.isArray(system) && system.length > 0 && !hasCachePoint(system)) system.push(point);
|
|
175
185
|
const messages = payload.messages;
|
|
176
|
-
if (Array.isArray(messages) && messages.length > 0)
|
|
177
|
-
const msg
|
|
178
|
-
if (msg.role === "user" && Array.isArray(msg.content)) {
|
|
186
|
+
if (Array.isArray(messages) && messages.length > 0) {
|
|
187
|
+
for (const msg of messages.toReversed()) if (msg.role === "user" && Array.isArray(msg.content)) {
|
|
179
188
|
if (!hasCachePoint(msg.content)) msg.content.push(point);
|
|
180
189
|
break;
|
|
181
190
|
}
|
|
@@ -200,7 +209,7 @@ function registerAmazonBedrockPlugin(api) {
|
|
|
200
209
|
/ModelStreamErrorException.*(?:Input is too long|too many input tokens)/i
|
|
201
210
|
];
|
|
202
211
|
const deprecatedTemperatureValidationRe = /ValidationException[\s\S]*(?:invalid_request_error[\s\S]*)?temperature[\s\S]*deprecated|ValidationException[\s\S]*deprecated[\s\S]*temperature/i;
|
|
203
|
-
const anthropicByModelReplayHooks =
|
|
212
|
+
const anthropicByModelReplayHooks = buildProviderReplayFamilyHooks({ family: "anthropic-by-model" });
|
|
204
213
|
const startupPluginConfig = api.pluginConfig ?? {};
|
|
205
214
|
registerApiProvider({
|
|
206
215
|
api: "bedrock-converse-stream",
|
|
@@ -237,7 +246,10 @@ function registerAmazonBedrockPlugin(api) {
|
|
|
237
246
|
return {
|
|
238
247
|
...options,
|
|
239
248
|
onPayload: async (payload, payloadModel) => {
|
|
249
|
+
const signal = options.signal;
|
|
250
|
+
signal?.throwIfAborted();
|
|
240
251
|
await refreshAwsSharedConfigCacheForBedrock();
|
|
252
|
+
signal?.throwIfAborted();
|
|
241
253
|
return originalOnPayload?.(payload, payloadModel);
|
|
242
254
|
}
|
|
243
255
|
};
|
|
@@ -351,7 +363,7 @@ function registerAmazonBedrockPlugin(api) {
|
|
|
351
363
|
if (shouldPatchMaxThinking) patchMaxThinkingEffort(payloadRecord);
|
|
352
364
|
if (shouldOmitTemperature) omitUnsupportedClaudePayloadTemperature(payloadRecord);
|
|
353
365
|
else if (mayNeedTemperatureTrait) {
|
|
354
|
-
if ((await resolveAppProfileTraits(modelId, region)).omitTemperature) omitUnsupportedClaudePayloadTemperature(payloadRecord);
|
|
366
|
+
if ((await resolveAppProfileTraits(modelId, region, merged.signal)).omitTemperature) omitUnsupportedClaudePayloadTemperature(payloadRecord);
|
|
355
367
|
}
|
|
356
368
|
}
|
|
357
369
|
return originalOnPayload?.(payload, payloadModel);
|
|
@@ -361,7 +373,7 @@ function registerAmazonBedrockPlugin(api) {
|
|
|
361
373
|
return underlying(streamModel, context, withAwsCredentialRefreshOnPayload({
|
|
362
374
|
...merged,
|
|
363
375
|
onPayload: async (payload, payloadModel) => {
|
|
364
|
-
const traits = await resolveAppProfileTraits(modelId, region);
|
|
376
|
+
const traits = await resolveAppProfileTraits(modelId, region, merged.signal);
|
|
365
377
|
if (payload && typeof payload === "object") {
|
|
366
378
|
const payloadRecord = payload;
|
|
367
379
|
if (traits.cacheEligible) injectBedrockCachePoints(payloadRecord, cacheRetention);
|
package/dist/stream.runtime.js
CHANGED
|
@@ -5,6 +5,8 @@ import { requiresClaudeMandatoryAdaptiveThinking, resolveClaudeFable5ModelIdenti
|
|
|
5
5
|
import { applyAnthropicRefusal, createDeferredEventBuffer, notifyLlmRequestActivity } from "openclaw/plugin-sdk/provider-stream-shared";
|
|
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
|
+
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
9
|
+
import { describeToolResultMediaPlaceholder } from "openclaw/plugin-sdk/provider-transport-runtime";
|
|
8
10
|
//#region extensions/amazon-bedrock/stream.runtime.ts
|
|
9
11
|
/**
|
|
10
12
|
* Amazon Bedrock Converse streaming runtime. It maps OpenClaw messages/tools,
|
|
@@ -284,7 +286,7 @@ function handleContentBlockDelta(event, blocks, output, stream) {
|
|
|
284
286
|
};
|
|
285
287
|
output.content.push(newBlock);
|
|
286
288
|
index = blocks.length - 1;
|
|
287
|
-
block =
|
|
289
|
+
block = newBlock;
|
|
288
290
|
stream.push({
|
|
289
291
|
type: "text_start",
|
|
290
292
|
contentIndex: index,
|
|
@@ -375,7 +377,6 @@ function handleContentBlockStop(event, blocks, output, stream) {
|
|
|
375
377
|
});
|
|
376
378
|
break;
|
|
377
379
|
case "toolCall":
|
|
378
|
-
block.arguments = parseStreamingJson(block.partialJson);
|
|
379
380
|
delete block.partialJson;
|
|
380
381
|
stream.push({
|
|
381
382
|
type: "toolcall_end",
|
|
@@ -474,11 +475,26 @@ 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);
|
|
480
496
|
for (let i = 0; i < transformedMessages.length; i++) {
|
|
481
|
-
const m = transformedMessages[i];
|
|
497
|
+
const m = expectDefined(transformedMessages[i], "message conversion index is in bounds");
|
|
482
498
|
switch (m.role) {
|
|
483
499
|
case "user": {
|
|
484
500
|
const content = [];
|
|
@@ -541,19 +557,12 @@ function convertMessages(context, model, cacheRetention) {
|
|
|
541
557
|
}
|
|
542
558
|
case "toolResult": {
|
|
543
559
|
const toolResults = [];
|
|
544
|
-
toolResults.push(
|
|
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
|
-
while (
|
|
551
|
-
const nextMsg = transformedMessages
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
content: nextMsg.content.map((c) => c.type === "image" ? { image: createImageBlock(c.mimeType, c.data) } : { text: sanitizeSurrogates(c.text) }),
|
|
555
|
-
status: nextMsg.isError ? ToolResultStatus.ERROR : ToolResultStatus.SUCCESS
|
|
556
|
-
} });
|
|
562
|
+
while (true) {
|
|
563
|
+
const nextMsg = transformedMessages.at(j);
|
|
564
|
+
if (nextMsg?.role !== "toolResult") break;
|
|
565
|
+
toolResults.push(createBedrockToolResult(nextMsg));
|
|
557
566
|
j++;
|
|
558
567
|
}
|
|
559
568
|
i = j - 1;
|
|
@@ -567,7 +576,7 @@ function convertMessages(context, model, cacheRetention) {
|
|
|
567
576
|
}
|
|
568
577
|
}
|
|
569
578
|
if (cacheRetention !== "none" && supportsPromptCaching(model) && result.length > 0) {
|
|
570
|
-
const lastMessage = result
|
|
579
|
+
const lastMessage = expectDefined(result.at(-1), "non-empty converted message list");
|
|
571
580
|
if (lastMessage.role === ConversationRole.USER && lastMessage.content) lastMessage.content.push({ cachePoint: {
|
|
572
581
|
type: CachePointType.DEFAULT,
|
|
573
582
|
...cacheRetention === "long" ? { ttl: CacheTTL.ONE_HOUR } : {}
|
|
@@ -703,5 +712,6 @@ const testing = {
|
|
|
703
712
|
resolveSimpleBedrockOptions,
|
|
704
713
|
shouldUseExplicitBedrockEndpoint
|
|
705
714
|
};
|
|
715
|
+
if (process.env.VITEST === "true") Reflect.set(globalThis, Symbol.for("openclaw.amazonBedrockStreamTestApi"), testing);
|
|
706
716
|
//#endregion
|
|
707
|
-
export { streamBedrock, streamSimpleBedrock
|
|
717
|
+
export { streamBedrock, streamSimpleBedrock };
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/amazon-bedrock-provider",
|
|
3
|
-
"version": "2026.7.
|
|
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.
|
|
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.
|
|
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.
|
|
28
|
+
"pluginApi": ">=2026.7.2-beta.2"
|
|
29
29
|
},
|
|
30
30
|
"build": {
|
|
31
|
-
"openclawVersion": "2026.7.
|
|
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.
|
|
49
|
+
"openclaw": ">=2026.7.2-beta.2"
|
|
50
50
|
},
|
|
51
51
|
"peerDependenciesMeta": {
|
|
52
52
|
"openclaw": {
|