How to force a Tool call for an agent

Hi,
I have a graph with some basic math tools, for example:

def add(a: int, b: int) -> int:
    """Adds a and b.

    Args:
        a: first int
        b: second int
    """
    return a + b

Say I’m receiving the parameters a and b from an API (so not from the user), how can I make a call to the graph using these parameters.

The full endpoint looks like this:

@app.post("/math_operations")
async def chat_with_math_payload(input: MathWidget) -> dict:
    """test to receive parameters to math operations
    """
    print(f"{input=}")

    payload = {
        "operator": str(input.operator), 
        "first number": str(input.num_1),
        "second number": str(input.num_2), 
    }

    # should match the names of the math_agent tools
    if input.operator == "+":
        operator_name = "add"
    elif input.operator == "-":
        operator_name = "subtract"
    elif input.operator == "*":
        operator_name = "multiply"
    else:
        operator_name = "divide"

    message = AIMessage(
            content="",
            tool_calls=[
                {
                    "name": operator_name,
                    "args": {"a": input.num_1, "b": input.num_2},
                    "id": "tool_call_id",
                    "type": "tool_call",
                }
            ],
        )
    res = graph.invoke({"messages": [message]},)
    return res

But I’m getting the following error:

openai.BadRequestError: Error code: 400 - {'error': {'message': "An assistant message with 'tool_calls' must be followed by tool messages responding to each 'tool_call_id'. The following tool_call_ids did not have response messages: tool_call_id", 'type': 'invalid_request_error', 'param': 'messages', 'code': None}} 

Should I use a unique (or existing) id ?

thanks.

The error occurs because the model expects tool results for each tool call ID but did not receive them.

So your issue is not forcing a tool call, it is sending back the tool result to the model. So execute the tool calls yourself and send back ToolMessages with matching IDs before invoking the model again.

thanks a lot @Jameskanyiri

Below is my quick solution. I imported the tools available by the agent and executed by hand before with the proper args.

That might not work for all tool and it’s clearly a toy example but I see the mechanism.

Appreciate the help !

# ugly hack - FIX ME later
    res = ""

    # should match the names of the math_agent tools
    if input.operator == "+":
        operator_name = "add"
        tmp = add(input.num_1, input.num_2)
    elif input.operator == "-":
        operator_name = "subtract"
        tmp = subtract(input.num_1, input.num_2)
    elif input.operator == "*":
        operator_name = "multiply"
        tmp = multiply(input.num_1, input.num_2)
    else:
        operator_name = "divide"
        tmp = divide(input.num_1, input.num_2)

    print(f"{operator_name=},{input.num_1=}, {input.num_2=}")
    messages = []

    messages.append(AIMessage(
            content="",
            tool_calls=[
                {
                    "name": operator_name,
                    "args": {"a": input.num_1, "b": input.num_2},
                    "id": "call_18TdmTfJMty5bRiltHyZepbV",
                    "type": "tool_call",
                }
            ],
        ))
    messages.append(ToolMessage(content=str(tmp), name='multiply', id='e184c5b3-8527-4457-a53f-fab32ec4f06b', tool_call_id='call_18TdmTfJMty5bRiltHyZepbV'))
    res = graph.invoke({"messages": messages},)