- Bounded rewind report recovery to messages created after the active checkpoint.
- Added resumed-context regression coverage for late stale rewind results.
Fixes#7739
The ExtensionAPI getAllTools() wired to session.getAllToolNames(),
returning bare tool-name strings. Upstream @earendil-works/pi-coding-agent
promises ToolInfo[] with sourceInfo, so extensions loaded through the
legacy-pi shim (e.g. gentle-pi) crashed on t.sourceInfo.source at every
session start.
Added SourceInfo/ToolInfo types plus SessionTools.getAllToolInfos(), which
returns { name, description, parameters, sourceInfo } and classifies each
tool as builtin/mcp/sdk/extension. Rewired every getAllTools action site
(interactive, acp, print/rpc, subagent executor) and the example extension.
Fixes#7732
- Implemented in-house, zero-dependency utility modules in `pi-utils` covering DOM manipulation, markdown parsing, templating, browser automation helpers, and terminal buffers.
- Migrated packages across the repository to consume the new internal utilities and `omptype` schema validators instead of external dependencies.
- Removed multiple external runtime and development dependencies including Zod, Marked, LRU cache, Turndown, and Puppeteer browser packages.
Registered live session resume commands with postmortem handling so a
fatal rejection or exception identifies every recoverable agent before
cleanup. Escaped terminal control characters in recovery output.
The 17.2.9 revert (172ce9b) restored the legacy path-based session
directory names but removed all migration, including the reverse path.
Sessions written under the short-lived hashed scheme (17.2.5-17.2.8,
`<scope>-<readable>-<sha256>`) were left orphaned, so `omp -r`
current-folder scope reported no sessions.
computeDefaultSessionDir now reconstructs the hashed dir name for the
cwd and performs a one-way best-effort migration into the legacy name,
alongside the existing legacy-absolute migration.
Fixes#7677
Reset-window rotation requires account-specific wording; concurrency caps require an actual cap signal; credential removal gated on AuthFailed without UsageLimit so a valid-but-blocked 403 credential is retained.
(cherry picked from commit 2f72752c2586352a4f7e9e814af1cdb0cf192af4)
Account-reset hint evaluated before short retry hints; account-scoped caps rotate on status 403 or undefined (Devin statusless trailer); statusless concurrency caps marked transient; transient same-model retries use the concurrency backoff.
Refuted: quota-worded concurrency caps were already excluded from rotation before the usage-limit text match.
(cherry picked from commit f2b9a18d715ddbcb6ae703670f2212da36bb2826)
A classifier refusal returned before the `onTurnError` hook that owns
model fallback, so `AdvisorRuntime` treated one provider's policy verdict
as terminal: `Refusal (cyber)` on the advisor model disabled the advisor
outright even with a fallback chain configured. Its only recovery was
stripping echoed primary reasoning and resending once, which does nothing
for a refusal about the content itself.
Route a refusal that outlives the strip through the same hook the generic
failure path uses, mirroring its epoch guard, session-transition requeue,
and requeue-on-recovery. The cascade walks the chain to exhaustion and
only reports the advisor unavailable once the host runs out of candidates,
matching what turn-recovery already allows for the primary.
Each cascade visits a model at most once. A switch re-arms
`#includeThinking` through `#syncModelIdentity`, so chain keys that point
back at each other (A to B, B to A) would otherwise strip-and-resend
against the same pair forever. A successful turn or a reset starts a
fresh walk.
Also stop `/advisor status` throwing when a live advisor has no roster
entry: `formatAdvisorStatus` guarded only the inactive case before
dereferencing `stats.advisors[0]`, and `#ensureAdvisors` clears
`#advisorStatuses` before repopulating it, so a status call landing in
that window hit `undefined.contextWindow`.
Made text replay safety depend on whether the active output sink has committed streamed text.
Kept tool calls, images, and server tools replay-unsafe while covering text and JSON print policies plus a transient socket-close recovery.
Fixes#7625
Align isUnexpectedStopCandidate with #isEmptyAssistantStop: only a signed (non-whitespace thinkingSignature) thinking-only stop is a candidate. Unsigned thinking-only stops stay with the empty-stop retry path and its cap, so unexpected-stop classification no longer re-handles a turn the empty-stop cap already gave up on.
Fixes#7499
isUnexpectedStopCandidate only counted non-whitespace text blocks, so a stopReason:"stop" turn whose sole content was a signed thinking block bypassed the unexpected-stop guard entirely. #isEmptyAssistantStop treats signed thinking as terminal (not empty), so such stops fell through both recovery handlers and the agent silently stopped mid-task.
Count non-whitespace thinking blocks as candidates and feed the thinking text to the classifier when no text block is present.
Fixes#7499
Branched session files preserve entry ids, so leaf-id equality alone let a stale /btw answer promote into a different loaded session. Capture the originating session id at /btw start and require it to match at both the controller gate and every branchFromBtw checkpoint.
Fixes#7474
- Passed the authorized leaf through the branch executor and revalidated it before rewriting history.
- Refused promotion during active turns and bounded post-prompt drains.
- Consumed unavailable branch keys while showing pending and refusal state in the panel.
Fixes#7474
Publish terminal daemon completions to the session that started the
process so idle agents can resume without polling hub status.
Persist every unacknowledged generation with a stable completion ID and
immutable snapshot. Replay the collection after reconnect or broker
recovery, and clear each event only after the owning client acknowledges
it.
Signed-off-by: Christian Stewart <christian@aperture.us>
- Added shared Python call and literal serialization utilities with multiline verbatim support.
- Standardized tool inventories to format as an OpenAI-Harmony functions namespace using TypeScript declarations.
- Updated tool normalization and rendering functions to accept options objects and default to Python-syntax examples.
- Refactored Gemini dialect rendering to leverage shared serialization functions directly.
Completed transcript entries now write through to the OS page cache on
append instead of microtask-batching, supersede in-flight atomic rewrites
with a synchronous full-body publish, and land on the live moveTo path
(source pre-rename, destination post-rename) so a software crash no longer
drops finished user/assistant/tool events. Streaming text remains durable
only at message_end; no fsync/power-loss guarantee is claimed.