little_ghost 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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +50 -47
  3. data/docs/guides/{Core Concepts.md → core_concepts.md} +40 -20
  4. data/docs/guides/getting_started.md +164 -0
  5. data/lib/little_ghost/ag_ui/adapter.rb +1 -1
  6. data/lib/little_ghost/agent/context_management.rb +1 -4
  7. data/lib/little_ghost/agent.rb +94 -26
  8. data/lib/little_ghost/agent_builder.rb +1 -1
  9. data/lib/little_ghost/configuration.rb +210 -29
  10. data/lib/little_ghost/data/model_catalog.json +19178 -0
  11. data/lib/little_ghost/errors.rb +6 -0
  12. data/lib/little_ghost/invocation.rb +2 -17
  13. data/lib/little_ghost/model.rb +53 -33
  14. data/lib/little_ghost/model_capabilities.rb +6 -5
  15. data/lib/little_ghost/model_resolver.rb +316 -0
  16. data/lib/little_ghost/models/catalog/models_dev_source.rb +62 -0
  17. data/lib/little_ghost/models/catalog/source.rb +30 -0
  18. data/lib/little_ghost/models/catalog.rb +154 -0
  19. data/lib/little_ghost/models/catalog_snapshot.rb +44 -0
  20. data/lib/little_ghost/models/configuration.rb +43 -0
  21. data/lib/little_ghost/models/details.rb +48 -0
  22. data/lib/little_ghost/models/target.rb +29 -0
  23. data/lib/little_ghost/provider_registry.rb +75 -0
  24. data/lib/little_ghost/providers/anthropic/catalog_source.rb +31 -0
  25. data/lib/little_ghost/providers/anthropic.rb +222 -0
  26. data/lib/little_ghost/providers/base.rb +46 -0
  27. data/lib/little_ghost/providers/bedrock/aws_protocol.rb +132 -0
  28. data/lib/little_ghost/providers/bedrock/catalog_source.rb +200 -0
  29. data/lib/little_ghost/providers/bedrock/credential_resolver.rb +123 -0
  30. data/lib/little_ghost/providers/bedrock/http_client.rb +78 -0
  31. data/lib/little_ghost/providers/bedrock.rb +23 -15
  32. data/lib/little_ghost/providers/configuration.rb +79 -0
  33. data/lib/little_ghost/providers/gemini/catalog_source.rb +35 -0
  34. data/lib/little_ghost/providers/gemini.rb +204 -0
  35. data/lib/little_ghost/providers/open_router/catalog_source.rb +42 -0
  36. data/lib/little_ghost/providers/open_router.rb +6 -2
  37. data/lib/little_ghost/providers/openai_compatible.rb +19 -23
  38. data/lib/little_ghost/providers/vertex_ai/credential_resolver.rb +90 -0
  39. data/lib/little_ghost/providers/vertex_ai.rb +38 -0
  40. data/lib/little_ghost/run.rb +7 -7
  41. data/lib/little_ghost/runtime.rb +10 -7
  42. data/lib/little_ghost/sandbox.rb +5 -5
  43. data/lib/little_ghost/session_store.rb +3 -3
  44. data/lib/little_ghost/structured_output.rb +2 -8
  45. data/lib/little_ghost/support/http_client.rb +186 -0
  46. data/lib/little_ghost/{providers → support}/sse_parser.rb +1 -1
  47. data/lib/little_ghost/tool.rb +5 -1
  48. data/lib/little_ghost/tool_registry.rb +2 -3
  49. data/lib/little_ghost/version.rb +1 -1
  50. data/lib/little_ghost/workflow.rb +1 -1
  51. data/lib/little_ghost.rb +21 -15
  52. metadata +28 -7
  53. data/docs/guides/Getting Started.md +0 -187
  54. data/lib/little_ghost/default_model_registry.rb +0 -71
  55. data/lib/little_ghost/model_registry.rb +0 -173
  56. data/lib/little_ghost/providers/http_transport.rb +0 -149
@@ -10,7 +10,10 @@ module LittleGhost
10
10
  #
11
11
  # configuration = LittleGhost::Configuration.new(
12
12
  # root: Dir.pwd,
