-
Notifications
You must be signed in to change notification settings - Fork 633
feat: make structured output prompt message configurable (#1288) #1627
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: make structured output prompt message configurable (#1288) #1627
Conversation
…nts#1288) When using structured output with Bedrock Guardrails (prompt attack filter enabled), the internal framework message 'You must format the previous response as structured output.' can be flagged as a potential prompt injection attack. This change allows users to customize the structured output prompt message via a new 'structured_output_prompt' parameter on the Agent constructor. This is a more general solution than PR strands-agents#1564's guardContent approach because: 1. It's model-agnostic (works with any provider, not just Bedrock) 2. Users can customize the wording to avoid their specific guardrail rules 3. More flexible for different use cases and languages 4. Simpler implementation without provider-specific detection logic Usage: agent = Agent( structured_output_model=MyModel, structured_output_prompt='Please format your response as structured data.' ) The default prompt remains 'You must format the previous response as structured output.' for backwards compatibility.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
I got my agent to review **Decision:** Merge ✅Rationale: This is a well-implemented feature that:
Quick Stats
Critical IssuesNone identified. Important IssuesNone. The previous feedback about per-invocation override has been addressed in this update. Suggestions
Positive Highlights
Quality Check Results
|
| File | Status | Notes |
|---|---|---|
src/strands/agent/agent.py |
Modified | Adds structured_output_prompt to __init__, __call__, invoke_async, stream_async, _run_loop |
src/strands/event_loop/event_loop.py |
Modified | Uses context's prompt instead of hardcoded string |
src/strands/tools/structured_output/__init__.py |
Modified | Exports DEFAULT_STRUCTURED_OUTPUT_PROMPT constant |
src/strands/tools/structured_output/_structured_output_context.py |
Modified | Adds structured_output_prompt parameter with default |
tests/strands/agent/test_agent_structured_output.py |
Modified | Adds TestAgentStructuredOutputPrompt class with 6 tests |
tests/strands/event_loop/test_event_loop_structured_output.py |
Modified | Adds test for custom prompt in event loop |
tests/strands/tools/structured_output/test_structured_output_context.py |
Modified | Adds tests for custom prompt initialization |
Checklist
- Issue/feature validated (not already fixed/implemented)
- PR title follows conventional commit format
- Single focused objective (no scope creep)
- Type annotations complete
- Docstrings present
- Tests included (>80% patch coverage)
- Both streaming/non-streaming paths tested
- No breaking changes (or documented)
- Follows project patterns (see AGENTS.md)
- Error handling appropriate
- Backwards compatible
- Per-invocation override consistent with
structured_output_model - External API compliance verified (if applicable) - N/A
- Architectural decisions documented (for complex changes) - N/A (simple feature)
Additional Notes
Changes from Previous Version
The author addressed the feedback from the initial review:
-
Added per-invocation override:
structured_output_promptcan now be specified at call time, just likestructured_output_model:# Constructor default agent = Agent(structured_output_prompt="Default prompt") # Override at call time result = agent("query", structured_output_prompt="Custom prompt for this call")
-
Added comprehensive tests: 6 new tests specifically for
structured_output_promptfunctionality.
Historical Context
This PR is an alternative approach to #1564 which proposed using guardContent wrapper for Bedrock-specific protection. This solution is more general and works with any model provider.
Usage Example
from strands import Agent
from pydantic import BaseModel
class UserInfo(BaseModel):
name: str
age: int
# Option 1: Default prompt for all calls
agent = Agent(
structured_output_model=UserInfo,
structured_output_prompt="Please use the output tool now."
)
# Option 2: Override per-invocation
agent = Agent(structured_output_model=UserInfo)
result = agent(
"Get user info",
structured_output_prompt="Please format using the schema."
)| DEFAULT_STRUCTURED_OUTPUT_PROMPT = "You must format the previous response as structured output." | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the user override this instead of us having to plumb this all the way through from the agent initialization?
Here's the PR description:
Description
When using structured output with Bedrock Guardrails (prompt attack filter enabled), the internal framework message
"You must format the previous response as structured output."gets flagged as a potential prompt injection attack, causingguardrail_intervened.This PR adds a new
structured_output_promptparameter to the Agent constructor that allows users to customize this message. This is a more general solution than wrapping inguardContent(as proposed in #1564) because:Usage
E2E Test Results
Tested with a Bedrock Guardrail with prompt attack detection enabled (HIGH sensitivity):
"You must format the previous response as structured output.""Please use the output tool now."Related Issues
Fixes #1288
Alternative approach to #1564
Documentation PR
Type of Change
New feature
Testing
Ran
hatch run test tests/strands/tools/structured_output/test_structured_output_context.py- 18 tests passRan
hatch run test tests/strands/event_loop/test_event_loop_structured_output.py- 8 tests passRan
hatch run test tests/strands/event_loop/- 94 tests passE2E tested with actual Bedrock Guardrail with prompt attack filter enabled
I ran
hatch run prepareChecklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice