Class: LittleGhost::RunContext

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

Overview

RunContext gives tools and workflows one place for shared state, cancellation, deadlines, checkpoints, and accumulated usage. It travels with work inside a run without becoming global process state.

Tools and workflows use it to share JSON-like state, check cancellation and deadlines, checkpoint messages, and accumulate usage. Access to framework-managed fields is thread-safe.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(state: {}, cancellation_token: Support::CancellationToken.new, deadline: nil, metadata: {}, checkpoint: nil, conversation_id: nil, interruption_metadata: nil, interruption_ids: []) ⇒ RunContext

Creates a context with optional checkpoint and interruption state.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/little_ghost/run_context.rb', line 18

def initialize(
  state: {},
  cancellation_token: Support::CancellationToken.new,
  deadline: nil,
  metadata: {},
  checkpoint: nil,
  conversation_id: nil,
  interruption_metadata: nil,
  interruption_ids: []
)
  if conversation_id
    conversation_id = String(conversation_id)
    raise ArgumentError, "conversation_id cannot be empty" if conversation_id.empty?
    conversation_id = conversation_id.dup.freeze
  end
  @state = state
  @cancellation_token = cancellation_token
  @deadline = deadline
  @metadata = .freeze
  @checkpoint = checkpoint
  @conversation_id = conversation_id
  @usage = Usage.new
  @usage_mutex = Mutex.new
  @structured_result = nil
  @structured_result_mutex = Mutex.new
  @agent_operation_id = nil
  @agent_operation_id_mutex = Mutex.new
  @interruption_mutex = Mutex.new
  @interruption_metadata = &.to_h
  @interruption_ids = Array(interruption_ids).map { |id| String(id).dup.freeze }.freeze
end

Instance Attribute Details

#agent_operation_idObject (readonly)

Shared state, cancellation, deadline, metadata, operation identity, and durable conversation identity for the current work.



14
15
16
# File 'lib/little_ghost/run_context.rb', line 14

def agent_operation_id
  @agent_operation_id
end

#cancellation_tokenObject (readonly)

Shared state, cancellation, deadline, metadata, operation identity, and durable conversation identity for the current work.



14
15
16
# File 'lib/little_ghost/run_context.rb', line 14

def cancellation_token
  @cancellation_token
end

#conversation_idObject (readonly)

Shared state, cancellation, deadline, metadata, operation identity, and durable conversation identity for the current work.



14
15
16
# File 'lib/little_ghost/run_context.rb', line 14

def conversation_id
  @conversation_id
end

#deadlineObject (readonly)

Shared state, cancellation, deadline, metadata, operation identity, and durable conversation identity for the current work.



14
15
16
# File 'lib/little_ghost/run_context.rb', line 14

def deadline
  @deadline
end

#metadataObject (readonly)

Shared state, cancellation, deadline, metadata, operation identity, and durable conversation identity for the current work.



14
15
16
# File 'lib/little_ghost/run_context.rb', line 14

def 
  @metadata
end

#stateObject (readonly)

Shared state, cancellation, deadline, metadata, operation identity, and durable conversation identity for the current work.



14
15
16
# File 'lib/little_ghost/run_context.rb', line 14

def state
  @state
end

Instance Method Details

#activate_interruption(metadata:, ids:) ⇒ Object

:nodoc:



110
111
112
113
114
115
116
117
# File 'lib/little_ghost/run_context.rb', line 110

def activate_interruption(metadata:, ids:) # :nodoc:
  value = &.to_h
  values = Array(ids).map { |id| String(id).dup.freeze }.freeze
  @interruption_mutex.synchronize do
    @interruption_metadata = value
    @interruption_ids = values
  end
end

#bind_agent_operation_id(operation_id) ⇒ Object

:nodoc:



119
120
121
122
123
124
125
126
127
# File 'lib/little_ghost/run_context.rb', line 119

def bind_agent_operation_id(operation_id) # :nodoc:
  @agent_operation_id_mutex.synchronize do
    if @agent_operation_id && @agent_operation_id != operation_id
      raise Error, "run context is already bound to an agent operation"
    end

    @agent_operation_id ||= operation_id
  end
end

#check!Object

Raises LittleGhost::CancelledError or LittleGhost::DeadlineExceededError when execution should stop.



52
53
54
55
# File 'lib/little_ghost/run_context.rb', line 52

def check!
  cancellation_token.raise_if_cancelled!
  raise DeadlineExceededError, "The run deadline was reached" if deadline && Time.now >= deadline
end

#checkpoint(messages) ⇒ Object

Sends messages and current state to the configured checkpoint callback. With no checkpoint callback, this method does nothing and returns nil.



59
60
61
62
63
64
65
66
67
# File 'lib/little_ghost/run_context.rb', line 59

def checkpoint(messages)
  return unless @checkpoint

  if agent_operation_id
    @checkpoint.call(messages:, state:, parent_operation_id: agent_operation_id)
  else
    @checkpoint.call(messages:, state:)
  end
end

#interruption_idsObject

:nodoc:



106
107
108
# File 'lib/little_ghost/run_context.rb', line 106

def interruption_ids # :nodoc:
  @interruption_mutex.synchronize { @interruption_ids }
end

#interruption_metadataObject

:nodoc:



102
103
104
# File 'lib/little_ghost/run_context.rb', line 102

def  # :nodoc:
  @interruption_mutex.synchronize { @interruption_metadata }
end

#record_usage(value) ⇒ Object

Adds value to accumulated model usage.



70
71
72
# File 'lib/little_ghost/run_context.rb', line 70

def record_usage(value)
  @usage_mutex.synchronize { @usage += value }
end

#remaining_time(maximum = nil) ⇒ Object

Calculates seconds remaining before the deadline.

When maximum is provided, the result is capped at that value. With no deadline, returns maximum.



83
84
85
86
87
88
89
# File 'lib/little_ghost/run_context.rb', line 83

def remaining_time(maximum = nil)
  check!
  return maximum unless deadline

  remaining = deadline - Time.now
  maximum ? [remaining, maximum].min : remaining
end

#structured_resultObject

Finds the latest validated structured result, if any.



98
99
100
# File 'lib/little_ghost/run_context.rb', line 98

def structured_result
  @structured_result_mutex.synchronize { @structured_result }
end

#submit_structured_result(result) ⇒ Object

Stores a validated LittleGhost::StructuredResult and returns it.



92
93
94
95
# File 'lib/little_ghost/run_context.rb', line 92

def submit_structured_result(result)
  @structured_result_mutex.synchronize { @structured_result = result }
  result
end

#usageObject

Takes a snapshot of accumulated usage.



75
76
77
# File 'lib/little_ghost/run_context.rb', line 75

def usage
  @usage_mutex.synchronize { @usage }
end