Skip to content

Provide support for complex function parameters in tool requests #249

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
wants to merge 1 commit into from

Conversation

patvice
Copy link

@patvice patvice commented Jun 16, 2025

What this does

Hey @crmne! This PR aims to have RubyLLM support complex function parameter in tool calls.

Motivation

The RubyLLM Tools Guide mentions support for object and array parameters, but advises against using them to maintain compatibility across language models. This guidance is supported by benchmarks like ComplexFuncBench, which highlight varying support across models.

However, as models are getting better complex parameters seem to be getting used more and more. Some of the MCP example servers already include tools with complex parameters. For example, the Filesystem MCP server defines tools with array-based inputs.

RubyLLM::MCP has allowed support through optional monkey patches that you can apply if you know your tools will include complex function parameters. While functional, this not a great longterm approach. This PR refactors and improves that logic, lifting it from those patches into the core implementation. Regardless of this being beneficial to RubyLLM::MCP, sounds like this could also benefit anyone else who would want to be able to use complex parameters.

Implementation

This PR introduces native support for complex tool parameters by enhancing the Parameters class adding optional parameters to the param method to handle both:

  • Objects — nested parameter structure defined using blocks.
  • Arrays — lists of values with a defined item type.

This enables more expressive and capable tool definitions while remaining compatible with RubyLLM’s execution model.

Examples

Here are some usage examples, as seen in specs:

Object Parameter Example

class WeatherWithObject < RubyLLM::Tool
  description 'Gets current weather for a location'

  param :geo_location, type: :object do
    param :latitude, desc: 'Latitude (e.g., 52.5200)'
    param :longitude, desc: 'Longitude (e.g., 13.4050)'
  end

  def execute(geo_location:)
    "Current weather at #{geo_location[:latitude]}, #{geo_location[:longitude]}: 15°C, Wind: 10 km/h"
  end
end

Array Parameter Example

class WeatherForMultipleCities < RubyLLM::Tool
  description 'Returns the weather for multiple cities that are provided'
  param :cities, type: :array, item_type: :string

  def execute(cities:)
    <<~RESPONSE
      Weather in #{cities.join(', ')}:
      - Ottawa: 19°C, Wind: 5 km/h
      - Berlin: 20°C, Wind: 10 km/h
      - London: 17°C, Wind: 8 km/h
    RESPONSE
  end
end

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Performance improvement

Scope check

  • I read the Contributing Guide
  • This aligns with RubyLLM's focus on LLM communication
  • This isn't application-specific logic that belongs in user code
  • This benefits most users, not just my specific use case

Quality check

  • I ran overcommit --install and all hooks pass
  • I tested my changes thoroughly
  • I updated documentation if needed
  • I didn't modify auto-generated files manually (models.json, aliases.json)

API changes

  • Breaking change
  • New public methods/classes
  • Changed method signatures
  • No API changes

Related issues

No an open issue, but when running the commit hooks the alias.json was changed and did break a spec. Let me know if I need to change this or make other adjustments on this PR.

I also did not update the documentation to reflect these changes. Happy to if this approach is good to be merged.

@tpaulshippy
Copy link
Contributor

tpaulshippy commented Jun 16, 2025

Looks like a duplicate of #124

I've been using a fork with a variant of that one in production for months. This is definitely needed in the library.

@tpaulshippy
Copy link
Contributor

tpaulshippy commented Jun 16, 2025

Latest guidance from Carmine -- #11 (comment)

@patvice
Copy link
Author

patvice commented Jun 16, 2025

Hey @tpaulshippy - thanks for bringing this up! Didn't realize this was an topic already worked on. Happy to close this if this is already something that is already being worked on.

@patvice
Copy link
Author

patvice commented Jun 16, 2025

I'm going to close this for the time being, sounds like there is a solution that is going to get extracted to support complex parameters in tools and i'll wait for that implementation to integrate it back into RubyLLM::MCP

@patvice patvice closed this Jun 16, 2025
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants