aws-samples / aws-samples/sample-multi-agent-orchestration-chat-on-agentcore
feat: Add xAI Grok 4.3 support via bedrock-mantle endpoint (OpenAI-compatible API)
- Dominant language
- TypeScript
- Stars
- 128
- Forks
- 12
- Avg merge
- 3d 1h
- Merged PRs (30d)
- 4
Description
## Summary
[xAI Grok 4.3](https://x.ai/news/grok-4) went GA on Amazon Bedrock on June 15–17, 2026 (model ID: `xai.grok-4.3`). It is the **cheapest frontier reasoning model on Bedrock** ($1.25/M input vs Claude Opus 4.8's $15/M — **12× cheaper**), with a 1M-token context window, 30k max output, configurable reasoning, and full tool-calling support.
Moca currently **cannot support Grok 4.3** because it uses a fundamentally different endpoint and API than all existing Bedrock models.
---
## Root Cause: Architectural Mismatch
| | Traditional Bedrock (Claude, Nova, Qwen) | Grok 4.3 on Bedrock |
|---|---|---|
| **Endpoint** | `bedrock-runtime` | `bedrock-mantle` |
| **API** | Converse / InvokeModel | OpenAI-compatible Chat Completions |
| **SDK** | AWS SDK / boto3 | OpenAI SDK with IAM Bearer token |
| **Auth** | SigV4 | IAM → Bearer token via `@aws/bedrock-token-generator` |
| **Region** | Multi-region (inference profiles) | `us-west-2` only (currently) |
Moca's `createBedrockModel()` factory creates only `BedrockModel` from `@strands-agents/sdk`, which targets `bedrock-runtime` + Converse API exclusively. There is no `bedrock-mantle` path, no OpenAI SDK dependency, and no IAM Bearer token flow anywhere in the codebase.
### Good news: the SDK already supports this
`@strands-agents/sdk` **v1.3.0+** (released 2026-05-21) already ships `OpenAIModel` with built-in `BedrockMantleConfig` support — including lazy-loaded `@aws/bedrock-token-generator` integration. The app currently pins `^1.2.0` (which predates Mantle support); bumping to `^1.3.0` or higher unlocks the required model class with zero new infrastructure.
---
## Grok 4.3 Specifications
| Property | Value |
|---|---|
| Model ID | `xai.grok-4.3` |
| Context window | 1,000,000 tokens |
| Max output | 30,000 tokens |
| Input price | $1.25 / 1M tokens |
| Output price | $2.50 / 1M tokens |
| Reasoning | `none` / `low` / `medium` / `high` |
| Region | `us-west-2` only |
| Tool calling | ✅ |
| Streaming | ✅ |
---
## Required Changes
### 1. — Model Registry (Single Source of Truth)
**a) Add `xAI` provider and `endpoint` field to `BedrockModelDefinition`:**
```ts
export interface BedrockModelDefinition {
// ... existing fields ...
readonly provider: 'Anthropic' | 'Amazon' | 'Qwen' | 'xAI'; // add 'xAI'
/**
* Endpoint type for this model.
* 'bedrock-runtime': standard Converse/InvokeModel via BedrockModel (default)
* 'bedrock-mantle': OpenAI-compatible endpoint via OpenAIModel + BedrockMantleConfig
*/
readonly endpoint?: 'bedrock-runtime' | 'bedrock-mantle';
}
```
**b) Add a `getModelEndpoint()` helper:**
```ts
export function getModelEndpoint(modelId: string): 'bedrock-runtime' | 'bedrock-mantle' {
return findModel(modelId)?.endpoint ?? 'bedrock-runtime';
}
```
**c) Add Grok 4.3 entry** (first in list for priority, or after Fable 5 — team's discretion):
```ts
{
id: 'xai.grok-4.3',
name: 'Grok 4.3',
provider: 'xAI',
maxOutputTokens: 30000,
endpoint: 'bedrock-mantle',
reasoningCapable: true,
region: 'us-west-2', // bedrock-mantle is us-west-2 only currently
},
```
**d) Grok reasoning config**: Grok 4.3 uses `{ reasoning: { effort: 'low'|'medium'|'high' } }` (passed via OpenAI `params`), not Anthropic's `{ thinking: { type: 'adaptive' }, output_config: { effort } }`. The `getReasoningConfig()` function — or a new `getOpenAIReasoningParams()` counterpart — needs to handle this divergence. Suggested approach: add a `reasoningParamStyle?: 'anthropic' | 'grok'` field to `BedrockModelDefinition` and export a separate helper for OpenAI-style params.
---
### 2. — Model Factory
**a) Bump SDK and add optional dep in `packages/agent/package.json`:**
```json
{
"dependencies": {
"@strands-agents/sdk": "^1.3.0", // was ^1.2.0; 1.3+ has BedrockMantleConfig
"@aws/bedrock-token-generator": "^1.0.0" // optional peer of @strands-agents/sdk
}
}
```
**b) Add `createMantleModel()` factory** (or extend `createBedrockModel()` to dispatch on endpoint):
```ts
import { OpenAIModel } from '@strands-agents/sdk/models/openai';
import { getModelEndpoint } from '@moca/core';
export function createMantleModel(options?: BedrockModelOptions): OpenAIModel {
const modelId = options?.modelId || config.BEDROCK_MODEL_ID;
const region = options?.region || getModelRegion(modelId) || config.BEDROCK_REGION;
// Map Moca's ReasoningDepth to Grok's effort string
const grokEffort = mapToGrokEffort(options?.reasoningEffort);
return new OpenAIModel({
api: 'chat', // Grok 4.3 uses Chat Completions
modelId,
maxTokens: options?.maxTokens ?? getMaxOutputTokens(modelId),
bedrockMantleConfig: { region },
...(grokEffort ? { params: { reasoning: { effort: grokEffort } } } : {}),
});
}
/** Map Moca ReasoningDepth → Grok effort string */
function mapToGrokEffort(depth?: ReasoningDepth): string | undefined {
switch (depth) {
case 'low': return 'low';
case 'high': return 'medium';
case 'max': return 'high';
default: return undefined; // 'off' or undefined → no reasoning field
}
}
```
**c) Update `createBedrockModel()` (or rename to `createModel()`) to dispatch**:
```ts
export function createModel(options?: BedrockModelOptions): BedrockModel | OpenAIModel {
const modelId = options?.modelId || config.BEDROCK_MODEL_ID;
if (getModelEndpoint(modelId) === 'bedrock-mantle') {
return createMantleModel(options);
}
return createBedrockModel(options); // existing path unchanged
}
```
Update `agent.ts` to call `createModel()` instead of `createBedrockModel()`.
---
### 3. — Provider Type
```ts
export interface BedrockModel {
id: string;
name: string;
provider: 'Anthropic' | 'Amazon' | 'Qwen' | 'xAI'; // add 'xAI'
}
const VALID_PROVIDERS: ReadonlySet = new Set([
'Anthropic', 'Amazon', 'Qwen', 'xAI', // add 'xAI'
]);
```
---
### 4. — CDK Config Types
```ts
export interface BedrockModelConfig {
// ...
provider: 'Anthropic' | 'Amazon' | 'Qwen' | 'xAI'; // add 'xAI'
/**
* Optional endpoint type override.
* 'bedrock-mantle' models (e.g. Grok 4.3) use OpenAI-compatible API + Bearer auth
* and do NOT get inference-profile or foundation-model IAM ARNs — those don't apply.
* Instead, the agent role needs bedrock:GetFoundationModelToken permission.
*/
endpoint?: 'bedrock-runtime' | 'bedrock-mantle';
}
```
---
### 5. — IAM Grant
The `deriveBedrockIamResources()` function currently derives inference-profile and foundation-model ARNs. Grok 4.3 on `bedrock-mantle` uses a completely different auth path (IAM → bearer token) and does **not** use those ARNs. Instead, the agent's IAM role needs:
```json
{
"Effect": "Allow",
"Action": "bedrock:GetFoundationModelToken",
"Resource": "arn:aws:bedrock:us-west-2::foundation-model/xai.grok-4.3"
}
```
Update `deriveBedrockIamResources()` to skip the standard ARN derivation for `endpoint: 'bedrock-mantle'` models and instead emit the `GetFoundationModelToken` resource.
Also add Grok 4.3 to `DEFAULT_CONFIG.bedrockModels`:
```ts
{
id: 'xai.grok-4.3',
name: 'Grok 4.3',
provider: 'xAI',
endpoint: 'bedrock-mantle',
region: 'us-west-2',
},
```
And update `VALID_PROVIDERS` and `validateBedrockModels()` to accept `'xAI'`.
---
### 6. Tests
- [ ] Unit test: `getModelEndpoint()` returns `'bedrock-mantle'` for `xai.grok-4.3` and `'bedrock-runtime'` for all existing models
- [ ] Unit test: `createBedrockModel.test.ts` — add dispatch test (Grok ID → `createMantleModel`, existing IDs → `BedrockModel`)
- [ ] Unit test: reasoning depth mapping `ReasoningDepth → Grok effort`
- [ ] Integration test: `grok-4.3-model.integration.test.ts` (opt-in, mirrors existing `qwen3-model.integration.test.ts` pattern)
- [ ] CDK test: `deriveBedrockIamResources` emits `GetFoundationModelToken` ARN (not inference-profile) for Mantle models
---
## Files to Modify
| File | Change |
|---|---|
| `packages/libs/core/src/bedrock-models.ts` | Add `xAI` provider, `endpoint` field, Grok 4.3 entry, `getModelEndpoint()` |
| `packages/agent/src/config/bedrock.ts` | Add `createMantleModel()`, update dispatch |
| `packages/agent/src/agent.ts` | Call `createModel()` instead of `createBedrockModel()` |
| `packages/agent/package.json` | Bump SDK to `^1.3.0`, add `@aws/bedrock-token-generator` |
| `packages/frontend/src/config/models.ts` | Add `'xAI'` to provider type |
| `packages/cdk/config/environment-types.ts` | Add `'xAI'` provider, `endpoint` field |
| `packages/cdk/config/environment-utils.ts` | Grok 4.3 entry, IAM for `GetFoundationModelToken`, `VALID_PROVIDERS` |
| Test files (new) | Unit + integration tests per above |
---
## Why This Is Worth Implementing
- **12× cheaper** than Claude Opus 4.8 for reasoning-heavy workloads ($1.25 vs $15/M input tokens)
- **1M context window** — largest on Bedrock, ideal for large codebases and long documents
- **Strong reasoning** with configurable effort (low/medium/high)
- **Tool calling + streaming** — fully compatible with Moca's agent loop
- The Strands SDK already handles the hard parts (`OpenAIModel` + `BedrockMantleConfig`) — the Moca-side work is primarily wiring
- Establishes a pattern for any future `bedrock-mantle` models (other OpenAI-compatible providers on Bedrock)
---
## Notes & Caveats
- **Session persistence**: Grok 4.3 uses the OpenAI message format (not Bedrock Converse blocks). The `content-block-codec.ts` (used to serialize/deserialize session history via AgentCore Memory) targets the Converse `ContentBlock` shape. Session history for Grok turns may need a separate codec path or the `OpenAIModel` stateful mode.
- **Prompt caching**: Not applicable to Grok 4.3 on bedrock-mantle; the `ENABLE_PROMPT_CACHING` flag should be ignored for Mantle models.
- **Empty block hooks**: `EmptyTextBlockHook` and `EmptyReasoningBlockHook` operate on Converse blocks; verify they are no-ops or properly bypass for the OpenAI path.
- **Region**: `us-west-2` only for now — same pinning pattern as Qwen3 Coder Next (`us-east-1`).
Contributor guide
Research direction
Start with packages/libs/core/src/bedrock-models.ts and packages/agent/src/config/bedrock.ts to trace model definitions and factory dispatch. Review the listed CDK configuration files and existing qwen3-model.integration.test.ts pattern, then add the requested unit, integration, and IAM coverage. Done means xai.grok-4.3 uses the Mantle path while existing models retain their current path and configuration.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, typescript
- Domain
- backend-api-design, cloud, infrastructure, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100