@oh-my-pi/pi-agent-core
Changed
- Deprecated
createFileOps,computeFileLists,formatFileOperations,upsertFileOperations,isUrlSchemePathandFileOperationsin@oh-my-pi/pi-agent-core/compaction; they now re-export@oh-my-pi/snapcompact, which callers should import directly
Fixed
- Context estimates for a model without a known tokenizer family (Gemini, Grok and the like), and token counts made without a model (compress metrics, the legacy
estimateTokensexport), count text in o200k_base instead of guessing 4 bytes per token, which undercounted what those providers bill by 11–48% on code-heavy sessions and let compaction fire late after a switch to them (#17607 by @will-bogusz) - Context estimates no longer charge a reader another model's thinking signatures or redacted thinking, which the request strips: a Claude session switched to Grok or Gemini, including Gemini through Factory, counted them as text (#17607 by @will-bogusz)
Removed
- Removed
PI_TOKENIZER_ACCURATE: every model is now counted with a native tokenizer (#17607 by @will-bogusz)
@oh-my-pi/pi-ai
Added
/login mistralsigns in through the browser like the Mistral Vibe CLI and stores the minted API key, whose usage counts against the plan's Vibe Code quota instead of pay-as-you-go API credits;MISTRAL_API_KEYstill works (#13875 by @Gauthier-Huguenin, continued in #17672 by @abilliontokens)- Added
dropsForeignReasoningPayload(turn, model), which tells whethertransformMessagescertainly strips a turn's thinking signatures and redacted thinking on the way tomodel, and, for Factory Droid's Gemini wire,isFactoryDroidGeminiWire(model)andkeepsFactoryGeminiReasoning(turn)(#17607 by @will-bogusz) - Factory Droid Beam 1.0 requests accept tool-call turns that arrive without reasoning (#17766 by @will-bogusz)
Changed
- Deprecated
formatErroron the embeddings, images, rerank, speech, transcriptions, video, pi-native and SystemOne server modules (now aliases ofcodedErrorResponse/noStoreErrorResponseinauth-gateway/http) andasStrictinproviders/aws-sigv4(nowasStrictBytesfrom@oh-my-pi/pi-utils)
Fixed
- Fixed Factory Droid Fable requests offering Opus 5 as the refusal fallback when your organization's model policy excludes Opus 5; Claude requests now offer only fallback models your account can use, and a request served by another organization's login than the one your model list came from offers none (#17772 by @will-bogusz)
@oh-my-pi/pi-catalog
Added
/login mistralnow offers the Mistral Vibe browser sign-in besideMISTRAL_API_KEY(#13875 by @Gauthier-Huguenin, continued in #17672 by @abilliontokens)- Added
revisionAtLeasttocompat/revisionand exportedwithOpenAICompatibleDiscoveryTimeoutfromdiscovery/openai-compatible - Added the Factory Droid models droid 1.1.0 serves: GPT-6.1 Terra, GPT-6 Sol and Luna Fast Mode, GPT-6 Astra and GPT-6.1 Sol Ultra Fast (after the organization's high-cost opt-in), Nemotron 3.5 Super, Muse Spark Open, Muse Spark 1.2 and Beam 1.0, each listed once the account may use it (#17766 by @will-bogusz)
- Added Factory Droid's dated credit rates: the credit rate follows Factory's promotions, discounted from a promotion's start and back to the base rate at its end, using the same dated rate cards as dollar prices (currently GPT-5.6 Sol and Gemini 3.7/3.8 Flash) (#16309 by @will-bogusz)
Changed
- Factory Droid lists Opus 5.5 Fast, GPT-6.1 Sol and MiniMax M3 without the feature flags Factory retired, and no longer routes GPT-5.5 to Snowflake (#17766 by @will-bogusz)
- Factory Droid Opus 5.5 now falls back to Opus 5 when Anthropic refuses a request, as droid does, while your account can use Opus 5 (#17772 by @will-bogusz)
Fixed
- GPT-3.5 and GPT-4 (Turbo) resolve the
cl100ktokenizer, so their context estimates count in cl100k_base rather than the o200k_base default for models without one (#17607 by @will-bogusz) - Added Scaleway Generative APIs as a built-in provider with 12 serverless chat models (glm-5.3 default), API-key login, and live model discovery (#16687 by @reda-maizate)
@oh-my-pi/pi-coding-agent
Added
- With the Hindsight memory backend,
retainandlearncan now store a memory withscope: "global"so every project recalls it. It is opt-in through the newhindsight.globalScopesetting (off by default) and needsglobalorper-project-taggedscoping (#17706 by @alphastorm, from #15030 by @kithawk). - Added
btw.inject(off by default;/settings→ Interaction → "/btw Steering Inject"): when you ask/btwfor a steering prompt, it drafts one in an<inject>block shown behind a pink rail, andAlt+I(app.btw.inject) sends it to the main session (as a steer while the agent runs, else as a new turn) from the inline answer or the BTW history sheet, once per answer from the current run. Once sent, the block turns green with➤on each line and "Injected into main session" below it; if the main session drops or refuses the send, the block turns back to pending and the same key retries (#17618 by @apullin) - With OTLP metrics export configured (
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT), composer predictions export content-freeomp.composer.prediction.*metrics by serving model: requests by outcome (offered, skipped, stale, cancelled, timeout, error) with their duration, predictions shown (counted on the first frame that paints them), shown predictions by whether they were accepted with Tab or Right, and the time from first display to acceptance (#17739 by @wolfiesch) - Bash results the output minimizer rewrote now keep which filter ran and the bytes before and after in the session, and the bash card shows them (
Minimized: git 120.4KB → 3.2KB) (#16586 by @will-bogusz) - Eval completion handles expose
attempts(JSawait handle.attempts(), Pythonhandle.attempts): each fallback candidate tried, in order, with the model, the reasoning effort sent, its outcome, and the error when it failed (#17782 by @xiangnan0811) - Added
composer.predictionAlternatives(off by default;/settings→ Interaction → "Prediction Alternatives", listed while Composer Predictions is on): the same single prediction request returns up to four different next messages, most likely first. Type a few letters to get ghost text for the first one that matches; after inserting one, press Tab again to pick another from a list. Prediction metrics carry how many alternatives were offered (omp.composer.prediction.choices), and an accepted prediction now resolves when it retires, with the rank of the alternative inserted last (omp.composer.prediction.rank) (#17796 by @wolfiesch) /reviewand/annotate code-reviewwork from a folder of checkouts:/review owner/repo#123reviews a GitHub PR from anywhere;/review ./repo [#123 | !7] [focus]reviews in that checkout (#Na GitHub PR,!Na GitLab MR); and outside any repository, the local and open-PR menu choices ask which child repository to use
Changed
/resumeandomp --resumeopen at once on your titled sessions (read from~/.omp/agent/history.db), then fill in prompts, status, and untitled sessions when the full scan finishes; the first scan saves older sessions' titles too, so later opens list them right away- With
symbolPreset: ascii, status glyphs are three columns wide ([+],[-],[#],[ ]) and status spinners animate as[|] [/] [-] [\](#17732 by @JustasMasiulis) - The subagent HUD marks each running agent with the running status glyph instead of a dot (#17732 by @JustasMasiulis)
Fixed
- Browser:
browser.close({ all: true })from a subagent no longer closes its parent's tabs; it releases only the calling agent's tabs. Tabs now belong to the agent that opened them rather than its conversation id, so after/new,/resume, fork, or branch they are still frozen, idle-closed, released by close-all, and closed when the session ends instead of leaking (#15975, #16133 by @harshaygadekar) lsp requestnow sendspayload: "null"as JSON null instead of substituting auto-built document params (#17715).- A prompt rejected before a turn starts because its model or credential is missing returns to the editor for retry;
./con an empty conversation reports that there is nothing to resume (#17828). - Factory Droid requests keep attached images and snapcompact system-prompt frames when tools carry large runtime state (#17819).
pr://<n>,issue://<n>, and repo-lessgithubtool calls in a checkout whoseupstreamremote is not the fork parent oforiginnow resolve toorigininstead of the upstream project;gh repo set-defaultstill winsomp -ptext mode now prints each automatic retry with its error (for example "Couldn't reach api.anthropic.com … check your network") instead of showing onlyWorking...while a turn retries (#17529 by @Mannan-Goyal)omp --exportand/exportno longer fail withError: Out of memoryon large sessions with subagent transcripts, and use far less memory: the HTML is now streamed to disk instead of built as one string (#17741)- A native
security_scanwithasync.enabledon (the default) now waits for its backgroundsecurity-reviewerworkers and publishes their findings, instead of endingpartialwith 0 findings and "The scan session ended without publishing a canonical result" (#17788) - Browser (Chrome tabs): a click or drag cancelled before its final release now releases off-page instead of completing on its target, and the page sees no click from it (not even on the document root), a timed-out key combo sends no further key, and a call or run cut off mid-gesture releases the mouse button or keys it held instead of leaving them down in the tab. Input already dispatched to Chrome, including a target release, cannot be recalled and may still take effect after timeout (#17778 by @will-bogusz)
- Relay mode:
tab.waitForSelector,tab.evaluateandtab.gotono longer fail after 20 s when the page or server takes longer; like on a launched Chrome they now run to the call's own timeout, up to omp's 60 s protocol timeout, and a command Chrome never answers names itself and its tab (#17778 by @will-bogusz) - Fixed browser
tab.click(selector, { button, count })andframe.clickignoring their options and left-clicking once, so a right-click meant to open a context menu clicked the element instead; cmux tabs refuse buttons and counts they cannot press (#17767 by @will-bogusz) - Browser
fillin Chrome no longer sometimes puts the new text in front of a Slate editor's old text when the machine is busy, and refuses a rich-text editor whose focus moves to a wrapper or the page instead of reporting success (#17742 by @will-bogusz) - Fixed a browser relay call working in a cross-site frame (an embedded sign-in form, say) failing with a bare
Target closedwhen Chrome detached omp from the tab; it now says Chrome detached omp and whether the tab was reattached, as a call in the page itself does (#17768 by @will-bogusz) - Browser tabs omp opens with
persist: truein your Chrome through the relay now stay open when the session ends (anomp -prun exits, a subagent finishes), so a page left for you is still there; other tabs omp opened still close, and an explicit close racing session cleanup still closes its page (#17751 by @will-bogusz) - Fixed keys you type in another app going into a page on macOS when omp's click in a relay tab opened a new tab or popup (#16284 by @will-bogusz)
- Parked subagents keep their
xd://device mounts when woken after omp restarts, so they no longer lose their earlier Claude thinking (#17746 by @will-bogusz) - Fixed cancelling
%pipin Python eval leaving the installer process behind in Linux containers and chroots without a usable/proc(#16552 by @will-bogusz) - Fixed numbered
readpages of files with very long lines ending after a few KB: a line cut totools.outputMaxColumnsnow counts the width shown, not its full length, against the page size, so paging no longer stops before such a line or refuses to step past it. When the first cut line is larger than a:rawread returns, the cut notice names that byte cap, and a multi-range read that the page size stops partway through a range says where to continue (#16595 by @will-bogusz) - Fixed
writeaccepting the output of areadwhose long lines were cut totools.outputMaxColumnsand overwriting the file with the cut lines; it now refuses it as an incomplete read, as it does for other truncated reads (#16595 by @will-bogusz) - Fixed a session resumed, or a parked subagent woken, on a later day resending its first message with that day's date, which made Claude drop all of its earlier thinking and missed the prompt cache; earlier messages now keep the date they were sent with (#15343) (#17622 by @will-bogusz)
models.ymlacceptstokenizer: cl100kon a custom model or override (#17607 by @will-bogusz)- Claude no longer receives the reasoning kept in a snapcompact archive whose summary an extension wrote without the reasoning legend, with or without image input, and reads that summary's own words instead of a generic one (#17745 by @will-bogusz)
- Fixed
~/.omp/agent/agent.dbgetting corrupted (wiping stored logins) on Linux when grep,read, the bash tool, extensions or eval read it while omp has it open;writeandttsnow refuse to overwrite a database omp holds open (#15586)
@oh-my-pi/pi-natives
Added
- Added
macOSFrontApp(), which reads the app macOS has in front and can put it back in front for a while (keepInFront) without stopping for the user's typing (#16284 by @will-bogusz)
Fixed
- Fixed iPhone Mirroring clicks, scrolls and keys reporting success while the mirror showed a connection screen such as "iPhone in Use" instead of the phone; they now fail and quote that screen (#17755 by @will-bogusz)
parseKey/matchesKeynow recognize the parameterlessCSI P/CSI Q/CSI S(andCSI 1 <letter>) forms that kitty-protocol terminals such as Ghostty send for unmodified F1/F2/F4, and modified F2–F9 no longer match other keys (e.g. Ctrl+PageDown as Ctrl+F8) (#17812).- Added
installSqliteLockShim()(Linux), which moves Bun's SQLite record locks onto open-file-description locks that no other close of the file releases, andheldFileKind(path), which reports a file this process holds open and locked. Both are also on@oh-my-pi/pi-natives/sqlite-locks, which loads the addon on first call (#15586)
@oh-my-pi/snapcompact
Added
- Added
archiveIncludesThinking(), whether a compaction may replay reasoning from its summary's legend or its archive's text, andviewSummary(), which keeps a summary the template did not write in its own words, followed by the template's guide to the view's text (#17745 by @will-bogusz)
Fixed
- Fixed
viewWithoutFramesandviewWithoutThinkingkeeping an archive's reasoning for a reader without it when the summary (say, one an extension wrote) declares no¶think:scope, and replacing such a summary with the template's (#17745 by @will-bogusz)
@oh-my-pi/omp-stats
Fixed
- Fixed Stats staying at an empty snapshot when the final ingest update arrives during an in-flight dashboard request (#17754).
@oh-my-pi/pi-tui
Breaking Changes
buildExecutionFramesets its loader into the newbottomBorderitself, so callers no longer add it as a row and must dispose it;buildStatusFooterno longer takesstatusorexitCode, andexecutionStatusLabelreturns a settled run'sexit N/cancelledmarker for that border (#17732 by @JustasMasiulis)SessionSelectorOptions.loadAllSessionsandSessionPickerHost.loadAllSessionsresolve to aSessionListing, andallSessionstakes one, so the all-projects scope can show preliminary rows before its complete listingEditor.predictionis replaced byEditor.predictions, which returns every prediction for the next prompt, most likely first, andEditor.onPredictionAcceptedreceives the inserted prediction's index in that list (#17796 by @wolfiesch)
Added
SessionSelectorOptions.completeSessions(andSessionPickerOptions.completeSessions) replaces the picker's preliminary rows with the complete listing once it settles, keeping the query, the selected session, and deletes/renames made meanwhile/btwanswers can show a steering prompt as a block behind a pink rail (a toned card in Tern) thatAlt+I(app.btw.inject, remappable) sends to the main session; once sent it turns green with➤on each line, without moving (#17618 by @apullin)- Added
singleLineandfiniteWidthtoutilsfor row-confined text and cell widths Loader.inlineText()returns the current spinner frame and message as one styled line, andDynamicBorder.setLabel()sets a label (or a function re-read every render) into the rule (#17732 by @JustasMasiulis)
Changed
- The ASCII symbol preset's status glyphs are all three columns wide: success is
[+], error[-], aborted[#]and pending[ ](alongside[~]running,[!]warning and[i]info), and status spinners animate as[|] [/] [-] [\](#17732 by @JustasMasiulis) - Built-in renderers no longer use
status.done,theme.status.doneor thedonevalue ofToolUIStatus; they remain as aliases ofstatus.success/success(an explicitsymbols.overrides["status.done"]still applies totheme.status.done) (#17732 by @JustasMasiulis) - Every finished state shows the success glyph (
✔, ASCII[+]). Task rows, verdicts and headers, background-job, launch and supervised-process rows, Eval cells, Vibe, Wait and process job rows, Yield and the generic tool card showed a separate•done dot, and a finished Read showed●(ASCII[x]). Live Task agent rows show the pending or running glyph, and a Task whose merge failed shows the warning glyph (#17732 by @JustasMasiulis) - Edit and Write animate their streaming spinner in the card header, as Eval does, and show their
preview/streaminglabel in the card's bottom border instead of on a row below the content;streamingends once the content has fully arrived (#17732 by @JustasMasiulis) !shell and$Python runs show their spinner, and thenexit Norcancelled, in the frame's bottom border instead of on rows of their own; the spinner is the status spinner tool headers use (#17732 by @JustasMasiulis)- GitHub run-watch job rows use the shared status glyphs: a running job shows the running glyph instead of a warning-colored dot, a queued job the pending glyph instead of a hollow circle (a job in a state omp does not recognize keeps the circle), and a passed job's glyph is green like other success glyphs. Ask's multi-line custom answer lines up under its first line in every symbol preset (#17732 by @JustasMasiulis)
Fixed
- An LSP result other than diagnostics, such as a raw
requestresponse, that contains the error glyph (✘, ASCII[-]) is shown as a response instead of as diagnostics reading "No issues" with the rest of its lines dropped (#17732 by @JustasMasiulis) Editor.onPredictionAcceptedandEditor.onPredictionShownreport when Tab or Right inserts the rest of the composer prediction and when a frame paints it (at least one cell in the terminal, or the ghost on a native editor node) (#17739 by @wolfiesch)- Added
OutputMeta.minimized(bash minimizer filter, raw and minimized byte counts, raw-output artifact), shown as aMinimizedfact on bash result cards (#16586 by @will-bogusz) - Added
isColumnTruncationNoticeandhasColumnTruncationClausetotools/output-meta, matching the[Some lines truncated to …]clause thatformatOutputNoticeemits alone or inside a longer notice, andLimitsMeta.columnTruncated.rawByteCap, which makes that notice name the byte cap a:rawread of the first cut line stops at (#16595 by @will-bogusz) - Fixed the model browser showing Factory Droid's undiscounted credit rate during a Factory promotion (2× instead of 1.6× for GPT-5.6 Sol); rows now show the rate in force and the model details show the next rate and its date (#16309 by @will-bogusz)
- With two or more
Editor.predictions, the ghost text follows the first one the draft is a prefix of; a typed draft that equals a shorter one keeps the ghost of a longer one. Once the buffer equals one of them with no ghost (always right after Tab, Right, or the list inserts one), a dim⇥ N morehint appears; press Tab to list them all, then Enter, Tab or Right to swap the whole line (never submitting) or Esc to keep it (#17796 by @wolfiesch) - F2 now opens the rename dialog in the resume picker in Ghostty, kitty and other terminals using the kitty keyboard protocol; F1 and F4 shortcuts work there too (#17812).
- Added
Component.nativeTrailers(), which lets a transcript block add native blocks of its own directly after it. Trailing blocks stay visible while the block is collapsed.
@oh-my-pi/pi-utils
Added
- Added
isPidAlive(signal-0 liveness probe) andasStrictBytes(aUint8Arraynarrowed to its ownArrayBufferfor WebCrypto) - Added
ensureSqliteLockShim(), whichopenSqliteDatabase/openSqliteDatabaseSynccall before opening a store, so on Linux the process's SQLite locks are open-file-description locks that other closes of the file cannot release (#15586) - Added
assertNotHeldOpen(path)(@oh-my-pi/pi-utils/held-file), which throwsEBUSYfor a SQLite database or-shmthis process holds open (#15586)
Changed
acpruntime validators (zNewSessionResponse,zSessionNotification, …) now report each failing field's path and reason inerror.issuesinstead of a singleInvalid <label>;ValidationErrorissue paths are typedPropertyKey[](#17699)
@oh-my-pi/pi-wire
Added
- Added the collab envelope helpers
packEnvelope,unpackEnvelopeandrewriteEnvelopePeer
What's Changed
- feat(coding-agent): inject /btw steering prompts into the main session by @apullin in #17618
- feat(auth): add Mistral Vibe browser sign-in to /login mistral by @abilliontokens in #17672
- refactor: replace hand-rolled schemas and validators with omptype by @H4vC in #17699
- refactor: replace duplicated helpers with existing shared implementations by @H4vC in #17704
- fix(coding-agent): show retry errors in text print mode by @Mannan-Goyal in #17529
- feat(coding-agent): let retain and learn write global memories with Hindsight (supersedes #15030) by @alphastorm in #17706
- feat(coding-agent): export composer prediction OTLP metrics by @wolfiesch in #17739
- feat(catalog): add Scaleway Generative APIs provider by @reda-maizate in #16687
- feat(eval): expose completion fallback attempts on handles by @xiangnan0811 in #17782
- feat(coding-agent): offer up to four composer prediction alternatives by @wolfiesch in #17796
- fix(coding-agent): stop the %pip installer on cancel when /proc cannot be listed by @will-bogusz in #16552
- feat(coding-agent,tui): show which bash minimizer filter ran and how much it cut by @will-bogusz in #16586
- fix(agent): count models without a known tokenizer in o200k, and skip thinking signatures the request strips by @will-bogusz in #17607
- fix(coding-agent): keep each message's date across resume and subagent revival by @will-bogusz in #17622
- fix(browser): stop rich-text fill landing before the old text or outside the editor by @will-bogusz in #17742
- fix(snapcompact,coding-agent): drop an archive's reasoning when its summary declares none by @will-bogusz in #17745
- fix(task): keep a cold-revived subagent's xd:// devices mounted by @will-bogusz in #17746
- fix(browser): keep persist relay tabs open when the session ends by @will-bogusz in #17751
- fix(natives): refuse iPhone Mirroring input while the mirror is not showing the phone by @will-bogusz in #17755
- feat(ai,catalog): add the Factory Droid models droid 1.1.0 serves by @will-bogusz in #17766
- fix(browser): press the button and count tab.click and frame.click are asked for by @will-bogusz in #17767
- fix(browser): report Chrome's relay detach to a call running in a cross-site frame by @will-bogusz in #17768
- feat(ai,catalog): give Factory Droid Opus 5.5 the Opus 5 refusal fallback by @will-bogusz in #17772
- fix(browser): stop later input steps after timeout and let relay page waits use the call deadline by @will-bogusz in #17778
- fix(browser): keep the user's app in front when omp's relay tab opens a popup on macOS by @will-bogusz in #16284
- feat(catalog,tui): show Factory Droid credit promotions in the model browser by @will-bogusz in #16309
- fix(coding-agent): charge column-cut lines their shown width against the read page budget by @will-bogusz in #16595
- fix(tui): restored f2 rename under kitty keyboard protocol by @roboomp in #17814
- fix(natives): kept SQLite locks across in-process closes with OFD locks by @H4vC in #17833
- fix(security): settled background reviewer jobs before ending scans by @roboomp in #17790
- fix(session): counted declared tools for image budgets by @roboomp in #17822
- fix(session): restored prompts rejected before dispatch by @roboomp in #17830
- fix(export): streamed html export payload to disk by @roboomp in #17744
- fix(stats): recover live updates after in-flight overview settles by @roboomp in #17758
- fix(lsp): preserved literal null request payloads by @roboomp in #17719
- fix(browser): scope close all tabs to calling session (#15975) by @harshaygadekar in #16133
- feat(tui): consistent status glyphs, colors and placement by @JustasMasiulis in #17732
- feat(review): reviewed PRs and checkouts from outside a git directory by @H4vC in #17854
New Contributors
- @apullin made their first contribution in #17618
- @Mannan-Goyal made their first contribution in #17529
- @reda-maizate made their first contribution in #16687
Full Changelog: v18.15.0...v18.16.0