@openclaw/amazon-bedrock-mantle-provider 2026.9.2 → 2026.9.4

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/discovery.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { LiveModelCatalogHttpError } from "openclaw/plugin-sdk/provider-catalog-live-runtime";
1
2
  import { createSubsystemLogger } from "openclaw/plugin-sdk/core";
2
3
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
3
4
  import { isFutureDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
@@ -178,7 +179,7 @@ async function readMantleModelDiscoveryJson(response) {
178
179
  chunkTimeoutMs: MANTLE_DISCOVERY_TIMEOUT_MS,
179
180
  onIdleTimeout: ({ chunkTimeoutMs }) => /* @__PURE__ */ new Error(`Mantle model discovery response stalled: no data received for ${chunkTimeoutMs}ms`)
180
181
  });
181
- if (!body || typeof body !== "object" || Array.isArray(body)) return {};
182
+ if (!body || typeof body !== "object" || !("data" in body) || !Array.isArray(body.data)) throw new Error("Mantle model discovery response must contain a data array");
182
183
  return body;
183
184
  }
184
185
  const discoveryCache = /* @__PURE__ */ new Map();
@@ -190,15 +191,14 @@ const discoveryCache = /* @__PURE__ */ new Map();
190
191
  * { "data": [{ "id": "anthropic.claude-sonnet-4-6", "object": "model", "owned_by": "anthropic" }] }
