@oh-my-pi/pi-coding-agent 15.9.5 → 15.10.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.
Files changed (192) hide show
  1. package/CHANGELOG.md +98 -1
  2. package/dist/types/cli/args.d.ts +1 -1
  3. package/dist/types/cli/gallery-cli.d.ts +43 -0
  4. package/dist/types/cli/gallery-fixtures/agentic.d.ts +2 -0
  5. package/dist/types/cli/gallery-fixtures/codeintel.d.ts +3 -0
  6. package/dist/types/cli/gallery-fixtures/edit.d.ts +3 -0
  7. package/dist/types/cli/gallery-fixtures/fs.d.ts +2 -0
  8. package/dist/types/cli/gallery-fixtures/index.d.ts +4 -0
  9. package/dist/types/cli/gallery-fixtures/interaction.d.ts +3 -0
  10. package/dist/types/cli/gallery-fixtures/memory.d.ts +2 -0
  11. package/dist/types/cli/gallery-fixtures/misc.d.ts +3 -0
  12. package/dist/types/cli/gallery-fixtures/search.d.ts +3 -0
  13. package/dist/types/cli/gallery-fixtures/shell.d.ts +3 -0
  14. package/dist/types/cli/gallery-fixtures/types.d.ts +44 -0
  15. package/dist/types/cli/gallery-fixtures/web.d.ts +2 -0
  16. package/dist/types/cli/gallery-screenshot.d.ts +35 -0
  17. package/dist/types/commands/gallery.d.ts +47 -0
  18. package/dist/types/config/keybindings.d.ts +10 -2
  19. package/dist/types/config/model-id-affixes.d.ts +2 -0
  20. package/dist/types/config/model-registry.d.ts +8 -1
  21. package/dist/types/config/settings-schema.d.ts +43 -7
  22. package/dist/types/edit/file-snapshot-store.d.ts +1 -1
  23. package/dist/types/eval/backend.d.ts +6 -6
  24. package/dist/types/eval/bridge-timeout.d.ts +27 -0
  25. package/dist/types/eval/idle-timeout.d.ts +16 -14
  26. package/dist/types/eval/js/executor.d.ts +3 -3
  27. package/dist/types/eval/py/executor.d.ts +2 -2
  28. package/dist/types/eval/py/spawn-options.d.ts +58 -0
  29. package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
  30. package/dist/types/lsp/types.d.ts +10 -0
  31. package/dist/types/main.d.ts +3 -2
  32. package/dist/types/memory-backend/index.d.ts +2 -1
  33. package/dist/types/memory-backend/resolve.d.ts +1 -1
  34. package/dist/types/memory-backend/types.d.ts +1 -1
  35. package/dist/types/modes/components/assistant-message.d.ts +5 -0
  36. package/dist/types/modes/components/copy-selector.d.ts +22 -0
  37. package/dist/types/modes/components/custom-editor.d.ts +2 -1
  38. package/dist/types/modes/components/model-selector.d.ts +1 -0
  39. package/dist/types/modes/components/tool-execution.d.ts +18 -0
  40. package/dist/types/modes/controllers/command-controller.d.ts +0 -1
  41. package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
  42. package/dist/types/modes/index.d.ts +5 -4
  43. package/dist/types/modes/interactive-mode.d.ts +2 -2
  44. package/dist/types/modes/setup-version.d.ts +11 -0
  45. package/dist/types/modes/setup-wizard/index.d.ts +2 -1
  46. package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +2 -1
  47. package/dist/types/modes/types.d.ts +2 -2
  48. package/dist/types/modes/utils/copy-targets.d.ts +53 -0
  49. package/dist/types/sdk.d.ts +1 -1
  50. package/dist/types/task/executor.d.ts +7 -0
  51. package/dist/types/telemetry-export.d.ts +1 -1
  52. package/dist/types/tools/eval-render.d.ts +1 -0
  53. package/dist/types/tools/fetch.d.ts +15 -7
  54. package/dist/types/tools/render-utils.d.ts +33 -0
  55. package/dist/types/tools/renderers.d.ts +16 -2
  56. package/dist/types/tools/search.d.ts +1 -1
  57. package/dist/types/tools/write.d.ts +2 -0
  58. package/dist/types/tui/code-cell.d.ts +6 -0
  59. package/dist/types/tui/output-block.d.ts +11 -0
  60. package/dist/types/web/scrapers/github.d.ts +22 -0
  61. package/dist/types/web/search/providers/perplexity.d.ts +8 -1
  62. package/dist/types/web/search/types.d.ts +1 -1
  63. package/package.json +9 -9
  64. package/scripts/dev-launch +42 -0
  65. package/scripts/dev-launch-preload.ts +19 -0
  66. package/src/autoresearch/dashboard.ts +11 -21
  67. package/src/cli/args.ts +2 -2
  68. package/src/cli/claude-trace-cli.ts +13 -1
  69. package/src/cli/gallery-cli.ts +223 -0
  70. package/src/cli/gallery-fixtures/agentic.ts +292 -0
  71. package/src/cli/gallery-fixtures/codeintel.ts +188 -0
  72. package/src/cli/gallery-fixtures/edit.ts +194 -0
  73. package/src/cli/gallery-fixtures/fs.ts +153 -0
  74. package/src/cli/gallery-fixtures/index.ts +40 -0
  75. package/src/cli/gallery-fixtures/interaction.ts +49 -0
  76. package/src/cli/gallery-fixtures/memory.ts +81 -0
  77. package/src/cli/gallery-fixtures/misc.ts +221 -0
  78. package/src/cli/gallery-fixtures/search.ts +213 -0
  79. package/src/cli/gallery-fixtures/shell.ts +167 -0
  80. package/src/cli/gallery-fixtures/types.ts +41 -0
  81. package/src/cli/gallery-fixtures/web.ts +158 -0
  82. package/src/cli/gallery-screenshot.ts +279 -0
  83. package/src/cli-commands.ts +1 -0
  84. package/src/commands/gallery.ts +52 -0
  85. package/src/commands/launch.ts +1 -1
  86. package/src/config/keybindings.ts +68 -2
  87. package/src/config/model-equivalence.ts +35 -12
  88. package/src/config/model-id-affixes.ts +39 -22
  89. package/src/config/model-registry.ts +16 -16
  90. package/src/config/settings-schema.ts +29 -6
  91. package/src/config/settings.ts +11 -0
  92. package/src/dap/client.ts +14 -16
  93. package/src/debug/raw-sse.ts +18 -4
  94. package/src/edit/file-snapshot-store.ts +1 -1
  95. package/src/edit/index.ts +1 -1
  96. package/src/edit/renderer.ts +43 -55
  97. package/src/edit/streaming.ts +1 -1
  98. package/src/eval/__tests__/agent-bridge.test.ts +102 -58
  99. package/src/eval/__tests__/bridge-timeout.test.ts +64 -0
  100. package/src/eval/__tests__/idle-timeout.test.ts +26 -12
  101. package/src/eval/__tests__/kernel-spawn.test.ts +103 -0
  102. package/src/eval/__tests__/llm-bridge.test.ts +10 -10
  103. package/src/eval/agent-bridge.ts +38 -12
  104. package/src/eval/backend.ts +6 -6
  105. package/src/eval/bridge-timeout.ts +44 -0
  106. package/src/eval/idle-timeout.ts +33 -15
  107. package/src/eval/js/executor.ts +10 -10
  108. package/src/eval/llm-bridge.ts +4 -5
  109. package/src/eval/py/executor.ts +6 -6
  110. package/src/eval/py/kernel.ts +11 -1
  111. package/src/eval/py/spawn-options.ts +126 -0
  112. package/src/export/ttsr.ts +9 -0
  113. package/src/extensibility/extensions/runner.ts +3 -0
  114. package/src/extensibility/plugins/doctor.ts +0 -1
  115. package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
  116. package/src/goals/tools/goal-tool.ts +2 -2
  117. package/src/internal-urls/docs-index.generated.ts +7 -6
  118. package/src/lsp/client.ts +179 -52
  119. package/src/lsp/index.ts +38 -4
  120. package/src/lsp/render.ts +3 -3
  121. package/src/lsp/types.ts +10 -0
  122. package/src/main.ts +47 -52
  123. package/src/memory-backend/index.ts +13 -1
  124. package/src/memory-backend/resolve.ts +3 -5
  125. package/src/memory-backend/types.ts +1 -1
  126. package/src/modes/components/agent-dashboard.ts +13 -4
  127. package/src/modes/components/assistant-message.ts +22 -1
  128. package/src/modes/components/copy-selector.ts +249 -0
  129. package/src/modes/components/custom-editor.ts +10 -1
  130. package/src/modes/components/extensions/extension-list.ts +17 -8
  131. package/src/modes/components/history-search.ts +19 -11
  132. package/src/modes/components/model-selector.ts +125 -29
  133. package/src/modes/components/oauth-selector.ts +28 -12
  134. package/src/modes/components/session-observer-overlay.ts +13 -15
  135. package/src/modes/components/session-selector.ts +24 -13
  136. package/src/modes/components/status-line.ts +3 -5
  137. package/src/modes/components/tool-execution.ts +83 -24
  138. package/src/modes/components/tree-selector.ts +19 -7
  139. package/src/modes/components/user-message-selector.ts +25 -14
  140. package/src/modes/controllers/command-controller.ts +13 -118
  141. package/src/modes/controllers/event-controller.ts +26 -10
  142. package/src/modes/controllers/input-controller.ts +11 -3
  143. package/src/modes/controllers/selector-controller.ts +40 -3
  144. package/src/modes/index.ts +5 -4
  145. package/src/modes/interactive-mode.ts +21 -7
  146. package/src/modes/setup-version.ts +11 -0
  147. package/src/modes/setup-wizard/index.ts +3 -2
  148. package/src/modes/setup-wizard/scenes/web-search.ts +3 -2
  149. package/src/modes/theme/theme.ts +46 -10
  150. package/src/modes/types.ts +2 -2
  151. package/src/modes/utils/context-usage.ts +10 -6
  152. package/src/modes/utils/copy-targets.ts +254 -0
  153. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  154. package/src/prompts/tools/ast-edit.md +1 -1
  155. package/src/prompts/tools/ast-grep.md +1 -1
  156. package/src/prompts/tools/read.md +1 -1
  157. package/src/prompts/tools/search.md +1 -1
  158. package/src/sdk.ts +21 -23
  159. package/src/session/agent-session.ts +13 -9
  160. package/src/slash-commands/builtin-registry.ts +4 -12
  161. package/src/slash-commands/helpers/usage-report.ts +2 -0
  162. package/src/task/executor.ts +20 -2
  163. package/src/task/render.ts +37 -11
  164. package/src/telemetry-export.ts +25 -7
  165. package/src/tools/bash.ts +18 -8
  166. package/src/tools/browser/render.ts +5 -4
  167. package/src/tools/debug.ts +3 -3
  168. package/src/tools/eval-backends.ts +6 -17
  169. package/src/tools/eval-render.ts +28 -10
  170. package/src/tools/eval.ts +19 -23
  171. package/src/tools/fetch.ts +99 -89
  172. package/src/tools/read.ts +7 -7
  173. package/src/tools/render-utils.ts +63 -3
  174. package/src/tools/renderers.ts +16 -1
  175. package/src/tools/report-tool-issue.ts +1 -1
  176. package/src/tools/search.ts +173 -81
  177. package/src/tools/ssh.ts +21 -8
  178. package/src/tools/todo.ts +20 -7
  179. package/src/tools/write.ts +39 -9
  180. package/src/tui/code-cell.ts +19 -4
  181. package/src/tui/output-block.ts +14 -0
  182. package/src/web/scrapers/github.ts +255 -3
  183. package/src/web/scrapers/youtube.ts +3 -2
  184. package/src/web/search/providers/perplexity.ts +199 -51
  185. package/src/web/search/render.ts +42 -57
  186. package/src/web/search/types.ts +5 -1
  187. package/dist/types/eval/heartbeat.d.ts +0 -45
  188. package/src/eval/__tests__/heartbeat.test.ts +0 -84
  189. package/src/eval/__tests__/shared-executors.test.ts +0 -609
  190. package/src/eval/heartbeat.ts +0 -74
  191. /package/dist/types/eval/__tests__/{heartbeat.test.d.ts → bridge-timeout.test.d.ts} +0 -0
  192. /package/dist/types/eval/__tests__/{shared-executors.test.d.ts → kernel-spawn.test.d.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,7 +2,103 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [15.10.0] - 2026-06-06
6
+
7
+ ### Breaking Changes
8
+
9
+ - Replaced the `providers.parallelFetch` boolean setting with the `providers.fetch` enum (`auto` / `native` / `trafilatura` / `lynx` / `parallel` / `jina`) that selects the URL reader-backend priority for the `read`/`fetch` tool, mirroring `providers.image`/`providers.webSearch`. Existing configs are migrated automatically: the legacy key is dropped and the new `auto` default applies.
10
+
11
+ ### Added
12
+
13
+ - Added a GitHub Actions read handler to the `read`/web-fetch GitHub scraper. Fetching `github.com/{owner}/{repo}/actions/runs/{id}` renders the run metadata plus a per-job breakdown (steps listed for any job that did not succeed), and `…/actions/runs/{id}/job/{id}` (also the API-style `…/jobs/{id}`) renders a single job's metadata, step table, and full plain-text logs. Logs are fetched via the `actions/jobs/{id}/logs` redirect using `GITHUB_TOKEN`/`GH_TOKEN` when present, with the per-line ISO timestamp prefix and leading BOM stripped; the section degrades to an explicit notice when logs are unavailable (no token, private repo, or expired/unfinalized run).
14
+
15
+ ### Changed
16
+
17
+ - Changed eval `agent()` subagents so they are never subject to the `task.maxRuntimeMs` wall-clock cap. The parent cell's idle watchdog is already suspended for the entire bridge call (`withBridgeTimeoutPause`), so a long-running fan-out/recovery workflow must not be killed by a per-subagent runtime limit. `runEvalAgent` now passes `maxRuntimeMs: 0` to `runSubprocess`, which honors an explicit `ExecutorOptions.maxRuntimeMs` override over the inherited setting.
18
+ - Changed interactive timing behavior so `PI_TIMING=x pi` preloads the module timer before the CLI graph loads and includes the `(modules)` report. `PI_TIMING=full` now also exits after printing, matching `PI_TIMING=x`, so full module reports are usable for cold-start measurement without launching the TUI. Added the root `dev:timing` script for the same profiled startup path.
19
+ - Changed coding-agent startup imports so normal TUI launch imports `InteractiveMode` directly, keeps print/RPC/ACP runners on their branch-only paths, and moves marketplace auto-update work behind a lightweight deferred starter.
20
+ - Changed cold-launch setup gating so the full setup wizard (every scene plus the overlay and their TUI/OAuth/web-search/theme dependencies) is no longer statically imported by `main.ts`. The current setup version now lives in a tiny dependency-free `modes/setup-version` module, and the wizard barrel is lazy-loaded only when the stored setup version is stale or the wizard is forced — the common up-to-date launch skips loading it entirely.
21
+ - Changed cold-launch startup imports so the hot-path CLI files no longer pull the full `@oh-my-pi/pi-ai` barrel: `commands/launch.ts` and `cli/args.ts` import `THINKING_EFFORTS`/`Effort` from the tiny `@oh-my-pi/pi-ai/effort` module, and `config/model-registry.ts` now imports its ~20 symbols from narrow subpaths (`api-registry`, `model-cache`, `model-manager`, `model-thinking`, `models`, `provider-models`, `types`, `utils/event-stream`) instead of the barrel — so launching no longer eagerly loads every provider, auth, OAuth, and usage module re-exported by the barrel.
22
+ - Changed the `read`/`fetch` HTML reader-backend priority to `native > trafilatura > lynx > parallel > jina` (was `parallel > jina > trafilatura > lynx > native`). The in-process native `htmlToMarkdown` runs first — instant, no network, full-fidelity — so the common case no longer depends on a remote service, and a stalled remote backend can no longer mask it. Selecting a specific backend via `providers.fetch` tries it first, then the rest fall back. The low-quality gate (`>100` chars and not `isLowQualityOutput`) now applies uniformly to every backend; when none clears it, the highest-priority substantial-but-low-quality output is still surfaced so the `llms.txt` / document-extraction fallbacks keep running.
23
+
24
+ ### Fixed
25
+
26
+ - Fixed eval `agent()` failures surfacing as an opaque `RuntimeError: bridge call '__agent__' failed` with no reason. When a subagent aborted, `runEvalAgent` built its failure message with `result.error ?? result.stderr ?? result.abortReason ?? …`, but `result.stderr` is the empty string on a clean abort (and `result.error` is gated on a non-empty `stderr`), so the nullish chain stopped at `""` and never reached `abortReason`. The empty string propagated through the loopback bridge and the Python prelude's `RuntimeError(msg or "bridge call … failed")`, discarding the real reason. The chain now uses `||` so an empty `stderr` falls through to `abortReason`.
27
+ - Fixed subagent aborts being mislabeled as the generic "Cancelled by caller" when the abort originated inside the subagent's own turn (`stopReason: "aborted"` with no caller signal and no runtime-limit timer). `runSubprocess` now prefers the aborted assistant message's `errorMessage` (e.g. "Request was aborted" or a specific stream error) for that case, while a real caller signal or wall-clock abort still reports its precise reason.
28
+ - Fixed a long streaming tool preview that alone overflows the viewport dropping its scrolled-off head on ED3-risk terminals (ghostty/kitty/iTerm2/…). When expanded with `Ctrl+O`, a streaming `write` (content streaming in) and a streaming `eval` (stdout streaming below its fixed code cell) render top-anchored and grow append-only, but the tool block never reported itself append-only to the transcript, so the renderer's commit-as-you-go boundary stopped at the block start and the earlier rows that scrolled above the viewport were committed nowhere — they vanished, leaving the preview looking like a viewport-tall circular buffer. `ToolExecutionComponent` now implements `isTranscriptBlockAppendOnly()` (gated on `isTranscriptBlockFinalized()`, so it also covers partial-result streams like `eval`), delegating to a renderer-declared `isStreamingPreviewAppendOnly` predicate so the expanded stream commits its head exactly like a streamed assistant reply. Collapsed previews (bounded sliding tail windows) and finalized/result previews (which can collapse to a capped view) stay deferred.
29
+ - Fixed `read`/`fetch` silently dropping whole list sections on pages with malformed list markup — stray `<img>`, text, or `<video>` nodes as direct children of `<ul>` (e.g. the Alacritty changelog). The Jina reader (previously tried before the local renderers) mis-extracts such lists, returning empty `Added`/`Changed` sections; the native in-process renderer now runs first and preserves the full content.
30
+ - Fixed `/usage` aggregate amount fallback using raw `limits.length` as account count — now counts unique `accountId` values from limit scopes, so N limits from a single account no longer display as "N accts".
31
+ - Fixed `/usage` account labeling falling back to "account N" for providers that use `projectId` as their primary identity (e.g. Google Antigravity, Gemini CLI) — `projectId` from report metadata is now considered before the generic fallback.
32
+ - Fixed the `todo` tool's TUI renderer crashing with `TypeError: args?.ops?.map is not a function` when a streaming tool-call delta surfaced a non-array `ops` field (mid-stream `parseStreamingJson` shapes like `{ ops: "[{" }`, or `[null]` entries before fields arrive). The renderer now treats non-array `ops`, non-object entries, and non-array `items` as missing structure instead of crashing, which also stops the spam-warn cascade that followed each malformed delta. Paired with the Anthropic-side reasoning-replay fix in `packages/ai` ([#2005](https://github.com/can1357/oh-my-pi/issues/2005)).
33
+ - Fixed Python eval `agent()` collapsing subagent runtime-limit aborts (and other empty-stderr aborts) into a generic `RuntimeError: bridge call '__agent__' failed`. `runEvalAgent` coalesced the failure message with `??`, which stopped at the empty `stderr` and never reached `abortReason`, shipping an empty error through the loopback bridge. The bridge now prefers `abortReason` for aborts and trims empty `stderr`/`error` out of the fallback chain, so Python surfaces the actionable reason (e.g. `Subagent runtime limit exceeded (task.maxRuntimeMs=900000)`) ([#2006](https://github.com/can1357/oh-my-pi/issues/2006)).
34
+
35
+ ## [15.9.69] - 2026-06-06
36
+
37
+ ### Added
38
+
39
+ - Added anonymous fallback for Perplexity web search, allowing `web_search` and explicit Perplexity provider usage when no Perplexity credentials are configured
40
+ - Added `gallery` CLI command to render built-in tool renderer output across streaming, in-progress, success, and failure states
41
+ - Added `omp gallery` filtering and rendering options (`--tool`, `--state`, `--width`, `--expanded`, and `--plain`) for focused renderer previews and plain-text output
42
+ - Added `omp gallery` fidelity for tools whose renderers are attached on the tool instance (`lsp`, `task`): the gallery now drives them through the same custom-tool render branch production uses, so regressions in that path surface in the gallery rather than only in a live session.
43
+ - Added `omp gallery --screenshot`, which renders the gallery through a real virtual terminal (VHS) and writes PNG screenshot(s) instead of ANSI, so agents (and anything that can only read raw bytes) can actually see the rendered output. The capture forces truecolor and matches the active theme/symbol preset; tall galleries split across multiple images (whole renderers are never cut). Tune with `--out`, `--font`, and `--font-size`; requires `vhs` on `PATH` and fails with install guidance when absent.
44
+ - Added `app.display.reset`, bound to `Ctrl+L` by default, to force an immediate terminal display reset/redraw without resizing the window.
45
+
46
+ ### Changed
47
+
48
+ - Changed authenticated Perplexity ask requests to default to the `experimental` model preference, matching the anonymous fallback.
49
+ - Changed Perplexity explicit provider availability checks so the setup wizard can mark `perplexity` as available for manual selection without credentials, while auto provider discovery still requires auth
50
+ - Changed the default persistent model selector shortcut from `Ctrl+L` to `Alt+M`, leaving `Ctrl+L` for display reset. Existing user remaps in `keybindings.yml` are preserved.
51
+ - Changed the edit tool result header to carry the diff change stats (`+N / -M / K hunks`) inline next to the file path, and removed the redundant lone language-icon metadata row and the blank line between the header and the diff body, so a single-hunk edit renders as `✔ Edit: <icon> path:LINE ⟨+3 / 1 hunk⟩` immediately followed by the diff.
52
+ - Changed the `web_search` tool result rendering: the answer text now shows in full instead of being truncated to a "… N more lines" preview (the `omp q` CLI still caps its compact output), each source renders as a single `title (domain) · age` line with the URL linked on the title (dropping the snippet and bare-URL rows), and the metadata block collapses to one `Provider: <model> @ <provider> (<auth>)` line plus `Usage:` (removing the redundant Sources/Citations/Request/Queries rows).
53
+
54
+ ### Fixed
55
+
56
+ - Fixed Perplexity `perplexity_ask` response parsing so OAuth, cookie, and anonymous searches correctly extract answer text and sources from JSON payloads
57
+ - Fixed framed read results rendering with an extra blank row above and below the output block.
58
+ - Fixed collapsed search result previews that could show only "… N more matches" when the first grouped section exceeded the preview budget. Collapsed search output now compacts to match rows, fills the budget with visible hits before the summary, and keeps truncation details out of the bottom user-visible notice.
59
+ - Fixed the expanded search result view dumping every match when all hits live in one file. A single file's matches collapse into one blank-line group, and the expanded tree list ignored the line budget, so a hot file whose matches span its whole length rendered every row (e.g. lines 374–2858). Expanded search output is now bounded by a larger-than-collapsed budget (`EXPANDED_LINES × 2`), keeps surrounding context rows, and appends a `… N more matches` summary when truncated.
60
+ - Fixed boolean environment flag overrides that were ORed with settings, so `PI_INTENT_TRACING=0`, `PI_AUTO_QA=0`, and per-backend eval flags now take precedence when present while falling back to config when unset.
61
+ - Fixed custom-rendered tools that set `mergeCallAndResult` (e.g. `lsp`) rendering a redundant tool-name line above the framed result once a result arrived. `ToolExecutionComponent`'s custom-tool branch now emits the fallback label only when the tool has no `renderCall` and the call is not suppressed by an existing result, matching the built-in renderer branch.
62
+ - Fixed the `write` tool result rendering with a green success checkmark even when the write failed. `writeToolRenderer.renderResult` now branches on `result.isError`, rendering the error status icon plus the failure message instead of the success header and content preview.
63
+ - Fixed Perplexity OAuth/cookie web search returning a refusal answer ("I don't currently have access to the web-search tools in this turn") despite returning real sources. `callPerplexityOAuth` was prepending the API-style `web-search` system prompt to the query (`query_str = systemPrompt + "\n\n" + query`), but the consumer `www.perplexity.ai/rest/sse/perplexity_ask` endpoint has no system-message slot and reads the prepended instruction as a meta-prompt, making the model decline. The OAuth/cookie path now sends the bare query; the API-key path still passes the system prompt as a proper `system` message.
64
+ - Fixed Perplexity OAuth web search always returning the free `turbo` model instead of the account's Pro model (e.g. `pplx_pro_upgraded`/Sonar). The `www.perplexity.ai/rest/sse/perplexity_ask` endpoint authenticates via the `__Secure-next-auth.session-token` cookie and ignores the `Authorization: Bearer` header entirely — so sending the OAuth session token as a bearer was treated as an anonymous request, which silently downgrades to `turbo` regardless of `model_preference`. The stored Perplexity OAuth token is itself the next-auth session JWT (the macOS app injects the same value as that cookie), so `callPerplexityAsk` now sends it as the `__Secure-next-auth.session-token` cookie, unlocking Pro model selection.
65
+
66
+ ## [15.9.67] - 2026-06-06
67
+
68
+ ### Added
69
+
70
+ - Added `timeout-pause` and `timeout-resume` eval bridge status events emitted around `agent()`/`llm()` operations
71
+ - Added a `/copy` picker: `/copy` now opens a fullscreen, outlined tree of recent assistant messages with their code blocks nested beneath (like `/tree`). Navigate with ↑↓, and Enter copies the highlighted node — a whole message, an individual code block, "All N blocks", or a bash/eval command interleaved with the assistant turn that issued it. A live preview pane shows the selected target, wrapping prose and syntax-highlighting code/commands.
72
+
73
+ ### Changed
74
+
75
+ - Changed eval timeout accounting so delegated bridge calls now suspend the cell watchdog and start a fresh timeout window when runtime control returns
76
+ - Changed `IdleTimeout` to support reference-counted pauses so overlapping delegated bridge calls keep timeout paused until all calls complete
77
+ - Changed the default `app.message.followUp` binding from `Ctrl+Enter` alone to `[Ctrl+Q, Ctrl+Enter]` so the follow-up shortcut works in Windows Terminal, which does not deliver a distinct `Ctrl+Enter` event to console apps. `Ctrl+Q` mirrors the GitHub Copilot CLI default for the same action; existing remaps in `~/.omp/agent/keybindings.yml` are untouched, and if another user-remapped action already claims `Ctrl+Q`, that user binding wins while follow-up keeps `Ctrl+Enter`. `Ctrl+Q` is also reserved by `ExtensionRunner` so an extension cannot register that chord and be silently overwritten by the built-in follow-up handler ([#1903](https://github.com/can1357/oh-my-pi/issues/1903)).
78
+ - Changed all scrollable TUI pickers and viewports to render through the shared `ScrollView` right-edge scrollbar for a uniform look, replacing their ad-hoc `(N/M)` / `[a-b/total]` text indicators (search hints and the tree filter-mode label are preserved). Covers the session/resume picker, model selector, OAuth provider selector, history search, session tree selector, agent dashboard list, extension list, user-message selector, the raw SSE debug viewer, the autoresearch dashboard overlay, and the session observer overlay.
79
+ - Changed the `/model` and `/switch` selectors to dim and skip models whose context windows are smaller than the current chat context.
80
+ - Changed `/copy` command targets to appear inline with recent assistant messages instead of as a separate "Last bash command" row at the end of the picker.
81
+
82
+ ### Fixed
83
+
84
+ - Fixed the idle `Working...` loader freezing on ED3-risk terminals with unobservable native scrollback by keeping foreground live-region rendering enabled from `agent_start` until `agent_end`, before the first assistant or tool event arrives.
85
+ - Fixed framed tool output blocks rendering one column inset inside tool boxes; modern bordered blocks now span the same width as legacy background-filled tool boxes.
86
+ - Fixed potential `TimeoutError` aborts for short `timeout` eval cells during long bridged `agent()`/`llm()` work where no progress events are emitted until completion
87
+ - Fixed retry recovery to allow automatic retries without switching models when `retry.modelFallback` is disabled.
88
+ - Fixed `ttsr.enabled: false` being ignored at runtime. TTSR rules were still being registered with `TtsrManager.addRule` and matched against stream deltas even when the global toggle was off, so disabling TTSR did not suppress rule injection or stream abort. The manager now gates `addRule`, `hasRules`, and `#matchBuffer` on the enabled flag, so disabling fully short-circuits the TTSR path. Condition rules fall through to the rulebook bucket instead of being silently swallowed. ([#1767](https://github.com/can1357/oh-my-pi/issues/1767))
89
+ - Fixed the Python eval kernel hanging on Windows during `import pandas` / `import numpy`, with SIGINT unable to recover the cell. `PythonKernel.start()` spawned the runner with `windowsHide: true`, which in Bun maps to the Win32 `CREATE_NO_WINDOW` flag and detaches the long-lived child from any inherited console — so native extensions like `numpy/_core/_multiarray_umath.pyd` (and its bundled OpenBLAS/SLEEF thread-pool init) could deadlock inside `LoadLibraryExW`, and `GenerateConsoleCtrlEvent`-based SIGINT delivery silently became a no-op. The kernel now hides its window only when the host itself has no console to share (service / piped launch); an interactive TUI launch lets the kernel inherit the parent's console, matching the behavior of `python.exe` invoked from `cmd.exe` ([#1960](https://github.com/can1357/oh-my-pi/issues/1960)).
90
+ - Fixed `task` renderer crashing the TUI with `TypeError: completeData?.map is not a function` when a subagent's `extractedToolData.yield` slot held a non-array value. `renderAgentResult` (and the live-progress sibling) cast the slot to `Array<{ data }>` and called `?.map`, but optional chaining short-circuits only on `null`/`undefined`, so a plain object made `.map` `undefined` and threw — taking down every `review` task render. Both sites now go through `normalizeYieldData`, which wraps a single object as a 1-element array and drops primitives ([#1987](https://github.com/can1357/oh-my-pi/issues/1987))
91
+ - Fixed `sdk-async-job-manager-singleton` tests flaking under the full parallel suite. The four `createAgentSession`-based cases ran on the default 5000ms per-test timeout, which two real session startups can exceed when `test:ts` saturates the machine across packages; on timeout the still-running test body and `afterEach` reset raced, surfacing a spurious "Unhandled error between tests" on the `AsyncJobManager.instance()` assertion. They now carry an explicit 60000ms timeout, matching the convention used by the other session-creating tests in this suite.
92
+ - Fixed streaming `eval`, `bash`, `ssh`, and `task` call previews overflowing the live transcript viewport and cutting off their top while pending. A volatile tool block taller than the viewport could strand its scrolled-off head out of native scrollback on ED3-risk terminals (committed nowhere, repainted nowhere) until the result landed. The pending `eval` source preview now follows the streaming edge in a bounded 12-line tail window (newest lines pinned to the bottom, "… N earlier lines" on top) so you can watch the code being written without the box overflowing; `bash`/`ssh` commands and `task` context use a bounded head+tail window. `Ctrl+O` still lifts the cap for a full view.
93
+ - Fixed the streaming `write` call preview ignoring `Ctrl+O` so the expand toggle was a no-op while a file was being written. Unlike the `eval`/`bash`/`ssh`/`task` streaming previews, `formatStreamingContent` never received the `expanded` flag, leaving the preview pinned to a bounded 12-line tail window even after pressing `Ctrl+O` — so on a large write you could not widen past the streaming edge until the tool result landed. The preview now lifts the cap to the full file (head through tail) when expanded, matching the documented streaming-preview behavior of the other tools.
94
+ - Fixed turn-ending provider errors rendering twice — once as the transcript's inline `Error: …` line and again in the pinned banner above the editor (added in 15.9.5). The inline line is now suppressed while the same error is mirrored in the banner and restored to the transcript when the banner clears at the next turn, so the error stays in history without the duplicate render at the error moment.
95
+
96
+ ### Removed
97
+
98
+ - Removed the `/copy last|code|all|cmd` subcommands; every copy target is now reachable by picking it in the `/copy` tree.
99
+
5
100
  ## [15.9.5] - 2026-06-05
101
+
6
102
  ### Added
7
103
 
8
104
  - Added a persistent error banner pinned above the editor when an assistant turn ends on a provider error (e.g. Anthropic's "Output blocked by content filtering policy"). The transcript `Error: …` line scrolls away as the conversation grows, so terminal turns that ended on a stream error could pass unnoticed; the banner stays in the fixed region above the input and is cleared when the next turn starts.
@@ -31,6 +127,7 @@
31
127
  - Blocked OSC 8 hyperlink wrapping for URI targets containing terminal control bytes to avoid rendering malformed control-sequence links
32
128
 
33
129
  ## [15.9.4] - 2026-06-05
130
+
34
131
  ### Fixed
35
132
 
36
133
  - Fixed chat transcript updates after submitting input so frozen scrollback is only thawed when native scrollback replay succeeds, preventing misplaced or duplicated rows when the viewport is not at the tail
@@ -9399,4 +9496,4 @@ Initial public release.
9399
9496
  - Git branch display in footer
9400
9497
  - Message queueing during streaming responses
9401
9498
  - OAuth integration for Gmail and Google Calendar access
9402
- - HTML export with syntax highlighting and collapsible sections
9499
+ - HTML export with syntax highlighting and collapsible sections
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * CLI argument parsing and help display
3
3
  */
4
- import { type Effort } from "@oh-my-pi/pi-ai";
4
+ import { type Effort } from "@oh-my-pi/pi-ai/effort";
5
5
  export type Mode = "text" | "json" | "rpc" | "acp" | "rpc-ui";
6
6
  export interface Args {
7
7
  cwd?: string;
@@ -0,0 +1,43 @@
1
+ import { type GalleryFixture } from "./gallery-fixtures";
2
+ /** Lifecycle states the gallery renders, in display order. */
3
+ export declare const GALLERY_STATES: readonly ["streaming", "progress", "success", "error"];
4
+ export type GalleryState = (typeof GALLERY_STATES)[number];
5
+ export interface GalleryCommandArgs {
6
+ /** Render width in columns (defaults to terminal width, clamped). */
7
+ width?: number;
8
+ /** Restrict to a single tool name. */
9
+ tool?: string;
10
+ /** Restrict to specific lifecycle states. */
11
+ states?: GalleryState[];
12
+ /** Render the expanded variant of each renderer. */
13
+ expanded?: boolean;
14
+ /** Strip ANSI styling from the output (useful when redirecting to a file). */
15
+ plain?: boolean;
16
+ /** Capture the rendered gallery as PNG screenshot(s) via VHS instead of printing ANSI. */
17
+ screenshot?: boolean;
18
+ /** Screenshot output path (single image) or base path (suffixed when split across images). */
19
+ out?: string;
20
+ /** Font family for screenshots (must be installed; Nerd Font recommended for icon glyphs). */
21
+ font?: string;
22
+ /** Font size in points for screenshots. */
23
+ fontSize?: number;
24
+ }
25
+ /** One tool's rendered lifecycle, as ANSI lines: a leading blank, the section rule, then each state. */
26
+ export interface GallerySection {
27
+ heading: string;
28
+ lines: string[];
29
+ }
30
+ /** The curated fixture for a tool, or a generic one for registry tools lacking sample data. */
31
+ export declare function resolveFixture(name: string): GalleryFixture;
32
+ /**
33
+ * Render a single tool/state pair to lines. Builds a fresh component, drives it
34
+ * to the requested state, settles any async edit preview, then snapshots the
35
+ * render and stops all animation timers.
36
+ */
37
+ export declare function renderGalleryState(name: string, fixture: GalleryFixture, state: GalleryState, width: number, expanded?: boolean): Promise<string[]>;
38
+ /**
39
+ * Render the gallery. Iterates the renderer registry (or a single tool),
40
+ * printing each requested lifecycle state under a labeled section — or, with
41
+ * `screenshot`, capturing the rendered output as PNG(s) via VHS.
42
+ */
43
+ export declare function runGalleryCommand(args: GalleryCommandArgs): Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { GalleryFixture } from "./types";
2
+ export declare const agenticFixtures: Record<string, GalleryFixture>;
@@ -0,0 +1,3 @@
1
+ /** Gallery fixtures for the code-intelligence tools (lsp, debug). */
2
+ import type { GalleryFixture } from "./types";
3
+ export declare const codeintelFixtures: Record<string, GalleryFixture>;
@@ -0,0 +1,3 @@
1
+ /** Gallery fixtures for the edit tools (edit, apply_patch, ast_edit). */
2
+ import type { GalleryFixture } from "./types";
3
+ export declare const editFixtures: Record<string, GalleryFixture>;
@@ -0,0 +1,2 @@
1
+ import type { GalleryFixture } from "./types";
2
+ export declare const fsFixtures: Record<string, GalleryFixture>;
@@ -0,0 +1,4 @@
1
+ export * from "./types";
2
+ export declare const galleryFixtures: {
3
+ [x: string]: import("./types").GalleryFixture;
4
+ };
@@ -0,0 +1,3 @@
1
+ /** Gallery fixtures for the todo / ask / resolve interaction tools. */
2
+ import type { GalleryFixture } from "./types";
3
+ export declare const interactionFixtures: Record<string, GalleryFixture>;
@@ -0,0 +1,2 @@
1
+ import type { GalleryFixture } from "./types";
2
+ export declare const memoryFixtures: Record<string, GalleryFixture>;
@@ -0,0 +1,3 @@
1
+ /** Gallery fixtures for the ask / resolve / ssh / github / inspect_image tools. */
2
+ import type { GalleryFixture } from "./types";
3
+ export declare const miscFixtures: Record<string, GalleryFixture>;
@@ -0,0 +1,3 @@
1
+ /** Gallery fixtures for the search tools (search, search_tool_bm25, ast_grep). */
2
+ import type { GalleryFixture } from "./types";
3
+ export declare const searchFixtures: Record<string, GalleryFixture>;
@@ -0,0 +1,3 @@
1
+ /** Gallery fixtures for the shell tools (bash, eval). */
2
+ import type { GalleryFixture } from "./types";
3
+ export declare const shellFixtures: Record<string, GalleryFixture>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Types for `omp gallery` sample data. See {@link ./index} for the aggregated
3
+ * fixture registry and the contract each fixture must satisfy.
4
+ */
5
+ import type { EditMode } from "../../edit";
6
+ /** A tool result snapshot, matching the shape `ToolExecutionComponent` consumes. */
7
+ export interface GalleryResult {
8
+ content: Array<{
9
+ type: string;
10
+ text?: string;
11
+ data?: string;
12
+ mimeType?: string;
13
+ }>;
14
+ details?: unknown;
15
+ isError?: boolean;
16
+ }
17
+ export interface GalleryFixture {
18
+ /** Display label for the tool header (defaults to the tool name). */
19
+ label?: string;
20
+ /** Edit mode for edit-like tools so the streaming preview dispatches correctly. */
21
+ editMode?: EditMode;
22
+ /**
23
+ * Set for tools whose real `AgentTool` attaches `renderCall`/`renderResult`
24
+ * directly on the instance (e.g. `lsp`, `task`). The harness then attaches
25
+ * the registry renderer onto the fake tool so the component routes through
26
+ * the custom-tool branch — the same path production takes — instead of the
27
+ * built-in registry branch. The two branches can diverge, so exercising the
28
+ * real one keeps the gallery honest for these tools.
29
+ */
30
+ customRendered?: boolean;
31
+ /**
32
+ * Arguments shown during the streaming state — a partial view of {@link args}
33
+ * as if the tool-call JSON were still arriving. May include `__partialJson`
34
+ * for renderers (bash, edit) that surface fields before the object closes.
35
+ * Defaults to {@link args} when omitted.
36
+ */
37
+ streamingArgs?: unknown;
38
+ /** Complete arguments shown for the in-progress, success, and error states. */
39
+ args: unknown;
40
+ /** Successful result. */
41
+ result: GalleryResult;
42
+ /** Failed result. Falls back to a generic error when omitted. */
43
+ errorResult?: GalleryResult;
44
+ }
@@ -0,0 +1,2 @@
1
+ import type { GalleryFixture } from "./types";
2
+ export declare const webFixtures: Record<string, GalleryFixture>;
@@ -0,0 +1,35 @@
1
+ import type { GallerySection } from "./gallery-cli";
2
+ /** Nerd Font family so the gallery's icon glyphs (PUA) render instead of tofu. */
3
+ export declare const DEFAULT_SCREENSHOT_FONT = "JetBrainsMono Nerd Font";
4
+ export declare const DEFAULT_SCREENSHOT_FONT_SIZE = 18;
5
+ export interface GalleryScreenshotOptions {
6
+ /** Gallery render width in columns (matches the ANSI line width). */
7
+ width: number;
8
+ /** VHS `FontFamily`. */
9
+ font?: string;
10
+ /** VHS `FontSize`. */
11
+ fontSize?: number;
12
+ /**
13
+ * Output destination. When omitted, PNGs land in a fresh temp directory.
14
+ * With multiple images the path is suffixed (`name-01.png`, `name-02.png`).
15
+ */
16
+ out?: string;
17
+ }
18
+ /**
19
+ * Capture the gallery sections as one or more PNGs and return their absolute
20
+ * paths. Tall galleries are split across images so no single capture exceeds
21
+ * the terminal-canvas height limit.
22
+ */
23
+ export declare function captureGalleryScreenshots(sections: GallerySection[], options: GalleryScreenshotOptions): Promise<string[]>;
24
+ /**
25
+ * Resolve a chunk's PNG path. A single image keeps the bare name (or the exact
26
+ * `out`); multiple images gain a zero-padded `-NN` suffix so they sort and never
27
+ * collide.
28
+ */
29
+ export declare function resolveScreenshotOutputPath(out: string | undefined, baseDir: string, index: number, total: number): string;
30
+ /**
31
+ * Group whole tool sections into chunks that stay under `rowBudget` rows. A
32
+ * single section larger than the budget gets its own (taller) image rather than
33
+ * being split mid-renderer.
34
+ */
35
+ export declare function chunkGallerySections(sections: GallerySection[], rowBudget: number): GallerySection[][];
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Render every built-in tool's renderer across its lifecycle states.
3
+ */
4
+ import { Command } from "@oh-my-pi/pi-utils/cli";
5
+ export default class Gallery extends Command {
6
+ static description: string;
7
+ static flags: {
8
+ tool: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"string"> & {
9
+ char: string;
10
+ description: string;
11
+ };
12
+ state: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"string"> & {
13
+ char: string;
14
+ description: string;
15
+ options: ("error" | "progress" | "streaming" | "success")[];
16
+ multiple: true;
17
+ };
18
+ width: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"integer"> & {
19
+ char: string;
20
+ description: string;
21
+ };
22
+ expanded: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
23
+ char: string;
24
+ description: string;
25
+ default: boolean;
26
+ };
27
+ plain: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
28
+ description: string;
29
+ default: boolean;
30
+ };
31
+ screenshot: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
32
+ description: string;
33
+ default: boolean;
34
+ };
35
+ out: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"string"> & {
36
+ char: string;
37
+ description: string;
38
+ };
39
+ font: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"string"> & {
40
+ description: string;
41
+ };
42
+ "font-size": import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"integer"> & {
43
+ description: string;
44
+ };
45
+ };
46
+ run(): Promise<void>;
47
+ }
@@ -8,6 +8,7 @@ interface AppKeybindings {
8
8
  "app.clear": true;
9
9
  "app.exit": true;
10
10
  "app.suspend": true;
11
+ "app.display.reset": true;
11
12
  "app.thinking.cycle": true;
12
13
  "app.thinking.toggle": true;
13
14
  "app.model.cycleForward": true;
@@ -191,6 +192,10 @@ export declare const KEYBINDINGS: {
191
192
  readonly defaultKeys: "ctrl+z";
192
193
  readonly description: "Suspend application";
193
194
  };
195
+ readonly "app.display.reset": {
196
+ readonly defaultKeys: "ctrl+l";
197
+ readonly description: "Reset terminal display";
198
+ };
194
199
  readonly "app.thinking.cycle": {
195
200
  readonly defaultKeys: "shift+tab";
196
201
  readonly description: "Cycle thinking level";
@@ -208,7 +213,7 @@ export declare const KEYBINDINGS: {
208
213
  readonly description: "Cycle to previous model";
209
214
  };
210
215
  readonly "app.model.select": {
211
- readonly defaultKeys: "ctrl+l";
216
+ readonly defaultKeys: "alt+m";
212
217
  readonly description: "Select model";
213
218
  };
214
219
  readonly "app.model.selectTemporary": {
@@ -224,7 +229,7 @@ export declare const KEYBINDINGS: {
224
229
  readonly description: "Open external editor";
225
230
  };
226
231
  readonly "app.message.followUp": {
227
- readonly defaultKeys: "ctrl+enter";
232
+ readonly defaultKeys: ["ctrl+q", "ctrl+enter"];
228
233
  readonly description: "Send follow-up message";
229
234
  };
230
235
  readonly "app.message.dequeue": {
@@ -329,6 +334,9 @@ export declare class KeybindingsManager extends TuiKeybindingsManager {
329
334
  * Reload keybindings from the config file.
330
335
  */
331
336
  reload(): void;
337
+ setUserBindings(userBindings: KeybindingsConfig): void;
338
+ getKeys(keybinding: Keybinding): KeyId[];
339
+ getResolvedBindings(): KeybindingsConfig;
332
340
  /**
333
341
  * Get the effective resolved bindings (defaults + user overrides).
334
342
  */
@@ -5,6 +5,8 @@ export declare function getLongestModelLikeIdSegment(modelId: string): string |
5
5
  * upstream model id, e.g.
6
6
  * "[Kiro] claude-opus-4-8" -> "claude-opus-4-8"
7
7
  * "[gcli转] gemini-3.1-pro-preview [假流]" -> "gemini-3.1-pro-preview"
8
+ *
9
+ * Candidates are returned most-stripped first: both ends, then leading-only, then trailing-only.
8
10
  */
9
11
  export declare function getBracketStrippedModelIdCandidates(modelId: string): string[];
10
12
  export declare function stripBracketedModelIdAffixes(modelId: string): string | undefined;
@@ -1,4 +1,6 @@
1
- import { type Api, type AssistantMessageEventStream, type Context, type Model, type ModelRefreshStrategy, type SimpleStreamOptions, type ThinkingConfig } from "@oh-my-pi/pi-ai";
1
+ import { type ModelRefreshStrategy } from "@oh-my-pi/pi-ai/model-manager";
2
+ import type { Api, Context, Model, SimpleStreamOptions, ThinkingConfig } from "@oh-my-pi/pi-ai/types";
3
+ import type { AssistantMessageEventStream } from "@oh-my-pi/pi-ai/utils/event-stream";
2
4
  import type { OAuthCredentials, OAuthLoginCallbacks } from "@oh-my-pi/pi-ai/utils/oauth/types";
3
5
  import { type ThemeColor } from "../modes/theme/theme";
4
6
  import type { AuthStorage } from "../session/auth-storage";
@@ -355,6 +357,11 @@ export declare class ModelRegistry {
355
357
  * Check if a model selector is currently suppressed due to rate limits.
356
358
  */
357
359
  isSelectorSuppressed(selector: string): boolean;
360
+ /**
361
+ * Clear all cooldown suppressions recorded via {@link suppressSelector}.
362
+ * Used to reset retry-fallback cooldown state without a full {@link refresh}.
363
+ */
364
+ clearSuppressedSelectors(): void;
358
365
  }
359
366
  /**
360
367
  * Input type for registerProvider API (from extensions).
@@ -1027,6 +1027,15 @@ export declare const SETTINGS_SCHEMA: {
1027
1027
  readonly description: "Maximum wait between retries, in ms. When the provider asks us to wait longer than this and no credential or model fallback succeeds, the request fails fast instead of sleeping (e.g. 3-hour Anthropic rate-limit windows).";
1028
1028
  };
1029
1029
  };
1030
+ readonly "retry.modelFallback": {
1031
+ readonly type: "boolean";
1032
+ readonly default: true;
1033
+ readonly ui: {
1034
+ readonly tab: "model";
1035
+ readonly label: "Retry Model Fallback";
1036
+ readonly description: "Allow retry recovery to switch to configured fallback models";
1037
+ };
1038
+ };
1030
1039
  readonly "retry.fallbackChains": {
1031
1040
  readonly type: "record";
1032
1041
  readonly default: Record<string, string[]>;
@@ -2186,7 +2195,7 @@ export declare const SETTINGS_SCHEMA: {
2186
2195
  readonly ui: {
2187
2196
  readonly tab: "editing";
2188
2197
  readonly label: "Hash Lines";
2189
- readonly description: "Include snapshot-tag headers and line numbers in read output for hashline edit mode (PATH#tag plus LINE:content)";
2198
+ readonly description: "Include snapshot-tag headers and line numbers in read output for hashline edit mode ([PATH#TAG] plus LINE:content)";
2190
2199
  };
2191
2200
  };
2192
2201
  readonly "read.defaultLimit": {
@@ -3308,7 +3317,7 @@ export declare const SETTINGS_SCHEMA: {
3308
3317
  }, {
3309
3318
  readonly value: "perplexity";
3310
3319
  readonly label: "Perplexity";
3311
- readonly description: "Requires PERPLEXITY_COOKIES or PERPLEXITY_API_KEY";
3320
+ readonly description: "Uses auth when configured; explicit selection falls back to anonymous search";
3312
3321
  }, {
3313
3322
  readonly value: "brave";
3314
3323
  readonly label: "Brave";
@@ -3661,13 +3670,39 @@ export declare const SETTINGS_SCHEMA: {
3661
3670
  }];
3662
3671
  };
3663
3672
  };
3664
- readonly "providers.parallelFetch": {
3665
- readonly type: "boolean";
3666
- readonly default: true;
3673
+ readonly "providers.fetch": {
3674
+ readonly type: "enum";
3675
+ readonly values: readonly ["auto", "native", "trafilatura", "lynx", "parallel", "jina"];
3676
+ readonly default: "auto";
3667
3677
  readonly ui: {
3668
3678
  readonly tab: "providers";
3669
- readonly label: "Parallel Fetch";
3670
- readonly description: "Use Parallel extract API for URL fetching when credentials are available";
3679
+ readonly label: "Fetch Provider";
3680
+ readonly description: "Reader backend priority for the fetch/read URL tool";
3681
+ readonly options: readonly [{
3682
+ readonly value: "auto";
3683
+ readonly label: "Auto";
3684
+ readonly description: "Priority: native > trafilatura > lynx > parallel > jina";
3685
+ }, {
3686
+ readonly value: "native";
3687
+ readonly label: "Native";
3688
+ readonly description: "In-process HTML→Markdown converter (always available)";
3689
+ }, {
3690
+ readonly value: "trafilatura";
3691
+ readonly label: "Trafilatura";
3692
+ readonly description: "Auto-installs via uv/pip";
3693
+ }, {
3694
+ readonly value: "lynx";
3695
+ readonly label: "Lynx";
3696
+ readonly description: "Requires lynx system package";
3697
+ }, {
3698
+ readonly value: "parallel";
3699
+ readonly label: "Parallel";
3700
+ readonly description: "Requires PARALLEL_API_KEY";
3701
+ }, {
3702
+ readonly value: "jina";
3703
+ readonly label: "Jina";
3704
+ readonly description: "Uses r.jina.ai reader (JINA_API_KEY optional)";
3705
+ }];
3671
3706
  };
3672
3707
  };
3673
3708
  readonly "provider.appendOnlyContext": {
@@ -3902,6 +3937,7 @@ export interface RetrySettings {
3902
3937
  maxRetries: number;
3903
3938
  baseDelayMs: number;
3904
3939
  maxDelayMs: number;
3940
+ modelFallback: boolean;
3905
3941
  }
3906
3942
  export interface MemoriesSettings {
3907
3943
  enabled: boolean;
@@ -12,7 +12,7 @@ import { InMemorySnapshotStore } from "@oh-my-pi/hashline";
12
12
  /**
13
13
  * Upper bound on the file size we snapshot. A section tag is a content hash of
14
14
  * the *whole* file, so minting one means holding the full normalized text in
15
- * the store. Files above this cap emit no path#tag` header — line-anchored
15
+ * the store. Files above this cap emit no `[path#tag]` header — line-anchored
16
16
  * editing of multi-megabyte files is out of scope under the full-content model.
17
17
  */
18
18
  export declare const SNAPSHOT_MAX_BYTES: number;
@@ -9,12 +9,12 @@ export interface ExecutorBackendExecOptions {
9
9
  signal?: AbortSignal;
10
10
  session: ToolSession;
11
11
  /**
12
- * Inactivity budget in milliseconds (the cell's `timeout`). Cancellation is
13
- * driven entirely by `signal`, which the eval tool arms as an idle watchdog
14
- * that fires a `TimeoutError` reason after this much time with no progress
15
- * (status) events. Backends use this value only for timeout-annotation text
16
- * and as cold-start headroom; they MUST NOT derive a competing wall-clock
17
- * timer from it.
12
+ * Runtime-work budget in milliseconds (the cell's `timeout`). Cancellation is
13
+ * driven entirely by `signal`, which the eval tool arms as a watchdog that
14
+ * pauses on bridge timeout-control status events and fires a `TimeoutError`
15
+ * reason only while the Python/JS runtime owns control. Backends use this
16
+ * value only for timeout-annotation text and as cold-start headroom; they MUST
17
+ * NOT derive a competing wall-clock timer from it.
18
18
  */
19
19
  idleTimeoutMs: number;
20
20
  reset: boolean;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Timeout suspension for in-flight host-side eval bridge calls.
3
+ *
4
+ * The eval watchdog caps a cell's `timeout` as a budget on the cell runtime's
5
+ * own work. Host-side `agent()` / `parallel()` / `llm()` bridge calls hand
6
+ * control to the outer TypeScript process, where the Python kernel or JS VM is
7
+ * only waiting for a result. While that delegated work is in flight, the cell
8
+ * timeout must be ignored completely; once the bridge returns and the runtime is
9
+ * back in control, the watchdog starts a fresh timeout window.
10
+ *
11
+ * Bridge helpers express that handoff with synthetic pause/resume status events
12
+ * on the existing `emitStatus → onStatus` path. Consumers MUST treat these as
13
+ * timeout-control events only: update the watchdog and drop them from rendered
14
+ * or persisted cell output.
15
+ */
16
+ import type { JsStatusEvent } from "./js/shared/types";
17
+ /** Synthetic status op emitted when a bridge call leaves the cell runtime. */
18
+ export declare const EVAL_TIMEOUT_PAUSE_OP = "timeout-pause";
19
+ /** Synthetic status op emitted when a bridge call returns control to the runtime. */
20
+ export declare const EVAL_TIMEOUT_RESUME_OP = "timeout-resume";
21
+ /** Whether a status event is pure eval-timeout control and should not render. */
22
+ export declare function isEvalTimeoutControlEvent(event: JsStatusEvent): boolean;
23
+ /**
24
+ * Run {@link operation} while suspending the eval watchdog through
25
+ * {@link emitStatus}. A no-op wrapper when no status sink is wired.
26
+ */
27
+ export declare function withBridgeTimeoutPause<T>(emitStatus: ((event: JsStatusEvent) => void) | undefined, operation: () => Promise<T>): Promise<T>;