pi-agent-rb 0.2.0 → 0.2.2

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: 24f258d02d946aa8752944f4438581126665c94b5ee1253e61c8ebd16ecb6596
4
- data.tar.gz: f98727ad546acbc6ea8dee3e2cf52af1cf7694f3875181fdec16c3773fd2e0b7
3
+ metadata.gz: db7831746ed3cbbd46e215293bb6a6e34dff2e31915b47a733737aa91ae15e4b
4
+ data.tar.gz: 61af774b3c9125f05aa4cfcafe11e5af31459a7db8a796487ed8857f5b677c1c
5
5
  SHA512:
6
- metadata.gz: 32e5f3a97a2f6b890a1f1c8aecdd59125a4588b6879e815471ad2257942d291a6ccc5c46d32e4bd04abe13020e8ccb4cde1643dfb9230bea9e7974bb8008513f
7
- data.tar.gz: '099b2a2267bd8a7212c6d90473775d54a22e7d80982471682ae339cd01875383561bd77364f9f9fe54c8a9514ae26023811ec24a8bcbe1b2dd035f1412f30377'
6
+ metadata.gz: cb4424e7698e4481dbda464cd5df382a3a555316ee923d5ca5d55faf9692701b606932d753e13ebf5dacf94c878868c7455e401786e1b5667f0d8daaccbf5c15
7
+ data.tar.gz: ccc703e5e81c2bf3ff3b47fa2605a391eeea66e9f1cee7603fba83db2e74f948a7c4b14b90db79ade99a5d8024513619c8764595a9d9456a8af6ede8b34815d1
data/CHANGELOG.md CHANGED
@@ -7,6 +7,84 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.2] - 2026-07-30
11
+
12
+ ### Added
13
+ - Added the optional `on_extension_ui_error` callback to `PiAgent.open`,
14
+ `PiAgent.session`, and `PiAgent::Client`. Applications can now observe an
15
+ Extension UI handler exception together with its request while the dialog
16
+ still fails closed as cancelled. Exceptions raised by the observer are also
17
+ isolated so they cannot prevent the cancellation response.
18
+
19
+ ### Changed
20
+ - Bumped pinned upstream `pi-coding-agent` version to `0.83.0` (from
21
+ `0.82.1`). This is a CLI/provider/extension batch; none of the changes
22
+ alter the JSONL RPC command/response shapes this gem drives, so no gem
23
+ API change is required.
24
+ - Adds `pi auth print-api-key` and `pi auth print-bearer-token` for
25
+ exporting configured credentials to external clients, with automatic
26
+ OAuth refresh and configurable minimum token validity. These are CLI
27
+ subcommands, outside the RPC surface this gem speaks.
28
+ - Adds headless OpenRouter sign-in (paste the redirect URL or
29
+ authorization code when the loopback callback is unavailable) and
30
+ Claude Opus 5 on GitHub Copilot with adaptive thinking and a 1M
31
+ context window. Both are provider/`/login` concerns.
32
+ - Exposes the session's resolved model scope as `ctx.scopedModels` to
33
+ extensions, adds a `"pending"` stop reason for partial streaming
34
+ messages, and surfaces raw provider stop reasons across Google,
35
+ Anthropic, Bedrock, Mistral, and OpenAI (unmapped terminal reasons now
36
+ surface as provider errors). These are SDK/extension and
37
+ provider-stream concerns; RPC event payloads still flow through
38
+ `PiAgent::Event` transparently.
39
+ - **Breaking for TypeScript extensions only:** upstream upgraded bundled
40
+ TypeBox aliases to 1.3.7, removing deprecated APIs (`Type.Base`,
41
+ `Type.Awaited`, `Type.Promise`, `Type.AsyncIterator`, `Type.Iterator`,
42
+ `Type.Options`, `Value.Mutate`) and fixing nullable-array tool-argument
43
+ validation. This does not affect this Ruby gem, which does not author
44
+ TypeBox schemas.
45
+ - The remainder are inherited fixes (tool-output expansion status line,
46
+ file-backed `SYSTEM.md`/`APPEND_SYSTEM.md` startup listing, worktree
47
+ context double-load, llama.cpp usage accounting, session replacement
48
+ during active responses, Git package install retries, `/model`
49
+ selector, direct RPC bash bypassing `user_bash` handlers, resource
50
+ metadata, and assorted provider fixes) that leave the RPC contract
51
+ unchanged.
52
+
53
+ ## [0.2.1] - 2026-07-25
54
+
55
+ ### Changed
56
+ - Bumped pinned upstream `pi-coding-agent` version to `0.82.1` (from
57
+ `0.81.1`, rolling up `0.82.0` and `0.82.1`). This is a provider/tooling
58
+ and reliability batch; none of the changes alter the JSONL RPC
59
+ command/response shapes this gem drives, so no gem API change is required.
60
+ - `0.82.1` adds Claude Opus 5 (Anthropic and Amazon Bedrock, with
61
+ adaptive thinking), `ANTHROPIC_AUTH_TOKEN` bearer auth for
62
+ Anthropic-compatible gateways, and faster/more resilient model
63
+ catalogs (pi.dev revalidates with `If-None-Match`). It exposes the
64
+ `outputPad` setting to custom message renderers and fixes
65
+ compaction/branch summaries for header-only auth providers, `/models`
66
+ hiding of unavailable scoped models, startup context-file `EISDIR`
67
+ warnings, and llama.cpp catalog persistence. All provider/SDK/TUI
68
+ concerns, leaving the RPC contract unchanged.
69
+ - `0.82.0` details follow.
70
+ - Adds constrained tool sampling (`Tool.constrainedSampling` with strict
71
+ JSON Schema and OpenAI Lark/regex grammars) plus `supportsGrammarTools`
72
+ / `supportsStrictTools` model capability metadata. This is an
73
+ SDK/extension tool-configuration concern, not part of the RPC surface.
74
+ - Adds OpenRouter OAuth PKCE and Kimi Code subscription sign-in via
75
+ `/login`, and exposes `PI_SESSION_ID`, `PI_SESSION_FILE`, `PI_PROVIDER`,
76
+ `PI_MODEL`, and `PI_REASONING_LEVEL` to commands run by built-in and
77
+ factory-created bash tools.
78
+ - Adds streaming `bash_execution_update` events for direct RPC bash
79
+ commands, correlated with request IDs. These flow through
80
+ `PiAgent::Event` transparently — it preserves the native payload on
81
+ `#raw` and exposes `#type` as a symbol — so no gem change is needed to
82
+ consume them.
83
+ - The remainder are inherited provider/retry/model-catalog fixes (DNS
84
+ lookup retries, OpenRouter cache breakpoints, protobufjs 7.6.5 security
85
+ bump, catalog mtime and llama.cpp context fixes) that leave the RPC
86
+ contract unchanged.
87
+
10
88
  ## [0.2.0] - 2026-07-23