13
- # models: CustomerSupportModels,
13
+ # providers: {
14
+ # openai: {adapter: :openai, api_key: ENV.fetch("OPENAI_API_KEY")}
15
+ # },
16
+ # models: {customer_support: {target: "openai:gpt-5.6-luna"}},
14
17
  # default_model: "customer_support",
15
18
  # service_name: "support-api"
16
19
  # )
@@ -22,7 +25,7 @@ module LittleGhost
22
25
  # Without explicit +settings+, construction canonicalizes the root, loads
23
26
  # +config/little_ghost.rb+ once through the Configuration, snapshots settings,
24
27
  # configures instrumentation, eager-loads application constants, and builds the
25
- # selected model registry and session store. Supplying +settings+ is the
28
+ # selected model resolver and session store. Supplying +settings+ is the
26
29
  # lower-level path used to create a sibling runtime from an existing snapshot.
27
30
  #
28
31
  # Reuse a runtime across runs. +build_run+ creates any missing workspace and
@@ -38,7 +41,7 @@ module LittleGhost
38
41
  class Runtime
39
42
  # The snapshotted setup and materialized services used by new runs.
40
43
  attr_reader :configuration, :settings, :root, :loader, :prompt_paths, :skill_paths,
41
- :skill_resource_root, :models, :session_store, :workspace_class, :sandbox_class,
44
+ :skill_resource_root, :model_resolver, :session_store, :workspace_class, :sandbox_class,
42
45
  :runtime_hooks
43
46
 
44
47
  # Starts a runtime from +configuration+ or an existing settings snapshot.
@@ -75,9 +78,9 @@ module LittleGhost
75
78
  loader.setup
76
79
  loader.eager_load
77
80
 
78
- @startup_phase = "models"
81
+ @startup_phase = "model_resolver"
79
82
  @invocation_class = @settings[:invocation] || Invocation
80
- @models = build_service(@settings[:models], default: -> { DefaultModelRegistry.new })
83
+ @model_resolver = @settings.fetch(:model_resolver)
81
84
  @default_model = @settings.fetch(:default_model, "default").to_s
82
85
 
83
86
  @startup_phase = "session_store"
@@ -189,8 +192,8 @@ module LittleGhost
189
192
  end
190
193
 
191
194
  def model_for(agent_class, run) # :nodoc:
192
- role = agent_class.model_role(run.invocation) || @default_model
193
- models.resolve(role, invocation: run.invocation, run:)
195
+ selection = agent_class.model_selection(run.invocation) || @default_model
196
+ model_resolver.resolve(selection, invocation: run.invocation, context: run)
194
197
  end
195
198
 
196
199
  def open_session(run) # :nodoc:
@@ -90,22 +90,22 @@ module LittleGhost
90
90
 
91
91
  # Reads UTF-8 text at a workspace-relative +path+.
92
92
  def read(path, context: nil)
93
- raise NotImplementedError, "#{self.class} does not support filesystem reads"
93
+ raise AbstractMethodError, "#{self.class} does not support filesystem reads"
94
94
  end
95
95
 
96
96
  # Lists entries at a workspace-relative directory +path+.
97
97
  def list(path = ".", context: nil)
98
- raise NotImplementedError, "#{self.class} does not support filesystem listings"
98
+ raise AbstractMethodError, "#{self.class} does not support filesystem listings"
99
99
  end
100
100
 
101
101
  # Writes +content+ to a workspace-relative +path+.
102
102
  def write(path, content, context: nil)
103
- raise NotImplementedError, "#{self.class} does not support filesystem writes"
103
+ raise AbstractMethodError, "#{self.class} does not support filesystem writes"
104
104
  end
105
105
 
106
106
  # Replaces one exact +old_text+ occurrence with +new_text+.
107
107
  def replace(path, old_text, new_text, context: nil)
108
- raise NotImplementedError, "#{self.class} does not support filesystem edits"
108
+ raise AbstractMethodError, "#{self.class} does not support filesystem edits"
109
109
  end
110
110
 
111
111
  # Executes +command+ through +/bin/sh+.
@@ -127,7 +127,7 @@ module LittleGhost
127
127
  # Implementations must enforce +timeout+ and +max_output_bytes+. Environment
128
128
  # inheritance is disabled by default to avoid leaking process credentials.
129
129
  def execute_program(command, timeout:, context: nil, max_output_bytes: 1_000_000, environment: {}, inherit_environment: false)
130
- raise NotImplementedError, "#{self.class} does not support program execution"
130
+ raise AbstractMethodError, "#{self.class} does not support program execution"
131
131
  end
132
132
 
133
133
  # Releases sandbox resources. Runs close the sandbox before its workspace.
@@ -36,19 +36,19 @@ module LittleGhost
36
36
 
37
37
  # Finds the snapshot for +id+, or returns nil when it does not exist.
38
38
  def load(_id, actor_id: nil)
39
- raise NotImplementedError
39
+ raise AbstractMethodError, "#{self.class} must implement #load"
40
40
  end
41
41
 
42
42
  # Atomically appends sanitized messages and stores state and metadata.
43
43
  # Implementations raise ProtocolError if the persisted message count differs
44
44
  # from +expected_count+.
45
45
  def append(_id, messages:, state:, metadata:, expected_count:, actor_id: nil)
46
- raise NotImplementedError
46
+ raise AbstractMethodError, "#{self.class} must implement #append"
47
47
  end
48
48
 
49
49
  # Replaces the complete snapshot for +id+ atomically.
50
50
  def replace(_id, messages:, state:, metadata:, actor_id: nil)
51
- raise NotImplementedError
51
+ raise AbstractMethodError, "#{self.class} must implement #replace"
52
52
  end
53
53
 
54
54
  # Stores may expose a clean conversational view without changing the stored
@@ -56,11 +56,7 @@ module LittleGhost
56
56
  return unless configuration
57
57
 
58
58
  requested = configuration.fetch(:strategy, :auto).to_sym
59
- capabilities = if model.respond_to?(:capabilities)
60
- model.capabilities
61
- else
62
- ModelCapabilities.legacy
63
- end
59
+ capabilities = model.capabilities
64
60
  strategy = case requested
65
61
  when :auto then automatic_strategy(model, capabilities, ordinary_tools)
66
62
  when :provider
@@ -117,9 +113,7 @@ module LittleGhost
117
113
  private_class_method :validate_explicit_tool!
118
114
 
119
115
  def model_identity(model)
120
- provider = model.respond_to?(:provider_name) ? model.provider_name : model.class.name
121
- id = model.respond_to?(:id) ? model.id : nil
122
- [provider, id].compact.join("/")
116
+ [model.target.provider, model.model_id].join("/")
123
117
  end
124
118
  private_class_method :model_identity
125
119
  end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "openssl"
