Skip to content

fix(docs): (DO NOT MERGE) strands integration - #29

Closed
namrataghadi-galileo wants to merge 29 commits into
mainfrom
feature/strands-integration
Closed

fix(docs): (DO NOT MERGE) strands integration#29
namrataghadi-galileo wants to merge 29 commits into
mainfrom
feature/strands-integration

Conversation

@namrataghadi-galileo

@namrataghadi-galileo namrataghadi-galileo commented Feb 13, 2026

Copy link
Copy Markdown
Contributor

Strands Integration Example
Demonstrates automatic safety controls for AWS Strands agents using a reusable hook pattern - no code decorators needed.

What's Included

Core Integration

  • AgentControlHook - Reusable hook class that intercepts Strands agent events and enforces controls
  • Automatic tool name extraction from Strands events for tool-specific controls
  • Support for both pre and post-stage evaluation across LLM calls and tool executions

Interactive Demo (interactive_demo/)

  • Customer support agent with Streamlit UI
  • Real-time PII detection (SSN, email, credit card blocking)
  • SQL injection prevention for database queries
  • Shows control violations with user-friendly error messages

Steering Demo (steering_demo/)

  • Banking email agent with PII redaction
  • Combines AgentControl detection + Strands Steering correction
  • Demonstrates layered governance: detect sensitive data, then intelligently redact it
  • Shows integration between two safety systems

Hook-Based Architecture

  • Attaches to Strands agents via the hooks parameter
  • Intercepts BeforeToolCallEvent, AfterModelCallEvent, and other Strands lifecycle events
  • Automatically constructs Step payloads and evaluates controls server-side
  • No modification to agent code or tool definitions required

@namrataghadi-galileo
namrataghadi-galileo changed the base branch from main to feature/54252-step_name-as_parameter February 13, 2026 22:41
@codecov

codecov Bot commented Feb 13, 2026

Copy link
Copy Markdown

The author of this PR, namrataghadi-galileo, is not an activated member of this organization on Codecov.
Please activate this user on Codecov to display this PR comment.
Coverage data is still being uploaded to Codecov.io for purposes of overall coverage calculations.
Please don't hesitate to email us at support@codecov.io with any questions.

Comment thread examples/strands_integration/interactive_demo/interactive_support_demo.py Outdated
Base automatically changed from feature/54252-step_name-as_parameter to main February 17, 2026 17:00
@namrataghadi-galileo
namrataghadi-galileo changed the base branch from main to feature/add-stage-override February 19, 2026 00:20
@namrataghadi-galileo
namrataghadi-galileo changed the base branch from feature/add-stage-override to main February 21, 2026 02:52
Comment thread sdks/python/src/agent_control/evaluation.py Outdated
Comment thread sdks/python/src/agent_control/evaluation.py Outdated
Comment thread sdks/python/src/agent_control/evaluation.py Outdated
Comment thread sdks/python/src/agent_control/evaluation.py Outdated

@lan17 lan17 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM overall, just a few remaining nits, but i love the more simplified version of evaluate :)

async def evaluate_controls(
step_name: str,
*,
input: Any = None,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be Any | None? not sure if Any covers None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, in what situations would this be null?

Same question for the output.

I suppose it would only be the case if there's no args to a tool call and a void output?

context: dict[str, Any] | None = None,
step_type: Literal["tool", "llm"] = "llm",
stage: Literal["pre", "post"] = "pre",
agent_uuid: str | UUID,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wonder if we should get rid of it since im getting rid of it here: #44

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will have to uptake it once your PR is merged.

output_text = ""

# BeforeInvocationEvent - has messages attribute with user input
if hasattr(event, "messages") and event.messages:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explicit event type checks would be preferable IMHO - for type safety purposes and readability

Same for below for tools

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure.

# selected_tool is an AgentTool object with name attribute
if hasattr(event.selected_tool, "name"):
tool_name = event.selected_tool.name
elif hasattr(event.selected_tool, "__name__"):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you see a case where you got something that wasn't AgentTool? Same question for below and "get"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type check refactor takes care of this redundancy

if isinstance(event.tool_use, dict):
tool_name = event.tool_use.get("toolName", "unknown-tool")
elif hasattr(event.tool_use, "get"):
tool_name = event.tool_use.get("toolName", "unknown-tool")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar question to the need for "get" here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed. The original code had overly defensive hasattr() checks that don't correspond to any real case in Strands. Refactored code correctly removes these unnecessary checks and uses the actual types

print(f"🔍 Extracted tool name: {tool_name}")

# Extract input (pre-stage) or output (post-stage)
if event_phase == "pre":

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you did an isinstance check for BeforeToolCall and AfterToolCall, I think you could even omit the event_phase here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switching to an isinstance check let us remove a lot of code — great catch. This is handled there now.

content = content.content

# List of content blocks
if isinstance(content, list):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you ever want anything other than plain text?

Our AgentResult also stringifies structured output and citation blocks

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hooks intercept at a lower level (model/tool calls) BEFORE AgentResult is constructed. What we receive from the events is:

Message.content: list[ContentBlock]
ToolResult.content: list[ToolResultContent]
invocation_state values: Any (strings, dicts, etc.)

So we need more than plain text—thanks for flagging it. We now extract text, citations, tool info, and JSON from ContentBlock/ToolResultContent TypedDicts for control inspection, since those fields can contain content that needs policy enforcement.

@namrataghadi-galileo namrataghadi-galileo changed the title fix(docs): strands integration fix(docs): (DO NOT MERGE) strands integration Mar 5, 2026
@namrataghadi-galileo
namrataghadi-galileo deleted the feature/strands-integration branch March 10, 2026 05:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants