lex-llm 0.4.8 → 0.4.9

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: 1babd0169f0795262a38d54afd99e737b647e9dffd3a6066a480cdabd45ba072
4
- data.tar.gz: f6b1433ab12a083ace1c22814a4b0525c57c0ce52ebddf710fdd4358bb92203e
3
+ metadata.gz: e2b7839d1fcb47e176aa62970f3ec40d04b9e25095418285d3cf6a5d492ccb8d
4
+ data.tar.gz: f444cd5054325a007f05749d6d4a2ca0933bf1f5b7004b2585daaa97745eb337
5
5
  SHA512:
6
- metadata.gz: aebc2f2c85f5d06c4c5d9409d071f6043a6e3e53fbe23f474f0cfea9b452dc5ae2da44c7c44281562797d09621dc9287062c37f9d3710e76b02ea8d79d6712ec
7
- data.tar.gz: 698e2b35ef850a75d845860ac5342b45f2eb4d0a570f77e1a3e76ea0e93bbe9cd6b44d9f7b1d1beecb1936c6cd4df58989a3ea394a3394f2978cd057b3b60935
6
+ metadata.gz: 7412bc0234b379941ae045fa826f267d97b1577dba15ee7268957d62c999808e27392d9acf65d0bf464c31aa7365e3912642a4b0041eb92294f108c4203d8f38
7
+ data.tar.gz: a90e99a7c61f6fda2ffc4d2e4fd6b2fcba6f69bf75d5da526cacef550c345aadd157ea1ee6efeae59e3f69160a8e6ad92237a31997e9ef259c69dc29a6db01e6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.9 - 2026-05-13
4
+
5
+ - Route provider, tool, streaming, model, attachment, connection, credential, and fleet diagnostics through `Legion::Logging::Helper`.
6
+ - Replace temporary provider and stream probes with helper-backed debug logs that preserve model, tool, parameter, and header-key context without stdout or fatal-level noise.
7
+ - Add handled debug exception logging around provider discovery, credential probes, and fleet cleanup fallbacks.
8
+ - Fix provider request debug logging when callers pass tools as a hash.
9
+
3
10
  ## 0.4.8 - 2026-05-11
4
11
 
5
12
  - Set `remote_invocable?` to false — this extension does not need remote AMQP topology (exchanges, queues, DLX).
@@ -8,6 +8,8 @@ module Legion
8
8
  module Llm
9
9
  # A class representing a file attachment.
10
10
  class Attachment
11
+ include Legion::Logging::Helper
12
+
11
13
  attr_reader :source, :filename, :mime_type
12
14
 
13
15
  def initialize(source, filename: nil)
@@ -50,9 +52,7 @@ module Legion
50
52
  elsif io_like?
51
53
  load_content_from_io
52
54
  else
53
- Legion::Extensions::Llm.logger.warn(
54
- "Source is neither a URL, path, ActiveStorage, nor IO-like: #{@source.class}"
55
- )
55
+ log.warn { "Source is neither a URL, path, ActiveStorage, nor IO-like: #{@source.class}" }
56
56
  nil
57
57
  end
58
58
 
@@ -5,6 +5,8 @@ module Legion
5
5
  module Llm
6
6
  # Global configuration for Legion::Extensions::Llm
7
7
  class Configuration
8
+ include Legion::Logging::Helper
9
+
8
10
  class << self
9
11
  # Declare a single configuration option.
10
12
  def option(key, default = nil)
@@ -68,7 +70,7 @@ module Legion
68
70
  elsif Regexp.respond_to?(:timeout)
69
71
  @log_regexp_timeout = value
70
72
  else
71
- Legion::Extensions::Llm.logger.warn("log_regexp_timeout is not supported on Ruby #{RUBY_VERSION}")
73
+ log.warn { "log_regexp_timeout is not supported on Ruby #{RUBY_VERSION}" }
72
74
  @log_regexp_timeout = value
73
75
  end
74
76
  end
@@ -5,18 +5,34 @@ module Legion
5
5
  module Llm
6
6
  # Connection class for managing API connections to various providers.
7
7
  class Connection
8
+ include Legion::Logging::Helper
9
+
8
10
  attr_reader :provider, :connection, :config
9
11
 
