From e6f0374cc8844d4a053db4e68feee23ffc793d73 Mon Sep 17 00:00:00 2001 From: icebaker Date: Thu, 14 Dec 2023 22:49:06 -0300 Subject: adding support for google gemini --- spec/data/providers/google/tools.yml | 9 ++++ spec/logic/providers/google/tools_spec.rb | 78 +++++++++++++++++++++++++++++++ spec/logic/providers/openai/tools_spec.rb | 7 ++- 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 spec/data/providers/google/tools.yml create mode 100644 spec/logic/providers/google/tools_spec.rb (limited to 'spec') diff --git a/spec/data/providers/google/tools.yml b/spec/data/providers/google/tools.yml new file mode 100644 index 0000000..a5c53af --- /dev/null +++ b/spec/data/providers/google/tools.yml @@ -0,0 +1,9 @@ +--- +- functionCall: + name: get_current_weather + args: + location: Tokyo, Japan +- functionCall: + name: what_time_is_it + args: + timezone: local diff --git a/spec/logic/providers/google/tools_spec.rb b/spec/logic/providers/google/tools_spec.rb new file mode 100644 index 0000000..149a5c4 --- /dev/null +++ b/spec/logic/providers/google/tools_spec.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'yaml' + +require_relative '../../../../logic/providers/google/tools' + +RSpec.describe NanoBot::Logic::Google::Tools do + context 'tools' do + let(:cartridge) { load_symbolized('cartridges/tools.yml') } + + context 'adapt' do + it 'adapts to Google expected format' do + expect(described_class.adapt(cartridge[:tools][0])).to eq( + { name: 'what-time-is-it', + description: 'Returns the current date and time for a given timezone.', + parameters: { + type: 'object', + properties: { + timezone: { + type: 'string', + description: 'A string representing the timezone that should be used to provide a datetime, following the IANA (Internet Assigned Numbers Authority) Time Zone Database. Examples are "Asia/Tokyo" and "Europe/Paris".' + } + }, + required: ['timezone'] + } } + ) + + expect(described_class.adapt(cartridge[:tools][1])).to eq( + { name: 'get-current-weather', + description: 'Get the current weather in a given location.', + parameters: { + type: 'object', + properties: { location: { type: 'string' }, unit: { type: 'string' } } + } } + ) + + expect(described_class.adapt(cartridge[:tools][2])).to eq( + { name: 'sh', + description: "It has access to computer users' data and can be used to run shell commands, similar to those in a Linux terminal, to extract information. Please be mindful and careful to avoid running dangerous commands on users' computers.", + parameters: { + type: 'object', + properties: { + command: { + type: 'array', + description: 'An array of strings that represents a shell command along with its arguments or options. For instance, `["df", "-h"]` executes the `df -h` command, where each array element specifies either the command itself or an associated argument/option.', + items: { type: 'string' } + } + } + } } + ) + + expect(described_class.adapt(cartridge[:tools][3])).to eq( + { name: 'clock', + description: 'Returns the current date and time.', + parameters: { type: 'object', properties: {} } } + ) + end + end + + context 'prepare' do + let(:tools) { load_symbolized('providers/google/tools.yml') } + + it 'prepare tools to be executed' do + expect(described_class.prepare(cartridge[:tools], tools)).to eq( + [{ name: 'get_current_weather', + label: 'get-current-weather', + type: 'function', + parameters: { location: 'Tokyo, Japan' }, + source: { fennel: "(let [{:location location :unit unit} parameters]\n (.. \"Here is the weather in \" location \", in \" unit \": 35.8°C.\"))\n" } }, + { name: 'what_time_is_it', + label: 'what-time-is-it', + type: 'function', parameters: { timezone: 'local' }, + source: { fennel: "(os.date)\n" } }] + ) + end + end + end +end diff --git a/spec/logic/providers/openai/tools_spec.rb b/spec/logic/providers/openai/tools_spec.rb index 949d097..9757c17 100644 --- a/spec/logic/providers/openai/tools_spec.rb +++ b/spec/logic/providers/openai/tools_spec.rb @@ -78,10 +78,15 @@ RSpec.describe NanoBot::Logic::OpenAI::Tools do expect(described_class.prepare(cartridge[:tools], tools)).to eq( [{ id: 'call_XYZ', name: 'get-current-weather', + label: 'get-current-weather', type: 'function', parameters: { 'location' => 'Tokyo, Japan' }, source: { fennel: "(let [{:location location :unit unit} parameters]\n (.. \"Here is the weather in \" location \", in \" unit \": 35.8°C.\"))\n" } }, - { id: 'call_ZYX', name: 'what-time-is-it', type: 'function', parameters: {}, + { id: 'call_ZYX', + name: 'what-time-is-it', + label: 'what-time-is-it', + type: 'function', + parameters: {}, source: { fennel: "(os.date)\n" } }] ) end -- cgit v1.2.3 From fef3d5b3b2f823999fae68276382fe33872350c4 Mon Sep 17 00:00:00 2001 From: icebaker Date: Fri, 15 Dec 2023 08:04:27 -0300 Subject: improving provider options --- components/provider.rb | 2 +- components/providers/google.rb | 24 +++++++++++++++++++----- components/providers/openai.rb | 2 +- logic/cartridge/streaming.rb | 9 ++++++++- spec/data/cartridges/streaming.yml | 1 + spec/logic/cartridge/streaming_spec.rb | 19 +++++++++++++++---- static/cartridges/default.yml | 2 ++ 7 files changed, 47 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/components/provider.rb b/components/provider.rb index 2ad35f4..d83319f 100644 --- a/components/provider.rb +++ b/components/provider.rb @@ -11,7 +11,7 @@ module NanoBot when 'openai' Providers::OpenAI.new(provider[:settings], provider[:credentials], environment:) when 'google' - Providers::Google.new(provider[:model], provider[:settings], provider[:credentials], environment:) + Providers::Google.new(provider[:options], provider[:settings], provider[:credentials], environment:) else raise "Unsupported provider \"#{provider[:id]}\"" end diff --git a/components/providers/google.rb b/components/providers/google.rb index 2a99bcb..f847677 100644 --- a/components/providers/google.rb +++ b/components/providers/google.rb @@ -14,13 +14,16 @@ module NanoBot module Providers class Google < Base SETTINGS = { - safetySettings: %i[category threshold].freeze, - generationConfig: %i[temperature topP topK candidateCount maxOutputTokens stopSequences].freeze + generationConfig: %i[ + temperature topP topK candidateCount maxOutputTokens stopSequences + ].freeze }.freeze + SAFETY_SETTINGS = %i[category threshold].freeze + attr_reader :settings - def initialize(model, settings, credentials, _environment) + def initialize(options, settings, credentials, _environment) @settings = settings @client = Gemini.new( @@ -29,7 +32,7 @@ module NanoBot project_id: credentials[:'project-id'], region: credentials[:region] }, - settings: { model:, stream: false } + settings: { model: options[:model], stream: options[:stream] } ) end @@ -77,6 +80,16 @@ module NanoBot end end end + + if @settings[:safetySettings].is_a?(Array) + payload[:safetySettings] = [] unless payload.key?(:safetySettings) + + @settings[:safetySettings].each do |safety_setting| + setting = {} + SAFETY_SETTINGS.each { |key| setting[key] = safety_setting[key] } + payload[:safetySettings] << setting + end + end end if input[:tools] @@ -143,7 +156,8 @@ module NanoBot else begin result = @client.stream_generate_content( - Logic::Google::Tokens.apply_policies!(cartridge, payload) + Logic::Google::Tokens.apply_policies!(cartridge, payload), + stream: false ) rescue StandardError => e raise e.class, e.response[:body] if e.response && e.response[:body] diff --git a/components/providers/openai.rb b/components/providers/openai.rb index b70984b..f6eafd4 100644 --- a/components/providers/openai.rb +++ b/components/providers/openai.rb @@ -18,7 +18,7 @@ module NanoBot CHAT_SETTINGS = %i[ model stream temperature top_p n stop max_tokens - presence_penalty frequency_penalty logit_bias + presence_penalty frequency_penalty logit_bias seed response_format ].freeze attr_reader :settings diff --git a/logic/cartridge/streaming.rb b/logic/cartridge/streaming.rb index a0f8700..6949b3a 100644 --- a/logic/cartridge/streaming.rb +++ b/logic/cartridge/streaming.rb @@ -7,7 +7,14 @@ module NanoBot module Cartridge module Streaming def self.enabled?(cartridge, interface) - return false if Helpers::Hash.fetch(cartridge, %i[provider settings stream]) == false + provider_stream = case Helpers::Hash.fetch(cartridge, %i[provider id]) + when 'openai' + Helpers::Hash.fetch(cartridge, %i[provider settings stream]) + when 'google' + Helpers::Hash.fetch(cartridge, %i[provider options stream]) + end + + return false if provider_stream == false specific_interface = Helpers::Hash.fetch(cartridge, [:interfaces, interface, :output, :stream]) diff --git a/spec/data/cartridges/streaming.yml b/spec/data/cartridges/streaming.yml index 8234d34..e004110 100644 --- a/spec/data/cartridges/streaming.yml +++ b/spec/data/cartridges/streaming.yml @@ -10,5 +10,6 @@ interfaces: stream: true provider: + id: openai settings: stream: true diff --git a/spec/logic/cartridge/streaming_spec.rb b/spec/logic/cartridge/streaming_spec.rb index 466dd0b..4b71dfd 100644 --- a/spec/logic/cartridge/streaming_spec.rb +++ b/spec/logic/cartridge/streaming_spec.rb @@ -7,11 +7,22 @@ require_relative '../../../logic/cartridge/streaming' RSpec.describe NanoBot::Logic::Cartridge::Streaming do context 'interfaces override' do context 'defaults' do - let(:cartridge) { {} } + context 'openai' do + let(:cartridge) { { provider: { id: 'openai' } } } - it 'uses default values when appropriate' do - expect(described_class.enabled?(cartridge, :repl)).to be(true) - expect(described_class.enabled?(cartridge, :eval)).to be(true) + it 'uses default values when appropriate' do + expect(described_class.enabled?(cartridge, :repl)).to be(true) + expect(described_class.enabled?(cartridge, :eval)).to be(true) + end + end + + context 'google' do + let(:cartridge) { { provider: { id: 'google' } } } + + it 'uses default values when appropriate' do + expect(described_class.enabled?(cartridge, :repl)).to be(true) + expect(described_class.enabled?(cartridge, :eval)).to be(true) + end end end diff --git a/static/cartridges/default.yml b/static/cartridges/default.yml index 98dd47b..fbf449b 100644 --- a/static/cartridges/default.yml +++ b/static/cartridges/default.yml @@ -30,5 +30,7 @@ interfaces: feedback: true provider: + options: + stream: true settings: stream: true -- cgit v1.2.3