fix: gate Bedrock Mantle discovery · openclaw/openclaw@159dae9
steipete
·
2026-05-10
·
via Recent Commits to openclaw:main
File tree
extensions/amazon-bedrock-mantle
| Original file line number | Diff line number | Diff line change |
|---|
@@ -25,6 +25,7 @@ Docs: https://docs.openclaw.ai
|
25 | 25 | - OpenAI-compatible models: strip prior assistant reasoning fields from replayed Chat Completions history by default, preventing oMLX/vLLM Qwen follow-up turns from rejecting or stalling on stale `reasoning` payloads. Fixes #46637. Thanks @zipzagster and @lexhoefsloot. |
26 | 26 | - CLI/onboarding: give non-Azure custom providers a safe generated context window and heal legacy 4k wizard entries without overwriting explicit valid small model limits, preventing first-turn compaction loops. Fixes #79428. (#79911) Thanks @Jefsky. |
27 | 27 | - OpenAI-compatible models: add `compat.strictMessageKeys` to strip Chat Completions replay messages to `role` and `content` for strict providers that reject OpenAI-style tool and metadata keys. Fixes #50374. Thanks @choutos. |
| 28 | +- Bedrock Mantle: add `plugins.entries.amazon-bedrock-mantle.config.discovery.enabled=false` to suppress automatic Mantle discovery and IAM bearer-token generation while keeping the plugin enabled. Fixes #67288. Thanks @kanekoh. |
28 | 29 | - Ollama: stop native `/api/chat` requests from copying catalog `contextWindow` or `maxTokens` into `options.num_ctx` unless `params.num_ctx` is explicitly configured, avoiding pathological prompt-ingestion latency on local large-context models. Fixes #62267. Thanks @BenSHPD. |
29 | 30 | - Ollama: keep the model idle watchdog enabled for `*:cloud` models routed through a local Ollama host, so cloud-backed tool-loop stalls fail over visibly instead of inheriting local-model no-idle behavior. Fixes #79350. Thanks @geek111. |
30 | 31 | - Voice/Ollama: honor routed voice agent `tools.allow` for classic embedded voice responses, including empty allowlists, so no-tool Ollama agents do not receive tool schemas. Fixes #79506. Thanks @donkeykong91. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -90,6 +90,13 @@ region's `/v1/models` endpoint.
|
90 | 90 | | Discovery cache | Results cached for 1 hour | |
91 | 91 | | IAM token refresh | Hourly | |
92 | 92 | |
| 93 | +To keep the Mantle plugin enabled but suppress automatic discovery and IAM |
| 94 | +bearer-token generation, disable the plugin-owned discovery toggle: |
| 95 | + |
| 96 | +```bash |
| 97 | +openclaw config set plugins.entries.amazon-bedrock-mantle.config.discovery.enabled false |
| 98 | +``` |
| 99 | + |
93 | 100 | <Note> |
94 | 101 | The bearer token is the same `AWS_BEARER_TOKEN_BEDROCK` used by the standard [Amazon Bedrock](/providers/bedrock) provider. |
95 | 102 | </Note> |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -141,6 +141,22 @@ describe("bedrock mantle discovery", () => {
|
141 | 141 | ).resolves.toBeUndefined(); |
142 | 142 | }); |
143 | 143 | |
| 144 | +it("skips IAM token generation when plugin discovery is disabled", async () => { |
| 145 | +const tokenProviderFactory = vi.fn(() => { |
| 146 | +throw new Error("disabled discovery should not generate a token"); |
| 147 | +}); |
| 148 | + |
| 149 | +await expect( |
| 150 | +resolveImplicitMantleProvider({ |
| 151 | +env: { AWS_REGION: "us-east-1" } as NodeJS.ProcessEnv, |
| 152 | +pluginConfig: { discovery: { enabled: false } }, |
| 153 | + tokenProviderFactory, |
| 154 | +}), |
| 155 | +).resolves.toBeNull(); |
| 156 | + |
| 157 | +expect(tokenProviderFactory).not.toHaveBeenCalled(); |
| 158 | +}); |
| 159 | + |
144 | 160 | it("getCachedIamToken returns cached token when valid", async () => { |
145 | 161 | const tokenProvider = vi.fn(async () => "bedrock-cached-token"); // pragma: allowlist secret |
146 | 162 | const tokenProviderFactory = createTokenProviderFactory(tokenProvider); |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -225,6 +225,10 @@ interface MantleCacheEntry {
|
225 | 225 | fetchedAt: number; |
226 | 226 | } |
227 | 227 | |
| 228 | +type MantleDiscoveryConfig = { |
| 229 | +enabled?: boolean; |
| 230 | +}; |
| 231 | + |
228 | 232 | const discoveryCache = new Map<string, MantleCacheEntry>(); |
229 | 233 | |
230 | 234 | /** Clear the discovery cache (for testing). */ |
@@ -322,10 +326,14 @@ export async function discoverMantleModels(params: {
|
322 | 326 | */ |
323 | 327 | export async function resolveImplicitMantleProvider(params: { |
324 | 328 | env?: NodeJS.ProcessEnv; |
| 329 | +pluginConfig?: { discovery?: MantleDiscoveryConfig }; |
325 | 330 | fetchFn?: typeof fetch; |
326 | 331 | tokenProviderFactory?: MantleBearerTokenProviderFactory; |
327 | 332 | }): Promise<ModelProviderConfig | null> { |
328 | 333 | const env = params.env ?? process.env; |
| 334 | +if (params.pluginConfig?.discovery?.enabled === false) { |
| 335 | +return null; |
| 336 | +} |
329 | 337 | const region = resolveMantleRegion(env); |
330 | 338 | const explicitBearerToken = resolveMantleBearerToken(env); |
331 | 339 | |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -7,6 +7,38 @@ describe("amazon-bedrock-mantle provider plugin", () => {
|
7 | 7 | vi.restoreAllMocks(); |
8 | 8 | }); |
9 | 9 | |
| 10 | +it("uses live plugin config to disable catalog discovery", async () => { |
| 11 | +const fetchMock = vi |
| 12 | +.spyOn(globalThis, "fetch") |
| 13 | +.mockRejectedValue(new Error("unexpected fetch")); |
| 14 | +const provider = await registerSingleProviderPlugin(bedrockMantlePlugin); |
| 15 | +const catalog = provider.catalog; |
| 16 | +if (!catalog) { |
| 17 | +throw new Error("catalog registration missing"); |
| 18 | +} |
| 19 | + |
| 20 | +const result = await catalog.run({ |
| 21 | +config: { |
| 22 | +plugins: { |
| 23 | +entries: { |
| 24 | +"amazon-bedrock-mantle": { |
| 25 | +config: { |
| 26 | +discovery: { enabled: false }, |
| 27 | +}, |
| 28 | +}, |
| 29 | +}, |
| 30 | +}, |
| 31 | +}, |
| 32 | +env: { |
| 33 | +AWS_BEARER_TOKEN_BEDROCK: "test-token", |
| 34 | +AWS_REGION: "us-east-1", |
| 35 | +}, |
| 36 | +} as never); |
| 37 | + |
| 38 | +expect(result).toBeNull(); |
| 39 | +expect(fetchMock).not.toHaveBeenCalled(); |
| 40 | +}); |
| 41 | + |
10 | 42 | it("registers with correct provider ID and label", async () => { |
11 | 43 | const provider = await registerSingleProviderPlugin(bedrockMantlePlugin); |
12 | 44 | expect(provider.id).toBe("amazon-bedrock-mantle"); |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -7,7 +7,28 @@
|
7 | 7 | "configSchema": { |
8 | 8 | "type": "object", |
9 | 9 | "additionalProperties": false, |
10 | | -"properties": {} |
| 10 | +"properties": { |
| 11 | +"discovery": { |
| 12 | +"type": "object", |
| 13 | +"additionalProperties": false, |
| 14 | +"properties": { |
| 15 | +"enabled": { |
| 16 | +"type": "boolean", |
| 17 | +"description": "When false, skip implicit Mantle model discovery." |
| 18 | + } |
| 19 | + } |
| 20 | + } |
| 21 | + } |
| 22 | + }, |
| 23 | +"uiHints": { |
| 24 | +"discovery": { |
| 25 | +"label": "Model Discovery", |
| 26 | +"help": "Plugin-owned controls for Amazon Bedrock Mantle model auto-discovery." |
| 27 | + }, |
| 28 | +"discovery.enabled": { |
| 29 | +"label": "Enable Discovery", |
| 30 | +"help": "When false, OpenClaw keeps the Amazon Bedrock Mantle plugin available but skips implicit startup discovery. Leave unset for default auto-detect behavior." |
| 31 | + } |
11 | 32 | }, |
12 | 33 | "providers": ["amazon-bedrock-mantle"] |
13 | 34 | } |
| Original file line number | Diff line number | Diff line change |
|---|
|
| 1 | +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types"; |
| 2 | +import { resolvePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime"; |
1 | 3 | import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry"; |
2 | 4 | import { |
3 | 5 | mergeImplicitMantleProvider, |
@@ -7,8 +9,25 @@ import {
|
7 | 9 | } from "./discovery.js"; |
8 | 10 | import { createMantleAnthropicStreamFn } from "./mantle-anthropic.runtime.js"; |
9 | 11 | |
| 12 | +type BedrockMantlePluginConfig = { |
| 13 | +discovery?: { |
| 14 | +enabled?: boolean; |
| 15 | +}; |
| 16 | +}; |
| 17 | + |
10 | 18 | export function registerBedrockMantlePlugin(api: OpenClawPluginApi): void { |
11 | 19 | const providerId = "amazon-bedrock-mantle"; |
| 20 | +const startupPluginConfig = (api.pluginConfig ?? {}) as BedrockMantlePluginConfig; |
| 21 | + |
| 22 | +function resolveCurrentPluginConfig( |
| 23 | +config: OpenClawConfig | undefined, |
| 24 | +): BedrockMantlePluginConfig | undefined { |
| 25 | +const runtimePluginConfig = resolvePluginConfigObject(config, providerId); |
| 26 | +return ( |
| 27 | +(runtimePluginConfig as BedrockMantlePluginConfig | undefined) ?? |
| 28 | +(config ? undefined : startupPluginConfig) |
| 29 | +); |
| 30 | +} |
12 | 31 | |
13 | 32 | api.registerProvider({ |
14 | 33 | id: providerId, |
@@ -18,8 +37,10 @@ export function registerBedrockMantlePlugin(api: OpenClawPluginApi): void {
|
18 | 37 | catalog: { |
19 | 38 | order: "simple", |
20 | 39 | run: async (ctx) => { |
| 40 | +const currentPluginConfig = resolveCurrentPluginConfig(ctx.config); |
21 | 41 | const implicit = await resolveImplicitMantleProvider({ |
22 | 42 | env: ctx.env, |
| 43 | +pluginConfig: currentPluginConfig, |
23 | 44 | }); |
24 | 45 | if (!implicit) { |
25 | 46 | return null; |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -77,6 +77,11 @@ const BUNDLED_LIVE_CONFIG_PROVIDER_GUARDS = {
|
77 | 77 | "const currentPluginConfig = resolveCurrentPluginConfig(ctx.config);", |
78 | 78 | "const currentGuardrail = resolveCurrentPluginConfig(config)?.guardrail;", |
79 | 79 | ], |
| 80 | +"extensions/amazon-bedrock-mantle/register.sync.runtime.ts": [ |
| 81 | +"resolvePluginConfigObject(", |
| 82 | +"const startupPluginConfig = (api.pluginConfig ?? {})", |
| 83 | +"const currentPluginConfig = resolveCurrentPluginConfig(ctx.config);", |
| 84 | +], |
80 | 85 | "extensions/codex/provider.ts": [ |
81 | 86 | "resolvePluginConfigObject(", |
82 | 87 | "const runtimePluginConfig = resolvePluginConfigObject(ctx.config, CODEX_PROVIDER_ID);", |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。