connector::params — messages, tools, formats
The request vocabulary. These types are what you hand to
Connector for tool use and structured output — and the message
builders are the ergonomic way to construct [ChatMessage] values.
ChatMessage — the shared conversation format
pub struct ChatMessage {
pub role: String, // "system" | "user" | "assistant" | "tool"
pub content: Option<String>,
pub tool_calls: Option<Vec<ToolCallMsg>>, // assistant-only
pub tool_call_id: Option<String>, // tool-result-only
pub thinking_blocks: Option<Vec<ClaudeThinkingBlock>>, // Claude-only transport detail
}
The format mirrors OpenAI’s Chat Completion message shape, so the model
natively understands tool calls (role: "assistant" + tool_calls) and tool
results (role: "tool" + tool_call_id). Each family translates it onto its
own wire format internally.
The builders
pub fn user_message(content: &str) -> ChatMessage // role: "user"
pub fn system_message(content: &str) -> ChatMessage // role: "system"
pub fn tool_result_message(tool_call_id: &str, content: &str) -> ChatMessage // role: "tool"
pub fn assistant_tool_call_message(tool_calls: Vec<ToolCallMsg>) -> ChatMessage // role: "assistant"
Prefer these over constructing ChatMessage by hand — they set exactly the
fields each role needs (e.g. tool_result_message carries the tool_call_id
that pairs it with the assistant’s call).
Tool-call payloads
pub struct ToolCallMsg {
pub id: String,
#[serde(rename = "type")] pub kind: String, // "function"
pub function: ToolCallFunctionMsg,
pub thought_signature: Option<String>, // Gemini 3.x transport detail
}
pub struct ToolCallFunctionMsg {
pub name: String,
pub arguments: String, // JSON-encoded string
}
The thought_signature field is a Gemini 3.x requirement: when a
thinking model emits a native functionCall, the part travels with a sibling
thoughtSignature that MUST be replayed verbatim when the call is re-sent in
conversation history (the API rejects the replay with HTTP 400 otherwise).
The skip_serializing_if keeps it off every other provider’s wire format.
Why this field exists: Gemini 3.x thinking models use cryptographic signatures to verify that function calls haven’t been tampered with during conversation replay. This is a security/validity requirement specific to Gemini’s architecture. Other providers don’t have this requirement, so we use conditional serialization to keep the field off their wire formats.
Tools: ToolDefinition + ToolFunction
// Example: Define a weather tool with parameters
let tool = ToolDefinition::new(
ToolFunction::new("get_weather")
.with_description("Get the current weather for a city")
.with_parameters(serde_json::json!({
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}))
);
connector.with_tools(vec![tool]);
// Control tool selection with with_tool_choice
connector.with_tool_choice(serde_json::json!("auto")); // let model decide
connector.with_tool_choice(serde_json::json!("none")); // disable tools
connector.with_tool_choice(serde_json::json!(ToolName)); // force specific tool
ToolFunction::new(name)→with_description(...)→with_parameters(...).ToolDefinition::new(function)wraps it withtype: "function".- Hand the
Vec<ToolDefinition>toConnector::with_toolsorset_tools, and control selection withwith_tool_choice("auto","none", or a specific tool name).
ResponseFormat — structured output
pub fn ResponseFormat::json_object() -> Self
connector.with_response_format(ResponseFormat::json_object());
Currently the only variant is json_object (serializes as
{"type": "json_object"}) — request that the model emit valid JSON.
ClaudeThinkingBlock — extended thinking replay
pub struct ClaudeThinkingBlock {
pub thinking: String,
pub signature: String,
}
Captured from a previous Claude response and replayed verbatim at the
start of the assistant message when the turn is re-sent — the Anthropic API
validates the signature cryptographically and rejects modified/missing blocks
with HTTP 400. Only the Claude caller sets this; skip_serializing_if keeps
it off other providers’ wire formats.
Next: output — responses and streams.
Summary
ChatMessageis the shared conversation format mirroring OpenAI’s shape:role(“system” | “user” | “assistant” | “tool”),content,tool_calls(assistant-only), andtool_call_id(tool-result-only).- Builders (
user_message,system_message,tool_result_message,assistant_tool_call_message) construct messages with exactly the fields each role needs. ToolCallMsgcarriesthought_signaturefor Gemini 3.x — required when replaying function calls in conversation history;skip_serializing_ifkeeps this off other providers.- Tools:
ToolDefinition::new(ToolFunction::new(name).with_description(...).with_parameters(...))— wrap withtype: "function"and hand toConnector::with_tools. ResponseFormat::json_object()requests that the model emit valid JSON (currently the only variant).ClaudeThinkingBlockcaptures extended thinking for verbatim replay — Anthropic validates the signature cryptographically and rejects modified/missing blocks.