Skip to content

feat: add AgentAsTool#1932

Merged
notowen333 merged 9 commits intostrands-agents:mainfrom
notowen333:agent-as-tool
Mar 26, 2026
Merged

feat: add AgentAsTool#1932
notowen333 merged 9 commits intostrands-agents:mainfrom
notowen333:agent-as-tool

Conversation

@notowen333
Copy link
Copy Markdown
Contributor

@notowen333 notowen333 commented Mar 18, 2026

Description

Will close #1002.

This PR adds the AgentAsTool class as well as a convenience method on the Agent class to return an instance of it.

The AgentAsTool class just calls stream_async on the underlying agent and formats the response as a ToolResultEvent.

The added integration test confirms that an AgentAsTool was invoked and that agent-as-tool used a tool of its own.

Related Issues

#1002

Documentation PR

strands-agents/docs#686

Type of Change

New feature

Testing

  • Added unit tests

  • Added a minimal integ test

  • [ x] I ran hatch run prepare

Checklist

  • [ x ] I have read the CONTRIBUTING document
  • [ x ] I have added any necessary tests that prove my fix is effective or my feature works
  • [ x ] I have updated the documentation accordingly
  • [ x ] I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • [ x ] My changes generate no new warnings
  • [ x ] Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 18, 2026

Codecov Report

❌ Patch coverage is 97.16981% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/strands/agent/_agent_as_tool.py 96.70% 2 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@github-actions
Copy link
Copy Markdown

Issue: The original issue #1002 mentions a preserve_context: bool parameter to control whether previous conversation context is preserved between invocations.

Question: Is this parameter intentionally deferred to a follow-up PR, or should it be included in this initial implementation? The current implementation appears to preserve context by default (since it uses the same agent instance), but there's no way for users to reset context between calls.

This could be a breaking change if added later, so it would be good to clarify the intended behavior.

@github-actions
Copy link
Copy Markdown

Code Review Summary

Assessment: Request Changes

This PR introduces a well-designed AgentAsTool class and Agent.as_tool() convenience method. The implementation follows SDK patterns and includes comprehensive tests. However, documentation is required before merge.

Review Categories
  • Documentation: Missing documentation PR. This introduces new public API surface (AgentAsTool class, Agent.as_tool() method) and requires user documentation per project guidelines.
  • API Review: Consider adding needs-api-review label since this adds new public abstractions customers will use.
  • Design Clarification: The preserve_context parameter from [FEATURE] Agent to_tool method #1002 should be addressed - either as part of this PR or explicitly deferred.

The core implementation looks solid - just needs the documentation PR linked to unblock merge.

@notowen333
Copy link
Copy Markdown
Contributor Author

/strands review

@github-actions
Copy link
Copy Markdown

Code Review Summary - Updated

Assessment: Approve ✅

Thank you for addressing the feedback from the previous review! All blocking issues have been resolved:

Changes Addressed
  • Documentation PR: Now linked (feat: add section in user guide on new functionality for Agent.as_tool() docs#686)
  • preserve_context parameter: Implemented with proper input schema, context clearing logic, and comprehensive tests
  • Input type handling: Added explicit type checks with warning logs for unexpected input formats
  • Test coverage: Expanded from 213 to 352 lines with tests for all new functionality
Minor Notes (Non-blocking)
  • The discussion with @awsarron about class vs @tool approach is still open - waiting for direction on how to proceed
  • Coverage at 94.52% is acceptable; the 4 uncovered lines appear to be edge cases
  • Previous inline comments about empty string checks remain as suggestions but are not blocking

The implementation is well-designed, follows SDK patterns, and includes proper error handling and logging. Ready to merge once the awsarron discussion is resolved and any CI checks pass.

…e; yield AgentAsToolStreamEvents; small fixes
@notowen333
Copy link
Copy Markdown
Contributor Author

/strands review

@mkmeral
Copy link
Copy Markdown
Contributor

mkmeral commented Mar 25, 2026

/strands review

@github-actions
Copy link
Copy Markdown

Code Review Summary - Round 5

Assessment: Request Changes

The session manager divergence bug has been addressed with a ValueError check. However, there are still inconsistencies in the API design that should be resolved.

Blocking Issues
Issue Location Action Needed
Private class export strands/__init__.py:15, strands/agent/__init__.py:28 Remove _AgentAsTool from __all__ — underscore prefix means private
Docstring references private class agent.py:636 Change "An _AgentAsTool" to "A tool wrapping this agent"
What's Been Addressed
  • Session manager check (lines 89-95): ValueError raised when preserve_context=False with session manager
  • Description handling: Moved to constructor with proper fallback (line 75-77)
  • Type annotation: agent: Agent is explicit about requirements
Design Decision Needed

@mkmeral raised a valid point: should _AgentAsTool be:

  1. Truly private — Remove from __all__, customers only use agent.as_tool()
  2. Public — Rename to AgentAsTool, export properly

The current state (private name + public export) is contradictory. I'd suggest option 1 (truly private) since customers have agent.as_tool() as the main API.

Once the export inconsistency is resolved, this is ready to merge.

@notowen333
Copy link
Copy Markdown
Contributor Author

/strands review

@github-actions
Copy link
Copy Markdown

Code Review Summary - Round 6

Assessment: Approve ✅

All blocking issues from previous reviews have been resolved.

Issues Resolved
Issue Resolution
Private class export _AgentAsTool removed from __all__ in both modules
Return type ✅ Changed from _AgentAsTool to AgentTool
Docstring ✅ Now says "A tool wrapping this agent"
Final Implementation Summary

API Design:

  • _AgentAsTool is truly private (underscore prefix, not exported)
  • Public API as_tool() returns AgentTool (public base type)
  • Docstrings don't reference internal implementation details

Key Features:

  • preserve_context parameter (default False for stateless invocations)
  • Session manager check raises ValueError when incompatible
  • Concurrency protection with threading.Lock
  • Interrupt propagation to parent agent
  • AgentAsToolStreamEvent for differentiating sub-agent events

Test Coverage: 97.20% with 676 lines of comprehensive tests

The implementation is well-designed, follows SDK patterns, and addresses the original issue #1002 completely. Ready to merge! 🎉

mkmeral
mkmeral previously approved these changes Mar 26, 2026
@notowen333 notowen333 merged commit 6a35add into strands-agents:main Mar 26, 2026
18 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Agent to_tool method

5 participants