@oh-my-pi/pi-ai
Added
- Exported
renderDelimitedThinkingfrom the@oh-my-pi/pi-ai/dialectbarrel so consumers can reuse the dialect's<thinking>envelope unwrap-and-rewrap logic (the only./dialect/renderingprimitive re-exported; the rest stay dialect-internal).
Fixed
- Fixed OpenAI Responses/Codex tool schema normalization stripping provider-rejected regex lookaround patterns from MCP tool parameter schemas. (#2784)
- Fixed OpenAI Responses parallel tool-call routing so late keyed argument deltas for a closed call are dropped instead of being appended to another open call.
@oh-my-pi/pi-coding-agent
Added
- Added support for LaTeX color commands (
\textcolor,\colorbox, and\fcolorbox) in user-visible terminal prose and final chat to colorize output
Changed
- Changed STT dependency setup to validate recorder and model assets per
stt.modelName, so switching speech models re-runs dependency checks and downloads for the new model - Changed STT startup with cached models to warm the speech model in the background and defer full model loading until transcription begins, reducing push-to-talk start latency
- Allowed user-visible terminal and final-chat responses to include LaTeX math delimiters/commands and Mermaid
```mermaiddiagrams - Changed the hold-
Spacepush-to-talk gesture to recognize a held bar from the regularity of the OS key auto-repeat rather than a raw space count or speed alone, so it no longer spams the editor, no longer eats deliberate space taps, and no longer triggers when the bar is smashed. Recording starts only after two consecutive inter-space deltas are "mechanical" — both fast (within ~120 ms) and near-identical, the metronomic signature of auto-repeat; the few pre-burst spaces typed are then tracked back out. Smashing (fast but jittery) and deliberate spacing (steady but slow) both keep typing real spaces and never start recording. - Updated markdown Mermaid rendering to color ASCII diagrams with the active theme and automatically choose a narrower layout that better fits the terminal width
- Made the watched-session transcript sent to the advisor (and shown by
/advisor dump) clearer: each turn now opens with a### Session updateheading; watched-agent roles render as inline**agent**:/**user**:labels instead of level-2 headings that collided with the advisor's own turns; consecutive same-role messages collapse under one label (the watched agent emits one assistant message per tool call); and batched updates are joined by a blank line rather than a---rule. - Changed the compact transcript tool-intent prefix (
history://,/advisor dump) from#to//so intent lines read as comments instead of rendering as Markdown H1 headings. - Changed the advisor advice injected into the primary transcript from a
Advisor (...): - [severity] noteprose block to one<advisory severity="…" guidance="weigh, don't blindly obey">…</advisory>element per note, with XML-escaped bodies. (Relocated the sharedescapeXmlTexthelper to@oh-my-pi/pi-utils.) - Reverted
/dumpand/advisor dump rawto the pre-16.x full verbose dump: system prompt, model/thinking config, tool inventory with parameters, and the message transcript rendered with markdown role headings (## User,## Assistant,### Tool Call: <name>with the call's_iintent as a//comment under the heading and the remaining arguments as a fenced YAML block,### Tool Result: <name>, plus## Bash Execution/## File Mention/summary sections) instead of the model's native-dialect turn envelopes and<invoke>/<parameter>XML tool calls. Dropped the compact default and the[raw]flag on/dump; the compact→ tool(...) ⇒ okhistory format is no longer reachable from/dump./advisor dumpstill defaults to compact, and/advisor dump rawnow renders the same markdown dump (previously the model's native-dialect envelopes).
Fixed
- Fixed Whisper STT cache detection to require both encoder and decoder
.onnxfiles, so partial model downloads now trigger a proper foreground download instead of being treated as fully cached - Fixed same-process
JsRuntimecleanup so disposing an older inline/direct runtime no longer deletes a newer runtime's JS helper globals; inactive cmux/direct runtimes now re-activate their globals before sequential use while overlapping cross-runtime runs fail explicitly. - Fixed magic-keyword steering notices (
ultrathink-notice,orchestrate-notice,workflow-notice) to be prepended before the related user message so they influence that same turn - Fixed dequeuing or popping queued user messages to remove their preceding hidden magic-keyword notice companions, preventing orphaned queued notices
- Fixed queued user steers to auto-resume after interrupts even when the transcript tail is a preserved advisor card or other non-conversational custom message
- Fixed queued user follow-up messages to remain queued after an interrupt and only run on explicit resume, even when an IRC wake leaves a provider-valid tail
- Fixed stranded IRC asides to wake a response turn after interruption instead of remaining pending
- Fixed accepted IRC asides to be flushed into the transcript during disposal instead of being discarded
- Fixed interactive submissions made while the TUI had no active input waiter: they now start a real prompt directly, with steer fallback if a background turn races in, instead of queueing behind a non-resumable idle transcript and appearing to do nothing.
- Fixed pressing Esc (or Alt+Up dequeue) while agent-authored messages were queued — advisor concern/blocker notes, hidden goal/plan/budget steers, IRC/extension asides — dumping their text into the user's editor. Editor restoration (
clearQueue()), pending chips (getQueuedMessages()), andpopLastQueuedMessage()now surface only genuinely user-authored queued messages (plain user turns andattribution: "user"custom messages like/skill). Plain Alt+Up dequeue leaves all other queued messages in place for the continuing stream; only the Esc interrupt path keeps just advisor cards (so abort's preservation still re-records them as visible advice) and drops other internal steers, so a user interrupt can't be silently undone by an auto-resume on leftover internal context.queuedMessageCountstill reflects all actual queued work (advisor cards included) sohasPendingMessages()/RPC and the empty-submit abort gate stay accurate. - Fixed advisor
concern/blockeradvice being withheld from the running agent and then dumped as one burst at the next user prompt after a deliberate interrupt. A user interrupt latches advisor auto-resume suppression, but a non-user resume (synthetic/auto-continue, or a queued steer draining after the abort) leaves the run streaming with that latch still set, so every interrupting note was parked hidden in the next-turn queue instead of steered into the live turn — the agent never heard the advisor mid-run and the backlog flushed all at once on the next prompt. Suppression now only withholds interrupting advice while the agent is idle (or still tearing the interrupted turn down); once a turn is streaming again the note is steered in live, since steering an active run never auto-resumes a stopped one. A concern that strands in the steer queue past the resumed turn's final poll is reclaimed as visible advice when the agent settles (mirroring abort), so it neither auto-resumes the stopped run nor lingers to flush at the next prompt. - Fixed
omp --continue/-csometimes resuming into a subagent transcript instead of the interactive session. Subagent (and HTML-export)SessionManager.open()calls run in the parent's terminal and were clobbering the per-TTY--continuebreadcrumb with their own artifact-dir session file; these headless opens now suppress the breadcrumb.continueRecent()also recovers already-poisoned breadcrumbs by resolving any session file inside a parent's artifacts dir (<parent>/<agentId>.jsonl) back up to the top-level session. - Fixed the Agent Hub stacking duplicate
Agent Hub · N runningframes and stranding garbage rows in scrollback while navigating with subagents still streaming. The hub was a non-fullscreen overlay composited over a live transcript, so each time a running subagent's progress grew the frame and scrolled the window the previously-painted hub copy was pushed permanently into the terminal's native scrollback (which the engine can't rewrite). It now renders inline in the editor slot — the same anchored region every other selector and theasktool use — riding the normal append-only commit path, so the transcript commits above it exactly once and the hub repaints in place instead of leaking copies. (Avoids borrowing the alternate screen.) - Fixed every subagent registering itself as its own parent in the agent registry (
parentId === id), so the Agent Hub rendered each agent assub · of <itself>and the ←← parent-navigation gesture looped on the same agent. The SDK was reusingparentTaskPrefix— the agent's own artifact/output-id prefix — as the registry parent link; spawns now pass a separateparentAgentId(the spawning agent's id:Mainfor top-leveltaskspawns, the parent subagent for nested spawns and evalagent(), the focused agent for/tan) and the registry records that as the parent. - Fixed messaging a
parkedsubagent that was restored from disk (Agent Hub scan, or a resumed/restarted session) failing withcannot be revived (no reviver registered)even though its transcript was intact. Such refs carry a session file but no in-memory reviver — the executor's live reviver closure dies with the spawning turn/process — so IRC sends and Agent Hub focus refused them.AgentLifecycleManager.ensureLivenow cold-revives them through a persisted-subagent reviver factory (installed by the top-level interactive/RPC session) that rebuilds the subagent from its JSONL the way--resumerebuilds a session: it reopens the file and replays it throughcreateAgentSession, but sources the runtime contract from a now-readablesession_initrecord (SessionManager.peekSessionInit) so tools, system prompt, output schema, and kind are restored rather than resurrected as a default top-level session.session_initnow also persists the effectivespawnsallowlist and read-summarization flag so a cold revive keeps the original capability surface (old files without them deny re-spawning rather than defaulting to wildcard). Isolated runs and pre-session_initfiles whose recorded workspace no longer exists stay transcript-only (history://). - Fixed the terminal window-title OSC writes (
setTerminalTitle/pushTerminalTitle/popTerminalTitle) leaking escape sequences to a developer's terminal duringbun test; they now skip when the terminal is headless (the test-runtime default), matching theProcessTerminalrender/probe suppression so interactive-mode tests no longer paint to the real terminal - Fixed empty CLI sessions being retained after opening
ompand exiting without a prompt (#2800). - Fixed
hooks/pre/*.tsandhooks/post/*.tsfiles discovered throughhookCapabilitybeing registered in discovery but never loaded into the extension runner, so theirtool_callhandlers now run without a manualsettings.jsonextensionsentry (#2796). - Fixed startup model fallback choosing the plain OpenAI
gpt-5.5provider before the Codex OAuth provider when both shared the same default model id, which could surface a misleading OpenAI 401 despite valid Codex credentials (#2807). - Fixed local auto-thinking classification for reasoning-capable tiny models by giving them the same safe answer budget as online reasoning classifiers, with a larger local floor for non-reasoning tiny models (#2808).
Removed
- Removed the built-in
render_mermaidtool and itsrenderMermaid.enabledsetting, so it can no longer be invoked directly
@oh-my-pi/collab-web
Removed
- Removed rendering support for the
render_mermaidtool from the web tool registry
@oh-my-pi/pi-tui
Added
- Added
\tfracsupport to stacked display-math rendering so it now displays as a vertical fraction inlatexToBlockoutput - Added markdown parsing for own-line display-math blocks (
$$...$$and\[...\]) and delimiter-free\begin{...}...\end{...}math environments so block equations render via LaTeX-to-Unicode - Added stacked rendering of display-math fractions (
\frac,\dfrac,\cfrac): the numerator is drawn over a horizontal bar over the denominator, with surrounding terms andalign/equation-style environment rows aligned to the bar. Triggered for own-line$$/\[blocks, bare\begin{...}environments, and a paragraph whose sole content is a single display-math span; inline$...$fractions stay single-line (½,(a+b)/c) - Added bare math auto-rendering in
renderMathInTextfor math-shaped lines and math environment blocks that omit$/\(delimiters - Added LaTeX-to-Unicode rendering for markdown math spans, converting
$$...$$,$...$,\(...\), and\[...\]into readable Unicode in Markdown output - Exported LaTeX conversion helpers from the package entrypoint so consumers can call
latexToUnicode,latexToBlock,renderMathInText,inlineMathSpanEnd, andisBareMathEnvironmentdirectly - Expanded LaTeX-to-Unicode conversion coverage for additional math fonts, delimiters, extensible arrows, layout environments, cancel/brace annotations, references, and AMS symbols
- Added ANSI color rendering for LaTeX
\textcolor, scoped\color,\colorbox, and\fcolorbox, including xcolor/CSS color parsing and truecolor/256-color terminal output - Added an optional
maxWidthparameter toMarkdownTheme.resolveMermaidAsciito allow diagram resolvers to fit ASCII output to the available content width
Changed
- Changed markdown math rendering to preserve multiline layout for display equations, keeping
\\row breaks as separate output lines (including inside list items)
Fixed
- Fixed
alignat/alignedat/gatheredatrendering inlatexToBlockso the required{n}preamble is not rendered as visible math content - Fixed math parsing to leave non-math LaTeX snippets (for example
\begin{itemize}) and fenced code blocks as literal text instead of rendering them as math - Fixed
renderInlineMarkdownto handle top-level display-math tokens so raw$$...$$delimiters are no longer leaked - Fixed inline math span detection so escaped dollars and currency-like patterns (such as
$5and$10) are not converted as math - Fixed Mermaid diagram rendering in Markdown code blocks to clip each ASCII line to content width before wrapping, preventing preformatted diagram rows from fragmenting
- Fixed fullscreen overlays losing keyboard focus to hidden prompt surfaces, which could make settings unresponsive while a background approval request was pending (#2789).
- Fixed
bun testruns inside a real terminal leaking TUI output:ProcessTerminalnow honors a headless test-runtime default, so frame paints,start()capability probes (OSC 11 / DA1 / kitty), the progress keepalive, notifications, and teardown escapes no longer reach the developer's terminal, and stdin raw mode is never engaged. Previously#safeWriteonly skipped on!process.stdout.isTTY, so a developer running the suite in an interactive terminal saw stray status/editor boxes and probe queries. Terminal-contract suites opt back into real I/O viasetTerminalHeadless(false)
@oh-my-pi/pi-utils
Added
- Added
escapeXmlTextutility to escape XML-significant characters&,<, and>in element body text - Added
isTerminalHeadless()/setTerminalHeadless()to centrally suppress real-terminal side effects (stdout escape/frame writes, stdin raw mode, CSI/OSC capability probes, SIGWINCH, window-title changes, emergency restore) under the test runtime. Defaults on whenbun testsetsNODE_ENV=test; terminal-contract tests opt out viasetTerminalHeadless(false)
What's Changed
- fix(tui): keep overlay focus above hidden prompts by @roboomp in #2795
- fix(coding-agent): load discovered hook factories by @roboomp in #2798
- fix(cli): skip empty session persistence by @roboomp in #2804
- fix(coding-agent): prefer Codex default auth by @roboomp in #2810
- fix(coding-agent): expand local auto-thinking classifier budget by @roboomp in #2814
Full Changelog: v16.0.2...v16.0.3