diff --git a/lib/ruby_llm/providers/anthropic/tools.rb b/lib/ruby_llm/providers/anthropic/tools.rb index 3ccfb202..d847a284 100644 --- a/lib/ruby_llm/providers/anthropic/tools.rb +++ b/lib/ruby_llm/providers/anthropic/tools.rb @@ -81,13 +81,22 @@ def parse_tool_calls(content_block) def clean_parameters(parameters) parameters.transform_values do |param| - { - type: param.type, - description: param.description - }.compact + clean_parameter(param) end end + def clean_parameter(param) + { + type: param.type, + description: param.description, + items: param.items && { + type: 'object', + properties: clean_parameters(param.items) + }, + properties: param.properties && clean_parameters(param.properties) + }.compact + end + def required_parameters(parameters) parameters.select { |_, param| param.required }.keys end diff --git a/lib/ruby_llm/providers/gemini/tools.rb b/lib/ruby_llm/providers/gemini/tools.rb index 8cb85b1c..36e63ace 100644 --- a/lib/ruby_llm/providers/gemini/tools.rb +++ b/lib/ruby_llm/providers/gemini/tools.rb @@ -62,16 +62,32 @@ def function_declaration_for(tool) def format_parameters(parameters) { type: 'OBJECT', - properties: parameters.transform_values do |param| - { - type: param_type_for_gemini(param.type), - description: param.description - }.compact - end, + properties: parameters.transform_values { |param| format_parameter(param) }, required: parameters.select { |_, p| p.required }.keys.map(&:to_s) } end + def format_parameter(param) + { + type: param_type_for_gemini(param.type), + description: param.description, + items: param.items && { + type: 'OBJECT', + properties: format_nested_parameters(param.items) + }, + properties: param.properties && format_nested_parameters(param.properties) + }.compact + end + + def format_nested_parameters(parameters) + parameters.transform_values do |param| + { + type: param_type_for_gemini(param.type), + description: param.description + }.compact + end + end + # Convert RubyLLM param types to Gemini API types def param_type_for_gemini(type) case type.to_s.downcase diff --git a/lib/ruby_llm/providers/openai/tools.rb b/lib/ruby_llm/providers/openai/tools.rb index 82bc356d..3769bd8a 100644 --- a/lib/ruby_llm/providers/openai/tools.rb +++ b/lib/ruby_llm/providers/openai/tools.rb @@ -25,7 +25,12 @@ def tool_for(tool) # rubocop:disable Metrics/MethodLength def param_schema(param) { type: param.type, - description: param.description + description: param.description, + items: param.items && { + type: 'object', + properties: param.items.transform_values { |p| param_schema(p) } + }, + properties: param.properties&.transform_values { |p| param_schema(p) } }.compact end diff --git a/lib/ruby_llm/tool.rb b/lib/ruby_llm/tool.rb index fa28ed55..df1642a0 100644 --- a/lib/ruby_llm/tool.rb +++ b/lib/ruby_llm/tool.rb @@ -4,13 +4,15 @@ module RubyLLM # Parameter definition for Tool methods. Specifies type constraints, # descriptions, and whether parameters are required. class Parameter - attr_reader :name, :type, :description, :required + attr_reader :name, :type, :description, :required, :items, :properties - def initialize(name, type: 'string', desc: nil, required: true) + def initialize(name, **options) @name = name - @type = type - @description = desc - @required = required + @type = options.fetch(:type, 'string') + @description = options.fetch(:desc, nil) + @required = options.fetch(:required, true) + @items = options[:items]&.transform_values { |v| Parameter.new(v[:name], **v) } + @properties = options[:properties]&.transform_values { |v| Parameter.new(v[:name], **v) } end end diff --git a/spec/fixtures/vcr_cassettes/chat_array_parameters_with_anthropic_claude-3-5-haiku-20241022_handles_array_parameters_with_object_items.yml b/spec/fixtures/vcr_cassettes/chat_array_parameters_with_anthropic_claude-3-5-haiku-20241022_handles_array_parameters_with_object_items.yml new file mode 100644 index 00000000..5d522452 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_array_parameters_with_anthropic_claude-3-5-haiku-20241022_handles_array_parameters_with_object_items.yml @@ -0,0 +1,60 @@ +--- +http_interactions: +- request: + method: post + uri: https://api.anthropic.com/v1/messages + body: + encoding: UTF-8 + string: '{"model":"claude-3-5-haiku-20241022","messages":[{"role":"user","content":"Add + information about California (capital: Sacramento, pop: 39538223) and Texas + (capital: Austin, pop: 29145505)."}],"temperature":0.7,"stream":false,"max_tokens":8192,"tools":[{"name":"state_manager","description":"Manages + US states information","input_schema":{"type":"object","properties":{"states":{"type":"array","description":"List + of states","items":{"type":"object","properties":{"name":{"type":"string","description":"The + state name"},"capital":{"type":"string","description":"The capital city"},"population":{"type":"number","description":"Population + count"}}}}},"required":["states"]}}]}' + headers: + User-Agent: + - Faraday v2.12.2 + X-Api-Key: + - test + Anthropic-Version: + - '2023-06-01' + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 401 + message: Unauthorized + headers: + Date: + - Mon, 14 Apr 2025 21:08:25 GMT + Content-Type: + - application/json + Content-Length: + - '86' + Connection: + - keep-alive + X-Should-Retry: + - 'false' + Request-Id: + - "" + Via: + - 1.1 google + Cf-Cache-Status: + - DYNAMIC + X-Robots-Tag: + - none + Server: + - cloudflare + Cf-Ray: + - "" + body: + encoding: UTF-8 + string: '{"type":"error","error":{"type":"authentication_error","message":"invalid + x-api-key"}}' + recorded_at: Mon, 14 Apr 2025 21:09:07 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_array_parameters_with_bedrock_anthropic_claude-3-5-haiku-20241022-v1_0_handles_array_parameters_with_object_items.yml b/spec/fixtures/vcr_cassettes/chat_array_parameters_with_bedrock_anthropic_claude-3-5-haiku-20241022-v1_0_handles_array_parameters_with_object_items.yml new file mode 100644 index 00000000..b5c2de31 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_array_parameters_with_bedrock_anthropic_claude-3-5-haiku-20241022-v1_0_handles_array_parameters_with_object_items.yml @@ -0,0 +1,129 @@ +--- +http_interactions: +- request: + method: post + uri: https://bedrock-runtime..amazonaws.com/model/anthropic.claude-3-5-haiku-20241022-v1:0/invoke + body: + encoding: UTF-8 + string: '{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":"Add + information about California (capital: Sacramento, pop: 39538223) and Texas + (capital: Austin, pop: 29145505). Make sure to return all the information + in the final output. Do not add commas to the population numbers."}],"temperature":0.7,"max_tokens":4096,"tools":[{"name":"state_manager","description":"Manages + US states information","input_schema":{"type":"object","properties":{"states":{"type":"array","description":"List + of states","items":{"type":"object","properties":{"name":{"type":"string","description":"The + state name"},"capital":{"type":"string","description":"The capital city"},"population":{"type":"number","description":"Population + count"}}}}},"required":["states"]}}]}' + headers: + User-Agent: + - Faraday v2.12.2 + Host: + - bedrock-runtime..amazonaws.com + X-Amz-Date: + - 20250414T211556Z + X-Amz-Security-Token: + - "" + X-Amz-Content-Sha256: + - 7e4b21d6cf065b6dc4368d96391d34051b6301218526854ae8052fcf46afd2ae + Authorization: + - AWS4-HMAC-SHA256 Credential=/20250414//bedrock/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=a332b9db6d9b43ff184e9daff338de64ad01bf51c48b53579b42e05ede0db345 + Content-Type: + - application/json + Accept: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 14 Apr 2025 21:15:16 GMT + Content-Type: + - application/json + Content-Length: + - '629' + Connection: + - keep-alive + X-Amzn-Requestid: + - 61c59f85-06c1-41c0-978d-23bce85bf8b5 + X-Amzn-Bedrock-Invocation-Latency: + - '2462' + X-Amzn-Bedrock-Output-Token-Count: + - '137' + X-Amzn-Bedrock-Input-Token-Count: + - '450' + body: + encoding: UTF-8 + string: '{"id":"msg_bdrk_016xbQ39Gp6TChms9Bjsq2aE","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[{"type":"text","text":"I''ll + help you add the information about California and Texas using the state_manager + tool."},{"type":"tool_use","id":"toolu_bdrk_01EjxynnEzfb8BT2fPe4aSZF","name":"state_manager","input":{"states":[{"name":"California","capital":"Sacramento","population":39538223},{"name":"Texas","capital":"Austin","population":29145505}]}}],"stop_reason":"tool_use","stop_sequence":null,"usage":{"input_tokens":450,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":137}}' + recorded_at: Mon, 14 Apr 2025 21:15:58 GMT +- request: + method: post + uri: https://bedrock-runtime..amazonaws.com/model/anthropic.claude-3-5-haiku-20241022-v1:0/invoke + body: + encoding: UTF-8 + string: '{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":"Add + information about California (capital: Sacramento, pop: 39538223) and Texas + (capital: Austin, pop: 29145505). Make sure to return all the information + in the final output. Do not add commas to the population numbers."},{"role":"assistant","content":[{"type":"text","text":"I''ll + help you add the information about California and Texas using the state_manager + tool."},{"type":"tool_use","id":"toolu_bdrk_01EjxynnEzfb8BT2fPe4aSZF","name":"state_manager","input":{"states":[{"name":"California","capital":"Sacramento","population":39538223},{"name":"Texas","capital":"Austin","population":29145505}]}}]},{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_bdrk_01EjxynnEzfb8BT2fPe4aSZF","content":"California: + Capital is Sacramento (pop: 39538223)\nTexas: Capital is Austin (pop: 29145505)"}]}],"temperature":0.7,"max_tokens":4096,"tools":[{"name":"state_manager","description":"Manages + US states information","input_schema":{"type":"object","properties":{"states":{"type":"array","description":"List + of states","items":{"type":"object","properties":{"name":{"type":"string","description":"The + state name"},"capital":{"type":"string","description":"The capital city"},"population":{"type":"number","description":"Population + count"}}}}},"required":["states"]}}]}' + headers: + User-Agent: + - Faraday v2.12.2 + Host: + - bedrock-runtime..amazonaws.com + X-Amz-Date: + - 20250414T211558Z + X-Amz-Security-Token: + - "" + X-Amz-Content-Sha256: + - 68c0f2dfe2b0a596d0b31497c23b3443f50aa292e4a408e4c61059e15de752f3 + Authorization: + - AWS4-HMAC-SHA256 Credential=/20250414//bedrock/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=5db5594ee8b8fb8d5a394267d15c8e6c9185680a0939c84a6bfa9c1dd4edaf1e + Content-Type: + - application/json + Accept: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 14 Apr 2025 21:15:20 GMT + Content-Type: + - application/json + Content-Length: + - '567' + Connection: + - keep-alive + X-Amzn-Requestid: + - 3e033fcf-0d5a-49f7-8017-17aa94aa0ad0 + X-Amzn-Bedrock-Invocation-Latency: + - '3399' + X-Amzn-Bedrock-Output-Token-Count: + - '77' + X-Amzn-Bedrock-Input-Token-Count: + - '600' + body: + encoding: UTF-8 + string: '{"id":"msg_bdrk_015rg1zK3aSpbT9KtB3tgPLf","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[{"type":"text","text":"I''ve + added the information for both California and Texas to the state manager. + The output confirms the details:\n- California: Capital is Sacramento, with + a population of 39,538,223\n- Texas: Capital is Austin, with a population + of 29,145,505\n\nIs there anything else you would like me to do with this + state information?"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":600,"output_tokens":77}}' + recorded_at: Mon, 14 Apr 2025 21:16:02 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_array_parameters_with_deepseek_deepseek-chat_handles_array_parameters_with_object_items.yml b/spec/fixtures/vcr_cassettes/chat_array_parameters_with_deepseek_deepseek-chat_handles_array_parameters_with_object_items.yml new file mode 100644 index 00000000..3a0d4084 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_array_parameters_with_deepseek_deepseek-chat_handles_array_parameters_with_object_items.yml @@ -0,0 +1,61 @@ +--- +http_interactions: +- request: + method: post + uri: https://api.deepseek.com/chat/completions + body: + encoding: UTF-8 + string: '{"model":"deepseek-chat","messages":[{"role":"user","content":"Add + information about California (capital: Sacramento, pop: 39538223) and Texas + (capital: Austin, pop: 29145505)."}],"temperature":0.7,"stream":false,"tools":[{"type":"function","function":{"name":"state_manager","description":"Manages + US states information","parameters":{"type":"object","properties":{"states":{"type":"array","description":"List + of states","items":{"type":"object","properties":{"name":{"type":"string","description":"The + state name"},"capital":{"type":"string","description":"The capital city"},"population":{"type":"number","description":"Population + count"}}}}},"required":["states"]}}}],"tool_choice":"auto"}' + headers: + User-Agent: + - Faraday v2.12.2 + Authorization: + - Bearer test + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 401 + message: Unauthorized + headers: + Date: + - Mon, 14 Apr 2025 21:08:31 GMT + Content-Type: + - application/json + Content-Length: + - '149' + Connection: + - keep-alive + Vary: + - origin, access-control-request-method, access-control-request-headers + Access-Control-Allow-Credentials: + - 'true' + X-Ds-Trace-Id: + - f561e72cb0f2899eff06e3264398bacc + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + Cf-Cache-Status: + - DYNAMIC + Set-Cookie: + - "" + Server: + - cloudflare + Cf-Ray: + - "" + body: + encoding: UTF-8 + string: '{"error":{"message":"Authentication Fails, Your api key: test is invalid","type":"authentication_error","param":null,"code":"invalid_request_error"}}' + recorded_at: Mon, 14 Apr 2025 21:09:13 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_array_parameters_with_gemini_gemini-2_0-flash_handles_array_parameters_with_object_items.yml b/spec/fixtures/vcr_cassettes/chat_array_parameters_with_gemini_gemini-2_0-flash_handles_array_parameters_with_object_items.yml new file mode 100644 index 00000000..51ebd065 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_array_parameters_with_gemini_gemini-2_0-flash_handles_array_parameters_with_object_items.yml @@ -0,0 +1,196 @@ +--- +http_interactions: +- request: + method: post + uri: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent + body: + encoding: UTF-8 + string: '{"contents":[{"role":"user","parts":[{"text":"Add information about + California (capital: Sacramento, pop: 39538223) and Texas (capital: Austin, + pop: 29145505). Make sure to return all the information in the final output."}]}],"generationConfig":{"temperature":0.7},"tools":[{"functionDeclarations":[{"name":"state_manager","description":"Manages + US states information","parameters":{"type":"OBJECT","properties":{"states":{"type":"ARRAY","description":"List + of states","items":{"type":"OBJECT","properties":{"name":{"type":"STRING","description":"The + state name"},"capital":{"type":"STRING","description":"The capital city"},"population":{"type":"NUMBER","description":"Population + count"}}}}},"required":["states"]}}]}]}' + headers: + User-Agent: + - Faraday v2.12.2 + X-Goog-Api-Key: + - "" + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json; charset=UTF-8 + Vary: + - Origin + - Referer + - X-Origin + Date: + - Mon, 14 Apr 2025 21:14:08 GMT + Server: + - scaffolding on HTTPServer2 + X-Xss-Protection: + - '0' + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff + Server-Timing: + - gfet4t7; dur=727 + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + Transfer-Encoding: + - chunked + body: + encoding: ASCII-8BIT + string: | + { + "candidates": [ + { + "content": { + "parts": [ + { + "functionCall": { + "name": "state_manager", + "args": { + "states": [ + { + "population": 39538223, + "capital": "Sacramento", + "name": "California" + }, + { + "name": "Texas", + "population": 29145505, + "capital": "Austin" + } + ] + } + } + } + ], + "role": "model" + }, + "finishReason": "STOP", + "avgLogprobs": -0.00093624428180711608 + } + ], + "usageMetadata": { + "promptTokenCount": 76, + "candidatesTokenCount": 14, + "totalTokenCount": 90, + "promptTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 76 + } + ], + "candidatesTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 14 + } + ] + }, + "modelVersion": "gemini-2.0-flash" + } + recorded_at: Mon, 14 Apr 2025 21:14:50 GMT +- request: + method: post + uri: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent + body: + encoding: UTF-8 + string: '{"contents":[{"role":"user","parts":[{"text":"Add information about + California (capital: Sacramento, pop: 39538223) and Texas (capital: Austin, + pop: 29145505). Make sure to return all the information in the final output."}]},{"role":"model","parts":[{"functionCall":{"name":"state_manager","args":{"states":[{"population":39538223,"capital":"Sacramento","name":"California"},{"name":"Texas","population":29145505,"capital":"Austin"}]}}}]},{"role":"user","parts":[{"functionResponse":{"name":"18770573-25f8-41e1-b047-cb8ef0a3f172","response":{"name":"18770573-25f8-41e1-b047-cb8ef0a3f172","content":"California: + Capital is Sacramento (pop: 39538223)\nTexas: Capital is Austin (pop: 29145505)"}}}]}],"generationConfig":{"temperature":0.7},"tools":[{"functionDeclarations":[{"name":"state_manager","description":"Manages + US states information","parameters":{"type":"OBJECT","properties":{"states":{"type":"ARRAY","description":"List + of states","items":{"type":"OBJECT","properties":{"name":{"type":"STRING","description":"The + state name"},"capital":{"type":"STRING","description":"The capital city"},"population":{"type":"NUMBER","description":"Population + count"}}}}},"required":["states"]}}]}]}' + headers: + User-Agent: + - Faraday v2.12.2 + X-Goog-Api-Key: + - "" + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json; charset=UTF-8 + Vary: + - Origin + - Referer + - X-Origin + Date: + - Mon, 14 Apr 2025 21:14:09 GMT + Server: + - scaffolding on HTTPServer2 + X-Xss-Protection: + - '0' + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff + Server-Timing: + - gfet4t7; dur=597 + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + Transfer-Encoding: + - chunked + body: + encoding: ASCII-8BIT + string: | + { + "candidates": [ + { + "content": { + "parts": [ + { + "text": "California: Capital is Sacramento (pop: 39538223)\nTexas: Capital is Austin (pop: 29145505)\n" + } + ], + "role": "model" + }, + "finishReason": "STOP", + "avgLogprobs": -0.00251712336351997 + } + ], + "usageMetadata": { + "promptTokenCount": 197, + "candidatesTokenCount": 38, + "totalTokenCount": 235, + "promptTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 197 + } + ], + "candidatesTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 38 + } + ] + }, + "modelVersion": "gemini-2.0-flash" + } + recorded_at: Mon, 14 Apr 2025 21:14:51 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_array_parameters_with_openai_gpt-4o-mini_handles_array_parameters_with_object_items.yml b/spec/fixtures/vcr_cassettes/chat_array_parameters_with_openai_gpt-4o-mini_handles_array_parameters_with_object_items.yml new file mode 100644 index 00000000..75d1e280 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_array_parameters_with_openai_gpt-4o-mini_handles_array_parameters_with_object_items.yml @@ -0,0 +1,251 @@ +--- +http_interactions: +- request: + method: post + uri: https://api.openai.com/v1/chat/completions + body: + encoding: UTF-8 + string: '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Add information + about California (capital: Sacramento, pop: 39538223) and Texas (capital: + Austin, pop: 29145505). Make sure to return all the information in the final + output. "}],"temperature":0.7,"stream":false,"tools":[{"type":"function","function":{"name":"state_manager","description":"Manages + US states information","parameters":{"type":"object","properties":{"states":{"type":"array","description":"List + of states","items":{"type":"object","properties":{"name":{"type":"string","description":"The + state name"},"capital":{"type":"string","description":"The capital city"},"population":{"type":"number","description":"Population + count"}}}}},"required":["states"]}}}],"tool_choice":"auto"}' + headers: + User-Agent: + - Faraday v2.12.2 + Authorization: + - Bearer + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 14 Apr 2025 21:26:53 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Access-Control-Expose-Headers: + - X-Request-ID + Openai-Organization: + - "" + Openai-Processing-Ms: + - '1014' + Openai-Version: + - '2020-10-01' + X-Ratelimit-Limit-Requests: + - '30000' + X-Ratelimit-Limit-Tokens: + - '150000000' + X-Ratelimit-Remaining-Requests: + - '29999' + X-Ratelimit-Remaining-Tokens: + - '149999953' + X-Ratelimit-Reset-Requests: + - 2ms + X-Ratelimit-Reset-Tokens: + - 0s + X-Request-Id: + - "" + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Set-Cookie: + - "" + - "" + X-Content-Type-Options: + - nosniff + Server: + - cloudflare + Cf-Ray: + - "" + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: | + { + "id": "chatcmpl-BMLcKjVwX1fSIG2fB8XIsURDiH4uD", + "object": "chat.completion", + "created": 1744666012, + "model": "gpt-4o-mini-2024-07-18", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": null, + "tool_calls": [ + { + "id": "call_Oluav8irb6cZvRSQwS8OuWrZ", + "type": "function", + "function": { + "name": "state_manager", + "arguments": "{\"states\": [{\"name\": \"California\", \"capital\": \"Sacramento\", \"population\": 39538223}]}" + } + }, + { + "id": "call_daUVINMbQfHdcJOQtwWznVqq", + "type": "function", + "function": { + "name": "state_manager", + "arguments": "{\"states\": [{\"name\": \"Texas\", \"capital\": \"Austin\", \"population\": 29145505}]}" + } + } + ], + "refusal": null, + "annotations": [] + }, + "logprobs": null, + "finish_reason": "tool_calls" + } + ], + "usage": { + "prompt_tokens": 117, + "completion_tokens": 74, + "total_tokens": 191, + "prompt_tokens_details": { + "cached_tokens": 0, + "audio_tokens": 0 + }, + "completion_tokens_details": { + "reasoning_tokens": 0, + "audio_tokens": 0, + "accepted_prediction_tokens": 0, + "rejected_prediction_tokens": 0 + } + }, + "service_tier": "default", + "system_fingerprint": "fp_64e0ac9789" + } + recorded_at: Mon, 14 Apr 2025 21:27:35 GMT +- request: + method: post + uri: https://api.openai.com/v1/chat/completions + body: + encoding: UTF-8 + string: '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Add information + about California (capital: Sacramento, pop: 39538223) and Texas (capital: + Austin, pop: 29145505). Make sure to return all the information in the final + output. "},{"role":"assistant","tool_calls":[{"id":"call_Oluav8irb6cZvRSQwS8OuWrZ","type":"function","function":{"name":"state_manager","arguments":"{\"states\":[{\"name\":\"California\",\"capital\":\"Sacramento\",\"population\":39538223}]}"}},{"id":"call_daUVINMbQfHdcJOQtwWznVqq","type":"function","function":{"name":"state_manager","arguments":"{\"states\":[{\"name\":\"Texas\",\"capital\":\"Austin\",\"population\":29145505}]}"}}]},{"role":"tool","content":"California: + Capital is Sacramento (pop: 39538223)","tool_call_id":"call_Oluav8irb6cZvRSQwS8OuWrZ"},{"role":"tool","content":"Texas: + Capital is Austin (pop: 29145505)","tool_call_id":"call_daUVINMbQfHdcJOQtwWznVqq"}],"temperature":0.7,"stream":false,"tools":[{"type":"function","function":{"name":"state_manager","description":"Manages + US states information","parameters":{"type":"object","properties":{"states":{"type":"array","description":"List + of states","items":{"type":"object","properties":{"name":{"type":"string","description":"The + state name"},"capital":{"type":"string","description":"The capital city"},"population":{"type":"number","description":"Population + count"}}}}},"required":["states"]}}}],"tool_choice":"auto"}' + headers: + User-Agent: + - Faraday v2.12.2 + Authorization: + - Bearer + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 14 Apr 2025 21:26:54 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Access-Control-Expose-Headers: + - X-Request-ID + Openai-Organization: + - "" + Openai-Processing-Ms: + - '799' + Openai-Version: + - '2020-10-01' + X-Ratelimit-Limit-Requests: + - '30000' + X-Ratelimit-Limit-Tokens: + - '150000000' + X-Ratelimit-Remaining-Requests: + - '29999' + X-Ratelimit-Remaining-Tokens: + - '149999928' + X-Ratelimit-Reset-Requests: + - 2ms + X-Ratelimit-Reset-Tokens: + - 0s + X-Request-Id: + - "" + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Set-Cookie: + - "" + - "" + X-Content-Type-Options: + - nosniff + Server: + - cloudflare + Cf-Ray: + - "" + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: | + { + "id": "chatcmpl-BMLcLBh88FzAMA90ukeBVxzeK6WUL", + "object": "chat.completion", + "created": 1744666013, + "model": "gpt-4o-mini-2024-07-18", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Here is the information added:\n\n- **California**: Capital is Sacramento (Population: 39,538,223)\n- **Texas**: Capital is Austin (Population: 29,145,505)", + "refusal": null, + "annotations": [] + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 229, + "completion_tokens": 44, + "total_tokens": 273, + "prompt_tokens_details": { + "cached_tokens": 0, + "audio_tokens": 0 + }, + "completion_tokens_details": { + "reasoning_tokens": 0, + "audio_tokens": 0, + "accepted_prediction_tokens": 0, + "rejected_prediction_tokens": 0 + } + }, + "service_tier": "default", + "system_fingerprint": "fp_64e0ac9789" + } + recorded_at: Mon, 14 Apr 2025 21:27:36 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_anthropic_claude-3-5-haiku-20241022_handles_nested_object_parameters.yml b/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_anthropic_claude-3-5-haiku-20241022_handles_nested_object_parameters.yml new file mode 100644 index 00000000..023e4c4c --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_anthropic_claude-3-5-haiku-20241022_handles_nested_object_parameters.yml @@ -0,0 +1,59 @@ +--- +http_interactions: +- request: + method: post + uri: https://api.anthropic.com/v1/messages + body: + encoding: UTF-8 + string: '{"model":"claude-3-5-haiku-20241022","messages":[{"role":"user","content":"Add + John Doe to the address book at 123 Main St, Springfield 12345"}],"temperature":0.7,"stream":false,"max_tokens":8192,"tools":[{"name":"address_book","description":"Manages + address book entries","input_schema":{"type":"object","properties":{"contact":{"type":"object","description":"Contact + information","properties":{"name":{"type":"string","description":"Full name"},"address":{"type":"object","description":"Address + details","properties":{"street":{"type":"string","description":"Street address"},"city":{"type":"string","description":"City + name"},"zip":{"type":"string","description":"ZIP/Postal code"}}}}}},"required":["contact"]}}]}' + headers: + User-Agent: + - Faraday v2.12.2 + X-Api-Key: + - test + Anthropic-Version: + - '2023-06-01' + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 401 + message: Unauthorized + headers: + Date: + - Mon, 14 Apr 2025 21:09:04 GMT + Content-Type: + - application/json + Content-Length: + - '86' + Connection: + - keep-alive + X-Should-Retry: + - 'false' + Request-Id: + - "" + Via: + - 1.1 google + Cf-Cache-Status: + - DYNAMIC + X-Robots-Tag: + - none + Server: + - cloudflare + Cf-Ray: + - "" + body: + encoding: UTF-8 + string: '{"type":"error","error":{"type":"authentication_error","message":"invalid + x-api-key"}}' + recorded_at: Mon, 14 Apr 2025 21:09:46 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_bedrock_anthropic_claude-3-5-haiku-20241022-v1_0_handles_nested_object_parameters.yml b/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_bedrock_anthropic_claude-3-5-haiku-20241022-v1_0_handles_nested_object_parameters.yml new file mode 100644 index 00000000..364e28c8 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_bedrock_anthropic_claude-3-5-haiku-20241022-v1_0_handles_nested_object_parameters.yml @@ -0,0 +1,126 @@ +--- +http_interactions: +- request: + method: post + uri: https://bedrock-runtime..amazonaws.com/model/anthropic.claude-3-5-haiku-20241022-v1:0/invoke + body: + encoding: UTF-8 + string: '{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":"Add + John Doe to the address book at 123 Main St, Springfield 12345"}],"temperature":0.7,"max_tokens":4096,"tools":[{"name":"address_book","description":"Manages + address book entries","input_schema":{"type":"object","properties":{"contact":{"type":"object","description":"Contact + information","properties":{"name":{"type":"string","description":"Full name"},"address":{"type":"object","description":"Address + details","properties":{"street":{"type":"string","description":"Street address"},"city":{"type":"string","description":"City + name"},"zip":{"type":"string","description":"ZIP/Postal code"}}}}}},"required":["contact"]}}]}' + headers: + User-Agent: + - Faraday v2.12.2 + Host: + - bedrock-runtime..amazonaws.com + X-Amz-Date: + - 20250414T210946Z + X-Amz-Security-Token: + - "" + X-Amz-Content-Sha256: + - 20bc836937097802a104c9ae3c86ad4f5f74750c68d26050182b4720a23eba7b + Authorization: + - AWS4-HMAC-SHA256 Credential=/20250414//bedrock/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=a5df834cb610f068397cb62fe151c75110efa170b1fe4a42ce795d46a3705e61 + Content-Type: + - application/json + Accept: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 14 Apr 2025 21:09:06 GMT + Content-Type: + - application/json + Content-Length: + - '655' + Connection: + - keep-alive + X-Amzn-Requestid: + - 5e77035b-9fb7-4f9a-a5d7-31d91b879490 + X-Amzn-Bedrock-Invocation-Latency: + - '2425' + X-Amzn-Bedrock-Output-Token-Count: + - '140' + X-Amzn-Bedrock-Input-Token-Count: + - '444' + body: + encoding: UTF-8 + string: '{"id":"msg_bdrk_01Ko7AtCEYwWGeWASuiHmuSq","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[{"type":"text","text":"I''ll + help you add John Doe to the address book using the `address_book` function. + I''ll parse the address details you provided and create a contact entry."},{"type":"tool_use","id":"toolu_bdrk_016zu287CPSP7fc7whbMpAZm","name":"address_book","input":{"contact":{"name":"John + Doe","address":{"street":"123 Main St","city":"Springfield","zip":"12345"}}}}],"stop_reason":"tool_use","stop_sequence":null,"usage":{"input_tokens":444,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":140}}' + recorded_at: Mon, 14 Apr 2025 21:09:48 GMT +- request: + method: post + uri: https://bedrock-runtime..amazonaws.com/model/anthropic.claude-3-5-haiku-20241022-v1:0/invoke + body: + encoding: UTF-8 + string: '{"anthropic_version":"bedrock-2023-05-31","messages":[{"role":"user","content":"Add + John Doe to the address book at 123 Main St, Springfield 12345"},{"role":"assistant","content":[{"type":"text","text":"I''ll + help you add John Doe to the address book using the `address_book` function. + I''ll parse the address details you provided and create a contact entry."},{"type":"tool_use","id":"toolu_bdrk_016zu287CPSP7fc7whbMpAZm","name":"address_book","input":{"contact":{"name":"John + Doe","address":{"street":"123 Main St","city":"Springfield","zip":"12345"}}}}]},{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_bdrk_016zu287CPSP7fc7whbMpAZm","content":"Completed + contact: John Doe at 123 Main St, Springfield 12345"}]}],"temperature":0.7,"max_tokens":4096,"tools":[{"name":"address_book","description":"Manages + address book entries","input_schema":{"type":"object","properties":{"contact":{"type":"object","description":"Contact + information","properties":{"name":{"type":"string","description":"Full name"},"address":{"type":"object","description":"Address + details","properties":{"street":{"type":"string","description":"Street address"},"city":{"type":"string","description":"City + name"},"zip":{"type":"string","description":"ZIP/Postal code"}}}}}},"required":["contact"]}}]}' + headers: + User-Agent: + - Faraday v2.12.2 + Host: + - bedrock-runtime..amazonaws.com + X-Amz-Date: + - 20250414T210948Z + X-Amz-Security-Token: + - "" + X-Amz-Content-Sha256: + - 2826a3b34811574291899c05638d0d60f20dc746eeb29235ced9f7fc1e09ed94 + Authorization: + - AWS4-HMAC-SHA256 Credential=/20250414//bedrock/aws4_request, + SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=7475450c7cd8c01a696d678566c9b4677f18f452d9925d4f28be69d5d4cbf934 + Content-Type: + - application/json + Accept: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 14 Apr 2025 21:09:08 GMT + Content-Type: + - application/json + Content-Length: + - '542' + Connection: + - keep-alive + X-Amzn-Requestid: + - fb2c2301-2178-4b18-8f3f-2702d4fc5ea7 + X-Amzn-Bedrock-Invocation-Latency: + - '1306' + X-Amzn-Bedrock-Output-Token-Count: + - '66' + X-Amzn-Bedrock-Input-Token-Count: + - '594' + body: + encoding: UTF-8 + string: '{"id":"msg_bdrk_01EB71hKVYvuo5J2f9B2rpXm","type":"message","role":"assistant","model":"claude-3-5-haiku-20241022","content":[{"type":"text","text":"I''ve + added John Doe to the address book with the following details:\n- Name: John + Doe\n- Street: 123 Main St\n- City: Springfield\n- ZIP Code: 12345\n\nThe + contact has been successfully saved. Is there anything else I can help you + with?"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":594,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":66}}' + recorded_at: Mon, 14 Apr 2025 21:09:50 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_deepseek_deepseek-chat_handles_nested_object_parameters.yml b/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_deepseek_deepseek-chat_handles_nested_object_parameters.yml new file mode 100644 index 00000000..0dbfecef --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_deepseek_deepseek-chat_handles_nested_object_parameters.yml @@ -0,0 +1,60 @@ +--- +http_interactions: +- request: + method: post + uri: https://api.deepseek.com/chat/completions + body: + encoding: UTF-8 + string: '{"model":"deepseek-chat","messages":[{"role":"user","content":"Add + John Doe to the address book at 123 Main St, Springfield 12345"}],"temperature":0.7,"stream":false,"tools":[{"type":"function","function":{"name":"address_book","description":"Manages + address book entries","parameters":{"type":"object","properties":{"contact":{"type":"object","description":"Contact + information","properties":{"name":{"type":"string","description":"Full name"},"address":{"type":"object","description":"Address + details","properties":{"street":{"type":"string","description":"Street address"},"city":{"type":"string","description":"City + name"},"zip":{"type":"string","description":"ZIP/Postal code"}}}}}},"required":["contact"]}}}],"tool_choice":"auto"}' + headers: + User-Agent: + - Faraday v2.12.2 + Authorization: + - Bearer test + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 401 + message: Unauthorized + headers: + Date: + - Mon, 14 Apr 2025 21:09:10 GMT + Content-Type: + - application/json + Content-Length: + - '149' + Connection: + - keep-alive + Vary: + - origin, access-control-request-method, access-control-request-headers + Access-Control-Allow-Credentials: + - 'true' + X-Ds-Trace-Id: + - 1637f04e185f05aae40972a845805bf2 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + Cf-Cache-Status: + - DYNAMIC + Set-Cookie: + - "" + Server: + - cloudflare + Cf-Ray: + - "" + body: + encoding: UTF-8 + string: '{"error":{"message":"Authentication Fails, Your api key: test is invalid","type":"authentication_error","param":null,"code":"invalid_request_error"}}' + recorded_at: Mon, 14 Apr 2025 21:09:52 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_gemini_gemini-2_0-flash_handles_nested_object_parameters.yml b/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_gemini_gemini-2_0-flash_handles_nested_object_parameters.yml new file mode 100644 index 00000000..8e57884b --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_gemini_gemini-2_0-flash_handles_nested_object_parameters.yml @@ -0,0 +1,189 @@ +--- +http_interactions: +- request: + method: post + uri: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent + body: + encoding: UTF-8 + string: '{"contents":[{"role":"user","parts":[{"text":"Add John Doe to the address + book at 123 Main St, Springfield 12345"}]}],"generationConfig":{"temperature":0.7},"tools":[{"functionDeclarations":[{"name":"address_book","description":"Manages + address book entries","parameters":{"type":"OBJECT","properties":{"contact":{"type":"OBJECT","description":"Contact + information","properties":{"name":{"type":"STRING","description":"Full name"},"address":{"type":"OBJECT","description":"Address + details"}}}},"required":["contact"]}}]}]}' + headers: + User-Agent: + - Faraday v2.12.2 + X-Goog-Api-Key: + - "" + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json; charset=UTF-8 + Vary: + - Origin + - Referer + - X-Origin + Date: + - Mon, 14 Apr 2025 21:09:09 GMT + Server: + - scaffolding on HTTPServer2 + X-Xss-Protection: + - '0' + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff + Server-Timing: + - gfet4t7; dur=701 + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + Transfer-Encoding: + - chunked + body: + encoding: ASCII-8BIT + string: | + { + "candidates": [ + { + "content": { + "parts": [ + { + "functionCall": { + "name": "address_book", + "args": { + "contact": { + "address": { + "zip": "12345", + "city": "Springfield", + "street": "123 Main St" + }, + "name": "John Doe" + } + } + } + } + ], + "role": "model" + }, + "finishReason": "STOP", + "avgLogprobs": -0.048165299675681374 + } + ], + "usageMetadata": { + "promptTokenCount": 40, + "candidatesTokenCount": 22, + "totalTokenCount": 62, + "promptTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 40 + } + ], + "candidatesTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 22 + } + ] + }, + "modelVersion": "gemini-2.0-flash" + } + recorded_at: Mon, 14 Apr 2025 21:09:51 GMT +- request: + method: post + uri: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent + body: + encoding: UTF-8 + string: '{"contents":[{"role":"user","parts":[{"text":"Add John Doe to the address + book at 123 Main St, Springfield 12345"}]},{"role":"model","parts":[{"functionCall":{"name":"address_book","args":{"contact":{"address":{"zip":"12345","city":"Springfield","street":"123 + Main St"},"name":"John Doe"}}}}]},{"role":"user","parts":[{"functionResponse":{"name":"fa7e318e-60b9-443a-b9fb-064beb07def1","response":{"name":"fa7e318e-60b9-443a-b9fb-064beb07def1","content":"Completed + contact: John Doe at 123 Main St, Springfield 12345"}}}]}],"generationConfig":{"temperature":0.7},"tools":[{"functionDeclarations":[{"name":"address_book","description":"Manages + address book entries","parameters":{"type":"OBJECT","properties":{"contact":{"type":"OBJECT","description":"Contact + information","properties":{"name":{"type":"STRING","description":"Full name"},"address":{"type":"OBJECT","description":"Address + details"}}}},"required":["contact"]}}]}]}' + headers: + User-Agent: + - Faraday v2.12.2 + X-Goog-Api-Key: + - "" + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json; charset=UTF-8 + Vary: + - Origin + - Referer + - X-Origin + Date: + - Mon, 14 Apr 2025 21:09:09 GMT + Server: + - scaffolding on HTTPServer2 + X-Xss-Protection: + - '0' + X-Frame-Options: + - SAMEORIGIN + X-Content-Type-Options: + - nosniff + Server-Timing: + - gfet4t7; dur=582 + Alt-Svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + Transfer-Encoding: + - chunked + body: + encoding: ASCII-8BIT + string: | + { + "candidates": [ + { + "content": { + "parts": [ + { + "text": "OK. I've added John Doe to the address book at 123 Main St, Springfield 12345.\n" + } + ], + "role": "model" + }, + "finishReason": "STOP", + "avgLogprobs": -2.87032814632202e-06 + } + ], + "usageMetadata": { + "promptTokenCount": 144, + "candidatesTokenCount": 29, + "totalTokenCount": 173, + "promptTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 144 + } + ], + "candidatesTokensDetails": [ + { + "modality": "TEXT", + "tokenCount": 29 + } + ] + }, + "modelVersion": "gemini-2.0-flash" + } + recorded_at: Mon, 14 Apr 2025 21:09:51 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_openai_gpt-4o-mini_handles_nested_object_parameters.yml b/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_openai_gpt-4o-mini_handles_nested_object_parameters.yml new file mode 100644 index 00000000..cc236ea3 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_nested_parameters_with_openai_gpt-4o-mini_handles_nested_object_parameters.yml @@ -0,0 +1,239 @@ +--- +http_interactions: +- request: + method: post + uri: https://api.openai.com/v1/chat/completions + body: + encoding: UTF-8 + string: '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Add John + Doe to the address book at 123 Main St, Springfield 12345"}],"temperature":0.7,"stream":false,"tools":[{"type":"function","function":{"name":"address_book","description":"Manages + address book entries","parameters":{"type":"object","properties":{"contact":{"type":"object","description":"Contact + information","properties":{"name":{"type":"string","description":"Full name"},"address":{"type":"object","description":"Address + details","properties":{"street":{"type":"string","description":"Street address"},"city":{"type":"string","description":"City + name"},"zip":{"type":"string","description":"ZIP/Postal code"}}}}}},"required":["contact"]}}}],"tool_choice":"auto"}' + headers: + User-Agent: + - Faraday v2.12.2 + Authorization: + - Bearer + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 14 Apr 2025 21:09:11 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Access-Control-Expose-Headers: + - X-Request-ID + Openai-Organization: + - "" + Openai-Processing-Ms: + - '800' + Openai-Version: + - '2020-10-01' + X-Ratelimit-Limit-Requests: + - '30000' + X-Ratelimit-Limit-Tokens: + - '150000000' + X-Ratelimit-Remaining-Requests: + - '29999' + X-Ratelimit-Remaining-Tokens: + - '149999981' + X-Ratelimit-Reset-Requests: + - 2ms + X-Ratelimit-Reset-Tokens: + - 0s + X-Request-Id: + - "" + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Set-Cookie: + - "" + - "" + X-Content-Type-Options: + - nosniff + Server: + - cloudflare + Cf-Ray: + - "" + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: | + { + "id": "chatcmpl-BMLLCcjzvidhHBtxez6XVPcNgczrE", + "object": "chat.completion", + "created": 1744664950, + "model": "gpt-4o-mini-2024-07-18", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": null, + "tool_calls": [ + { + "id": "call_cAycKaaDWaCzemZl97fq37Ei", + "type": "function", + "function": { + "name": "address_book", + "arguments": "{\"contact\":{\"name\":\"John Doe\",\"address\":{\"street\":\"123 Main St\",\"city\":\"Springfield\",\"zip\":\"12345\"}}}" + } + } + ], + "refusal": null, + "annotations": [] + }, + "logprobs": null, + "finish_reason": "tool_calls" + } + ], + "usage": { + "prompt_tokens": 101, + "completion_tokens": 37, + "total_tokens": 138, + "prompt_tokens_details": { + "cached_tokens": 0, + "audio_tokens": 0 + }, + "completion_tokens_details": { + "reasoning_tokens": 0, + "audio_tokens": 0, + "accepted_prediction_tokens": 0, + "rejected_prediction_tokens": 0 + } + }, + "service_tier": "default", + "system_fingerprint": "fp_f7d56a8a2c" + } + recorded_at: Mon, 14 Apr 2025 21:09:53 GMT +- request: + method: post + uri: https://api.openai.com/v1/chat/completions + body: + encoding: UTF-8 + string: '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Add John + Doe to the address book at 123 Main St, Springfield 12345"},{"role":"assistant","tool_calls":[{"id":"call_cAycKaaDWaCzemZl97fq37Ei","type":"function","function":{"name":"address_book","arguments":"{\"contact\":{\"name\":\"John + Doe\",\"address\":{\"street\":\"123 Main St\",\"city\":\"Springfield\",\"zip\":\"12345\"}}}"}}]},{"role":"tool","content":"Completed + contact: John Doe at 123 Main St, Springfield 12345","tool_call_id":"call_cAycKaaDWaCzemZl97fq37Ei"}],"temperature":0.7,"stream":false,"tools":[{"type":"function","function":{"name":"address_book","description":"Manages + address book entries","parameters":{"type":"object","properties":{"contact":{"type":"object","description":"Contact + information","properties":{"name":{"type":"string","description":"Full name"},"address":{"type":"object","description":"Address + details","properties":{"street":{"type":"string","description":"Street address"},"city":{"type":"string","description":"City + name"},"zip":{"type":"string","description":"ZIP/Postal code"}}}}}},"required":["contact"]}}}],"tool_choice":"auto"}' + headers: + User-Agent: + - Faraday v2.12.2 + Authorization: + - Bearer + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Date: + - Mon, 14 Apr 2025 21:09:11 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Access-Control-Expose-Headers: + - X-Request-ID + Openai-Organization: + - "" + Openai-Processing-Ms: + - '464' + Openai-Version: + - '2020-10-01' + X-Ratelimit-Limit-Requests: + - '30000' + X-Ratelimit-Limit-Tokens: + - '150000000' + X-Ratelimit-Remaining-Requests: + - '29999' + X-Ratelimit-Remaining-Tokens: + - '149999963' + X-Ratelimit-Reset-Requests: + - 2ms + X-Ratelimit-Reset-Tokens: + - 0s + X-Request-Id: + - "" + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Cf-Cache-Status: + - DYNAMIC + Set-Cookie: + - "" + - "" + X-Content-Type-Options: + - nosniff + Server: + - cloudflare + Cf-Ray: + - "" + Alt-Svc: + - h3=":443"; ma=86400 + body: + encoding: ASCII-8BIT + string: | + { + "id": "chatcmpl-BMLLDEPQfYItQFOa2G0mMQE7xT6Y1", + "object": "chat.completion", + "created": 1744664951, + "model": "gpt-4o-mini-2024-07-18", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "John Doe has been successfully added to the address book with the address 123 Main St, Springfield 12345.", + "refusal": null, + "annotations": [] + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 160, + "completion_tokens": 25, + "total_tokens": 185, + "prompt_tokens_details": { + "cached_tokens": 0, + "audio_tokens": 0 + }, + "completion_tokens_details": { + "reasoning_tokens": 0, + "audio_tokens": 0, + "accepted_prediction_tokens": 0, + "rejected_prediction_tokens": 0 + } + }, + "service_tier": "default", + "system_fingerprint": "fp_f7d56a8a2c" + } + recorded_at: Mon, 14 Apr 2025 21:09:53 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/ruby_llm/chat_tools_spec.rb b/spec/ruby_llm/chat_tools_spec.rb index 2193369c..24e92ca6 100644 --- a/spec/ruby_llm/chat_tools_spec.rb +++ b/spec/ruby_llm/chat_tools_spec.rb @@ -37,6 +37,72 @@ def execute end end + class AddressBook < RubyLLM::Tool # rubocop:disable Lint/ConstantDefinitionInBlock,RSpec/LeakyConstantDeclaration + description 'Manages address book entries' + + param :contact, + type: 'object', + desc: 'Contact information', + properties: { + name: { + type: 'string', + desc: 'Full name' + }, + address: { + type: 'object', + desc: 'Address details', + properties: { + street: { + type: 'string', + desc: 'Street address' + }, + city: { + type: 'string', + desc: 'City name' + }, + zip: { + type: 'string', + desc: 'ZIP/Postal code' + } + } + } + } + + def execute(contact:) + address = contact['address'] + "Completed contact: #{contact['name']} at #{address['street']}, " \ + "#{address['city']} #{address['zip']}" + end + end + + class StateManager < RubyLLM::Tool # rubocop:disable Lint/ConstantDefinitionInBlock,RSpec/LeakyConstantDeclaration + description 'Manages US states information' + + param :states, + type: 'array', + desc: 'List of states', + items: { + name: { + type: 'string', + desc: 'The state name' + }, + capital: { + type: 'string', + desc: 'The capital city' + }, + population: { + type: 'number', + desc: 'Population count' + } + } + + def execute(states:) + return 'No states provided' if states.empty? + + states.map { |s| "#{s['name']}: Capital is #{s['capital']} (pop: #{s['population']})" }.join("\n") + end + end + describe 'function calling' do chat_models.each do |model| provider = RubyLLM::Models.provider_for(model).slug @@ -127,6 +193,46 @@ def execute end end + describe 'nested parameters' do + chat_models.each do |model| + provider = RubyLLM::Models.provider_for(model).slug + + context "with #{provider}/#{model}" do + let(:chat) { RubyLLM.chat(model: model).with_tool(AddressBook) } + + it 'handles nested object parameters', :aggregate_failures do + prompt = 'Add John Doe to the address book at 123 Main St, Springfield 12345' + response = chat.ask(prompt) + + expect(response.content).to include('John Doe', '123 Main St', + 'Springfield', '12345') + end + end + end + end + + describe 'array parameters' do + chat_models.each do |model| + provider = RubyLLM::Models.provider_for(model).slug + + context "with #{provider}/#{model}" do + let(:chat) { RubyLLM.chat(model: model).with_tool(StateManager) } + let(:prompt) do + 'Add information about California (capital: Sacramento, ' \ + 'pop: 39538223) and Texas (capital: Austin, pop: 29145505). ' \ + 'Make sure to return all the information in the final output. ' + end + + it 'handles array parameters with object items', :aggregate_failures do + response = chat.ask(prompt) + + expect(response.content).to include('Sacramento', 'Austin') + expect(response.content).to match(/39538223|39,538,223/).and(match(/29145505|29,145,505/)) + end + end + end + end + describe 'error handling' do it 'raises an error when tool execution fails' do # rubocop:disable RSpec/MultipleExpectations chat = RubyLLM.chat.with_tool(BrokenTool)