senior 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39730d334959dd50f95ebdf665ac8731d61fc15fda52692e61c6a521d1228b4b
4
- data.tar.gz: e2d2bb32557f3d3c7c780ec7f4293f0c56f68d885e0ed792ce2e0fce69e00b2a
3
+ metadata.gz: 448f1287d6404de5d6a2168f69b2517605310f99865992d7e4db5ffee9fc538a
4
+ data.tar.gz: f7d0392887141cd1ee232438483cebc274a6b39607d81c93a5b9033312c62415
5
5
  SHA512:
6
- metadata.gz: 30cabd4898ce92778b12e1bac480d6e6de51bf57af8a0f1356ab24f29626cbe1c778c89b89f073880bcb099e871ab45b65cbb0f162555b1a85db9014239f1342
7
- data.tar.gz: 5654b395cf96a528179988edc566ca0f4eebaa2a8f521859ba64b56f9ba1ffe60ef8a457c71f7d5da3a9ed2920b96568245fe676b2a9711b2cd9ca105cb47c1f
6
+ metadata.gz: be9c24e647fe23cbb5e5e8580d775ab0822672856b2bc4f1bc0567a61ad9677e455b08e73aad7e95f51a1a3835809abd640220fcb6c8c249f6276376f5203021
7
+ data.tar.gz: 8210280b84ae3c47b5442a1a7ae8b6cdf23cd9bdc7b255701d8b6808f7864267e855bc730b424e567abd44d5de8607f7a324256ef5e1762b9a3c92599be81b2d
data/.rubocop.yml CHANGED
@@ -44,3 +44,6 @@ Metrics/MethodLength:
44
44
 
45
45
  RSpec/ExampleLength:
46
46
  Enabled: false
47
+
48
+ RSpec/NestedGroups:
49
+ Max: 4
data/CHANGELOG.md CHANGED
@@ -2,9 +2,6 @@
2
2
 
3
3
  - Ability to wrap a method invocation. For example, `Senior.suggest_fix { my_broken_method(2) }`
4
4
  - Test generation `Senior.write_tests_for {}`
5
- - Configure API keys for the OpenAI
6
- - Use different OpenAI models
7
- - Parametrize the calls to OpenAI
8
5
  - See price per call
9
6
  - Set API calling and pricing limits
10
7
  - Use different AI APIs, not just OpenAI
@@ -13,6 +10,28 @@
13
10
  - RBS Signatures
14
11
  - Domain exceptions
15
12
 
13
+ ## [0.2.0] - 2023-04-10
14
+
15
+ ### Added
16
+ - Added the ability to configure the gem with a block:
17
+ ```ruby
18
+ Senior.configure do |config|
19
+ config.open_ai.access_token = ENV.fetch('OPEN_AI_ACCESS_TOKEN')
20
+ config.open_ai.organization_id = ENV.fetch('OPEN_AI_ORGANIZATION_ID') # Optional
21
+ config.open_ai.api_version = 'v1'
22
+ config.open_ai.max_tokens = 1024
23
+ config.open_ai.model = 'text-davinci-003'
24
+ config.open_ai.n = 1
25
+ config.open_ai.request_timeout = 120
26
+ config.open_ai.temperature = 0.7
27
+ config.open_ai.uri_base = 'https://api.openai.com/'
28
+ end
29
+ ```
30
+ These configurations are used as default values for the OpenAI API calls.
31
+
16
32
  ## [0.1.0] - 2023-04-10
17
33
 
18
34
  - Initial release