11
89
 
12
90
  Minor (not patch) release: besides the stream-truncation fix, the block form
data/README.md CHANGED
@@ -14,7 +14,7 @@ building interactive agent UIs (web, TUI) on top of pi.
14
14
 
15
15
  - Ruby 3.3+
16
16
  - `pi` 0.80.4+ on `PATH` (install via `npm i -g @earendil-works/pi-coding-agent`)
17
- - This gem is pinned against pi `0.81.1`; other versions may work but are not verified.
17
+ - This gem is pinned against pi `0.83.0`; other versions may work but are not verified.
18
18
 
19
19
  ## Installation
20
20
 
@@ -105,7 +105,7 @@ Pi emits `agent_end` after each low-level agent run, but may then retry,
105
105
  compact and retry, or process queued continuations. It emits
106
106
  `agent_settled` only when no automatic work remains, so high-level streams
107
107
  use that as their completion boundary. Upstream added the RPC event in pi
108
- 0.80.4; it is available in this gem's pinned pi 0.81.1.
108
+ 0.80.4; it is available in this gem's pinned pi 0.83.0.
109
109
 
110
110
  `events` is a lower-level, prompt-less drain of the same stream. Because it
111
111
  subscribes lazily when iteration begins, it only works when you subscribe
@@ -175,6 +175,32 @@ Returning `nil` from a dialog handler cancels it. With no handler,
175
175
  dialogs are auto-cancelled so the agent never hangs. Handlers run on
176
176
  their own thread and never block the event stream.
177
177
 
178
+ If a handler raises, the dialog is cancelled as a fail-safe. Use
179
+ `on_extension_ui_error` when the application needs to observe those failures:
180
+
181
+ ```ruby
182
+ on_ui_error = lambda do |error, request|
183
+ logger.error(
184
+ "Extension UI handler failed",
185
+ error: error.class.name,
186
+ request_id: request.id,
187
+ method: request.method
188
+ )
189
+ end
190
+
191
+ PiAgent.session(
192
+ extension_ui: handler,
193
+ on_extension_ui_error: on_ui_error
194
+ ) do |session|
195
+ session.prompt("Refactor the parser") { |e| ... }
196
+ end
197
+ ```
198
+
199
+ The observer runs on the same worker thread and cannot change the fail-safe
200
+ cancellation. If it raises, the dialog is still cancelled. Requests can contain
201
+ sensitive titles, messages, options, or prefilled text, so avoid logging
202
+ `request.raw` without application-specific filtering.
203
+
178
204
  ## Forking
