crewAI icon indicating copy to clipboard operation
crewAI copied to clipboard

Adding async support for tools

Open tg1482 opened this issue 1 year ago • 3 comments

Following our discussion here, creating another PR with minimal changes to the codebase for supporting async tooling.

Previous PR here - https://github.com/joaomdmoura/crewAI/pull/550

Added a test which passes for executing a pipeline with an async tool.

Screenshot 2024-06-05 at 10 35 27 AM

tg1482 avatar Jun 05 '24 05:06 tg1482

This PR is stale because it has been open for 45 days with no activity.

github-actions[bot] avatar Sep 25 '24 12:09 github-actions[bot]

Disclaimer: This review was made by a crew of AI Agents.

Code Review Comment for Async Tooling Implementation

Overview

The pull request introduces asynchronous tool support in crewAI, specifically modifying tool_usage.py and including test cases in crew_test.py. The changes accommodate both decorator-based (@tool) and BaseTool-based asynchronous implementations, enhancing the framework's flexibility and responsiveness.

Positive Aspects

  1. Effective Async Tool Execution: The implementation allows for seamless execution of async tools, preserving essential error handling mechanisms to ensure robustness.
  2. Support for Multiple Tool Decorators: It accommodates both @tool decorators and BaseTool class instances, promoting versatility within the codebase.
  3. Comprehensive Test Coverage: The tests are well-structured to cover both async implementations, ensuring that functionality is preserved across different execution paths.

Issues and Recommendations

  1. Async Tool Method Detection Logic: Current implementation:

    tool_method = tool.func or tool.coroutine
    is_async_tool = asyncio.iscoroutinefunction(tool_method)
    

    Recommendation: Introduce explicit error checking to avoid runtime issues:

    def _get_tool_method(tool):
        if hasattr(tool, 'func') and tool.func:
            return tool.func
        elif hasattr(tool, 'coroutine') and tool.coroutine:
            return tool.coroutine
        raise ValueError("Tool must have either func or coroutine attribute")
    
    tool_method = _get_tool_method(tool)
    is_async_tool = asyncio.iscoroutinefunction(tool_method)
    
  2. Async Execution Context: Current usage of asyncio.run() could create new event loops which might be problematic. Recommendation: Use context-aware execution:

    async def _execute_async_tool(tool_run, *args, **kwargs):
        try:
            loop = asyncio.get_running_loop()
        except RuntimeError:
            return await tool_run(*args, **kwargs)
        return await tool_run(*args, **kwargs)
    
  3. Code Duplication in Argument Handling: The async execution code is repeated across files. Recommendation: Extract common logic into a single method to reduce repetition:

    def _execute_tool(tool_run, is_async, *args, **kwargs):
        if is_async:
            return asyncio.run(tool_run(*args, **kwargs))
        return tool_run(*args, **kwargs)
    
  4. Test Isolation and Performance: Improve test isolation with setup/teardown strategies, and refine test performance by reducing asyncio.sleep() timeframes. Recommendation: Use fixtures and shorter sleep calls or mocks:

    @pytest.fixture
    def async_tool_setup():
        async def async_search(query: str) -> str:
            await asyncio.sleep(0.01)  # Reduced to enhance speed
            return "The capital of France is Paris."
        return async_search
    
  5. Documentation and Type Hints: Provide detailed docstrings and type hints for better maintenance. Recommendation: Include comprehensive type hints and clear documentation:

    from typing import Union, Callable, Awaitable
    
    ToolResult = Union[str, dict, list]
    ToolCallable = Union[Callable[..., ToolResult], Callable[..., Awaitable[ToolResult]]]
    

Links to Related PRs

While specific historical context cannot be provided, reviewing PRs that previously addressed error handling and async functionality can inform improvements in the current implementation.

Conclusion

The changes in this pull request proficiently introduce async capabilities, but addressing suggested areas for improvement will further enhance code quality and maintainability. Streamlining the execution patterns, reinforcing error handling logic, and optimizing tests will make the project more robust and efficient. Thank you for the hard work put into this implementation!

joaomdmoura avatar Dec 04 '24 17:12 joaomdmoura

Hey @tg1482 , awesome job on the PR!

Could you take a moment to check if the code you added is still relevant and working? We're here to help with anything you need to update and merge this addition.

Thanks

pythonbyte avatar Dec 09 '24 13:12 pythonbyte

This PR is stale because it has been open for 45 days with no activity.

github-actions[bot] avatar Jan 24 '25 12:01 github-actions[bot]