191
192
  * ```
192
193
  *
193
- * Results are cached per region for `DEFAULT_REFRESH_INTERVAL_SECONDS`.
194
- * Returns an empty array if the request fails (no permission, network error, etc.).
194
+ * Results are cached per region and bearer credential for `DEFAULT_REFRESH_INTERVAL_SECONDS`.
195
+ * Public calls retain advisory results; strict catalog calls propagate acquisition failures.
195
196
  */
196
- /** Discover Mantle models for one region/config. */
197
197
  async function discoverMantleModels(params) {
198
198
  const { region, bearerToken, fetchFn = fetch, now = Date.now } = params;
199
- const cacheKey = region;
200
- const cached = discoveryCache.get(cacheKey);
201
- if (cached && now() - cached.fetchedAt < DEFAULT_REFRESH_INTERVAL_SECONDS * 1e3) return cached.models;
199
+ const cached = discoveryCache.get(region);
200
+ if (cached?.bearerToken === bearerToken && now() - cached.fetchedAt < DEFAULT_REFRESH_INTERVAL_SECONDS * 1e3) return cached.models;
201
+ if (cached?.bearerToken !== bearerToken) discoveryCache.delete(region);
202
202
  const endpoint = `${mantleEndpoint(region)}/v1/models`;
203
203
  try {
204
204
  const response = await fetchFn(endpoint, {
@@ -211,29 +211,26 @@ async function discoverMantleModels(params) {
211
211
  });
212
212
  if (!response.ok) {
213
213
  await response.body?.cancel().catch(() => void 0);
214
- log.debug?.("Mantle model discovery failed", {
215
- status: response.status,
216
- statusText: response.statusText
217
- });
218
- return cached?.models ?? [];
214
+ throw new LiveModelCatalogHttpError("amazon-bedrock-mantle", response.status);
219
215
  }
220
- const models = ((await readMantleModelDiscoveryJson(response)).data ?? []).filter((m) => m.id?.trim()).map((m) => ({
221
- id: m.id,
222
- name: m.id,
223
- reasoning: inferReasoningSupport(m.id),
216
+ const models = (await readMantleModelDiscoveryJson(response)).data.filter((model) => model.id?.trim()).map((model) => ({
217
+ id: model.id,
218
+ name: model.id,
219
+ reasoning: inferReasoningSupport(model.id),
224
220
  input: ["text"],
225
221
  cost: DEFAULT_COST,
226
222
  contextWindow: DEFAULT_CONTEXT_WINDOW,
227
223
  maxTokens: DEFAULT_MAX_TOKENS
228
- })).toSorted((a, b) => a.id.localeCompare(b.id));
229
- discoveryCache.set(cacheKey, {
224
+ })).toSorted((left, right) => left.id.localeCompare(right.id));
225
+ discoveryCache.set(region, {
226
+ bearerToken,
230
227
  models,
231
228
  fetchedAt: now()
232
229
  });
233
230
  return models;
234
231
  } catch (error) {
235
- log.debug?.("Mantle model discovery error", { error: formatErrorMessage(error) });
236
- return cached?.models ?? [];
232
+ if (params.discoveryMode === "strict") throw error;
233
+ return cached?.bearerToken === bearerToken ? cached.models : [];
237
234
  }
238
235
  }
239
236
  /**
@@ -245,7 +242,7 @@ async function discoverMantleModels(params) {
245
242
  * - Region from AWS_REGION / AWS_DEFAULT_REGION / default us-east-1
246
243
  * - Models discovered from `/v1/models`
247
244
  */
248
- /** Resolve implicit Mantle provider config from env, IAM token support, and discovery. */
245
+ /** Public resolution keeps advisory null results; strict catalog callers retain acquired empties. */
249
246
  async function resolveImplicitMantleProvider(params) {
250
247
  const env = params.env ?? process.env;
251
248
  if (params.pluginConfig?.discovery?.enabled === false) return null;
@@ -263,9 +260,10 @@ async function resolveImplicitMantleProvider(params) {
263
260
  const models = await discoverMantleModels({
264
261
  region,
265
262
  bearerToken,
263
+ discoveryMode: params.discoveryMode,
266
264
  fetchFn: params.fetchFn
267
265
  });
268
- if (models.length === 0) return null;
266
+ if (models.length === 0 && params.discoveryMode !== "strict") return null;
269
267
  log.debug?.("Mantle provider resolved", {
270
268
  region,
271
269
  modelCount: models.length
@@ -379,7 +377,7 @@ async function resolveImplicitMantleProvider(params) {
379
377
  api: "openai-completions",
380
378
  auth: "api-key",
381
379
  apiKey: explicitBearerToken ? "env:AWS_BEARER_TOKEN_BEDROCK" : MANTLE_IAM_TOKEN_MARKER,
382
- models: allModels
380
+ models: models.length === 0 ? [] : allModels
383
381
  };
384
382
  }
385
383
  /** Merge an implicit Mantle provider catalog with explicit user config. */
@@ -1,6 +1,7 @@
1
1
  import { resolveImplicitMantleProvider, resolveMantleBearerToken, resolveMantleRuntimeBearerToken, resolveMantleSonnet5Cost } from "./discovery.js";
2
2
  import { createMantleAnthropicStreamFn } from "./mantle-anthropic.runtime.js";
3
3
  import { resolvePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
4
+ import { runLiveProviderCatalog } from "openclaw/plugin-sdk/provider-catalog-live-runtime";
4
5
  import { modelCostsEqual, resolveClaudeOpus5ModelIdentity, resolveClaudeSonnet5ModelIdentity } from "openclaw/plugin-sdk/provider-model-shared";
5
6
  //#region extensions/amazon-bedrock-mantle/register.sync.runtime.ts
6
7
  const MANTLE_OPUS_5_COST = {
@@ -36,15 +37,18 @@ function registerBedrockMantlePlugin(api) {
36
37
  auth: [],
37
38
  catalog: {
38
39
  order: "simple",
39
- run: async (ctx) => {
40
- const currentPluginConfig = resolveCurrentPluginConfig(ctx.config);
41
- const implicit = await resolveImplicitMantleProvider({
42
- env: ctx.env,
43
- pluginConfig: currentPluginConfig
44
- });
45
- if (!implicit) return null;
46
- return { provider: implicit };
47
- }
40
+ run: (ctx) => runLiveProviderCatalog({
41
+ providerId,
42
+ run: async () => {
43
+ const currentPluginConfig = resolveCurrentPluginConfig(ctx.config);
44
+ const implicit = await resolveImplicitMantleProvider({
45
+ discoveryMode: "strict",
46
+ env: ctx.env,
47
+ pluginConfig: currentPluginConfig
48
+ });
49
+ return implicit ? { provider: implicit } : null;
50
+ }
51
+ })
48
52
  },
49
53
  resolveConfigApiKey: ({ env }) => resolveMantleBearerToken(env) ? "env:AWS_BEARER_TOKEN_BEDROCK" : void 0,
50
54
  prepareRuntimeAuth: async ({ apiKey, env }) => await resolveMantleRuntimeBearerToken({
@@ -55,6 +59,7 @@ function registerBedrockMantlePlugin(api) {
55
59
  modelId,
56
60
  model
57
61
  }),
62
+ supportsSystemPromptCacheBoundary: true,
58
63
  createStreamFn: ({ model }) => model.api === "anthropic-messages" ? createMantleAnthropicStreamFn() : void 0,
59
64
  matchesContextOverflowError: ({ errorMessage }) => /context_length_exceeded|max.*tokens.*exceeded/i.test(errorMessage),
60
65
  classifyFailoverReason: ({ errorMessage }) => {
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "id": "amazon-bedrock-mantle",
3
+ "categories": ["models"],
3
4
  "name": "Amazon Bedrock Mantle",
4
5
  "description": "OpenClaw Amazon Bedrock Mantle provider plugin for OpenAI-compatible model routing.",
5
6
  "activation": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/amazon-bedrock-mantle-provider",
3
- "version": "2026.9.2",
3
+ "version": "2026.9.4",
4
4
  "description": "OpenClaw Amazon Bedrock Mantle provider plugin for OpenAI-compatible model routing.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,10 +21,10 @@
21
21
  "minHostVersion": ">=2026.5.12-beta.1"
22
22
  },
23
23
  "compat": {
24
- "pluginApi": ">=2026.9.2"
24
+ "pluginApi": ">=2026.9.4"
25
25
  },
26
26
  "build": {
27
- "openclawVersion": "2026.9.2",
27
+ "openclawVersion": "2026.9.4",
28
28
  "bundledDist": false
29
29
  },
30
30
  "release": {
@@ -41,7 +41,7 @@
41
41
  "README.md"
42
42
  ],
43
43
  "peerDependencies": {
44
- "openclaw": ">=2026.9.2"
44
+ "openclaw": ">=2026.9.4"
45
45
  },
46
46
  "peerDependenciesMeta": {
47
47
  "openclaw": {