diff --git a/agent/Dockerfile b/agent/Dockerfile index 90c4ff5e..69088234 100644 --- a/agent/Dockerfile +++ b/agent/Dockerfile @@ -13,7 +13,7 @@ RUN uv pip install --no-cache -r requirements.txt RUN useradd -m -u 1000 bedrock_agentcore USER bedrock_agentcore -COPY basic_agent.py cost_logger.py factory.py composition.py mcp_clients.py mantle_client.py model_profiles.py resilience.py session.py streaming.py ./ +COPY basic_agent.py cost_logger.py errors.py factory.py composition.py mcp_clients.py mantle_client.py model_profiles.py resilience.py session.py streaming.py ./ COPY prompts/ prompts/ COPY modes/ modes/ COPY tools/ tools/ diff --git a/agent/mantle_client.py b/agent/mantle_client.py index 103ca0b4..01237c17 100644 --- a/agent/mantle_client.py +++ b/agent/mantle_client.py @@ -40,12 +40,28 @@ async def aclose(self): def mantle_model(model_id: str, region: str = "us-east-1"): - """Create a Strands OpenAIModel pointing at bedrock-mantle with SigV4 auth. + """Create a Strands model pointing at bedrock-mantle with AWS-native auth. + + Models that only support the Responses API (see + ``model_profiles.MANTLE_RESPONSES_MODELS``, e.g. GPT-5.6 Terra) use + Strands' native ``OpenAIResponsesModel`` with ``bedrock_mantle_config`` + (bearer token minted per request). All other models use the legacy + Chat Completions path with a SigV4-signed httpx transport. Usage: from mantle_client import mantle_model model = mantle_model("openai.gpt-5.4", region="us-east-1") """ + from model_profiles import MANTLE_RESPONSES_MODELS + + if model_id in MANTLE_RESPONSES_MODELS: + from strands.models.openai_responses import OpenAIResponsesModel + + return OpenAIResponsesModel( + bedrock_mantle_config={"region": region}, + model_id=model_id, + ) + from strands.models.openai import OpenAIModel class _MantleOpenAIModel(OpenAIModel): diff --git a/agent/model_profiles.py b/agent/model_profiles.py index ef6b21d4..416287fa 100644 --- a/agent/model_profiles.py +++ b/agent/model_profiles.py @@ -99,10 +99,18 @@ def to_bedrock_kwargs(self) -> dict: # Models served via bedrock-mantle (OpenAI-compatible endpoint, not Converse API). # model_id → list of supported regions (first entry is the fallback). MANTLE_MODELS: dict[str, list[str]] = { + "openai.gpt-5.6-terra": ["us-east-1", "us-east-2", "us-west-2"], "openai.gpt-5.5": ["us-east-1", "us-east-2"], "openai.gpt-5.4": ["us-east-1", "us-east-2", "us-west-2"], } +# Mantle models that only support the Responses API (no Chat Completions). +# GPT-5.6 model cards: Responses ✅ / Chat Completions ❌ — calling +# /chat/completions returns 400 Bad Request. +MANTLE_RESPONSES_MODELS: set[str] = { + "openai.gpt-5.6-terra", +} + def resolve_mantle_region(model_id: str, deploy_region: str | None = None) -> str: """Resolve the best mantle region for a model. @@ -136,6 +144,7 @@ def resolve_mantle_region(model_id: str, deploy_region: str | None = None) -> st # Amazon Nova "us.amazon.nova-2-lite-v1:0": NOVA_2_DEFAULT, # OpenAI GPT (bedrock-mantle) + "openai.gpt-5.6-terra": GPT_DEFAULT, "openai.gpt-5.5": GPT_DEFAULT, "openai.gpt-5.4": GPT_DEFAULT, } diff --git a/agent/requirements.txt b/agent/requirements.txt index b558e073..b6fd1fb9 100644 --- a/agent/requirements.txt +++ b/agent/requirements.txt @@ -1,6 +1,6 @@ # Dependencies for Strands Agent. AI model access requires appropriate # IAM permissions and Bedrock model access grants. -strands-agents[otel,openai]>=1.30.0 +strands-agents[otel,openai]>=1.47.0 mcp>=1.23.1 bedrock-agentcore[strands-agents]>=1.0.6 aws-opentelemetry-distro>=0.10.0 diff --git a/infra/config.example.yaml b/infra/config.example.yaml index 9f49aaa7..20a08263 100644 --- a/infra/config.example.yaml +++ b/infra/config.example.yaml @@ -42,6 +42,7 @@ model: - "global.anthropic.claude-opus-4-6-v1" - "global.anthropic.claude-haiku-4-5-20251001-v1:0" - "us.amazon.nova-2-lite-v1:0" + - "openai.gpt-5.6-terra" # bedrock-mantle (us-east-1, us-east-2, us-west-2) - "openai.gpt-5.5" # bedrock-mantle (us-east-1, us-east-2) - "openai.gpt-5.4" # bedrock-mantle (us-east-1, us-east-2, us-west-2) diff --git a/infra/lib/agent-stack.ts b/infra/lib/agent-stack.ts index 791e85c5..30fbaf78 100644 --- a/infra/lib/agent-stack.ts +++ b/infra/lib/agent-stack.ts @@ -65,10 +65,12 @@ export class AgentStack extends cdk.Stack { resources: ["*"], }) ); - // bedrock-mantle (OpenAI-compatible endpoint) for models like GPT-5.4/5.5 + // bedrock-mantle (OpenAI-compatible endpoint) for models like GPT-5.4/5.5/5.6. + // CreateInference: legacy SigV4 path (Chat Completions). + // CallWithBearerToken: Responses API path (bearer token, e.g. GPT-5.6 Terra). role.addToPolicy( new iam.PolicyStatement({ - actions: ["bedrock-mantle:CreateInference"], + actions: ["bedrock-mantle:CreateInference", "bedrock-mantle:CallWithBearerToken"], resources: ["*"], }) ); diff --git a/infra/lib/model-metadata.ts b/infra/lib/model-metadata.ts index 6f202426..22d9963f 100644 --- a/infra/lib/model-metadata.ts +++ b/infra/lib/model-metadata.ts @@ -50,6 +50,10 @@ export const MODEL_METADATA: Record = { composable: false, }, // --- OpenAI GPT --- + "openai.gpt-5.6-terra": { + displayName: "GPT-5.6 Terra", + description: "Balanced performance competitive with GPT-5.5 at half the cost", + }, "openai.gpt-5.5": { displayName: "GPT-5.5", description: "OpenAI's most capable model, advanced coding and agentic tasks",