gptel icon indicating copy to clipboard operation
gptel copied to clipboard

Fix tool argument parsing for hyphenated parameter names

Open jwiegley opened this issue 1 month ago • 0 comments

Fixes #924

Summary

This PR fixes a bug where tool arguments with hyphenated names (e.g., "file-path", "file-edits") failed to parse correctly, causing tool functions to receive nil arguments instead of the actual values from the LLM.

Root Cause

When tool argument names contain hyphens, the code was using make-symbol to create JSON schema property keys. This created uninterned symbols whose names include the leading colon (e.g., ":file-path"), which then became JSON keys. When the LLM returned these keys and the JSON was parsed back, there was a mismatch:

  • Schema creation (with make-symbol): JSON key ":file-path" → parsed as keyword ::file-path
  • Value retrieval (with intern): Looks for keyword :file-path
  • Result: Keys don't match, plist-get returns nil, tool function receives nil arguments

Changes

1. Changed make-symbol to intern (3 files)

  • gptel-request.el:1496 - Base gptel--parse-tools implementation
  • gptel-anthropic.el:275 - Anthropic-specific tool schema generation
  • gptel-gemini.el:209 - Gemini-specific tool schema generation

This ensures proper keywords are created that survive JSON round-trip correctly.

2. Improved error handling in gptel-openai.el

  • Replaced silent ignore-errors with condition-case that logs parse failures
  • Provides context: tool name, error message, raw arguments
  • Applied to both streaming (lines 213-221) and non-streaming (lines 284-292) code paths
  • Helps debug future issues while maintaining safe fallback behavior

Why This Fix is Correct

The retrieval code in gptel-request.el:1699 uses intern:

(let ((key (intern (concat ":" (plist-get arg :name)))))
  (plist-get args key))

By using intern during schema creation as well, both sides create the same keyword object, so plist-get succeeds.

Testing

The issue reporter confirmed that:

  • Non-streaming mode works correctly
  • Streaming mode had the bug (now fixed)

This fix ensures both modes work correctly by addressing the root cause.

Impact

  • No breaking changes - The old behavior was broken for hyphenated arg names
  • Consistent across all backends - OpenAI, Anthropic, Gemini all fixed
  • Better debugging - Error logging helps identify future parse issues
  • Backward compatible - Tool specs are created fresh each session

🤖 Generated with Claude Code

jwiegley avatar Oct 05 '25 03:10 jwiegley