Class: LittleGhost::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/little_ghost/configuration.rb

Overview

Configure shared services and lookup rules before agents start. A configuration collects model profiles, persistence, paths, instrumentation, and runtime hooks for an application.

LittleGhost.configure do |config|
config.models CustomerSupportModels
config.default_model :customer_support
config.service_name "support-api"
end

LittleGhost.configuration.default_model # => "customer_support"
LittleGhost.configuration.service_name  # => "support-api"

Prompt and skill lookup paths default to app/prompts and app/skills under the application root. Applications may append shared roots or replace the arrays entirely.

Configuration is a mutable builder, while each Runtime owns a settings snapshot. The first runtime for a root loads config/little_ghost.rb once; later mutations do not alter that runtime, and one configuration cannot load files for two different roots.

Session actor resolvers belong at an authentication boundary. Multi-tenant applications should derive actor identity from trusted authenticated state, not from an unverified request field.

Constant Summary collapse

FILE_LOAD_MUTEX =

:nodoc:

Mutex.new
CONFIGURATION_KEYS =

:nodoc:

%i[invocation models default_model service_name].freeze
DEFAULT_PROMPT_PATHS =

:nodoc:

["app/prompts"].freeze
DEFAULT_SKILL_PATHS =

:nodoc:

["app/skills"].freeze

Instance Method Summary collapse

Constructor Details

#initialize(values = {}) ⇒ Configuration

Starts a mutable builder with optional values.

Prompt paths default to app/prompts and skill paths to app/skills. Collection settings are copied so callers can safely reuse their input arrays after construction.



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/little_ghost/configuration.rb', line 111

def initialize(values = {})
  @configuration_values = {
    prompt_paths: DEFAULT_PROMPT_PATHS.dup,
    skill_paths: DEFAULT_SKILL_PATHS.dup,
    skill_resource_root: nil,
    workspace: nil,
    sandbox: nil,
    instrumentation_subscribers: [],
    runtime_hooks: []
  }.merge(values)
  @configuration_values[:prompt_paths] = Array(@configuration_values[:prompt_paths]).dup
  @configuration_values[:skill_paths] = Array(@configuration_values[:skill_paths]).dup
  @configuration_values[:instrumentation_subscribers] = Array(
    @configuration_values[:instrumentation_subscribers]
  ).dup
  @configuration_values[:runtime_hooks] = Array(@configuration_values[:runtime_hooks]).dup
end

Instance Method Details

#[](name) ⇒ Object

Looks up an arbitrary setting by symbol or string-compatible name.



166
167
168
# File 'lib/little_ghost/configuration.rb', line 166

def [](name)
  configuration_values.fetch(name.to_sym)
end

#[]=(name, value) ⇒ Object

Adds or replaces an arbitrary setting.



171
172
173
# File 'lib/little_ghost/configuration.rb', line 171

def []=(name, value)
  configuration_values[name.to_sym] = value
end

#configure {|_self| ... } ⇒ Object

Yields this builder for setup and returns the same instance.

Yields:

  • (_self)

Yield Parameters:



130
131
132
133
# File 'lib/little_ghost/configuration.rb', line 130

def configure
  yield self if block_given?
  self
end

#instrument(subscriber) ⇒ Object

Adds an Instrumentation::Subscriber to each new runtime and returns it.



181
182
183
184
185
186
187
188
# File 'lib/little_ghost/configuration.rb', line 181

def instrument(subscriber)
  unless subscriber.is_a?(Instrumentation::Subscriber)
    raise ArgumentError, "instrumentation subscriber must be a LittleGhost::Instrumentation::Subscriber"
  end

  configuration_values[:instrumentation_subscribers] << subscriber
  subscriber
end

#load_file!(root: nil) ⇒ Object

:nodoc:



293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/little_ghost/configuration.rb', line 293

