* feat(bedrock): add Bedrock Mantle (OpenAI-compatible) provider
New amazon-bedrock-mantle extension that provides auto-discovery and
authentication for Amazon Bedrock Mantle endpoints.
Mantle (bedrock-mantle.<region>.api.aws) is Amazon Bedrock's OpenAI-
compatible API surface, separate from the existing bedrock-runtime
(ConverseStream) endpoint. It has its own model catalog including
models not available via ConverseStream (e.g. openai.gpt-oss-120b,
mistral.devstral-2-123b).
Extension structure:
- discovery.ts: Model discovery via GET /v1/models (OpenAI format),
bearer token resolution, implicit provider configuration
- register.sync.runtime.ts: Provider registration with catalog,
error classification (rate limits, context overflow)
- openclaw.plugin.json: Plugin manifest, enabledByDefault
Auth support:
- Long-lived Bedrock API key (AWS_BEARER_TOKEN_BEDROCK env var)
created from the AWS Console → used directly as Bearer token
- Pre-generated SigV4-derived tokens (via aws-bedrock-token-generator)
set in AWS_BEARER_TOKEN_BEDROCK → works transparently
Provider config (auto-resolved when AWS_BEARER_TOKEN_BEDROCK is set):
api: "openai-completions"
baseUrl: "https://bedrock-mantle.<region>.api.aws/v1"
auth: "api-key" (bearer token)
Available in 12 regions: us-east-1, us-east-2, us-west-2,
ap-northeast-1, ap-south-1, ap-southeast-3, eu-central-1,
eu-west-1, eu-west-2, eu-south-1, eu-north-1, sa-east-1
Tests: 15 passing (13 discovery + 2 plugin registration)
* chore(bedrock): clarify mantle bearer auth scope
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* feat(bedrock): add inference profile discovery and region injection
Inference profiles (cross-region and application) work with ConverseStream
but require the SDK client region to match the profile region. Without
this, users get "The provided model identifier is invalid" errors when
using cross-region profiles like us.anthropic.claude-sonnet-4-6.
Changes:
1. Inference profile discovery (discovery.ts):
- Call ListInferenceProfiles alongside ListFoundationModels (parallel)
- Inference profiles INHERIT capabilities from their underlying
foundation model (modalities, reasoning, context window, cost)
- resolveBaseModelId() maps profile → foundation model:
"us.anthropic.claude-sonnet-4-6" → "anthropic.claude-sonnet-4-6"
Application ARNs → extract model ID from models[].modelArn
- Graceful degradation if IAM lacks bedrock:ListInferenceProfiles
- Provider filter applies to profiles via underlying model ARNs
2. Region injection (register.sync.runtime.ts):
- Extract region from provider baseUrl or bedrockDiscovery.region
- Pass through to pi-ai options.region in wrapStreamFn
- Ensures SDK client connects to correct regional endpoint
3. Inference profile model detection (anthropic-family-cache-semantics.ts):
- isAnthropicBedrockModel() now recognizes application inference
profile ARNs (arn:aws:bedrock:...:application-inference-profile/*)
4. Tests (discovery.test.ts):
- New: inference profile inheritance test (4 models: 1 foundation +
3 profiles, verifies capability inheritance, inactive filtering)
- New: graceful AccessDeniedException handling test
- Updated: all existing tests for dual-API discovery pattern
Fixes#55642
* fix(bedrock): preserve inference profile model lookup
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
resolveTrackedFacadePluginId triggers config loading (plugin auto-enable,
channel discovery) which can re-enter loadBundledPluginPublicSurfaceModuleSync
for the same module. Because the sentinel was still empty at that point,
re-entrant callers saw undefined exports (e.g. shouldNormalizeGoogleProviderConfig).
Move Object.assign(sentinel, loaded) before the plugin ID resolution so any
re-entrant lookup through the cached sentinel finds the real exports.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The cron tool schema used type arrays (['string','null']), the 'not'
keyword, and 'const' — all unsupported by the OpenAPI 3.0 subset that
Gemini-backed providers (e.g. GitHub Copilot) enforce. This caused
HTTP 400 for every request when cron was enabled.
Replace type arrays with scalar types, remove not/const from
CronFailureAlertSchema, and add 'not' to the Gemini unsupported
keywords list as defense-in-depth.
Fixes#61206