10
- def self.basic(&)
11
- Faraday.new do |f|
12
- f.response :logger,
13
- Legion::Extensions::Llm.logger,
14
- bodies: false,
15
- errors: true,
16
- headers: false,
17
- log_level: :debug
18
- f.response :raise_error
19
- yield f if block_given?
12
+ class << self
13
+ include Legion::Logging::Helper
14
+
15
+ def basic(&)
16
+ logger = faraday_logger
17
+ Faraday.new do |f|
18
+ f.response :logger,
19
+ logger,
20
+ bodies: false,
21
+ errors: true,
22
+ headers: false,
23
+ log_level: :debug
24
+ f.response :raise_error
25
+ yield f if block_given?
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def faraday_logger
32
+ config = Legion::Extensions::Llm.config
33
+ return config.logger if config.respond_to?(:logger) && config.logger
34
+
35
+ log
20
36
  end
21
37
  end
22
38
 
@@ -59,9 +75,10 @@ module Legion
59
75
  end
60
76
 
61
77
  def setup_logging(faraday)
78
+ logger = faraday_logger
62
79
  faraday.response :logger,
63
- Legion::Extensions::Llm.logger,
64
- bodies: Legion::Extensions::Llm.logger.debug?,
80
+ logger,
81
+ bodies: debug_logger?(logger),
65
82
  errors: true,
66
83
  headers: false,
67
84
  log_level: :debug do |logger|
@@ -70,6 +87,19 @@ module Legion
70
87
  end
71
88
  end
72
89
 
90
+ def faraday_logger
91
+ return config.logger if config.respond_to?(:logger) && config.logger
92
+
93
+ log
94
+ end
95
+
96
+ def debug_logger?(logger)
97
+ return logger.debug? if logger.respond_to?(:debug?)
98
+ return logger.level.to_i <= Logger::DEBUG if logger.respond_to?(:level)
99
+
100
+ false
101
+ end
102
+
73
103
  def logging_regexp(pattern)
74
104
  return Regexp.new(pattern) if @config.log_regexp_timeout.nil? || !Regexp.respond_to?(:timeout)
75
105
 
@@ -11,6 +11,9 @@ module Legion
11
11
  # network probes). All methods are pure readers — the calling provider
12
12
  # decides what to do with the result.
13
13
  module CredentialSources
14
+ include Legion::Logging::Helper
15
+ extend Legion::Logging::Helper
16
+
14
17
  CLAUDE_SETTINGS = File.expand_path('~/.claude/settings.json')
15
18
  CLAUDE_PROJECT = File.join(Dir.pwd, '.claude', 'settings.json')
16
19
  CODEX_AUTH = File.expand_path('~/.codex/auth.json')
@@ -79,7 +82,9 @@ module Legion
79
82
  return nil unless defined?(::Legion::Settings)
80
83
 
81
84
  ::Legion::Settings.dig(*path)
82
- rescue StandardError
85
+ rescue StandardError => e
86
+ handle_exception(e, level: :debug, handled: true, operation: 'llm.credential_sources.setting',
87
+ path: path.map(&:to_s))
83
88
  nil
84
89
  end
85
90
 
@@ -104,7 +109,9 @@ module Legion
104
109
  end
105
110
  end
106
111
  true
107
- rescue StandardError
112
+ rescue StandardError => e
113
+ handle_exception(e, level: :debug, handled: true, operation: 'llm.credential_sources.socket_open',
114
+ host:, port:)
108
115
  false
109
116
  ensure
110
117
  sock&.close
@@ -120,7 +127,9 @@ module Legion
120
127
  end
121
128
  response = conn.get(path)
122
129
  response.status >= 200 && response.status < 300
123
- rescue StandardError
130
+ rescue StandardError => e
131
+ handle_exception(e, level: :debug, handled: true, operation: 'llm.credential_sources.http_ok',
132
+ path:)
124
133
  false
125
134
  ensure
126
135
  conn&.close if conn.respond_to?(:close)
@@ -168,7 +177,8 @@ module Legion
168
177
 
169
178
  normalized = host.delete_prefix('[').delete_suffix(']')
170
179
  %w[localhost 127.0.0.1 ::1].include?(normalized)
171
- rescue URI::InvalidURIError
180
+ rescue URI::InvalidURIError => e
181
+ handle_exception(e, level: :debug, handled: true, operation: 'llm.credential_sources.localhost')
172
182
  false
173
183
  end
174
184
 
@@ -199,7 +209,9 @@ module Legion
199
209
  else
200
210
  ::JSON.parse(raw, symbolize_names: true)
201
211
  end
202
- rescue StandardError
212
+ rescue StandardError => e
213
+ handle_exception(e, level: :debug, handled: true, operation: 'llm.credential_sources.read_json',
214
+ path:)
203
215
  {}
204
216
  end
205
217
 
@@ -220,7 +232,8 @@ module Legion
220
232
  return true if exp.nil?
221
233
 
222
234
  exp.to_i > Time.now.to_i
223
- rescue StandardError
235
+ rescue StandardError => e
236
+ handle_exception(e, level: :debug, handled: true, operation: 'llm.credential_sources.token_valid')
224
237
  true
225
238
  end
226
239
 
@@ -22,6 +22,9 @@ module Legion
22
22
  module Fleet
23
23
  # Shared implementation for provider-owned fleet responder runners.
24
24
  module ProviderResponder
25
+ include Legion::Logging::Helper
26
+ extend Legion::Logging::Helper
27
+
25
28
  class ConfigurationError < StandardError; end
26
29
 