5
+ require "uri"
6
+
7
+ module LittleGhost
8
+ module Support
9
+ # HTTPClient gives integrations a shared, bounded streaming HTTP layer.
10
+ # It applies cancellation, deadlines, timeouts, and response-size limits while
11
+ # yielding response chunks as they arrive.
12
+ #
13
+ # === Security and trust
14
+ #
15
+ # HTTPS is required by default. Enabling +allow_insecure_http+ can expose API
16
+ # keys and model content in transit; use it only with a trusted local
17
+ # development endpoint.
18
+ class HTTPClient
19
+ # Default upper bound for a complete provider response (50 MiB).
20
+ DEFAULT_MAX_RESPONSE_BYTES = 50 * 1024 * 1024
21
+ DEFAULT_MAX_ERROR_BODY_BYTES = 4 * 1024 # :nodoc:
22
+ TRANSIENT_NETWORK_ERRORS = [
23
+ Net::OpenTimeout,
24
+ Net::ReadTimeout,
25
+ Net::WriteTimeout,
26
+ EOFError,
27
+ SocketError,
28
+ SystemCallError,
29
+ IOError,
30
+ OpenSSL::SSL::SSLError,
31
+ Net::ProtocolError,
32
+ Net::HTTPBadResponse,
33
+ Net::HTTPHeaderSyntaxError
34
+ ].freeze # :nodoc:
35
+
36
+ # Configures +base_url+ with connection, read, and response
37
+ # size limits.
38
+ def initialize(
39
+ base_url: nil,
40
+ open_timeout: 10,
41
+ read_timeout: 120,
42
+ allow_insecure_http: false,
43
+ max_response_bytes: DEFAULT_MAX_RESPONSE_BYTES,
44
+ max_error_body_bytes: DEFAULT_MAX_ERROR_BODY_BYTES
45
+ )
46
+ if base_url
47
+ @base_url = URI(base_url.end_with?("/") ? base_url : "#{base_url}/")
48
+ validate_uri!(@base_url, allow_insecure_http:)
49
+ end
50
+
51
+ @open_timeout = open_timeout
52
+ @read_timeout = read_timeout
53
+ @allow_insecure_http = allow_insecure_http
54
+ @max_response_bytes = positive_integer(max_response_bytes, :max_response_bytes)
55
+ @max_error_body_bytes = positive_integer(max_error_body_bytes, :max_error_body_bytes)
56
+ end
57
+
58
+ # Posts +body+ and yields response chunks until completion.
59
+ #
60
+ # Cancellation and +deadline+ interrupt the request. Without a block, this
61
+ # method returns an Enumerator.
62
+ def stream(path:, headers:, body:, cancellation_token:, deadline: nil)
63
+ return enum_for(__method__, path:, headers:, body:, cancellation_token:, deadline:) unless block_given?
64
+ raise ConfigurationError, "HTTP client requires base_url for streaming" unless @base_url
65
+
66
+ stream = Support::InterruptibleStream.new(cancellation_token:, deadline:) do |emit|
67
+ uri = URI.join(@base_url.to_s, path.sub(%r{\A/}, ""))
68
+ each_chunk(
69
+ uri:,
70
+ method: :post,
71
+ headers:,
72
+ body:,
73
+ deadline:,
74
+ allow_insecure_http: @allow_insecure_http,
75
+ label: "Provider"
76
+ ) { |chunk| emit.call(chunk) }
77
+ end
78
+ stream.each { |chunk| yield chunk }
79
+ end
80
+
81
+ # Executes a bounded request and returns the complete response body.
82
+ def request(uri:, method: :get, headers: {}, body: nil, allow_insecure_http: false,
83
+ cancellation_token: nil, deadline: nil)
84
+ response_body = +""
85
+ each_chunk(
86
+ uri:,
87
+ method:,
88
+ headers:,
89
+ body:,
90
+ cancellation_token:,
91
+ deadline: deadline || Time.now + @read_timeout,
92
+ allow_insecure_http:
93
+ ) { |chunk| response_body << chunk }
94
+ response_body
95
+ end
96
+
97
+ # Executes a bounded request and yields response chunks as they arrive.
98
+ def each_chunk(uri:, method: :get, headers: {}, body: nil, deadline: nil,
99
+ cancellation_token: nil, allow_insecure_http: false, label: "HTTP request")
100
+ unless block_given?
101
+ return enum_for(
102
+ __method__, uri:, method:, headers:, body:, deadline:, cancellation_token:, allow_insecure_http:, label:
103
+ )
104
+ end
105
+
106
+ uri = URI(uri.to_s)
107
+ validate_uri!(uri, allow_insecure_http:)
108
+ check_control!(cancellation_token, deadline)
109
+ request_class = {get: Net::HTTP::Get, post: Net::HTTP::Post, put: Net::HTTP::Put}.fetch(method.to_sym) do
110
+ raise ArgumentError, "unsupported HTTP method: #{method}"
111
+ end
112
+ request = request_class.new(uri)
113
+ headers.each { |name, value| request[name] = value unless value.to_s.empty? }
114
+ request.body = body if body
115
+ http = Net::HTTP.new(uri.host, uri.port)
116
+ http.use_ssl = uri.scheme == "https"
117
+ http.open_timeout = remaining_timeout(deadline, @open_timeout)
118
+ http.read_timeout = remaining_timeout(deadline, @read_timeout)
119
+ http.write_timeout = remaining_timeout(deadline, @read_timeout)
120
+ http.request(request) do |response|
121
+ unless response.is_a?(Net::HTTPSuccess)
122
+ response_body = read_limited(response, @max_error_body_bytes)
123
+ raise Providers::HTTPError.new(
124
+ "#{label} failed with HTTP #{response.code}",
125
+ status: response.code.to_i,
126
+ body: response_body
127
+ )
128
+ end
129
+
130
+ bytes_read = 0
131
+ response.read_body do |chunk|
132
+ check_control!(cancellation_token, deadline)
133
+ bytes_read += chunk.bytesize
134
+ raise ProtocolError, "#{label} response exceeded #{@max_response_bytes} bytes" if bytes_read > @max_response_bytes
135
+
136
+ yield chunk
137
+ end
138
+ end
139
+ rescue *TRANSIENT_NETWORK_ERRORS => error
140
+ raise Providers::HTTPError, "#{label} failed (#{error.class})"
141
+ end
142
+
143
+ private
144
+
145
+ def check_control!(cancellation_token, deadline)
146
+ cancellation_token&.raise_if_cancelled!
147
+ raise DeadlineExceededError, "The request deadline was reached" if deadline && Time.now >= deadline
148
+ end
149
+
150
+ def validate_uri!(uri, allow_insecure_http:)
151
+ unless %w[http https].include?(uri.scheme) && uri.host
152
+ raise ConfigurationError, "HTTP endpoint must be an HTTP(S) URL"
153
+ end
154
+ if uri.scheme == "http" && !allow_insecure_http
155
+ raise ConfigurationError, "HTTP endpoint must use HTTPS unless allow_insecure_http is enabled"
156
+ end
157
+ end
158
+
159
+ def remaining_timeout(deadline, maximum)
160
+ return maximum unless deadline
161
+
162
+ remaining = deadline - Time.now
163
+ raise DeadlineExceededError, "The run deadline was reached" unless remaining.positive?
164
+
165
+ [remaining, maximum].min
166
+ end
167
+
168
+ def read_limited(response, limit)
169
+ body = +""
170
+ response.read_body do |chunk|
171
+ remaining = limit - body.bytesize
172
+ body << chunk.byteslice(0, remaining) if remaining.positive?
173
+ break if body.bytesize >= limit
174
+ end
175
+ body
176
+ end
177
+
178
+ def positive_integer(value, name)
179
+ integer = Integer(value)
180
+ raise ArgumentError, "#{name} must be positive" unless integer.positive?
181
+
182
+ integer
183
+ end
184
+ end
185
+ end
186
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LittleGhost
4
- module Providers
4
+ module Support
5
5
  class SSEParser # :nodoc:
