anthropics / anthropics/claude-agent-sdk-python

[FEATURE] Native Bedrock Guardrail body wrapping for InvokeModel / InvokeModelWithResponseStream

Ouverte
#999 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
enhancement
Langage dominant
Python
Étoiles
8.1k
Forks
1.3k
Merge moyen
2 j 31 min
PR mergées (30 j)
1

Description

## Summary

When using `claude-agent-sdk` with Amazon Bedrock and a Bedrock Guardrail
attached via the `X-Amzn-Bedrock-GuardrailIdentifier` /
`X-Amzn-Bedrock-GuardrailVersion` headers (e.g. injected through
`ANTHROPIC_CUSTOM_HEADERS`), every `InvokeModel` /
`InvokeModelWithResponseStream` call fails closed with:

HTTP 400 Guardrail was enabled but input is in incorrect format.

The model is never invoked, the guardrail never evaluates, no usage is
billed beyond the round-trip, and no `guardrailTrace` event is produced —
so guardrails can be neither **enforced** nor **observed** while routing
through this SDK against Bedrock.

Reproduced on `claude-agent-sdk==0.2.87` + `us.anthropic.claude-opus-4-7`
on Bedrock `us-east-1`, both single-agent and multi-agent (sub-agent /
A2A) configurations.

## Why it fails

Bedrock Guardrail enforcement on the InvokeModel path requires **two
coordinated changes** per request:

1. **Headers** — `X-Amzn-Bedrock-GuardrailIdentifier`,
`X-Amzn-Bedrock-GuardrailVersion`, optional
`X-Amzn-Bedrock-Trace`. The SDK forwards these correctly.

2. **Body** — when the headers are present, Bedrock requires:
- a top-level `amazon-bedrock-guardrailConfig` object
(e.g. `{\"streamProcessingMode\": \"sync\"}`), and
- natural-language text segments in `messages[]` and the system
prompt wrapped in
`>...`
markers so the engine knows which spans to evaluate.
Tool-use / tool-result blocks must NOT be wrapped.

The SDK currently emits Anthropic Messages-shaped bodies on the
Bedrock path with neither of these, so Bedrock fails closed.

Reference: AWS Bedrock Guardrails — *Use a guardrail with the
InvokeModel API* (the `guardContent` and `guardrailConfig` sections).

## Requested behavior

When \`ClaudeAgentOptions\` is configured for Bedrock and the runtime
detects guardrail headers (or via an explicit option, e.g.
\`bedrock_guardrail={\"id\": \"...\", \"version\": \"DRAFT\"}\`), the SDK should:

- Inject \`amazon-bedrock-guardrailConfig\` into the outgoing body.
- Wrap text content blocks in \`messages[]\` and the system prompt with
\`guardContent\` markers; leave \`tool_use\` / \`tool_result\` blocks
untouched.
- Pass through \`guardrailTrace\` / intervention metadata on the
response side so callers can attribute guardrail actions to a turn.

Equivalent support is already needed on
\`InvokeModelWithResponseStream\` for the streaming code path.

## Why this matters

Without native support, integrators have two choices, both bad:

1. **Local botocore hook** that monkey-patches the outgoing body —
fragile, will silently double-wrap once the SDK adds real support
unless a feature flag is plumbed.
2. **\`ApplyGuardrail\` sidecar calls** — possible for *observability*
but does not enforce; adds 1–2 extra round-trips per turn.

Native support lets every \`claude-agent-sdk\` user pick up Bedrock
Guardrail enforcement and the corresponding \`guardrailTrace\`
observability with a single config option, the same way Bedrock
Guardrail headers already work today.

## Related

- Bedrock Converse API handles this natively; the InvokeModel path
does not. Migrating the SDK's Bedrock transport to Converse would
also resolve this (and prompt-caching #626) but is a larger change.

## Environment

- \`claude-agent-sdk==0.2.87\`
- AWS Bedrock \`us-east-1\`
- \`us.anthropic.claude-opus-4-7\`
- Reproduced on AWS Bedrock AgentCore Runtime; same body-shape issue
applies to any caller that adds guardrail headers.

Guide de contribution

Aucun guide de contribution indexé pour ce dépôt

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.