@oh-my-pi/pi-agent-core
Fixed
- Fixed remote compaction input trimming to use unlimited context when
model.contextWindowis unset
@oh-my-pi/pi-ai
Added
- Added
GITLAB_CLIENT_IDandGITLAB_REDIRECT_URIenv-var overrides for the GitLab Duo OAuth login flow so users running with their own GitLab OAuth application can replace the bundled credentials when GitLab rejects the bundledclient_id's redirect URI. SettingGITLAB_REDIRECT_URIalso disables the random-port fallback (strict OAuth providers reject mismatched URIs anyway). (#2424) - Added
AuthStorage.listStoredCredentials()andAuthStorage.removeCredential()for per-account credential management.
Changed
- Replaced the OpenAI SDK client usage in
openai-completions,openai-responses,azure-openai-responses, andopenai-codex-responseswith the new internalpostOpenAIStreamOpenAI-wire JSON/SSE transport
Fixed
- Fixed streaming providers to cancel upstream model requests when the client closes the response body, so interrupted SSE sessions stop instead of continuing in the background
- Fixed: provider request builders treat unknown
model.maxTokens(null) as "no model cap" instead of coercing to0viaMath.min; Anthropic falls back to the 64k Claude-Code cap for its requiredmax_tokens. - Fixed transient stream failures on OpenAI-compatible providers by retrying HTTP 408/429/5xx responses and transient network errors with Retry-After/quota-hint aware backoff
- Fixed SSE stream handling for OpenAI-compatible responses by parsing wire-level JSON frames directly and honoring
[DONE]termination - Fixed stream error handling for OpenAI-compatible providers by preserving structured HTTP status/headers and response body details from failed requests for retry and strict-tool fallback logic
- Fixed OpenAI-compat streams ending with a bare
finish_reason: "error"(gateways like OpenRouter reporting upstream failures, e.g. GeminiMALFORMED_FUNCTION_CALL) surfacing as a non-retryableProvider finish_reason: error. The reason is now mapped toProvider returned error finish_reason, which the session retry classifier recognizes as transient, so the turn auto-retries instead of stopping with a pinned error banner. - Fixed
SqliteAuthCredentialStore.open()crashing withSQLITE_BUSY_RECOVERY(errno 261) when severalomp --sessionpanes restore concurrently after an unclean shutdown:PRAGMA busy_timeout = 5000now runs as a standalone statement BEFOREPRAGMA journal_mode=WAL(the first lock-taking statement during WAL recovery), andopen()retries the BUSY family —SQLITE_BUSY,SQLITE_BUSY_RECOVERY,SQLITE_BUSY_SNAPSHOT,SQLITE_BUSY_TIMEOUT— with bounded exponential backoff. The exhausted-retry error message includes the DB path. ExportedisSqliteBusyError(err)for callers that need the same classifier (#2421). - Fixed MiniMax-M3 OpenAI-compatible streams rendering reasoning twice when the same chunk carried both
<think>…</think>content and structuredreasoning_content; structured reasoning now wins and cumulative MiniMax reasoning snapshots are collapsed to deltas. (#2433) - Fixed Gemini turns silently halting the agent when the model returned
finishReason: STOPwith only an empty (or whitespace-only) text part and no tool call — the well-known "empty response" failure. All Google surfaces (public Generative LanguagestreamGoogle, VertexstreamGoogleVertex, and Cloud Code Assistgoogle-gemini-cli/google-antigravity) now classify such a turn as empty via the sharedhasMeaningfulGoogleContentcheck and retry it up toMAX_EMPTY_STREAM_RETRIEStimes before surfacing an error. The Cloud Code Assist path previously had an empty-stream retry that never fired for this case (itshasContentflag counted an empty-string text part as content), and the public/Vertex path had no retry at all; the retry now emits a singlestartevent so no duplicate partial message leaks downstream.
@oh-my-pi/pi-catalog
Added
- Added bundled Fireworks models
deepseek-v4-flash,kimi-k2.7-code,minimax-m2.5,minimax-m3,nemotron-3-ultra-nvfp4,qwen3.6-plus, andqwen3.7-plus - Changed
Changed
- Model
contextWindow/maxTokensare nownumber | null; discovery emitsnullwhen a provider reports no limit, replacing the222222/8888(UNK_CONTEXT_WINDOW/UNK_MAX_TOKENS) sentinels (now removed). Bundledmodels.jsonunknown limits arenull. - Changed the
github-copilotmodel context window to524288tokens - Changed Fireworks model discovery to source the control-plane
List ModelsAPI (GET /v1/accounts/fireworks/models?filter=supports_serverless=true) instead of the OpenAI-compatible/v1/modelsinference listing. The inference endpoint returns a sparse, account-specific subset that omits on-demand serverless models (e.g.kimi-k2.7-code), so newly published serverless models stayed invisible in the picker until hand-added to the bundled catalog. The control-plane catalog enumerates every serverless model with capability metadata (supportsServerless/supportsTools/supportsImageInput/contextLength/displayName), paginated and filtered to tool-capableREADYentries, then merged with bundled/models.dev references — the Kimi K2 max-output clamp and DeepSeek V4 thinking-toggle strip are preserved, and unbundled models default to reasoning sobuildModelderives the Fireworks effort map. New serverless releases now surface automatically with no catalog edits.
Fixed
- Filled missing
contextWindowandmaxTokensin generatedmodels.jsonfor proxy/reseller variants by inheriting limits from canonical-family and segment-reference models - Ignored zero-cost
x-aisubscription entries as reference sources when backfilling limits so inflated values are not propagated - Fixed the model cache opening with
PRAGMA journal_mode=WALbeforePRAGMA busy_timeout, so concurrent omp startups could crash insidegetDb()onSQLITE_BUSYduring WAL recovery instead of waiting through the transient lock. The busy handler is now installed before the first lock-taking statement (#2421).
@oh-my-pi/pi-coding-agent
Breaking Changes
- Removed the top-level
--list-modelsflag path and migrated model listing to the newomp modelscommand
Added
- Added
omp modelscommand to list and manage models withls,find,canonical, andrefreshactions - Added
--jsonoutput plus-e/--extension,--no-extensions, and--configcontrols toomp modelslistings - Added
skills.enableAgentsUserandskills.enableAgentsProjectsettings (default on) so the canonical OMP-native~/.agent[s]/skillsand project-walkup.agent[s]/skillsare configurable independently from the third-party Claude/Codex/Pi toggles.
Changed
- Model registry merge and
omp models/ model picker handle unknown context/output limits (null) — unknown limits render as-instead of a fake222K/8.9K. - Changed
omp modelsto use cached provider data by default and requireomp models refreshfor a forced online re-fetch - Updated model-resolution errors to point to
omp modelswhen a provider or model is not found - Upgraded workspace catalog packages to their latest versions as of 3 days ago, and refactored the ACP agent implementation to be compatible with
@agentclientprotocol/sdkversion0.25.0. - Made the
zodversion requirement in the workspace catalog more tolerant (^4.0.0instead of4.4.3), and aligned type definitions in coding-agent extensibility modules. - Changed
/logoutto pick a stored account after the provider, so multi-account OAuth providers can remove one credential without logging out every account. - Changed the status-line context% to report the provider's real prompt-token count — anchored on the last assistant response, matching the
/contextpanel and the collab host broadcast — instead of an independent cl100k estimate of the whole conversation. The estimate could read several points high and climb past 100% on subscription/Codex models (whose advertised window, e.g.272K, is already the input budget after reserving max output) while the request was still well within the real limit. Right after compaction the segment now shows?until the next response re-establishes the true count, and the redundant per-message estimate cache was dropped in favor of memoizinggetContextUsage().
Fixed
- Fixed ACP thinking-delta mapping to tolerate live chunks that only carry delta text.
- Fixed image input to Ollama (local
ollama,ollama-cloud, and anyollama-chatmodel) failing with an opaque HTTP 400 when an attached image was encoded as WebP. Ollama decodes images through llama.cpp /stb_image, which is built without WebP support, so the resize pipeline now auto-excludes WebP for those models — the automatic equivalent ofOMP_NO_WEBP=1, applied across every image path (@filementions and prompt/paste/CLI attachments, theread/inspect_imagetools,evaldisplay images,fetched images, and browser screenshots). Other providers are unaffected and still honorOMP_NO_WEBP. - Fixed queued steering/follow-up display to derive from the agent-core queue, so queued chips clear when the core dequeues them and no longer strand after empty-Enter aborts.
- Fixed model auth gateway probing to avoid skipping candidates with unknown
maxTokenslimits (null) - Fixed model listings so providers registered via extensions are now included from
-eand configuredextensionssources - Fixed
/mcp reauth,/mcp test, and/mcp unauthto find and operate on MCP servers reported by/mcp listeven when they are only runtime-discovered and not stored in writable config, including namespaced plugin servers likecloudflare:cloudflare-api - Fixed MCP server name validation so colon-namespaced server IDs are accepted when persisting reauth overrides so namespaced OAuth MCP servers can be stored in user config as
server:subserverentries - Retried assistant turns that stop with reasoning/thinking only and no final text or tool call, so Gemini/Antigravity thought-only
STOPresponses continue instead of silently ending the session. - Fixed
~/.agent[s]/skillsnot appearing as/skill:<name>commands when every named source toggle (skills.enableCodexUser,skills.enableClaudeUser,skills.enableClaudeProject,skills.enablePiUser,skills.enablePiProject) was off:loadSkillsgated theagentsprovider onanyBuiltInSkillSourceEnabled, so a user who turned off the Claude/Codex/Pi sources to clean noise also lost their own canonical OMP-native skills. Theagentsprovider now reads the dedicatedenableAgentsUser/enableAgentsProjecttoggles, decoupled from the third-party fall-through (#2401). - Fixed Windows PowerShell image paste so Ctrl+V can fall back to the PowerShell clipboard bridge when the native clipboard reader reports no image (#2429).
- Fixed misaligned box borders in Mermaid ASCII rendering for CJK (Korean/Japanese/Chinese) and emoji labels — affects both fenced
mermaidcode blocks in assistant messages and therender_mermaidtool.beautiful-mermaid@1.1.3measures label width in UTF-16 code units while terminals render East Asian characters 2 columns wide; apatchedDependenciesentry rebuilds its ASCII renderer to measure terminal display columns (grapheme-cluster aware, wcwidth-style policy). The patch mirrors the upstream PR (lukilabs/beautiful-mermaid#128) and should be dropped once it ships in a release. - Fixed interrupt loader state getting stuck after queued-message aborts by removing the session-layer flush/latch path; empty Enter now aborts the active turn and lets the existing post-unwind queue drain resume normally.
- Fixed
/goal <objective>and/goal set <objective>during streaming so goal context is steered immediately but objective submission waits for the active turn to finish instead of spammingAgentBusyError(#2454). - Fixed concurrent
omp --sessionstartups (e.g. cmux pane restore after an unclean shutdown) crashing withSQLITE_BUSY_RECOVERYwhile the agent SQLite databases were still under WAL recovery. The auth credential store andAgentStorage.open()retry theSQLITE_BUSYfamily with bounded backoff, and every shared SQLite open path (AgentStorage, history, autoresearch, memories, github cache, auto-QA grievances, catalog model cache, stats) now installs the busy handler before the first lock-taking statement so transient WAL recovery contention waits instead of crashing (#2421). - Mnemopi
per-project/per-project-taggedbank derivation is now stable for one cwd, ignoring the surrounding git layout. Previously the bank id was hashed fromgit.repo.resolveSync(cwd)?.repoRoot ?? path.resolve(cwd), so adding or removing a.gitanywhere above the working directory silently repointed the same conversation to a new bank and stranded its memories (e.g./home/x/projects/repoflipping betweenprojects-…andrepo-…). The derivation inpackages/coding-agent/src/mnemopi/config.tsnow hashespath.resolve(cwd)directly, and session startup widens the recall set with any sibling bank under<dbDir>/banks/whoseworking_memoryrows already carry the active cwd inmetadata_json.$.cwd, so memories stranded by the old, less-stable derivation become visible again on the next session without manual migration (#2412). - Fixed model switching (Ctrl+P role cycling and the alt+p /
/switch//modelsselector) intermittently freezing the UI for several seconds.AgentSession.setModel/setModelTemporaryran an eagerawait modelRegistry.getApiKey(model)purely as an existence pre-flight and discarded the value — butgetApiKeydoes real work: it synchronously executes command-backed key programs (apiKey: "!cmd",execSyncwith a 10s timeout, blocking the event loop) and refreshes OAuth tokens over the network when one crosses the expiry window (the "fine for a few switches, then a multi-second stall" symptom). Switching now uses the synchronous, side-effect-freeModelRegistry.hasConfiguredAuthcheck; the concrete key (command execution + OAuth refresh) is still resolved lazily per request via the existing resolver, so an unconfigured provider still fails fast withNo API keywhile a healthy switch never touches the network or spawns a subprocess.hasConfiguredAuthno longer runs the command program or refreshes tokens either, matching its documented "probe without resolving an API key" contract. - Fixed session resume (
pi -c/--continue/--session) hanging for ~10s at startup — surfaced by the watchdog asStill starting … phase: createAgentSession > restoreSessionModel— when an OAuth token needed refreshing or the auth broker (OMP_AUTH_BROKER_URL) was unreachable. Picking which saved model to restore is a pure selection that only needs to know whether auth is configured, butrestoreSessionModelprobed each candidate with the asyncgetApiKey, which refreshes OAuth tokens over the network, executes command-backed key programs, and issues auth-broker requests — so a slow or unreachable endpoint stalled resume for the full refresh timeout per candidate. Startup model selection now uses the synchronous, side-effect-freeModelRegistry.hasConfiguredAuthprobe (the same fix already applied to interactive model switching); the concrete key is still resolved lazily on the first request via the resolver.
@oh-my-pi/collab-web
Fixed
- Fixed context usage percentage calculations to return null when context window is missing or non-positive, preventing invalid or Infinity/NaN usage display
@oh-my-pi/pi-mnemopi
Fixed
- Fixed
consolidateToEpisodic(the function backingsleep/sleepAllSessions) never populating the episodic graph: thegistsandgraph_edgestables stayed at 0 rows across every bank even after multiple consolidation cycles, so Polyphonic Recall'sgraphvoice (BFS overfindGistsByParticipant/findRelatedMemories) always returned nothing. Consolidation now best-effort ingests the new episodic memory intoEpisodicGraphso the gist row, gist→memoryctxedge, fact edges, and cross-memory similarity/entity/temporal edges land alongside the episodic row. Independent of the existingMNEMOPI_PROACTIVE_LINKINGflag, which still gates the same enrichment on theremember()write path. (#2435)
@oh-my-pi/pi-natives
Fixed
- Fixed native shell execution rejecting quoted heredocs whose closing delimiter is the final line without a trailing newline, matching bash paste-run snippets.
@oh-my-pi/omp-stats
Fixed
- Fixed the stats dashboard's SQLite init never setting
PRAGMA busy_timeout, so a concurrentompstartup hitting WAL recovery could crashinitDb()withSQLITE_BUSYinstead of waiting through it. The busy handler is now installed beforePRAGMA journal_mode=WAL(#2421).
@oh-my-pi/pi-tui
Added
PI_FORCE_HYPERLINKS=1/PI_NO_HYPERLINKS=1env overrides for the OSC 8 hyperlink capability, mirroring thePI_FORCE_SYNC_OUTPUT/PI_NO_SYNC_OUTPUTshape (opt-out beats force-on).
Changed
- Auto-enable OSC 8 hyperlinks inside tmux when tmux self-reports >= 3.4 via
TERM_PROGRAM_VERSION; tmux 3.4 stores OSC 8 as a cell attribute and forwards it to outer terminals whoseterminal-featuresincludehyperlinks. Older tmux, GNU screen, and tmux without a reported version still default off. Resolution is factored intohyperlinksUserOverride()andshouldEnableHyperlinksByDefault()mirroring the sync-output helpers (#2403).
@oh-my-pi/pi-utils
Fixed
- Fixed abortable stream wrappers to cancel the source stream on abort, so timeout watchdogs release upstream HTTP bodies instead of only stopping the local reader.
@oh-my-pi/pi-wire
Changed
- Changed
WireModel.contextWindowandContextUsage.contextWindowtonumber | nullto allow representing unavailable context-window values
What's Changed
- fix(tui): respect OSC 8 hyperlinks under tmux >= 3.4 by @roboomp in #2404
- fix(skills): load ~/.agents/skills even when third-party source toggles are off by @roboomp in #2405
- fix(coding-agent): stabilize mnemopi per-project bank derivation (#2412) by @roboomp in #2414
- fix(auth): retried SQLITE_BUSY family and hoisted busy_timeout by @roboomp in #2423
- fix(ai): added GITLAB_CLIENT_ID and GITLAB_REDIRECT_URI overrides for gitlab-duo OAuth by @roboomp in #2425
- fix(coding-agent): restore Windows image paste fallback by @roboomp in #2430
- fix(ai): deduplicate MiniMax reasoning stream by @roboomp in #2434
- fix(mnemopi): populated gists and graph_edges during consolidation by @roboomp in #2439
- fix: align Mermaid ASCII box borders for CJK/emoji labels by @chan1103 in #2442
- docs: document project settings and disabledProviders by @roboomp in #2448
- fix(cli): defer goal objectives while streaming by @roboomp in #2455
Full Changelog: v15.12.3...v15.12.4