phronomy 0.16.0 → 0.17.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.
- checksums.yaml +4 -4
- data/.mutant.yml +8 -9
- data/CHANGELOG.md +54 -0
- data/CONTRIBUTING.md +28 -16
- data/README.md +124 -92
- data/benchmark/baseline.json +2 -3
- data/benchmark/bench_agent_invoke.rb +4 -4
- data/benchmark/bench_context_assembler.rb +134 -34
- data/benchmark/bench_regression.rb +1 -1
- data/benchmark/bench_tool_schema.rb +2 -35
- data/docs/decisions/005-static-knowledge-class-level-cache.md +12 -1
- data/docs/decisions/010-cooperative-first-concurrency.md +7 -0
- data/docs/decisions/011-build-context-as-single-llm-input-authority.md +2 -2
- data/docs/decisions/013-journal-backed-knowledge-as-context-candidates.md +122 -0
- data/lib/phronomy/agent/agent_invocation.rb +2 -36
- data/lib/phronomy/agent/agent_invocation_session_builder.rb +156 -93
- data/lib/phronomy/agent/agent_root.rb +1 -2
- data/lib/phronomy/agent/base.rb +135 -314
- data/lib/phronomy/agent/context/capability/base.rb +166 -297
- data/lib/phronomy/agent/context_assembler.rb +65 -29
- data/lib/phronomy/agent/context_parts/unit_builders/dependency_aware_unit_builder.rb +19 -89
- data/lib/phronomy/agent/context_plan_validator.rb +0 -33
- data/lib/phronomy/agent/execution_coordinator.rb +0 -1
- data/lib/phronomy/agent/journal_projection.rb +28 -2
- data/lib/phronomy/agent/ruby_llm_materializer.rb +2 -111
- data/lib/phronomy/agent/shared_state.rb +46 -138
- data/lib/phronomy/agent/token_budget_resolver.rb +5 -4
- data/lib/phronomy/agent/tool_invocation.rb +108 -314
- data/lib/phronomy/agent.rb +6 -10
- data/lib/phronomy/configuration.rb +15 -158
- data/lib/phronomy/engine/concurrency/cancellation_token.rb +7 -80
- data/lib/phronomy/engine/runtime.rb +15 -230
- data/lib/phronomy/engine/task_group.rb +30 -102
- data/lib/phronomy/llm_context_window/token_budget.rb +8 -79
- data/lib/phronomy/multi_agent/orchestrator.rb +152 -204
- data/lib/phronomy/multi_agent/team_coordinator.rb +42 -133
- data/lib/phronomy/vector_store/in_memory.rb +2 -2
- data/lib/phronomy/version.rb +1 -1
- data/lib/phronomy.rb +3 -120
- data/scripts/api_snapshot.rb +1 -12
- metadata +3 -9
- data/lib/phronomy/agent/context/knowledge/base.rb +0 -58
- data/lib/phronomy/agent/context/knowledge/entity_knowledge.rb +0 -102
- data/lib/phronomy/agent/context/knowledge/static_knowledge.rb +0 -58
- data/lib/phronomy/agent/fsm_runtime_adapter.rb +0 -210
- data/lib/phronomy/knowledge_source.rb +0 -12
- data/lib/phronomy/llm_context_window/assembler.rb +0 -191
- data/lib/phronomy/llm_context_window/context_version_cache.rb +0 -52
|
@@ -3,191 +3,36 @@
|
|
|
3
3
|
module Phronomy
|
|
4
4
|
# Holds global configuration for the entire framework.
|
|
5
5
|
# Configure via the Phronomy.configure block.
|
|
6
|
-
#
|
|
7
|
-
# @example
|
|
8
|
-
# Phronomy.configure do |config|
|
|
9
|
-
# config.default_model = "claude-3-5-sonnet-20241022"
|
|
10
|
-
# config.recursion_limit = 50
|
|
11
|
-
# end
|
|
12
6
|
class Configuration
|
|
13
7
|
STREAM_CALLBACK_ERROR_POLICIES = %i[report fail_task].freeze
|
|
14
|
-
|
|
8
|
+
RUNTIME_BACKENDS = %i[thread immediate fiber].freeze
|
|
9
|
+
private_constant :STREAM_CALLBACK_ERROR_POLICIES, :RUNTIME_BACKENDS
|
|
15
10
|
|
|
16
|
-
# Default LLM model name (nil delegates to RubyLLM default)
|
|
17
11
|
attr_accessor :default_model
|
|
18
|
-
|
|
19
|
-
# Default embedding model name
|
|
20
12
|
attr_accessor :default_embedding_model
|
|
21
|
-
|
|
22
|
-
# Tracer instance
|
|
23
13
|
attr_accessor :tracer
|
|
24
|
-
|
|
25
|
-
# Global before_llm_input hook callable (Proc / lambda).
|
|
26
|
-
# Called before every LLM request across all agents.
|
|
27
|
-
# Receives a {Phronomy::Agent::LLMInputBuildContext}; must return a
|
|
28
|
-
# {Phronomy::Agent::LLMInputPatch} or nil to pass through unchanged.
|
|
29
14
|
attr_accessor :before_llm_input
|
|
30
|
-
|
|
31
|
-
# Default output token reservation when an agent does not set max_output_tokens
|
|
32
|
-
# and the model registry value equals the context window (making it unusable
|
|
33
|
-
# as a per-request output reserve). Integer or nil.
|
|
34
15
|
attr_accessor :default_output_reserve
|
|
35
|
-
|
|
36
|
-
# Recursion limit for graph execution (default: 25)
|
|
37
16
|
attr_accessor :recursion_limit
|
|
38
|
-
|
|
39
|
-
# When true, agent LLM calls use {Phronomy::MultiAgent::ParallelToolChat}
|
|
40
|
-
# for concurrent tool dispatch within a single agent turn.
|
|
41
|
-
# Defaults to false.
|
|
42
|
-
#
|
|
43
|
-
# Previously, this was automatically enabled when +event_loop+ was true.
|
|
44
|
-
# As of Phase 3, +parallel_tool_execution+ is a separate setting that must
|
|
45
|
-
# be explicitly enabled.
|
|
46
|
-
# @example
|
|
47
|
-
# Phronomy.configure { |c| c.parallel_tool_execution = true }
|
|
48
|
-
# @return [Boolean]
|
|
49
17
|
attr_accessor :parallel_tool_execution
|
|
50
|
-
|
|
51
|
-
# When true, user input and LLM output are recorded in trace spans.
|
|
52
|
-
# Defaults to false; set to true only in environments where PII capture is acceptable.
|
|
53
|
-
# Set to false in privacy-sensitive environments to prevent PII from reaching
|
|
54
|
-
# the tracing backend (OTel, Langfuse, etc.).
|
|
55
18
|
attr_accessor :trace_pii
|
|
56
|
-
|
|
57
|
-
# Optional logger for framework diagnostic messages (e.g. unreachable-state warnings).
|
|
58
|
-
# Must respond to +#warn(message)+. When nil (default), messages are written to +$stderr+
|
|
59
|
-
# via +Kernel#warn+.
|
|
60
|
-
# @example
|
|
61
|
-
# Phronomy.configure { |c| c.logger = Rails.logger }
|
|
62
19
|
attr_accessor :logger
|
|
63
|
-
|
|
64
|
-
# Grace period (in seconds) before the EventLoop background thread is force-killed
|
|
65
|
-
# after a cooperative stop request. Applies both to the overall thread join
|
|
66
|
-
# and to the drain-and-cancel phase when +stop(drain: true)+ is used.
|
|
67
|
-
# Default: 5 seconds.
|
|
68
|
-
# @see Phronomy::EventLoop#stop
|
|
69
20
|
attr_accessor :event_loop_stop_grace_seconds
|
|
70
|
-
|
|
71
|
-
# Global state store for workflow persistence.
|
|
72
|
-
# When set, WorkflowRunner routes all state reads and writes through this store.
|
|
73
|
-
# Must be an instance of a class that inherits from Phronomy::StateStore::Base.
|
|
74
|
-
# Defaults to +nil+ (no persistence — state lives only for the duration of invoke).
|
|
75
|
-
# @example
|
|
76
|
-
# Phronomy.configure { |c| c.state_store = Phronomy::StateStore::InMemory.new }
|
|
77
21
|
attr_accessor :state_store
|
|
78
|
-
|
|
79
|
-
# Maximum byte length of a tool result returned to the LLM.
|
|
80
|
-
# When a tool returns a String longer than this limit, the string is truncated
|
|
81
|
-
# and a warning is logged. Set to +nil+ (default) to disable truncation.
|
|
82
|
-
# @example
|
|
83
|
-
# Phronomy.configure { |c| c.tool_result_max_size = 8192 }
|
|
84
22
|
attr_accessor :tool_result_max_size
|
|
85
|
-
|
|
86
|
-
# LLM adapter used by Agent::Base to perform LLM calls.
|
|
87
|
-
# Must be an instance of a class that inherits from
|
|
88
|
-
# {Phronomy::LLMAdapter::Base}. Defaults to
|
|
89
|
-
# {Phronomy::LLMAdapter::RubyLLM} which delegates to +chat.ask+ via
|
|
90
|
-
# {BlockingAdapterPool}.
|
|
91
|
-
# Set to a custom adapter to swap in an alternative LLM client without
|
|
92
|
-
# changing any agent code.
|
|
93
|
-
# @example
|
|
94
|
-
# Phronomy.configure { |c| c.llm_adapter = MyAsyncLLMAdapter.new }
|
|
95
23
|
attr_accessor :llm_adapter
|
|
96
|
-
|
|
97
|
-
# Set to +nil+ to disable the warning.
|
|
98
|
-
# @return [Numeric, nil]
|
|
99
24
|
attr_accessor :event_loop_starvation_threshold_seconds
|
|
100
|
-
|
|
101
|
-
# Warn when processing a single event on the EventLoop thread takes longer
|
|
102
|
-
# than this many seconds (long-running task / blocking-on-loop detection).
|
|
103
|
-
# Set to +nil+ to disable the warning.
|
|
104
|
-
# @return [Numeric, nil]
|
|
105
25
|
attr_accessor :event_loop_dispatch_threshold_seconds
|
|
106
|
-
|
|
107
|
-
# When true, enables all blocking operation diagnostics (Issue #279).
|
|
108
|
-
# Equivalent to setting all diagnostic thresholds to their defaults.
|
|
109
|
-
# @return [Boolean]
|
|
110
26
|
attr_accessor :scheduler_debug
|
|
111
|
-
|
|
112
|
-
# Wall-clock threshold (milliseconds) after which a task that has not
|
|
113
|
-
# yielded the scheduler emits a warning log. nil disables the check.
|
|
114
|
-
# @return [Float, nil]
|
|
115
27
|
attr_accessor :blocking_detect_threshold_ms
|
|
116
|
-
|
|
117
|
-
# Determines how an unhandled Application exception from a terminal stream
|
|
118
|
-
# callback affects the Task returned by Agent#stream_async or
|
|
119
|
-
# Agent#approve_async.
|
|
120
|
-
#
|
|
121
|
-
# +:report+ logs the callback failure and preserves the Agent result.
|
|
122
|
-
# +:fail_task+ logs the callback failure and fails the current Task with
|
|
123
|
-
# {Phronomy::StreamCallbackError}. Neither policy terminates EventLoop.
|
|
124
|
-
#
|
|
125
|
-
# Default: +:report+.
|
|
126
|
-
# @return [:report, :fail_task]
|
|
127
28
|
attr_reader :stream_callback_error_policy
|
|
128
|
-
|
|
129
|
-
# Number of OS worker threads in the default {BlockingAdapterPool}.
|
|
130
|
-
# All LLM calls, MCP tool calls, and other blocking I/O share this pool.
|
|
131
|
-
# Increase for higher LLM/tool throughput; decrease to limit
|
|
132
|
-
# concurrency (e.g. to stay within a provider's rate limit).
|
|
133
|
-
# Default: 10.
|
|
134
|
-
# @return [Integer]
|
|
135
29
|
attr_accessor :blocking_io_pool_size
|
|
136
|
-
|
|
137
|
-
# Maximum number of operations that may wait in the {BlockingAdapterPool}
|
|
138
|
-
# queue before {Phronomy::BackpressureError} is raised (on_full: :raise) or
|
|
139
|
-
# the caller blocks (on_full: :wait, the default). Default: 100.
|
|
140
|
-
# @return [Integer]
|
|
141
30
|
attr_accessor :blocking_io_queue_size
|
|
142
|
-
|
|
143
|
-
# Worker count for Tool authorization evaluation. The named pool is owned
|
|
144
|
-
# by Runtime#pool(:authorization) and shares PoolRegistry lifecycle.
|
|
145
|
-
# @return [Integer]
|
|
146
31
|
attr_accessor :authorization_pool_size
|
|
147
|
-
|
|
148
|
-
# Maximum queued Tool authorization evaluations.
|
|
149
|
-
# @return [Integer]
|
|
150
32
|
attr_accessor :authorization_queue_size
|
|
151
|
-
|
|
152
|
-
# Operation-wide deadline for approval_facts, requires_approval callables,
|
|
153
|
-
# and Agent#tool_approval_policy. Timeout fails closed to Human approval.
|
|
154
|
-
# @return [Numeric]
|
|
155
33
|
attr_accessor :authorization_timeout
|
|
156
|
-
|
|
157
|
-
# Scheduler starvation threshold (milliseconds).
|
|
158
|
-
# When a task waits more than this many milliseconds after calling
|
|
159
|
-
# +runtime.yield+ before being resumed, the wait is counted as a starvation
|
|
160
|
-
# event. Used by the fairness regression test and by the
|
|
161
|
-
# +tasks_waiting_over_threshold+ metric on {Phronomy::Runtime}.
|
|
162
|
-
# Default: 50ms.
|
|
163
|
-
# @return [Numeric]
|
|
164
34
|
attr_accessor :starvation_threshold_ms
|
|
165
|
-
|
|
166
|
-
# Scheduler backend to use for new {Phronomy::Runtime} instances.
|
|
167
|
-
#
|
|
168
|
-
# | Value | Scheduler | Typical use |
|
|
169
|
-
# |-------|-----------|-------------|
|
|
170
|
-
# | +:thread+ | {Runtime::ThreadScheduler} | **Default** — production-ready; one OS thread per task |
|
|
171
|
-
# | +:immediate+ | {Runtime::FakeScheduler} | Tests — tasks run synchronously, no extra threads |
|
|
172
|
-
# | +:fiber+ | {Runtime::DeterministicScheduler} (autorun) | **EXPERIMENTAL** — Fiber-based cooperative scheduler; do not use as production default |
|
|
173
|
-
# | +:cooperative+ | {Runtime::FakeScheduler} | **Deprecated** — alias for +:immediate+; do not use in new code |
|
|
174
|
-
#
|
|
175
|
-
# The default is +:thread+. The +:fiber+ backend remains experimental and opt-in;
|
|
176
|
-
# it will not become the default until integration test coverage is production grade
|
|
177
|
-
# and virtual-time/timeout semantics are fully resolved (see Issues #350, #347, #348).
|
|
178
|
-
#
|
|
179
|
-
# When this setting is changed, the change only takes effect on the NEXT
|
|
180
|
-
# call to {Runtime.instance} that auto-creates a new instance (i.e. after the
|
|
181
|
-
# previous instance has been replaced or reset). To replace the current
|
|
182
|
-
# instance immediately call +Phronomy::Runtime.instance = nil+ first.
|
|
183
|
-
#
|
|
184
|
-
# @return [:thread, :immediate, :fiber]
|
|
185
|
-
attr_accessor :runtime_backend
|
|
186
|
-
|
|
187
|
-
# When +true+, calling {Agent#invoke} from inside a scheduler task
|
|
188
|
-
# raises {SchedulerReentrancyError}. When +false+ (default), a warning
|
|
189
|
-
# is logged instead so that existing callers have time to migrate.
|
|
190
|
-
# @return [Boolean]
|
|
35
|
+
attr_reader :runtime_backend
|
|
191
36
|
attr_accessor :strict_runtime_guards
|
|
192
37
|
|
|
193
38
|
def stream_callback_error_policy=(value)
|
|
@@ -200,6 +45,18 @@ module Phronomy
|
|
|
200
45
|
@stream_callback_error_policy = value
|
|
201
46
|
end
|
|
202
47
|
|
|
48
|
+
# Scheduler backend used for newly-created Runtime instances.
|
|
49
|
+
# Supported values are :thread, :immediate, and :fiber.
|
|
50
|
+
def runtime_backend=(value)
|
|
51
|
+
value = value.to_sym if value.respond_to?(:to_sym)
|
|
52
|
+
unless RUNTIME_BACKENDS.include?(value)
|
|
53
|
+
allowed = RUNTIME_BACKENDS.map(&:inspect).join(", ")
|
|
54
|
+
raise Phronomy::ConfigurationError,
|
|
55
|
+
"runtime_backend must be one of: #{allowed}"
|
|
56
|
+
end
|
|
57
|
+
@runtime_backend = value
|
|
58
|
+
end
|
|
59
|
+
|
|
203
60
|
def initialize
|
|
204
61
|
@recursion_limit = 25
|
|
205
62
|
@tracer = Phronomy::Tracing::NullTracer.new
|
|
@@ -2,90 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
module Phronomy
|
|
4
4
|
module Concurrency
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# Pass a token to an agent via +config: { cancellation_token: token }+.
|
|
8
|
-
# The agent checks the token before each LLM call and raises
|
|
9
|
-
# {Phronomy::CancellationError} when the token is cancelled or the
|
|
10
|
-
# optional deadline has passed.
|
|
11
|
-
#
|
|
12
|
-
# A token may be shared across multiple agent invocations and across threads;
|
|
13
|
-
# all access to internal state is protected by a Mutex.
|
|
14
|
-
#
|
|
15
|
-
# @example Explicit cancel from another thread
|
|
16
|
-
# token = Phronomy::Concurrency::CancellationToken.new
|
|
17
|
-
# Thread.new { sleep 5; token.cancel! }
|
|
18
|
-
# result = agent.invoke("...", config: { cancellation_token: token })
|
|
19
|
-
#
|
|
20
|
-
# @example Hard deadline via monotonic clock (recommended)
|
|
21
|
-
# token = Phronomy::Concurrency::CancellationToken.timeout_after(30)
|
|
22
|
-
# result = agent.invoke("...", config: { cancellation_token: token })
|
|
23
|
-
#
|
|
24
|
-
# @example Hard deadline via wall-clock (legacy)
|
|
25
|
-
# token = Phronomy::Concurrency::CancellationToken.new(deadline: Time.now + 30)
|
|
26
|
-
# result = agent.invoke("...", config: { cancellation_token: token })
|
|
27
|
-
#
|
|
28
|
-
# @example Propagate to parallel workers
|
|
29
|
-
# token = Phronomy::Concurrency::CancellationToken.new
|
|
30
|
-
# orchestrator.dispatch_parallel(task1, task2, cancellation_token: token)
|
|
5
|
+
# Cooperative cancellation token for Agent/Tool work.
|
|
31
6
|
class CancellationToken
|
|
32
|
-
#
|
|
33
|
-
# with the monotonic clock (+Process::CLOCK_MONOTONIC+). Unlike constructing
|
|
34
|
-
# a token with +deadline: Time.now + seconds+, this factory is immune to NTP
|
|
35
|
-
# adjustments and DST transitions.
|
|
36
|
-
#
|
|
37
|
-
# @param seconds [Numeric] duration in seconds until the token expires.
|
|
38
|
-
# @return [CancellationToken]
|
|
7
|
+
# Creates a token that expires after +seconds+ measured with the monotonic clock.
|
|
39
8
|
# @api public
|
|
40
9
|
def self.timeout_after(seconds)
|
|
41
10
|
monotonic_deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + seconds
|
|
42
11
|
new(monotonic_deadline: monotonic_deadline)
|
|
43
12
|
end
|
|
44
13
|
|
|
45
|
-
# @param
|
|
46
|
-
# +cancelled?+ as +true+ once +Time.now >= deadline+. Prefer
|
|
47
|
-
# {.timeout_after} for duration-based cancellation.
|
|
48
|
-
# @param monotonic_deadline [Float, nil] internal monotonic timestamp set by
|
|
49
|
-
# {.timeout_after}; prefer that factory method over passing this directly.
|
|
14
|
+
# @param monotonic_deadline [Float, nil] internal monotonic timestamp.
|
|
50
15
|
# @api public
|
|
51
|
-
|
|
52
|
-
def initialize(deadline: nil, monotonic_deadline: nil)
|
|
16
|
+
def initialize(monotonic_deadline: nil)
|
|
53
17
|
@cancelled = false
|
|
54
|
-
@deadline = deadline
|
|
55
18
|
@monotonic_deadline = monotonic_deadline
|
|
56
19
|
@mutex = Mutex.new
|
|
57
20
|
@cancel_callbacks = []
|
|
58
21
|
end
|
|
59
22
|
|
|
60
|
-
# @return [Time, nil] the wall-clock deadline passed to {#initialize}, or +nil+.
|
|
61
|
-
attr_reader :deadline
|
|
62
|
-
|
|
63
|
-
# Returns the remaining seconds until the monotonic deadline fires, or +nil+
|
|
64
|
-
# when no monotonic deadline is set. Returns 0.0 if already past.
|
|
65
|
-
# @return [Float, nil]
|
|
66
23
|
# @api public
|
|
67
24
|
def remaining_monotonic_seconds
|
|
68
25
|
return nil if @monotonic_deadline.nil?
|
|
26
|
+
|
|
69
27
|
remaining = @monotonic_deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
70
28
|
[remaining, 0.0].max
|
|
71
29
|
end
|
|
72
30
|
|
|
73
|
-
# Registers a one-shot callback invoked when this token is explicitly
|
|
74
|
-
# cancelled via {#cancel!}. If the token is already cancelled, the block
|
|
75
|
-
# is called immediately (still within the caller's thread).
|
|
76
|
-
#
|
|
77
|
-
# Callbacks are NOT fired for deadline-based cancellation (i.e. when
|
|
78
|
-
# {#cancelled?} returns +true+ due to +@monotonic_deadline+ expiry). Use
|
|
79
|
-
# {Phronomy::Concurrency::CancellationScope#deadline_in}, which registers
|
|
80
|
-
# a timer via {Runtime#timer_queue} and calls {#cancel!} on expiry — this
|
|
81
|
-
# fires all +on_cancel+ callbacks automatically. {.timeout_after} is a
|
|
82
|
-
# lightweight alternative that uses lazy clock comparison only and does
|
|
83
|
-
# NOT trigger callbacks on expiry.
|
|
84
|
-
#
|
|
85
|
-
# @yield called with no arguments when (or if) the token is cancelled
|
|
86
|
-
# @return [self]
|
|
87
31
|
# @api public
|
|
88
|
-
# mutant:disable - mutex removal mutation is GVL-safe equivalent under MRI
|
|
89
32
|
def on_cancel(&block)
|
|
90
33
|
already_cancelled = @mutex.synchronize do
|
|
91
34
|
if @cancelled
|
|
@@ -99,14 +42,11 @@ module Phronomy
|
|
|
99
42
|
self
|
|
100
43
|
end
|
|
101
44
|
|
|
102
|
-
# Mark the token as cancelled and fire any registered {#on_cancel} callbacks.
|
|
103
|
-
# Thread-safe; idempotent — calling multiple times has no additional effect.
|
|
104
|
-
# @return [self]
|
|
105
45
|
# @api public
|
|
106
|
-
# mutant:disable - mutex removal and dup-vs-ref mutations are GVL-safe equivalents
|
|
107
46
|
def cancel!
|
|
108
47
|
callbacks = @mutex.synchronize do
|
|
109
48
|
return self if @cancelled
|
|
49
|
+
|
|
110
50
|
@cancelled = true
|
|
111
51
|
@cancel_callbacks.dup
|
|
112
52
|
end
|
|
@@ -114,28 +54,15 @@ module Phronomy
|
|
|
114
54
|
self
|
|
115
55
|
end
|
|
116
56
|
|
|
117
|
-
# Returns +true+ when the token has been explicitly cancelled via {#cancel!},
|
|
118
|
-
# when the wall-clock deadline has passed, or when the monotonic deadline
|
|
119
|
-
# (set by {.timeout_after}) has elapsed. Thread-safe.
|
|
120
|
-
# @return [Boolean]
|
|
121
57
|
# @api public
|
|
122
|
-
# mutant:disable - mutex removal on @cancelled read is GVL-safe equivalent under MRI
|
|
123
58
|
def cancelled?
|
|
124
59
|
return true if @mutex.synchronize { @cancelled }
|
|
125
|
-
|
|
60
|
+
|
|
126
61
|
!@monotonic_deadline.nil? &&
|
|
127
62
|
Process.clock_gettime(Process::CLOCK_MONOTONIC) >= @monotonic_deadline
|
|
128
63
|
end
|
|
129
64
|
|
|
130
|
-
# Raises {Phronomy::CancellationError} if the token is cancelled.
|
|
131
|
-
# A convenience method for cooperative cancellation checks inside tools,
|
|
132
|
-
# RAG loaders, and hooks, replacing the +if cancelled? then raise+ pattern.
|
|
133
|
-
#
|
|
134
|
-
# @param message [String] optional error message
|
|
135
|
-
# @return [nil] when the token is not cancelled
|
|
136
|
-
# @raise [Phronomy::CancellationError] when the token is cancelled
|
|
137
65
|
# @api public
|
|
138
|
-
# mutant:disable - raise(CancellationError) resolves to raise(Phronomy::CancellationError) in this namespace
|
|
139
66
|
def raise_if_cancelled!(message = "invocation cancelled")
|
|
140
67
|
raise Phronomy::CancellationError, message if cancelled?
|
|
141
68
|
end
|