Skip to content

feat: modern function-calling config — validated mode, allowed functions, call ID round-trip - #71

Open
PandelisZ wants to merge 1 commit into
flachesis:mainfrom
PandelisZ:pz/chonkyllm-gemini-modern-fc-pr
Open

feat: modern function-calling config — validated mode, allowed functions, call ID round-trip#71
PandelisZ wants to merge 1 commit into
flachesis:mainfrom
PandelisZ:pz/chonkyllm-gemini-modern-fc-pr

Conversation

@PandelisZ

Copy link
Copy Markdown
Contributor

What this adds

Support for the current Gemini function-calling API contract as documented at https://ai.google.dev/gemini-api/docs/function-calling.

Three gaps existed in the library that made it impossible to use the modern Gemini function-calling surface correctly:

  1. No way to set functionCallingConfig — the model always used AUTO mode implicitly.
  2. No allowedFunctionNames — callers couldn't restrict or force a specific function.
  3. FunctionCall and FunctionResponse had no id field — Gemini attaches a stable ID to each call; without round-tripping it back in the response the API rejects multi-turn and parallel tool-call flows.

Changes

src/tools/model.rs

  • FunctionCallingMode enum with variants Auto / Any / None / Validated, serialising to Gemini's SCREAMING_SNAKE_CASE wire format.
  • FunctionCallingConfig struct: mode + allowed_function_names: Option<Vec<String>>.
  • ToolConfig wrapper that serialises to {"functionCallingConfig": {...}}.
  • FunctionCall.id: Option<String> — preserves the ID Gemini attaches to each call.
  • FunctionResponse.id: Option<String> — must echo back the matching call ID.
  • Builder helpers: FunctionCall::with_id(), FunctionResponse::with_id().

src/generation/builder.rs

  • GenerationRequest gains tool_config: Option<ToolConfig> (serialised as toolConfig).
  • .tool_config(config) builder method.

src/lib.rs

Re-exports ToolConfig, FunctionCallingConfig, FunctionCallingMode from the crate root.

src/tests.rs

New unit tests:

  • test_tool_config_serializes_validated_mode_and_allowed_function_names — verifies the exact JSON wire shape
  • test_function_call_with_id_serialization — round-trips FunctionCall.id
  • test_function_response_with_id_serialization — round-trips FunctionResponse.id
  • Extended test_multi_turn_content_structure to verify Content::function_call_with_thought propagates thoughtSignature to the Part

Usage example

use gemini_rust::{ToolConfig, FunctionCallingConfig, FunctionCallingMode};

// Force the model to call a specific function
let request = GenerationRequest::new(model, contents)
    .tools(vec![my_tool])
  .tool_config(ToolConfig {
        function_calling_config: Some(FunctionCallingConfig {
         mode: FunctionCallingMode::Any,
            allowed_function_names: Some(vec!["get_weather".to_string()]),
        }),
        ..Default::default()
    });

// Round-trip the call ID in the response
let call_id = function_call.id.clone();
let response = FunctionResponse::new("get_weather", result_json)
    .with_id(call_id.unwrap());

All 11 existing + new unit tests pass.

@PandelisZ
PandelisZ force-pushed the pz/chonkyllm-gemini-modern-fc-pr branch from 29d30d7 to 84d5968 Compare June 30, 2026 13:55
- FunctionCallingMode enum: Auto/Any/None/Validated (SCREAMING_SNAKE_CASE wire format)
- FunctionCallingConfig: mode + optional allowed_function_names
- ToolConfig wrapper that serialises to {functionCallingConfig: {...}}
- FunctionCall.id + FunctionResponse.id for stable call/response matching
- tool_config() builder method on GenerationRequest
- Re-export ToolConfig, FunctionCallingConfig, FunctionCallingMode from lib.rs
- Tests: validated mode wire shape, function call ID round-trip,
  function response ID round-trip, Content::function_call helper
@PandelisZ
PandelisZ force-pushed the pz/chonkyllm-gemini-modern-fc-pr branch from 84d5968 to 9c1daed Compare June 30, 2026 13:59
@PandelisZ

Copy link
Copy Markdown
Contributor Author

Hi @flachesis

Thanks for the approval. I saw you merged in main and the CI failed so I've rebased on master and fixed the issues.

So this is now mergable and re-tested.

I hope that helps and feel free to merge when you're happy with it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants