phronomy 0.24.1 → 0.25.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb31ae2fdc7b102461fd91480ea2e2aaeda618fb65cc3eb885a9525ca1e985e2
4
- data.tar.gz: 2ede56b656b789ff195561ac72cac5df2f51dba410dbee8e3025437985509e61
3
+ metadata.gz: 636ce578204172927316a89f0f65a2bdfda49140822da98cd1eec9230d821105
4
+ data.tar.gz: 8d776e0ab9bf2775af4e23f77b0b29968a3d4962f8fbd877d3fe9574a3efb306
5
5
  SHA512:
6
- metadata.gz: fe717ea7a31272ad7d7247f214c59ca8c5370a80ce80e67d69d8bb14f5e285d779004545e56f3298e85d63ca7352ba430f2912e967453b899c1181e8d00fb77e
7
- data.tar.gz: e3a45c05b4b8f129e61fa09ae7e23be8916aeae762642f5333fb3876c6d142091d836c8c33d3dcb0a3908d1d1d6d99261bffde3e07d8ad505aa136a0df9f9097
6
+ metadata.gz: 81a2b295d5fb03d4cd03c6f3ceabca7b62f4e635fc5dd6ed3db31b1c5f59c6031fc38958895a1fc7b8e9fc75394a81181d51529ebb86f310e85cd2300a9395af
7
+ data.tar.gz: f701f8fd0be60d655e9676c8cbdfec93606cca20769da90b7c67617c9d876cbde51bf18a42531b7cf70079aa12863af022acd21500fe40cff64c04d5a70df6ab
data/CHANGELOG.md CHANGED
@@ -12,8 +12,18 @@ Release history for 0.14.0 and earlier is archived in
12
12
 
13
13
  ## [Unreleased]
14
14
 
15
+ ---
16
+
17
+ ## [0.25.0] - 2026-09-12
18
+
19
+ ### Added
20
+
21
+ - Public `Task.completed` / `Task.failed` factories for application-owned settled results.
22
+ - `Blocking.call_async` for non-waiting submission of synchronous application work.
23
+
15
24
  ### Fixed
16
25
 
26
+ - Reject waiting OffloadPool admission from EventLoop before creating an operation.
17
27
  - Add runtime dependency constraint `json < 3` to prevent Faraday/RubyLLM JSON
18
28
  parser incompatibilities from resolving in consumer environments.
19
29
 
data/README.md CHANGED
@@ -23,6 +23,8 @@ tracking `main` directly.
23
23
  - **EventLoop + FSMSession** — the framework control plane for logical lifecycle coordination.
24
24
  - **OffloadPool** — bounded operating-system-thread execution boundary for synchronous work that must not run on EventLoop.
25
25
  - **Task** — the common thread-free completion handle returned by Phronomy asynchronous APIs, including OffloadPool-backed work.
26
+ - **Task.completed / Task.failed** — already-settled application results without starting execution.
27
+ - **Blocking.call_async** — submits synchronous application work to the existing bounded OffloadPool without waiting for queue space.
26
28
  - **Journal / Context Policy / Manifest** — canonical history plus per-LLM-call context selection.
27
29
 
28
30
  See [Features and Application Programming Interface (API) stability](docs/features.md) for the full feature matrix.
data/docs/features.md CHANGED
@@ -66,6 +66,8 @@ rather than implicitly inheriting the parent revision. The Stable
66
66
  | **`stream_callback_error_policy`** — Terminal event callback error policy (`:report` / `:fail_task`) | Beta |
67
67
  | **Task completion contract** — `Task` is the common caller-facing completion handle for EventLoop/FSMSession lifecycles and OffloadPool work | Beta |
68
68
  | **`Task#map`** — Application-level Task result transformation and error propagation | Stable |
69
+ | **Settled Task factories** — Public `Task.completed` / `Task.failed` represent already available application results without starting execution | Beta |
70
+ | **Blocking.call_async** — Public non-waiting admission of synchronous application work to the existing OffloadPool, returning a Task | Beta |
69
71
  | **CancellationToken** — Cooperative cancellation with explicit `cancel!`, lazy monotonic deadlines, and callback registration | Experimental |
70
72
  | **Tool `execution_mode`** — `:cooperative` for short EventLoop-safe work; `:offloaded` for synchronous work that must stay off EventLoop | Experimental |
71
73
  | **OffloadPool sizing** — `offload_pool_size` / `offload_queue_size`; named pools available for application-owned isolation | Beta |
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phronomy
4
+ # Public adapter for synchronous application I/O or computation.
5
+ # This uses the existing bounded OffloadPool. It does not execute logical
6
+ # waits, persist work, force-stop a running block, or create a scheduler.
7
+ module Blocking
8
+ # Submits synchronous application work to the default Runtime OffloadPool.
9
+ # Admission never waits for queue space. Admission StandardError failures
10
+ # become failed Tasks; accepted work retains the pool's Task unchanged.
11
+ # A timeout/cancellation can settle that Task before a running worker exits.
12
+ # The block must not wait for another Agent, Workflow, or Task.
13
+ # @param timeout [Numeric, nil] operation deadline, including queue time
14
+ # @param cancellation_token [Phronomy::Concurrency::CancellationToken, nil]
15
+ # @yield synchronous application work
16
+ # @return [Phronomy::Task] original accepted Task or failed admission Task
17
+ # @raise [ArgumentError] if no block is supplied
18
+ # @api public
19
+ def self.call_async(timeout: nil, cancellation_token: nil, &block)
20
+ raise ArgumentError, "Blocking.call_async requires a block" unless block
21
+
22
+ begin
23
+ Phronomy::Runtime.instance.offload.submit(
24
+ on_full: :raise,
25
+ timeout: timeout,
26
+ cancellation_token: cancellation_token,
27
+ &block
28
+ )
29
+ rescue => error
30
+ Phronomy::Task.failed(error, name: "blocking-admission-failed")
31
+ end
32
+ end
33
+ end
34
+ end
@@ -347,6 +347,9 @@ module Phronomy
347
347
  # Synchronous queue admission may delay return from this method when
