Skip to content

Conversation

@gabriel-eidelman
Copy link
Collaborator

@gabriel-eidelman gabriel-eidelman commented Aug 14, 2025

Why are these changes needed?

The FunctionTarget represents a logical next step in the development of the AG2 Framework. It is very often useful or even critical to pass an agent's output into a function, whether to validate the output, parse it, extract it, save it to context, allow for more complex routing, or anything else. Traditionally, in order to have an agent pass to a function upon completion, you would have to explicitly instruct it in its prompt to call the tool and instruct the agent regarding what to pass in. There are two main problems with this approach:

  1. Consistency - sometimes agents don't listen to instructions well, particularly if the task is complex or confusing in some way. For larger flows with multiple agents, even one mistake like this can break a flow and make failure handling very difficult.
  2. Output quality - agents may shape their responses in a “tool call” context, leading to truncated or less natural outputs. I have experienced this very often.

The FunctionTarget solves this problem elegantly. Subclassing the TransitionTarget class, it is easy to define in the same way that we would an AgentTarget:

agent.handoffs.set_after_work(FunctionTarget(afterwork_function))

The afterwork_function is expected to have the following signature by default:

def afterwork_function(agent_output: str, context_variables: Any) -> FunctionTargetResult:

Custom Parameters:

To add more parameters, place them after context_variables. It is important to note that arguments are passed in positionally, so the order needs to be maintained. Here is an example:

def afterwork_function(agent_output: str, context_variables: Any, extra_bool: bool) -> FunctionTargetResult:

We pass in this parameter using the extra_args parameter which expects a dictionary as follows:

agent.handoffs.set_after_work(FunctionTarget(afterwork_function, extra_args: {"extra_bool": True}))

When the agent finishes its turn, its output (along with context_variables) is automatically passed to this function, where you can implement any custom logic.

Potential use cases:

  • Validating output and retrying if needed
  • Parsing and transforming results before passing them on
  • Gracefully handling failures with corrective feedback
  • Routing dynamically based on output content

Return Type

The returned FunctionTargetResult has the following signature:

class FunctionTargetResult(BaseModel):
    messages: list[FunctionTargetMessage] | str | None = None
    target: TransitionTarget
    context_variables: ContextVariables | None = None

if messages is a str, then it will by default send the message to the 'next' agent (the target agent). Otherwise messages are of the following type:

    class FunctionTargetMessage(BaseModel):
        content: str
        msg_target: Any

this allows for fine-grained control in message handling if beneficial for a given use case. An example use would be passing a large input to the next agent, and passing a status update to all other agents. All messages are sent from the chat manager.

An example implementation is provided in test/agentchat/test_function_targets.py

Checks

@CLAassistant
Copy link

CLAassistant commented Aug 14, 2025

CLA assistant check
All committers have signed the CLA.

@marklysze marklysze marked this pull request as draft August 15, 2025 01:03
@marklysze
Copy link
Collaborator

@gabriel-eidelman this is a great addition to the framework. Following our discussion, let's refactor to keep the FunctionTarget functionality separate from the core group chat code and work on incorporating adding the ability to include a message in the conversation from the function.

@bassilkhilo-ag2
Copy link
Contributor

Hello!

Great addition, nice work.

Note... I think it may be a good idea to add some kind of message indicating there is a tool being executed via a handoff such as '[FUNCTION HANDOFF] - whatevertheoutput is'.

@qingyun-wu
Copy link
Collaborator

@gabriel-eidelman thanks for the PR! Please remember to run pre-commit: https://docs.ag2.ai/latest/docs/contributor-guide/pre-commit/

@marklysze marklysze mentioned this pull request Aug 24, 2025
15 tasks
@joggrbot
Copy link

joggrbot bot commented Sep 5, 2025

📝 Documentation Analysis

All docs are up to date! 🎉


✅ Latest commit analyzed: ce5e37e | Powered by Joggr

@marklysze
Copy link
Collaborator

marklysze commented Sep 6, 2025

Still to do:

  • Create events and emit
  • Proper tests
  • @Lancetnik to look over for impact on RemoteAgent work (this calls a function as an afterwork handoff, also includes optional message broadcasting to agents)

@bassilkhilo-ag2 @gabriel-eidelman - Can you assist in helping to explain the message broadcasting requirement.

@Lancetnik
Copy link
Member

@marklysze, we don't support handoffs in RemoteAgents yet. So, I don't think it should be designed with an impact on Remote Agents. I have no concerns about this feature - it seems like we can support it without any problems if we find a way to support regular hand-offs in Remote Agents.