6
6
  def initialize
7
7
  @buffer = +""
@@ -306,7 +306,11 @@ module LittleGhost
306
306
  # Subclasses must override this method. The current RunContext is available
307
307
  # through +context+ while the call executes.
308
308
  def call(_input)
309
- raise NotImplementedError, "#{self.class} must implement #call"
309
+ raise AbstractMethodError, "#{self.class} must implement #call"
310
+ end
311
+
312
+ # Releases resources owned by this tool. Subclasses may override it.
313
+ def close
310
314
  end
311
315
 
312
316
  protected
@@ -12,7 +12,7 @@ module LittleGhost
12
12
  # Entries may be Tool instances, Tool subclasses, nested arrays, or provider
13
13
  # classes that implement <tt>tools(binding)</tt>. Names must be unique, contain only
14
14
  # letters, numbers, underscores, or hyphens, and be at most 64 characters.
15
- # Owned tools that implement +close+ are closed once in reverse order.
15
+ # Owned tools are closed once in reverse order.
16
16
  class ToolRegistry
17
17
  MAX_NAME_LENGTH = 64 # :nodoc:
18
18
  NAME_PATTERN = /\A[a-zA-Z0-9_-]+\z/ # :nodoc:
@@ -76,7 +76,7 @@ module LittleGhost
76
76
  raise error
77
77
  end
78
78
 
79
- # Closes every owned tool that responds to +close+.
79
+ # Closes every owned tool.
80
80
  def close
81
81
  return if @closed
82
82
 
@@ -113,7 +113,6 @@ module LittleGhost
113
113
  def close_instances(instances)
114
114
  first_error = nil
115
115
  instances.reverse_each do |instance|
116
- next unless instance.respond_to?(:close)
117
116
  next if @closed_tool_ids[instance.object_id]
118
117
 
119
118
  @closed_tool_ids[instance.object_id] = true
@@ -2,5 +2,5 @@
2
2
 
3
3
  module LittleGhost
4
4
  # Current LittleGhost gem version.
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
@@ -246,7 +246,7 @@ module LittleGhost
246
246
  # Implements the composition and returns its final unconsumed invocation.
