openai-term 3.0.2 → 3.0.3

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 (3) hide show
  1. checksums.yaml +4 -4
  2. data/bin/openai +69 -29
  3. metadata +4 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3fb2544c45742c1bd784318ce02cc766f8724ef9a1d51827fb4efbf64559447c
4
- data.tar.gz: 41f43c059ace1ca015899fc01ac59592eb7558f24b313588b6b25d27280f56b1
3
+ metadata.gz: 1b541d1b3b223edaa022070e38cbf187104deed56fe67f321c3197a3ff7c2992
4
+ data.tar.gz: 5d6f9cf9ee175e59b6b90a790c2ae273a12cad80069ca1662a64b14ba4ecd199
5
5
  SHA512:
6
- metadata.gz: 7b362f3fb442ad40d3154d5e969d02b8fed6b15b74caed1fadff50d62da4968cc4da4379cce731e10d83672a2c412e3985dbf1dc1eea614b69044b434705899d
7
- data.tar.gz: abaa7268da5b0d47be8aa554fbab1b1e9043455a2f5d5d864bf732c6f9559fcd6e8c044379af28a72e91ea1abf8724a84897fbb59db76bf908407dab1292119d
6
+ metadata.gz: e4de85e3718a0c94b6d8173a25424222e4b496960207151953a07557046ef81be336f495235439c25c31c324e3998de5b5e2c384aa0dc805d6ed95055aebdc00
7
+ data.tar.gz: 1e0f248ac0d35859d2a2fee6446358205f454f5b4e37b75da83828803f8ca2f512a230f7f139c285e7f1cf7c4748bcfe4e734e21f55011c7c1f55dc573e173e1
data/bin/openai CHANGED
@@ -18,7 +18,10 @@ CONFIG_FILE = File.join(Dir.home, '.openai.conf')
18
18
  HISTORY_FILE = File.join(Dir.home, '.openai_history.json')
19
19
  DEFAULT_MODEL = "gpt-4-turbo-preview"
20
20
  DEFAULT_MAX_TOKENS = 2048
21
- VERSION = "3.0.2"
21
+ VERSION = "3.0.3"
22
+ REQUEST_TIMEOUT = 30
23
+ MAX_RETRIES = 2
24
+ RETRY_DELAY = 2
22
25
 
23
26
  # Global variables
24
27
  @model = DEFAULT_MODEL
@@ -138,10 +141,39 @@ end
138
141
  # Initialize OpenAI client
139
142
  def init_client
140
143
  @client = OpenAI::Client.new(
141
- access_token: @api_key
144
+ access_token: @api_key,
145
+ request_timeout: REQUEST_TIMEOUT
142
146
  )
143
147
  end
144
148
 
149
+ # Retry wrapper for transient API failures
150
+ def with_retry
151
+ retries = 0
152
+ begin
153
+ yield
154
+ rescue Net::OpenTimeout, Net::ReadTimeout, Errno::ETIMEDOUT => e
155
+ if retries < MAX_RETRIES
156
+ retries += 1
157
+ msg = "Timeout, retrying (#{retries}/#{MAX_RETRIES})..."
158
+ @chat_pane ? add_to_chat("system", msg.fg(208)) : $stderr.puts(msg)
159
+ sleep(RETRY_DELAY)
160
+ retry
161
+ end
162
+ raise
163
+ rescue Faraday::Error => e
164
+ status = e.respond_to?(:response_status) ? e.response_status : nil
165
+ if status && [429, 500, 502, 503].include?(status) && retries < MAX_RETRIES
166
+ retries += 1
167
+ delay = status == 429 ? RETRY_DELAY * 2 : RETRY_DELAY
168
+ msg = "HTTP #{status}, retrying (#{retries}/#{MAX_RETRIES})..."
169
+ @chat_pane ? add_to_chat("system", msg.fg(208)) : $stderr.puts(msg)
170
+ sleep(delay)
171
+ retry
172
+ end
173
+ raise
174
+ end
175
+ end
176
+
145
177
  # Setup UI
146
178
  def setup_ui
