- Update scrubPartialJson to utilize clearStreamingPartialJson for consistent tool-call cleanup.
- Adjust execution order in streamProxy to ensure partial error messages are finalized before scrubbing.
- Remove redundant test expectation comment regarding partialJson leakage.
- 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.
`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.
- 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.
Address review feedback: when the SSE stream disconnects after a
toolcall_delta but before toolcall_end/done/error, the catch-block
at lines 183-192 pushes the partial message as the error result
without calling scrubPartialJson. This leaked the internal partialJson
field into the final error message.
Added scrubPartialJson(partial) call in the catch block, before
pushing the error event.
Added test verifying partialJson does not leak when server disconnects
mid-tool-call (toolcall_start + partial toolcall_delta, no terminal event).
Address review feedback: downstream renderers (event-controller.ts:535)
read content.partialJson during toolcall_delta to pace streaming
previews (bash env assignments, write/edit smooth streaming).
Revised approach:
- toolcall_start: initialize partialJson on content via typed
ToolCall & { partialJson: string } intersection (not as any)
- toolcall_delta: accumulate in side-channel Map, write onto content
via typed intersection cast
- toolcall_end: delete partialJson from content + side-channel map
- done/error: scrubPartialJson() cleans any remaining blocks that
never got toolcall_end (the original leak bug, now fixed for all
terminal paths)
Added test verifying partialJson IS present during streaming and
IS absent after completion.
streamProxy stored internal partialJson streaming state directly on typed
ToolCall objects via 4 'as any' casts. If toolcall_end was skipped (stream
error, early done), the field leaked into the final AssistantMessage content,
corrupting downstream serialization.
Replace with a side-channel Map<number, string> keyed by contentIndex:
- toolcall_start initializes the map entry
- toolcall_delta accumulates into it
- toolcall_end cleans it up
The typed ToolCall object never carries non-spec fields. All 4 'as any'
casts are eliminated.
Added 4 contract tests covering argument parsing, partialJson isolation on
normal completion, partialJson isolation when toolcall_end is missing, and
multiple concurrent tool calls with interleaved deltas.
- Integrated comprehensive loop guard support for DeepSeek and assistant prose patterns, including configurable stream checks.
- Implemented Moonshot Flavored JSON Schema (MFJS) normalization for improved tool compatibility and enum type inference.
- Added support for Ollama reasoning effort backfilling and Grok-specific service tier cost tracking across providers.
- Expanded model catalog with new entries and unified compatibility logic for improved OpenRouter API integration.
Move bundled models, model cache/manager, thinking metadata, effort helpers,
provider descriptors/discovery, wire constants, and model identity utilities
into the new @oh-my-pi/pi-catalog package.
Update pi-ai to keep provider runtime/auth concerns, move catalog provider
metadata into CATALOG_PROVIDERS, and migrate coding-agent, agent, stats, docs,
and tests to import catalog values from pi-catalog.
Split coding-agent model registry helpers into discovery, roles, and models
config modules while preserving registry orchestration.
BREAKING CHANGE: @oh-my-pi/pi-ai no longer exports catalog subpaths such as
/models, /model-cache, /model-manager, /model-thinking, /effort,
/provider-models*, discovery helpers, and provider wire constants; use the
matching @oh-my-pi/pi-catalog subpaths instead.
- 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.
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.
- 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.
The proxy server returns accurate raw token counts but omits pre-calculated
costs. Each direct provider normally calls calculateCost internally, but the
proxy path bypasses that entirely — leaving cost fields at their initialized
zero values.
Import calculateCost from @oh-my-pi/pi-ai/models and invoke it after assigning
usage in both "done" and "error" cases within processProxyEvent.
- Added topP, topK, minP, presencePenalty, and repetitionPenalty sampling control options to StreamOptions and AgentOptions interfaces.
- Implemented getter and setter properties on Agent class for runtime configuration of model sampling parameters.
- Added UI configuration and preset value providers for five new sampling parameters in coding-agent settings schema and components.
- Integrated sampling control parameters through proxy layer and agent session configuration for end-to-end provider support.
- Fixed handling of aborted requests to properly throw abort errors when stream terminates without a terminal event.
- Fixed exit error handling in ChildProcess.wait() to properly capture exit reasons and non-zero exit codes.
- Fixed stdout text conversion in ChildProcess.wait() to use Response API for proper text decoding.
- Refactored SSE stream parsing to use generic `readSseJson` utility instead of domain-specific handlers across multiple packages.
- Migrated from Node.js Buffer API to Web standard APIs (Uint8Array, TextDecoder, DataView) for cross-platform compatibility.
- Simplified stream transformation pipeline by consolidating multiple stream operations into unified `createTextLineSplitter` utility.
- Refactored `ptree.ts` to remove complex stream pumping infrastructure and simplify stderr handling with direct async iteration.
- Rewrote stream utilities to operate at binary level with byte-level parsing for improved efficiency and reduced string allocations.
- Updated TypeScript configuration to include DOM.AsyncIterable type definitions for async iterable DOM API support.
- Added default generic type parameter to Model interface, allowing Model to be used without explicit type argument.
- Removed explicit <any> generic type parameters from Model type annotations throughout codebase, leveraging new default parameter.
- Removed Prettier configuration files (.prettierignore and .prettierrc) and migrated formatting to Biome.
- Updated Biome configuration from version 2.3.11 to 2.3.12 and changed arrowParentheses rule from 'always' to 'asNeeded'.
- Pinned @biomejs/biome dependency to exact version 2.3.12 in package.json and bun.lock.
- Applied consistent arrow function formatting across 489 files by removing unnecessary parentheses around single parameters.
- Removed blank lines after comment blocks and reorganized imports for consistency across the codebase.
- Added tsconfig.publish.json files to all packages with optimized publish-time configuration.
- Updated all package.json scripts with prepublishOnly hooks for correct type checking during publish.
- Added @oh-my-pi/omp-stats path mappings to root tsconfig.json for consistent imports.
- Added WASM generation script for photon module and integrated into install:dev script.
- Added Cursor OAuth provider support to CLI authentication flow.
- Fixed race conditions in OAuth callback handling and session picker cleanup.
- Improved JWT token parsing and error handling across OAuth providers.
- Replaced Bun.sleep() with abortable sleep for proper cancellation support.
- Enhanced process execution with concurrent stream reading and better timeout handling.
- Added cache cleanup mechanism for auth storage with 5-minute intervals.
- Created new @oh-my-pi/pi-utils workspace package with shared utilities for logging, process management, stream handling, and temporary directory management.
- Migrated all packages to use centralized logger from @oh-my-pi/pi-utils instead of local winston implementations.
- Replaced custom process spawning and stream reading implementations with standardized cspawn and readLines utilities across all modules.
- Converted synchronous file operations and process spawning to async patterns using Bun shell syntax and fs/promises.
- Added streaming edit abort functionality with configurable setting to abort on patch preview failures.
- Updated test framework from vitest to bun:test across all test suites.
- Port pi-ai from upstream with Bun-first approach (source files, no dist)
- Add cli_ prefix to tool names in OAuth mode to avoid collisions
- Improve beta header handling with proper deduplication
- Convert codex-instructions.md to Bun text embed
- Strip .js extensions from all imports
- Renamed npm package scope from @mariozechner to @oh-my-pi across all packages for consistent branding.
- Removed packages/pods directory and all related pod management functionality.
- Updated import paths and module declarations throughout codebase to reflect new package names.
- Reformatted code with consistent trailing comma removal and ternary operator alignment.
Merged 53 commits from pi/main including:
- Export HTML rewrite with tree sidebar and /share command
- Hooks API enhancements (custom status, editor, session management)
- Edit diff preview before tool execution
- TUI fixes (Unicode format chars, OSC 8 hyperlinks, emoji optimization)
- Gemini CLI rate limit retry with server-provided delay
- Various bug fixes and documentation updates
Resolved conflicts by preserving Bun migration (spawn→Bun.spawn,
fs→Bun.file) while accepting upstream's new features and APIs.
- Migrated from Node.js to Bun runtime to leverage native TypeScript execution and faster startup times.
- Replaced npm with bun package manager and updated lockfile format.
- Converted Node.js APIs (child_process, fs, readline) to Bun equivalents across all packages.
- Updated shebang lines from node/tsx to bun for CLI entry points.
- Removed TypeScript build step by using source files directly as package entry points.
- Updated CI workflows to use Bun instead of Node.js for installation and testing.
- Renamed AppMessage to AgentMessage throughout
- New agent-loop.ts with AgentLoopContext, AgentLoopConfig
- Removed transport abstraction, Agent now takes streamFn directly
- Extracted streamProxy to proxy.ts utility
- Removed agent-loop from pi-ai (now in agent package)
- Updated consumers (coding-agent, mom) for AgentMessage rename
- Tests updated but some consumers still need migration
Known issues:
- AgentTool, AgentToolResult not exported from pi-ai
- Attachment not exported from pi-agent-core
- ProviderTransport removed but still referenced
- messageTransformer -> convertToLlm migration incomplete
- CustomMessages declaration merging not working properly