247
247
  # Subclasses must override this hook.
248
248
  def perform
249
- raise NotImplementedError, "#{self.class} must implement #perform"
249
+ raise AbstractMethodError, "#{self.class} must implement #perform"
250
250
  end
251
251
 
252
252
  # :doc:
data/lib/little_ghost.rb CHANGED
@@ -18,15 +18,27 @@ require_relative "little_ghost/model_request"
18
18
  require_relative "little_ghost/model_response"
19
19
  require_relative "little_ghost/run_result"
20
20
  require_relative "little_ghost/model_capabilities"
21
+ require_relative "little_ghost/models/target"
22
+ require_relative "little_ghost/models/details"
21
23
  require_relative "little_ghost/model"
22
- require_relative "little_ghost/model_registry"
23
- require_relative "little_ghost/providers/sse_parser"
24
- require_relative "little_ghost/providers/http_transport"
24
+ require_relative "little_ghost/support/sse_parser"
25
+ require_relative "little_ghost/support/http_client"
26
+ require_relative "little_ghost/providers/base"
27
+ require_relative "little_ghost/providers/configuration"
28
+ require_relative "little_ghost/models/catalog/source"
29
+ require_relative "little_ghost/models/catalog/models_dev_source"
25
30
  require_relative "little_ghost/providers/openai_compatible"
26
31
  require_relative "little_ghost/providers/openai"
27
32
  require_relative "little_ghost/providers/open_router"
28
33
  require_relative "little_ghost/providers/bedrock"
29
- require_relative "little_ghost/default_model_registry"
34
+ require_relative "little_ghost/providers/anthropic"
35
+ require_relative "little_ghost/providers/gemini"
36
+ require_relative "little_ghost/providers/vertex_ai"
37
+ require_relative "little_ghost/models/catalog"
38
+ require_relative "little_ghost/models/catalog_snapshot"
39
+ require_relative "little_ghost/models/configuration"
40
+ require_relative "little_ghost/provider_registry"
41
+ require_relative "little_ghost/model_resolver"
30
42
  require_relative "little_ghost/run_context"
31
43
  require_relative "little_ghost/workspace"
32
44
  require_relative "little_ghost/sandbox"
@@ -60,19 +72,14 @@ require_relative "little_ghost/runtime"
60
72
  # A customer support agent can answer directly, use an application tool, or ask a
61
73
  # specialist for research while the caller observes one run:
62
74
  #
63
- # LittleGhost.configure do |config|
64
- # config.models CustomerSupportModels
65
- # config.default_model :customer_support
66
- # end
67
- #
68
75
  # class ResearchAgent < LittleGhost::Agent
69
76
  # description "Researches difficult support questions"
70
- # model "customer_support.research"
77
+ # model "openai:gpt-5.6-luna"
71
78
  # end
72
79
  #
73
80
  # class CustomerSupportAgent < LittleGhost::Agent
74
81
  # description "Handles support requests"
75
- # model :customer_support
82
+ # model "openai:gpt-5.6-luna"
76
83
  # tools AccountTool
77
84
  # subagent ResearchAgent, kind: "research"
78
85
  # end
@@ -97,10 +104,6 @@ module LittleGhost
97
104
  ExecutionState[:configuration] || (@configuration ||= Configuration.new)
98
105
  end
99
106
 
100
- # Alias for .configuration. Without an execution-scoped override, this is the
101
- # process-wide default Configuration.
102
- alias_method :default_configuration, :configuration
103
-
104
107
  # Opens the active Configuration for application setup and returns it.
105
108
  #
106
109
  # Configuration files are loaded lazily when a runtime is first built, so
@@ -109,6 +112,9 @@ module LittleGhost
109
112
  configuration.configure(&block)
110
113
  end
111
114
 
115
+ # Returns the model resolver owned by the active process configuration.
116
+ def model_resolver = configuration.model_resolver
117
+
112
118
  # Makes +configuration+ current only while the block runs.
113
119
  #
114
120
  # Execution state restores the previous configuration even when the block
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: little_ghost
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
  - Matt Robinson
@@ -117,8 +117,8 @@ extra_rdoc_files: []
117
117
  files:
