- Added declaration-only compiler options to multiple package publish tsconfig files.
- Standardized publish include/exclude settings to emit types from src into dist/types.
- Added manifest rewrite helpers to remap type paths from ./src to ./dist/types/*.d.ts.
- Updated publish flow to append dist/types/extra files and skip publish build/rewrite for native packages.
- SearchTool now tracked the last emitted line and inserted ellipsis markers when noncontiguous match blocks were output.
- Display output gap markers were padded to align with code-frame gutters.
- Added a regression test that verified a no-context search emits an ellipsis between separated matches in the same file.
- Added MockResponse metadata fields and invoked onResponse pre-stream with lowercased headers, status fallback, and requestId.
- Wrapped request onResponse in agent-loop, captured response headers, and forwarded them with baseUrl to finish/fail span handling.
- Added detectGatewayFromHeaders export and pi.gen_ai.gateway.* span attributes via header-based gateway detection.
- Extended telemetry event/span payloads with responseHeaders and validated detection-priority and onResponse forwarding in tests.
- Unified line-ending normalization to `replace(/\r\n?/g, "\\n")` in editor, scraper, benchmark, and utils modules.
- Added terminal-aware line sanitization in code-cell rendering to collapse inline carriage returns and avoid overwrite corruption.
- Tightened editor and paste sanitizers to trim control characters consistently after CR normalization.
- Updated read-line selector parsing to accept line-range selectors ending with a trailing dash.
- Mapped selectors with a trailing dash to open-ended ranges that read from the start line onward without requiring an explicit end.
- Updated read tool documentation to document `:50-` as the shorthand for reading from line 50 onward.
- Updated the hashline prompt to state the tool should never be used for code reformatting tasks.
- Added guidance to run the project's formatter for whitespace, indentation, and style-only edits.
- Replaced per-line carriage-return stripping with CRLF-aware line splitting in hashline input and parser paths.
- Adjusted payload collection to trim trailing whitespace from edit separator lines and handle line matching without extra normalization.
- Removed the now-unused hashline utils module and stopped exporting it from the hashline index barrel.
- Adopted draft-2020-12 tuple validation with `prefixItems`, rejecting array-valued `items`.
- Expanded strict-mode handling to recurse `prefixItems` entries and infer `array` when tuple prefixes exist.
- Normalized Anthropic schemas through `prefixItems`, keeping supported tuple constraints and dropping unsupported fields.
- Updated coding-agent schema metadata and tests to draft-2020-12 `$schema` targets, including MCP/theme fixtures.
- Added `trimTrailingWhitespace()` to strip trailing spaces/tabs and keep the original line when none exist.
- Changed `zodToWireSchema` to generate wire schemas with `target: "draft-2020-12"` instead of `draft-7` for better Anthropic input schema compatibility.
- Updated the nearby comment to describe that OpenAI strict, Google, and Anthropic CCA sanitizers accept the newer structural superset.
Fixes#1101
- Added homepage metadata entries to the Rust and Python package manifests.
- Replaced OpenRouter HTTP-Referer values with https://omp.sh/ in completion and image requests.
- Updated Codex WebSocket typing and construction to use Bun.WebSocket for handshake header capture.
Fixes#1102
- Updated `raceWithDeadline` to track whether the timeout branch won the race before logging.
- Deferred the startup scan timeout warning until after the race completed with a deferred result.
- Added path-based key deletion helpers that remove keys from object and array arguments while preserving sibling structure sharing.
- Mapped Zod unrecognized_keys and JSON Schema additionalProperties violations to an unrecognized issue type and applied them in issue repair to tolerate strict input shapes.
- Updated tool argument coercion tests to confirm extra keys are stripped for strict and nested strict schemas and additionalProperties false payloads.
- Relocated compaction, branch-summarization, pruning, and utils from coding-agent to packages/agent/src/compaction.
- Moved OpenAI remote compaction helpers from packages/ai to the new compaction module.
- Added handoff.ts with extractHandoffDocument, createHandoffContext, and renderHandoffPrompt helpers.
- Exposed new entries.ts with standalone SessionEntry types so coding-agent no longer owns them.
parseSessionFile(fromOffset) still recovers the active service tier from the already-ingested prefix, but now scans only for service_tier_change entries and keeps a single current tier value instead of materializing every prefix entry. This preserves incremental sync memory behavior for large sessions.
YieldTool's unresolved-ref fallback now skips literal-value positions such as const, enum, default, and examples when looking for unresolved schema refs. Valid schemas containing data literals like { "": "literal" } no longer degrade to the loose schema and still reject invalid yield payloads.
- Runtime-limit timeout is now tracked with a sticky runtimeLimitExceeded flag, so later caller aborts during teardown cannot downgrade the timeout state and let a late yield report success.
- Awaited setup operations before the first prompt are now raced against the subagent abort signal, including auth discovery, model refresh, model resolution, session open, session creation, extension session_start, prompt, and waitForIdle.
- disposeAllKernelSessions removes sessions from the registry before awaiting shutdown, preventing queued work from seeing a registered-but-disposing session and spawning a replacement kernel.
- replaceSessionKernel re-checks registry membership after old-kernel shutdown and after starting a replacement, shutting the replacement down if the session was disposed mid-replace.
- owner-scoped disposal now preserves ownerIds when shutdown is unconfirmed so a later disposeKernelSessionsByOwner(ownerId) can retry.
Primitive $ref recursion now emits a validation issue when the depth cap is exceeded instead of returning true. This preserves termination without accepting invalid values at the end of a long ref chain.
- Keep duplicate suppression for chunks that carry both leaked markers and structured delta.tool_calls, but allow later independently healed calls to promote stopReason from stop to toolUse even if earlier chunks had structured calls.
- Treat streamFirstEventTimeoutMs: 0 as disabling the SDK request timeout instead of passing timeout: 0 or falling back to the env timeout floor.
- Detected async wrapper need via AST traversal instead of regex, enabling pre-demote analysis.
- Published demoted var bindings back to `this` (worker global) when inside the async wrapper, preventing function-scope from hiding them across cells.
- Added `collectBindingNames`/`getLexicalBindingNames` to extract names from destructured patterns.
Stats sync depends on service_tier_change entries to derive priority premium requests since 69043d307 stopped folding priority-tier into per-message premiumRequests. parseSessionFile(path, fromOffset) initialized currentServiceTier to undefined per call, so an incremental resume past the tier change attributed subsequent priority OpenAI replies with premiumRequests: 0. When fromOffset > 0, parseSessionFile now replays bytes[0..start] purely to seed currentServiceTier from the latest service_tier_change before parsing the unprocessed tail. Bytes are already loaded, so no extra I/O.
- Type.String({ format, minLength, maxLength, pattern }) no longer drops the length/pattern constraints when a format selects a Zod format-specific schema (z.email, z.url, z.uuid, …). The instanceof z.ZodString guard never matched those subclasses; constraints are now applied via the shared _ZodString base so all format variants honor them.
- Type.Object without explicit additionalProperties now installs .loose() (matching TypeBox's preserve-extras default) instead of stripping unknown keys. additionalProperties: false continues to install .strict(); a schema value installs .catchall(schemaToZod(schema)).
dereferenceJsonSchema leaves $ref strings in place when references are unresolvable (external URLs, missing definitions, certain cycles). The new yield-parameters builder now walks the resolved schema for any remaining $ref strings before installing validation; if any are found, it throws so the existing catch branch swaps in looseRecordSchema and disables strict validation. Previously YieldTool installed a validator that rejected every success payload with an unresolved-reference error.
The status-line path segment was selecting theme.icon.scratchFolder for scratch directories regardless of opts.stripWorkPrefix, while the CHANGELOG promised both behaviors honor the option. Icon selection now uses the same opts.stripWorkPrefix !== false gate as the scratch path stripping, so disabling stripWorkPrefix keeps the regular folder icon even when the project directory is inside a scratch root.
- Added defensive abort re-check after registering the abortSignal listener plus a checkAbort() immediately before await session.prompt(...), so a wall-clock timer that fires during pre-prompt setup is no longer lost between listener registration and the prompt call.
- Late yield events arriving after a wall-clock timeout no longer flip the result to success: a runtimeLimitExceeded flag derived from the internal abortReason forces wasAborted=true and exitCode=1 regardless of hasYield, while yield payloads remain captured in extractedToolData.
- Async task progress now copies contextTokens and contextWindow from the completed SingleResult onto AgentProgress, so backgrounded tasks still surface their context gauge to the UI.
- executeOnSession's runQueued callback now re-checks sessions.get(sessionId) === session at slot entry and before the dead-kernel replace retry; if the session was removed by disposeAllKernelSessions / disposeKernelSessionsByOwner / resetSession during the queue wait, the queued caller now rejects with PythonExecutionCancelledError instead of spawning an untracked replacement kernel on a stale session object.
- Both dispose paths now inspect KernelShutdownResult.confirmed and retain (or re-insert) sessions whose shutdown was unconfirmed or rejected, logging a warn so a later dispose can retry the kernel instead of orphaning the subprocess.
- Skipped tool double-count: runTool's interrupt early-return no longer records the skipped tool inline; the post-batch tail sweep now handles accounting once per record so a single queued steering cancellation no longer logs N+1 skips.
- Aborted/errored assistant messages with embedded tool calls now record a collector orphan with status 'aborted' or 'error', so coverage.toolsInvoked and tools counters reflect them.
- run-collector chat record now stores inputTokens = input + cacheRead + cacheWrite, matching ChatUsageEvent and the public AgentRunSummary contract.
- onSpanStart and onSpanEnd hook invocations are wrapped in safeOnSpanStart/safeOnSpanEnd; thrown user callbacks surface via onTelemetryWarning (on_span_start_failed / on_span_end_failed) instead of leaking through finishChatSpan/finishExecuteToolSpan/finishInvokeAgentSpan/recordHandoff.
- summarizeTelemetryValue gained a depth+ancestor guard for arrays (matching the existing object recursion guard); cycles return '[Circular]' and over-depth returns the bounded {kind:'array',length} sentinel.
- mergeUsage now recomputes totalTokens (and cost.total when cost components are supplied) when omitted by a Partial<Usage>, so mock-backed telemetry/run-summary tests don't under-count.
- Tool-call ID counter moved into MockState; reset() restores it, so two createMockModel() instances with identical scripted tool calls produce identical IDs regardless of test ordering.
- buildOpenAiNativeHistory now emits custom_tool_call / custom_tool_call_output for blocks with customWireName (apply_patch and other freeform tools), matching the normal Responses replay path; previously demoted to function_call which broke remote-compaction replay or mismatched the original call.
- requestOpenAiRemoteCompaction and requestRemoteCompaction accept an optional AbortSignal; the coding-agent compaction caller forwards the existing signal so cancellation now terminates the in-flight fetch instead of stranding the session in the compacting state until the server replies.
- JSON Schema validator now enforces propertyNames, patternProperties, dependentRequired, dependencies, if/then/else, contains, and prefixItems instead of silently accepting values that violate them; unevaluated* still permissive but warns once.
- Recursive $ref no longer short-circuits to true on revisit: cycle detection keys on (ref, value-identity) with a primitive depth cap, so nested sub-schema violations are caught.
- Meta-validator now structurally validates if/then/else/dependencies sub-schemas and accepts draft-07 dependencies as either schemas or string-array dependent keys.
- Wire-schema null normalization no longer strips null-valued unknown root fields before preserveUnknownRootFields snapshots them, so task.simple and similar callers still see disallowed null arguments.
- Promotion of healed stop→toolUse now gated on prior stopReason === "stop" so error/length/aborted finishes are preserved.
- When a chunk carries both leaked markers and a structured delta.tool_calls, the healer strips visible markers but discards its synthesized calls so structured payloads remain the single source of truth.
- Healer no longer finalizes tool calls outside an active <|tool_calls_section_begin|>…<|tool_calls_section_end|> section; bare tokens in assistant prose survive as text.
- OpenAI SDK client now honors per-request streamFirstEventTimeoutMs so slow-before-headers providers are not aborted at the env default before the wrapping watchdog arms.
`SessionManager.close()` queues `#closePersistWriterInternal()` on the
persist chain. The task awaits `#persistWriter.close()`, which flips
`#closing = true` synchronously before yielding on its inner writer
`close()`. A concurrent `appendMessage()` landing in that yield window
hit the hot path, got the still-cached (but closing) writer back from
`#ensurePersistWriter()`, and threw `Error("Writer closed")` from
`writeSync`. The throw was stashed into `#persistError`; the next async
caller (`flush()` or a later `appendMessage()`) re-threw it as an
unhandled rejection with the original line-1282 stack.
Expose `NdjsonFileWriter.isOpen()` and treat a mid-close cached writer
as a miss in `#ensurePersistWriter()`. `_persist` now falls back to the
async `#rewriteFile()` cold path so the entry — already in
`#fileEntries` — still lands on disk once the close drains.
- Added a dedicated `@sinclair/typebox` specifier remap path and routed bare legacy imports to the in-repo shim during extension rewriting and module resolution.
- Added resolve hooks for both `file` and legacy-file namespaces so legacy extensions load the shim consistently at runtime.
- Replaced fromTypeBox conversion with a JSON-schema validator flow in ai tool handling and execution paths.
- Added recursive schema validation and expanded TypeBox checks for refs, enums, uniqueItems, and constraint keywords.
- Sanitized Azure/CCA tool schemas by dropping unsupported fields and rewriting oneOf tool branches as anyOf.
- Tightened argument and model-config validation, preserving unknown tool fields and adding apiKey plus compatibility flags.
- Added canonical `pi.zod` schema API exports and removed TypeBox package exports/imports.
- Migrated Tool schema typing from TypeBox to shared `TSchema`/Zod flow with legacy TypeBox compatibility.
- Updated AI provider adapters and MCP/agent builders to convert tool params through `toolWireSchema()`.
- Reworked schema validation from AJV to Zod-safe parsing with `fromTypeBox`, `toolWireSchema`, and meta schema checks.
- Swapped deprecated telemetry keys for OpenAIAttr/PiGenAIAttr constants, including tool intent keys.
- Normalized provider names via mapProviderNameToOtel and emitted OTEL pi.gen_ai fields on chat/request/response spans.
- Revised usage and aggregate telemetry to include cache-token totals plus failed and skipped step counts in run summaries.
- Updated OTEL and run-summary tests to use z.object schemas and renamed GenAI/PiGenAI attribute assertions.
- Added a task.maxRuntimeMs setting with a default disabled state for per-subagent runtime limits.
- Updated subprocess execution to enforce the configured wall-clock timeout, mark timeouts as aborts, and include timeout-specific abort messaging.
- Tracked per-turn context size and context window through task progress/results and updated UI renderers to display current context against window with cumulative tokens rendered separately.
- Added OpenAI completions progress detection to treat usage, finish reason, and real content deltas as progress while ignoring keepalive and role-only preamble chunks.
- Applied the new detector through the stream idle watchdog via `isProgressItem` so the timeout only advances on meaningful model output.
- Derived an SDK request timeout from the stream first-event watchdog window and passed it to the OpenAI client to avoid long pre-header stalls.
- Preserved description at the top level when wrapping optional properties with anyOf/null.
- Substituted schema-supplied defaults when a required field arrives as null or "null", cloning to prevent cross-call mutation.
- Added coercion tests for default substitution, isolation, optional null stripping, and nested JSON deserialization.
- Replaced custom MockAssistantStream helpers with createMockModel streams across agent tests.
- Removed manual queueMicrotask stream-event scripting in favor of scripted mock responses.
- Consolidated helper fixtures by deleting local aliases and reusing shared user-message/model helpers.
- Updated test assertions to use mock.calls and mock.model metadata for call and context validation.
- Added `onChatUsage` telemetry configuration and `ChatUsageEvent` payload so each chat step with usage now emits a usage event without requiring a cost estimator.
- Updated chat span completion paths to await async chat usage emission, and emitted `on_chat_usage_failed` warnings when callbacks or hooks reject.
- Awaited `finishChatSpan` in assistant-stream completion and abort flows so telemetry callbacks run before returning from chat completion.
- Added resolveAttributes, normalizeProvider, normalizeAgentName, onCostDelta, onTelemetryWarning, and contentSerializer hooks to AgentTelemetryConfig.
- Added "summary" capture mode emitting bounded dashboard-friendly span attributes without full payloads.
- Added recordManualChatTelemetry for instrumenting non-loop model calls.
- Introduced TelemetryAttributeContext as a base for TelemetryHookContext.