Completes the injectable-fetch transport wiring (15.10.8) that the feature
left half-done, fixing the deterministic CI test failures:
- compaction.compact() rebuilt summaryOptions field-by-field but dropped
`fetch`, so the injected transport never reached
requestOpenAiRemoteCompaction / generateSummary's remote path. Thread it.
- Read-tool URL pipeline had no fetch seam: renderHtmlToText gained a
fetchOverride param but renderUrl/ToolSession never carried one, so the
jina/parallel reader backends always used global fetch. Add
ToolSession.fetch -> renderUrl -> renderHtmlToText (defaults to global).
- searchWithParallel mirrored extractWithParallel but missed the fetch
option; add it.
- Repair tests whose deleted hookFetch interceptors were never replaced
with a FetchImpl seam (fetch-kagi-toggle, web-search-parallel,
issue-970 discovery).
- Update issue-1746 POSIX case to the #2154 preserved-scrollback contract:
unknown-viewport streaming deferral is now platform-independent.
- Added optional FetchImpl fields to compaction, proxy, AI, coding-agent, and mnemopi options.
- Threaded injected fetch implementations through OAuth, discovery, and search/LLM request flows.
- Removed exported hookFetch utility and its package entrypoint from utils.
- Replaced global-fetch test monkeypatching with per-test FetchImpl mocks across test suites.
- Added `AssistantMessage.upstreamProvider` and emitted it as `pi.gen_ai.response.upstream_provider` telemetry.
- Clamped OpenAI-family output caps to `OPENAI_MAX_OUTPUT_TOKENS` and model limits to avoid oversized token requests.
- Kept committed tool-call blocks on TTSR/user-interrupt aborts, pairing them with a labeled placeholder result.
- Dropped incomplete tool calls only on anonymous `abort()` where partial args are unsafe to replay.
- Stopped aborted runs from waiting on provider iterator cleanup.
- Ran afterToolCall for completed executions after a run aborts.
- Ignored unknown Anthropic content blocks while preserving known ones.
- Kept sampling params and tool-result caching for disabled thinking.
- Clarified the `onRunEnd` documentation to note warning emission through `onTelemetryWarning` with `console.warn` fallback.
- Updated the non-fatal `onRunEnd` test to collect warnings via `onTelemetryWarning` instead of overriding `console.warn`.
- Added a short async pause in the test to let run-loop warning callbacks flush before asserting their presence.
- Normalized image-content preprocessing in agent sessions now returns early when `content` is missing or not a string/array, avoiding invalid normalization paths.
- Updated agent-loop tests to verify partial tool calls are dropped when an assistant aborts before `toolcall_end`, with run completion reported via an assistant `stopReason` of `aborted`.
- Adjusted Anthropic alignment expectations to reflect a single trailing cache-control breakpoint on the final system block.
- Updated `docs/ttsr-injection-lifecycle.md` to document `astCondition` behavior, including registration rules and tool-stream matching.
- Extended `packages/natives/test/native.test.ts` with new `astMatch` coverage for Smart matching, metavariable consistency, parse errors, and empty-language rejection.
- Deferred non-interrupting asides to the outer drain when a turn was finishing, preventing an extra model turn from firing before queued follow-ups.
- Coerced post-hook tool results before emission and only marked interrupted tool calls as skipped when execution failed, preserving completed call outcomes.
- Reworked Anthropic CCH patching with native `Buffer.indexOf`, and logged a warning while sending the body unchanged when the billing placeholder could not be anchored.
- Removed `maxToolCallsPerTurn` from `AgentOptions`, `AgentLoopConfig`, and config serialization.
- Removed stream-loop cap enforcement, including the `toolcall_end` abort path and capped assistant messages.
- Removed Anthropic Opus 4.8 batch-cap resolver and agent-session sync logic from coding-agent.
- Updated tests and changelogs to align with uncapped tool-call behavior and dropped cap-specific cases.
- Introduced `AsideMessage` as a message-or-thunk union so aside providers can defer injection decisions.
- Updated agent loop handling to resolve aside thunks at injection time and skip entries that returned `null`, then switched the session yield queue to `drainLazy` for deferred message building.
- Added tests validating lazy aside evaluation and staleness-aware dropping when everything becomes stale after dequeueing.
- Routed background-job completions and late LSP diagnostics through the new non-interrupting aside channel so the model sees them mid-run between requests.
- Removed inline custom rendering from the LSP tool now that diagnostics surface through the shared transcript renderer.
- Added an agent loop test proving aside messages are delivered after tool results, before the next model request, without interrupting tool execution.
- Added a yield-queue test confirming stale entries are excluded, the queue is cleared, and re-draining yields no messages.
- Added a new aside-message source on `Agent` and exposed it in `AgentLoopConfig` as `getAsideMessages`.
- Updated the agent loop to poll aside messages after tool batches and before yielding, merging them with follow-up messages before continuing.
- Changed coding-agent session and yield queue handling to pull queued background messages via `drainMessages` at step boundaries instead of streaming-only injection.
- Updated `buildOpenAiNativeHistory` to maintain known and custom tool-call ID sets incrementally while appending provider payload history.
- Rebuilt call-ID state when a full-snapshot payload replaced history so stale outputs were no longer emitted after reset.
- Added compaction regression tests for codex provider payload call-ID registration and stale-result dropping.
- Scope.
- Summary.
- Type.
- Added per-path edit versioning in `EditTool` to drop stale late diagnostics after later edits.
- Added deferred diagnostics queueing through `queueDeferredDiagnostics` and late-diagnostic yield batching.
- Updated `UiHelpers` to render late diagnostic file path and summary lines in the chat transcript.
- Enabled clickable read-path output for result rows, summaries, and previews.
- Resolved read links from result paths, source metadata, internal URLs, and absolutes.
- Preserved selector suffixes while rendering line-anchor hyperlinks.
- Ignored aborted signals for plain-file and directory reads while keeping conflicts-cancel behavior.
- Added tests for non-abortable read behavior and link-label rendering regression coverage.
- Updated `executeToolCalls` to always pass the active `toolSignal` into `tool.execute` rather than bypassing it for non-abortable tools.
- Removed the `nonAbortable` option from `AgentTool` and from the read, write, and edit tools so they can no longer opt out of abort handling.
- Documented the cancellation behavior change in the affected tool docs and package changelogs.
- Updated `waitForDiagnostics` to accept exact document-version matches immediately and otherwise wait for a quiescence window before using the latest publish.
- Removed the old unversioned-acceptance option and applied the settle-based wait logic through inline and deferred diagnostics fetch paths.
- Added an LSP writethrough regression test ensuring stale unversioned diagnostics are ignored in favor of later fresh publishes.
- Updated `convertToLlm` logic to emit `developer` role for custom, hook, and file-mention inputs.
- Simplified OpenAI compact output filtering to retain only `user` and `assistant` messages, removing legacy `system-reminder` pattern checks.
- Adjusted compaction and session tests to match the new developer-role mapping and expected compacted content.
- Removed `<turn-aborted>` guidance injection from `transformMessages`, deleted `turn-aborted-guidance.md`, and dropped the synthetic abort note path for aborted/error turns.
- Updated `c`/`.` continue shortcuts to submit `manual-continue.md` as a hidden synthetic `developer` message via `session.prompt(..., { synthetic: true })` instead of sending an empty user turn.
- Updated tests and changelog notes in AI and coding-agent to reflect the revised abort-context and continue behavior.
- Reworked running-task rendering so shimmer animation is applied to descriptions instead of IDs.
- Added accent coloring for the separator and description text to keep the status line formatting consistent.
The !sawTerminalEvent guard must check signal.aborted first and throw
the caller's reason (not a generic disconnect message) so that
Agent.abort('user-interrupt') surfaces the custom reason in
errorMessage instead of overwriting it.
- Assert error event reason='error' in server disconnect test
- Add test for server-sent 'error' terminal event (verifies sawTerminalEvent
guard does not interfere with proper error flow)
- Clear timeout timers in collectEvents to prevent timer leaks
- Export ProxyMessageEventStream class (avoid ReturnType<> per AGENTS.md)
- Use hookFetch from @oh-my-pi/pi-utils instead of manual globalThis.fetch mutation
- Use Promise.withResolvers() instead of new Promise for timeout races
- Use typed Context object instead of 'as never' cast
- Add client-initiated abort test (verifies stopReason='aborted' path)
- Remove 'as IteratorResult' cast on timeout sentinel
When the proxy SSE stream ends without sending a done or error
terminal event, streamProxy now throws an error instead of silently
calling stream.end() with no arguments. The thrown error is caught by
the existing catch block, which pushes an error event with
stopReason='error' and resolves finalResultPromise.
Previously, server disconnects produced a silent success: the stream
iterator completed normally with stopReason='stop' (the default) and
empty content, and finalResultPromise never resolved, causing
callers that awaited stream.result() to hang indefinitely.
This matches the pattern used by the codex provider
(openai-codex-responses.ts) which already guards against missing
terminal events.
Tests assert that streamProxy emits an error event when the SSE
stream ends without a done/error terminal event. Currently failing
because streamProxy silently ends the stream with stopReason='stop'
and empty content.
- Added `EventLoopKeepalive` in `instrumentedCompleteSimple` to keep the event loop alive during oneshot completion calls.
- This prevented long-lived completion promises from freezing host spinners in Bun by keeping timer servicing active.
- Added `/tan` slash command registration and interactive handling.
- Added TanCommandController validation and async task scheduling for `/tan` dispatch.
- Added session cloning that suppresses breadcrumbs, copies artifacts, and handles abort cleanup.
- Added `promptCacheKey` support in Agent and inherited `providerPromptCacheKey` in session creation.
- Added optional `reason` parameters to `Agent.abort` and `AgentSession.abort` APIs.
- Passed abort reasons through interrupt flows into underlying agent cancellation.
- Replaced hard-coded abort text with `resolveAbortLabel` for streaming and replayed messages.
- Fell back to generic `Request was aborted` text when no abort reason was provided.
- Added `ApiKeyResolver`/`ApiKey` types and exported auth-retry helpers.
- Changed stream and gateway auth retry handling to use resolver steps.
- Added initial-key, force-refresh, and rotate credential retries for auth failures.
- Updated agent and coding-agent integrations to use context-aware API-key resolvers.