147
179
  unless $stdin.tty?
@@ -309,13 +341,15 @@ def get_openai_response(message, generate_image = false)
309
341
 
310
342
  begin
311
343
  if generate_image
312
- response = @client.images.generate(
313
- parameters: {
314
- prompt: message,
315
- n: 1,
316
- size: "1024x1024"
317
- }
318
- )
344
+ response = with_retry do
345
+ @client.images.generate(
346
+ parameters: {
347
+ prompt: message,
348
+ n: 1,
349
+ size: "1024x1024"
350
+ }
351
+ )
352
+ end
319
353
 
320
354
  url = response.dig("data", 0, "url")
321
355
  if url
@@ -334,28 +368,32 @@ def get_openai_response(message, generate_image = false)
334
368
  end
335
369
  end
336
370
 
337
- response = @client.chat(
338
- parameters: {
339
- model: @model,
340
- messages: messages,
341
- max_tokens: @max_tokens,
342
- temperature: @temperature
343
- }
344
- )
371
+ response = with_retry do
372
+ @client.chat(
373
+ parameters: {
374
+ model: @model,
375
+ messages: messages,
376
+ max_tokens: @max_tokens,
377
+ temperature: @temperature
378
+ }
379
+ )
380
+ end
345
381
 
346
382
  content = response.dig("choices", 0, "message", "content")
347
383
  else
348
384
  # Use completion for older models
349
385
  prompt = @current_conversation.map { |m| "#{m['role']}: #{m['content']}" }.join("\n") + "\nassistant:"
350
386
 
351
- response = @client.completions(
352
- parameters: {
353
- model: @model,
354
- prompt: prompt,
355
- max_tokens: @max_tokens,
356
- temperature: @temperature
357
- }
358
- )
387
+ response = with_retry do
388
+ @client.completions(
389
+ parameters: {
390
+ model: @model,
391
+ prompt: prompt,
392
+ max_tokens: @max_tokens,
393
+ temperature: @temperature
394
+ }
395
+ )
396
+ end
359
397
 
360
398
  content = response.dig("choices", 0, "text")
361
399
  end
@@ -398,7 +436,7 @@ def show_model_selection
398
436
 
399
437
  # Get available models
400
438
  begin
401
- models_response = @client.models.list
439
+ models_response = with_retry { @client.models.list }
402
440
  @available_models = models_response["data"]
403
441
  .map { |m| m["id"] }
404
442
  .select { |id| id.include?("gpt") || id.include?("davinci") || id.include?("curie") }
@@ -951,9 +989,11 @@ def main
951
989
  input_loop
952
990
 
953
991
  ensure
954
- save_history if defined?(@conversation_history)
955
- Rcurses::Cursor.show if defined?(Rcurses::Cursor)
956
- Rcurses.clear_screen if defined?(Rcurses)
992
+ if @chat_pane # Only cleanup UI if TUI was initialized
993
+ save_history if defined?(@conversation_history)
994
+ Rcurses::Cursor.show if defined?(Rcurses::Cursor)
995
+ Rcurses.clear_screen if defined?(Rcurses)
996
+ end
957
997
  end
958
998
 
959
999
  # Run the program
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openai-term
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.2
4
+ version: 3.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-08-15 00:00:00.000000000 Z
11
+ date: 2026-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-openai
@@ -40,9 +40,8 @@ dependencies:
40
40
  version: '6.0'
41
41
  description: 'A modern terminal interface to OpenAI with a full TUI using rcurses.
42
42
  Features include interactive chat mode, conversation history, model selection, and
43
- more. Version 3.0.2: Complete fix for ruby-openai 3.7.0 compatibility - using ''ruby/openai''
44
- for backward compatibility, fixed Rcurses::Pane and Rcurses::Cursor references,
45
- added missing io/console requirement, improved configuration help.'
43
+ more. Version 3.0.3: Add configurable request timeout and retry logic for transient
44
+ API failures (timeout, 429, 500/502/503).'
46
45
  email: g@isene.com
47
46
  executables:
48
47
  - openai