179
205
 
180
206
  ```ruby
@@ -52,8 +52,9 @@ module PiAgent
52
52
  end
53
53
 
54
54
  def initialize(bin: nil, args: DEFAULT_ARGS, env: {}, cwd: nil, approve: nil,
55
- extension_ui: nil, transport_factory: nil)
55
+ extension_ui: nil, on_extension_ui_error: nil, transport_factory: nil)
56
56
  @extension_ui_handler = extension_ui
57
+ @extension_ui_error_handler = on_extension_ui_error
57
58
  args = [*args, approve ? "--approve" : "--no-approve"] unless approve.nil?
58
59
  @transport_factory = transport_factory || build_subprocess_factory(bin, args, env, cwd)
59
60
  @pending = {}
@@ -70,7 +71,11 @@ module PiAgent
70
71
  on_message: method(:handle_message),
71
72
  on_stderr: method(:handle_stderr)
72
73
  )
73
- @extension_ui = ExtensionUI.new(writer: @transport, handler: @extension_ui_handler)
74
+ @extension_ui = ExtensionUI.new(
75
+ writer: @transport,
76
+ handler: @extension_ui_handler,
77
+ on_error: @extension_ui_error_handler
78
+ )
74
79
  @transport.start
75
80
  self
76
81
  end
@@ -19,6 +19,7 @@ module PiAgent
19
19
  # - fire-and-forget methods : return value ignored
20
20
  #
21
21
  # With no handler, dialogs are auto-cancelled so the agent never hangs.
22
+ # Handler failures also cancel the dialog; pass `on_error` to observe them.
22
23
  class ExtensionUI
23
24
  DIALOG_METHODS = %i[select confirm input editor].freeze
24
25
 
@@ -50,9 +51,10 @@ module PiAgent
50
51
  end
51
52
  end
52
53
 
53
- def initialize(writer:, handler: nil)
54
+ def initialize(writer:, handler: nil, on_error: nil)
54
55
  @writer = writer
55
56
  @handler = handler
57
+ @on_error = on_error
56
58
  @threads = []
57
59
  @mutex = Mutex.new
58
60
  end
@@ -75,7 +77,21 @@ module PiAgent
75
77
  private
76
78
 
77
79
  def handle(request)
78
- result = invoke_handler(request)
80
+ result, error = invoke_handler(request)
81
+ write_response(request, result)
82
+ notify_error(error, request) if error
83
+ end
84
+
85
+ def invoke_handler(request)
86
+ return [nil, nil] if @handler.nil?
87
+
88
+ [@handler.call(request), nil]
89
+ rescue StandardError => e
90
+ # A raising handler cancels the dialog rather than hanging the agent.
91
+ [nil, e]
92
+ end
93
+
94
+ def write_response(request, result)
79
95
  return unless request.dialog?
80
96
 
81
97
  @writer.write(response_for(request, result))
@@ -83,12 +99,10 @@ module PiAgent
83
99
  # Transport closed during shutdown; the response is moot.
84
100
  end
85
101
 
86
- def invoke_handler(request)
87
- return nil if @handler.nil?
88
-
89
- @handler.call(request)
102
+ def notify_error(error, request)
103
+ @on_error&.call(error, request)
90
104
  rescue StandardError
91
- # A raising handler cancels the dialog rather than hanging the agent.
105
+ # Error observers cannot prevent the fail-closed response.
92
106
  nil
93
107
  end
94
108
 
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PiAgent
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.2"
5
5
 
6
6
  # Pinned upstream pi-coding-agent version this gem is verified against.
7
7
  # See: https://www.npmjs.com/package/@earendil-works/pi-coding-agent
8
- SUPPORTED_PI_VERSION = "0.81.1"
8
+ SUPPORTED_PI_VERSION = "0.83.0"
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pi-agent-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - chagel
@@ -85,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
85
  - !ruby/object:Gem::Version
86
86
  version: '0'
87
87
  requirements: []
88
- rubygems_version: 4.0.10
88
+ rubygems_version: 3.6.9
89
89
  specification_version: 4
90
90
  summary: Ruby client for the pi coding agent (drives `pi --mode rpc`)
91
91
  test_files: []