348
348
  # +on_full: :wait+ is used. EventLoop-owned framework paths therefore submit
349
349
  # with +on_full: :raise+ and handle backpressure asynchronously.
350
+ # EventLoop callers requesting a waiting policy are rejected before any
351
+ # operation, timer, or cancellation subscription is created. Application
352
+ # code should use Phronomy::Blocking.call_async.
350
353
  #
351
354
  # @param timeout [Numeric, nil] operation-wide deadline in seconds
352
355
  # @param cancellation_token [CancellationToken, nil] operation-wide token
@@ -359,6 +362,7 @@ module Phronomy
359
362
  # @raise [Phronomy::PoolShutdownError] when the pool has been shut down
360
363
  # @raise [Phronomy::BackpressureError] when +on_full: :raise+ and queue is full
361
364
  # @raise [Phronomy::TimeoutError] when +on_full: :timeout+ exceeds +full_timeout+
365
+ # @raise [Phronomy::EventLoopReentrancyError] for waiting admission on EventLoop
362
366
  # @api private
363
367
  def submit(
364
368
  timeout: nil,
@@ -367,6 +371,10 @@ module Phronomy
367
371
  full_timeout: nil,
368
372
  &block
369
373
  )
374
+ if Phronomy::Runtime.in_event_loop_context? && on_full != :raise
375
+ raise Phronomy::EventLoopReentrancyError,
376
+ "OffloadPool admission cannot wait on EventLoop; use on_full: :raise"
377
+ end
370
378
  raise Phronomy::PoolShutdownError, "pool has been shut down" if @shutdown
371
379
 
372
380
  submitted_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@@ -23,6 +23,29 @@ module Phronomy
23
23
  new(name: name, parent: parent)
24
24
  end
25
25
 
26
+ # Public factories for already-settled values. No execution is started.
27
+ # Always create a base Task: there is no physical worker to supervise.
28
+ # @param value [Object] already available result
29
+ # @param name [String, nil] optional diagnostic name
30
+ # @return [Phronomy::Task] a completed base Task
31
+ # @api public
32
+ def self.completed(value = nil, name: nil)
33
+ Phronomy::Task.deferred(name: name).tap { |task| task.complete(value) }
34
+ end
35
+
36
+ # Represents an already known failure without raising the stored error.
37
+ # Observation through wait_result raises it; on_complete receives it.
38
+ # @param error [Exception] original failure object
39
+ # @param name [String, nil] optional diagnostic name
40
+ # @return [Phronomy::Task] a failed base Task
41
+ # @raise [ArgumentError] if error is not an Exception
42
+ # @api public
43
+ def self.failed(error, name: nil)
44
+ raise ArgumentError, "error must be an Exception" unless error.is_a?(Exception)
45
+
46
+ Phronomy::Task.deferred(name: name).tap { |task| task.fail(error) }
47
+ end
48
+
26
49
  attr_reader :name, :parent
27
50
 
28
51
  # @api private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Phronomy
4
- VERSION = "0.24.1"
4
+ VERSION = "0.25.0"
5
5
  end
@@ -1,5 +1,8 @@
1
1
  module Phronomy
2
2
  class Task[A]
3
+ def self.completed: [V] (V value, ?name: String?) -> Task[V]
4
+ | (?name: String?) -> Task[nil]
5
+ def self.failed: (Exception error, ?name: String?) -> Task[untyped]
3
6
  attr_reader name: String?
4
7
  attr_reader parent: Task[untyped]?
5
8
 
@@ -38,3 +41,9 @@ module Phronomy
38
41
  def initialize: (?user_id: String?, ?cancellation_token: Concurrency::CancellationToken?, ?deadline: untyped, ?token_budget: Integer?, ?approval_policy: untyped, ?redaction_policy: untyped, ?task_id: String?, ?parent_task_id: String?) -> void
39
42
  end
40
43
  end
44
+
45
+ module Phronomy
46
+ module Blocking
47
+ def self.call_async: [V] (?timeout: Numeric?, ?cancellation_token: Concurrency::CancellationToken?) { () -> V } -> Task[V]
48
+ end
49
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phronomy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.24.1
4
+ version: 0.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Raizo T.C.S
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-07 00:00:00.000000000 Z
11
+ date: 2026-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby_llm
@@ -252,6 +252,7 @@ files:
252
252
  - lib/phronomy/agent_already_exists_error.rb
253
253
  - lib/phronomy/agent_busy_error.rb
254
254
  - lib/phronomy/agent_purged_error.rb
255
+ - lib/phronomy/blocking.rb
255
256
  - lib/phronomy/canonical_json.rb
256
257
  - lib/phronomy/configuration.rb
257
258
  - lib/phronomy/content_store/base.rb