35
+
36
+ [0.2.0]: https://github.com/wilsonsilva/senior/compare/v0.1.0...v0.2.0
37
+ [0.1.0]: https://github.com/wilsonsilva/senior/compare/eecec20...v0.1.0
data/README.md CHANGED
@@ -2,10 +2,24 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/senior.svg)](https://badge.fury.io/rb/senior)
4
4
  [![Tests](https://github.com/wilsonsilva/senior/actions/workflows/main.yml/badge.svg)](https://github.com/wilsonsilva/senior/actions/workflows/main.yml)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/87e6e2167d3283e3b79b/test_coverage)](https://codeclimate.com/github/wilsonsilva/senior/test_coverage)
6
+ [![Maintainability](https://api.codeclimate.com/v1/badges/87e6e2167d3283e3b79b/maintainability)](https://codeclimate.com/github/wilsonsilva/senior/maintainability)
5
7
 
6
8
  Provides AI-powered debugging and automatic suggestion of code fixes. It makes use of OpenAI's language model to analyze
7
9
  and modify the source code of broken methods, allowing them to be fixed automatically.
8
10
 
11
+ ## Table of Contents
12
+
13
+ - [Installation](#installation)
14
+ - [Usage](#usage)
15
+ - [Auto-debugging a broken method](#auto-debugging-a-broken-method)
16
+ - [Suggesting a fix for a broken method](#suggesting-a-fix-for-a-broken-method)
17
+ - [Development](#development)
18
+ - [Type checking](#type-checking)
19
+ - [Contributing](#contributing)
20
+ - [License](#license)
21
+ - [Code of Conduct](#code-of-conduct)
22
+
9
23
  ## Installation
10
24
 
11
25
  Install the gem and add to the application's Gemfile by executing:
@@ -18,8 +32,23 @@ If bundler is not being used to manage dependencies, install the gem by executin
18
32
 
19
33
  ## Usage
20
34
 
21
- Before using Senior, ensure that the environment variables `OPEN_AI_ACCESS_TOKEN` and `OPEN_AI_ORGANIZATION_ID` are
22
- defined. These variables are used by the gem to authenticate and access OpenAI's language model.
35
+ - Get your API key from https://platform.openai.com/account/api-keys
36
+ - (optional) If you belong to multiple organizations, you can get your Organization ID from https://platform.openai.com/account/org-settings
37
+ - Configure the library by passing your OpenAI API credentials:
38
+
39
+ ```ruby
40
+ Senior.configure do |config|
41
+ config.open_ai.access_token = ENV.fetch('OPEN_AI_ACCESS_TOKEN')
42
+ config.open_ai.organization_id = ENV.fetch('OPEN_AI_ORGANIZATION_ID') # Optional
43
+ end
44
+ ```
45
+
46
+ Note that `OPEN_AI_ACCESS_TOKEN` and `OPEN_AI_ORGANIZATION_ID` are environment variables that should be set in your
47
+ environment. You should never hardcode your API credentials directly in your code, as this is a security risk.
48
+ Instead, store your API credentials securely, such as using environment variables or a separate configuration file that
49
+ is excluded from source control.
50
+
51
+ Once you have configured the library, you can use the Senior module to interact with the OpenAI API.
23
52
 
24
53
  ### Auto-debugging a broken method
25
54
  To debug a broken method, call Senior.auto_debug and pass in the broken method, its arguments, and optionally its
@@ -45,8 +45,8 @@ module Senior
45
45
  #
46
46
  def open_ai_client
47
47
  @open_ai_client ||= ::OpenAI::Client.new(
48
- access_token: ENV.fetch('OPEN_AI_ACCESS_TOKEN'),
49
- organization_id: ENV.fetch('OPEN_AI_ORGANIZATION_ID')
48
+ access_token: Senior.configuration.open_ai.access_token,
49
+ organization_id: Senior.configuration.open_ai.organization_id
50
50
  )
51
51
  end
52
52
 
@@ -55,19 +55,18 @@ module Senior
55
55
  # @api private
56
56
  #
57
57
  # @param prompt [String] The prompt for which to generate a completion
58
- # @param max_tokens [Integer] The maximum number of tokens to generate in the completion. Default value is 1024
59
58
  #
60
59
  # @return [String] The create completion
61
60
  #
62
- def request_completion(prompt, max_tokens = 1024)
61
+ def request_completion(prompt)
63
62
  response = open_ai_client.completions(
64
63
  parameters: {
65
- model: 'text-davinci-003',
64
+ model: defaults.model,
66
65
  prompt:,
67
- max_tokens:,
68
- n: 1,
66
+ max_tokens: defaults.max_tokens,
67
+ n: defaults.n,
69
68
  stop: nil,
70
- temperature: 0.7
69
+ temperature: defaults.temperature
71
70
  }
72
71
  )
73
72
 
@@ -75,6 +74,16 @@ module Senior
75
74
 
76
75
  response.dig('choices', 0, 'text').strip
77
76
  end
77
+
78
+ # Returns the default configuration object for the OpenAI brain
79
+ #
80
+ # @api private
81
+ #
82
+ # @return [Senior::Configuration::OpenAI] The default configuration object for the OpenAI brain.
83
+ #
84
+ def defaults
85
+ Senior.configuration.open_ai
86
+ end
78
87
  end
79
88
  end
80
89
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'senior/configuration/open_ai'
4
+
5
+ module Senior
6
+ module Configuration
7
+ # Index file for all configurations of the gem
8
+ #
9
+ # @api public
10
+ #
11
+ class Main
12
+ # The OpenAI configuration
13
+ #
14
+ # @api public
15
+ #
16
+ #
17
+ # @example
18
+ # configuration = Senior::Configuration::Main.new
19
+ # configuration.open_ai # => #<Configuration::OpenAI:0x00007fa2a61a63d8>
20
+ #
21
+ # @return [Configuration::OpenAI] The OpenAI configuration
22
+ #
23
+ attr_accessor :open_ai
24
+
25
+ # Initializes a new instance of the configuration for the Senior gem
26
+ #
27
+ # @api public
28
+ #
29
+ # @example
30
+ # configuration = Senior::Configuration::Main.new
31
+ #
32
+ def initialize
33
+ @open_ai = Configuration::OpenAI.new
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Senior
4
+ module Configuration
5
+ # Encapsulates the OpenAI configuration
6
+ #
7
+ # @api public
8
+ class OpenAI
9
+ # The OpenAI access token
10
+ #
11
+ # @return [String, nil] The OpenAI access token, or nil if not set
12
+ #
13
+ # @example
14
+ # configuration = Senior::Configuration::OpenAI.new
15
+ # configuration.access_token = 'your_openai_api_key'
16
+ attr_writer :access_token
17
+
18
+ # The OpenAI API version
19
+ #
20
+ # @return [String] The OpenAI API version
21
+ #
22
+ # @example
23
+ # configuration = Senior::Configuration::OpenAI.new
24
+ # configuration.api_version = 'v1'
25
+ attr_accessor :api_version
26
+
27
+ # The maximum number of tokens to use in the OpenAI API request
28
+ #
29
+ # @return [Integer] The maximum number of tokens to use in the OpenAI API request
30
+ #
31
+ # @example
32
+ # configuration = Senior::Configuration::OpenAI.new
33
+ # configuration.max_tokens = 1024
34
+ attr_accessor :max_tokens
35
+
36
+ # The OpenAI model to use
37
+ #
38
+ # @return [String] The OpenAI model to use
39
+ #
40
+ # @example
41
+ # configuration = Senior::Configuration::OpenAI.new
42
+ # configuration.model = 'text-davinci-003'
43
+ attr_accessor :model
44
+
45
+ # The number of responses to generate
46
+ #
47
+ # @return [Integer] The number of responses to generate
48
+ #
49
+ # @example
50
+ # configuration = Senior::Configuration::OpenAI.new
51
+ # configuration.n = 1
52
+ attr_accessor :n
53
+
54
+ # The OpenAI organization ID
55
+ #
56
+ # @return [String, nil] The OpenAI organization ID, or nil if not set
57
+ #
58
+ # @example
59
+ # configuration = Senior::Configuration::OpenAI.new
60
+ # configuration.organization_id = 'your_organization_id'
61
+ attr_accessor :organization_id
62
+
63
+ # The maximum amount of time to wait for an OpenAI API request to complete
64
+ #
65
+ # @return [Integer] The maximum amount of time to wait for an OpenAI API request to complete
66
+ #
67
+ # @example
68
+ # configuration = Senior::Configuration::OpenAI.new
69
+ # configuration.request_timeout = 120
70
+ attr_accessor :request_timeout
71
+
72
+ # The temperature to use in the OpenAI API request
73
+ #
74
+ # @return [Float] The temperature to use in the OpenAI API request
75
+ #
76
+ # @example
77
+ # configuration = Senior::Configuration::OpenAI.new
78
+ # configuration.temperature = 0.7
79
+ attr_accessor :temperature
80
+
81
+ # The OpenAI URI base
82
+ #
83
+ # @return [String] The OpenAI URI base
84
+ #
85
+ # @example
86
+ # configuration = Senior::Configuration::OpenAI.new
87
+ # configuration.uri_base = 'https://api.openai.com/'
88
+ attr_accessor :uri_base
89
+
90
+ # The default OpenAI API version
91
+ DEFAULT_API_VERSION = 'v1'
92
+
93
+ # The default maximum number of tokens to use in the OpenAI API request
94
+ DEFAULT_MAX_TOKENS = 1024
95
+
96
+ # The default OpenAI model to use
97
+ DEFAULT_MODEL = 'text-davinci-003'
98
+
99
+ # The default number of responses to generate
100
+ DEFAULT_N = 1
101
+
102
+ # The default maximum amount of time to wait for an OpenAI API request to complete
103
+ DEFAULT_REQUEST_TIMEOUT = 120
104
+
105
+ # The default temperature to use in the OpenAI API request
106
+ DEFAULT_TEMPERATURE = 0.7
107
+
108
+ # The default OpenAI URI base
109
+ DEFAULT_URI_BASE = 'https://api.openai.com/'
110
+
111
+ # Initializes a new instance of the OpenAI configuration for the Senior gem
112
+ #
113
+ # @example
114
+ # configuration = Senior::Configuration::OpenAI.new
115
+ #
116
+ def initialize
117
+ @access_token = nil
118
+ @api_version = DEFAULT_API_VERSION
119
+ @max_tokens = DEFAULT_MAX_TOKENS
120
+ @model = DEFAULT_MODEL
121
+ @n = DEFAULT_N
122
+ @organization_id = nil
123
+ @request_timeout = DEFAULT_REQUEST_TIMEOUT
124
+ @temperature = DEFAULT_TEMPERATURE
125
+ @uri_base = DEFAULT_URI_BASE
126
+ end
127
+
128
+ # Gets the OpenAI access token, raising an error if it is not set
129
+ #
130
+ # @raise [ConfigurationError] If the OpenAI access token is not set
131
+ #
132
+ # @return [String] The OpenAI access token.
133
+ #
134
+ # @example
135
+ # configuration = Senior::Configuration::OpenAI.new
136
+ # configuration.access_token # => raises ConfigurationError if access token is not set
137
+ #
138
+ def access_token
139
+ return @access_token if @access_token
140
+
141
+ error_text = 'OpenAI access token missing! See https://github.com/wilsonsilva/senior#usage'
142
+ raise ConfigurationError, error_text
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Senior
4
+ # Base class for all Senior's errors
5
+ class Error < StandardError; end
6
+
7
+ # Raised when the gem's configuration is faulty
8
+ class ConfigurationError < Error; end
9
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Senior
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/senior.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'senior/errors'
4
+ require_relative 'senior/configuration/main'
3
5
  require_relative 'senior/brains/open_ai'
4
6
  require_relative 'senior/agent'
5
7
  require_relative 'senior/version'
@@ -56,4 +58,32 @@ module Senior
56
58
  def self.agent
57
59
  @agent ||= Agent.new
58
60
  end
61
+
62
+ # Returns the configuration object for the Senior gem
63
+ #
64
+ # @api private
65
+ #
66
+ # @return [Senior::Configuration::Main] The configuration object for the Senior gem
67
+ #
68
+ def self.configuration
69
+ @configuration ||= Configuration::Main.new
70
+ end
71
+
72
+ # Provides a way to configure the Senior gem
73
+ #
74
+ # @api public
75
+ #
76
+ # @yield [configuration] A block to configure the Senior gem
77
+ # @yieldparam configuration [Senior::Configuration::Main] The configuration object for the Senior gem
78
+ #
79
+ # @example Configuring the Senior gem
80
+ # Senior.configure do |config|
81
+ # config.open_ai.access_token = 'your_openai_api_key'
82
+ # end
83
+ #
84
+ # @return [void]
85
+ #
86
+ def self.configure
87
+ yield(configuration)
88
+ end
59
89
  end
@@ -8,7 +8,8 @@ module Senior
8
8
  private
9
9
 
10
10
  def open_ai_client: -> untyped
11
- def request_completion: (String prompt, ?Integer max_tokens) -> String
11
+ def request_completion: (String prompt) -> String
12
+ def defaults: -> Senior::Configuration::OpenAI
12
13
  end
13
14
  end
14
15
  end
@@ -0,0 +1,7 @@
1
+ module Senior
2
+ module Configuration
3
+ class Main
4
+ attr_accessor open_ai: Configuration::OpenAI
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,26 @@
1
+ module Senior
2
+ module Configuration
3
+ class OpenAI
4
+ DEFAULT_API_VERSION: String
5
+ DEFAULT_MAX_TOKENS: Integer
6
+ DEFAULT_MODEL: String
7
+ DEFAULT_N: Integer
8
+ DEFAULT_REQUEST_TIMEOUT: Integer
9
+ DEFAULT_TEMPERATURE: Float
10
+ DEFAULT_URI_BASE: String
11
+
12
+ attr_writer access_token: String?|nil
13
+ attr_accessor api_version: String
14
+ attr_accessor max_tokens: Integer
15
+ attr_accessor model: String
16
+ attr_accessor n: Integer
17
+ attr_accessor organization_id: String?|nil
18
+ attr_accessor request_timeout: Integer
19
+ attr_accessor temperature: Float
20
+ attr_accessor uri_base: String
21
+
22
+ def initialize: -> void
23
+ def access_token: -> String?
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ module Senior
2
+ class Error < StandardError
3
+ end
4
+
5
+ class ConfigurationError < Error
6
+ end
7
+ end
data/sig/senior.rbs CHANGED
@@ -1,12 +1,11 @@
1
1
  module Senior
2
2
  VERSION: String
3
+ self.@configuration: Configuration::Main
3
4
  self.@agent: Agent
4
5
 
5
6
  def self.auto_debug: (Method broken_method, untyped args, String? | nil broken_method_source) -> untyped
6
-
7
7
  def self.suggest_fix: (Method broken_method, untyped args) -> String
8
-
9
- private
10
-
8
+ def self.configuration: -> Configuration::Main
9
+ def self.configure: -> untyped
11
10
  def self.agent: -> Agent
12
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: senior
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wilson Silva
@@ -361,7 +361,7 @@ dependencies:
361
361
  - !ruby/object:Gem::Version
362
362
  version: '0.9'
363
363
  description: |-
364
- This gem provides a simple interface to OpenAI's GPT4 API for code repair. Given a piece of broken
364
+ This gem provides a simple interface to OpenAI's GPT API for code repair. Given a piece of broken
365
365
  code, the gem generates a corrected version.
366
366
  email:
367
367
  - wilson.dsigns@gmail.com
@@ -387,6 +387,9 @@ files:
387
387
  - lib/senior.rb
388
388
  - lib/senior/agent.rb
389
389
  - lib/senior/brains/open_ai.rb
390
+ - lib/senior/configuration/main.rb
391
+ - lib/senior/configuration/open_ai.rb
392
+ - lib/senior/errors.rb
390
393
  - lib/senior/version.rb
391
394
  - sig/gems/method_source/method.rbs
392
395
  - sig/gems/ruby-openai/client.rbs
@@ -394,6 +397,9 @@ files:
394
397
  - sig/senior/agent.rbs
395
398
  - sig/senior/brains/i_brain.rbs
396
399
  - sig/senior/brains/open_ai.rbs
400
+ - sig/senior/configuration/main.rbs
401
+ - sig/senior/configuration/open_ai.rbs
402
+ - sig/senior/errors.rbs
397
403
  homepage: https://github.com/wilsonsilva/senior
398
404
  licenses:
399
405
  - MIT