- Replaced functional streaming logic with a stateful `CodexStreamProcessor` class.
- Converted `CodexStreamRuntime` into a class with explicit state initializers and lifecycle methods.
- Encapsulated tool call delta tracking and interruption logic within dedicated class methods.
- Integrated `textSignature` generation into text-type output blocks using versioned encoders.
- Added optional `phase` field to assistant messages to distinguish between `commentary` and `final_answer` stages.
- Updated `openai-responses-server` to parse and propagate phase metadata via text signatures during streaming and batch processing.
- Modified `encodeStream` and `buildOutputItems` to trigger new message items when an assistant message phase transition is detected.
- Extended schema definitions and test suites to validate phase-aware message handling and history replay.
- Added textVerbosity option to OpenAIResponsesOptions and SimpleStreamOptions.
- Updated stream mapping logic to propagate verbosity setting to the API request body.
- Implemented endpoint validation to ensure verbosity settings are only applied to official OpenAI endpoints.
- Added comprehensive test coverage for request payload inspection and stream event handling.
- Default the reasoning context to all_turns in the OpenAI Codex request transformer.
- Increase the default text verbosity for Codex requests to medium.
- Set a detailed reasoning summary for AI streams by default.
- Remove outdated testing logic for low verbosity defaults.
- Migrated configuration constants to use dynamic environment variable lookups.
- Removed unused helper functions and associated internal logic.
- Deleted comprehensive test suite for decommissioned WebSocket transport mechanisms.
- Resolved environment variables for Codex WebSocket settings at module load time to prevent redundant parsing during requests.
- Removed deprecated `parseCodexPositiveInteger` helper as environment variables are now resolved once globally.
- Hardened internal state chaining by implementing structural equality checks that ignore transient streaming symbol properties.
- Removed `stripStreamingBlockSymbols` utility as streaming symbol handling is now implicitly managed via key enumeration.
- Refactored `deepEqualsWithout` to rely on `for...in` string key enumeration, ensuring transient streaming symbols are ignored during structural equality checks.
- Aligned structural equality logic to treat `undefined` values and absent keys as equivalent, improving reliability when matching stream chain prefixes.
- Migrated internal streaming state from string-based properties to symbol-keyed properties for improved data isolation and safety.
- Replaced the deprecated `stripVariant` utility with centralized `clearStreamingPartialJson` and symbol-specific helper methods across all provider implementations.
- Implemented `stripStreamingBlockSymbols` and updated deep equality checks to ensure metadata does not interfere with content comparisons.
- Standardized streaming metadata access through a new `block-symbols` utility module.
The CI gate failed in several non-overlapping ways once the full coding-agent suite ran here: tests wrote into the real $HOME (`/srv/agent-home`) which is read-only, a fixture rotated stored Anthropic API keys but Settings reloaded the user models.yml and shadowed them, an OAuth callback server bound to `hostname:"localhost"` (loopback unreachable in this runtime), a built-in tool metadata assertion only saw `github` when `gh` was installed, and the GithubTool `pr_checkout` worktree assertions assumed `~/.omp/wt` but `XDG_DATA_HOME` redirected `getWorktreesDir()` to `$XDG_DATA_HOME/omp/wt`.
Fixes:
- `packages/ai/src/registry/oauth/callback-server.ts`: drop `hostname: "localhost"` when no caller-supplied hostname overrides it. Bun on Linux refused inbound connections to the listener when bound explicitly to `localhost`; defaulting to Bun.serves default binding restores loopback connectivity.
- `packages/coding-agent/test/status-line-path.test.ts`: route the `~/Projects` fixtures through a writable temp home (spy `os.homedir()`), housed under the repo `.wt/` worktree scratch so the temp home is not classified as a status-line scratch root.
- `packages/coding-agent/test/skills.test.ts`: ditto for the `~/.pi-skills-test-*` mkdtemp in the tilde-expansion test.
- `packages/coding-agent/test/marketplace/project-scope.test.ts`: stop writing `~/.git`; build the entire home-dir guard fixture in a temp dir and spy `os.homedir()`.
- `packages/coding-agent/test/oauth-flow.test.ts`: wrap each callback fetch in a brief retry so the simulated browser redirect tolerates the few-ms gap before the Bun callback server starts accepting connections.
- `packages/coding-agent/test/tools/gh.test.ts`: extend `setupTempHome()` to clear `XDG_DATA_HOME`/`XDG_STATE_HOME`/`XDG_CACHE_HOME` for the duration of the test so the rebuilt dirs resolver routes `getWorktreesDir()` back through the spied home, then restore them on cleanup.
- `packages/coding-agent/test/tool-discovery/initial-tools.test.ts`: instantiate `GithubTool` directly in the metadata fixture so the assertion runs even when `gh` is unavailable (GithubTool.createIf returns null without `gh`).
- `packages/coding-agent/test/agent-session-retry-cap.test.ts`: pass an isolated `models.yml` path to `ModelRegistry` so the two-Anthropic-key fixture is the authoritative credential source instead of any user-level command-backed Anthropic key.
Verification:
- `bun check` → passed
- `bun run test` (full coding-agent suite, 4 buckets, all chunks) → 0 fails
Fixes#3639
- Centralized transient transport error patterns to enable consistent reuse across error handling modules.
- Refactored `isOpaqueStatusBody` for improved accessibility in classification logic.
- Updated retryable error detection to include the consolidated transport pattern and additional provider-specific error criteria.
- Migrated 288 lines of scattered error classification logic from `utils/error-id.ts` into a cohesive `packages/ai/src/error/` module with 13 specialized submodules covering flags, classes, OAuth, providers, rate-limiting, and finalization.
- Replaced 100+ generic `Error` throws across 60+ provider and registry files with semantic `AIError.*` classes (e.g., `AIError.MissingApiKeyError`, `AIError.OAuthError`, `AIError.ProviderResponseError`), improving error diagnostics and retry logic.
- Consolidated error utility imports from `pi-utils` and scattered classification functions into a single `AIError` namespace, reducing coupling and simplifying error handling across all packages.
- Simplified the crc32 function by delegating to the Bun native hash implementation.
- Removed the manual lookup table generation and bitwise iteration logic.
`delete` on object properties degrades V8 hidden class optimization; the new `stripVariant` util sets the property to `undefined` instead, keeping the object shape stable.
`performance.now()` is used in place of `Date.now()` for duration and TTFT measurements to get a monotonic, high-resolution clock that is unaffected by system clock adjustments.
- Added support for `<scratchpad>`, fenced markdown blocks, and specific model-specific channel tags to the thinking scan logic.
- Exposed the `ThinkingInbandScanner` via the package dialect index.
- Removed the pi dialect implementation and associated source files.
- Updated dialect resolution, factory registration, and type definitions to exclude pi.
- Cleaned up settings schema and user options to remove pi-related configurations.
- Deleted corresponding test suites covering pi dialect functionality, in-band tools, and examples.
- Centralized thinking block demotion logic using `renderDemotedThinking` across all model providers.
- Updated `transformMessages` to default to text-based demotion for foreign thinking content.
- Restricted foreign thinking preservation to explicitly supported targets with `zai` thinking formats.
- Refactored message transformations and updated test suites to validate standardized demotion outcomes.
- Implement `renderDemotedThinking` to encapsulate reasoning from prior turns when switching models across providers.
- Render reasoning in the target model's canonical thinking dialect (e.g., Markdown fences) to preserve context while ensuring the blocks are processed as reasoning.
- Use a neutral `<think>` tag fallback for models where canonical native formatting risks leaking incompatible chat-template instrumentation tokens.
- Introduce `resolveWithThinkingLoopCook` to manage automated retries for detected model thinking-loop stalls.
- Update `complete` and `completeSimple` to utilize the new retry orchestrator instead of direct stream resolution.
- Configure `pi-native-server` to respect the `loopGuard` option flag.
- Enable a final unguarded pass for persistent stalls after the retry budget is exhausted to ensure generation completion.
- Added `rewrite-changelog.ts` and `fix-changelogs.ts` utilities to automate the consolidation of release notes using LLM-assisted processing.
- Updated multiple internal changelog files by consolidating redundant entries and improving phrasing for readability.
- Implemented `previewLine` utility in `coding-agent` to prevent visual spillover in status rows by managing text truncation and whitespace.
- Updated `package.json` with new workflow scripts for managing package-level change histories and documentation indexes.
- Implemented a monitoring system to identify Gemini model runaway behavior during thinking steps using consecutive header detection.
- Introduced a configurable tool-call reminder prompt to inject corrective context when reasoning stalls.
- Added session-level logic to automatically interrupt and prune stalled assistant turns from the conversation history.
- Provided comprehensive test coverage for the detection logic and stream interruption scenarios.
- Relocated json-parse (repairJson/parseJsonWithRepair/parseStreamingJson/
parseStreamingJsonThrottled) into @oh-my-pi/pi-utils; repointed all
ai/agent/coding-agent import sites to @oh-my-pi/pi-utils.
- readSseJson now recovers a truncated or lightly malformed final SSE event
through the shared streaming parser, removing the bespoke scanJsonState/
getClosingSuffix/isJsonTruncated scanner from stream.ts.
- Dropped the @oh-my-pi/pi-ai/utils/json-parse legacy bundled-plugin registry
entry; the symbols are exposed via the @oh-my-pi/pi-utils barrel.
- Moved json-parse tests into packages/utils/test.
- Centralized JSON parsing and stream processing logic by moving utilities from `packages/ai` to the shared `@oh-my-pi/pi-utils` package.
- Standardized import paths for JSON parsing and streaming across the agent, ai, and coding-agent packages.
- Refactored SSE stream handling to use consolidated `parseStreamingJson` logic and introduced robust error recovery for malformed container-shaped tail events.
- Cleaned up legacy bundled registry references and updated related module exports and tests to reflect the new utility structure.
- Explicitly prohibited HTML escaping in tool arguments for all dialects to ensure raw data transmission.
- Clarified that tool call bodies are delimiter-parsed rather than XML-parsed where applicable.
- Enforced strict requirements to complete tool call output before emitting stop sequences and halting.
Downgraded named forced chat-completions tool_choice to required for llama.cpp so string-only parsers do not ignore the directive.
Added a compat flag and regression coverage for the capture-at-stop resolve path.
Fixes#3593