def load_file!(root: nil) # :nodoc:
  requested_root = canonical_root(root || self.root)
  FILE_LOAD_MUTEX.synchronize do
    (@configuration_file_mutex ||= Mutex.new).synchronize do
      if @configuration_file_root
        return self if @configuration_file_root == requested_root

        raise ConfigurationError, "configuration file is already loaded for #{@configuration_file_root}"
      end

      path = File.join(requested_root, "config/little_ghost.rb")
      LittleGhost.with_configuration(self) { Kernel.load(path) } if File.file?(path)
      @configuration_file_root = requested_root
    end
  end

  self
end

#log_events_to(destination = :__read__) ⇒ Object

:call-seq:

log_events_to() -> :stdout, :stderr, nil
log_events_to(destination) -> destination

Sends structured framework events to :stdout or :stderr. This setting controls the process-wide Events console destination; the most recent setting replaces it without changing other event listeners. By default, events have no console destination. Passing nil disables console output. The console listener redacts sensitive values and writes one JSON object per line.



200
201
202
203
204
# File 'lib/little_ghost/configuration.rb', line 200

def log_events_to(destination = :__read__)
  return Events.console_output if destination == :__read__

  Events.console_output = destination
end

#log_events_to=(destination) ⇒ Object

Replaces the console destination for structured framework events.



207
208
209
# File 'lib/little_ghost/configuration.rb', line 207

def log_events_to=(destination)
  log_events_to(destination)
end

#nameObject

Replaces the service name attached to telemetry from new runtimes. :method: service_name= :call-seq:

service_name=(value) -> value


71
72
73
74
75
76
77
# File 'lib/little_ghost/configuration.rb', line 71

CONFIGURATION_KEYS.each do |name|
  define_method(name) do |value = :__read__|
    return configuration_values[name] if value == :__read__

    configuration_values[name] = (name == :default_model) ? value.to_s : value
  end
end

#prompt_pathsObject

Mutable prompt lookup paths, in precedence order.



259
# File 'lib/little_ghost/configuration.rb', line 259

def prompt_paths = configuration_values[:prompt_paths]

#prompt_paths=(value) ⇒ Object

Replaces prompt lookup paths with value converted to an Array.



262
263
264
# File 'lib/little_ghost/configuration.rb', line 262

def prompt_paths=(value)
  configuration_values[:prompt_paths] = Array(value)
end

#root(value = :__read__) ⇒ Object

:call-seq:

root() -> Pathname
root(path) -> Pathname

The resolved application root, defaulting to Dir.pwd.

Setting or reading an invalid root raises ConfigurationError. Symlinks are resolved so runtimes and lookup paths share one stable boundary.



249
250
251
252
253
254
255
256
# File 'lib/little_ghost/configuration.rb', line 249

def root(value = :__read__)
  if value != :__read__
    return configuration_values[:root] = canonical_root(value)
  end

  configured = configuration_values[:root]
  configured ? canonical_root(configured) : inferred_root
end

#root=(value) ⇒ Object

Replaces the application root after resolving it to a stable real path.



176
177
178
# File 'lib/little_ghost/configuration.rb', line 176

def root=(value)
  root(value)
end

#runtime_hook(hook_class) ⇒ Object

Adds a Runtime::Hook subclass to each new runtime and returns it.



212
213
214
215
216
217
218
219
# File 'lib/little_ghost/configuration.rb', line 212

def runtime_hook(hook_class)
  unless hook_class.is_a?(Class) && hook_class <= Runtime::Hook
    raise ArgumentError, "runtime_hook must be a LittleGhost::Runtime::Hook class"
  end

  configuration_values[:runtime_hooks] << hook_class
  hook_class
end

#sandboxObject

Sandbox declaration used for subsequently built runtimes.



138
139
# File 'lib/little_ghost/configuration.rb', line 138

def sandbox = configuration_values[:sandbox]
# Session-store declaration used for subsequently built runtimes.

#sandbox=(value) ⇒ Object

Selects the Sandbox subclass instantiated around each run's workspace.



