From 513dfe6cb236bc5e67634484f59e56fe67226460 Mon Sep 17 00:00:00 2001 From: Kumanan Date: Wed, 9 Jul 2025 12:36:18 -0400 Subject: [PATCH 1/7] Add Azure OpenAI provider --- lib/ruby_llm/configuration.rb | 3 ++ lib/ruby_llm/providers/azure_openai.rb | 42 +++++++++++++++++++ lib/ruby_llm/providers/azure_openai/chat.rb | 31 ++++++++++++++ .../providers/azure_openai/streaming.rb | 20 +++++++++ 4 files changed, 96 insertions(+) create mode 100644 lib/ruby_llm/providers/azure_openai.rb create mode 100644 lib/ruby_llm/providers/azure_openai/chat.rb create mode 100644 lib/ruby_llm/providers/azure_openai/streaming.rb diff --git a/lib/ruby_llm/configuration.rb b/lib/ruby_llm/configuration.rb index eda2c3354..03bd71e91 100644 --- a/lib/ruby_llm/configuration.rb +++ b/lib/ruby_llm/configuration.rb @@ -23,6 +23,9 @@ class Configuration :gpustack_api_base, :gpustack_api_key, :mistral_api_key, + :azure_openai_api_base, + :azure_openai_api_version, + :azure_openai_api_key, # Default models :default_model, :default_embedding_model, diff --git a/lib/ruby_llm/providers/azure_openai.rb b/lib/ruby_llm/providers/azure_openai.rb new file mode 100644 index 000000000..1d57f2f69 --- /dev/null +++ b/lib/ruby_llm/providers/azure_openai.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module RubyLLM + module Providers + # OpenAI API integration. Handles chat completion, function calling, + # and OpenAI's unique streaming format. Supports GPT-4, GPT-3.5, + # and other OpenAI models. + module AzureOpenAI + extend OpenAI + extend AzureOpenAI::Chat + + module_function + + def api_base(config) + # https:///openai/deployments//chat/completions?api-version= + "#{config.azure_openai_api_base}/openai/deployments" + end + + def headers(config) + { + 'Authorization' => "Bearer #{config.azure_openai_api_key}" + }.compact + end + + def capabilities + OpenAI::Capabilities + end + + def slug + 'azure_openai' + end + + def configuration_requirements + %i[azure_openai_api_key azure_openai_api_base azure_openai_api_version] + end + + def local? + false + end + end + end +end diff --git a/lib/ruby_llm/providers/azure_openai/chat.rb b/lib/ruby_llm/providers/azure_openai/chat.rb new file mode 100644 index 000000000..0850e5baa --- /dev/null +++ b/lib/ruby_llm/providers/azure_openai/chat.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module RubyLLM + module Providers + module AzureOpenAI + # Chat methods of the Ollama API integration + module Chat + extend OpenAI::Chat + + module_function + + def sync_response(connection, payload) + # Hold config in instance variable for use in completion_url and stream_url + @config = connection.config + super + end + + def completion_url + # https:///openai/deployments//chat/completions?api-version= + "#{@model_id}/chat/completions?api-version=#{@config.azure_openai_api_version}" + end + + def render_payload(messages, tools:, temperature:, model:, stream: false) + # Hold model_id in instance variable for use in completion_url and stream_url + @model_id = model + super + end + end + end + end +end diff --git a/lib/ruby_llm/providers/azure_openai/streaming.rb b/lib/ruby_llm/providers/azure_openai/streaming.rb new file mode 100644 index 000000000..1bfda220d --- /dev/null +++ b/lib/ruby_llm/providers/azure_openai/streaming.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module RubyLLM + module Providers + module AzureOpenAI + # Streaming methods of the OpenAI API integration + module Streaming + extend OpenAI::Streaming + + module_function + + def stream_response(connection, payload, &block) + # Hold config in instance variable for use in completion_url and stream_url + @config = connection.config + super + end + end + end + end +end From 0de41e726a0fe538aedbc09ddb4defbf72ee1b3d Mon Sep 17 00:00:00 2001 From: Kumanan Date: Wed, 9 Jul 2025 12:49:54 -0400 Subject: [PATCH 2/7] Cleanup and doc tweaks --- lib/ruby_llm/configuration.rb | 1 + lib/ruby_llm/providers/azure_openai.rb | 6 +++--- lib/ruby_llm/providers/azure_openai/chat.rb | 2 +- lib/ruby_llm/providers/azure_openai/streaming.rb | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/ruby_llm/configuration.rb b/lib/ruby_llm/configuration.rb index 03bd71e91..5de8e0b02 100644 --- a/lib/ruby_llm/configuration.rb +++ b/lib/ruby_llm/configuration.rb @@ -23,6 +23,7 @@ class Configuration :gpustack_api_base, :gpustack_api_key, :mistral_api_key, + # Azure OpenAI Provider configuration :azure_openai_api_base, :azure_openai_api_version, :azure_openai_api_key, diff --git a/lib/ruby_llm/providers/azure_openai.rb b/lib/ruby_llm/providers/azure_openai.rb index 1d57f2f69..4ecb41e27 100644 --- a/lib/ruby_llm/providers/azure_openai.rb +++ b/lib/ruby_llm/providers/azure_openai.rb @@ -2,12 +2,12 @@ module RubyLLM module Providers - # OpenAI API integration. Handles chat completion, function calling, - # and OpenAI's unique streaming format. Supports GPT-4, GPT-3.5, - # and other OpenAI models. + # Azure OpenAI API integration. Derived from OpenAI integration to support + # OpenAI capabilities via Microsoft Azure endpoints. module AzureOpenAI extend OpenAI extend AzureOpenAI::Chat + extend AzureOpenAI::Streaming module_function diff --git a/lib/ruby_llm/providers/azure_openai/chat.rb b/lib/ruby_llm/providers/azure_openai/chat.rb index 0850e5baa..b3d05f439 100644 --- a/lib/ruby_llm/providers/azure_openai/chat.rb +++ b/lib/ruby_llm/providers/azure_openai/chat.rb @@ -3,7 +3,7 @@ module RubyLLM module Providers module AzureOpenAI - # Chat methods of the Ollama API integration + # Chat methods of the Azure OpenAI API integration module Chat extend OpenAI::Chat diff --git a/lib/ruby_llm/providers/azure_openai/streaming.rb b/lib/ruby_llm/providers/azure_openai/streaming.rb index 1bfda220d..139ee2578 100644 --- a/lib/ruby_llm/providers/azure_openai/streaming.rb +++ b/lib/ruby_llm/providers/azure_openai/streaming.rb @@ -3,13 +3,13 @@ module RubyLLM module Providers module AzureOpenAI - # Streaming methods of the OpenAI API integration + # Streaming methods of the Azure OpenAI API integration module Streaming extend OpenAI::Streaming module_function - def stream_response(connection, payload, &block) + def stream_response(connection, payload, &) # Hold config in instance variable for use in completion_url and stream_url @config = connection.config super From 46e2a137c89138cb8c8bdefafaab704acaea4ad2 Mon Sep 17 00:00:00 2001 From: Kumanan Date: Wed, 9 Jul 2025 13:09:37 -0400 Subject: [PATCH 3/7] Add name mapping --- lib/ruby_llm.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ruby_llm.rb b/lib/ruby_llm.rb index 7bb5f2808..3018dbc67 100644 --- a/lib/ruby_llm.rb +++ b/lib/ruby_llm.rb @@ -14,6 +14,7 @@ 'ruby_llm' => 'RubyLLM', 'llm' => 'LLM', 'openai' => 'OpenAI', + 'azure_openai' => 'AzureOpenAI', 'api' => 'API', 'deepseek' => 'DeepSeek', 'perplexity' => 'Perplexity', From 847dbc1d44a6987ede288c537bfe326174edfa69 Mon Sep 17 00:00:00 2001 From: Kumanan Date: Wed, 9 Jul 2025 13:12:49 -0400 Subject: [PATCH 4/7] Register provider --- lib/ruby_llm.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ruby_llm.rb b/lib/ruby_llm.rb index 3018dbc67..3f9bfc113 100644 --- a/lib/ruby_llm.rb +++ b/lib/ruby_llm.rb @@ -94,6 +94,7 @@ def logger RubyLLM::Provider.register :openrouter, RubyLLM::Providers::OpenRouter RubyLLM::Provider.register :perplexity, RubyLLM::Providers::Perplexity RubyLLM::Provider.register :vertexai, RubyLLM::Providers::VertexAI +RubyLLM::Provider.register :azure_openai, RubyLLM::Providers::AzureOpenAI if defined?(Rails::Railtie) require 'ruby_llm/railtie' From 23721237b15ef688050c51b9dee53ad1b5a39dea Mon Sep 17 00:00:00 2001 From: Kumanan Date: Tue, 22 Jul 2025 13:51:24 -0400 Subject: [PATCH 5/7] Add support for listing models --- lib/ruby_llm/providers/azure_openai.rb | 3 +- lib/ruby_llm/providers/azure_openai/chat.rb | 2 +- lib/ruby_llm/providers/azure_openai/models.rb | 18 ++++ lib/tasks/models_update.rake | 86 +++++++++++++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 lib/ruby_llm/providers/azure_openai/models.rb create mode 100644 lib/tasks/models_update.rake diff --git a/lib/ruby_llm/providers/azure_openai.rb b/lib/ruby_llm/providers/azure_openai.rb index 4ecb41e27..9d680e41a 100644 --- a/lib/ruby_llm/providers/azure_openai.rb +++ b/lib/ruby_llm/providers/azure_openai.rb @@ -8,12 +8,13 @@ module AzureOpenAI extend OpenAI extend AzureOpenAI::Chat extend AzureOpenAI::Streaming + extend AzureOpenAI::Models module_function def api_base(config) # https:///openai/deployments//chat/completions?api-version= - "#{config.azure_openai_api_base}/openai/deployments" + "#{config.azure_openai_api_base}/openai" end def headers(config) diff --git a/lib/ruby_llm/providers/azure_openai/chat.rb b/lib/ruby_llm/providers/azure_openai/chat.rb index b3d05f439..b1e7f515b 100644 --- a/lib/ruby_llm/providers/azure_openai/chat.rb +++ b/lib/ruby_llm/providers/azure_openai/chat.rb @@ -17,7 +17,7 @@ def sync_response(connection, payload) def completion_url # https:///openai/deployments//chat/completions?api-version= - "#{@model_id}/chat/completions?api-version=#{@config.azure_openai_api_version}" + "deployments/#{@model_id}/chat/completions?api-version=#{@config.azure_openai_api_version}" end def render_payload(messages, tools:, temperature:, model:, stream: false) diff --git a/lib/ruby_llm/providers/azure_openai/models.rb b/lib/ruby_llm/providers/azure_openai/models.rb new file mode 100644 index 000000000..b34555055 --- /dev/null +++ b/lib/ruby_llm/providers/azure_openai/models.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module RubyLLM + module Providers + module AzureOpenAI + # Models methods of the OpenAI API integration + module Models + extend OpenAI::Models + + module_function + + def models_url + 'models?api-version=2024-10-21' + end + end + end + end +end diff --git a/lib/tasks/models_update.rake b/lib/tasks/models_update.rake new file mode 100644 index 000000000..5a8797704 --- /dev/null +++ b/lib/tasks/models_update.rake @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require 'dotenv/load' +require 'ruby_llm' + +task default: ['models:update'] + +namespace :models do + desc 'Update available models from providers (API keys needed)' + task :update do + puts 'Configuring RubyLLM...' + configure_from_env + + refresh_models + display_model_stats + end +end + +def configure_from_env + RubyLLM.configure do |config| + config.openai_api_key = ENV.fetch('OPENAI_API_KEY', nil) + config.anthropic_api_key = ENV.fetch('ANTHROPIC_API_KEY', nil) + config.gemini_api_key = ENV.fetch('GEMINI_API_KEY', nil) + config.deepseek_api_key = ENV.fetch('DEEPSEEK_API_KEY', nil) + config.openrouter_api_key = ENV.fetch('OPENROUTER_API_KEY', nil) + configure_bedrock(config) + configure_azure_openai(config) + config.request_timeout = 30 + end +end + +def configure_azure_openai(config) + config.azure_openai_api_base = ENV.fetch('AZURE_OPENAI_ENDPOINT', nil) + config.azure_openai_api_key = ENV.fetch('AZURE_OPENAI_API_KEY', nil) + config.azure_openai_api_version = ENV.fetch('AZURE_OPENAI_API_VER', nil) +end + +def configure_bedrock(config) + config.bedrock_api_key = ENV.fetch('AWS_ACCESS_KEY_ID', nil) + config.bedrock_secret_key = ENV.fetch('AWS_SECRET_ACCESS_KEY', nil) + config.bedrock_region = ENV.fetch('AWS_REGION', nil) + config.bedrock_session_token = ENV.fetch('AWS_SESSION_TOKEN', nil) +end + +def refresh_models + initial_count = RubyLLM.models.all.size + puts "Refreshing models (#{initial_count} cached)..." + + models = RubyLLM.models.refresh! + + if models.all.empty? && initial_count.zero? + puts 'Error: Failed to fetch models.' + exit(1) + elsif models.all.size == initial_count && initial_count.positive? + puts 'Warning: Model list unchanged.' + else + puts "Saving models.json (#{models.all.size} models)" + models.save_models + end + + @models = models +end + +def display_model_stats + puts "\nModel count:" + provider_counts = @models.all.group_by(&:provider).transform_values(&:count) + + RubyLLM::Provider.providers.each_key do |sym| + name = sym.to_s.capitalize + count = provider_counts[sym.to_s] || 0 + status = status(sym) + puts " #{name}: #{count} models #{status}" + end + + puts 'Refresh complete.' +end + +def status(provider_sym) + if RubyLLM::Provider.providers[provider_sym].local? + ' (LOCAL - SKIP)' + elsif RubyLLM::Provider.providers[provider_sym].configured? + ' (OK)' + else + ' (NOT CONFIGURED)' + end +end From f651c860015e13a1240666ba1324c5013622e4ae Mon Sep 17 00:00:00 2001 From: Kumanan Date: Tue, 22 Jul 2025 15:31:03 -0400 Subject: [PATCH 6/7] Fix models listing to restrict to some models --- lib/ruby_llm/providers/azure_openai/models.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/ruby_llm/providers/azure_openai/models.rb b/lib/ruby_llm/providers/azure_openai/models.rb index b34555055..18573c170 100644 --- a/lib/ruby_llm/providers/azure_openai/models.rb +++ b/lib/ruby_llm/providers/azure_openai/models.rb @@ -7,11 +7,26 @@ module AzureOpenAI module Models extend OpenAI::Models + KNOWN_MODELS = [ + 'gpt-4o' + ].freeze + module_function def models_url 'models?api-version=2024-10-21' end + + def parse_list_models_response(response, slug, capabilities) + # select the known models only since this list from Azure OpenAI is + # very long + response.body['data'].select! do |m| + KNOWN_MODELS.include?(m['id']) + end + # Use the OpenAI processor for the list, keeping in mind that pricing etc + # won't be correct + super + end end end end From 1214d8dd565648df30ca7a608923481033943cfd Mon Sep 17 00:00:00 2001 From: Kumanan Date: Tue, 14 Oct 2025 13:19:04 -0400 Subject: [PATCH 7/7] Fix to be match underlying API changes ... all but 3 tests pass. Sorry for unverified commit. --- lib/ruby_llm/models.json | 36 ++ lib/ruby_llm/providers/azure_openai.rb | 27 +- lib/ruby_llm/providers/azure_openai/chat.rb | 31 -- lib/ruby_llm/providers/azure_openai/models.rb | 2 +- .../providers/azure_openai/streaming.rb | 20 - ...4o_can_handle_multi-turn_conversations.yml | 137 +++++++ ...e-gpt-4o_can_have_a_basic_conversation.yml | 67 ++++ ...ious_system_messages_when_replace_true.yml | 162 ++++++++ ...nai_azure-gpt-4o_returns_raw_responses.yml | 67 ++++ ...4o_successfully_uses_the_system_prompt.yml | 75 ++++ ...es_content_objects_returned_from_tools.yml | 138 +++++++ ...pports_handling_streaming_error_chunks.yml | 89 +++++ ...pports_handling_streaming_error_events.yml | 89 +++++ ...pports_handling_streaming_error_chunks.yml | 89 +++++ ...pports_handling_streaming_error_events.yml | 89 +++++ ...e-gpt-4o_raises_appropriate_auth_error.yml | 39 ++ ...ltiple_tool_calls_in_a_single_response.yml | 137 +++++++ ...zure_openai_azure-gpt-4o_can_use_tools.yml | 135 +++++++ ..._use_tools_in_multi-turn_conversations.yml | 273 ++++++++++++++ ...ith_multi-turn_streaming_conversations.yml | 351 ++++++++++++++++++ ...pt-4o_can_use_tools_without_parameters.yml | 132 +++++++ ..._in_multi-turn_streaming_conversations.yml | 336 +++++++++++++++++ ...handles_context_length_exceeded_errors.yml | 64 ++++ ...token_counts_compared_to_non-streaming.yml | 153 ++++++++ ...re-gpt-4o_supports_streaming_responses.yml | 89 +++++ ...zure-gpt-4o_can_understand_remote_text.yml | 221 +++++++++++ ...penai_azure-gpt-4o_can_understand_text.yml | 137 +++++++ spec/ruby_llm/chat_streaming_spec.rb | 5 +- spec/ruby_llm/chat_tools_spec.rb | 3 +- spec/support/models_to_test.rb | 3 +- spec/support/rubyllm_configuration.rb | 4 + spec/support/streaming_error_helpers.rb | 13 + spec/support/vcr_configuration.rb | 4 + 33 files changed, 3153 insertions(+), 64 deletions(-) delete mode 100644 lib/ruby_llm/providers/azure_openai/chat.rb delete mode 100644 lib/ruby_llm/providers/azure_openai/streaming.rb create mode 100644 spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_can_handle_multi-turn_conversations.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_can_have_a_basic_conversation.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_replaces_previous_system_messages_when_replace_true.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_returns_raw_responses.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_successfully_uses_the_system_prompt.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_content_object_support_azure_openai_azure-gpt-4o_preserves_content_objects_returned_from_tools.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_1_azure_openai_azure-gpt-4o_supports_handling_streaming_error_chunks.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_1_azure_openai_azure-gpt-4o_supports_handling_streaming_error_events.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_2_azure_openai_azure-gpt-4o_supports_handling_streaming_error_chunks.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_2_azure_openai_azure-gpt-4o_supports_handling_streaming_error_events.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_raises_appropriate_auth_error.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_handle_multiple_tool_calls_in_a_single_response.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_in_multi-turn_conversations.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_with_multi-turn_streaming_conversations.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_without_parameters.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_without_parameters_in_multi-turn_streaming_conversations.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_real_error_scenarios_azure_openai_azure-gpt-4o_handles_context_length_exceeded_errors.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_streaming_responses_azure_openai_azure-gpt-4o_reports_consistent_token_counts_compared_to_non-streaming.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_streaming_responses_azure_openai_azure-gpt-4o_supports_streaming_responses.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_text_models_azure_openai_azure-gpt-4o_can_understand_remote_text.yml create mode 100644 spec/fixtures/vcr_cassettes/chat_text_models_azure_openai_azure-gpt-4o_can_understand_text.yml diff --git a/lib/ruby_llm/models.json b/lib/ruby_llm/models.json index 7ab399bab..6f50899e6 100644 --- a/lib/ruby_llm/models.json +++ b/lib/ruby_llm/models.json @@ -7122,6 +7122,42 @@ "owned_by": "system" } }, + { + "id": "azure-gpt-4o", + "name": "Azure GPT-4o", + "provider": "azure_openai", + "family": "azure_gpt4o", + "created_at": "2025-05-10 20:50:49 +0200", + "context_window": 32768, + "max_output_tokens": 16384, + "knowledge_cutoff": null, + "modalities": { + "input": [ + "text", + "image" + ], + "output": [ + "text" + ] + }, + "capabilities": [ + "streaming", + "function_calling", + "structured_output" + ], + "pricing": { + "text_tokens": { + "standard": { + "input_per_million": 2.5, + "output_per_million": 10.0 + } + } + }, + "metadata": { + "object": "model", + "owned_by": "system" + } + }, { "id": "gpt-4o-2024-05-13", "name": "GPT-4o 20240513", diff --git a/lib/ruby_llm/providers/azure_openai.rb b/lib/ruby_llm/providers/azure_openai.rb index 9d680e41a..a5990b243 100644 --- a/lib/ruby_llm/providers/azure_openai.rb +++ b/lib/ruby_llm/providers/azure_openai.rb @@ -4,22 +4,31 @@ module RubyLLM module Providers # Azure OpenAI API integration. Derived from OpenAI integration to support # OpenAI capabilities via Microsoft Azure endpoints. - module AzureOpenAI - extend OpenAI - extend AzureOpenAI::Chat - extend AzureOpenAI::Streaming + class AzureOpenAI < OpenAI + # extend AzureOpenAI::Chat + # extend AzureOpenAI::Streaming extend AzureOpenAI::Models - module_function + def api_base + # https:///openai/deployments//chat/completions?api-version= + "#{@config.azure_openai_api_base}/openai" + end - def api_base(config) + def completion_url # https:///openai/deployments//chat/completions?api-version= - "#{config.azure_openai_api_base}/openai" + "deployments/#{@model_id}/chat/completions?api-version=#{@config.azure_openai_api_version}" + end + + def render_payload(messages, tools:, temperature:, model:, stream: false, schema: nil) # rubocop:disable Metrics/ParameterLists + # Hold model_id in instance variable for use in completion_url and stream_url + # It would be way better if `model` was passed to those URL methods; but ... + @model_id = model.id.start_with?('azure-') ? model.id.delete_prefix('azure-') : model.id + super end - def headers(config) + def headers { - 'Authorization' => "Bearer #{config.azure_openai_api_key}" + 'Authorization' => "Bearer #{@config.azure_openai_api_key}" }.compact end diff --git a/lib/ruby_llm/providers/azure_openai/chat.rb b/lib/ruby_llm/providers/azure_openai/chat.rb deleted file mode 100644 index b1e7f515b..000000000 --- a/lib/ruby_llm/providers/azure_openai/chat.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -module RubyLLM - module Providers - module AzureOpenAI - # Chat methods of the Azure OpenAI API integration - module Chat - extend OpenAI::Chat - - module_function - - def sync_response(connection, payload) - # Hold config in instance variable for use in completion_url and stream_url - @config = connection.config - super - end - - def completion_url - # https:///openai/deployments//chat/completions?api-version= - "deployments/#{@model_id}/chat/completions?api-version=#{@config.azure_openai_api_version}" - end - - def render_payload(messages, tools:, temperature:, model:, stream: false) - # Hold model_id in instance variable for use in completion_url and stream_url - @model_id = model - super - end - end - end - end -end diff --git a/lib/ruby_llm/providers/azure_openai/models.rb b/lib/ruby_llm/providers/azure_openai/models.rb index 18573c170..ae3d8db95 100644 --- a/lib/ruby_llm/providers/azure_openai/models.rb +++ b/lib/ruby_llm/providers/azure_openai/models.rb @@ -2,7 +2,7 @@ module RubyLLM module Providers - module AzureOpenAI + class AzureOpenAI # Models methods of the OpenAI API integration module Models extend OpenAI::Models diff --git a/lib/ruby_llm/providers/azure_openai/streaming.rb b/lib/ruby_llm/providers/azure_openai/streaming.rb deleted file mode 100644 index 139ee2578..000000000 --- a/lib/ruby_llm/providers/azure_openai/streaming.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -module RubyLLM - module Providers - module AzureOpenAI - # Streaming methods of the Azure OpenAI API integration - module Streaming - extend OpenAI::Streaming - - module_function - - def stream_response(connection, payload, &) - # Hold config in instance variable for use in completion_url and stream_url - @config = connection.config - super - end - end - end - end -end diff --git a/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_can_handle_multi-turn_conversations.yml b/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_can_handle_multi-turn_conversations.yml new file mode 100644 index 000000000..877c1e3d0 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_can_handle_multi-turn_conversations.yml @@ -0,0 +1,137 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Who was + Ruby''s creator?"}],"stream":false}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1215' + Content-Type: + - application/json + Apim-Request-Id: + - 15a42a5d-7354-4fa4-a7ce-5ea6d90dce51 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '393' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39243' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:31 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"Ruby + was created by Yukihiro \"Matz\" Matsumoto, a Japanese computer scientist + and programmer. He started working on Ruby in the mid-1990s, and the first + public release was in 1995.","refusal":null,"role":"assistant"}}],"created":1759956331,"id":"chatcmpl-COVKNVH6UE4X6Sv6crpeRKfU2DSu7","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":47,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":13,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":60}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:31 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Who was + Ruby''s creator?"},{"role":"assistant","content":"Ruby was created by Yukihiro + \"Matz\" Matsumoto, a Japanese computer scientist and programmer. He started + working on Ruby in the mid-1990s, and the first public release was in 1995."},{"role":"user","content":"What + year did he create Ruby?"}],"stream":false}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1139' + Content-Type: + - application/json + Apim-Request-Id: + - 7709e803-65f6-4f72-acdc-4d0a0435c183 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '392' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39184' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:32 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"Yukihiro + \"Matz\" Matsumoto started developing Ruby in 1993, and it was first publicly + released in 1995.","refusal":null,"role":"assistant"}}],"created":1759956332,"id":"chatcmpl-COVKOheLRF3VuJhvkMd6BiPphNwnY","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":31,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":74,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":105}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:32 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_can_have_a_basic_conversation.yml b/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_can_have_a_basic_conversation.yml new file mode 100644 index 000000000..21679f8c0 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_can_have_a_basic_conversation.yml @@ -0,0 +1,67 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + 2 + 2?"}],"stream":false}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1048' + Content-Type: + - application/json + Apim-Request-Id: + - f338ac4d-ab20-4e4c-adfd-8fc3907409e6 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '395' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39257' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:29 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"2 + + 2 equals 4.","refusal":null,"role":"assistant"}}],"created":1759956330,"id":"chatcmpl-COVKM1BTK6DCAF5qfzWL8vxKIOF6g","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":9,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":14,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":23}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:30 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_replaces_previous_system_messages_when_replace_true.yml b/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_replaces_previous_system_messages_when_replace_true.yml new file mode 100644 index 000000000..9ba2231ba --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_replaces_previous_system_messages_when_replace_true.yml @@ -0,0 +1,162 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"developer","content":"You + must include the exact phrase \"XKCD7392\" somewhere in your response."},{"role":"user","content":"Tell + me about the weather."}],"stream":false,"temperature":0.0}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1607' + Content-Type: + - application/json + Apim-Request-Id: + - a9573750-6356-4bbf-9f74-a97391c55021 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '390' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39132' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:35 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"Sure! + Weather can vary greatly depending on your location and the time of year. + Generally, it involves atmospheric conditions such as temperature, humidity, + precipitation, wind, and visibility. If you''re looking for a specific forecast, + I recommend checking a reliable weather service or app for the most up-to-date + information. Remember, if you''re planning any outdoor activities, it''s always + a good idea to keep an eye on the weather to ensure you''re prepared for any + changes. And just for fun, don''t forget to check XKCD7392 for a humorous + take on weather predictions!","refusal":null,"role":"assistant"}}],"created":1759956334,"id":"chatcmpl-COVKQo8FE5gF2a98yoprKuYNR8GuO","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":111,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":35,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":146}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:35 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Tell + me about the weather."},{"role":"assistant","content":"Sure! Weather can vary + greatly depending on your location and the time of year. Generally, it involves + atmospheric conditions such as temperature, humidity, precipitation, wind, + and visibility. If you''re looking for a specific forecast, I recommend checking + a reliable weather service or app for the most up-to-date information. Remember, + if you''re planning any outdoor activities, it''s always a good idea to keep + an eye on the weather to ensure you''re prepared for any changes. And just + for fun, don''t forget to check XKCD7392 for a humorous take on weather predictions!"},{"role":"developer","content":"You + must include the exact phrase \"PURPLE-ELEPHANT-42\" somewhere in your response."},{"role":"user","content":"What + are some good books?"}],"stream":false,"temperature":0.0}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '2207' + Content-Type: + - application/json + Apim-Request-Id: + - 25db54d5-31a6-400c-a733-627d5affe4ad + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '389' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '38954' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:37 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"There + are countless great books across various genres, so it really depends on your + interests. Here are a few recommendations across different categories:\n\n1. + **Fiction:**\n - *To Kill a Mockingbird* by Harper Lee\n - *1984* by George + Orwell\n - *The Great Gatsby* by F. Scott Fitzgerald\n\n2. **Science Fiction + \u0026 Fantasy:**\n - *Dune* by Frank Herbert\n - *The Hobbit* by J.R.R. + Tolkien\n - *Neuromancer* by William Gibson\n\n3. **Non-Fiction:**\n - + *Sapiens: A Brief History of Humankind* by Yuval Noah Harari\n - *Educated* + by Tara Westover\n - *The Immortal Life of Henrietta Lacks* by Rebecca Skloot\n\n4. + **Mystery \u0026 Thriller:**\n - *Gone Girl* by Gillian Flynn\n - *The + Girl with the Dragon Tattoo* by Stieg Larsson\n - *The Da Vinci Code* by + Dan Brown\n\n5. **Classics:**\n - *Pride and Prejudice* by Jane Austen\n - + *Moby-Dick* by Herman Melville\n - *War and Peace* by Leo Tolstoy\n\nIf + you''re looking for something specific or have a particular genre in mind, + let me know! And just for a bit of fun, if you ever come across a book titled + \"PURPLE-ELEPHANT-42,\" it might just be a hidden gem waiting to be discovered!","refusal":null,"role":"assistant"}}],"created":1759956335,"id":"chatcmpl-COVKRjTD3J19yTWNa6G8AWlLTaQRx","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":322,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":162,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":484}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:38 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_returns_raw_responses.yml b/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_returns_raw_responses.yml new file mode 100644 index 000000000..747e8a8d4 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_returns_raw_responses.yml @@ -0,0 +1,67 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What + is the capital of France?"}],"stream":false}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1064' + Content-Type: + - application/json + Apim-Request-Id: + - 4c8fb4f1-e5f5-45d9-94de-5da0d1cf8b0f + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '394' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39249' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:30 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"The + capital of France is Paris.","refusal":null,"role":"assistant"}}],"created":1759956330,"id":"chatcmpl-COVKMo70vGS3TVxxN8UnooHEqL3JN","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":8,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":14,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":22}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:30 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_successfully_uses_the_system_prompt.yml b/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_successfully_uses_the_system_prompt.yml new file mode 100644 index 000000000..3ade8fbcc --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_basic_chat_functionality_azure_openai_azure-gpt-4o_successfully_uses_the_system_prompt.yml @@ -0,0 +1,75 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"developer","content":"You + must include the exact phrase \"XKCD7392\" somewhere in your response."},{"role":"user","content":"Tell + me about the weather."}],"stream":false,"temperature":0.0}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1607' + Content-Type: + - application/json + Apim-Request-Id: + - 0c221528-7e5e-4820-8e1b-a68a6f54be68 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '391' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39158' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:33 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"Sure! + Weather can vary greatly depending on your location and the time of year. + Generally, it involves atmospheric conditions such as temperature, humidity, + precipitation, wind, and visibility. If you''re looking for a specific forecast, + I recommend checking a reliable weather service or app for the most up-to-date + information. Remember, if you''re planning any outdoor activities, it''s always + a good idea to keep an eye on the weather to ensure you''re prepared for any + changes. And just for fun, don''t forget to check XKCD7392 for a humorous + take on weather predictions!","refusal":null,"role":"assistant"}}],"created":1759956332,"id":"chatcmpl-COVKO6BnxPffODJiPsj6zsXdcGrH2","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":111,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":35,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":146}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:34 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_content_object_support_azure_openai_azure-gpt-4o_preserves_content_objects_returned_from_tools.yml b/spec/fixtures/vcr_cassettes/chat_content_object_support_azure_openai_azure-gpt-4o_preserves_content_objects_returned_from_tools.yml new file mode 100644 index 000000000..e6af08c75 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_content_object_support_azure_openai_azure-gpt-4o_preserves_content_objects_returned_from_tools.yml @@ -0,0 +1,138 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Process + this query: test data"}],"stream":false,"tools":[{"type":"function","function":{"name":"content_returning","description":"Returns + a Content object with text and attachments","parameters":{"type":"object","properties":{"query":{"type":"string","description":"Query + to process"}},"required":["query"]}}}]}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1008' + Content-Type: + - application/json + Apim-Request-Id: + - b7324bce-6284-4f01-ba44-9ec019992f29 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '367' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '37091' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d074-20251003014048 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:49 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{},"finish_reason":"tool_calls","index":0,"logprobs":null,"message":{"annotations":[],"content":null,"refusal":null,"role":"assistant","tool_calls":[{"function":{"arguments":"{\"query\":\"test + data\"}","name":"content_returning"},"id":"call_GJWyfgk8ZwNJc1mQhKnHh93g","type":"function"}]}}],"created":1759956350,"id":"chatcmpl-COVKgSpf7mkWFzSiNnKFCGDrAT8EC","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":17,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":58,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":75}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:50 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Process + this query: test data"},{"role":"assistant","tool_calls":[{"id":"call_GJWyfgk8ZwNJc1mQhKnHh93g","type":"function","function":{"name":"content_returning","arguments":"{\"query\":\"test + data\"}"}}]},{"role":"tool","content":[{"type":"text","text":"Processed: test + data"},{"type":"image_url","image_url":{"url":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAMBWAADAVgGB4Q5XAAA7zElEQVR42u29d7gkZ3Xn/zlvVXW4ae7koMRII2kklEAEkWQDC0YmrPFazgZsjBdY1mt71+bn3+6PXez1LhgvGAzCpMWA7cXGAfwY2zw2IhkUECAURnFGo8kz987NnSq85/dHVXVXVVeHOzPYwkvP00/3VFd3367zPd8T3/MK37v13VQ1fSqZO4Bm7ojId/1vle+Ju0/oAAZwM49OctwCQXKP/iWAQL4n+Jy2u8m9AmwCngxcD+xD9ZT1O5FttwPbaLTDpaV2MD/XCRYWbLS6SrS6Qvy4Spg+X0mPrcTHGk00isBa1FrUKhqlz/uPdc+L1KDqLdeMNirSsTBnVNrWsbxmKTqr3+9+T+hdLfeASWA38DzgJuApwCywDDQ1jLCtlkaNhtp2S1VVxXFUHAdxHEjukrnjpsdcxBiwESrpV2vGyEj3WPpUkydqVFqumI4HgK/wYCDcE1nnK78/43w7Qo4LRG9c6XyPAdZJ8U6i7TuAGxKhPx24KEP7vc8Iw1ibl1cyGr9CmGh+37GVFaK1HhOEq6vYdivV6q7WZzQ9xwbWWjpYWo6l4wgRYBEiBAtESCeCxyxyV4T8lcIXfFfnvUj45eX29xigRNudjPA3AJcDLwZeAlyBak1thIYhhAFqbWzjXQ/xPMR1cWY2xDTtd7B+B/GrGN9H/Q7aqWIrHaRSxVR8tFpFfR9brSK+j/E7aOCDVTAKKiASa7oIGEU0/n9ooGWsto2VqOt5Ss4LVagqsldhr8LNFu42oXwogE+/tzZxulG1vHkEEOT/EopPBV9LtPv5wMuw9pqosbYlmDsh/pHH8Q8dJDh+hOj0HHZtFQ18xHFxpqbxtu2gevGlVPdeTeWCi7ChxT9xnHBxoavdpSzQ9Qd6x4osQEbrgyjUtvXpEEmIFjW++5g/lrIDWAis8PUIftvC3wr4/3kICNx/wRTvJHcP2A5cC/yghuHzw8WFC9sHH3Wa93yTxr3fpPPwAwQnjmJXllG/DVGEoIl5FkQE47o4k5NUzruIiWc+l5mbXom3Z28cGvh+jwX8KraTskAHrVSxFR+ppmyRsID2WEBFiFDa1teOdiTCYpO/oKDxyfGBjIAKnoVnK3xC4QMR/M5bZ2sn/+tS+18mA5RQfOrQzQBXJPT+r6K11cta+x+ur9z+ZVa++kVaD9xHOHcC7XRAY6qXJKwzkqGP7nOJRaKKcV0qF+5m9uZXMfNvfoaw3aF9YD/h8hLR6tqYLNBGrSWKQtp+S1t+C6uRpEIu1/S8xqfPbRKTWsAKWTawEfyDFf69wMOihrcuN7/7ATDCi98DPAN4sVr7jGDu5KbVu+9i8da/Y+X2f6Tz+AFsq4GgGJFE8IJI72LkBU/ymmSeg6jFnd3I7I++mo2v+2UUQ2Pf/QQnjhOtrvVCwTIgrK4SrK7QbjVodhqEod/7baVCLlK9JOBgFADS57da4fWiPBIZeNti+7vTBJRouwfUgZ3AMxOH7rlq7U7/+FGz+NUvMP/Zv2T1G3cQzJ+KqV0EY2J6td00X+x8pcLVRBKSzf+JJrFZ/CBiCJeWWPw//xszvYFN//Y/MvOMZ9K45x6ajzyE6VQSJ7CDTanfr2E7HTqhrytrC/jtVvKBmd+Y0LrNUXue9m2R9nv0P+j4CxTeHwmvQTmS/T7nu1D4JhO6PRf4OeCXgddg7bXtY4dn5j77l/L4e3+b43/8Udbu/Rbh2mqs3cb0pNp36UFVuse6+d4MT4pk/xObC+20CY4dprrncmpXXEVl5y5MtUq4tIhttdAocfLCkNbCPIuPP8ryyaMSBZ0+9s3a+NQHsF2hZ5/3jvV8gx4AsgCxPVBcrFCN4PPPqbnR19rhdw8AMsJ3gC3Aq4D/F/h3wI3ADn9h3p37+7/hsXe/naOf+DBr++4lajVj4pYeuWvmamuJMVQkZxiLICmCABHsyjJYy+QNN2Kmpqls205l23ai5WXC5SU6C/Ocvu9bzN9/N52lRVBb/jvXKfgcAIQ8GMqPX6XwqMC9z5zwuL0VPvEBkBG+C+wC3gK8ObH11ajZYOG2r/DYe97BoY+8j5VvfwvbaibGWvoEmRWw5gSfEbZKARQFb6n7EanNUOzaCvXrn0Xlwt0xUqenqV98Ca35Ofvgxz9sFx950KgNKeAr9/cNFrz0sYMtRABlALBSjCDwVLg4Ev4aWL29/QQHQEH4FwD/HXg14Km1NB/bz+Mf/QD73/N2Tn/1i0Srq4n8pFR7VcgxgRZOygu6xEZIkQl6BUPttKjt2cvE9Td0XxTPY/Kyy2F2U3j07rt1rdES3/HwjUMkRiIxCSCzdn24xpdpv0pB6wcDABW2KxwUuPNpdfeJC4BE+JI4epcA/xP4UcAJV1c4+bef4eF3/AbH/uJP6Jw4AapdAWtBx1T6ta20kicF2k8FWar9BRBEEd7O85h67guRSrV3uuPI5muuM5uuuS6cv+++aO3kSScyLoE4+OLSMfHdF5fAuATGwYrBiohisJLmAyTx7KXPESyl/zJQxOeJwhYLnwaazhNc+C5wKfDbwA+ptabxyEMc+OB72H/LO1m+5240CHLKqhlJ6YAgNytQGRQJF8BUBEHfZ1nF3bKN6RfehJmcLn6hTD9pt7vred+nK/sf9VceO2DiyFJ6nr8IViQRvsGKgzUOagyIAWPikFUS75M0jVzQ+uHan/5/C/B14EHnCa75VwHvBG6Kmg058bnP8tBvv5Vjn/4UweJCX6tGn9eexu7pobxpzxyXHPPTFwFkQJCJCLq5g8QPcDZtYeZFL8OZ3VT622qbNzvnv/DFGrVb/vw933bUWhndTxB/USp8I4IrgmeEihGqxlAVwROJq1tJRquLy0x+IAVColhrgvy1+wQTfFb4TwXegepzm0ce5/CffIJDf/RRmocOxmlUYbCrrllLH2uJJKF8GudnAYFqXvJ9IFBsQicmpdf0s6R3ogYBGoRDf2dty5bK09/6W87Ezl2te97zzkpnackTY87omvUqyYKo4olQVTSKCYkQJQRCwFfFBwmBKAbDU0G3uE9Q4T8LeLeG4bWL37yTR9//Lk7+w98SNRq9X615wWfJoCsQ6SV5Sp05Lb6pJ3lJ6TIFk2hM1ZqPt7NvV5FeCrH/R8aFnyjCqDpX/exrJ6a3bu3c8Vtv1caJE5UzBYFNrp8FrGr3b1YUo0lbk2qcMVPVJDMoVnWHhfOcJ5Dw0wTP9wHvDNdWrz36mT/jwXf8BnP/+AVsp5MTXFaTpaeo+f/nwJFP9+bMQS40k377Ltnz8inh7nmqVC+6mNmX34yzYTYWeBRB4KPtFlFjFbuyTLS0SLQwT7hwWqY3bnQ37d7trxx6PGyePu2tt72sKHybCN+i2AQEVsmDo3fNa6je4z6BhO8BLwDe0z55fM/BT3yExz72AVpHj+SkKprR1wwTFLs3c5SfMEFceeu91s3sFphA0hCraA4UtIQJ0p9hNsxi6hMARGur2OW4umjbHbTTRjsdbPKonTa205EN01MTT7v5R/17/uLPm8cffLCWXIuzFr5Fk/9nX9euT6CqnsIl7hNI81+K6ttXHn7gkkfe/y6OfvpTBCvL5YInzwQygAnI0XMiXJW845hlla6w+x0B7eV8eiDI5Q8Ed+sOzMQkGoUEhx8nWlyMawF5oXfBkP7f8/3K1Tc8Q+qO6Rx84MFKFEXOMDboCjgj3LzGDxF+el782tPdJ4Dwq8ArNYresfDNO3c9+K7/wakv/D1RQvmS8fBzkVixnU7zQCmagFTYRSYYBIJe1aff19SENlTjeNwIiONRueBJmFqd8PQ8nUcfxjYbQwUf9w8EaBigUeg9afeFTkW0deDh/ZVOp+MWQaAZLR8mfJtcrxHCx8JO959Z+DXgNdbv/LcTt35u64PvfhuL37gztp3Su9hZn81oeR5Vct5/ni00AwIrYEhbr8YEQRaEGdqXxHaoVWR6kurFl4ExdB55CH//I4n2J4JPGkZskAg8jNAoRKMIjSKstWgUma2bN064l+4ODhx43G80214aoWqZfR9D+Knt7zsviVzdfybhO8AE8Kqo1fzNo3/zmY0PvOu3WHlwX87DKwpStBD+FDVe+tmiDARZczAIBLkQUbqZ/9znaWouVHG3bqe2ew/q+7Tuvgv/8EE0COPQMAx6go4i1EYZwfeea/yaTHpu5ZLzd3QOHTsZLDdalWHC79H9cOHnzusBYtL9ZxJ+HfgPYWPtzQc/+fGph275HRoHHxvu5esQwZN3DEX7Enal5oAxmEATEIhIzxGk4AAK1C69gsr5FxKcOEb7oX2ES0uxoGPNLhd+T+h9/3eiqHr+xqnIUdueb3Y8izolFF5w/NYRFcSAqLj/DMKfBd7kLy3+p4N/8rGph973v2gmnn6WxnWAABlC9bkQ7xwzgSbRAcWmC1VMrcbUU5+Os2Eja1/9Mu3jx5Imz4Jgi8IeCIakXVyts73uVQw2ONn0xaoaPROvf8DroMb9JxJ+2sGzCfh1f3npjY9+9P2Vhz/4bjqnTuXsPQUtlyH/LwVHIUQcBwRx0qRXO5AhTJCm8NO/VVVxt+9i6mnPhihi9c6v4a8ux59t+4Wf+38q8OyqIE0MS69U6WyuesYV6RxpdEw7sl4qyHEdv1JwxBfnO+cDlCy52gG8pXN67tWP/sHve498+L20M8JHy7W8WMQpo37KTPc6QWALIMgxQa6qmHBBtwAlTF51HRN7n0zn0EHW7vs2YaOBqu0Ttu1qdwRWUbVdQecf889VVaZdU71wshIebfrBSmBdi4qOKfwi/WvvPQvuP4HwPeA84Df9pcWfeOSj7zcPffDd+AsLSWK9RKharvXdrJwO+e5iTkD6wTQMBKK9foI0QWSzuQWJf1+cB1DMxCQbnvt83I2bWfjcZ2kdOVSg90S71cbZweTaFAXePZ6hwsI5UjfiXVivhIfxgwU/8iwq6xV+1zGMPzdw/wk0/3Lgf/pLCzc9/JH3mYc//F46Cwu58mpZcqcstcsQGy/DADECBP1JIS3Uf/NsICkTqFK/dC8zN9yIWsvybV/BX14CY2KQqCZC71HaGQg+pWsUcFD3gponnhAc74SOBUcHeP3DhG8VHOh8J30Ah7gv/x3B6sqL9//hR3joQ79HZ36uV7/XbDk1r/lmlJZLvzNY2vQxBgi6zzMgEFWsyTNB1z8gzgaaapWNz38x9T2X0TlyiJV77yaKYnofQud5IXcji149e9Q5As4OzxEXwiOdkJb2QDCuYwjgKUe+kwC4Bnhf2GzccOCTf8ADv/8u2onw+1K7BUEOC+O0hN51FAOM8AlyoElrBBKDQLO94tIDiFqoXngxm1/8Mkylyso37qR95HAMDmv7GHGYVqMDgDDsHDCbHFPxqm7nsXZg1xRv3HRw+vMNPO5+h+j/WcDvWd+//vHP/CkP3PJOmieO5/rss/a3TPgMcfBGefvrBcEg31PJgCCj/SKA67Lp+1/E5JXXoNay8OVbCTsdxHEyvYZ6ZoIvmIWC4HPnTwrVS6pueLAT+qcj66pihjmGueqbcsz9Dgj/+4APaBRdfuwLn2Pf+36H1cOPZ0KpDDVr/IdImTkoEbpmSmXrEWqfzS+cr4XmnzImEOnlCtQqtYsvZstLX4kzMUn7yGGWv3Fnov3aJ+RhdJ47ZwAoNKM1ZedUwL3YM3gQHAsjz8atAH0ZwezPdBRm9Bz5AJlY/2bgbcDuuW/czr2/+z9YfvgBMMlv1H5Pv1i9yxZ3yhI9A0O6s2CCXLGlPALtOoaKYipVttz0r5m57mkALH/jDlpHDiem35YwwFlQfla5dPDnGNS9wBHjqukcCq3bUXW1X/jd3+mCrSpt9xxq/vXA7wAXrOx/mH23/C9Of+tOsl9fRvvF/D5DwreBzts6QTDIfGhJc2nXMUx9AoX6nsvY/oofwZmcAmDpG3cSttvxhJA+wWcFNZzO1y34fh/D7DDUKq74j4bqN6xWKO+FwlP8yjk0AZPEizUuaM+f4oEP/i5HP/+32Mj2c6yWdesM8OYHMAHfISbI1/d7jRfZ6NCZmGDHK25m+snXAODPz7F421dj7bd61nS+3nOK0QUgs2j1ciOdA6r+olKRkss6oTQ9OO6eI+1/BfDSqN3iwF/8Hx77yz+JNUJ6jlOZg1fU/jKhFplAh9QAzsYn0LKIoBgiAhuufybb//WPYKo1AFbu/TZr+x+Nz7d2oI0/C63uhZPjnJM8n4TqpYbwoKU9r1Q0swzQAWpKQ2D+XDDAZuANam39yK2f44EPv4/WwgJiComWAgJFhydwyphgWEQwit4HCTaX6NH+5WKSqVNUt23n/J/+OSb3XNZ93/wXP0+wutKl/1LKH9OOK8OFOo7gs7+tAu4eg9Qt9qjihMlPqyjUlMiC754D7f9x4FlLD+3j/g+8h+UDj5Tm8vtq+YWUbpmHn3tegiY5RyFi1/OXAdoPiOuy7QdeytYX3oSYWJn8hdPMf/XLWJvks4cIcz0Cz047GVfgg24GnPMNTk3hcQvtmP5xIbAQuWcheIgXaL6pPT/n3v+RWzhxR2wLcxe+UJ/PmYGScEyGOX2F7M0gP4AR3n5OyFJu+9NscOq0Tj/5ai786Z+nsmlz9zNW7ruX1YcfxIqAteuj/CFaPQoUw4hy0LXbJlAx8JiFqdivWlRYdc9Q+OlkjtfYINi7/9N/yv5Pf4qw4yNmSJ6+jPbHsPGDMoBl54wb8mXz+2VgyAKhumkzF73qdWx4yvW59y/edQfB6iqIKdHqAQwwTPDZv7EkfCsLVdPnERBpbzqIEi8IibS3OigEpoB6/D1NOLMwMBX+tcBPnfrm19n3sQ/Rmp9HTK+HT0o0XEbk9XWcEm8JcEoTOgOSP4P8AJXyv0lcl+03vZxdr/gRjNeLqqJmg1Nf/DxRaBFHxg7rypxEzfbsky7syI14GSjowiiYTMdP7zOyz2cUXO0GOOOPiCks1Z4E3tg4fvRJ9374Fub33d93ZTUee9en7YOAMMwcjAMCO+T8su8YNCOgGKNufNoz2f3aN1LZsjX35648+AAL93w7HhhsbZx1K2h5ukJHc+yjubUE3YWbWrKYs+Rx2GsMCK1Nco4BJnr54AXOwAlMBzLdYIPglfv/+tM89rnPEoVh19Z3F2LogNBKxu/i0RFC7VubNwZoirSvAwypKtR3ncfu1/07Nlzz1L4L0VpYsPOLK9IJoqTZXMubVqFvANWQnhdKMDiwMCZljJfpVireKvFkyfR2XCA0Z6D9M8Br5u779qZ9f/gHtBeX8tSlvbSvFilX80gvuyAyREA6KGUrg8O8svfkhikVnqcnu9PTXPhTP8eOF78snvlbuE3vuVQnt++wYiHKaX+58FNNTB/77jJgkcuQhJkMcQLLzqlrXANIbseykdc4wk+1/3mdpcWbHvjjTzB37z1dbcnZnqzwS7wWHVHrZwwQlNL7AKDkqFYygh9gBsR12PmSl3PRz/w87tR0eepz1y4zu3evehbqErc99S1Nk7zAsyAoPpcBIJAxhC9jRAMmAUDmtgxjrkNL08dJ0uffHr3tH2ce+au/IPT9nv3JabfkmKDn7GQWOOhgCjwXILBlTFDUfCn//E1PfxZ73vArTJx/4WBbWKmy47k32tSv8SS+myECLGp9qYBluBaPE/qVvVZRqORnU9mRACi0c7vACxonjj9n35/8MStHj/acEu2lweO75kq/OadH+83BuQaBljGB5EeqZI9n7f70ZVdw6Zt+lQ1XX5evBCYzfUl6/QCZ3XuFmKqbp8h0hfgIbR5Xu2E8QIx6bUJzwo6AxXGjgLSxc7va6BcO3voP9cdv/TxqtVvmzXvl0l02qVmHRHqLKDTj5dkM9Y0TIo5yDLPfJSnMpT/cK8b+YqG2fQd7Xv8f2P7Cl3TtvoYhmgx37lJX0is+vWuX1jdvCRonTlSymmsGCEYKdY+ydMioxyEplIE3F6jntb8DnBgKgILjVwFeuXr02DP2feqTNObnemVdKWRWhO7SaTJLsLPHsq/JOQDBINha7Q/3tCQsRcHbtJGLX/tGzv+hH8NU4njftltECwtoGOQ93MS21SYm3JndFweNYycGTlzUASAoY69xBbreW812Y//0tgbMj8MAqfafr9a++tBXvugeuf02rI2HbvYt3MzG2ZphgMIyqiwDaAEE5ypE7EvuyIBoQ8GdmODCm3+ai1/zerwNszFHrq4QHD2C+p1S4atVxBjZcsUVevxrXxvq1EYMT4Z9J2+mX/shLgk0BgIgo/0e8QreH147fuzKB//yz2kvLna1K9eZK/m2p6y2a251TYF+C0wgA9igLKU7tLmzbABk0U9QcGo1Lnjlj3PpG36ZapLsCedP4e9/FNtplws/eS5iZPbCC8WpepENAochqds0W+dmLroyIicx5mvDwFfX2AEseak8E1iydv8y4FWHb/uac/i2jPYnwjPZXKvk/aYsCKz2NDznIBbMQfFcKROsltvNgc5jIU+c0r7xPHa+6Ae5/Bd/jckLd4MqwZFDtPfdh3bavetRcleNB8hNbZx1ahs22MbcvCNSLvzsFQ/pjTaXAbn9YfmP9QAlzfyVsM5awgJDTUA1Sfn+ZGdp6dL9f/PXNOfnchOyyDw3BaEgJWYgywTkncCcUDMgKO0nKJgDO4L2ixlIVTCuy84X/SBX/upbmN5zOVhL+8F9tO/9VryHwAjhp2zg2chs2LkraJyaH5mQSu8+8b5zRTbIhsrjgmBYwajaH/qltzkpMwGFsK9GvLDj5QsPPsDcXV/HFSHsXpis5kk8eKEwN0czDmGZdkN/bh7tB8Ewx9Cegc03rsu2G1/Alf/xvzD75GvRKKJ9z7do3vHVePCkJp29NpPSTH5zusSLrhkQM7V5k2FE5a5/54/YJKRAMIOylkMofxgYZLD2k0QAHR3AAJIIfwb4GRv4Tzr2j1/CP3WSquchUUQQRViNc99G+p2+7I9MfYO0GJFzAtOMhPZeKwOBDPAJKDiZZbmAXKinII7D9u//V1z95t9g47XXo0FA4ytfoHnn11A/yNn4+ItsQfjkct0iwvTMtBrXWLXWjBJ8UaChxmYh3d9GhqSwGcNkpNe/qlC1A9l9SSFysgAohH114u3TXtY6cZL5O27HiUI81+1+WRBF8WKD3KLJQm5d8zn29CtStiiCILtTB8VBjAOYAEPplFAtCfXEc9n+vBdy1a/9NzY95WnYTpu1v/87Gl/7UrxTWNaByTVzaO5LcsdFmJiaNNWJCdtaXTPIeILXQgUworeY0gx477iPI7S/mwV8XQkDpNq/ibjVa+vyg/toPPoIFceBwhTuIIq6o++FPOWnHr1NR6gV1gOWgSCldJGSMW/96zW7YJMBvgIF2t/xgh/g6l97K5uuvR7baLD0mU/RvONruaVcvfq99oUtWprOBNdxzNTG2bC5ujaSwsuErxmpdOjteCUDnMlRj5XBtr/LAFltL4Z9E8CzgRdqGLJ8z7fR1ZVY+5Ou1ywLBmq7TGAKIBjEBOm5g0BQFJ6UmQ7pz/Nn29C6GFAw1SrnveilXPUr/5mN1zyVcOE0i3/+SRp33dGXo86u1MkKWpUBxxRBzOTsrHDoiKar3Yc5gWXCz/4/He+aAmGUOcn+aQJMRiPzDcdyAMhEDTVgK/ATwGywvMzaQ/twVVHXhSjqK/XGTGCT5dCZvHsJCLLJHpthAilxDDOJxT5HUYZs5JDLDyiYWo0LX/bDXPUr/4WZy64gXFpk/uMfpvHNu3KbAqn2a73mWoi0sJInX/+dmpkWcRy1NpKhTqCOYIZC909Y4hvokHJ33ZbG/dlbCBzvAqBE+5+T3OmcOEZ49AgV1+nN1k+7XAoXPYxszifIOnApG5kCCLIXMOvs5QZDST7FIJmMYlkdVDKFpsrMDLtv/hn2vv6XmN69B//YEU79wYdo3nM32XV6+eyS5lmgZA1fFiip1lU8Tyr1mm2uNQb7ATqkR2GA2bAZ/8CUACH72Y7mOn6GAWCxyACp9m8j3pRhEqBz+BAsL1Nx3bhaQmY0Wkk8EoMgXo/WFUgmUrAjQEB+Y67yFict7yoqNpLUt29nz0+9lstf+ybq23fSPniAEx98L83770OM5DpwR2l4/7F8ezYKRq2p1Wu2sdYYSPvjhIiDXk+BYEoSX1ntd0cXEzSbOnELBZ8XpNqvUUjn8CGM30kAEJU7Mqqo9rKgRSawGcGaAgiKzl63ETPzKJpPNBaZILsAJdX+qYt2c+UbfoXdP/LTVDbM0nzgfo6995209j9Crm2ZMsFn/YHRgu+ygCC1WjV1b6RM+HoGgi8zC8Wikip4WprzL7t10jpAFgBp4ufZSQYQ2/EJ5ubideROzyfV7BJnLXe8wyiOmW2JdveNfymAgKzwB9S6i4Dpzg0yhs1PuZ4rX/8rnP+SV+DWJ1i58zaO3fJu2gcfi3PYfcLU8tCv4AxqXw4739ItwES1aowRokyXL2PSvTJ+/sDSPzxzMhq7u6dRNAHZXbUPpJ+tnQ5Rs4Gp1lDaeEkWO+sg9znGGRiEkcamoACCNGTLzgXI7dI5qI6e9fClP6p1alV2Pu8FXPWLb2bbM56DOC7Lt/0jh97+m/gnTyTCL4vxe0LtO7YOk0DSFeR6rg39XmGo6PGfidYPNAup8G2u2XPULU1A9kUBAhxOXqzYwAcb4UxOxvvVtJrJewvKUfCN4nn6EQIEUZgDgRZ8gtyiUCk4fvRif8kwQq6RMd1DfdMmLvmRn2Tvz76RmUv3IqrM/81fceT33oV/8ni3dt3v9OlwX6CMBUrCxC4LqJqq60YtPxgq/LMVfNahdIxQh3ixwHg3PytIlwFVU40iMA4mAQCq0G7lzEB2Vm6vCzbKxeFZEEgmNSwZMOTaqYvt5eSbK/NlY2Hmkj1c8epfYM+PvZralq1oFHHqM3/O4+98G8HiIpITfl7QOkSYfUAZdm7vP1J3HVnMvPWcCz7LvgKVikF8XU8ryWJSDewCQDO04HVT9iI4tTrO5BQiic4ZgzabeMUlNln7LYW9NyTOGFpr+yd/FsAgA1qjU7ro1gw0pvxdz34eV7/+l9h14wtwanU08Dn6sY9w+L2/G28XKzK2nS+1/f1p8v56drGEaowYRCNUzrngC99VcQ2ea+I5DOPfTgKtIgOECTXUEn8AcV2cqakEANLbJku1+3bNTepOd+KO4n16JGNxEnRZa/tHv2a0O5vEMWUhYhJVTG7bxiU/9KM8+Wdfz+zlVyDGEDUbHPnQ+zl0y7uJmk0kmdVXkOTgpgod3WKhQw+kfoCIa4yGUST6HRB8qv3GESqV+KpFZrw+o2TU1akvVoz//X6UA0Cahq53FbdSxZ2dxZ2aIjKmsPGyQLNBhfyeO90t2Ir76SRD733ADtg312YoPlcKziivW/HY9pSncvVr38CTXvJyqhvj7dmixhr73/abHPv4R+P+PZG0c3dswY3stBlysFiG9RyjrSg6J6Ff7pwM9dcqDiaZYK7S868GCl/SvY6k8/zA8gsFBrCJfCa7eeFqBW/zFpypqUT4xTytQquVy8D1snaZRJD0nEIVCKKYCcpWdNqMT5BtPDHA5I4dXPKyH+LKn/k5tl7zFExSmQwWTnPgnW/n6Mf/d1zRG7Q2SkcLb5Ta63jNWFJ3HFlOHO1zIviCQ1nzHFynp/XWgBpBShxBybGzIIIfZ9uiviggwNrJWLYWcT0q23fgbNjQX4bLJuVbLYQgtytX70vBiI01O5PSDYBoDBBYhcpEjV3PfBZXvern2P0DL6U6u7Hnzs6d4qG3/DonP/3nmRgz75/ouF10OuqMUeajd2WqjmBENFKVM3UCB6WQXddQ8Uyh5N2/S2pXBkhXFsnzE11PGnBjR0m5f+ukvXzfYwYboWGEMz1NZecuvE2b4wURJT8/RVbUakJA70voIc5ImPPqsn/nQBBYcFyHzZddxuWvvJm9N/84G/dclluj13r8IA+95f/h1Of+ptBhOlrgug7V13V0YaY/xRMRV0TDBADjCn6U8I0RahVTWha3RnCShFRG23MgMPEeN8eyUugywEWf+iuCw4es2gjCkGhmA94FF1HddR621SpvzMv9Jc38RG8Tb3Mq0p/QSd8ehBBmQKA2/pFTu3ZyyYtfwpN/8lXsfPozcGv13Fc3D+xn36/9EvNfurU7rqVYHF2v4EpP1DFdgewnJJFKxTG0rF13lm9g8Six+44ZvDN6KnST0/yu7ceI+EkUkAfA8p/9MebyZ+Mf+IaH2jiX6xzD3bKV+sV7CE6fplh+EYk3Mw7JgyDudpXuBovQX7jJMoGGEEVxZD+1fRsXfd/3c+XNP8YFz72RemYcS3pbuffb3P+rv8TSXXckU7ntWFLS8Q38eL5BbiBEf1GyZkSXzyYCKFQOq56D58pgY+RI4qr1FC8LAhM/t5J0A+cAEJ44ASf/0lVkFo23N9UwxN22nfr1z6C++2Kajzyco/4odQxVCXN/UhM3cYBksEva7bETz+Bu28SuG57FFT/8b3jS81/I5NZtJX4HLN/9Te77T7/I0jfuQlynZP35uMLLpn9Z100HGf/CORURkWRDsTPN8qWve66h6pmhvyNyBCOkgi5QfxcMVuKQPw8A/8hhEPGAjaSbHCXLoerXPpWJy/di223ahx9P+b1vP/Uw5xg2cYOgNERKUqaYiTozOy5m+w3P5sIXv4Rdz7yBiS1bGbCHrs7ffrve/e9/wbQffRhxTDKTdx2C0/HgMTwEHDNkJG3yFEJ03Vm+7DmOEeoVp6/cXebuizExADKefx4QrAmy2AeA4MhhEKrATAoAoojw5AmmHn2I+nXXM/nkqxHHoX34UH7ea0YtQqGXL2g2cLvtQwZ1FHGqVDdvpnbRbjY94wa2P/d5bHry1VRnZko1PmvYH/3DP5UHv3UvtZrLpFWqJt5GXf4ZYv1R74vrFUrFiLaj8R3B4jkiQr3q9OpYQ744SqZMGM05fcUwcFmEEgCcPEGSBJqJ+Seu6WMjmnfeTv266/E2b2bquqfibtxE67ED+CePEyLdnTHSHvMwOyqEeI/7ytQ07nnnM3nlVcxc91Rm9l5Jbfu23NClfnVV0j3bWydOyuLXvoEnNZaDNqsBuCLUjGHCMT0wSL+2jis4HdeA6Jg+BUhVcnWysbN86bFaJR/vD0OdTVqqnbgzPfED+sLA0yK9OkAXANbvpC1h1ZzaRRFrd3yV2Zt/AmfjJpzJSSYu30tl5078EyfwTxzDnztFuLhItLZG1Gqivh/TfKWKO7OBys6d1C7aTe38C/C2bMFUqoVfnPThJ+vv0y3W1cYsJCIs3P511h47yISp4xMQEhGp0ogimlGEI0LNxICoGMEdsNL4XMX648QREnfYiKG3OHScLF93VU/FoeLJWLDstt0nDECX+gu5APBFpN8HsL04X4qdMa0Dj9K87x6mn/f98QmOg7dxE97sRiYuvRTb6cS7Ywc+ai1iDOJ5mGoNU60irttN0KiNYoAke+qR7qCV7KrVNT/J7lpEEajl5Oe/RLDWwHEc6lRpaDPnZFpVmpHSjCyOgBcDQqsi4ogM6ZA9hyFjCaO4IK6gYcERHJblU6DiGWqeM4TFtE/4AKFRjO13AqXHCGExW+IC8T433R4NzZfGGw1Wvnwr08+5sddUkeb8XQ/H9bpj07t18+4kjTDeIDnKCzvW8KymDwKCJVhdZe6Ou7o/vIJHBweb6U3IgwE6qnSsigE8I1oRoSLgCmLG1Gw9ByFjsrZeW4VW8WEt4q5jqFWcZF/isR2VeKsYAyYJz7NhYMYXmDOIbzOfkTBABHFHcDXXDJGUQlfvugP/5HEqO8/rs9Wpw6hRGOfiwyijxXltLgq7FAiZ9wjK2iMHaBw5BibZrAFDVSq0tTV0VEp6qXyr4icZMlfQikjcuUMJGEbYjPUOb5DYpo4tfMckTl/GmRmH+rsMIBon4Po1P00SHVO6e2FlABAzwIzG5eC+RRKdY8do3HM3lR274l2wuztghxCGGRBkBG4H03oPABnNL2EEUWX+rrvpLK/kIo8KLmGGBWSAjhQjhEARX7tgwAWtFMBwrm+exMo8anGIMUK96iaZvvVRf9qTGIrGAzpzmp9zAo8BvGRxrmACYgaoQrbXowd722ryyC3v58qdF1DduCHeFTsV4kABZ2nd5hhh8Gu9EFStxfo+83ffH4Mj00cuCJ54BBoN1LxhtKwxGPBBWsmoo4rEbdHJpK9zMsgjGdmOC9rJdgoXh1xIHOvHHv/6qD8fCcQFMSf5BSUp4WbxPVkGGJg0WWl3WPzybcz80Sd50k/eHA9OSjS2K7xh2lzKDENeiyJQpXFynuWDRzLtv72kioODFYOlvL9AdHzKjkCa8fRkNQqeoNUYFOKcJRgcoCrQ1vJET5rj91wztrh1wB67NikNm0JBLsMA4QAAWABHsx+deIGRKvOrTSS0HPvs37H1GU+hunE2pv+Mxg6k/qGAiM8rMx+osvTwATqrje7qIs1YUUFwcJM2hhJdkcwqopKKXZm50GT1Q5g0PRmFiqC1hBmc/oLmWH5AjcxqzIIpqHlOJs27furPN9VovN4yhUAmDDRx+DdfCoDEBMygONk/QoClVoe1js+MqdA4fIRTt36J8154IzYIysO2Pm3OMkM5U3Tj/zQfkEQSCweOxOyUW3XfM1Ex2Rm0wAI5IpVyJ15GEKwSq0ugcSO9UbQi2BqYqnSXccs4c3pqghiNG3eLsX6t4ozQ+fVUNqAjNuME5moBASKLRY3ImoCNSTKo2/ceWctCs53MwxFsFHH8y19l06VPwqvXY88/1dispheBkA5ZjJJNlDPC7h/DEpeH/WabtbnFkqXfWqgvOEgGADqMNnWM8XIDwJGYCScFQ1Ww9TjbJ94IMHjJPch8XtXLCv/sqD97JMQmoWC2MpjmQkSLKfdsGLhJCxmRpbZPKwi7zgRGWD18lPm7vsW2q6+IfYHUnmdi9z5tzgrXav+xvuFLytrJeVrLa4n9tzn7Xxw3Ld1FZ8PpflTMPq7ORSANxVlLmQHshKB1kIr0Gug04wfU6K3H8twk1h9ZbxiP+rO8GIhNegJMMQzsiLCmpSYgZoBN2U/zrWWpHfRtdmBDy9w997Nx55a4cjdCm7vHbMmx4vClFDDA0tE5ojBMc5Mlgs+uUhbMOAQq/e1b6yPagQ6k01A0cfhsTWACnGpmdnA1+W7PNdSrTkYR1yv84YDuEGGTbGihM2hF4j0CygEgsCH7gSudED+yuS6eeCSLsHz0BCuHjrJh51Y0skO1uQuQ4oStLjD6ARF2ApZPLg68PJpfoI4lSX6M2+h5RlZ2tL+X+AzOatIVVI2BwFQSYlYdQ7Wb6Dmb4LL8uBCPrteUAXJNISwIsjIwDBTp5UL8yLLqRxlNkZz1DX2fUw/vZ2rDZK6oM0zwWQ0feh5KY2GN1mqrwN9lC9M1Y6Pjnrj1XsqBexCc5S0CGhovwTmtsE0ctrkua6J99YRzQf3dbCCWANuj/l5iaAWkVfwM9x92bUYJUdWu3VoJLGHGITDkW5EUYfHoCRoXncfk7HTPyStqeZ8PMOBY4b46v0IYhBlLOtwMgOaWTQ9cTaPrA8awcSzjfqYAs+KyQTycSHADZdmN4qTNulpMxrtZlA4RTlK3ybaD5d3gBABqwrRHawKgEymNwlKjYlJFRfFbbU4fPka9dlGvlDtoqOJQM9Cbwq0JS6wuNdCceAfZ/3xtLZ3COU659Uw0flhtf5ADulk8thq3G5rNWIMXGRacgGBEELle7e9FApqYmSQEjH2B1aRBqd8EoNZFZKMCq2FmXf/A4Cv+osUTc2zbvhHPc+Px8SMof5ADmD3Wboc0VtvFumSfBzDINESUTNDQ0cIadz3esAJhLrePsNW4bBavWJBh2ho8hHknoC32nFB/9uo0NOj2BGTCwOOhNYFjohIAiHgCs83I0gxtCY31d6OqQGOtweLJebZu3ZgAIE3iDHEKs8utS1bZrq62CYKotHKuJT8+yxDpKtfsZC10/GEM6zUJWp5AwiBsMx6bjFfamGFEmMLgWYcTTocW0Rl7/WW3DvEKbScJBRMAHKs4cPXjj/YDwAj1wDK9EtiBe/0WXTBNGknmT55m40QVYySzeXJG6Nnq4ohNkVWVlZVOvJx8Hfa/JGmTM1vjCn9dTDBA+z2E7U6FDeL2t2UVyrMTIlyghhPSZqU3s2Fsr3/QkUCjZA5TJgxE5ss+xU00vNYMo+lONLg7QinpwhVhZa3J6soqM5P17qi4Qduf9m2qXJjN4wcRjWZQMup9tP3PO0L9Gb9hgl6PXR8GnooYdpgKM8btW5JlCos0UhDUxOUCJjlOiwU6Z0H9mb4AjRXRkZ4jKFJeNXNPdyIQnFaong7xZcvW3SgQRcrppTUmqpWCkPNTNoZuq56c1mwG+IEdot1lnoiOdNhGhXzrZgSlD3A1MexyqkyK21eKLenOzXjnsaAuZAoPh5PaPKO9AXJ9AVg6hMxINRnOJRaR1VIArIZ2ZBiTJf+yJUlLa022bJii6rmZDaPyI1n6AdA/f6/RDBMzoUPi/35e0JLee+1fJzpyyOJYjFAy8WtaXHY4VeomzvsVhW7KF2nmKNqIcAGTVNRw1DaIsOukfs0xQEtDHDFpg4iPxHsElZoA4tUineEQYEBODtpByMJqg20bprrbpRaFO1jzNUkPKM1mMMTxG23/GaHhZ20SShzKjcZju1PFS3rxTEHTy5ZpFY9n/YLzzRRV43AwXMHHFrLX42UNFPA1ikPB2AFtAHPDALAGnAYuLWusQKWP+vtCwrUmGyZqcQIi4wsUBT1oS/RWO0roX0v0nLHtfxG79gxYgAGaXwzztjgVtjiVrrdt+vPvJUu1Cp069Pfw7zSTVMThQLhMU8MzSA8rK5GfmCKDCE1BlnUIABrEE8JuKP/4Yavs41dbfsBaq8N0rdIdIAkUvP8BziFKqxURWR2g3TrA/o9nG+1Z+gUU9kCoiGGHU2XW8ca283kwlJuB7Dnb3UlqxuOhYIEV2xm4o9ogVmiluYD471FhgBMooaKuRGXdIoPxVRJ6qbLYaFF3nVzkQGFH7ZzmpxVGGzNA/2cPtv9ZoAz13qV8G5axQVB475SJ7f2kcQdqcNnxPlNQwgZFEG1yalxjtvKAf5rTUWtd1UvfhkQo1XiUagvELzvP/Pxqd+3/48MoJvuv/GIpa50OzU6AjSxRFBFFNrlHmccod8xGliCICEJdl/3XEc3cSv8swrL5u2XPcxth09sWZ7NT4SJ3giknzu7Fd5PcpXAvO545ZgQn/b8RnL5zYp9ixqlxTW0bO9zJsWMDAZo2oG1DjDGImHljZK2sCpkdEfPtxBGsDqoD6BD6USCwluV2G7deG+zwlcT/HV81HiB2Du1/SVOIHaH9lGh8N753a2wwHs4we97V9v7MX3Fkiylfv9/HEkaEaVPluvoOHuyc5pC/jB3qACfLxVF8orhnQzgpIu2ytfBZABwh3lF62zg5gHJAwKofMOPFGkLGFyiNDBIgdHxJIthy+89Z2P/iFnNDTYH2A2PaeOx0a0wYpzSRY4Y6fQy184Mdw/5jdeNxzcR2qsblkfZpou4VK1eHSC1rGiCOAWFewyh0PHckAA4UAaDDcgAljx0bseYHTLluLjNYpvmqirUQhM7QIo+Oaf9H5zPG03gFPDFsdapscSq4xpQMXTo3dr4sS1iWNzASm4yrJrZSMw77Wqfw1RZAkG8RX47aMQCQSDxhx923DwXAEvC1skhg3E0M4wHGykoQUE1KSGUFn+yxMDJqrUhRDGdi/4c5g0VfgCGO4bRx2enWmDRuaWiX9/BzTRdDwkD6unXHAlHfOYYrJrZRdzzubhynZcPkd/X3v3c0Qo2J8wADKkwG4HWL3QUjn6O4ekR7TpItOEw2IxCbPhNo2ohWGOYcPltw/tLnQTgo072+/P84CSEn/T1a/ls8Mexy6+yuTDLteF1HzJQ4aE7iyHWPm4zDZ6T8nIzTl57rmJ5j6OTOzZyTfW/yuXvqm3nOzEXMOFXKSngCNKMgXjLuOMezE9YGMQDA14FvkWwaQWlzRcH+Sr9tjVDWbISLyU3Zzo5jVxRVIbJmhHbr+LP+xkiVONLfn+8gzDoe290qE91CDufUzptSB2+IszjIhCSPiHB+bRbXdblz+RCng2bfIK6ODQlFqThOyw4YhuQWir6LwKfKAaD5vXhHOFQNjZi0Gu8mmqESzZV/HbUqA7R7tBkYaf91AOVlKoaTxmWHW2Um6+EPSOQMFuRwwKzHzg9+X+Z4OqLPGHZ5s3yfV+O2xcc43l7O7bPQCDs0bcCUMxHqgBG9XfV73WJ3F5HPAg9lnQlNlhypxKNILOX3LKX6QENtj+5D228CrCnsBrjeMHA8+1+kRlfAM4btXo3dlUlmE0evR7HpvRevO2IKFG0ydN+jbadgBspyAc6wY6b3/6x5SM8TYxDHSe4GdQybalPcuO0yLp7aQrbnL7QRHY0Cx3XnYmdwtAkAeBT4IPAOjRW4u/3bOE5gVhhrolRsPBWsP/2LquOW2P/xw8D12P8e5AXPdTCuQyjCnAY4CC49R83DUBGDm6yycyQ+5hKDgkRjU8YwI6KA4XmDfkYosg4iiEk03xjEpMdMlwk2eJM8d8deqvMHeGjpeKy0alkJWm3XdU9GoY4GwOsWm3xo4wTAx4AXAz9gGV/4RRPRNtBWSyUqmckvLiKODHfyBpuB9dp/NQKug3Gc7lJzH6U4wyu7F48kDo6gOMmyazcRiIvgpVqPUBWXmnGoGCcBjaFqHDycLrgkwxTDKoXpMVK6NykATPy8+5iAIAFE3a3yrJ2XM1mpc/fcQQIbMddaXcOY02MzQAKC08DbFK6xsHNkGCj9g1rT4y1H1AttfwxiXAvifMftv8SCF9cp3YpcSoRf9leEqr1FqFqeEDPd/sm4K9cVgycGV+KVQJ4YasalblyqEtcSKuJQdzzqxsVLwOMag2uceNqHiSMFSe8Z4acj+XqMEAPxqTv34Hkudx3fTyPsBB0N2+GA/gJ30NWrOdGXWqH76yK8xyozg7S8rEycfWx5wqQv6mg+EI37UIc1PJ1Z/N89ZgR1HdQpF/x6Om60Dyzlqeb4b4gvtFUlwNLUsiuT31XFSMwmaQuXJzGTIPHzCbfChFuh5lYwYvAclwmvQt2tUnE9xAqO4+AZDzcBzLU79jBZnWDf3CG949hDeMYdHwCvW2zx4Y0TWjX8kbW61cJ/jVSmekLXsRNEHSPS8sRO+RkAiFG69D9KyOuw/wLWGKzjoI4ZNHzyrBov1xuKSi4RLSXXK57BEKrty3Fm9wWUzJ56QpwzqBhPXeMEjpiO65i1mlsNZmuTOl2daBkxpycqteiijduP7F841nTFGZohLb19eOMEruA1La/xld+ysHUc548CU9RDtduaoUj6m0wlEnc62SDEYuPRBpmUUny3hf/nU06ZSp4RIuNgXYMas24PYVhX4fpeW19fv3R7VjSIhzcJBulI3L+3HGq0pEpUddzIEXPaiDml2BNrQWfBMUanK/W2wEnXOAutMFw4vtZob6h5bKpP+g8vNVbnG6G9ac+T7Isue7J/fGVZr/zyV9YHgBQEUwZzOuImX/n/Ini6Frb0GfjY2/5NtzdDWw/VAVTcSYupOXmBjiP4FCxgRbDGEDkG6xj0DBdc6hAt17G0X5ItDqwPqCOiItISZE1hMdRoVcBWjetb9FTHhquuOFo3bsuIHHdETrZscLIZBZ0NXp1pt9YwIgsTrrc611lrLgcte/XG8/Wa868Mdtz62Yjf/zPkDTdzrm5jXbU/3DLBcR/qhp0+vClSXmNhVykbSP+lssAG30ZbW5FBjIo7o4jj5AWvjGKDSJTIgSgRvMrZznIqDpsQBEIBX9FGhLYNoq4YX2DBCAuh2lOB2kbVuFTEWTXIcSOcXI38uUhtsMGt6aTjrXjiLHnGrB7qLLcMotdO7bDXb9obPP7Nv7V7P9hBfqHKE+G2rit4y+wEHphVuC6EH7PKSxUuU0kniwxmBE81Om8tooIL7rQBkWHab7FEYomMEpp4GHJkGCn0OF8loUDHog2FjonniLQFFkSYC1TnFO1UxKhBltoanRQIJowbumJOOzBvYWEp6qzVjWu3OPWoZty1rV69fe3Mxf7a8a/rlt9YRt4kfLffzugX3LKxTlWQJSs7Ldyocb7gKcDuCCY03cRa8oLZ0o7C2aBmcOpOzAw9WrdiCSUiEiU01oZG/choOgjQF6QBLFt0CfAdxBqVJQOnVDjpY+cdJKpifIPMOcjpEF1sEDYnxdUZ8YKqOGs7TK29p7IzXAvn9eITj/F/++2sIfx7GyfYAO5q7CBeEcIlFs4zcKWBy5IZCUZgohJpbapdi0Qqq6GJwpAwUOycFXs8NHq07djTBrUGmqFwPBLWqla0otJ0kNMGltqia4FouNV6ep6tBU8Jt4fL0uH81sN877b+2/8Prqk5f/cNbQ4AAABJdEVYdGNvbW1lbnQARmlsZSBzb3VyY2U6IGh0dHA6Ly9jb21tb25zLndpa2ltZWRpYS5vcmcvd2lraS9GaWxlOlJ1YnlfbG9nby5wbmfRrEvyAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDEyLTExLTEzVDEyOjQ3OjA2KzAwOjAwhERbHAAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMi0xMS0xM1QxMjo0NzowNiswMDowMPUZ46AAAABGdEVYdHNvZnR3YXJlAEltYWdlTWFnaWNrIDYuNi45LTcgMjAxMi0wOC0xNyBRMTYgaHR0cDovL3d3dy5pbWFnZW1hZ2ljay5vcmecvblIAAAAGHRFWHRUaHVtYjo6RG9jdW1lbnQ6OlBhZ2VzADGn/7svAAAAGHRFWHRUaHVtYjo6SW1hZ2U6OmhlaWdodAA5OTYGfuckAAAAF3RFWHRUaHVtYjo6SW1hZ2U6OldpZHRoADk5NUPb5RMAAAAZdEVYdFRodW1iOjpNaW1ldHlwZQBpbWFnZS9wbmc/slZOAAAAF3RFWHRUaHVtYjo6TVRpbWUAMTM1MjgxMDgyNpOSGLMAAAASdEVYdFRodW1iOjpTaXplADE5N0tCQhlJFDQAAAAzdEVYdFRodW1iOjpVUkkAZmlsZTovLy90bXAvbG9jYWxjb3B5X2VlNzBiNTEyMjExNy0xLnBuZ6uX/8EAAAAASUVORK5CYII="}}],"tool_call_id":"call_GJWyfgk8ZwNJc1mQhKnHh93g"}],"stream":false,"tools":[{"type":"function","function":{"name":"content_returning","description":"Returns + a Content object with text and attachments","parameters":{"type":"object","properties":{"query":{"type":"string","description":"Query + to process"}},"required":["query"]}}}]}' + headers: + User-Agent: + - Faraday v2.13.3 + Authorization: + - Bearer + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 400 + message: Bad Request + headers: + Content-Length: + - '238' + Content-Type: + - application/json; charset=utf-8 + Request-Id: + - "" + Apim-Request-Id: + - 86192b8e-a4e8-4bfe-9489-bdd000d2b02a + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Ratelimit-Remaining-Tokens: + - '36013' + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '366' + X-Ratelimit-Limit-Tokens: + - '40000' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ratelimit-Limit-Requests: + - '400' + Api-Supported-Versions: + - '1' + X-Envoy-Upstream-Service-Time: + - '416' + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:51 GMT + body: + encoding: UTF-8 + string: '{"error":{"message":"Invalid ''messages[2]''. Image URLs are only allowed + for messages with role ''user'', but this message with role ''tool'' contains + an image URL.","type":"invalid_request_error","param":"messages[2]","code":"invalid_value"}}' + recorded_at: Wed, 08 Oct 2025 20:45:51 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_1_azure_openai_azure-gpt-4o_supports_handling_streaming_error_chunks.yml b/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_1_azure_openai_azure-gpt-4o_supports_handling_streaming_error_chunks.yml new file mode 100644 index 000000000..051a09985 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_1_azure_openai_azure-gpt-4o_supports_handling_streaming_error_chunks.yml @@ -0,0 +1,89 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Count + from 1 to 3"}],"stream":true,"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - 71d0e9c4-7764-4487-937e-952cabde4f82 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '399' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39995' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:58:30 GMT + body: + encoding: UTF-8 + string: |+ + data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}]} + + data: {"choices":[{"content_filter_results":{},"delta":{"content":"","refusal":null,"role":"assistant"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957110,"id":"chatcmpl-COVWwSfKpF3G4uie3DntRK97LgON1","model":"gpt-4o-2024-08-06","obfuscation":"d4UQJ4s","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"1"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957110,"id":"chatcmpl-COVWwSfKpF3G4uie3DntRK97LgON1","model":"gpt-4o-2024-08-06","obfuscation":"n55fBdeU","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":","},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957110,"id":"chatcmpl-COVWwSfKpF3G4uie3DntRK97LgON1","model":"gpt-4o-2024-08-06","obfuscation":"y2xL1tLJ","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" "},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957110,"id":"chatcmpl-COVWwSfKpF3G4uie3DntRK97LgON1","model":"gpt-4o-2024-08-06","obfuscation":"smwpVNrM","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"2"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957110,"id":"chatcmpl-COVWwSfKpF3G4uie3DntRK97LgON1","model":"gpt-4o-2024-08-06","obfuscation":"1G8Ou6Cn","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":","},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957110,"id":"chatcmpl-COVWwSfKpF3G4uie3DntRK97LgON1","model":"gpt-4o-2024-08-06","obfuscation":"Ja1k5K3f","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" "},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957110,"id":"chatcmpl-COVWwSfKpF3G4uie3DntRK97LgON1","model":"gpt-4o-2024-08-06","obfuscation":"HO3EcfrT","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"3"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957110,"id":"chatcmpl-COVWwSfKpF3G4uie3DntRK97LgON1","model":"gpt-4o-2024-08-06","obfuscation":"5IVHVOwE","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"stop","index":0,"logprobs":null}],"created":1759957110,"id":"chatcmpl-COVWwSfKpF3G4uie3DntRK97LgON1","model":"gpt-4o-2024-08-06","obfuscation":"9WF","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[],"created":1759957110,"id":"chatcmpl-COVWwSfKpF3G4uie3DntRK97LgON1","model":"gpt-4o-2024-08-06","obfuscation":"Q4N2PqZ69","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":8,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":14,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":22}} + + data: [DONE] + + recorded_at: Wed, 08 Oct 2025 20:58:30 GMT +recorded_with: VCR 6.3.1 +... diff --git a/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_1_azure_openai_azure-gpt-4o_supports_handling_streaming_error_events.yml b/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_1_azure_openai_azure-gpt-4o_supports_handling_streaming_error_events.yml new file mode 100644 index 000000000..ce40889b0 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_1_azure_openai_azure-gpt-4o_supports_handling_streaming_error_events.yml @@ -0,0 +1,89 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Count + from 1 to 3"}],"stream":true,"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - ff8ff412-a0de-4aa0-9307-b16b70ddf33b + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '398' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39990' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:58:31 GMT + body: + encoding: UTF-8 + string: |+ + data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}]} + + data: {"choices":[{"content_filter_results":{},"delta":{"content":"","refusal":null,"role":"assistant"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxnA42Kyk6pwiENIhzu0eRO2B4","model":"gpt-4o-2024-08-06","obfuscation":"SlmfJlb","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"1"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxnA42Kyk6pwiENIhzu0eRO2B4","model":"gpt-4o-2024-08-06","obfuscation":"bzkJ9Gto","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":","},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxnA42Kyk6pwiENIhzu0eRO2B4","model":"gpt-4o-2024-08-06","obfuscation":"9qGDwOmQ","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" "},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxnA42Kyk6pwiENIhzu0eRO2B4","model":"gpt-4o-2024-08-06","obfuscation":"ZnnJaFNr","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"2"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxnA42Kyk6pwiENIhzu0eRO2B4","model":"gpt-4o-2024-08-06","obfuscation":"QrGLo7By","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":","},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxnA42Kyk6pwiENIhzu0eRO2B4","model":"gpt-4o-2024-08-06","obfuscation":"IaHLkX7w","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" "},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxnA42Kyk6pwiENIhzu0eRO2B4","model":"gpt-4o-2024-08-06","obfuscation":"gp2psUBW","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"3"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxnA42Kyk6pwiENIhzu0eRO2B4","model":"gpt-4o-2024-08-06","obfuscation":"Vcu0s2UZ","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"stop","index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxnA42Kyk6pwiENIhzu0eRO2B4","model":"gpt-4o-2024-08-06","obfuscation":"PrU","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[],"created":1759957111,"id":"chatcmpl-COVWxnA42Kyk6pwiENIhzu0eRO2B4","model":"gpt-4o-2024-08-06","obfuscation":"dV4Uof7x1","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":8,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":14,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":22}} + + data: [DONE] + + recorded_at: Wed, 08 Oct 2025 20:58:31 GMT +recorded_with: VCR 6.3.1 +... diff --git a/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_2_azure_openai_azure-gpt-4o_supports_handling_streaming_error_chunks.yml b/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_2_azure_openai_azure-gpt-4o_supports_handling_streaming_error_chunks.yml new file mode 100644 index 000000000..a0d1cd5ab --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_2_azure_openai_azure-gpt-4o_supports_handling_streaming_error_chunks.yml @@ -0,0 +1,89 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Count + from 1 to 3"}],"stream":true,"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - ab364091-5840-4601-b1b9-da7d6080f848 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '397' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39985' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:58:30 GMT + body: + encoding: UTF-8 + string: |+ + data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}]} + + data: {"choices":[{"content_filter_results":{},"delta":{"content":"","refusal":null,"role":"assistant"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxZyBdfKNEjAO5N35UY9no5c9k","model":"gpt-4o-2024-08-06","obfuscation":"tTdtYy4","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"1"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxZyBdfKNEjAO5N35UY9no5c9k","model":"gpt-4o-2024-08-06","obfuscation":"K8oBT8RV","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":","},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxZyBdfKNEjAO5N35UY9no5c9k","model":"gpt-4o-2024-08-06","obfuscation":"wdvPWgqQ","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" "},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxZyBdfKNEjAO5N35UY9no5c9k","model":"gpt-4o-2024-08-06","obfuscation":"ivJ3LhRY","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"2"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxZyBdfKNEjAO5N35UY9no5c9k","model":"gpt-4o-2024-08-06","obfuscation":"brkHInmB","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":","},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxZyBdfKNEjAO5N35UY9no5c9k","model":"gpt-4o-2024-08-06","obfuscation":"kHqa8hqQ","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" "},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxZyBdfKNEjAO5N35UY9no5c9k","model":"gpt-4o-2024-08-06","obfuscation":"VCWvrvWb","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"3"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxZyBdfKNEjAO5N35UY9no5c9k","model":"gpt-4o-2024-08-06","obfuscation":"oCi7jjfR","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"stop","index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWxZyBdfKNEjAO5N35UY9no5c9k","model":"gpt-4o-2024-08-06","obfuscation":"7fj","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[],"created":1759957111,"id":"chatcmpl-COVWxZyBdfKNEjAO5N35UY9no5c9k","model":"gpt-4o-2024-08-06","obfuscation":"AOWgAAEJB","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":8,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":14,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":22}} + + data: [DONE] + + recorded_at: Wed, 08 Oct 2025 20:58:31 GMT +recorded_with: VCR 6.3.1 +... diff --git a/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_2_azure_openai_azure-gpt-4o_supports_handling_streaming_error_events.yml b/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_2_azure_openai_azure-gpt-4o_supports_handling_streaming_error_events.yml new file mode 100644 index 000000000..8457ef8bf --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_faraday_version_2_azure_openai_azure-gpt-4o_supports_handling_streaming_error_events.yml @@ -0,0 +1,89 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Count + from 1 to 3"}],"stream":true,"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - 677a6b52-8321-4b01-8cf5-944665e9e69e + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '396' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39980' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:58:31 GMT + body: + encoding: UTF-8 + string: |+ + data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}]} + + data: {"choices":[{"content_filter_results":{},"delta":{"content":"","refusal":null,"role":"assistant"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWx72UhERO28JDS0afHyAREWWQa","model":"gpt-4o-2024-08-06","obfuscation":"gS6DHsb","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"1"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWx72UhERO28JDS0afHyAREWWQa","model":"gpt-4o-2024-08-06","obfuscation":"ZHV1tgwv","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":","},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWx72UhERO28JDS0afHyAREWWQa","model":"gpt-4o-2024-08-06","obfuscation":"QDBOG8DK","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" "},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWx72UhERO28JDS0afHyAREWWQa","model":"gpt-4o-2024-08-06","obfuscation":"cyL1peKp","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"2"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWx72UhERO28JDS0afHyAREWWQa","model":"gpt-4o-2024-08-06","obfuscation":"yDCkroPR","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":","},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWx72UhERO28JDS0afHyAREWWQa","model":"gpt-4o-2024-08-06","obfuscation":"MnH7Wink","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" "},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWx72UhERO28JDS0afHyAREWWQa","model":"gpt-4o-2024-08-06","obfuscation":"o63g0xHl","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"3"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWx72UhERO28JDS0afHyAREWWQa","model":"gpt-4o-2024-08-06","obfuscation":"mYWRIXKH","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"stop","index":0,"logprobs":null}],"created":1759957111,"id":"chatcmpl-COVWx72UhERO28JDS0afHyAREWWQa","model":"gpt-4o-2024-08-06","obfuscation":"Gge","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[],"created":1759957111,"id":"chatcmpl-COVWx72UhERO28JDS0afHyAREWWQa","model":"gpt-4o-2024-08-06","obfuscation":"Kvymo3Ddy","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":8,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":14,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":22}} + + data: [DONE] + + recorded_at: Wed, 08 Oct 2025 20:58:32 GMT +recorded_with: VCR 6.3.1 +... diff --git a/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_raises_appropriate_auth_error.yml b/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_raises_appropriate_auth_error.yml new file mode 100644 index 000000000..f126a4750 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_error_handling_with_azure_openai_azure-gpt-4o_raises_appropriate_auth_error.yml @@ -0,0 +1,39 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Hello"}],"stream":false}' + headers: + User-Agent: + - Faraday v2.13.3 + Authorization: + - Bearer invalid-key + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 401 + message: PermissionDenied + headers: + Content-Length: + - '224' + Content-Type: + - application/json + Apim-Request-Id: + - 221e9473-d4a7-4a4f-91b4-75baf0a16224 + Date: + - Wed, 08 Oct 2025 20:45:27 GMT + body: + encoding: UTF-8 + string: '{"error":{"code":"401","message":"Access denied due to invalid subscription + key or wrong API endpoint. Make sure to provide a valid key for an active + subscription and use a correct regional API endpoint for your resource."}}' + recorded_at: Wed, 08 Oct 2025 20:45:28 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_handle_multiple_tool_calls_in_a_single_response.yml b/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_handle_multiple_tool_calls_in_a_single_response.yml new file mode 100644 index 000000000..490b32415 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_handle_multiple_tool_calls_in_a_single_response.yml @@ -0,0 +1,137 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"developer","content":"You + must call the dice_roll tool exactly 3 times when asked to roll dice 3 times."},{"role":"user","content":"Roll + the dice 3 times"}],"stream":false,"tools":[{"type":"function","function":{"name":"dice_roll","description":"Rolls + a single six-sided die and returns the result","parameters":{"type":"object","properties":{},"required":[]}}}]}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1190' + Content-Type: + - application/json + Apim-Request-Id: + - 543e5ad9-1448-4f09-a928-cb861a1855e7 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '369' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '37245' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d097-20251003093454 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:49 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{},"finish_reason":"tool_calls","index":0,"logprobs":null,"message":{"annotations":[],"content":null,"refusal":null,"role":"assistant","tool_calls":[{"function":{"arguments":"{}","name":"dice_roll"},"id":"call_wfa4iyphieUXx5RBmdLMwXHn","type":"function"},{"function":{"arguments":"{}","name":"dice_roll"},"id":"call_ZjV2t2cF6jgXoR9I1YvvNSMs","type":"function"},{"function":{"arguments":"{}","name":"dice_roll"},"id":"call_F0VTAwvY3c0cMyEz0akEGqBh","type":"function"}]}}],"created":1759956348,"id":"chatcmpl-COVKensAxsDoBLlKIvO1sPpatzsHy","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":54,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":68,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":122}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:49 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"developer","content":"You + must call the dice_roll tool exactly 3 times when asked to roll dice 3 times."},{"role":"user","content":"Roll + the dice 3 times"},{"role":"assistant","tool_calls":[{"id":"call_wfa4iyphieUXx5RBmdLMwXHn","type":"function","function":{"name":"dice_roll","arguments":"{}"}},{"id":"call_ZjV2t2cF6jgXoR9I1YvvNSMs","type":"function","function":{"name":"dice_roll","arguments":"{}"}},{"id":"call_F0VTAwvY3c0cMyEz0akEGqBh","type":"function","function":{"name":"dice_roll","arguments":"{}"}}]},{"role":"tool","content":"{roll: + 1}","tool_call_id":"call_wfa4iyphieUXx5RBmdLMwXHn"},{"role":"tool","content":"{roll: + 2}","tool_call_id":"call_ZjV2t2cF6jgXoR9I1YvvNSMs"},{"role":"tool","content":"{roll: + 3}","tool_call_id":"call_F0VTAwvY3c0cMyEz0akEGqBh"}],"stream":false,"tools":[{"type":"function","function":{"name":"dice_roll","description":"Rolls + a single six-sided die and returns the result","parameters":{"type":"object","properties":{},"required":[]}}}]}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1089' + Content-Type: + - application/json + Apim-Request-Id: + - c4760668-6f28-4a1b-8e57-d1962205b008 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '368' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '37163' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d097-20251003093454 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:49 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"The + results of the three dice rolls are: 1, 2, and 3.","refusal":null,"role":"assistant"}}],"created":1759956349,"id":"chatcmpl-COVKf3MucvngfkKx4mvVlUlFv4eQB","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":21,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":151,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":172}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:49 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools.yml b/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools.yml new file mode 100644 index 000000000..d779fc0e6 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools.yml @@ -0,0 +1,135 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + the weather in Berlin? (52.5200, 13.4050)"}],"stream":false,"tools":[{"type":"function","function":{"name":"weather","description":"Gets + current weather for a location","parameters":{"type":"object","properties":{"latitude":{"type":"string","description":"Latitude + (e.g., 52.5200)"},"longitude":{"type":"string","description":"Longitude (e.g., + 13.4050)"}},"required":["latitude","longitude"]}}}]}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1026' + Content-Type: + - application/json + Apim-Request-Id: + - a96c3c13-f2cd-4636-870c-7cc80bf5ed33 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '385' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '38844' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d076-20251003014048 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:39 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{},"finish_reason":"tool_calls","index":0,"logprobs":null,"message":{"annotations":[],"content":null,"refusal":null,"role":"assistant","tool_calls":[{"function":{"arguments":"{\"latitude\":\"52.5200\",\"longitude\":\"13.4050\"}","name":"weather"},"id":"call_HcbqUiCrcfhCHj2iPJzN11U0","type":"function"}]}}],"created":1759956340,"id":"chatcmpl-COVKWWq211AQUh3XfrCgDc9hHMPF6","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":24,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":88,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":112}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:40 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + the weather in Berlin? (52.5200, 13.4050)"},{"role":"assistant","tool_calls":[{"id":"call_HcbqUiCrcfhCHj2iPJzN11U0","type":"function","function":{"name":"weather","arguments":"{\"latitude\":\"52.5200\",\"longitude\":\"13.4050\"}"}}]},{"role":"tool","content":"Current + weather at 52.5200, 13.4050: 15°C, Wind: 10 km/h","tool_call_id":"call_HcbqUiCrcfhCHj2iPJzN11U0"}],"stream":false,"tools":[{"type":"function","function":{"name":"weather","description":"Gets + current weather for a location","parameters":{"type":"object","properties":{"latitude":{"type":"string","description":"Latitude + (e.g., 52.5200)"},"longitude":{"type":"string","description":"Longitude (e.g., + 13.4050)"}},"required":["latitude","longitude"]}}}]}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1104' + Content-Type: + - application/json + Apim-Request-Id: + - 29176800-72bb-4da1-a78f-f48070a2829d + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '384' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '38734' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d076-20251003014048 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:40 GMT + body: + encoding: ASCII-8BIT + string: !binary |- + eyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZmluaXNoX3JlYXNvbiI6InN0b3AiLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGwsIm1lc3NhZ2UiOnsiYW5ub3RhdGlvbnMiOltdLCJjb250ZW50IjoiVGhlIGN1cnJlbnQgd2VhdGhlciBpbiBCZXJsaW4gaXMgMTXCsEMgd2l0aCBhIHdpbmQgc3BlZWQgb2YgMTAga20vaC4iLCJyZWZ1c2FsIjpudWxsLCJyb2xlIjoiYXNzaXN0YW50In19XSwiY3JlYXRlZCI6MTc1OTk1NjM0MCwiaWQiOiJjaGF0Y21wbC1DT1ZLV3AzN2R1MVJwQnJ4RGZ0WnRQZmxDeFg5QyIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24iLCJwcm9tcHRfZmlsdGVyX3Jlc3VsdHMiOlt7InByb21wdF9pbmRleCI6MCwiY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX19XSwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjp7ImNvbXBsZXRpb25fdG9rZW5zIjoyMSwiY29tcGxldGlvbl90b2tlbnNfZGV0YWlscyI6eyJhY2NlcHRlZF9wcmVkaWN0aW9uX3Rva2VucyI6MCwiYXVkaW9fdG9rZW5zIjowLCJyZWFzb25pbmdfdG9rZW5zIjowLCJyZWplY3RlZF9wcmVkaWN0aW9uX3Rva2VucyI6MH0sInByb21wdF90b2tlbnMiOjE0MywicHJvbXB0X3Rva2Vuc19kZXRhaWxzIjp7ImF1ZGlvX3Rva2VucyI6MCwiY2FjaGVkX3Rva2VucyI6MH0sInRvdGFsX3Rva2VucyI6MTY0fX0K + recorded_at: Wed, 08 Oct 2025 20:45:40 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_in_multi-turn_conversations.yml b/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_in_multi-turn_conversations.yml new file mode 100644 index 000000000..e0821cdb8 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_in_multi-turn_conversations.yml @@ -0,0 +1,273 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + the weather in Berlin? (52.5200, 13.4050)"}],"stream":false,"tools":[{"type":"function","function":{"name":"weather","description":"Gets + current weather for a location","parameters":{"type":"object","properties":{"latitude":{"type":"string","description":"Latitude + (e.g., 52.5200)"},"longitude":{"type":"string","description":"Longitude (e.g., + 13.4050)"}},"required":["latitude","longitude"]}}}]}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1026' + Content-Type: + - application/json + Apim-Request-Id: + - 733bf410-bd54-4b7f-a55c-785a4c71a94b + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '383' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '38639' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d076-20251003014048 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:40 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{},"finish_reason":"tool_calls","index":0,"logprobs":null,"message":{"annotations":[],"content":null,"refusal":null,"role":"assistant","tool_calls":[{"function":{"arguments":"{\"latitude\":\"52.5200\",\"longitude\":\"13.4050\"}","name":"weather"},"id":"call_J56cldK7JI94L8VcQrwWMjdA","type":"function"}]}}],"created":1759956341,"id":"chatcmpl-COVKXo9Jg49Oq4PbyQ29ErCNrMrIa","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":24,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":88,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":112}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:41 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + the weather in Berlin? (52.5200, 13.4050)"},{"role":"assistant","tool_calls":[{"id":"call_J56cldK7JI94L8VcQrwWMjdA","type":"function","function":{"name":"weather","arguments":"{\"latitude\":\"52.5200\",\"longitude\":\"13.4050\"}"}}]},{"role":"tool","content":"Current + weather at 52.5200, 13.4050: 15°C, Wind: 10 km/h","tool_call_id":"call_J56cldK7JI94L8VcQrwWMjdA"}],"stream":false,"tools":[{"type":"function","function":{"name":"weather","description":"Gets + current weather for a location","parameters":{"type":"object","properties":{"latitude":{"type":"string","description":"Latitude + (e.g., 52.5200)"},"longitude":{"type":"string","description":"Longitude (e.g., + 13.4050)"}},"required":["latitude","longitude"]}}}]}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1104' + Content-Type: + - application/json + Apim-Request-Id: + - 6a4b1542-a769-47ef-9c75-2832cdeeb77e + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '382' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '38529' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d076-20251003014048 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:42 GMT + body: + encoding: ASCII-8BIT + string: !binary |- + eyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZmluaXNoX3JlYXNvbiI6InN0b3AiLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGwsIm1lc3NhZ2UiOnsiYW5ub3RhdGlvbnMiOltdLCJjb250ZW50IjoiVGhlIGN1cnJlbnQgd2VhdGhlciBpbiBCZXJsaW4gaXMgMTXCsEMgd2l0aCBhIHdpbmQgc3BlZWQgb2YgMTAga20vaC4iLCJyZWZ1c2FsIjpudWxsLCJyb2xlIjoiYXNzaXN0YW50In19XSwiY3JlYXRlZCI6MTc1OTk1NjM0MSwiaWQiOiJjaGF0Y21wbC1DT1ZLWFhrclI2WXhPelFhaUlucXJvT1ZYTU91MiIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24iLCJwcm9tcHRfZmlsdGVyX3Jlc3VsdHMiOlt7InByb21wdF9pbmRleCI6MCwiY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX19XSwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjp7ImNvbXBsZXRpb25fdG9rZW5zIjoyMSwiY29tcGxldGlvbl90b2tlbnNfZGV0YWlscyI6eyJhY2NlcHRlZF9wcmVkaWN0aW9uX3Rva2VucyI6MCwiYXVkaW9fdG9rZW5zIjowLCJyZWFzb25pbmdfdG9rZW5zIjowLCJyZWplY3RlZF9wcmVkaWN0aW9uX3Rva2VucyI6MH0sInByb21wdF90b2tlbnMiOjE0MywicHJvbXB0X3Rva2Vuc19kZXRhaWxzIjp7ImF1ZGlvX3Rva2VucyI6MCwiY2FjaGVkX3Rva2VucyI6MH0sInRvdGFsX3Rva2VucyI6MTY0fX0K + recorded_at: Wed, 08 Oct 2025 20:45:42 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + the weather in Berlin? (52.5200, 13.4050)"},{"role":"assistant","tool_calls":[{"id":"call_J56cldK7JI94L8VcQrwWMjdA","type":"function","function":{"name":"weather","arguments":"{\"latitude\":\"52.5200\",\"longitude\":\"13.4050\"}"}}]},{"role":"tool","content":"Current + weather at 52.5200, 13.4050: 15°C, Wind: 10 km/h","tool_call_id":"call_J56cldK7JI94L8VcQrwWMjdA"},{"role":"assistant","content":"The + current weather in Berlin is 15°C with a wind speed of 10 km/h."},{"role":"user","content":"What''s + the weather in Paris? (48.8575, 2.3514)"}],"stream":false,"tools":[{"type":"function","function":{"name":"weather","description":"Gets + current weather for a location","parameters":{"type":"object","properties":{"latitude":{"type":"string","description":"Latitude + (e.g., 52.5200)"},"longitude":{"type":"string","description":"Longitude (e.g., + 13.4050)"}},"required":["latitude","longitude"]}}}]}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1026' + Content-Type: + - application/json + Apim-Request-Id: + - 792768a4-f727-4490-8599-751ba4c08e9f + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '381' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '38390' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d076-20251003014048 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:41 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{},"finish_reason":"tool_calls","index":0,"logprobs":null,"message":{"annotations":[],"content":null,"refusal":null,"role":"assistant","tool_calls":[{"function":{"arguments":"{\"latitude\":\"48.8575\",\"longitude\":\"2.3514\"}","name":"weather"},"id":"call_UuhpLcQkx505BtqYSYFAra8b","type":"function"}]}}],"created":1759956342,"id":"chatcmpl-COVKYrcMxAQJbA6T5xhwR4K07wmUZ","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":24,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":188,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":212}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:42 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + the weather in Berlin? (52.5200, 13.4050)"},{"role":"assistant","tool_calls":[{"id":"call_J56cldK7JI94L8VcQrwWMjdA","type":"function","function":{"name":"weather","arguments":"{\"latitude\":\"52.5200\",\"longitude\":\"13.4050\"}"}}]},{"role":"tool","content":"Current + weather at 52.5200, 13.4050: 15°C, Wind: 10 km/h","tool_call_id":"call_J56cldK7JI94L8VcQrwWMjdA"},{"role":"assistant","content":"The + current weather in Berlin is 15°C with a wind speed of 10 km/h."},{"role":"user","content":"What''s + the weather in Paris? (48.8575, 2.3514)"},{"role":"assistant","tool_calls":[{"id":"call_UuhpLcQkx505BtqYSYFAra8b","type":"function","function":{"name":"weather","arguments":"{\"latitude\":\"48.8575\",\"longitude\":\"2.3514\"}"}}]},{"role":"tool","content":"Current + weather at 48.8575, 2.3514: 15°C, Wind: 10 km/h","tool_call_id":"call_UuhpLcQkx505BtqYSYFAra8b"}],"stream":false,"tools":[{"type":"function","function":{"name":"weather","description":"Gets + current weather for a location","parameters":{"type":"object","properties":{"latitude":{"type":"string","description":"Latitude + (e.g., 52.5200)"},"longitude":{"type":"string","description":"Longitude (e.g., + 13.4050)"}},"required":["latitude","longitude"]}}}]}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1103' + Content-Type: + - application/json + Apim-Request-Id: + - e6c97247-625b-4640-ada2-5f6387314aa5 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '380' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '38237' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d076-20251003014048 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:42 GMT + body: + encoding: ASCII-8BIT + string: !binary |- + eyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZmluaXNoX3JlYXNvbiI6InN0b3AiLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGwsIm1lc3NhZ2UiOnsiYW5ub3RhdGlvbnMiOltdLCJjb250ZW50IjoiVGhlIGN1cnJlbnQgd2VhdGhlciBpbiBQYXJpcyBpcyAxNcKwQyB3aXRoIGEgd2luZCBzcGVlZCBvZiAxMCBrbS9oLiIsInJlZnVzYWwiOm51bGwsInJvbGUiOiJhc3Npc3RhbnQifX1dLCJjcmVhdGVkIjoxNzU5OTU2MzQyLCJpZCI6ImNoYXRjbXBsLUNPVktZNjU1a3UwdmdiVGozelY4MHFLVXJ4RzZ0IiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbiIsInByb21wdF9maWx0ZXJfcmVzdWx0cyI6W3sicHJvbXB0X2luZGV4IjowLCJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fX1dLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOnsiY29tcGxldGlvbl90b2tlbnMiOjIxLCJjb21wbGV0aW9uX3Rva2Vuc19kZXRhaWxzIjp7ImFjY2VwdGVkX3ByZWRpY3Rpb25fdG9rZW5zIjowLCJhdWRpb190b2tlbnMiOjAsInJlYXNvbmluZ190b2tlbnMiOjAsInJlamVjdGVkX3ByZWRpY3Rpb25fdG9rZW5zIjowfSwicHJvbXB0X3Rva2VucyI6MjQzLCJwcm9tcHRfdG9rZW5zX2RldGFpbHMiOnsiYXVkaW9fdG9rZW5zIjowLCJjYWNoZWRfdG9rZW5zIjowfSwidG90YWxfdG9rZW5zIjoyNjR9fQo= + recorded_at: Wed, 08 Oct 2025 20:45:43 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_with_multi-turn_streaming_conversations.yml b/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_with_multi-turn_streaming_conversations.yml new file mode 100644 index 000000000..e47166164 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_with_multi-turn_streaming_conversations.yml @@ -0,0 +1,351 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + the weather in Berlin? (52.5200, 13.4050)"}],"stream":true,"tools":[{"type":"function","function":{"name":"weather","description":"Gets + current weather for a location","parameters":{"type":"object","properties":{"latitude":{"type":"string","description":"Latitude + (e.g., 52.5200)"},"longitude":{"type":"string","description":"Longitude (e.g., + 13.4050)"}},"required":["latitude","longitude"]}}}],"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - 1018b535-dae2-4fa8-b736-f0911457140d + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '373' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '37730' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d076-20251003014048 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:46 GMT + body: + encoding: UTF-8 + string: |+ + data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}]} + + data: {"choices":[{"content_filter_results":{},"delta":{"content":null,"refusal":null,"role":"assistant","tool_calls":[{"function":{"arguments":"","name":"weather"},"id":"call_J4dQW8HbxjIx7wLczWtLOYdJ","index":0,"type":"function"}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"OHkWUF","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"{\""},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"11STFjSbq34r","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"latitude"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"ZDGVi7X","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"\":\""},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"b562KNfuES","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"52"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"QNeP7jd4zzFMA","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"."},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"2JoXMLRKYniMmD","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"520"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"L5s3Ahf3a2aF","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"0"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"lbyyfVvZQdNQu7","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"\",\""},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"9zhSChbxT4","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"longitude"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"d7wrhu","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"\":\""},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"MtZyvrXmzR","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"13"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"LIzYsZYGsqHvU","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"."},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"8N8JWeWAgli51g","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"405"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"F22NN1Octotz","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"0"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"z3a3MymLYI2qKy","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"\"}"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"GYqeuIqxgBTC","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"tool_calls","index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"hbtdC15jWEdef","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[],"created":1759956346,"id":"chatcmpl-COVKcSSovjAV7WtldjlZijnj4rvS0","model":"gpt-4o-2024-08-06","obfuscation":"8znLdNk","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":24,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":88,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":112}} + + data: [DONE] + + recorded_at: Wed, 08 Oct 2025 20:45:46 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + the weather in Berlin? (52.5200, 13.4050)"},{"role":"assistant","tool_calls":[{"id":"call_J4dQW8HbxjIx7wLczWtLOYdJ","type":"function","function":{"name":"weather","arguments":"{\"latitude\":\"52.5200\",\"longitude\":\"13.4050\"}"}}]},{"role":"tool","content":"Current + weather at 52.5200, 13.4050: 15°C, Wind: 10 km/h","tool_call_id":"call_J4dQW8HbxjIx7wLczWtLOYdJ"}],"stream":true,"tools":[{"type":"function","function":{"name":"weather","description":"Gets + current weather for a location","parameters":{"type":"object","properties":{"latitude":{"type":"string","description":"Latitude + (e.g., 52.5200)"},"longitude":{"type":"string","description":"Longitude (e.g., + 13.4050)"}},"required":["latitude","longitude"]}}}],"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - 1db75197-e23b-45cf-8036-4af3f05b0c4e + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '372' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '37620' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d076-20251003014048 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:46 GMT + body: + encoding: ASCII-8BIT + string: !binary |- + ZGF0YTogeyJjaG9pY2VzIjpbXSwiY3JlYXRlZCI6MCwiaWQiOiIiLCJtb2RlbCI6IiIsIm9iamVjdCI6IiIsInByb21wdF9maWx0ZXJfcmVzdWx0cyI6W3sicHJvbXB0X2luZGV4IjowLCJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fX1dfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7fSwiZGVsdGEiOnsiY29udGVudCI6IiIsInJlZnVzYWwiOm51bGwsInJvbGUiOiJhc3Npc3RhbnQifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDcsImlkIjoiY2hhdGNtcGwtQ09WS2Q0emhpb0xqUWpEM3kyQlp3WHk2SXU0UWgiLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJMUDZkUXNDIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IlRoZSJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0NywiaWQiOiJjaGF0Y21wbC1DT1ZLZDR6aGlvTGpRakQzeTJCWndYeTZJdTRRaCIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6IlAya0dwSiIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIgY3VycmVudCJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0NywiaWQiOiJjaGF0Y21wbC1DT1ZLZDR6aGlvTGpRakQzeTJCWndYeTZJdTRRaCIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6IjUiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiIHdlYXRoZXIifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDcsImlkIjoiY2hhdGNtcGwtQ09WS2Q0emhpb0xqUWpEM3kyQlp3WHk2SXU0UWgiLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJaIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IiBpbiJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0NywiaWQiOiJjaGF0Y21wbC1DT1ZLZDR6aGlvTGpRakQzeTJCWndYeTZJdTRRaCIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6IldHWEJYaCIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIgQmVybGluIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiQVUiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiICgifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDcsImlkIjoiY2hhdGNtcGwtQ09WS2Q0emhpb0xqUWpEM3kyQlp3WHk2SXU0UWgiLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJCZTJmam9nIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IjUyIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiNWQ2UUJUTiIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIuIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoieHczQkJTZVoiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiNTIwIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoidXd4djI1Iiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IjAifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDcsImlkIjoiY2hhdGNtcGwtQ09WS2Q0emhpb0xqUWpEM3kyQlp3WHk2SXU0UWgiLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJzNkZ2QjNoTSIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIsIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiWVNpTm91SDIiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiICJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0NywiaWQiOiJjaGF0Y21wbC1DT1ZLZDR6aGlvTGpRakQzeTJCWndYeTZJdTRRaCIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6IkM4Rnd5Uks4Iiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IjEzIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiNmhJTjR2YiIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIuIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoidGFlTFZzckoiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiNDA1In0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiY0NRWW15Iiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IjAifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDcsImlkIjoiY2hhdGNtcGwtQ09WS2Q0emhpb0xqUWpEM3kyQlp3WHk2SXU0UWgiLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJzYzR4NFhRNyIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIpIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiWWc0SjJZc2wiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiIGlzIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoic2tsZUZzIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IiAifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDcsImlkIjoiY2hhdGNtcGwtQ09WS2Q0emhpb0xqUWpEM3kyQlp3WHk2SXU0UWgiLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJIeFdWVWZtVyIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIxNSJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0NywiaWQiOiJjaGF0Y21wbC1DT1ZLZDR6aGlvTGpRakQzeTJCWndYeTZJdTRRaCIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6ImFIeEh1N1YiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiwrBDIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiYkVOMGJrdiIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIgd2l0aCJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0NywiaWQiOiJjaGF0Y21wbC1DT1ZLZDR6aGlvTGpRakQzeTJCWndYeTZJdTRRaCIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6InpPOTAiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiIGEifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDcsImlkIjoiY2hhdGNtcGwtQ09WS2Q0emhpb0xqUWpEM3kyQlp3WHk2SXU0UWgiLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiI3R1ZTZE5EIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IiB3aW5kIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiUzBrWiIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIgc3BlZWQifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDcsImlkIjoiY2hhdGNtcGwtQ09WS2Q0emhpb0xqUWpEM3kyQlp3WHk2SXU0UWgiLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJWQW8iLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiIG9mIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiTVBUZGVFIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IiAifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDcsImlkIjoiY2hhdGNtcGwtQ09WS2Q0emhpb0xqUWpEM3kyQlp3WHk2SXU0UWgiLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJleFVJUzdTSyIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIxMCJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0NywiaWQiOiJjaGF0Y21wbC1DT1ZLZDR6aGlvTGpRakQzeTJCWndYeTZJdTRRaCIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6IlpuN2VQM1QiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiIGttIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoic3VvRzBQIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6Ii9oIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoic3RNZ1lZMiIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIuIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiUVZRR2dMTzIiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnt9LCJkZWx0YSI6e30sImZpbmlzaF9yZWFzb24iOiJzdG9wIiwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDcsImlkIjoiY2hhdGNtcGwtQ09WS2Q0emhpb0xqUWpEM3kyQlp3WHk2SXU0UWgiLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJIdnAiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOltdLCJjcmVhdGVkIjoxNzU5OTU2MzQ3LCJpZCI6ImNoYXRjbXBsLUNPVktkNHpoaW9MalFqRDN5MkJad1h5Nkl1NFFoIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiWkVuSmdJIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjp7ImNvbXBsZXRpb25fdG9rZW5zIjozMywiY29tcGxldGlvbl90b2tlbnNfZGV0YWlscyI6eyJhY2NlcHRlZF9wcmVkaWN0aW9uX3Rva2VucyI6MCwiYXVkaW9fdG9rZW5zIjowLCJyZWFzb25pbmdfdG9rZW5zIjowLCJyZWplY3RlZF9wcmVkaWN0aW9uX3Rva2VucyI6MH0sInByb21wdF90b2tlbnMiOjE0MywicHJvbXB0X3Rva2Vuc19kZXRhaWxzIjp7ImF1ZGlvX3Rva2VucyI6MCwiY2FjaGVkX3Rva2VucyI6MH0sInRvdGFsX3Rva2VucyI6MTc2fX0KCmRhdGE6IFtET05FXQoK + recorded_at: Wed, 08 Oct 2025 20:45:47 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + the weather in Berlin? (52.5200, 13.4050)"},{"role":"assistant","tool_calls":[{"id":"call_J4dQW8HbxjIx7wLczWtLOYdJ","type":"function","function":{"name":"weather","arguments":"{\"latitude\":\"52.5200\",\"longitude\":\"13.4050\"}"}}]},{"role":"tool","content":"Current + weather at 52.5200, 13.4050: 15°C, Wind: 10 km/h","tool_call_id":"call_J4dQW8HbxjIx7wLczWtLOYdJ"},{"role":"assistant","content":"The + current weather in Berlin (52.5200, 13.4050) is 15°C with a wind speed of + 10 km/h."},{"role":"user","content":"What''s the weather in Paris? (48.8575, + 2.3514)"}],"stream":true,"tools":[{"type":"function","function":{"name":"weather","description":"Gets + current weather for a location","parameters":{"type":"object","properties":{"latitude":{"type":"string","description":"Latitude + (e.g., 52.5200)"},"longitude":{"type":"string","description":"Longitude (e.g., + 13.4050)"}},"required":["latitude","longitude"]}}}],"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - 1ed485ce-6fcb-4f3e-ab09-4ecfcf4acbf1 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '371' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '37476' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d076-20251003014048 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:47 GMT + body: + encoding: UTF-8 + string: |+ + data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}]} + + data: {"choices":[{"content_filter_results":{},"delta":{"content":null,"refusal":null,"role":"assistant","tool_calls":[{"function":{"arguments":"","name":"weather"},"id":"call_L2kkdcCzrtlYBctN9hwI6kgD","index":0,"type":"function"}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"op3U7S","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"{\""},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"ELGKmeSwp3aQ","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"latitude"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"5ksJBZj","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"\":\""},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"yAx8DR9v8i","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"48"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"4a2zymnECEPYJ","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"."},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"6Umsk1mwGzAYXQ","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"857"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"5zO1HngBLVuY","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"5"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"LcII322hcvEF6S","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"\",\""},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"IO22QoLPwH","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"longitude"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"1RYpb3","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"\":\""},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"pGzrll3YUa","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"2"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"ZHyMWv0zmDtuHD","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"."},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"Qlnn9EOJ9SDZij","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"351"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"8AqAmiv9vE5s","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"4"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"XzGEQr86deIyGS","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"\"}"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"DwW5cTHWbUs4","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"tool_calls","index":0,"logprobs":null}],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"dsUuyz0rLkl5b","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[],"created":1759956347,"id":"chatcmpl-COVKdf8sqjQpLPkxO2Bt5P8bqCoDk","model":"gpt-4o-2024-08-06","obfuscation":"9Ostam","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":24,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":200,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":224}} + + data: [DONE] + + recorded_at: Wed, 08 Oct 2025 20:45:47 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + the weather in Berlin? (52.5200, 13.4050)"},{"role":"assistant","tool_calls":[{"id":"call_J4dQW8HbxjIx7wLczWtLOYdJ","type":"function","function":{"name":"weather","arguments":"{\"latitude\":\"52.5200\",\"longitude\":\"13.4050\"}"}}]},{"role":"tool","content":"Current + weather at 52.5200, 13.4050: 15°C, Wind: 10 km/h","tool_call_id":"call_J4dQW8HbxjIx7wLczWtLOYdJ"},{"role":"assistant","content":"The + current weather in Berlin (52.5200, 13.4050) is 15°C with a wind speed of + 10 km/h."},{"role":"user","content":"What''s the weather in Paris? (48.8575, + 2.3514)"},{"role":"assistant","tool_calls":[{"id":"call_L2kkdcCzrtlYBctN9hwI6kgD","type":"function","function":{"name":"weather","arguments":"{\"latitude\":\"48.8575\",\"longitude\":\"2.3514\"}"}}]},{"role":"tool","content":"Current + weather at 48.8575, 2.3514: 15°C, Wind: 10 km/h","tool_call_id":"call_L2kkdcCzrtlYBctN9hwI6kgD"}],"stream":true,"tools":[{"type":"function","function":{"name":"weather","description":"Gets + current weather for a location","parameters":{"type":"object","properties":{"latitude":{"type":"string","description":"Latitude + (e.g., 52.5200)"},"longitude":{"type":"string","description":"Longitude (e.g., + 13.4050)"}},"required":["latitude","longitude"]}}}],"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - a27675cc-c339-4097-9801-f1148a1d860c + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '370' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '37318' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d076-20251003014048 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:48 GMT + body: + encoding: ASCII-8BIT + string: !binary |- + ZGF0YTogeyJjaG9pY2VzIjpbXSwiY3JlYXRlZCI6MCwiaWQiOiIiLCJtb2RlbCI6IiIsIm9iamVjdCI6IiIsInByb21wdF9maWx0ZXJfcmVzdWx0cyI6W3sicHJvbXB0X2luZGV4IjowLCJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fX1dfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7fSwiZGVsdGEiOnsiY29udGVudCI6IiIsInJlZnVzYWwiOm51bGwsInJvbGUiOiJhc3Npc3RhbnQifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDgsImlkIjoiY2hhdGNtcGwtQ09WS2VHd0tVcFMzU3haUTB1ZWtNQ1RZUVRIdE4iLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJZMmZtY2kwIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IlRoZSJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0OCwiaWQiOiJjaGF0Y21wbC1DT1ZLZUd3S1VwUzNTeFpRMHVla01DVFlRVEh0TiIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6InAyMmtnTCIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIgY3VycmVudCJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0OCwiaWQiOiJjaGF0Y21wbC1DT1ZLZUd3S1VwUzNTeFpRMHVla01DVFlRVEh0TiIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6ImYiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiIHdlYXRoZXIifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDgsImlkIjoiY2hhdGNtcGwtQ09WS2VHd0tVcFMzU3haUTB1ZWtNQ1RZUVRIdE4iLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJTIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IiBpbiJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0OCwiaWQiOiJjaGF0Y21wbC1DT1ZLZUd3S1VwUzNTeFpRMHVla01DVFlRVEh0TiIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6Ik1pNWNxTiIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIgUGFyaXMifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDgsImlkIjoiY2hhdGNtcGwtQ09WS2VHd0tVcFMzU3haUTB1ZWtNQ1RZUVRIdE4iLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJvZUgiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiICgifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDgsImlkIjoiY2hhdGNtcGwtQ09WS2VHd0tVcFMzU3haUTB1ZWtNQ1RZUVRIdE4iLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJMVHRmUnlWIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IjQ4In0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoicHR3a3pFbyIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIuIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoibG9hN2oycVAiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiODU3In0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiNjRlRGxuIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IjUifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDgsImlkIjoiY2hhdGNtcGwtQ09WS2VHd0tVcFMzU3haUTB1ZWtNQ1RZUVRIdE4iLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJheHZCazlONSIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIsIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiVTM2amZuUkYiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiICJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0OCwiaWQiOiJjaGF0Y21wbC1DT1ZLZUd3S1VwUzNTeFpRMHVla01DVFlRVEh0TiIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6IlRxZXZuV09KIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IjIifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDgsImlkIjoiY2hhdGNtcGwtQ09WS2VHd0tVcFMzU3haUTB1ZWtNQ1RZUVRIdE4iLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiI2bE1PQmNyUiIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIuIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiMm1QZVUzdnUiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiMzUxIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiaGZIMVVrIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IjQifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDgsImlkIjoiY2hhdGNtcGwtQ09WS2VHd0tVcFMzU3haUTB1ZWtNQ1RZUVRIdE4iLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiI5YWVRaGVXbCIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIpIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiUndzYkJpNGIiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiIGlzIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiM3NFd3NIIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IiAifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDgsImlkIjoiY2hhdGNtcGwtQ09WS2VHd0tVcFMzU3haUTB1ZWtNQ1RZUVRIdE4iLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJtejhjWXROVCIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIxNSJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0OCwiaWQiOiJjaGF0Y21wbC1DT1ZLZUd3S1VwUzNTeFpRMHVla01DVFlRVEh0TiIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6Im05amxhYXgiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiwrBDIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoibktFaWxOVCIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIgd2l0aCJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0OCwiaWQiOiJjaGF0Y21wbC1DT1ZLZUd3S1VwUzNTeFpRMHVla01DVFlRVEh0TiIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6IlpWaG4iLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiIGEifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDgsImlkIjoiY2hhdGNtcGwtQ09WS2VHd0tVcFMzU3haUTB1ZWtNQ1RZUVRIdE4iLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiI3S2xGQllkIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IiB3aW5kIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiVW1lbSIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIgc3BlZWQifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDgsImlkIjoiY2hhdGNtcGwtQ09WS2VHd0tVcFMzU3haUTB1ZWtNQ1RZUVRIdE4iLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJBNFYiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiIG9mIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoidUJuME9qIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6IiAifSwiZmluaXNoX3JlYXNvbiI6bnVsbCwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDgsImlkIjoiY2hhdGNtcGwtQ09WS2VHd0tVcFMzU3haUTB1ZWtNQ1RZUVRIdE4iLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJXbWpyQkNTeCIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIxMCJ9LCJmaW5pc2hfcmVhc29uIjpudWxsLCJpbmRleCI6MCwibG9ncHJvYnMiOm51bGx9XSwiY3JlYXRlZCI6MTc1OTk1NjM0OCwiaWQiOiJjaGF0Y21wbC1DT1ZLZUd3S1VwUzNTeFpRMHVla01DVFlRVEh0TiIsIm1vZGVsIjoiZ3B0LTRvLTIwMjQtMDgtMDYiLCJvYmZ1c2NhdGlvbiI6Ijl2Tmpjb00iLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnsiaGF0ZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZWxmX2hhcm0iOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2V4dWFsIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInZpb2xlbmNlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn19LCJkZWx0YSI6eyJjb250ZW50IjoiIGttIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiNEUxTVdmIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjpudWxsfQoKZGF0YTogeyJjaG9pY2VzIjpbeyJjb250ZW50X2ZpbHRlcl9yZXN1bHRzIjp7ImhhdGUiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwic2VsZl9oYXJtIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNleHVhbCI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJ2aW9sZW5jZSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9fSwiZGVsdGEiOnsiY29udGVudCI6Ii9oIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiS1pTOVB1VyIsIm9iamVjdCI6ImNoYXQuY29tcGxldGlvbi5jaHVuayIsInN5c3RlbV9maW5nZXJwcmludCI6ImZwXzVkN2VlMWI4NDQiLCJ1c2FnZSI6bnVsbH0KCmRhdGE6IHsiY2hvaWNlcyI6W3siY29udGVudF9maWx0ZXJfcmVzdWx0cyI6eyJoYXRlIjp7ImZpbHRlcmVkIjpmYWxzZSwic2V2ZXJpdHkiOiJzYWZlIn0sInNlbGZfaGFybSI6eyJmaWx0ZXJlZCI6ZmFsc2UsInNldmVyaXR5Ijoic2FmZSJ9LCJzZXh1YWwiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifSwidmlvbGVuY2UiOnsiZmlsdGVyZWQiOmZhbHNlLCJzZXZlcml0eSI6InNhZmUifX0sImRlbHRhIjp7ImNvbnRlbnQiOiIuIn0sImZpbmlzaF9yZWFzb24iOm51bGwsImluZGV4IjowLCJsb2dwcm9icyI6bnVsbH1dLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoiUVMxaUt2VTYiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOlt7ImNvbnRlbnRfZmlsdGVyX3Jlc3VsdHMiOnt9LCJkZWx0YSI6e30sImZpbmlzaF9yZWFzb24iOiJzdG9wIiwiaW5kZXgiOjAsImxvZ3Byb2JzIjpudWxsfV0sImNyZWF0ZWQiOjE3NTk5NTYzNDgsImlkIjoiY2hhdGNtcGwtQ09WS2VHd0tVcFMzU3haUTB1ZWtNQ1RZUVRIdE4iLCJtb2RlbCI6ImdwdC00by0yMDI0LTA4LTA2Iiwib2JmdXNjYXRpb24iOiJCOGkiLCJvYmplY3QiOiJjaGF0LmNvbXBsZXRpb24uY2h1bmsiLCJzeXN0ZW1fZmluZ2VycHJpbnQiOiJmcF81ZDdlZTFiODQ0IiwidXNhZ2UiOm51bGx9CgpkYXRhOiB7ImNob2ljZXMiOltdLCJjcmVhdGVkIjoxNzU5OTU2MzQ4LCJpZCI6ImNoYXRjbXBsLUNPVktlR3dLVXBTM1N4WlEwdWVrTUNUWVFUSHROIiwibW9kZWwiOiJncHQtNG8tMjAyNC0wOC0wNiIsIm9iZnVzY2F0aW9uIjoidHpBMEoxIiwib2JqZWN0IjoiY2hhdC5jb21wbGV0aW9uLmNodW5rIiwic3lzdGVtX2ZpbmdlcnByaW50IjoiZnBfNWQ3ZWUxYjg0NCIsInVzYWdlIjp7ImNvbXBsZXRpb25fdG9rZW5zIjozMywiY29tcGxldGlvbl90b2tlbnNfZGV0YWlscyI6eyJhY2NlcHRlZF9wcmVkaWN0aW9uX3Rva2VucyI6MCwiYXVkaW9fdG9rZW5zIjowLCJyZWFzb25pbmdfdG9rZW5zIjowLCJyZWplY3RlZF9wcmVkaWN0aW9uX3Rva2VucyI6MH0sInByb21wdF90b2tlbnMiOjI1NSwicHJvbXB0X3Rva2Vuc19kZXRhaWxzIjp7ImF1ZGlvX3Rva2VucyI6MCwiY2FjaGVkX3Rva2VucyI6MH0sInRvdGFsX3Rva2VucyI6Mjg4fX0KCmRhdGE6IFtET05FXQoK + recorded_at: Wed, 08 Oct 2025 20:45:48 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_without_parameters.yml b/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_without_parameters.yml new file mode 100644 index 000000000..244be2d19 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_without_parameters.yml @@ -0,0 +1,132 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + the best language to learn?"}],"stream":false,"tools":[{"type":"function","function":{"name":"best_language_to_learn","description":"Gets + the best language to learn","parameters":{"type":"object","properties":{},"required":[]}}}]}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '990' + Content-Type: + - application/json + Apim-Request-Id: + - d4f08622-4829-4185-8753-7a18a515b56f + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '379' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '38184' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d065-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:43 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{},"finish_reason":"tool_calls","index":0,"logprobs":null,"message":{"annotations":[],"content":null,"refusal":null,"role":"assistant","tool_calls":[{"function":{"arguments":"{}","name":"best_language_to_learn"},"id":"call_zdMmDL5qabwGU8aoSOrTKqx9","type":"function"}]}}],"created":1759956343,"id":"chatcmpl-COVKZjRC8zJHE2lkBvQDpjgkOiIej","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":14,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":48,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":62}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:43 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"What''s + the best language to learn?"},{"role":"assistant","tool_calls":[{"id":"call_zdMmDL5qabwGU8aoSOrTKqx9","type":"function","function":{"name":"best_language_to_learn","arguments":"{}"}}]},{"role":"tool","content":"Ruby","tool_call_id":"call_zdMmDL5qabwGU8aoSOrTKqx9"}],"stream":false,"tools":[{"type":"function","function":{"name":"best_language_to_learn","description":"Gets + the best language to learn","parameters":{"type":"object","properties":{},"required":[]}}}]}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1069' + Content-Type: + - application/json + Apim-Request-Id: + - a3f41315-adc3-447c-a5f2-188e9359e76c + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '378' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '38129' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d065-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:43 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"The + best language to learn is Ruby.","refusal":null,"role":"assistant"}}],"created":1759956344,"id":"chatcmpl-COVKaae0KNrngqMQHGsFoJ2IUipMA","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":10,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":73,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":83}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:44 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_without_parameters_in_multi-turn_streaming_conversations.yml b/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_without_parameters_in_multi-turn_streaming_conversations.yml new file mode 100644 index 000000000..7dad34658 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_function_calling_azure_openai_azure-gpt-4o_can_use_tools_without_parameters_in_multi-turn_streaming_conversations.yml @@ -0,0 +1,336 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"developer","content":"You + must use tools whenever possible."},{"role":"user","content":"What''s the + best language to learn?"}],"stream":true,"tools":[{"type":"function","function":{"name":"best_language_to_learn","description":"Gets + the best language to learn","parameters":{"type":"object","properties":{},"required":[]}}}],"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - ca0f246e-3f25-434f-a4cf-86f194643578 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '377' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '38066' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d078-20251003024559 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:44 GMT + body: + encoding: UTF-8 + string: |+ + data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}]} + + data: {"choices":[{"content_filter_results":{},"delta":{"content":null,"refusal":null,"role":"assistant","tool_calls":[{"function":{"arguments":"","name":"best_language_to_learn"},"id":"call_8Y8FVZ2wtb9oRRjBBnIu6nbU","index":0,"type":"function"}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956344,"id":"chatcmpl-COVKaHQKGQs1UO0L0pm9VUYgcdAkF","model":"gpt-4o-2024-08-06","obfuscation":"PwrY6u3","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"{}"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956344,"id":"chatcmpl-COVKaHQKGQs1UO0L0pm9VUYgcdAkF","model":"gpt-4o-2024-08-06","obfuscation":"lPg3c4OQvgjgC","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"tool_calls","index":0,"logprobs":null}],"created":1759956344,"id":"chatcmpl-COVKaHQKGQs1UO0L0pm9VUYgcdAkF","model":"gpt-4o-2024-08-06","obfuscation":"x7uaNc0ftkmtn","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[],"created":1759956344,"id":"chatcmpl-COVKaHQKGQs1UO0L0pm9VUYgcdAkF","model":"gpt-4o-2024-08-06","obfuscation":"5K2XnciB","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":14,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":55,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":69}} + + data: [DONE] + + recorded_at: Wed, 08 Oct 2025 20:45:45 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"developer","content":"You + must use tools whenever possible."},{"role":"user","content":"What''s the + best language to learn?"},{"role":"assistant","tool_calls":[{"id":"call_8Y8FVZ2wtb9oRRjBBnIu6nbU","type":"function","function":{"name":"best_language_to_learn","arguments":"{}"}}]},{"role":"tool","content":"Ruby","tool_call_id":"call_8Y8FVZ2wtb9oRRjBBnIu6nbU"}],"stream":true,"tools":[{"type":"function","function":{"name":"best_language_to_learn","description":"Gets + the best language to learn","parameters":{"type":"object","properties":{},"required":[]}}}],"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - a3f87a60-062a-4fc2-81fc-241ed46b4879 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '376' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '38001' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d078-20251003024559 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:44 GMT + body: + encoding: UTF-8 + string: |+ + data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}]} + + data: {"choices":[{"content_filter_results":{},"delta":{"content":"","refusal":null,"role":"assistant"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKbrBHzWGtZaIda8t0jvE7Cnmcm","model":"gpt-4o-2024-08-06","obfuscation":"xieshUW","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"The"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKbrBHzWGtZaIda8t0jvE7Cnmcm","model":"gpt-4o-2024-08-06","obfuscation":"zLvNqr","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" best"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKbrBHzWGtZaIda8t0jvE7Cnmcm","model":"gpt-4o-2024-08-06","obfuscation":"1R9E","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" language"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKbrBHzWGtZaIda8t0jvE7Cnmcm","model":"gpt-4o-2024-08-06","obfuscation":"","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" to"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKbrBHzWGtZaIda8t0jvE7Cnmcm","model":"gpt-4o-2024-08-06","obfuscation":"Qkuqg8","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" learn"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKbrBHzWGtZaIda8t0jvE7Cnmcm","model":"gpt-4o-2024-08-06","obfuscation":"t9g","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" is"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKbrBHzWGtZaIda8t0jvE7Cnmcm","model":"gpt-4o-2024-08-06","obfuscation":"oByIIG","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" Ruby"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKbrBHzWGtZaIda8t0jvE7Cnmcm","model":"gpt-4o-2024-08-06","obfuscation":"Y7rJ","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"."},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKbrBHzWGtZaIda8t0jvE7Cnmcm","model":"gpt-4o-2024-08-06","obfuscation":"vs4diEyZ","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"stop","index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKbrBHzWGtZaIda8t0jvE7Cnmcm","model":"gpt-4o-2024-08-06","obfuscation":"EwP","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[],"created":1759956345,"id":"chatcmpl-COVKbrBHzWGtZaIda8t0jvE7Cnmcm","model":"gpt-4o-2024-08-06","obfuscation":"o3P5zIBO","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":10,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":80,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":90}} + + data: [DONE] + + recorded_at: Wed, 08 Oct 2025 20:45:45 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"developer","content":"You + must use tools whenever possible."},{"role":"user","content":"What''s the + best language to learn?"},{"role":"assistant","tool_calls":[{"id":"call_8Y8FVZ2wtb9oRRjBBnIu6nbU","type":"function","function":{"name":"best_language_to_learn","arguments":"{}"}}]},{"role":"tool","content":"Ruby","tool_call_id":"call_8Y8FVZ2wtb9oRRjBBnIu6nbU"},{"role":"assistant","content":"The + best language to learn is Ruby."},{"role":"user","content":"Tell me again: + what''s the best language to learn?"}],"stream":true,"tools":[{"type":"function","function":{"name":"best_language_to_learn","description":"Gets + the best language to learn","parameters":{"type":"object","properties":{},"required":[]}}}],"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - 22b008aa-3aa1-4526-8d5c-3e49cfd8731a + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '375' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '37914' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d078-20251003024559 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:44 GMT + body: + encoding: UTF-8 + string: |+ + data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}]} + + data: {"choices":[{"content_filter_results":{},"delta":{"content":null,"refusal":null,"role":"assistant","tool_calls":[{"function":{"arguments":"","name":"best_language_to_learn"},"id":"call_cFW2kSSr4gxvLGPg1FAMbEkQ","index":0,"type":"function"}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKb5PxxnZc5L1FI0g7rpwitxMgL","model":"gpt-4o-2024-08-06","obfuscation":"WQRidL9","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{"tool_calls":[{"function":{"arguments":"{}"},"index":0}]},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKb5PxxnZc5L1FI0g7rpwitxMgL","model":"gpt-4o-2024-08-06","obfuscation":"ZBhOb18DR5grp","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"tool_calls","index":0,"logprobs":null}],"created":1759956345,"id":"chatcmpl-COVKb5PxxnZc5L1FI0g7rpwitxMgL","model":"gpt-4o-2024-08-06","obfuscation":"t8bskzDvNNMUd","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[],"created":1759956345,"id":"chatcmpl-COVKb5PxxnZc5L1FI0g7rpwitxMgL","model":"gpt-4o-2024-08-06","obfuscation":"accmrL","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":14,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":107,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":121}} + + data: [DONE] + + recorded_at: Wed, 08 Oct 2025 20:45:45 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"developer","content":"You + must use tools whenever possible."},{"role":"user","content":"What''s the + best language to learn?"},{"role":"assistant","tool_calls":[{"id":"call_8Y8FVZ2wtb9oRRjBBnIu6nbU","type":"function","function":{"name":"best_language_to_learn","arguments":"{}"}}]},{"role":"tool","content":"Ruby","tool_call_id":"call_8Y8FVZ2wtb9oRRjBBnIu6nbU"},{"role":"assistant","content":"The + best language to learn is Ruby."},{"role":"user","content":"Tell me again: + what''s the best language to learn?"},{"role":"assistant","tool_calls":[{"id":"call_cFW2kSSr4gxvLGPg1FAMbEkQ","type":"function","function":{"name":"best_language_to_learn","arguments":"{}"}}]},{"role":"tool","content":"Ruby","tool_call_id":"call_cFW2kSSr4gxvLGPg1FAMbEkQ"}],"stream":true,"tools":[{"type":"function","function":{"name":"best_language_to_learn","description":"Gets + the best language to learn","parameters":{"type":"object","properties":{},"required":[]}}}],"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - c64f7253-c0b8-4f30-a10f-1541bb96c9ce + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '374' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '37825' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d078-20251003024559 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:45 GMT + body: + encoding: UTF-8 + string: |+ + data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}]} + + data: {"choices":[{"content_filter_results":{},"delta":{"content":"","refusal":null,"role":"assistant"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcIhVMg5wQqAB3pt9CWAMGtDMW","model":"gpt-4o-2024-08-06","obfuscation":"hPFEWpK","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"The"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcIhVMg5wQqAB3pt9CWAMGtDMW","model":"gpt-4o-2024-08-06","obfuscation":"yNWE28","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" best"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcIhVMg5wQqAB3pt9CWAMGtDMW","model":"gpt-4o-2024-08-06","obfuscation":"4HFa","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" language"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcIhVMg5wQqAB3pt9CWAMGtDMW","model":"gpt-4o-2024-08-06","obfuscation":"","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" to"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcIhVMg5wQqAB3pt9CWAMGtDMW","model":"gpt-4o-2024-08-06","obfuscation":"tQvuoJ","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" learn"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcIhVMg5wQqAB3pt9CWAMGtDMW","model":"gpt-4o-2024-08-06","obfuscation":"Ggi","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" is"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcIhVMg5wQqAB3pt9CWAMGtDMW","model":"gpt-4o-2024-08-06","obfuscation":"darLPM","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" Ruby"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcIhVMg5wQqAB3pt9CWAMGtDMW","model":"gpt-4o-2024-08-06","obfuscation":"c4co","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"."},"finish_reason":null,"index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcIhVMg5wQqAB3pt9CWAMGtDMW","model":"gpt-4o-2024-08-06","obfuscation":"LGGQmfX6","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"stop","index":0,"logprobs":null}],"created":1759956346,"id":"chatcmpl-COVKcIhVMg5wQqAB3pt9CWAMGtDMW","model":"gpt-4o-2024-08-06","obfuscation":"KIf","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[],"created":1759956346,"id":"chatcmpl-COVKcIhVMg5wQqAB3pt9CWAMGtDMW","model":"gpt-4o-2024-08-06","obfuscation":"jhmC0r","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":10,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":132,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":142}} + + data: [DONE] + + recorded_at: Wed, 08 Oct 2025 20:45:46 GMT +recorded_with: VCR 6.3.1 +... diff --git a/spec/fixtures/vcr_cassettes/chat_real_error_scenarios_azure_openai_azure-gpt-4o_handles_context_length_exceeded_errors.yml b/spec/fixtures/vcr_cassettes/chat_real_error_scenarios_azure_openai_azure-gpt-4o_handles_context_length_exceeded_errors.yml new file mode 100644 index 000000000..32d26ce09 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_real_error_scenarios_azure_openai_azure-gpt-4o_handles_context_length_exceeded_errors.yml @@ -0,0 +1,64 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":""},{"role":"assistant","content":""},{"role":"user","content":""},{"role":"assistant","content":""},{"role":"user","content":""},{"role":"assistant","content":""},{"role":"user","content":""},{"role":"assistant","content":""},{"role":"user","content":""},{"role":"assistant","content":""},{"role":"user","content":"Hi"}],"stream":false}' + headers: + User-Agent: + - Faraday v2.13.3 + Authorization: + - Bearer + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 429 + message: Too Many Requests + headers: + Content-Length: + - '440' + Content-Type: + - application/json + Retry-After: + - '60' + X-Ratelimit-Reset-Tokens: + - '60' + X-Ratelimit-Limit-Tokens: + - '40000' + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Apim-Request-Id: + - 62954942-596e-4d89-838f-2f8a8209d243 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + Policy-Id: + - DeploymentRatelimit-Token + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '396' + X-Ratelimit-Limit-Requests: + - '400' + Date: + - Wed, 08 Oct 2025 20:45:29 GMT + body: + encoding: UTF-8 + string: '{"error":{"code":"429","message": "Requests to the ChatCompletions_Create + Operation under Azure OpenAI API version have exceeded + token rate limit of your current OpenAI S0 pricing tier. Please retry after + 60 seconds. Please go here: https://aka.ms/oai/quotaincrease if you would + like to further increase the default rate limit. For Free Account customers, + upgrade to Pay as you Go here: https://aka.ms/429TrialUpgrade."}}' + recorded_at: Wed, 08 Oct 2025 20:45:29 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_streaming_responses_azure_openai_azure-gpt-4o_reports_consistent_token_counts_compared_to_non-streaming.yml b/spec/fixtures/vcr_cassettes/chat_streaming_responses_azure_openai_azure-gpt-4o_reports_consistent_token_counts_compared_to_non-streaming.yml new file mode 100644 index 000000000..e57b7936d --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_streaming_responses_azure_openai_azure-gpt-4o_reports_consistent_token_counts_compared_to_non-streaming.yml @@ -0,0 +1,153 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Count + from 1 to 3"}],"stream":true,"temperature":0.0,"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - ff76e747-00ec-4ff8-9592-6653249d0907 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '398' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39990' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 21:07:45 GMT + body: + encoding: UTF-8 + string: |+ + data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}]} + + data: {"choices":[{"content_filter_results":{},"delta":{"content":"","refusal":null,"role":"assistant"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957666,"id":"chatcmpl-COVfupTRk2G4s7CPpYmH3X2ZKyW2v","model":"gpt-4o-2024-08-06","obfuscation":"Qfzv3Yx","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"1"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957666,"id":"chatcmpl-COVfupTRk2G4s7CPpYmH3X2ZKyW2v","model":"gpt-4o-2024-08-06","obfuscation":"YlAxxLPc","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":","},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957666,"id":"chatcmpl-COVfupTRk2G4s7CPpYmH3X2ZKyW2v","model":"gpt-4o-2024-08-06","obfuscation":"6zmpK4xo","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" "},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957666,"id":"chatcmpl-COVfupTRk2G4s7CPpYmH3X2ZKyW2v","model":"gpt-4o-2024-08-06","obfuscation":"dHNJ2SRg","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"2"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957666,"id":"chatcmpl-COVfupTRk2G4s7CPpYmH3X2ZKyW2v","model":"gpt-4o-2024-08-06","obfuscation":"vOnQsMBC","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":","},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957666,"id":"chatcmpl-COVfupTRk2G4s7CPpYmH3X2ZKyW2v","model":"gpt-4o-2024-08-06","obfuscation":"RRTv3aVa","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" "},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957666,"id":"chatcmpl-COVfupTRk2G4s7CPpYmH3X2ZKyW2v","model":"gpt-4o-2024-08-06","obfuscation":"H5m3BOzh","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"3"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957666,"id":"chatcmpl-COVfupTRk2G4s7CPpYmH3X2ZKyW2v","model":"gpt-4o-2024-08-06","obfuscation":"pTepUS0B","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"stop","index":0,"logprobs":null}],"created":1759957666,"id":"chatcmpl-COVfupTRk2G4s7CPpYmH3X2ZKyW2v","model":"gpt-4o-2024-08-06","obfuscation":"Bfo","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[],"created":1759957666,"id":"chatcmpl-COVfupTRk2G4s7CPpYmH3X2ZKyW2v","model":"gpt-4o-2024-08-06","obfuscation":"FczVtxyWP","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":8,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":14,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":22}} + + data: [DONE] + + recorded_at: Wed, 08 Oct 2025 21:07:46 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Count + from 1 to 3"}],"stream":false,"temperature":0.0}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1040' + Content-Type: + - application/json + Apim-Request-Id: + - fd6a9364-0df1-4ff2-b178-4dba326b828c + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '397' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39985' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 21:07:46 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"1, + 2, 3","refusal":null,"role":"assistant"}}],"created":1759957666,"id":"chatcmpl-COVful1XbUUFh36JiB7cw8POfXFhT","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":8,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":14,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":22}} + + ' + recorded_at: Wed, 08 Oct 2025 21:07:46 GMT +recorded_with: VCR 6.3.1 +... diff --git a/spec/fixtures/vcr_cassettes/chat_streaming_responses_azure_openai_azure-gpt-4o_supports_streaming_responses.yml b/spec/fixtures/vcr_cassettes/chat_streaming_responses_azure_openai_azure-gpt-4o_supports_streaming_responses.yml new file mode 100644 index 000000000..76bc0d3a2 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_streaming_responses_azure_openai_azure-gpt-4o_supports_streaming_responses.yml @@ -0,0 +1,89 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":"Count + from 1 to 3"}],"stream":true,"stream_options":{"include_usage":true}}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Transfer-Encoding: + - chunked + Content-Type: + - text/event-stream; charset=utf-8 + Apim-Request-Id: + - 1a809bcb-8c7f-4c88-9bdc-f3d8e14d42cb + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '399' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39995' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 21:07:45 GMT + body: + encoding: UTF-8 + string: |+ + data: {"choices":[],"created":0,"id":"","model":"","object":"","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}]} + + data: {"choices":[{"content_filter_results":{},"delta":{"content":"","refusal":null,"role":"assistant"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957665,"id":"chatcmpl-COVftCTNEXa0kKKy1MNv36FIkUUz6","model":"gpt-4o-2024-08-06","obfuscation":"VDVMCoL","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"1"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957665,"id":"chatcmpl-COVftCTNEXa0kKKy1MNv36FIkUUz6","model":"gpt-4o-2024-08-06","obfuscation":"yGXcFUPo","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":","},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957665,"id":"chatcmpl-COVftCTNEXa0kKKy1MNv36FIkUUz6","model":"gpt-4o-2024-08-06","obfuscation":"y9P1VcDM","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" "},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957665,"id":"chatcmpl-COVftCTNEXa0kKKy1MNv36FIkUUz6","model":"gpt-4o-2024-08-06","obfuscation":"g9d9n8bE","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"2"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957665,"id":"chatcmpl-COVftCTNEXa0kKKy1MNv36FIkUUz6","model":"gpt-4o-2024-08-06","obfuscation":"C4aqwYbz","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":","},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957665,"id":"chatcmpl-COVftCTNEXa0kKKy1MNv36FIkUUz6","model":"gpt-4o-2024-08-06","obfuscation":"QoRCVWZ1","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":" "},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957665,"id":"chatcmpl-COVftCTNEXa0kKKy1MNv36FIkUUz6","model":"gpt-4o-2024-08-06","obfuscation":"d4PSlWRA","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"delta":{"content":"3"},"finish_reason":null,"index":0,"logprobs":null}],"created":1759957665,"id":"chatcmpl-COVftCTNEXa0kKKy1MNv36FIkUUz6","model":"gpt-4o-2024-08-06","obfuscation":"6QsU144v","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[{"content_filter_results":{},"delta":{},"finish_reason":"stop","index":0,"logprobs":null}],"created":1759957665,"id":"chatcmpl-COVftCTNEXa0kKKy1MNv36FIkUUz6","model":"gpt-4o-2024-08-06","obfuscation":"kKv","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":null} + + data: {"choices":[],"created":1759957665,"id":"chatcmpl-COVftCTNEXa0kKKy1MNv36FIkUUz6","model":"gpt-4o-2024-08-06","obfuscation":"GWRtZyBIA","object":"chat.completion.chunk","system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":8,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":14,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":22}} + + data: [DONE] + + recorded_at: Wed, 08 Oct 2025 21:07:45 GMT +recorded_with: VCR 6.3.1 +... diff --git a/spec/fixtures/vcr_cassettes/chat_text_models_azure_openai_azure-gpt-4o_can_understand_remote_text.yml b/spec/fixtures/vcr_cassettes/chat_text_models_azure_openai_azure-gpt-4o_can_understand_remote_text.yml new file mode 100644 index 000000000..2e85f0a87 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_text_models_azure_openai_azure-gpt-4o_can_understand_remote_text.yml @@ -0,0 +1,221 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.ruby-lang.org/en/about/license.txt + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Faraday v2.13.3 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + response: + status: + code: 200 + message: OK + headers: + Connection: + - keep-alive + Content-Length: + - '2502' + Server: + - GitHub.com + Content-Type: + - text/plain; charset=utf-8 + X-Origin-Cache: + - HIT + Last-Modified: + - Tue, 07 Oct 2025 21:37:24 GMT + Access-Control-Allow-Origin: + - "*" + Etag: + - W/"68e58814-9c6" + Expires: + - Wed, 08 Oct 2025 16:41:06 GMT + Cache-Control: + - max-age=600 + X-Proxy-Cache: + - MISS + X-Github-Request-Id: + - F944:195D53:AA6A76:BB6094:68E691CA + Accept-Ranges: + - bytes + Age: + - '78' + Date: + - Wed, 08 Oct 2025 20:45:12 GMT + Via: + - 1.1 varnish + X-Served-By: + - cache-yul1970059-YUL + X-Cache: + - HIT + X-Cache-Hits: + - '0' + X-Timer: + - S1759956313.540339,VS0,VE2 + Vary: + - Accept-Encoding + X-Fastly-Request-Id: + - cf168c07c4c54b2e6b54c409c3c2dbd605035503 + body: + encoding: ASCII-8BIT + string: "Ruby is copyrighted free software by Yukihiro Matsumoto .\nYou + can redistribute it and/or modify it under either the terms of the\n2-clause + BSDL (see the file BSDL), or the conditions below:\n\n 1. You may make and + give away verbatim copies of the source form of the\n software without + restriction, provided that you duplicate all of the\n original copyright + notices and associated disclaimers.\n\n 2. You may modify your copy of the + software in any way, provided that\n you do at least ONE of the following:\n\n + \ a) place your modifications in the Public Domain or otherwise\n make + them Freely Available, such as by posting said\n\t modifications to Usenet + or an equivalent medium, or by allowing\n\t the author to include your modifications + in the software.\n\n b) use the modified software only within your corporation + or\n organization.\n\n c) give non-standard binaries non-standard + names, with\n instructions on where to get the original software + distribution.\n\n d) make other distribution arrangements with the author.\n\n + \ 3. You may distribute the software in object code or binary form,\n provided + that you do at least ONE of the following:\n\n a) distribute the binaries + and library files of the software,\n\t together with instructions (in the + manual page or equivalent)\n\t on where to get the original distribution.\n\n + \ b) accompany the distribution with the machine-readable source of\n\t + \ the software.\n\n c) give non-standard binaries non-standard names, + with\n instructions on where to get the original software distribution.\n\n + \ d) make other distribution arrangements with the author.\n\n 4. You + may modify and include the part of the software into any other\n software + (possibly commercial). But some files in the distribution\n are not written + by the author, so that they are not under these terms.\n\n For the list + of those files and their copying conditions, see the\n file LEGAL.\n\n + \ 5. The scripts and library files supplied as input to or produced as\n output + from the software do not automatically fall under the\n copyright of the + software, but belong to whomever generated them,\n and may be sold commercially, + and may be aggregated with this\n software.\n\n 6. THIS SOFTWARE IS PROVIDED + \"AS IS\" AND WITHOUT ANY EXPRESS OR\n IMPLIED WARRANTIES, INCLUDING, + WITHOUT LIMITATION, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR\n PURPOSE.\n" + recorded_at: Wed, 08 Oct 2025 20:45:12 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":[{"type":"text","text":"What''s + in this file?"},{"type":"text","text":"Ruby + is copyrighted free software by Yukihiro Matsumoto .\nYou + can redistribute it and/or modify it under either the terms of the\n2-clause + BSDL (see the file BSDL), or the conditions below:\n\n 1. You may make and + give away verbatim copies of the source form of the\n software without + restriction, provided that you duplicate all of the\n original copyright + notices and associated disclaimers.\n\n 2. You may modify your copy of the + software in any way, provided that\n you do at least ONE of the following:\n\n a) + place your modifications in the Public Domain or otherwise\n make + them Freely Available, such as by posting said\n\t modifications to Usenet + or an equivalent medium, or by allowing\n\t the author to include your modifications + in the software.\n\n b) use the modified software only within your corporation + or\n organization.\n\n c) give non-standard binaries non-standard + names, with\n instructions on where to get the original software + distribution.\n\n d) make other distribution arrangements with the author.\n\n 3. + You may distribute the software in object code or binary form,\n provided + that you do at least ONE of the following:\n\n a) distribute the binaries + and library files of the software,\n\t together with instructions (in the + manual page or equivalent)\n\t on where to get the original distribution.\n\n b) + accompany the distribution with the machine-readable source of\n\t the software.\n\n c) + give non-standard binaries non-standard names, with\n instructions + on where to get the original software distribution.\n\n d) make other + distribution arrangements with the author.\n\n 4. You may modify and include + the part of the software into any other\n software (possibly commercial). But + some files in the distribution\n are not written by the author, so that + they are not under these terms.\n\n For the list of those files and their + copying conditions, see the\n file LEGAL.\n\n 5. The scripts and library + files supplied as input to or produced as\n output from the software do + not automatically fall under the\n copyright of the software, but belong + to whomever generated them,\n and may be sold commercially, and may be + aggregated with this\n software.\n\n 6. THIS SOFTWARE IS PROVIDED \"AS + IS\" AND WITHOUT ANY EXPRESS OR\n IMPLIED WARRANTIES, INCLUDING, WITHOUT + LIMITATION, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR\n PURPOSE.\n"}]}],"stream":false}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '2860' + Content-Type: + - application/json + Apim-Request-Id: + - facc7cda-d239-4c1a-b40f-3a189f24b294 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '397' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39261' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d062-20251002210638 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:15 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"The + contents of the file `license.txt` you''ve provided pertain to the licensing + terms for the Ruby programming language. Here is a summary of the key points:\n\n1. + **Copyright and Redistribution**: \n - Ruby is copyrighted by Yukihiro Matsumoto.\n - + The software can be redistributed and/or modified under the 2-clause BSD License + or under certain specified conditions.\n\n2. **Conditions for Modifying Source + Code**:\n - You can modify the software, but you must do at least one of + the following:\n - Make modifications publicly available or freely available.\n - + Use the modified software internally within an organization.\n - Provide + non-standard binaries under non-standard names with the original distribution + reference.\n - Arrange other distribution terms with the author.\n\n3. + **Object Code or Binary Distribution**:\n - Distribution of binaries must + also meet at least one of these conditions:\n - Provide instructions to + obtain the original distribution.\n - Include machine-readable source + alongside distribution.\n - Use non-standard names for non-standard binaries + with a reference to the original distribution.\n - Set up distribution + agreements with the author.\n\n4. **Inclusion into Other Software**:\n - + Parts of the software may be included in other software, possibly commercial, + with exceptions for files not under these terms.\n\n5. **Scripts and Library + Files**:\n - Scripts and library files generated by or for the software + are owned by their creators and may be sold commercially.\n\n6. **Warranty + Disclaimer**:\n - The software is provided \"as is\" without any express + or implied warranties.\n\nThese terms allow for significant flexibility in + how Ruby can be used, modified, and distributed, while maintaining certain + obligations and disclaimers.","refusal":null,"role":"assistant"}}],"created":1759956312,"id":"chatcmpl-COVK41myT1Eo1nVkImrhJZxXm29hc","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":345,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":540,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":885}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:16 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/fixtures/vcr_cassettes/chat_text_models_azure_openai_azure-gpt-4o_can_understand_text.yml b/spec/fixtures/vcr_cassettes/chat_text_models_azure_openai_azure-gpt-4o_can_understand_text.yml new file mode 100644 index 000000000..9bea59ddc --- /dev/null +++ b/spec/fixtures/vcr_cassettes/chat_text_models_azure_openai_azure-gpt-4o_can_understand_text.yml @@ -0,0 +1,137 @@ +--- +http_interactions: +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":[{"type":"text","text":"What''s + in this file?"},{"type":"text","text":"Ruby + is the best."}]}],"stream":false}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1100' + Content-Type: + - application/json + Apim-Request-Id: + - 82ccfdf1-abbc-465a-9855-8e47176cb76c + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '399' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39976' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:10 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"The + file named `ruby.txt` contains the text: \"Ruby is the best.\"","refusal":null,"role":"assistant"}}],"created":1759956311,"id":"chatcmpl-COVK3sXrFkTHl9Rc4jAQLHmAGrsPg","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":18,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":31,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":49}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:11 GMT +- request: + method: post + uri: "/openai/deployments/gpt-4o/chat/completions?api-version=" + body: + encoding: UTF-8 + string: '{"model":"azure-gpt-4o","messages":[{"role":"user","content":[{"type":"text","text":"What''s + in this file?"},{"type":"text","text":"Ruby + is the best."}]},{"role":"assistant","content":"The file named `ruby.txt` + contains the text: \"Ruby is the best.\""},{"role":"user","content":[{"type":"text","text":"and + in this one?"},{"type":"text","text":"Ruby + is the best"}]}],"stream":false}' + headers: + User-Agent: + - Faraday v2.13.3 + 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: + Content-Length: + - '1174' + Content-Type: + - application/json + Apim-Request-Id: + - b2ad692d-eb66-401e-a39f-45d95d2a16f3 + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + X-Content-Type-Options: + - nosniff + X-Ms-Region: + - Canada East + X-Ratelimit-Remaining-Requests: + - '398' + X-Ratelimit-Limit-Requests: + - '400' + X-Ratelimit-Remaining-Tokens: + - '39907' + X-Ratelimit-Limit-Tokens: + - '40000' + Azureml-Model-Session: + - d066-20251002221726 + X-Accel-Buffering: + - 'no' + X-Ms-Rai-Invoked: + - 'true' + X-Request-Id: + - "" + X-Ms-Client-Request-Id: + - Not-Set + X-Ms-Deployment-Name: + - gpt-4o + Date: + - Wed, 08 Oct 2025 20:45:11 GMT + body: + encoding: UTF-8 + string: '{"choices":[{"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}},"finish_reason":"stop","index":0,"logprobs":null,"message":{"annotations":[],"content":"The + file named `ruby.xml` contains XML content with a single element:\n\n```xml\n\u003ctruism\u003eRuby + is the best\u003c/truism\u003e\n```","refusal":null,"role":"assistant"}}],"created":1759956311,"id":"chatcmpl-COVK3g9B4l9DN07FLs6FOqSYIpSzV","model":"gpt-4o-2024-08-06","object":"chat.completion","prompt_filter_results":[{"prompt_index":0,"content_filter_results":{"hate":{"filtered":false,"severity":"safe"},"self_harm":{"filtered":false,"severity":"safe"},"sexual":{"filtered":false,"severity":"safe"},"violence":{"filtered":false,"severity":"safe"}}}],"system_fingerprint":"fp_5d7ee1b844","usage":{"completion_tokens":32,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens":86,"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0},"total_tokens":118}} + + ' + recorded_at: Wed, 08 Oct 2025 20:45:12 GMT +recorded_with: VCR 6.3.1 diff --git a/spec/ruby_llm/chat_streaming_spec.rb b/spec/ruby_llm/chat_streaming_spec.rb index fc6ee8d9a..b93182a18 100644 --- a/spec/ruby_llm/chat_streaming_spec.rb +++ b/spec/ruby_llm/chat_streaming_spec.rb @@ -60,6 +60,7 @@ end it "#{provider}/#{model} supports handling streaming error chunks" do + skip 'Need to figure out how this works for Azure Open AI provider' if provider == :azure_openai # Testing if error handling is now implemented stub_error_response(provider, :chunk) @@ -75,6 +76,7 @@ it "#{provider}/#{model} supports handling streaming error events" do skip 'Bedrock uses AWS Event Stream format, not SSE events' if provider == :bedrock + skip 'Need to figure out how this works for Azure Open AI provider' if provider == :azure_openai # Testing if error handling is now implemented @@ -96,6 +98,7 @@ end it "#{provider}/#{model} supports handling streaming error chunks" do + skip 'Need to figure out how this works for Azure Open AI provider' if provider == :azure_openai # Testing if error handling is now implemented stub_error_response(provider, :chunk) @@ -111,7 +114,7 @@ it "#{provider}/#{model} supports handling streaming error events" do skip 'Bedrock uses AWS Event Stream format, not SSE events' if provider == :bedrock - + skip 'Need to figure out how this works for Azure Open AI provider' if provider == :azure_openai # Testing if error handling is now implemented stub_error_response(provider, :event) diff --git a/spec/ruby_llm/chat_tools_spec.rb b/spec/ruby_llm/chat_tools_spec.rb index 4f574a862..99ab56cb0 100644 --- a/spec/ruby_llm/chat_tools_spec.rb +++ b/spec/ruby_llm/chat_tools_spec.rb @@ -315,7 +315,8 @@ def execute(query:) end # Skip providers that don't support images in tool results - skip "#{provider} doesn't support images in tool results" if provider.in?(%i[deepseek gpustack bedrock]) + skip "#{provider} doesn't support images in tool results" if provider.in?(%i[deepseek gpustack bedrock + azure_openai]) chat = RubyLLM.chat(model: model, provider: provider) .with_tool(ContentReturningTool) diff --git a/spec/support/models_to_test.rb b/spec/support/models_to_test.rb index da9232516..e9187303b 100644 --- a/spec/support/models_to_test.rb +++ b/spec/support/models_to_test.rb @@ -11,7 +11,8 @@ { provider: :openai, model: 'gpt-4.1-nano' }, { provider: :openrouter, model: 'anthropic/claude-3.5-haiku' }, { provider: :perplexity, model: 'sonar' }, - { provider: :vertexai, model: 'gemini-2.5-flash' } + { provider: :vertexai, model: 'gemini-2.5-flash' }, + { provider: :azure_openai, model: 'azure-gpt-4o' } ].freeze PDF_MODELS = [ diff --git a/spec/support/rubyllm_configuration.rb b/spec/support/rubyllm_configuration.rb index 25a2a5b90..05995b2a4 100644 --- a/spec/support/rubyllm_configuration.rb +++ b/spec/support/rubyllm_configuration.rb @@ -16,6 +16,10 @@ config.mistral_api_key = ENV.fetch('MISTRAL_API_KEY', 'test') config.ollama_api_base = ENV.fetch('OLLAMA_API_BASE', 'http://localhost:11434/v1') + config.azure_openai_api_base = ENV.fetch('AZURE_OPENAI_ENDPOINT', 'test') + config.azure_openai_api_key = ENV.fetch('AZURE_OPENAI_API_KEY', 'test') + config.azure_openai_api_version = ENV.fetch('AZURE_OPENAI_API_VER', 'test') + config.gpustack_api_base = ENV.fetch('GPUSTACK_API_BASE', 'http://localhost:11444/v1') config.gpustack_api_key = ENV.fetch('GPUSTACK_API_KEY', nil) diff --git a/spec/support/streaming_error_helpers.rb b/spec/support/streaming_error_helpers.rb index 9c89ef9c5..0b8b3af31 100644 --- a/spec/support/streaming_error_helpers.rb +++ b/spec/support/streaming_error_helpers.rb @@ -27,6 +27,19 @@ module StreamingErrorHelpers chunk_status: 500, expected_error: RubyLLM::ServerError }, + azure_openai: { + url: 'https://project.openai.azure.com/deployments/gpt-4o/chat/completions?api_version=2025-01-01-preview', + error_response: { + error: { + message: 'The server is temporarily overloaded. Please try again later.', + type: 'server_error', + param: nil, + code: nil + } + }, + chunk_status: 500, + expected_error: RubyLLM::ServerError + }, gemini: { url: 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse', error_response: { diff --git a/spec/support/vcr_configuration.rb b/spec/support/vcr_configuration.rb index 0cdd63e7f..4a5b22525 100644 --- a/spec/support/vcr_configuration.rb +++ b/spec/support/vcr_configuration.rb @@ -27,6 +27,10 @@ config.filter_sensitive_data('') { ENV.fetch('MISTRAL_API_KEY', nil) } config.filter_sensitive_data('') { ENV.fetch('OLLAMA_API_BASE', 'http://localhost:11434/v1') } + config.filter_sensitive_data('') { ENV.fetch('AZURE_OPENAI_API_KEY', nil) } + config.filter_sensitive_data('') { ENV.fetch('AZURE_OPENAI_API_VER', nil) } + config.filter_sensitive_data('') { ENV.fetch('AZURE_OPENAI_ENDPOINT', nil) } + config.filter_sensitive_data('') { ENV.fetch('GPUSTACK_API_BASE', 'http://localhost:11444/v1') } config.filter_sensitive_data('') { ENV.fetch('GPUSTACK_API_KEY', nil) }