@oh-my-pi/pi-ai
Fixed
- Fixed MiniMax-compatible OpenAI-completions hosts (e.g.
minimax-code-cn/MiniMax-M3) losing tool-call arguments when the stream deliversfunction.argumentsas a complete object instead of the OpenAI JSON-string contract. The streaming buffer previously concatenated the object into a string, coercing it to[object Object]and leavingbash/editcalls with empty or malformed inputs; the tool-call block now holds the object payload directly. (#1776) - Fixed Cloud Code Assist (Gemini / Antigravity) rejecting tool schemas with
Invalid JSON payload received. Unknown name "propertyNames"(HTTP 400) when a tool exposed a property literally namedproperties(e.g. the Resend MCPcreate_contacttool). The schema normalizer'sinsidePropertiesflag was re-asserted when descending into such a property's value schema, so Google-unsupported keywords (propertyNames,additionalProperties, …) nested inside it were never stripped. The flag is now only set when entering a realpropertiesmap from a schema node, not from within anotherpropertiesmap. - Fixed local/self-hosted providers leaking machine-specific endpoints into the bundled
models.json. Agenerate-modelsrun on a machine with a LiteLLM proxy baked 1202litellmmodels pinned tohttp://localhost:4000/v1into the committed catalog.litellm(andlm-studio) now joinollama/vllmin the generator's discovery-only exclusion set, so local providers are never fetched during generation nor written tomodels.json— they are discovered dynamically at runtime instead. LiteLLM model discovery now enriches metadata against models.dev (the same reference source the other gateway providers use) rather than a bundled reference map. Added a regression test pinning the invariant (no local provider blocks, no loopback/private-networkbaseUrls in the bundled catalog).
@oh-my-pi/pi-coding-agent
Breaking Changes
- Removed synchronous
readTextSyncfromSessionStorageand core implementations (MemorySessionStorage,FileSessionStorage,RedisSessionStorage,SqlSessionStorage), requiring callers to use async text reads - Replaced the public
SessionStoragereadTextPrefix(path, maxBytes)andreadTextSuffix(path, maxBytes)methods withreadTextSlices(path, prefixBytes, suffixBytes): Promise<[string, string]>; custom session storage backends must implement the new combined slice API.
Added
- Added env-driven OpenTelemetry trace export. When
OTEL_EXPORTER_OTLP_ENDPOINT(orOTEL_EXPORTER_OTLP_TRACES_ENDPOINT) is set,ompregisters a global OTLP/proto trace exporter and switches on the agent loop's telemetry, so theinvoke_agent/chat/execute_toolspans actually reach a collector instead of a no-op tracer. Honors the standardOTEL_*env contract (endpoint, headers,OTEL_SERVICE_NAME,OTEL_SDK_DISABLEDandOTEL_TRACES_EXPORTER=noneparsed case-insensitively) and theOTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENTcapture toggle; it is a no-op when no endpoint is configured. Only thehttp/protobuftransport is supported — agrpcorhttp/jsonOTEL_EXPORTER_OTLP*_PROTOCOLdeclines rather than misrouting spans. This makes the existing telemetry usable from headless hosts that runompas a spawned child process, where an in-processTracerProviderregistered by the parent can't reach the child. Uses the@opentelemetry/exporter-trace-otlp-proto2.x line, which exports cleanly under Bun.
Fixed
- Fixed the status line session name (and the editor border / status-line gap fill) being nearly illegible on light themes.
- Added
IndexedSessionStorageandSessionStorageBackendexports to support shared metadata-indexed session backends - Added the
tui.maxInlineImagessetting (default8) capping how many inline images render as live terminal graphics. Once a new image pushes the count past the cap, the oldest images are hidden via a full redraw — replaced by their[Image: …]text placeholder and purged from the terminal's graphics store — so long sessions with many screenshots/diagrams stop piling up images (and, on Kitty, stop leaving scrollback ghosts). Set to0to keep every image inline. - Added a "View: terminal state" item to the
/debugmenu that prints the detected terminal, live geometry and cell size, multiplexer, and the negotiated subprotocols actually in use — graphics (Kitty/iTerm2/Sixel), desktop notifications (BEL/OSC 9/OSC 99, plus whether OSC 99 was confirmed via a device-attributes probe), OSC 8 hyperlinks, 24-bit color, DECCARA rectangular-SGR background fills, and DEC 2026 synchronized output — alongside the scrollback-clear strategy (CSI 22 JvsCSI 2 Jredraw / ED3 eager-erase risk) and the rawTERM/TERM_PROGRAM/COLORTERMdetection signals. - Added a "Test: terminal protocols" item to the
/debugmenu that renders one live sample of every special escape protocol the renderer can emit — SGR text attributes (bold/italic/underline/strikethrough/inverse/dim), themed and 24-bit truecolor, OSC 8 hyperlinks, OSC 66 text sizing (large text), and an inline graphics swatch via the active image protocol (Kitty/iTerm2/Sixel, with a text fallback) — and fires a desktop notification, so you can eyeball which protocols the current terminal actually honors. The sample image is a gradient PNG generated in-process, so the graphics test needs no asset on disk. - Added the
tui.textSizingsetting (default off) that renders Markdown H1 headings at 2x scale via Kitty's OSC 66 text-sizing protocol. It replaces the undocumentedPI_TUI_TEXT_SIZINGenv var with a real setting, and only takes effect on Kitty terminals (where OSC 66 is implemented) — it is ignored everywhere else so headings never emit raw escape bytes. - Added a lifecycle status to the
/resumesession picker. Each session's tail (last 32 KiB) is now read alongside the existing header window in a single pass, and its final message classified asdone(the agent ended its turn and yielded control back),interrupted(a trailing tool call or tool result the loop never continued from),aborted,error, orpending(a trailing user message with no reply). The status renders as a colored segment on each session's metadata line. When the final message is larger than the tail window the status is omitted rather than guessed. - Added support for
disable-model-invocation: truefrontmatter field from the Agent Skills standard. Skills using this field are now hidden from the system prompt listing, matching the behavior ofhide: true.
Changed
- Changed the
tasktool description to tag read-only agents and explicitly forbid assigning them file edits/commands or offloading reasoning toquick_task/explore. - Changed Redis and SQL session storage initialization to load only indexed metadata (
size,mtimeMs) instead of full session content - Changed
SessionStorageread paths to rely on backend-backed metadata/indexed storage, so session content is fetched on demand rather than cached as full in-memory mirrors - Changed session-list slice reads to go through
SessionStorage.readTextSlicesacross all backends, removing the file-only single-open branch and caller-managed buffers.FileSessionStoragenow reads both windows viapeekFileEnds, while Redis and SQL backends encode session content once per combined read. - Changed the
asktool transcript renderer to mark single-choice questions with circular radio glyphs (○/◉) instead of the rectangular checkbox glyphs (☐/☑) it shares with multi-select questions, so a "pick one" combo box visually reads as a radio group rather than a checklist. Multi-select questions keep checkboxes. Added aradio.selected/radio.unselectedsymbol pair across the unicode, nerd-font, and ASCII presets. - Changed the
asktool transcript renderer to mark the chosen answer inside the question form rather than re-listing the questions in a detached summary block below it. Once a question is answered, the standalone prompt preview is dropped and the result redraws the same form — every offered option still shown, with the selected one(s) filled in (◉/☑, highlighted) and the rest dimmed (○/☐); custom free-text answers and cancellations render in place as the final entry. This removes the duplicate question/option listing that previously appeared once as the call preview and again as the result. - Changed task-completion and
askdesktop notifications to structured terminal notifications (title, body, type, and a focus-on-click action). On Kitty these render through OSC 99 as a proper title/body with click-to-focus; terminals without confirmed OSC 99 support collapse them to the previous single-line message (BEL/OSC 9). - Updated the "each kitty/tmux split" tip to include cmux.
Fixed
- Fixed tiny-model startup in compiled binaries by resolving
@huggingface/transformersand its runtime dependencies from the installed cache usingpackage.jsonexports/mainmetadata, preventing module-resolution failures when launching models - Fixed tiny runtime installation flow in compiled binaries by using the build-time resolved
@huggingface/transformersversion and ensuring the runtime lock directory’s parent exists before acquiring the install lock, preventing mismatch and setup failures on fresh installs - Fixed the terminal protocol debug probe reusing one stable Kitty graphics id across repeated panels, which could move/replace an earlier swatch instead of rendering a new one.
- Fixed selector dialogs (the
asktool, hook prompts) collapsing to a single visible option on shorter terminals when options carried long descriptions: the highlighted option's wrapped description consumed the entire row budget, hiding every other option and making the menu feel unnavigable (down moved the lone visible entry, left/right did nothing). When the fully-expanded list overflows,HookSelectorComponentnow renders a compact list — every option label stays on screen and only the highlighted option expands its description, truncated to the remaining rows — so the whole menu is always visible and the detail pane follows the cursor. - Fixed
readfailing with "Path not found" on web URLs whose scheme//collapsed to a single/(e.g.https:/github.com/...), which happens when a URL is routed through Node'spath.normalize/path.resolve. The fetch URL recognizer now accepts a single-slash scheme and repairs it back to//before fetching, so collapsed URLs resolve instead of falling through to filesystem lookup. - Fixed subagent slow-model priority falling through to older Claude Opus aliases when Opus 4.8 is available by adding Opus 4.8 and 4.7 aliases ahead of older Opus fallbacks (#1753).
- Fixed the web-search provider selectors in TUI settings/setup to derive from the shared provider metadata, so newly added providers cannot be omitted from the preference list.
@oh-my-pi/pi-natives
Fixed
- Bounded sorted
glob()scans tomaxResultsduring uncached traversal and emittedonMatchcallbacks only for entries admitted to the bounded top-maxResultsheap so broad OMPfindprogress and timeout partials stay consistent with the returned mtime-ranked set while keeping parent-process memory bounded (#1761). - Fixed
wrapTextWithAnsihanging (infinite loop) on text containing a BEL-terminated string escape — DCS/SOS/PM/APC (ESC P/ESC X/ESC ^/ESC _) closed byBELinstead ofST.ansi_seq_len_u16only accepted theST(ESC \) terminator for these (OSC already accepted both), so a BEL-terminated APC such as the TUI cursor marker (ESC _ pi:c BEL) was left unclassified: it was miscounted as visible width andbreak_long_word's non-ESC scan could not advance past theESC, spinning forever. The terminator set now matches OSC (ST or BEL), andbreak_long_worddefensively emits and steps over any escape it cannot classify so a malformed/unknown sequence can never wedge the wrap loop.
@oh-my-pi/swarm-extension
Fixed
- Fixed swarm
/swarm runfailing with authStorage/modelRegistry identity error (#1472)
@oh-my-pi/pi-tui
Added
- Added Kitty
CSI 22 Jscreen-to-scrollback clears for non-destructive full paints, while keeping ED3 for destructive history/session rebuilds. - Added Kitty OSC 99 rich notification formatting and startup capability probing.
- Added Kitty OSC 66 text-sized Markdown H1 headings (2x scale) plus native text-width support for OSC 66 spans. Off by default and gated to Kitty (the only terminal implementing OSC 66) via the
TERMINAL.textSizingcapability; hosts enable it throughsetTextSizing. - Added Kitty Unicode placeholder image rendering (
U=1+ U+10EEEE with explicit row/column diacritics): inline images are drawn as real text cells that carry the image id in their foreground color, so they survive horizontal slicing, reflow, and overlapping draws instead of relying on cursor-positioneda=pplacements. Enabled by default on Kitty-family terminals; opt out withPI_NO_KITTY_PLACEHOLDERS=1, and falls back to direct placement when a grid exceeds the diacritic table's addressable range. - Added Kitty temp-file image transmission (
t=t): on local sessions, decoded PNG bytes are written to atty-graphics-protocoltemp file and the path is sent instead of in-band base64, gated behind a startupa=q,t=tsupport probe. Controlled byPI_KITTY_IMAGE_TRANSMISSION=direct|temp-file|auto; disabled over SSH unless explicitly forced. - Added DECRQM capability detection for DEC private modes 2026 (synchronized output) and 2048 (in-band resize). Synchronized-output paint wrappers are dropped when the terminal reports 2026 unsupported (preserving the
PI_NO_SYNC_OUTPUToverride), and DEC 2048 in-band resize is enabled when supported — reported geometry and cell pixel size are updated fromCSI 48 ; rows ; cols ; yPx ; xPx treports, with SIGWINCH andCSI 16 tkept as fallbacks. - Added an injectable render scheduler for TUI tests, allowing deterministic render drains without patching global clocks or event-loop timing.
- Added
ImageBudget, an inline-image cap that keeps only the most recent N images as live terminal graphics and demotes older ones to their text fallback. Once a new image pushes the count past the cap, the renderer hides the oldest via a full redraw plus an explicit Kitty graphics purge (a=d,d=I) — text-clear escapes (CSI 2 J/CSI 3 J) do not remove Kitty images. Configure the cap viaTUI#setMaxInlineImages(0disables it). - Changed Kitty inline images to a transmit-once + placement scheme: the base64 data is sent a single time (
a=t) keyed by a stable image id, then every repaint emits only the tiny placement (a=p,i=…,p=…). Repaints — including full redraws — no longer re-send image data or stack duplicate placements, and the diff/line buffers and render caches hold short placement strings instead of multi-KB base64. TheImageBudgetdoubles as the transmit store (it tracks which ids are loaded and re-transmits after a purge frees the data). iTerm2/Sixel, which have no addressable image store, keep sending inline data as before. - Added a renderer-level DECCARA rectangular-SGR optimizer that paints solid background panels/rows (Box/Text/Markdown fills, status bars, any full-width
theme.bgrow) as a single coalesced rectangle escape (CSI 2*x/CSI Pt;Pl;Pb;Pr;<sgr>$r/CSI *x) instead of emitting a full-width run of background-styled spaces on every visible row. It operates at emit time on the final ANSI strings — components are unchanged — and strips only trailing padding it can prove sits under a single non-default background span, coalescing vertically adjacent identical fills into one rectangle and falling back to the original bytes whenever the rectangle would not save bytes. Enabled only on Kitty, which implements the SGR-background extension (docs/deccara.rst); Ghostty is intentionally excluded because itsCSI $ris unimplemented (ghostty-org/ghostty#632) and would drop the background entirely. Scrollback-bound rows and the append/scroll paths always keep the padded representation so native history preserves colored cells, and thePI_NO_DECCARAkill switch (plus tmux/screen/zellij detection) forces the fallback. - Added
CMUX_SURFACE_IDenvironment variable support togetTerminalId(), so cmux terminal surfaces get a stable identifier alongside kitty, tmux, macOS Terminal.app, and Windows Terminal — enabling per-surface session breadcrumbs foromp -cin cmux.
Changed
- Changed TUI tests to use Ghostty's VT engine (
ghostty-web) instead of@xterm/headless. - Changed the default inline-image live graphics budget from 3 to 8 images.
Fixed
-
Fixed the DECCARA background-fill optimizer rejecting or repainting the wrong cells when a trailing fill crossed from default-background spaces into colored spaces.
-
Fixed DEC private-mode reports with DECRPM status 3/4 being treated as unsupported, so permanent 2026/2048 reports stay recognized.
-
Fixed OSC 66 text-sizing width and slicing edge cases, including ZWJ emoji payloads and partial slices through scaled spans.
-
Fixed focused
Inputcomponents followingTUI#setShowHardwareCursor, so single-line prompts render either the terminal cursor or software cursor consistently with the editor. -
Fixed the DECCARA background-fill optimizer painting fills on the wrong rows ("split into unaligned halves") in the differential repaint path. When a diff grew the transcript past the viewport, writing the rewritten rows scrolled the terminal, but the absolute DECCARA rectangle coordinates were derived from the pre-scroll viewport top, so every fill landed
scrollAmountrows too low while the relatively-positioned text settled correctly; rows scrolled into history were also shortened, dropping their background padding from native scrollback. Rectangles now target the post-scroll rows and only rows remaining in the final viewport are optimized. -
Fixed native scrollback desynchronization after terminal width or height changes reflowed overflowing content while the viewport was not at the bottom
-
Fixed a notification chip (or any injected block) rendering on top of an actively streaming tool render on ED3-risk terminals (Ghostty/kitty/Alacritty/iTerm2). While a foreground tool streams, its header's elapsed-time counter ticks every frame; once output scrolls the header above the viewport top, each tick is an offscreen edit that — because the eager scrollback-rebuild opt-in is gated off on these terminals — repaints the viewport in place and advances the rendered line count without committing the new overflow to native history.
#scrollbackHighWaterthen lagged the logical viewport top, so a later content shrink whose changes landed in the visible region slipped past the shrink-across-boundary guard and reached the differential emitter, which is anchored to#maxLinesRendered - height: it rewrote only the suffix, dropped the newly exposed top row, and left a blank at the bottom, drifting every row below the edit one line up so it painted over the rows above. Such shrinks now re-anchor the bottom of the viewport with a non-destructive repaint, and the foreground-streaming shrink-across-boundary case repaints the live tail instead of padding and pinning the pre-shrink viewport. -
Fixed a terminal resize during foreground-tool streaming on an unknown-viewport / ED3-risk host (Ghostty/kitty/Alacritty/iTerm2/WSL) leaving native scrollback permanently out of sync, so scrolling back after the turn showed missing rows. A pure geometry resize (no content change) takes the in-place viewport-repaint path, which — unlike a content-bearing resize that rebuilds via the geometry branch — never flagged native history. Because the prompt-submit checkpoint (
refreshNativeScrollbackIfDirty) only rebuilds when scrollback is marked dirty on these hosts, the discrepancy was never reconciled. Overflowing geometry repaints whose viewport is not known to be at the bottom now mark scrollback dirty so the next checkpoint rebuilds an exact copy of the transcript.
@oh-my-pi/pi-utils
Added
-
Added color helpers
colorLuma(perceptual luma),relativeLuminance(WCAG, linearized sRGB), andhslToHexto the color utilities. The luminance helpers parse#rgb/#rrggbbhex and 256-color palette indices, returningundefinedfor unparseable values. -
Added
peekFileEnds, a single-open head-and-tail file peek helper that reuses the head bytes for the tail when the file fits the head window. -
Added
peekFileTail, the tail mirror ofpeekFile: reads up to the lastmaxBytesof a file ending at EOF, reusing the same pooled-buffer strategy (no per-call allocation for small reads).
What's Changed
- fix(search): default paths to workspace root instead of hard-failing by @GratefulDave in #1808
- fix: recognize disable-model-invocation from Agent Skills spec by @fabkho in #1803
- fix(coding-agent/mcp): handle async broken-pipe rejections in stdio transport by @VoidChecksum in #1783
- Fix slow agent Opus priority by @daandden in #1754
- fix(swarm): remove redundant authStorage discovery from swarm pipeline (#1472) by @WodenJay in #1726
- Fix web search provider TUI options by @daandden in #1685
- Add cmux terminal surface detection to getTerminalId by @basedcorp99 in #1702
- fix(natives): bound sorted glob scans by @roboomp in #1762
- fix(tui): cap session accent luminance on light themes by @paweljw in #1715
- feat(coding-agent): env-driven OTLP trace export for headless hosts by @cgreeno in #1797
New Contributors
- @GratefulDave made their first contribution in #1808
- @fabkho made their first contribution in #1803
- @WodenJay made their first contribution in #1726
- @paweljw made their first contribution in #1715
- @cgreeno made their first contribution in #1797
Full Changelog: v15.8.3...v15.9.0