ai-chat 0.5.8 → 0.6.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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -17
  3. data/ai-chat.gemspec +1 -1
  4. data/lib/ai/chat.rb +42 -27
  5. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f564a7f3f476e11c343959e35eaf035f5c3e384fbc6f6ed33cdd85513bd38dcf
4
- data.tar.gz: d40af116bbbf374efa1b6be1370b94f7909d8de86fbf530a69bbabee86dbc21d
3
+ metadata.gz: 50c5c8743e007a3b5dee31d4d56e81073fd28b6bcf92fbb5d0fe0671bbbfac2e
4
+ data.tar.gz: 2cf832e2e5a211612f281e2058590bced4550fae4f60fc0410e7da37058cc010
5
5
  SHA512:
6
- metadata.gz: 6c0360ac379bb0db811199fa379aa03c778647e449638bb58204780631ced200d5983efca20ccd44acde047d0de87da4ef1ecaeedb4f4a88656a98f1aa77a539
7
- data.tar.gz: 664c82f27d85fec5ccf99122179902a4f910cf4854f50335638ac7458a61c4d9b3afc39f52aea69c0fc6856706cef25a17006f99904103bbf162a51e695ec8ee
6
+ metadata.gz: 53732280a8dc68de3bb9e90b174b6b3bf092f43e2fdfa997bbe499e253151570c713ee7166235a0c2e0494ae9b743b729ba8a7bea82e0aa26020baed16e14fd0
7
+ data.tar.gz: d0429dd257cc64fa91d31b0aa7543d21faa32aef74249f98d63810f71e63891bb32e878f571e2367e78b0bb098b9eaea79e8404ab1a380c0668124df37aa18e9
data/README.md CHANGED
@@ -238,7 +238,7 @@ See [OpenAI's model documentation](https://platform.openai.com/docs/models) for
238
238
 
239
239
  ### API key
240
240
 
241
- The gem by default looks for `AICHAT_API_KEY` first. If that is missing (or empty), it falls back to `OPENAI_API_KEY`.
241
+ By default, the gem uses `OPENAI_API_KEY`. When proxy mode is enabled (`AICHAT_PROXY=true`), it uses `AICHAT_PROXY_KEY` instead.
242
242
 
243
243
  You can specify a different environment variable name:
244
244
 
@@ -404,7 +404,7 @@ AI::Chat.generate_schema!("A user profile with name (required), email (required)
404
404
 
405
405
  This method returns a String containing the JSON schema. The JSON schema also writes (or overwrites) to `schema.json` at the root of the project.
406
406
 
407
- Similar to generating messages with `AI::Chat` objects, this class method will look for `AICHAT_API_KEY` first, then fall back to `OPENAI_API_KEY` if needed. You can also pass the API key directly or choose a different environment variable key for it to use.
407
+ This class method uses the same API key and proxy resolution as `AI::Chat.new`. You can also pass the API key directly or choose a different environment variable:
408
408
 
409
409
  ```rb
410
410
  # Passing the API key directly
@@ -414,7 +414,7 @@ AI::Chat.generate_schema!("A user with full name (required), first_name (require
414
414
  AI::Chat.generate_schema!("A user with full name (required), first_name (required), and last_name (required).", api_key_env_var: "CUSTOM_KEY")
415
415
  ```
416
416
 
417
- `generate_schema!` also follows proxy defaults from the `AICHAT_PROXY` environment variable. Proxy is enabled only when `AICHAT_PROXY` is exactly `"true"`.
417
+ `generate_schema!` also follows proxy defaults from the `AICHAT_PROXY` environment variable.
418
418
 
419
419
  ```bash
420
420
  export AICHAT_PROXY=true
@@ -617,28 +617,30 @@ message = chat.get_response(wait: true, timeout: 600)
617
617
  puts message[:content]
618
618
  ```
619
619
 
620
- ## Proxying Through prepend.me
620
+ ## Proxying Through Prepend.me
621
621
 
622
- You can proxy API calls through [prepend.me](https://prepend.me/).
622
+ You can proxy API calls through [Prepend.me](https://prepend.me/). When proxy mode is enabled, the gem uses the `AICHAT_PROXY_KEY` environment variable instead of `OPENAI_API_KEY`.
623
+
624
+ You can enable proxy mode at construction time:
623
625
 
624
626
  ```rb
625
- chat = AI::Chat.new
626
- chat.proxy = true
627
- chat.user("Tell me a story")
628
- chat.generate!
629
- puts chat.last[:content]
630
- # => "Once upon a time..."
627
+ chat = AI::Chat.new(proxy: true)
631
628
  ```
632
629
 
633
- You can also default proxy mode from the environment for both `AI::Chat.new` and `AI::Chat.generate_schema!`:
630
+ Or default it from the environment (case-insensitive):
634
631
 
635
632
  ```bash
636
633
  export AICHAT_PROXY=true
637
634
  ```
638
635
 
639
- Proxy is enabled only when `AICHAT_PROXY` is exactly `"true"`. Any other value (including `"TRUE"` or `"1"`) leaves proxy disabled unless you explicitly set `chat.proxy = true` or pass `proxy: true`.
636
+ Or toggle it on an existing instance:
637
+
638
+ ```rb
639
+ chat = AI::Chat.new
640
+ chat.proxy = true
641
+ ```
640
642
 
641
- When proxy is enabled, **you must use the API key provided by prepend.me** in place of a real OpenAI API key. Refer to [the section on API keys](#api-key) for options on how to set your key.
643
+ When proxy is enabled, **you must set `AICHAT_PROXY_KEY`** with your API key from Prepend.me.
642
644
 
643
645
  ## Building Conversations Without API Calls
644
646
 
@@ -748,9 +750,7 @@ This is particularly useful for background mode workflows. If you want to retrie
748
750
  ```ruby
749
751
  require "openai"
750
752
 
751
- api_key = ENV["AICHAT_API_KEY"]
752
- api_key = ENV.fetch("OPENAI_API_KEY") if api_key.nil? || api_key.empty?
753
- client = OpenAI::Client.new(api_key: api_key)
753
+ client = OpenAI::Client.new(api_key: ENV.fetch("OPENAI_API_KEY"))
754
754
 
755
755
  response_id = "resp_abc123..." # e.g., load from your database
756
756
  response = client.responses.retrieve(response_id)
data/ai-chat.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "ai-chat"
5
- spec.version = "0.5.8"
5
+ spec.version = "0.6.0"
6
6
  spec.authors = ["Raghu Betina", "Jelani Woods"]
7
7
  spec.email = ["raghu@firstdraft.com", "jelani@firstdraft.com"]
8
8
  spec.homepage = "https://github.com/firstdraft/ai-chat"
data/lib/ai/chat.rb CHANGED
@@ -22,10 +22,15 @@ module AI
22
22
  attr_reader :client, :last_response_id, :proxy, :schema, :schema_file, :verbosity
23
23
 
24
24
  BASE_PROXY_URL = "https://prepend.me/api.openai.com/v1"
25
-
26
- def initialize(api_key: nil, api_key_env_var: nil)
27
- @api_key = self.class.resolve_api_key(api_key: api_key, api_key_env_var: api_key_env_var)
28
- @proxy = ENV["AICHAT_PROXY"] == "true"
25
+ PROXY_ENV = "AICHAT_PROXY"
26
+ PROXY_KEY_ENV = "AICHAT_PROXY_KEY"
27
+ OPENAI_KEY_ENV = "OPENAI_API_KEY"
28
+
29
+ def initialize(api_key: nil, api_key_env_var: nil, proxy: nil)
30
+ @api_key_arg = api_key
31
+ @api_key_env_var_arg = api_key_env_var
32
+ @proxy = proxy.nil? ? ENV[PROXY_ENV]&.downcase == "true" : !!proxy
33
+ @api_key = resolve_api_key
29
34
  @messages = []
30
35
  @reasoning_effort = nil
31
36
  @model = "gpt-5.2"
@@ -40,8 +45,8 @@ module AI
40
45
  end
41
46
 
42
47
  def self.generate_schema!(description, location: "schema.json", api_key: nil, api_key_env_var: nil, proxy: nil)
43
- api_key = resolve_api_key(api_key: api_key, api_key_env_var: api_key_env_var)
44
- proxy = ENV["AICHAT_PROXY"] == "true" if proxy.nil?
48
+ proxy = proxy.nil? ? ENV[PROXY_ENV]&.downcase == "true" : !!proxy
49
+ api_key = api_key || ENV.fetch(api_key_env_var || (proxy ? PROXY_KEY_ENV : OPENAI_KEY_ENV))
45
50
  prompt_path = File.expand_path("../prompts/schema_generator.md", __dir__)
46
51
  system_prompt = File.read(prompt_path)
47
52
 
@@ -73,16 +78,6 @@ module AI
73
78
  content
74
79
  end
75
80
 
76
- def self.resolve_api_key(api_key: nil, api_key_env_var: nil)
77
- return api_key if api_key
78
- return ENV.fetch(api_key_env_var) if api_key_env_var
79
-
80
- aichat_api_key = ENV["AICHAT_API_KEY"]
81
- return aichat_api_key if aichat_api_key && !aichat_api_key.empty?
82
-
83
- ENV.fetch("OPENAI_API_KEY")
84
- end
85
-
86
81
  # :reek:TooManyStatements
87
82
  # :reek:NilCheck
88
83
  def add(content, role: "user", response: nil, status: nil, image: nil, images: nil, file: nil, files: nil)
@@ -169,15 +164,20 @@ module AI
169
164
  end
170
165
 
171
166
  def proxy=(value)
172
- @proxy = value
173
- @client = if value
174
- OpenAI::Client.new(
175
- api_key: @api_key,
176
- base_url: BASE_PROXY_URL
177
- )
178
- else
179
- OpenAI::Client.new(api_key: @api_key)
180
- end
167
+ new_proxy = !!value
168
+ previous_proxy = @proxy
169
+ @proxy = new_proxy
170
+ new_key = resolve_api_key
171
+ client_options = {api_key: new_key}
172
+ client_options[:base_url] = BASE_PROXY_URL if new_proxy
173
+ new_client = OpenAI::Client.new(**client_options)
174
+
175
+ @api_key = new_key
176
+ @api_key_validated = false
177
+ @client = new_client
178
+ rescue => error
179
+ @proxy = previous_proxy
180
+ raise
181
181
  end
182
182
 
183
183
  def schema=(value)
@@ -262,6 +262,21 @@ module AI
262
262
 
263
263
  private
264
264
 
265
+ def resolve_api_key
266
+ env_var = @api_key_env_var_arg || (@proxy ? PROXY_KEY_ENV : OPENAI_KEY_ENV)
267
+ @api_key_arg || ENV.fetch(env_var) {
268
+ if @proxy
269
+ raise KeyError, "Proxy mode is enabled but #{PROXY_KEY_ENV} is not set. " \
270
+ "Create an environment variable called #{PROXY_KEY_ENV} " \
271
+ "with your API key from Prepend.me."
272
+ else
273
+ raise KeyError, "#{OPENAI_KEY_ENV} is not set. " \
274
+ "Create an environment variable called #{OPENAI_KEY_ENV} " \
275
+ "with your API key from https://platform.openai.com/api-keys."
276
+ end
277
+ }
278
+ end
279
+
265
280
  class InputClassificationError < StandardError; end
266
281
 
267
282
  class WrongAPITokenUsedError < StandardError; end
@@ -597,11 +612,11 @@ module AI
597
612
  rescue OpenAI::Errors::AuthenticationError
598
613
  message = if proxy
599
614
  <<~STRING
600
- It looks like you're using an invalid API key. Proxying is enabled, so you must use an OpenAI API key from prepend.me. Please disable proxy or update your API key before generating a response.
615
+ Your API key was not accepted by Prepend.me. Since proxy mode is enabled, you need a valid API key from Prepend.me in the #{PROXY_KEY_ENV} environment variable.
601
616
  STRING
602
617
  else
603
618
  <<~STRING
604
- It looks like you're using an invalid API key. Check to make sure your API key is valid before generating a response.
619
+ Your API key was not accepted by OpenAI. Make sure the #{OPENAI_KEY_ENV} environment variable contains a valid key from https://platform.openai.com/api-keys.
605
620
  STRING
606
621
  end
607
622
  raise WrongAPITokenUsedError, message, cause: nil
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ai-chat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.8
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Raghu Betina