- Added first-event timeout detection for streaming responses to prevent stuck requests and enable faster recovery from stream stalls.
- Added PI_STREAM_FIRST_EVENT_TIMEOUT_MS environment variable to configure first-event timeout behavior independently from idle timeouts.
- Fixed Anthropic stream timeout errors to be properly retried with first-event recognition, distinguishing first-event from idle timeouts.
- Enhanced idle-iterator utility with FirstEventWatchdog mechanism and markFirstStreamEvent wrapper for unified timeout handling across OpenAI, Azure OpenAI, and Anthropic providers.
- Fixed rate-limit-utils to recognize and classify 'usage limit' errors as QUOTA_EXHAUSTED instead of transient.
- Added isUsageLimitError() utility function for unified detection of persistent quota limit errors across providers.
- Fixed Codex provider to return immediately on usage-limit errors instead of retrying, preventing unnecessary 5-minute delays.
- Removed usage.?limit pattern from TRANSIENT_MESSAGE_PATTERN to prevent misclassification of persistent quota errors.
- Added `edit.blockAutoGenerated` setting to control enforcement of auto-generated file detection.
- Improved auto-generated file detection to use language-specific comment parsing instead of broad regex patterns, reducing false positives.
- Enhanced marker detection to scan only leading header comments (1024-byte limit) rather than entire file prefix for better accuracy.
- Fixed tool argument validation to properly handle string 'null' values on optional LLM tool arguments.
- Improved type safety by changing validateToolCall and validateToolArguments return types from any to ToolCall["arguments"].
- Added Parallel AI provider integration for web search with fast and research modes.
- Added Parallel extract API for URL content and YouTube video extraction with fallback support.
- Added /login parallel command and PARALLEL_API_KEY environment variable authentication.
- Added providers.parallelFetch configuration setting to control Parallel extract usage.
- Integrated Parallel provider into web search priority order between Exa and Kagi.
- Updated HTML-to-text and YouTube scrapers to prefer Parallel extract over fallback providers.
* fix(path): PI_CONFIG_DIR discovery
* refactor: centralize agent dir name into getConfigAgentDirName()
- Add getConfigAgentDirName() to utils/dirs.ts as single source of truth
- Replace duplicated "/agent" suffix construction in helpers.ts and config.ts
- Let biome format mcp/manager.ts canonically
---------
Co-authored-by: can1357 <me@can.ac>
When the OpenAI responses stream stalls (e.g. with github-copilot/
gpt-5.4), the error message "stream stalled while waiting for the
next event" is now recognized as a retryable transient error.
Two locations updated:
- packages/ai/src/utils/retry.ts: add "stream stall" to
TRANSIENT_MESSAGE_PATTERN (used by provider-level retry logic)
- packages/coding-agent/src/session/agent-session.ts: add
"stream stall" to #isRetryableErrorMessage() regex (used by
agent-session retry loop for both thrown errors and error
AssistantMessages)
Fixes#348
Co-authored-by: GitHub User <user@example.com>
- Added Tavily web search provider with API key authentication and credential discovery from environment or database.
- Integrated Tavily as highest-priority search provider in fallback chain with structured response mapping and error handling.
- Added Tavily OAuth login flow in CLI and auth-storage with manual API key input and validation.
- Added comprehensive test suite for Tavily provider covering registration, response mapping, error handling, and credential validation.
Fixes#313
findAnthropicAuth() only checked OAuth credentials in agent.db, missing
api_key type credentials entirely. Users authenticated via stored API key
(not env var, not OAuth) got null from isAvailable(), causing the provider
chain to skip Anthropic.
Added tier 4 (api_key in agent.db) between OAuth check and env var
fallback. Refactored store lifecycle so tiers 3-4 share one instance.
Also fixed ExaProvider.isAvailable() which unconditionally returned true,
ignoring exa.enabled/exa.enableSearch settings and never checking for
credentials. It now respects both settings and requires an actual API key.
- Added idle-iterator utility to enforce maximum gaps between stream events, preventing indefinite hangs when providers stop sending mid-response. Applied watchdog to OpenAI completions, responses, Azure OpenAI responses, and Codex SSE streams with configurable timeout via PI_OPENAI_STREAM_IDLE_TIMEOUT_MS.
- Added separate first-event timeout for Codex websocket connections to quickly fall back to SSE when a prewarmed socket connects but never starts the response stream. Codex websocket now validates auth headers match before reusing connections.
- Fixed OAuth token refresh and usage lookups to respect request timeouts instead of waiting indefinitely during credential selection or rotation.
- Added automatic Ollama model capability detection via /api/show endpoint to discover reasoning and input modality support.
- Improved Kagi API error handling with structured error parsing for JSON and plain text response formats.
- Fixed Cerebras streaming compatibility by omitting stream_options.include_usage parameter.
- Simplified API key credential storage to always replace credentials instead of merging for non-minimax providers.
- Updated Kagi Search API key format from 'kagi_...' to 'KG_...' and clarified beta access requirement in provider description.
Fixes#326.
Fixes#321.
Fixes#298.
The context fullness gauge was driven by output token count, causing
erratic jumps between turns (e.g. 84% -> 64%) with no compaction.
Status bar and estimateContextTokens now use calculatePromptTokens()
which returns input + cacheRead + cacheWrite — the actual input context
size. Previously both used a formula that included the final output token
count, which fluctuates with response length and is not part of the
context window for the current request.
isContextOverflow's usage-based fallback (z.ai silent overflow) was
also missing cacheWrite (cache_creation_input_tokens). Per Anthropic
docs the threshold is input + cache_read + cache_creation — all three.
Ref: https://platform.claude.com/docs/en/about-claude/pricing#long-context-pricing
google.ts and google-vertex.ts were double-counting cached tokens.
Gemini's promptTokenCount already includes cachedContentTokenCount, so
assigning input = promptTokenCount and cacheRead = cachedContentTokenCount
overcounted by cachedContentTokenCount on every cached request. Fixed
by subtracting first, matching the OpenAI convention:
input = promptTokenCount - cachedContentTokenCount
cacheRead = cachedContentTokenCount
=> input + cacheRead = promptTokenCount (total prompt, no double-count)
Ref: https://ai.google.dev/api/generate-content#v1beta.GenerateContentResponse.UsageMetadata
All other providers validated: amazon-bedrock (inputTokens is uncached
by API contract), openai-completions/responses/azure (already subtract
cached), kimi/gitlab-duo (delegate to correct implementations), cursor
(API exposes output tokens only — input stays 0 by design).
Co-authored-by: Miroslav Drbal <miroslav.drbal@gendigital.com>
* fix(ai): preserve deepseek compatibility while adding alibaba coding plan
* feat(ai): add alibaba coding plan provider with deepseek compatibility fix
* feat(ai): update contextWindow and maxTokens for alibaba coding plan models
* fix(ai): restore Anthropic OAuth exports and add Alibaba env mapping
* fix(ai): set thinkingFormat to qwen for alibaba-coding-plan provider
* fix(ai): preserve bundled limits when fetching Alibaba models
* fix(ai): correct alibaba-coding-plan model limits and reasoning flags
---------
Co-authored-by: Can Bölük <can1357@users.noreply.github.com>
- Added serviceTier option to OpenAI providers for controlling processing priority and cost across agent, completions, responses, and codex APIs.
- Added providerPayload field to messages for transport-native history reconstruction in OpenAI Responses and Codex APIs.
- Added /fast slash command and serviceTier setting to coding-agent for toggling OpenAI priority mode with fast mode indicator.
- Added remote compaction support with encrypted reasoning preservation for OpenAI models in coding-agent.
- Removed usage caching layer across all providers and refactored UsageFetchContext to eliminate cache and now dependencies.
- Fixed OpenAI Codex streaming service_tier inclusion, provider retry logic with exponential backoff, and email-based credential deduplication.
- Added `/login <provider>` command for direct OAuth provider login with automatic selector routing.
- Added Kagi API key authentication support as new OAuth provider across ai and coding-agent packages.
- Added optional `providerId` parameter to `showOAuthSelector()` for direct provider selection without manual input.
- Simplified web search result formatting by removing empty sections (Answer, Sources, Meta, Related).
- Fixed MCP tool schema dereferencing and Ajv validation warnings for non-standard format keywords.
- Refactored OAuth login/logout logic into extracted handler methods for improved maintainability.
- Add dereferenceJsonSchema() that inlines local $ref pointers and strips
$defs/definitions from MCP tool schemas before they reach LLM providers.
Previously, Anthropic's convertTools() extracted only properties/required,
dropping $defs and leaving dangling $ref — the LLM never saw the actual
type definitions (e.g. SourceAnchorInput enum values from nucleus).
- Silence Ajv logger (logger: false) on all three instances that use
strict: false. MCP servers may declare non-standard format keywords
(e.g. "uint") that caused console.warn() to corrupt TUI output.
- Cache compiled Ajv validators per schema object identity in validation.ts,
eliminating redundant recompilation on every tool call.
Co-authored-by: Miroslav Drbal <miroslav.drbal@gendigital.com>
- Normalize LM Studio discovery URLs to avoid duplicated /v1 segments
- Harden status-line PR cache with branch+repo context validation and guarded async writes
- Apply Foundry auth precedence correctly and preserve system trust roots when custom CA is provided
- Split Copilot premium multiplier handling by plan tier while preserving agent-initiated zero billing
- Catch MCP notification refresh failures and route read_resource via deterministic full template matching
- Add regression tests for each fix cluster and keep targeted suites green
* feat: Add LM Studio as a supported model provider with OpenAI-compatible API fetching and discovery.
Add LM Studio as a supported AI provider with optional API key, environment variables, and discovery.
* feat: Add rustup as a dev dependency.
* fix: Refine LM Studio API key handling to conditionally send authorization headers during model discovery based on whether the key is a default local token or a custom key, and add new tests.
* feat: Enhance OAuth token and account ID resolution for model providers in the model registry.
* rebase for packages/ai/CHANGELOG.md
* feat: improve implicit model discovery to independently auto-detect Ollama and LM Studio, and refine LM Studio base URL handling.
---------
Co-authored-by: Can Bölük <can1357@users.noreply.github.com>
- Fixed tool argument coercion to handle malformed JSON with trailing wrapper braces by parsing leading JSON containers.
- Relaxed JSON detection heuristics to check only leading braces instead of requiring matching closing braces.
- Added test case for array strings with trailing wrapper braces from nested JSON malformation.
- Replaced custom `sanitizeSurrogates()` utility with native `String.prototype.toWellFormed()` across all provider implementations.
- Removed `sanitize-unicode.ts` utility module and all imports of `sanitizeSurrogates` function from 10 provider files.
- Updated Unicode surrogate handling in message conversion, response processing, and system prompt handling to use built-in JavaScript API.
- Documented removal of `sanitizeSurrogates()` utility and migration to native `toWellFormed()` in CHANGELOG.
providers/google-gemini-cli:
- parseGeminiCliCredentials() handles legacy, alias (project_id/refresh/expires),
and enriched credential JSON formats
- shouldRefreshGeminiCliCredentials() + refreshGeminiCliCredentialsIfNeeded()
proactively refresh OAuth tokens 60s before expiry for both providers
- normalizeAntigravityTools() converts parametersJsonSchema -> parameters
in function declarations for Antigravity compatibility
- VALIDATED tool calling config applied for Antigravity + Claude model combos
- maxOutputTokens removed from generation config for Antigravity non-Claude models
- Antigravity system instruction injection scoped to Claude + gemini-3-pro-high models
- Antigravity session ID: signed decimal int63 derived from SHA-256 of first user
message (or random bounded int63), replacing truncated hex hash
- Antigravity requestId uses agent-{uuid}; non-Antigravity requests omit
requestId/userAgent/requestType from payload
- ANTIGRAVITY_DAILY_ENDPOINT corrected to daily-cloudcode-pa.googleapis.com;
sandbox kept as fallback
- ANTIGRAVITY_SYSTEM_INSTRUCTION exported
oauth/google-antigravity:
- PKCE removed from OAuth flow (no code_challenge)
- loadCodeAssist metadata ideType changed to ANTIGRAVITY
- discoverProject uses single production endpoint; falls back to onboardUser LRO
(up to 5 retries, 2s interval) instead of hardcoded default project ID
- ANTIGRAVITY_LOAD_CODE_ASSIST_METADATA exported
oauth/google-gemini-cli:
- PKCE removed from OAuth flow
oauth/index:
- getOAuthApiKey includes refreshToken, expiresAt, email, accountId in
Gemini/Antigravity JSON payload for proactive refresh support
discovery/antigravity:
- Tries production daily endpoint first, sandbox as fallback
- Removed recommended/agentModelSorts filter; applies denylist instead
- ANTIGRAVITY_DISCOVERY_DENYLIST filters low-quality/internal models
- Request body no longer includes project field
coding-agent:
- gemini_image: corrected responseModalities to uppercase IMAGE/TEXT
- Gemini web search: endpoint fallback (daily->sandbox) with retry on 429/5xx,
aligned Antigravity request metadata, ANTIGRAVITY_SYSTEM_INSTRUCTION injection
- buildGeminiRequestTools() helper for composable googleSearch/codeExecution/urlContext
- Web search schema: expose max_tokens, temperature, num_search_results params
- Web search: explicit provider falls back to auto chain when unavailable
Tests: google-antigravity-auth, google-gemini-cli-alignment, web-search-gemini
providers/anthropic:
- Bump claudeCodeVersion to 2.1.63; system instruction identifies as Claude Agent SDK
- X-Stainless-Os and X-Stainless-Arch now runtime-computed via mapStainlessOs/mapStainlessArch
- Remove X-Stainless-Helper-Method; update package version to 0.74.0, runtime to v24.3.0
- Remove fine-grained-tool-streaming-2025-05-14 from default beta set; add
context-management-2025-06-27 and prompt-caching-scope-2026-01-05
- Accept-Encoding updated to 'gzip, deflate, br, zstd'
- Inject x-anthropic-billing-header block (SHA-256 payload fingerprint) and
Claude Agent SDK identity block with ephemeral 1h cache-control for OAuth requests
- Auto-generate cloaking user IDs for OAuth metadata.user_id when absent/invalid
- applyClaudeToolPrefix / stripClaudeToolPrefix skip Anthropic built-in tool names
- buildClaudeCodeTlsFetchOptions attaches SNI + default TLS ciphers for api.anthropic.com
- Non-Anthropic base URLs now use Bearer auth regardless of OAuth status
- Prompt-caching no longer strips then re-applies; skips if blocks already have cache_control
oauth/anthropic:
- Token URL changed from platform.claude.com to api.anthropic.com
- OAuth scopes trimmed to org:create_api_key user:profile user:inference
- Code exchange strips URL fragment from callback code (fragment used as state override)
- AnthropicOAuthFlow exported
- OAuth callback server timeout extended from 2 min to 5 min
usage/claude:
- user-agent updated to claude-cli/2.1.63 (external, cli)
- anthropic-beta header extended with full production beta set
coding-agent web search:
- Anthropic provider uses buildAnthropicSearchHeaders instead of buildAnthropicHeaders
Tests: anthropic-alignment, anthropic-oauth, claude-usage-headers, web-search-anthropic
- Add hasUnrepresentableStrictObjectMap() pre-flight in tryEnforceStrictSchema;
schemas using patternProperties or schema-valued additionalProperties now
degrade to non-strict mode instead of throwing during enforcement
- Add test coverage for patternProperties graceful degradation
- Extend ANTHROPIC_OAUTH_BETA in openai-compat route with
interleaved-thinking-2025-05-14, context-management-2025-06-27, and
prompt-caching-scope-2026-01-05 beta flags
- Add gemini, codex, and synthetic to providers.webSearch setting enum
## New: schema compatibility validation API
Add `validateSchemaCompatibility(schema, provider)` in
`packages/ai/src/utils/schema/compatibility.ts` that performs a static
audit of a JSON Schema against three provider targets:
- `openai-strict`: checks forbidden keys, required/properties symmetry,
additionalProperties constraint, and that every node declares a type,
combinator, or $ref
- `google`: checks unsupported keyword set and array-valued type
- `cloud-code-assist-claude`: checks forbidden keywords, array type,
null type, nullable keyword, and combiner presence; also validates via
AJV 2020 draft
Add `validateStrictSchemaEnforcement(original, result)` to assert the
fail-open contract: when strict enforcement succeeds the output must pass
openai-strict validation; when it fails the output must be the original
schema object (same reference).
Export both functions and their types from `./utils/schema/index.ts`.
## New: shared constants in fields.ts
Extract `COMBINATOR_KEYS` (`anyOf`, `allOf`, `oneOf`) and add
`CCA_UNSUPPORTED_SCHEMA_FIELDS` as exported constants, eliminating the
local duplicate in `strict-mode.ts` and providing a canonical field set
for Cloud Code Assist (much narrower than the Google set — CCA supports
validation keywords like `additionalProperties`, `minLength`,
`pattern`, etc.).
## Fix: cycle detection in all recursive schema traversals
All recursive walkers now carry a `WeakSet<object>` guard. Previously any
schema with a reference cycle (or a schema object that appears at two
nodes in the tree) would cause an infinite loop or a stack overflow:
- `sanitizeSchemaForStrictMode` / `enforceStrictSchema`
- `normalizeSchemaForCloudCodeAssistClaude`
- `normalizeNullablePropertiesForCloudCodeAssist`
- `stripResidualCombiners`
- `sanitizeSchemaImpl` (Google sanitizer)
- `hasResidualCloudCodeAssistIncompatibilities`
`hasResidualCloudCodeAssistIncompatibilities` previously returned `true`
for already-visited nodes, producing false positives that forced the CCA
fallback schema on valid (but multiply-referenced) schemas. It now
correctly returns `false`.
## Fix: stripResidualCombiners iterates to fixpoint
The previous single-pass approach missed chained combiner reductions
where one collapsed variant exposed another reducible combiner. The
rewriter now loops until no further reduction occurs.
## Fix: mergeObjectCombinerVariants required-field computation
The merged object schema now takes the intersection of all variants'
`required` arrays, then unions in own-level required properties that
exist in the merged schema. Previously the `required` field was silently
dropped from the flattened schema, making all properties effectively
optional.
## Fix: sanitizeSchemaForGoogle improvements
- Type inference for const-collapsed enums: type is derived from all
variants (must unanimously agree), falling back to inference from enum
values; mixed null/non-null infers the non-null scalar type and sets
`nullable: true`
- Const→enum deduplication now uses deep structural equality instead of
`Object.is`
- Recursion spreads the full options object so new fields (`unsupportedFields`,
`seen`) are not silently dropped when descending into sub-schemas
- Array-valued `type` is filtered to strings before processing
- Removed incorrect stripping of `additionalProperties: false` (the
field is valid and should be preserved)
- Parameterized `unsupportedFields` in `SanitizeSchemaOptions` enables
code reuse between the Google and CCA sanitizers
## Fix: sanitizeSchemaForStrictMode / enforceStrictSchema
- `nullable: true` is now stripped during sanitization and expanded into
`anyOf: [schema, {type: "null"}]` in the enforcer output, matching
what OpenAI strict mode requires
- Type inference: `type: "array"` is inferred when `items` is present;
a scalar type is inferred from uniform `enum` values
- Const→enum merge uses deep equality to avoid duplicate entries when
both `const` and `enum` exist with the same value
- `additionalProperties` is now dropped unconditionally in sanitization
(previously only object-valued `additionalProperties` was recursed;
non-object values were passed through)
- `enforceStrictSchema` recurses into `$defs` and `definitions` blocks
- `enforceStrictSchema` handles tuple-style `items` arrays
- `enforceStrictSchema` skips double-wrapping: optional properties
already expressed as `anyOf: [..., {type: "null"}]` are not wrapped again
- `tryEnforceStrictSchema` now caches results in a `WeakMap` keyed on
the input schema object to avoid redundant work on repeated calls
## Fix: mergeCompatibleEnumSchemas deep equality
Uses `areJsonValuesEqual` instead of `Object.is` when deduplicating
enum members, so structurally equal objects are not duplicated.
## New: test coverage
- `packages/ai/test/schema-normalization.test.ts`: comprehensive unit
tests for strict mode, Google, and Cloud Code Assist normalization
- `packages/ai/test/schema-compatibility.test.ts`: unit tests for all
three provider targets in the new compatibility validator
- `packages/coding-agent/test/tools/provider-schema-compatibility.test.ts`:
integration test that instantiates every builtin and hidden tool, runs
their parameter schemas through all three provider pipelines, and
asserts zero compatibility violations
- Extracted schema utilities from typebox-helpers and google-shared into new modular utils/schema package with 17 exported functions.
- Consolidated OpenAI strict mode schema enforcement across codex, completions, and responses providers using unified adaptSchemaForStrict() helper.
- Refactored credential ranking from hardcoded Codex-specific logic to pluggable CredentialRankingStrategy pattern with provider implementations.
- Migrated 500+ lines of Google schema sanitization and normalization logic from google-shared.ts to dedicated utils/schema modules with expanded functionality.
* fix(ai): throw on typeless schema node in enforceStrictSchema
A schema node with no type, combinator, or $ref (e.g. `{}` or
`{ items: {} }`) is not representable in strict mode. Previously
enforceStrictSchema silently produced an invalid schema; now it throws,
which causes tryEnforceStrictSchema to degrade to non-strict.
Adds a regression test covering the array-with-empty-items case.
* fix(ai): handle not-combinator and document enforceStrictSchema throws
- Guard now also accepts { not: <object> } as a valid combinator node,
preventing a false throw on schemas that use not without a type field
- Added @throws JSDoc documenting the throw condition and directing
callers to tryEnforceStrictSchema for graceful degradation
Addresses review comments on #210.
- Added graceful schema validation fallback mechanism that degrades to unconstrained schemas on repeated validation failures.
- Enhanced schema enforcement across AI providers to use try-catch pattern with automatic fallback to non-strict mode on validation errors.
- Improved handling of circular, deeply nested, and non-object output schemas with stack overflow prevention and type conversion fallbacks.
- Added `tryEnforceStrictSchema()` utility function providing error-resilient schema validation with strict mode flag tracking.
- Added `sanitizeSchemaForStrictMode` function to normalize JSON schemas by removing non-structural keys for strict mode compatibility.
- Enhanced `enforceStrictSchema` to handle union types with object variants and type arrays containing object.
- Fixed `enforceStrictSchema` to properly handle malformed object schemas with required keys.
- Integrated schema sanitization in coding-agent submit-result tool with fallback to non-strict mode on validation errors.
- Fixed `enforceStrictSchema` to properly handle malformed object schemas with required keys but missing properties.
- Fixed `enforceStrictSchema` to correctly process nested object schemas within `anyOf`, `allOf`, and `oneOf` combinators.
- Added type guards to validate schema entries before recursive processing to prevent incorrect transformations.
- Added 2 test cases covering malformed object normalization and nested schema repair scenarios.
* fix(ai): coerce string-to-number for Optional<number> parameters
When a tool schema uses Type.Optional(Type.Number()), TypeBox generates
an anyOf:[{type:"number"},{type:"null"}] schema. AJV reports validation
failures against this as keyword:"anyOf" errors rather than
keyword:"type" errors.
coerceArgsFromErrors only processes keyword:"type" errors, so Optional
numeric fields were invisible to the coercion loop. normalizeOptionalNullsForSchema
traverses anyOf branches recursively but returned early at primitive-type
branches (type !== "object") without attempting string coercion, so the
anyOf traversal produced no change and the string was left uncoerced.
Fix: add a string-to-number coercion guard in normalizeOptionalNullsForSchema
before the early return, covering schema branches that declare
type:"number" or type:"integer". This allows the existing anyOf
traversal to coerce "1.0" -> 1.0 when the schema is Optional<number>.
Required numeric fields (Type.Number()) were unaffected as they produce
keyword:"type" errors handled by the existing path.
Reproducer: any MCP tool with an optional float parameter (e.g. tick_size:
Option<f64> in Rust/schemars) receives the value as a string from the
LLM and fails deserialization despite the coercion infrastructure being
designed to handle exactly this case.
* style: biome format validation.ts and coercion test
---------
Co-authored-by: Miroslav Drbal <miroslav.drbal@gendigital.com>
- Consolidated @oh-my-pi/pi-utils subpath imports into single package root import across 100+ files.
- Moved tryParseJson utility from local web scrapers module to @oh-my-pi/pi-utils package for centralized JSON parsing.
- Renamed loadSkillsFromDir to scanSkillsFromDir and refactored skill discovery to use fs.promises.readdir instead of glob-based approach.
- Replaced custom parseJSON with tryParseJson across discovery modules for consistent error handling.
- Removed emitCustomToolSessionEvent method and cleanupSshResources function, consolidating shutdown logic into dispose method.
- Updated glob pattern construction to use GlobBuilder with literal_separator(true) for improved path handling.
- Enhanced GitLab Duo model mapping to support canonical model IDs with fallback lookup.
- Simplified Anthropic auth resolution from 4-tier to 3-tier priority system.
- Fixed artifact manager cache invalidation by validating session file before reuse.
- Improved JSONL parsing in stats package with streaming parser and error handling.
- Migrated AuthCredentialStore and AuthStorage to shared modules, standardizing credential management and soft deletion.
- Consolidated Anthropic authentication and various other formatting/utility helpers into shared modules.
- Improved unicode normalization in patch logic with regex for efficiency and correctness.
- Enhanced JTD type guards for robust schema validation.
- Extracted credential storage to shared @oh-my-pi/pi-ai package with AuthCredentialStore and AuthStorage classes.
- Consolidated UI formatting logic from ToolUIKit class into standalone utility functions across render-utils and output-meta modules.
- Moved utility functions (parseCommandArgs, substituteArgs, expandPath, normalizeUnicode) to dedicated modules for improved code reuse.
- Extracted JTD type definitions and type guards to jtd-utils module for shared use across schema conversion tools.
- Updated Claude model pricing and added cache read costs in models.json for accurate billing calculations.
- Refactored agent-storage to delegate credential management to AuthCredentialStore instead of direct SQLite operations.