Message Building¶
After executing tool calls, you need to construct conversation messages so the LLM can process the results and continue the dialogue. ToolRegistry provides three functions for this purpose.
Overview¶
| Function | Level | Input | Output |
|---|---|---|---|
build_assistant_messages() |
Module | list[ToolCall] |
Assistant message with tool call requests |
build_tool_result_messages() |
Module | dict[str, str] |
Tool result messages |
build_tool_call_messages() |
ToolRegistry method |
Raw tool calls + responses | Combined assistant + tool messages |
In most cases, you only need build_tool_call_messages() — the high-level convenience method that handles everything.
build_tool_call_messages()¶
Combines the assistant message (what the LLM decided to call) and the tool results into the messages required for the next LLM turn.
from toolregistry import ToolRegistry
registry = ToolRegistry()
@registry.register
def add(a: float, b: float) -> float:
"""Add two numbers."""
return a + b
# After LLM returns tool_calls and you execute them:
tool_responses = registry.execute_tool_calls(tool_calls)
# Build conversation messages for the next turn
messages = registry.build_tool_call_messages(
tool_calls, tool_responses, api_format="openai-chat"
)
# Extend your conversation history
conversation.extend(messages)
Gemini ID Alignment¶
Gemini does not provide tool call IDs upstream — ToolRegistry generates them internally. build_tool_call_messages() handles this transparently via position-based ID remapping: it aligns the generated IDs in tool_calls with the IDs in tool_responses by position.
Do not reorder tool_calls
You must not reorder the tool_calls list between calling execute_tool_calls() and build_tool_call_messages(). Both methods process tool calls in the same order, and Gemini format relies on this positional alignment. Reordering would cause mismatched function names in the output.
build_assistant_messages()¶
Low-level function that reconstructs just the assistant-side message containing tool call requests.
from toolregistry.types.common import build_assistant_messages, ToolCall
tool_calls = [
ToolCall(id="call_1", name="add", arguments='{"a": 1, "b": 2}')
]
# Returns the assistant message in the target format
assistant_msg = build_assistant_messages(tool_calls, api_format="openai-chat")
Scope and Boundaries¶
This function only handles tool calls. It does not handle:
content— text content returned alongside tool callsthinking/reasoning_content— chain-of-thought from third-party OpenAI-compatible APIsthought_signature— Google's thinking metadata- Any other vendor-specific fields
If the LLM returns mixed content (text + tool calls), you must preserve non-tool-call fields yourself from the original response.
build_tool_result_messages()¶
Low-level function that reconstructs tool result messages from execution responses.
from toolregistry.types.common import build_tool_result_messages
tool_responses = {"call_1": "3.0", "call_2": "7.0"}
# Returns tool result messages in the target format
tool_msgs = build_tool_result_messages(tool_responses, api_format="openai-chat")
Gemini Name Resolution¶
For Gemini format, functionResponse requires the function name (not the call ID). Pass tool_calls to enable name resolution:
tool_msgs = build_tool_result_messages(
tool_responses,
api_format="gemini",
tool_calls=generic_tool_calls, # Required for Gemini
)
Without tool_calls, the function falls back to using the call ID as the name, which produces incorrect Gemini messages.
API Format Values¶
The api_format parameter accepts these values:
| Value | Description |
|---|---|
"openai-chat" |
OpenAI Chat Completion format (default, canonical) |
"openai-responses" |
OpenAI Response API format |
"anthropic" |
Anthropic Messages API format |
"gemini" |
Google Gemini API format |
"rosetta-ir" |
Rosetta IR format (provider-agnostic) |
"open-responses" |
Alias for "openai-responses" |
"openai" |
Deprecated — alias for "openai-chat" |
"openai-chatcompletion" |
Deprecated — alias for "openai-chat" |
"openai-response" |
Deprecated — alias for "openai-responses" |
Using deprecated format names emits a DeprecationWarning.
Risk Summary¶
| Risk | Affected Function | Mitigation |
|---|---|---|
Reordering tool_calls breaks Gemini ID alignment |
build_tool_call_messages() |
Never reorder between execute_tool_calls() and build_tool_call_messages() |
Missing tool_calls param produces wrong Gemini names |
build_tool_result_messages() |
Always pass tool_calls for Gemini format |
| Mixed content (text + tool calls) silently dropped | build_assistant_messages() |
Preserve non-tool-call content from original response yourself |
tool_responses dict order matters for Gemini |
build_tool_call_messages() |
Python 3.7+ dicts preserve insertion order; do not reconstruct the dict |
Deprecated Names¶
The following old names still work but emit DeprecationWarning:
| Old Name | New Name |
|---|---|
recover_assistant_message() |
build_assistant_messages() |
recover_tool_message() |
build_tool_result_messages() |
registry.recover_tool_call_assistant_message() |
registry.build_tool_call_messages() |
registry.get_tools_json() |
registry.get_schemas() |