{"record":{"id":"2083cfb5320a8bf0","repo":"microsoft/autogen","slug":"toolcallmessage-is-not-supported-when-message-from-2083cf","errorCode":null,"errorMessage":"ToolCallMessage is not supported when message.From is not the same with agent","messagePattern":"ToolCallMessage is not supported when message\\.From is not the same with agent","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"dotnet/src/AutoGen.OpenAI/Middleware/OpenAIChatRequestMessageConnector.cs","lineNumber":306,"sourceCode":"            ImageMessage image => this.CreateChatMessageImageContentItemFromImageMessage(image),\n            _ => throw new NotImplementedException(),\n        });\n\n        return [new UserChatMessage(items) { ParticipantName = message.From }];\n    }\n\n    private ChatMessageContentPart CreateChatMessageImageContentItemFromImageMessage(ImageMessage message)\n    {\n        return message.Data is null && message.Url is not null\n            ? ChatMessageContentPart.CreateImagePart(new Uri(message.Url))\n            : ChatMessageContentPart.CreateImagePart(message.Data, message.Data?.MediaType);\n    }\n\n    private IEnumerable<ChatMessage> ProcessToolCallMessage(IAgent agent, ToolCallMessage message)\n    {\n        if (message.From is not null && message.From != agent.Name)\n        {\n            throw new ArgumentException(\"ToolCallMessage is not supported when message.From is not the same with agent\");\n        }\n\n        var toolCallParts = message.ToolCalls.Select((tc, i) => ChatToolCall.CreateFunctionToolCall(tc.ToolCallId ?? $\"{tc.FunctionName}_{i}\", tc.FunctionName, BinaryData.FromString(tc.FunctionArguments)));\n        var textContent = message.GetContent() ?? null;\n\n        // Don't set participant name for assistant when it is tool call\n        // fix https://github.com/microsoft/autogen/issues/3437\n        AssistantChatMessage chatRequestMessage;\n\n        if (string.IsNullOrEmpty(textContent) is true)\n        {\n            chatRequestMessage = new AssistantChatMessage(toolCallParts);\n        }\n        else\n        {\n            chatRequestMessage = new AssistantChatMessage(textContent);\n\n            foreach (var toolCallPart in toolCallParts)","sourceCodeStart":288,"sourceCodeEnd":324,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/dotnet/src/AutoGen.OpenAI/Middleware/OpenAIChatRequestMessageConnector.cs#L288-L324","documentation":"ProcessToolCallMessage converts an assistant's function-call message into an AssistantChatMessage with tool-call parts. This is only valid for the agent that issued the calls (tool call results must be attributed to the same assistant in OpenAI's protocol), so a ToolCallMessage authored by a different agent is rejected.","triggerScenarios":"message.From is non-null and differs from agent.Name while the connector's incoming-message switch routes the ToolCallMessage to this handler (the arm requires From == null or From == agent.Name, but this method double-checks and throws for mismatched senders in code paths that reach it directly).","commonSituations":"Group chats where one agent's tool calls land in another agent's context; manually forwarded tool-call messages between agents.","solutions":["Only forward a ToolCallMessage to the agent whose name matches message.From.","Set From to null if the tool call should be attributed to the receiving agent.","Filter other agents' tool calls out of the history: keep only ToolCallResultMessage pairs for the owning agent."],"exampleFix":"// before\nvar toolCallFromOther = new ToolCallMessage(toolCalls, from: \"agent-a\");\nawait agentB.SendAsync(new[] { toolCallFromOther });\n\n// after\nvar toolCallForSelf = new ToolCallMessage(toolCalls, from: agentB.Name);\nawait agentB.SendAsync(new[] { toolCallForSelf });","handlingStrategy":"validation","validationCode":"// Route tool-call messages only to their author\nvar forThisAgent = messages.Where(m => m is not ToolCallMessage tc || tc.From is null || tc.From == agent.Name);","typeGuard":"static bool ToolCallBelongsToAgent(ToolCallMessage tc, string agentName) =>\n    tc.From is null || tc.From == agentName;","tryCatchPattern":"catch (ArgumentException ex) when (ex.Message.Contains(\"ToolCallMessage is not supported\"))\n{\n    logger.LogWarning(\"Dropping foreign tool call from {From}\", foreignFrom);\n    return await agent.SendAsync(messages.Where(m => m is not ToolCallMessage tc || tc.From == agent.Name));\n}","preventionTips":["In multi-agent flows, pair each ToolCallMessage with its owning agent before dispatch.","Set From to null only when the receiving agent is genuinely the author."],"tags":["openai","tool-calls","message-connector","group-chat","autogen"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}