HELP:tool event missing "toolCallId" when tool return Command

copilotkit raise error:

[ { “code”: “invalid_type”, “expected”: “string”, “received”: “undefined”, “path”: [ “toolCallId” ], “message”: “Required” }, { “code”: “invalid_type”, “expected”: “string”, “received”: “undefined”, “path”: [ “toolCallName” ], “message”: “Required” } ]

langchain tool:

@tool(description="更新todolist")
def write_todos(
    todos: list[Todo], tool_call_id: Annotated[str, InjectedToolCallId]
) -> Command:
    """Create and manage a structured task list for your current work session."""
    # it it ok if return tool message
    # return ToolMessage(f"Updated todo list to {todos}", tool_call_id=tool_call_id, name="write_todos") 
    return Command(
        update={
            "todos": todos,
            "messages": [
                ToolMessage(f"Updated todo list to {todos}", tool_call_id=tool_call_id, name="write_todos")
            ],
        }
    )

hi @itzhoujun

can you share some more code? What’s the provider?

hi @pawel-twardziak

it is ok if the tool return ToolMessage, and will be error when return Command

my full code:


from os import name
from copilotkit import CopilotKitState
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
from typing import TYPE_CHECKING, Annotated, Literal, cast
from settings import settings
from src.utils import load_prompt
from langgraph.types import Command
from langchain.tools import InjectedToolCallId
from langchain_core.messages import SystemMessage, ToolMessage
from langchain_core.tools import tool
from langchain.agents.middleware.todo import Todo

@tool(description="更新todolist")
def write_todos(
    todos: list[Todo], tool_call_id: Annotated[str, InjectedToolCallId]
) -> Command:
    """Create and manage a structured task list for your current work session."""
    # it is ok if return ToolMessage
    # return ToolMessage(f"Updated todo list to {todos}", tool_call_id=tool_call_id, name="write_todos")
    return Command(
        update={
            "todos": todos,
            "messages": [
                ToolMessage(f"Updated todo list to {todos}", tool_call_id=tool_call_id, name="write_todos")
            ],
        }
    )
    
def create_demo_agent():
    """
    创建 Demo Agent 实例。
    
    这是一个通用的助手 Agent,可以处理各种用户请求和对话。
    
    Returns:
        LangChain Agent 实例
    """
    model = ChatOpenAI(
        model=settings.openai_model,
        base_url=settings.openai_base_url,
        api_key=settings.openai_api_key,
        temperature=0.7,  # 适中的温度以保持友好和灵活性
    )
    system_prompt = load_prompt("demo_agent_system.md")
    
    agent = create_agent(
        model=model,
        system_prompt=system_prompt,
        tools=[write_todos]
    )
    return agent


# 创建默认 agent 实例
agent = create_demo_agent()


copilokit error stack:

I guess that agui protocol require tool_call_id in TOOL_CALL_START but langgraph miss it
ref: Events - Agent User Interaction Protocol

do you use LangGraphAgent from CopilotKit SDK?

yes. I’m using LangGraphAgent as Copilot Runtime

Seems like CopilotKit LangGraphAgent doesn’t handle Command as tool response for now.

Return a normal tool result (ToolMessage or plain string), and move state updates (todos) into a graph node (or a post-tool node) instead of doing state updates inside the tool return.

One robust pattern is:

  • Tool returns a ToolMessage (optionally put structured data in artifact or JSON in content).
  • A “post-tools” node inspects the last ToolMessage and updates state["todos"].
ToolMessage(
            content=tool_output["stdout"],
            artifact=tool_output,
            tool_call_id="call_Jja7J89XsjrOLA5r!MEOW!SL",
        )

This keeps CopilotKit happy because it always sees a standard tool result (ToolMessage) with a valid tool_call_id.

@itzhoujun could you try to patch your local installed copilotkit package? I can provide you with a patch so that we can see whether it works. If it does, I could raise a PR.

And what is the version of copilotkit you are using? The latest?

Thank you very much, my copilotkit version is 1.50.1, can you send the patch package to my mailbox? itzhoujun@gmail.com
I set the ToolMessage.artifact to todos , and then how to update it to the state?

To update it in the state you would have to skip create_agent in favor of a custom graph.
I’ll send the patch here, in the thread.

hi @itzhoujun are you on Langchain Slack?

I’ve just raised a PR fix(runtime): ensure toolCallId and toolCallName in LangGraph agent by pawel-twardziak · Pull Request #2904 · CopilotKit/CopilotKit · GitHub

thanks :growing_heart: