dexter_llm 0.1.2

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 (73) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +1246 -0
  4. data/lib/dexter_llm/adapters/anthropic.rb +513 -0
  5. data/lib/dexter_llm/adapters/base.rb +61 -0
  6. data/lib/dexter_llm/adapters/google.rb +392 -0
  7. data/lib/dexter_llm/adapters/openai.rb +415 -0
  8. data/lib/dexter_llm/agent/agent.rb +277 -0
  9. data/lib/dexter_llm/agent/agent_busy_error.rb +9 -0
  10. data/lib/dexter_llm/agent/console.rb +525 -0
  11. data/lib/dexter_llm/agent/error.rb +5 -0
  12. data/lib/dexter_llm/agent/event.rb +27 -0
  13. data/lib/dexter_llm/agent/loop.rb +256 -0
  14. data/lib/dexter_llm/agent/max_iterations_error.rb +9 -0
  15. data/lib/dexter_llm/agent/session.rb +271 -0
  16. data/lib/dexter_llm/agent/state.rb +75 -0
  17. data/lib/dexter_llm/api.rb +9 -0
  18. data/lib/dexter_llm/api_error.rb +55 -0
  19. data/lib/dexter_llm/assistant_message.rb +47 -0
  20. data/lib/dexter_llm/authentication_error.rb +5 -0
  21. data/lib/dexter_llm/built_in_tool.rb +68 -0
  22. data/lib/dexter_llm/built_in_tools/web_fetch.rb +92 -0
  23. data/lib/dexter_llm/built_in_tools/web_search.rb +84 -0
  24. data/lib/dexter_llm/cancellation_signal.rb +31 -0
  25. data/lib/dexter_llm/cancelled_error.rb +12 -0
  26. data/lib/dexter_llm/client.rb +410 -0
  27. data/lib/dexter_llm/configuration.rb +119 -0
  28. data/lib/dexter_llm/content.rb +338 -0
  29. data/lib/dexter_llm/context_overflow_error.rb +5 -0
  30. data/lib/dexter_llm/documents/ingestor.rb +107 -0
  31. data/lib/dexter_llm/documents/store.rb +46 -0
  32. data/lib/dexter_llm/documents/stored_document.rb +27 -0
  33. data/lib/dexter_llm/documents/stores/file_system.rb +131 -0
  34. data/lib/dexter_llm/error.rb +5 -0
  35. data/lib/dexter_llm/instrumentation.rb +11 -0
  36. data/lib/dexter_llm/invalid_request_error.rb +5 -0
  37. data/lib/dexter_llm/message.rb +30 -0
  38. data/lib/dexter_llm/message_transformer.rb +90 -0
  39. data/lib/dexter_llm/model.rb +52 -0
  40. data/lib/dexter_llm/models/catalog.yml +324 -0
  41. data/lib/dexter_llm/models.rb +99 -0
  42. data/lib/dexter_llm/pricing.rb +46 -0
  43. data/lib/dexter_llm/prompt/materializer.rb +121 -0
  44. data/lib/dexter_llm/provider.rb +9 -0
  45. data/lib/dexter_llm/rate_limit_error.rb +5 -0
  46. data/lib/dexter_llm/retry_policy.rb +25 -0
  47. data/lib/dexter_llm/schema/builder.rb +258 -0
  48. data/lib/dexter_llm/schema/coercer.rb +159 -0
  49. data/lib/dexter_llm/schema/validator.rb +212 -0
  50. data/lib/dexter_llm/schema.rb +66 -0
  51. data/lib/dexter_llm/session/compaction.rb +216 -0
  52. data/lib/dexter_llm/session/compaction_settings.rb +17 -0
  53. data/lib/dexter_llm/session/entry.rb +589 -0
  54. data/lib/dexter_llm/session/error.rb +10 -0
  55. data/lib/dexter_llm/session/loaded_session.rb +18 -0
  56. data/lib/dexter_llm/session/manager.rb +181 -0
  57. data/lib/dexter_llm/session/store.rb +17 -0
  58. data/lib/dexter_llm/session/stores/jsonl_file.rb +99 -0
  59. data/lib/dexter_llm/stop_reason.rb +11 -0
  60. data/lib/dexter_llm/stream_event.rb +225 -0
  61. data/lib/dexter_llm/streaming/events.rb +7 -0
  62. data/lib/dexter_llm/streaming/sse_parser.rb +69 -0
  63. data/lib/dexter_llm/summary_message.rb +27 -0
  64. data/lib/dexter_llm/thinking_level.rb +31 -0
  65. data/lib/dexter_llm/token_estimator.rb +58 -0
  66. data/lib/dexter_llm/tool.rb +208 -0
  67. data/lib/dexter_llm/tool_result_message.rb +32 -0
  68. data/lib/dexter_llm/unsupported_content_error.rb +5 -0
  69. data/lib/dexter_llm/usage.rb +107 -0
  70. data/lib/dexter_llm/user_message.rb +23 -0
  71. data/lib/dexter_llm/version.rb +5 -0
  72. data/lib/dexter_llm.rb +103 -0
  73. metadata +158 -0
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DexterLlm
4
+ module TokenEstimator
5
+ module_function
6
+
7
+ # Heuristic fallback (provider-independent):
8
+ # - English-ish text averages ~4 bytes/token in many BPE tokenizers.
9
+ def estimate_text_tokens(text)
10
+ str = text.to_s
11
+ return 0 if str.empty?
12
+
13
+ (str.bytesize / 4.0).ceil
14
+ end
15
+
16
+ def estimate_tokens(messages)
17
+ Array(messages).sum { |m| estimate_message_tokens(m) }
18
+ end
19
+
20
+ def estimate_message_tokens(message)
21
+ case message
22
+ when String
23
+ estimate_text_tokens(message)
24
+ when Hash
25
+ estimate_content_tokens(message["content"] || message[:content])
26
+ else
27
+ if message.respond_to?(:content)
28
+ estimate_content_tokens(message.content)
29
+ else
30
+ estimate_text_tokens(message.to_s)
31
+ end
32
+ end
33
+ end
34
+
35
+ def estimate_content_tokens(content)
36
+ case content
37
+ when nil
38
+ 0
39
+ when String
40
+ estimate_text_tokens(content)
41
+ when Array
42
+ content.sum do |part|
43
+ if part.is_a?(String)
44
+ estimate_text_tokens(part)
45
+ elsif part.respond_to?(:text)
46
+ estimate_text_tokens(part.text)
47
+ elsif part.respond_to?(:thinking)
48
+ estimate_text_tokens(part.thinking)
49
+ else
50
+ estimate_text_tokens(part.to_s)
51
+ end
52
+ end
53
+ else
54
+ estimate_text_tokens(content.to_s)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,208 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DexterLlm
4
+ # Error raised when tool execution fails.
5
+ # @see Tool#execute
6
+ class ToolExecutionError < DexterLlm::Error; end
7
+
8
+ # Base class for defining tools that can be called by the LLM.
9
+ #
10
+ # Tools allow the LLM to perform actions and retrieve information.
11
+ # Define a tool by subclassing and providing a name, description,
12
+ # parameter schema, and execute method.
13
+ #
14
+ # @example Basic tool
15
+ # class WeatherTool < DexterLlm::Tool
16
+ # name "get_weather"
17
+ # description "Get current weather for a location"
18
+ #
19
+ # params do
20
+ # string :location, required: true, description: "City name"
21
+ # string :units, enum: %w[metric imperial]
22
+ # end
23
+ #
24
+ # def execute(location:, units: "metric")
25
+ # # Implementation here
26
+ # "Temperature: 72F"
27
+ # end
28
+ # end
29
+ #
30
+ # @example Using with an agent
31
+ # weather = WeatherTool.new
32
+ # agent = Agent::Agent.new(model: model, tools: [weather])
33
+ # agent.prompt("What's the weather in Tokyo?")
34
+ #
35
+ # @see Schema::Builder for parameter schema DSL
36
+ #
37
+ class Tool
38
+ class << self
39
+ # Set or get the tool name.
40
+ #
41
+ # If no name is set, it's derived from the class name by converting
42
+ # CamelCase to snake_case and removing "Tool" suffix.
43
+ #
44
+ # @param value [String, nil] The tool name to set
45
+ # @return [String] The tool name
46
+ #
47
+ # @example
48
+ # class MyCustomTool < DexterLlm::Tool
49
+ # name "custom_tool" # Set explicitly
50
+ # end
51
+ #
52
+ # class AnotherTool < DexterLlm::Tool
53
+ # # Name is automatically "another"
54
+ # end
55
+ #
56
+ def name(value = nil)
57
+ if value
58
+ @tool_name = value.to_s
59
+ else
60
+ @tool_name || self.to_s.split("::").last.gsub(/Tool$/, "").gsub(/([a-z])([A-Z])/, '\1_\2').downcase
61
+ end
62
+ end
63
+
64
+ # Set or get the tool description.
65
+ #
66
+ # The description is sent to the LLM to help it understand
67
+ # when and how to use the tool.
68
+ #
69
+ # @param value [String, nil] The description to set
70
+ # @return [String] The tool description
71
+ #
72
+ # @example
73
+ # class WeatherTool < DexterLlm::Tool
74
+ # description "Get current weather conditions for a location"
75
+ # end
76
+ #
77
+ def description(value = nil)
78
+ if value
79
+ @description = value
80
+ else
81
+ @description || ""
82
+ end
83
+ end
84
+
85
+ # Define the tool's parameter schema.
86
+ #
87
+ # The block is evaluated using the {Schema::Builder} DSL
88
+ # and generates a JSON Schema for parameter validation.
89
+ #
90
+ # @yield Block defining parameters using Schema::Builder DSL
91
+ #
92
+ # @example
93
+ # params do
94
+ # string :query, required: true, description: "Search query"
95
+ # integer :limit, minimum: 1, maximum: 100
96
+ # boolean :include_metadata
97
+ # end
98
+ #
99
+ # @see Schema::Builder
100
+ #
101
+ def params(&block)
102
+ @params_block = block if block_given?
103
+ @params_block
104
+ end
105
+
106
+ # @private
107
+ def inherited(subclass)
108
+ super
109
+ # Don't copy params block - each subclass should define its own
110
+ end
111
+ end
112
+
113
+ # @return [String] The tool name
114
+ def name
115
+ self.class.name
116
+ end
117
+
118
+ # @return [String] The tool description
119
+ def description
120
+ self.class.description
121
+ end
122
+
123
+ # Generate the JSON Schema for the tool's parameters.
124
+ #
125
+ # @return [Hash] JSON Schema object
126
+ def parameters_schema
127
+ block = self.class.params
128
+ return empty_schema unless block
129
+
130
+ # Evaluate block in tool's context so @instance_vars work,
131
+ # with builder methods available via singleton methods
132
+ builder = Schema::Builder.new
133
+ add_builder_methods(builder)
134
+
135
+ begin
136
+ instance_exec(&block)
137
+ ensure
138
+ remove_builder_methods
139
+ end
140
+
141
+ builder.to_json_schema
142
+ end
143
+
144
+ # Call the tool with the given arguments.
145
+ #
146
+ # This method validates and coerces the arguments according to
147
+ # the parameter schema, then calls {#execute}.
148
+ #
149
+ # @param arguments [Hash] The arguments to pass to the tool
150
+ # @return [Object] The result from execute
151
+ # @raise [ToolExecutionError] If validation fails or execution errors
152
+ #
153
+ # @example
154
+ # tool = WeatherTool.new
155
+ # result = tool.call({ location: "Paris", units: "metric" })
156
+ #
157
+ def call(arguments)
158
+ schema = parameters_schema
159
+ coerced = Schema::Coercer.new(schema).coerce(arguments)
160
+ Schema::Validator.new(schema).validate!(coerced)
161
+
162
+ execute(**coerced)
163
+ rescue Schema::ValidationError => e
164
+ raise ToolExecutionError, "Invalid arguments for #{name}: #{e.message}"
165
+ rescue StandardError => e
166
+ raise ToolExecutionError, "Error executing #{name}: #{e.message}"
167
+ end
168
+
169
+ # Execute the tool with validated arguments.
170
+ #
171
+ # Subclasses must override this method to implement the tool's logic.
172
+ # The return value is sent back to the LLM as the tool result.
173
+ #
174
+ # @abstract
175
+ # @param args [Hash] Validated and coerced arguments
176
+ # @return [String, Object] The tool result (converted to string if needed)
177
+ # @raise [ToolExecutionError] If execution fails
178
+ #
179
+ def execute(**_args)
180
+ raise NotImplementedError, "#{self.class}#execute must be implemented"
181
+ end
182
+
183
+ private
184
+
185
+ BUILDER_METHODS = %i[string number integer boolean null object array any_of].freeze
186
+
187
+ def add_builder_methods(builder)
188
+ @__schema_builder__ = builder
189
+
190
+ BUILDER_METHODS.each do |method|
191
+ define_singleton_method(method) do |*args, **kwargs, &blk|
192
+ @__schema_builder__.send(method, *args, **kwargs, &blk)
193
+ end
194
+ end
195
+ end
196
+
197
+ def remove_builder_methods
198
+ BUILDER_METHODS.each do |method|
199
+ singleton_class.remove_method(method) if respond_to?(method)
200
+ end
201
+ @__schema_builder__ = nil
202
+ end
203
+
204
+ def empty_schema
205
+ { "type" => "object", "properties" => {} }
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DexterLlm
4
+ class ToolResultMessage
5
+ include Message::Serializable
6
+
7
+ def initialize(tool_call_id:, tool_name:, content:, is_error: false, details: nil, timestamp: Time.now)
8
+ @tool_call_id = tool_call_id
9
+ @tool_name = tool_name
10
+ @content = normalize_content(content)
11
+ @is_error = is_error
12
+ @details = details
13
+ @timestamp = timestamp
14
+ end
15
+
16
+ attr_reader :tool_call_id, :tool_name, :content, :is_error, :details, :timestamp
17
+ def role = :tool_result
18
+
19
+ def to_h
20
+ h = {
21
+ "role" => "tool_result",
22
+ "tool_call_id" => tool_call_id,
23
+ "tool_name" => tool_name,
24
+ "is_error" => is_error,
25
+ "content" => content_to_h(content),
26
+ "timestamp" => timestamp.utc.iso8601(3)
27
+ }
28
+ h["details"] = details if details
29
+ h
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DexterLlm
4
+ class UnsupportedContentError < Error; end
5
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DexterLlm
4
+ class Usage
5
+ def initialize(
6
+ input_tokens: 0,
7
+ output_tokens: 0,
8
+ cached_input_tokens: 0,
9
+ cache_read_input_tokens: 0,
10
+ cache_write_input_tokens: 0,
11
+ input_audio_tokens: 0,
12
+ input_image_tokens: 0,
13
+ input_video_tokens: 0,
14
+ input_document_tokens: 0,
15
+ output_audio_tokens: 0,
16
+ reasoning_tokens: 0,
17
+ thoughts_tokens: 0,
18
+ tool_use_prompt_tokens: 0,
19
+ meta: {},
20
+ raw: nil
21
+ )
22
+ @input_tokens = input_tokens.to_i
23
+ @output_tokens = output_tokens.to_i
24
+
25
+ @cached_input_tokens = cached_input_tokens.to_i
26
+ @cache_read_input_tokens = cache_read_input_tokens.to_i
27
+ @cache_write_input_tokens = cache_write_input_tokens.to_i
28
+
29
+ @input_audio_tokens = input_audio_tokens.to_i
30
+ @input_image_tokens = input_image_tokens.to_i
31
+ @input_video_tokens = input_video_tokens.to_i
32
+ @input_document_tokens = input_document_tokens.to_i
33
+
34
+ @output_audio_tokens = output_audio_tokens.to_i
35
+
36
+ @reasoning_tokens = reasoning_tokens.to_i
37
+ @thoughts_tokens = thoughts_tokens.to_i
38
+ @tool_use_prompt_tokens = tool_use_prompt_tokens.to_i
39
+
40
+ @meta = meta
41
+ @raw = raw
42
+ end
43
+
44
+ attr_accessor :input_tokens, :output_tokens,
45
+ :cached_input_tokens, :cache_read_input_tokens, :cache_write_input_tokens,
46
+ :input_audio_tokens, :input_image_tokens, :input_video_tokens, :input_document_tokens,
47
+ :output_audio_tokens, :reasoning_tokens, :thoughts_tokens, :tool_use_prompt_tokens
48
+
49
+ attr_reader :meta, :raw
50
+
51
+ def prompt_tokens
52
+ input_tokens
53
+ end
54
+
55
+ def total_tokens
56
+ input_tokens + output_tokens
57
+ end
58
+
59
+ def billable_meters
60
+ cached_text = cached_input_tokens + cache_read_input_tokens
61
+ uncached_input = [ input_tokens - cached_text - cache_write_input_tokens, 0 ].max
62
+
63
+ input_text = [
64
+ uncached_input - input_audio_tokens - input_image_tokens - input_video_tokens - input_document_tokens,
65
+ 0
66
+ ].max
67
+
68
+ output_text = [ output_tokens - output_audio_tokens, 0 ].max
69
+
70
+ {
71
+ input_text_tokens: input_text,
72
+ input_text_tokens_cached: cached_text,
73
+ input_text_tokens_cache_write: cache_write_input_tokens,
74
+ input_audio_tokens: input_audio_tokens,
75
+ input_image_tokens: input_image_tokens,
76
+ input_video_tokens: input_video_tokens,
77
+ input_document_tokens: input_document_tokens,
78
+ output_text_tokens: output_text,
79
+ output_audio_tokens: output_audio_tokens
80
+ }
81
+ end
82
+
83
+ def calculate_cost(model)
84
+ billable_meters.sum do |meter, units|
85
+ model.pricing.cost_for(meter, units, usage: self)
86
+ end
87
+ end
88
+
89
+ def to_h
90
+ {
91
+ input_tokens: input_tokens,
92
+ output_tokens: output_tokens,
93
+ cached_input_tokens: cached_input_tokens,
94
+ cache_read_input_tokens: cache_read_input_tokens,
95
+ cache_write_input_tokens: cache_write_input_tokens,
96
+ input_audio_tokens: input_audio_tokens,
97
+ input_image_tokens: input_image_tokens,
98
+ input_video_tokens: input_video_tokens,
99
+ input_document_tokens: input_document_tokens,
100
+ output_audio_tokens: output_audio_tokens,
101
+ reasoning_tokens: reasoning_tokens,
102
+ thoughts_tokens: thoughts_tokens,
103
+ tool_use_prompt_tokens: tool_use_prompt_tokens
104
+ }
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DexterLlm
4
+ class UserMessage
5
+ include Message::Serializable
6
+
7
+ def initialize(content, timestamp: Time.now)
8
+ @content = normalize_content(content)
9
+ @timestamp = timestamp
10
+ end
11
+
12
+ attr_reader :content, :timestamp
13
+ def role = :user
14
+
15
+ def to_h
16
+ {
17
+ "role" => "user",
18
+ "content" => content_to_h(content),
19
+ "timestamp" => timestamp.utc.iso8601(3)
20
+ }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DexterLlm
4
+ VERSION = "0.1.2"
5
+ end
data/lib/dexter_llm.rb ADDED
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "json"
5
+ require "uri"
6
+
7
+ module DexterLlm
8
+ class << self
9
+ def configuration
10
+ @configuration ||= Configuration.new
11
+ end
12
+
13
+ def configure
14
+ yield(configuration)
15
+ end
16
+ end
17
+
18
+ module Agent
19
+ end
20
+
21
+ module Session
22
+ end
23
+ end
24
+
25
+ require_relative "dexter_llm/version"
26
+
27
+ # Core LLM types
28
+ %w[
29
+ dexter_llm/error
30
+ dexter_llm/api_error
31
+ dexter_llm/authentication_error
32
+ dexter_llm/invalid_request_error
33
+ dexter_llm/context_overflow_error
34
+ dexter_llm/rate_limit_error
35
+ dexter_llm/cancelled_error
36
+ dexter_llm/unsupported_content_error
37
+ dexter_llm/cancellation_signal
38
+ dexter_llm/instrumentation
39
+ dexter_llm/stop_reason
40
+ dexter_llm/thinking_level
41
+ dexter_llm/api
42
+ dexter_llm/provider
43
+ dexter_llm/message
44
+ dexter_llm/content
45
+ dexter_llm/user_message
46
+ dexter_llm/assistant_message
47
+ dexter_llm/tool_result_message
48
+ dexter_llm/summary_message
49
+ dexter_llm/token_estimator
50
+ dexter_llm/usage
51
+ dexter_llm/pricing
52
+ dexter_llm/model
53
+ dexter_llm/models
54
+ dexter_llm/configuration
55
+ dexter_llm/retry_policy
56
+ dexter_llm/stream_event
57
+ dexter_llm/streaming/sse_parser
58
+ dexter_llm/streaming/events
59
+ dexter_llm/schema
60
+ dexter_llm/schema/builder
61
+ dexter_llm/schema/coercer
62
+ dexter_llm/schema/validator
63
+ dexter_llm/tool
64
+ dexter_llm/built_in_tool
65
+ dexter_llm/built_in_tools/web_search
66
+ dexter_llm/built_in_tools/web_fetch
67
+ dexter_llm/documents/store
68
+ dexter_llm/documents/stored_document
69
+ dexter_llm/documents/ingestor
70
+ dexter_llm/documents/stores/file_system
71
+ dexter_llm/prompt/materializer
72
+ dexter_llm/message_transformer
73
+ dexter_llm/client
74
+ dexter_llm/adapters/base
75
+ dexter_llm/adapters/anthropic
76
+ dexter_llm/adapters/openai
77
+ dexter_llm/adapters/google
78
+ ].each { |path| require_relative path }
79
+
80
+ # Agent
81
+ %w[
82
+ dexter_llm/agent/error
83
+ dexter_llm/agent/agent_busy_error
84
+ dexter_llm/agent/max_iterations_error
85
+ dexter_llm/agent/event
86
+ dexter_llm/agent/state
87
+ dexter_llm/agent/loop
88
+ dexter_llm/agent/agent
89
+ dexter_llm/agent/console
90
+ dexter_llm/agent/session
91
+ ].each { |path| require_relative path }
92
+
93
+ # Session persistence
94
+ %w[
95
+ dexter_llm/session/error
96
+ dexter_llm/session/store
97
+ dexter_llm/session/entry
98
+ dexter_llm/session/loaded_session
99
+ dexter_llm/session/compaction_settings
100
+ dexter_llm/session/compaction
101
+ dexter_llm/session/manager
102
+ dexter_llm/session/stores/jsonl_file
103
+ ].each { |path| require_relative path }
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dexter_llm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Dexter Team
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: async
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: marcel
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: pastel
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ description: Ruby-native LLM agent framework with provider adapters (Anthropic, OpenAI,
55
+ Google), tool calling, streaming, and session persistence.
56
+ email:
57
+ - team@getdexter.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - LICENSE
63
+ - README.md
64
+ - lib/dexter_llm.rb
65
+ - lib/dexter_llm/adapters/anthropic.rb
66
+ - lib/dexter_llm/adapters/base.rb
67
+ - lib/dexter_llm/adapters/google.rb
68
+ - lib/dexter_llm/adapters/openai.rb
69
+ - lib/dexter_llm/agent/agent.rb
70
+ - lib/dexter_llm/agent/agent_busy_error.rb
71
+ - lib/dexter_llm/agent/console.rb
72
+ - lib/dexter_llm/agent/error.rb
73
+ - lib/dexter_llm/agent/event.rb
74
+ - lib/dexter_llm/agent/loop.rb
75
+ - lib/dexter_llm/agent/max_iterations_error.rb
76
+ - lib/dexter_llm/agent/session.rb
77
+ - lib/dexter_llm/agent/state.rb
78
+ - lib/dexter_llm/api.rb
79
+ - lib/dexter_llm/api_error.rb
80
+ - lib/dexter_llm/assistant_message.rb
81
+ - lib/dexter_llm/authentication_error.rb
82
+ - lib/dexter_llm/built_in_tool.rb
83
+ - lib/dexter_llm/built_in_tools/web_fetch.rb
84
+ - lib/dexter_llm/built_in_tools/web_search.rb
85
+ - lib/dexter_llm/cancellation_signal.rb
86
+ - lib/dexter_llm/cancelled_error.rb
87
+ - lib/dexter_llm/client.rb
88
+ - lib/dexter_llm/configuration.rb
89
+ - lib/dexter_llm/content.rb
90
+ - lib/dexter_llm/context_overflow_error.rb
91
+ - lib/dexter_llm/documents/ingestor.rb
92
+ - lib/dexter_llm/documents/store.rb
93
+ - lib/dexter_llm/documents/stored_document.rb
94
+ - lib/dexter_llm/documents/stores/file_system.rb
95
+ - lib/dexter_llm/error.rb
96
+ - lib/dexter_llm/instrumentation.rb
97
+ - lib/dexter_llm/invalid_request_error.rb
98
+ - lib/dexter_llm/message.rb
99
+ - lib/dexter_llm/message_transformer.rb
100
+ - lib/dexter_llm/model.rb
101
+ - lib/dexter_llm/models.rb
102
+ - lib/dexter_llm/models/catalog.yml
103
+ - lib/dexter_llm/pricing.rb
104
+ - lib/dexter_llm/prompt/materializer.rb
105
+ - lib/dexter_llm/provider.rb
106
+ - lib/dexter_llm/rate_limit_error.rb
107
+ - lib/dexter_llm/retry_policy.rb
108
+ - lib/dexter_llm/schema.rb
109
+ - lib/dexter_llm/schema/builder.rb
110
+ - lib/dexter_llm/schema/coercer.rb
111
+ - lib/dexter_llm/schema/validator.rb
112
+ - lib/dexter_llm/session/compaction.rb
113
+ - lib/dexter_llm/session/compaction_settings.rb
114
+ - lib/dexter_llm/session/entry.rb
115
+ - lib/dexter_llm/session/error.rb
116
+ - lib/dexter_llm/session/loaded_session.rb
117
+ - lib/dexter_llm/session/manager.rb
118
+ - lib/dexter_llm/session/store.rb
119
+ - lib/dexter_llm/session/stores/jsonl_file.rb
120
+ - lib/dexter_llm/stop_reason.rb
121
+ - lib/dexter_llm/stream_event.rb
122
+ - lib/dexter_llm/streaming/events.rb
123
+ - lib/dexter_llm/streaming/sse_parser.rb
124
+ - lib/dexter_llm/summary_message.rb
125
+ - lib/dexter_llm/thinking_level.rb
126
+ - lib/dexter_llm/token_estimator.rb
127
+ - lib/dexter_llm/tool.rb
128
+ - lib/dexter_llm/tool_result_message.rb
129
+ - lib/dexter_llm/unsupported_content_error.rb
130
+ - lib/dexter_llm/usage.rb
131
+ - lib/dexter_llm/user_message.rb
132
+ - lib/dexter_llm/version.rb
133
+ homepage: https://github.com/getdexter/llm
134
+ licenses:
135
+ - MIT
136
+ metadata:
137
+ homepage_uri: https://github.com/getdexter/llm
138
+ source_code_uri: https://github.com/getdexter/llm
139
+ changelog_uri: https://github.com/getdexter/llm/blob/main/CHANGELOG.md
140
+ rubygems_mfa_required: 'true'
141
+ rdoc_options: []
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: 3.2.0
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ requirements: []
155
+ rubygems_version: 3.6.9
156
+ specification_version: 4
157
+ summary: Unified LLM agent core (providers, tools, sessions, compaction)
158
+ test_files: []