Skip to content

Conversation

@rayrayraykk
Copy link
Member

Description

This PR updates the adapt_agentscope_message_stream logic to properly differentiate between standard plugin tool calls and MCP tool calls.

Key Changes:

  1. Tool Call Handling
    • Added detection for tool_type = "mcp" in elements of type "tool_use".
    • Introduced MessageType.MCP_TOOL_CALL with a corresponding McpCall schema.
    • Preserved regular tool calls as MessageType.PLUGIN_CALL using FunctionCall.
  2. Tool Result Handling
    • When processing "tool_result", determine the output type based on the original tool call message type.
    • Added MessageType.MCP_TOOL_CALL_OUTPUT and McpCallOutput for MCP tool results.
    • Default to MessageType.PLUGIN_CALL_OUTPUT / FunctionCallOutput for non-MCP tool results.
  3. Schema Update
    • Extended McpCallOutput to include an optional name field for tool calls, allowing enriched output metadata.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Refactoring

Component(s) Affected

  • Engine
  • Sandbox
  • Tools
  • Common
  • Documentation
  • Tests
  • CI/CD

Checklist

  • Pre-commit hooks pass
  • Tests pass locally
  • Documentation updated (if needed)
  • Ready for review

Copilot finished reviewing on behalf of rayrayraykk December 5, 2025 10:28
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces support for distinguishing between standard plugin tool calls and MCP (Model Context Protocol) tool calls in the AgentScope message stream adapter. The changes enable proper routing and handling of tool calls based on their type, ensuring MCP tools are processed with the correct message types and schemas.

Key Changes

  • Added MCP tool call detection logic that checks for tool_type="mcp" in tool use elements
  • Introduced MessageType.MCP_TOOL_CALL and MessageType.MCP_TOOL_CALL_OUTPUT for MCP-specific message routing
  • Extended McpCallOutput schema to include an optional name field for consistency with FunctionCallOutput

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/agentscope_runtime/engine/schemas/agent_schemas.py Added optional name field to McpCallOutput schema to match FunctionCallOutput structure
src/agentscope_runtime/adapters/agentscope/stream.py Implemented MCP vs plugin tool call detection, added conditional message type assignment, and introduced lookup logic to match tool results with their original call types
Comments suppressed due to low confidence (1)

src/agentscope_runtime/adapters/agentscope/stream.py:326

  • Critical bug: Tool calls processed in the last=True branch (lines 267-326) are not stored in tool_use_messages_dict. This causes tool results processed later (line 366+) to be unable to look up the original tool call message, resulting in incorrect message type assignment (defaults to PLUGIN_CALL_OUTPUT instead of MCP_TOOL_CALL_OUTPUT for MCP tools).

The else branch (lines 328-364) correctly stores the message at lines 362-364, but this branch is not executed when last=True.

Fix: Add the following after line 326 to store the completed tool call message:

tool_use_messages_dict[call_id] = plugin_call_message

This ensures tool results can correctly identify whether they correspond to MCP or plugin tool calls.

                        if last:
                            plugin_call_message = tool_use_messages_dict.get(
                                call_id,
                            )

                            if plugin_call_message is None:
                                # Only one tool use message yields, we fake
                                #  Build a new tool call message
                                plugin_call_message = Message(
                                    type=msg_type,
                                    role="assistant",
                                )

                                data_delta_content = DataContent(
                                    index=index,
                                    data=fc_cls(
                                        call_id=element.get("id"),
                                        name=element.get("name"),
                                        arguments="",
                                        **fc_kwargs,
                                    ).model_dump(),
                                    delta=True,
                                )

                                plugin_call_message = _update_obj_attrs(
                                    plugin_call_message,
                                    metadata=metadata,
                                    usage=usage,
                                )
                                yield plugin_call_message.in_progress()
                                data_delta_content = (
                                    plugin_call_message.add_delta_content(
                                        new_content=data_delta_content,
                                    )
                                )
                                yield data_delta_content

                            json_str = json.dumps(element.get("input"))
                            data_delta_content = DataContent(
                                index=index,
                                data=fc_cls(
                                    call_id=element.get("id"),
                                    name=element.get("name"),
                                    arguments=json_str,
                                    **fc_kwargs,
                                ).model_dump(),
                                delta=True,
                            )
                            data_delta_content = (
                                plugin_call_message.add_delta_content(
                                    new_content=data_delta_content,
                                )
                            )
                            yield data_delta_content.completed()
                            plugin_call_message = _update_obj_attrs(
                                plugin_call_message,
                                metadata=metadata,
                                usage=usage,
                            )
                            yield plugin_call_message.completed()

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

plugin_call_message = tool_use_messages_dict.get(
call_id,
)
# Check if the tool type
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

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

Incomplete comment. Consider expanding it to clearly explain the logic, for example:

# Determine output message type based on the original tool call type
Suggested change
# Check if the tool type
# Determine the output message type and class to use for the tool result message
# based on the type of the original tool call message.

Copilot uses AI. Check for mistakes.
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.

1 participant