27
30
  REQUIRED_FIELDS = %i[
@@ -71,6 +74,8 @@ module Legion
71
74
  ack(delivery || properties)
72
75
  response
73
76
  rescue StandardError => e
77
+ handle_exception(e, level: :warn, handled: false, operation: 'llm.fleet.provider_responder.call',
78
+ provider_family:)
74
79
  safe_publish_error(envelope, e) if defined?(envelope) && envelope
75
80
  reject(delivery || properties, requeue: requeue_error?(e))
76
81
  raise
@@ -165,7 +170,10 @@ module Legion
165
170
 
166
171
  def safe_publish_error(envelope, error)
167
172
  publish_error(envelope, error)
168
- rescue StandardError
173
+ rescue StandardError => e
174
+ handle_exception(e, level: :debug, handled: true,
175
+ operation: 'llm.fleet.provider_responder.safe_publish_error',
176
+ error_class: error.class.name)
169
177
  nil
170
178
  end
171
179
 
@@ -6,6 +6,8 @@ module Legion
6
6
  module Fleet
7
7
  # Publish-result helpers kept local to fleet messages so they work with older legion-transport releases.
8
8
  module PublishSafety
9
+ include Legion::Logging::Helper
10
+
9
11
  private
10
12
 
11
13
  def return_publish_result?(options)
@@ -6,6 +6,9 @@ module Legion
6
6
  module Fleet
7
7
  # Reads fleet settings from Legion::Settings when available, falling back to lex-llm defaults.
8
8
  module Settings
9
+ include Legion::Logging::Helper
10
+ extend Legion::Logging::Helper
11
+
9
12
  module_function
10
13
 
11
14
  def value(*path, default:)
@@ -29,7 +32,8 @@ module Legion
29
32
  llm = safe_fetch(::Legion::Settings, :llm)
30
33
  configured << llm if llm.respond_to?(:key?)
31
34
  configured
32
- rescue StandardError
35
+ rescue StandardError => e
36
+ handle_exception(e, level: :debug, handled: true, operation: 'llm.fleet.settings.configured')
33
37
  []
34
38
  end
35
39
 
@@ -49,7 +53,9 @@ module Legion
49
53
 
50
54
  def safe_fetch(source, key)
51
55
  source[key] || source[key.to_s]
52
- rescue StandardError
56
+ rescue StandardError => e
57
+ handle_exception(e, level: :debug, handled: true, operation: 'llm.fleet.settings.safe_fetch',
58
+ key: key.to_s)
53
59
  nil
54
60
  end
55
61
 
@@ -12,6 +12,9 @@ module Legion
12
12
  module Fleet
13
13
  # Verifies responder-side fleet JWTs and prevents replay on provider nodes.
14
14
  module TokenValidator
15
+ include Legion::Logging::Helper
16
+ extend Legion::Logging::Helper
17
+
15
18
  @seen_jtis = Concurrent::Map.new
16
19
  @replay_mutex = Mutex.new
17
20
 
@@ -35,6 +38,7 @@ module Legion
35
38
  rescue TokenError
36
39
  raise
37
40
  rescue StandardError => e
41
+ handle_exception(e, level: :warn, handled: false, operation: 'llm.fleet.token_validator.validate')
38
42
  raise TokenError, "fleet token verification failed: #{e.message}"
39
43
  end
40
44
 
@@ -167,6 +171,7 @@ module Legion
167
171
  rescue TokenError
168
172
  raise
169
173
  rescue StandardError => e
174
+ handle_exception(e, level: :warn, handled: false, operation: 'llm.fleet.token_validator.signing_key')
170
175
  raise TokenError, "no signing key available: #{e.message}"
171
176
  end
172
177
 
@@ -11,6 +11,9 @@ module Legion
11
11
  module Fleet
12
12
  # Applies responder-side policy and dispatches a fleet request to a local lex-llm provider.
13
13
  module WorkerExecution
14
+ include Legion::Logging::Helper
15
+ extend Legion::Logging::Helper
16
+
14
17
  class PolicyError < StandardError; end
15
18
 
16
19
  @idempotency_keys = Concurrent::Map.new
@@ -29,10 +32,12 @@ module Legion
29
32
  TokenValidator.mark_replay!(claims[:jti]) if claims.is_a?(Hash)
30
33
  response
31
34
  rescue TokenError => e
35
+ handle_exception(e, level: :warn, handled: false, operation: 'llm.fleet.worker_execution.identity')
32
36
  release_idempotency!(idempotency_key) if idempotency_key
33
37
  release_replay!(claims)
34
38
  raise PolicyError, e.message
35
- rescue StandardError
39
+ rescue StandardError => e
40
+ handle_exception(e, level: :warn, handled: false, operation: 'llm.fleet.worker_execution.call')
36
41
  release_idempotency!(idempotency_key) if idempotency_key
37
42
  release_replay!(claims)
38
43
  raise
@@ -169,7 +169,7 @@ module Legion
169
169
  end
170
170
 
171
171
  def fetch_models_dev_models(existing_models) # rubocop:disable Metrics/PerceivedComplexity
172
- Legion::Extensions::Llm.logger.info 'Fetching models from models.dev API...'
172
+ log.info 'Fetching models from models.dev API...'
173
173
 
174
174
  connection = Connection.basic do |f|
175
175
  f.request :json
@@ -202,11 +202,11 @@ module Legion
202
202
  end
203
203
 
204
204
  def log_provider_fetch(provider_fetch)
205
- Legion::Extensions::Llm.logger.info(
205
+ log.info(
206
206
  "Fetching models from providers: #{provider_fetch[:configured_names].join(', ')}"
207
207
  )
208
208
  provider_fetch[:failed].each do |failure|
209
- Legion::Extensions::Llm.logger.warn(
209
+ log.warn(
210
210
  "Failed to fetch #{failure[:name]} models (#{failure[:error].class}: #{failure[:error].message}). " \
211
211
  'Keeping existing.'
212
212
  )
@@ -216,7 +216,7 @@ module Legion
216
216
  def log_models_dev_fetch(models_dev_fetch)
217
217
  return if models_dev_fetch[:fetched]
218
218
 
219
- Legion::Extensions::Llm.logger.warn('Using cached models.dev data due to fetch failure.')
219
+ log.warn('Using cached models.dev data due to fetch failure.')
220
220
  end
221
221
 
222
222
  def merge_with_existing(existing_models, provider_fetch, models_dev_fetch)
@@ -75,6 +75,19 @@ module Legion
75
75
  def complete(messages, tools:, temperature:, model:, params: {}, headers: {}, schema: nil, thinking: nil,
76
76
  tool_prefs: nil, &)
77
77
  normalized_temperature = maybe_normalize_temperature(temperature, model)
78
+ log_provider_request(
79
+ messages: messages,
80
+ tools: tools,
81
+ temperature: temperature,
82
+ normalized_temperature: normalized_temperature,
83
+ model: model,
84
+ params: params,
85
+ headers: headers,
86
+ schema: schema,
87
+ thinking: thinking,
88
+ tool_prefs: tool_prefs,
89
+ streaming: block_given?
90
+ )
78
91
 
79
92
  payload = Utils.deep_merge(
80
93
  render_payload(
@@ -330,7 +343,8 @@ module Legion
330
343
  uri = URI.parse(url)
331
344
  Socket.tcp(uri.host, uri.port, connect_timeout: 1).close
332
345
  true
333
- rescue StandardError
346
+ rescue StandardError => e
347
+ handle_exception(e, level: :debug, handled: true, operation: 'llm.provider.url_reachable', url:)
334
348
  false
335
349
  end
336
350
 
@@ -352,7 +366,8 @@ module Legion
352
366
  return nil unless defined?(Legion::Cache)
353
367
 
354
368
  cache_local_instance? ? local_cache_get(key) : cache_get(key)
355
- rescue StandardError
369
+ rescue StandardError => e
370
+ handle_exception(e, level: :debug, handled: true, operation: 'llm.provider.model_cache_get', key:)
356
371
  nil
357
372
  end
358
373
 
@@ -368,7 +383,8 @@ module Legion
368
383
  return yield unless defined?(Legion::Cache)
369
384
 
370
385
  cache_local_instance? ? local_cache_fetch(key, ttl: ttl, &) : cache_fetch(key, ttl: ttl, &)
371
- rescue StandardError
386
+ rescue StandardError => e
387
+ handle_exception(e, level: :debug, handled: true, operation: 'llm.provider.model_cache_fetch', key:)
372
388
  yield
373
389
  end
374
390
 
@@ -593,6 +609,53 @@ module Legion
593
609
  temperature
594
610
  end
595
611
 
612
+ def log_provider_request(context)
613
+ log.debug do
614
+ "Preparing provider completion: provider=#{slug} model=#{debug_model_id(context[:model])} " \
615
+ "streaming=#{context[:streaming]} messages=#{Array(context[:messages]).size} " \
616
+ "tools=#{debug_tool_names(context[:tools]).inspect} " \
617
+ "temperature=#{context[:temperature].inspect} " \
618
+ "normalized_temperature=#{context[:normalized_temperature].inspect} " \
619
+ "param_keys=#{debug_hash_keys(context[:params]).inspect} " \
620
+ "header_keys=#{debug_hash_keys(context[:headers]).inspect} " \
621
+ "schema=#{debug_value_summary(context[:schema])} " \
622
+ "thinking=#{debug_value_summary(context[:thinking])} " \
623
+ "tool_prefs=#{debug_value_summary(context[:tool_prefs])}"
624
+ end
625
+ end
626
+
627
+ def debug_model_id(model)
628
+ return model.id if model.respond_to?(:id)
629
+
630
+ model
631
+ end
632
+
633
+ def debug_tool_names(tools)
634
+ tool_definitions = tools.is_a?(Hash) ? tools.values : Array(tools)
635
+
636
+ tool_definitions.filter_map do |tool|
637
+ if tool.respond_to?(:name)
638
+ tool.name
639
+ elsif tool.is_a?(Hash)
640
+ tool[:name] || tool['name']
641
+ else
642
+ tool.class.name
643
+ end
644
+ end
645
+ end
646
+
647
+ def debug_hash_keys(value)
648
+ value.respond_to?(:keys) ? value.keys.map(&:to_s).sort : []
649
+ end
650
+
651
+ def debug_value_summary(value)
652
+ return 'nil' if value.nil?
653
+ return "#{value.class}(keys=#{debug_hash_keys(value).inspect})" if value.respond_to?(:keys)
654
+ return "#{value.class}(size=#{value.size})" if value.respond_to?(:size)
655
+
656
+ value.class.name
657
+ end
658
+
596
659
  def endpoint_methods
597
660
  {
598
661
  completion: :completion_url,
@@ -25,7 +25,7 @@ module Legion
25
25
  end
26
26
 
27
27
  def add(chunk)
28
- Legion::Extensions::Llm.logger.debug { chunk.inspect } if Legion::Extensions::Llm.config.log_stream_debug
28
+ log.debug { chunk.inspect } if Legion::Extensions::Llm.config.log_stream_debug
29
29
  @model_id ||= chunk.model_id
30
30
 
31
31
  @last_content_delta = +''
@@ -33,7 +33,7 @@ module Legion
33
33
  handle_chunk_content(chunk)
34
34
  append_thinking_from_chunk(chunk)
35
35
  count_tokens chunk
36
- Legion::Extensions::Llm.logger.debug { inspect } if Legion::Extensions::Llm.config.log_stream_debug
36
+ log.debug { inspect } if Legion::Extensions::Llm.config.log_stream_debug
37
37
  end
38
38
 
39
39
  def filtered_chunk(chunk) # rubocop:disable Metrics/PerceivedComplexity
@@ -101,9 +101,7 @@ module Legion
101
101
  end
102
102
 
103
103
  def accumulate_tool_calls(new_tool_calls)
104
- if Legion::Extensions::Llm.config.log_stream_debug
105
- Legion::Extensions::Llm.logger.debug { "Accumulating tool calls: #{new_tool_calls}" }
106
- end
104
+ log.debug { "Accumulating tool calls: #{new_tool_calls}" } if Legion::Extensions::Llm.config.log_stream_debug
107
105
  new_tool_calls.each_value do |tool_call|
108
106
  if tool_call.id
109
107
  start_tool_call(tool_call)
@@ -5,6 +5,9 @@ module Legion
5
5
  module Llm
6
6
  # Handles streaming responses from AI providers.
7
7
  module Streaming
8
+ include Legion::Logging::Helper
9
+ extend Legion::Logging::Helper
10
+
8
11
  module_function
9
12
 
10
13
  def stream_response(connection, payload, additional_headers = {}, &block)
@@ -13,6 +16,9 @@ module Legion
13
16
  response = connection.post stream_url, payload do |req|
14
17
  req.headers = additional_headers.merge(req.headers) unless additional_headers.empty?
15
18
  on_chunk = build_stream_callback(accumulator, block)
19
+ if Legion::Extensions::Llm.config.log_stream_debug
20
+ log.debug { "Stream callback prepared: #{on_chunk.inspect}" }
21
+ end
16
22
  if faraday_1?
17
23
  req.options[:on_data] = handle_stream(&on_chunk)
18
24
  else
@@ -21,7 +27,7 @@ module Legion
21
27
  end
22
28
 
23
29
  message = accumulator.to_message(response)
24
- Legion::Extensions::Llm.logger.debug { "Stream completed: #{message.content}" }
30
+ log.debug { "Stream completed: #{message.content}" }
25
31
  message
26
32
  end
27
33
 
@@ -57,9 +63,7 @@ module Legion
57
63
  end
58
64
 
59
65
  def process_stream_chunk(chunk, parser, env, &)
60
- if Legion::Extensions::Llm.config.log_stream_debug
61
- Legion::Extensions::Llm.logger.debug { "Received chunk: #{chunk}" }
62
- end
66
+ log.debug { "Received chunk: #{chunk}" } if Legion::Extensions::Llm.config.log_stream_debug
63
67
 
64
68
  if error_chunk?(chunk)
65
69
  handle_error_chunk(chunk, env)
@@ -19,6 +19,8 @@ module Legion
19
19
 
20
20
  # Base class for creating tools that AI models can use
21
21
  class Tool
22
+ include Legion::Logging::Helper
23
+
22
24
  # Stops conversation continuation after tool execution
23
25
  class Halt
24
26
  attr_reader :content
@@ -105,9 +107,9 @@ module Legion
105
107
  validation_error = validate_keyword_arguments(normalized_args)
106
108
  return { error: "Invalid tool arguments: #{validation_error}" } if validation_error
107
109
 
108
- Legion::Extensions::Llm.logger.debug { "Tool #{name} called with: #{normalized_args.inspect}" }
110
+ log.debug { "Tool #{name} called with: #{normalized_args.inspect}" }
109
111
  result = execute(**normalized_args)
110
- Legion::Extensions::Llm.logger.debug { "Tool #{name} returned: #{result.inspect}" }
112
+ log.debug { "Tool #{name} returned: #{result.inspect}" }
111
113
  result
112
114
  end
113
115
 
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Llm
6
- VERSION = '0.4.8'
6
+ VERSION = '0.4.9'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-llm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.8
4
+ version: 0.4.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - LegionIO