148
149
150
# File 'lib/little_ghost/configuration.rb', line 148

def sandbox=(value)
  @configuration_values[:sandbox] = component_class(value, Sandbox, :sandbox)
end

#session_actor(value = :__read__, &resolver) ⇒ Object

:call-seq:

session_actor() -> callable, nil
session_actor(callable) -> callable
session_actor { |invocation| ... } -> callable

The callable that derives the persistence actor for each invocation.

Pass either a callable or a block. The configured resolver should use trusted authenticated identity in multi-tenant applications.

Raises:

  • (ArgumentError)


230
231
232
233
234
235
236
237
238
239
# File 'lib/little_ghost/configuration.rb', line 230

def session_actor(value = :__read__, &resolver)
  return configuration_values[:session_actor] if value == :__read__ && !resolver

  raise ArgumentError, "Provide a session actor resolver or a block, not both" if value != :__read__ && resolver

  configured = resolver || value
  raise ArgumentError, "session_actor must be callable" unless configured.respond_to?(:call)

  configuration_values[:session_actor] = configured
end

#session_storeObject

Session-store declaration used for subsequently built runtimes.



140
# File 'lib/little_ghost/configuration.rb', line 140

def session_store = configuration_values[:session_store]

#session_store=(value) ⇒ Object

Selects session persistence with a :provider and its constructor options.

The provider must be a SessionStore subclass. Runtime construction creates and owns the store instance.



156
157
158
159
160
161
162
163
# File 'lib/little_ghost/configuration.rb', line 156

def session_store=(value)
  unless value.is_a?(Hash)
    raise ArgumentError, "session_store must be a hash with a provider"
  end

  provider = value[:provider]
  @configuration_values[:session_store] = value.merge(provider: component_class(provider, SessionStore, :session_store))
end

#settings(root: nil) ⇒ Object

:nodoc:



282
283
284
285
286
287
288
289
290
291
# File 'lib/little_ghost/configuration.rb', line 282

def settings(root: nil) # :nodoc:
  requested_root = root && canonical_root(root)
  values = configuration_values.dup
  values[:prompt_paths] = Array(values[:prompt_paths]).dup
  values[:skill_paths] = Array(values[:skill_paths]).dup
  values[:instrumentation_subscribers] = Array(values[:instrumentation_subscribers]).dup
  values[:runtime_hooks] = Array(values[:runtime_hooks]).dup
  values[:root] = requested_root || values[:root] || self.root
  values
end

#skill_pathsObject

Mutable skill lookup paths, in precedence order.



267
# File 'lib/little_ghost/configuration.rb', line 267

def skill_paths = configuration_values[:skill_paths]

#skill_paths=(value) ⇒ Object

Replaces skill lookup paths with value converted to an Array.



270
271
272
# File 'lib/little_ghost/configuration.rb', line 270

def skill_paths=(value)
  configuration_values[:skill_paths] = Array(value)
end

#skill_resource_rootObject

Optional trusted root exposed to skills for resource lookup.



275
# File 'lib/little_ghost/configuration.rb', line 275

def skill_resource_root = configuration_values[:skill_resource_root]

#skill_resource_root=(value) ⇒ Object

Replaces the trusted skill resource root for new runtimes.



278
279
280
# File 'lib/little_ghost/configuration.rb', line 278

def skill_resource_root=(value)
  configuration_values[:skill_resource_root] = value
end

#workspaceObject

Workspace declaration used for subsequently built runtimes.



136
137
# File 'lib/little_ghost/configuration.rb', line 136

def workspace = configuration_values[:workspace]
# Sandbox declaration used for subsequently built runtimes.

#workspace=(value) ⇒ Object

Selects the Workspace subclass instantiated for each run.



143
144
145
# File 'lib/little_ghost/configuration.rb', line 143

def workspace=(value)
  @configuration_values[:workspace] = component_class(value, Workspace, :workspace)
end