@marklysze
Copy link
Collaborator

@marklysze, we don't support handoffs in RemoteAgents yet. So, I don't think it should be designed with an impact on Remote Agents. I have no concerns about this feature - it seems like we can support it without any problems if we find a way to support regular hand-offs in Remote Agents.

Great, thanks @Lancetnik, appreciated

@marklysze marklysze marked this pull request as ready for review October 21, 2025 18:59
@claude
Copy link

claude bot commented Oct 23, 2025

PR Review: FunctionTarget Implementation

Summary

This PR introduces a FunctionTarget class that allows agents to pass their output to a function upon completion, providing better control over output validation, parsing, and routing. This is a valuable addition to the AG2 framework.

Positive Aspects ✅

  1. Clear motivation: The PR addresses real problems with consistency and output quality when using tool-based approaches
  2. Good API design: The interface is intuitive and consistent with existing TransitionTarget patterns
  3. Comprehensive feature: Supports context variable updates, flexible message broadcasting, and dynamic routing
  4. Documentation: Includes docstrings and an example implementation

Critical Issues Found 🔴

1. Bug in Message Construction (CRITICAL)

Location: autogen/agentchat/group/targets/function_target.py:66-74

When messages is a string, the code has inconsistent variable assignments that will cause UnboundLocalError.

Line 66-74: The first branch assigns to messages instead of messages_list, and if the loop does not find a matching agent, messages_list is never assigned before being returned on line 77.

Fix: Use messages_list consistently in all branches and initialize it before the conditionals.

2. Potential UnboundLocalError (CRITICAL)

If isinstance(target, (AgentTarget, AgentNameTarget)) is true but the for loop does not find a matching agent, messages_list is undefined when returned.

Fix: Add a fallback assignment after the loop or initialize messages_list before the conditionals.

High Priority Issues 🟡

3. Missing Unit Tests

Location: test/agentchat/test_function_targets.py

The test file only contains an integration test requiring LLM API calls. It lacks:

  • Unit tests for FunctionTarget.init
  • Tests for validate_fn_sig edge cases
  • Tests for construct_broadcast_messages_list with all target types
  • Tests for broadcast function
  • Mock-based tests that do not require API keys

Recommendation: Follow the pattern in test/agentchat/group/targets/test_transition_target.py which has comprehensive unit tests.

4. Type Import Inconsistency

Location: autogen/agentchat/group/targets/function_target.py:9

Other files in the same directory import Optional from typing (see transition_target.py:6, group_chat_target.py:5). While using | None is fine, consistency with the codebase is preferred.

Minor Issues 🟢

5. Error Message Quality

Line 106: Error message could include agent name for better debugging.

6. Documentation Clarity

Line 50: FunctionTargetResult docstring should clarify that a string message is sent to the target agent (not broadcast to all).

7. Pydantic Config Style

Lines 36-37: Verify if codebase uses Pydantic v1 or v2 and use consistent config style.

Security & Performance ✅

  • No security concerns identified
  • No obvious performance issues

Recommendations

  1. Fix critical bugs in construct_broadcast_messages_list before merging
  2. Add comprehensive unit tests to catch these types of bugs
  3. Improve error messages for better debugging experience
  4. Consider exception handling: What happens if the user function raises an exception?

Overall Assessment

This is a valuable feature with good design, but has critical bugs that will cause runtime failures. The bugs are easily fixable. Once addressed, this will be a solid addition to AG2.

Recommendation: Request changes to fix critical bugs and add unit tests before merging.


Review by Claude Code

Copy link
Collaborator

@marklysze marklysze left a comment

Choose a reason for hiding this comment

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

Thanks for a great addition to handoffs @gabriel-eidelman!

If you can create a separate PR with some additions to the documentation, that would be great!

@marklysze marklysze enabled auto-merge October 23, 2025 17:21
@marklysze marklysze added this pull request to the merge queue Oct 26, 2025
Merged via the queue into main with commit 2606a72 Oct 26, 2025
21 checks passed
@marklysze marklysze deleted the feat/function-target branch October 26, 2025 19:10
@codecov
Copy link

codecov bot commented Oct 26, 2025

Codecov Report

❌ Patch coverage is 38.88889% with 55 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
autogen/agentchat/group/targets/function_target.py 38.20% 55 Missing ⚠️
Files with missing lines Coverage Δ
autogen/agentchat/group/__init__.py 100.00% <100.00%> (ø)
autogen/agentchat/group/targets/function_target.py 38.20% <38.20%> (ø)

... and 20 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

8 participants