118
118
  - LICENSE.txt
119
119
  - README.md
120
- - docs/guides/Core Concepts.md
121
- - docs/guides/Getting Started.md
120
+ - docs/guides/core_concepts.md
121
+ - docs/guides/getting_started.md
122
122
  - lib/little_ghost.rb
123
123
  - lib/little_ghost/ag_ui.rb
124
124
  - lib/little_ghost/ag_ui/adapter.rb
@@ -131,7 +131,7 @@ files:
131
131
  - lib/little_ghost/agent_interruptions.rb
132
132
  - lib/little_ghost/configuration.rb
133
133
  - lib/little_ghost/content.rb
134
- - lib/little_ghost/default_model_registry.rb
134
+ - lib/little_ghost/data/model_catalog.json
135
135
  - lib/little_ghost/errors.rb
136
136
  - lib/little_ghost/events.rb
137
137
  - lib/little_ghost/execution_state.rb
@@ -143,17 +143,36 @@ files:
143
143
  - lib/little_ghost/message.rb
144
144
  - lib/little_ghost/model.rb
145
145
  - lib/little_ghost/model_capabilities.rb
146
- - lib/little_ghost/model_registry.rb
147
146
  - lib/little_ghost/model_request.rb
147
+ - lib/little_ghost/model_resolver.rb
148
148
  - lib/little_ghost/model_response.rb
149
+ - lib/little_ghost/models/catalog.rb
150
+ - lib/little_ghost/models/catalog/models_dev_source.rb
151
+ - lib/little_ghost/models/catalog/source.rb
152
+ - lib/little_ghost/models/catalog_snapshot.rb
153
+ - lib/little_ghost/models/configuration.rb
154
+ - lib/little_ghost/models/details.rb
155
+ - lib/little_ghost/models/target.rb
149
156
  - lib/little_ghost/path_set.rb
150
157
  - lib/little_ghost/prompt_resolver.rb
158
+ - lib/little_ghost/provider_registry.rb
159
+ - lib/little_ghost/providers/anthropic.rb
160
+ - lib/little_ghost/providers/anthropic/catalog_source.rb
161
+ - lib/little_ghost/providers/base.rb
151
162
  - lib/little_ghost/providers/bedrock.rb
152
- - lib/little_ghost/providers/http_transport.rb
163
+ - lib/little_ghost/providers/bedrock/aws_protocol.rb
164
+ - lib/little_ghost/providers/bedrock/catalog_source.rb
165
+ - lib/little_ghost/providers/bedrock/credential_resolver.rb
166
+ - lib/little_ghost/providers/bedrock/http_client.rb
167
+ - lib/little_ghost/providers/configuration.rb
168
+ - lib/little_ghost/providers/gemini.rb
169
+ - lib/little_ghost/providers/gemini/catalog_source.rb
153
170
  - lib/little_ghost/providers/open_router.rb
171
+ - lib/little_ghost/providers/open_router/catalog_source.rb
154
172
  - lib/little_ghost/providers/openai.rb
155
173
  - lib/little_ghost/providers/openai_compatible.rb
156
- - lib/little_ghost/providers/sse_parser.rb
174
+ - lib/little_ghost/providers/vertex_ai.rb
175
+ - lib/little_ghost/providers/vertex_ai/credential_resolver.rb
157
176
  - lib/little_ghost/run.rb
158
177
  - lib/little_ghost/run_context.rb
159
178
  - lib/little_ghost/run_result.rb
@@ -178,10 +197,12 @@ files:
178
197
  - lib/little_ghost/support/class_attributes.rb
179
198
  - lib/little_ghost/support/content_capture.rb
180
199
  - lib/little_ghost/support/executor.rb
200
+ - lib/little_ghost/support/http_client.rb
181
201
  - lib/little_ghost/support/interruptible_stream.rb
182
202
  - lib/little_ghost/support/loader.rb
183
203
  - lib/little_ghost/support/output_truncation.rb
184
204
  - lib/little_ghost/support/redactor.rb
205
+ - lib/little_ghost/support/sse_parser.rb
185
206
  - lib/little_ghost/tool.rb
186
207
  - lib/little_ghost/tool_execution.rb
187
208
  - lib/little_ghost/tool_registry.rb