Class: LittleGhost::Invocation

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

Overview

Carry one application request into an agent run. An invocation keeps framework fields and application-specific context in one indifferent-key environment.

invocation = LittleGhost::Invocation.new(
message: "Why is transfer 481 pending?",
account_id: "account-1",
metadata: {channel: "customer_support"}
)

invocation.message.text  # => "Why is transfer 481 pending?"
invocation[:account_id]  # => "account-1"
invocation.    # => "account-1"

String and symbol keys address the same field. Known fields have named accessors, while unknown application fields remain available through hash access and dynamic readers or writers. message and every history entry are normalized to Message objects; deadline_at lazily parses ISO 8601 text.

Missing run, invocation, and session identifiers are generated when the object is built. Actor identity is never inferred: applications that use it for persistence or tenant isolation must pass a value established by their trusted authentication boundary. Invalid payloads, messages, keys, or deadlines raise InvocationError.

Constant Summary collapse

DEFAULTS =
{
  "history" => -> { [] },
  "settings" => -> { {} },
  "context" => -> { {} },
  "metadata" => -> { {} },
  "model_profiles" => -> { {} }
}.freeze
ACCESSORS =

:nodoc:

%i[
  message history settings context metadata model_profiles
  run_id invocation_id session_id actor_id
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env = {}) ⇒ Invocation

Copies env, normalizes known framework fields, and fills missing identifiers.

The payload must be a Hash and must contain a non-blank message.



50
51
52
53
54
55
56
57
58
# File 'lib/little_ghost/invocation.rb', line 50

def initialize(env = {})
  invalid!("Invocation payload must be an object") unless env.is_a?(Hash)

  @env = env.to_h { |key, value| [normalize_key(key), duplicate_value(value)] }
  DEFAULTS.each { |key, default| @env[key] = default.call unless @env.key?(key) }
  self.history = history
  self.message = message
  initialize_identifiers!
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *arguments) ⇒ Object

:nodoc:



227
228
229
230
231
232
233
234
235
# File 'lib/little_ghost/invocation.rb', line 227

def method_missing(name, *arguments) # :nodoc:
  value = name.to_s
  if value.end_with?("=") && arguments.length == 1
    return self[value.delete_suffix("=")] = arguments.first
  end
  return self[value] if arguments.empty? && key?(value)

  super
end

Instance Attribute Details

#envObject (readonly)

:nodoc:



45
46
47
# File 'lib/little_ghost/invocation.rb', line 45

def env
  @env
end

Instance Method Details

#[](key) ⇒ Object

Looks up key after normalizing it to a String.



176
# File 'lib/little_ghost/invocation.rb', line 176

def [](key) = env[normalize_key(key)]

#[]=(key, value) ⇒ Object

Stores value under a normalized String key.

The message and history fields are normalized before storage.



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

def []=(key, value)
  normalized = normalize_key(key)
  value = normalize_message(value) if normalized == "message"
  value = Array(value).map { |message| Message.coerce(message) }.freeze if normalized == "history"
  env[normalized] = value
end

#deadline_atObject

The request deadline as a Time, parsing ISO 8601 text on first access.



203
204
205
206
207
208
209
210
# File 'lib/little_ghost/invocation.rb', line 203

def deadline_at
  value = self[:deadline_at]
  return value if value.nil? || value.is_a?(Time)

  self[:deadline_at] = Time.iso8601(String(value))
rescue ArgumentError, TypeError
  invalid!("deadline_at must be a valid time")
end

#deadline_at=(value) ⇒ Object

Replaces the deadline; parsing is deferred until deadline_at is read.



213
214
215
# File 'lib/little_ghost/invocation.rb', line 213

def deadline_at=(value)
  self[:deadline_at] = value
end

#dig(key, *names) ⇒ Object

Traverses the environment from normalized key through names.



192
# File 'lib/little_ghost/invocation.rb', line 192

def dig(key, *names) = env.dig(normalize_key(key), *names)

#fetch(key, *defaults, &block) ⇒ Object

Fetches key with the same default and block behavior as Hash#fetch.



189
# File 'lib/little_ghost/invocation.rb', line 189

def fetch(key, *defaults, &block) = env.fetch(normalize_key(key), *defaults, &block)

#history=(value) ⇒ Object

Replaces and freezes the normalized message history.



223
224
225
# File 'lib/little_ghost/invocation.rb', line 223

def history=(value)
  self[:history] = value
end

#key?(key) ⇒ Boolean

Whether the environment contains key after normalization.

Returns:

  • (Boolean)


195
# File 'lib/little_ghost/invocation.rb', line 195

def key?(key) = env.key?(normalize_key(key))

#message=(value) ⇒ Object

Replaces and normalizes the current message.



218
219
220
# File 'lib/little_ghost/invocation.rb', line 218

def message=(value)
  self[:message] = value
end

#nameObject

Replaces the application-established actor identifier. :method: actor_id= :call-seq:

actor_id=(value) -> value


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

ACCESSORS.each do |name|
  define_method(name) { self[name] }
  define_method(:"#{name}=") { |value| self[name] = value } unless %i[message history].include?(name)
end

#respond_to_missing?(name, include_private = false) ⇒ Boolean

:nodoc:

Returns:

  • (Boolean)


237
238
239
240
# File 'lib/little_ghost/invocation.rb', line 237

def respond_to_missing?(name, include_private = false) # :nodoc:
  value = name.to_s
  value.end_with?("=") || key?(value) || super
end

#to_hObject

Produces a mutable copy of the invocation environment.

Nested hashes, arrays, strings, and other duplicable values are copied.



200
# File 'lib/little_ghost/invocation.rb', line 200

def to_h = duplicate_value(env)