Commit Graph
60 Commits
Author SHA1 Message Date
can1357 77d537add7 Merge PR #7618: fix(ai): respect explicit Codex usage allowance (@roboomp) 2026-08-05 02:22:00 +02:00
roboomp fe84294538 fix(ai): respected explicit Codex usage allowance
Treated an explicit allowed=true and limit_reached=false verdict as authoritative when Codex rounds usage to 100 percent. AuthStorage now honors normalized non-exhausted statuses before numeric fallbacks, keeping a usable Team credential ahead of rejected siblings.

Fixes #7617
2026-08-04 10:56:57 +00:00
Brent 353bbc034b fix(coding-agent): harden usage fallback review races 2026-08-03 17:15:57 +00:00
Brent db97103c32 fix(coding-agent): complete usage-aware fallback integration 2026-08-03 16:34:35 +00:00
can1357 ccd3bb9565 chore: reformat 2026-07-30 04:25:32 +02:00
can1357 091f670ea0 style: apply biome formatting to merged changes 2026-07-30 01:28:07 +02:00
can1357 fc768ae702 Merge PR #6980: fix(ai): keep missing usage windows neutral in ranking (@joswha) 2026-07-29 23:08:47 +02:00
Vlad Toieandcan1357 1f5161eeb0 fix(ai): keep missing ranking windows neutral
(cherry picked from commit 9adb69f2007b82f30a4ffe0bd5920d3c24c739d4)
2026-07-29 23:08:46 +02:00
Éverton Toffanettoandcan1357 e94442b694 fix(ai): preserve legacy Codex SQLite compatibility
(cherry picked from commit 3e5e7b6ea910c56765b4707f617e20b056f3d342)
2026-07-29 23:08:11 +02:00
Éverton Toffanettoandcan1357 db9aa4af1c fix(ai): preserve Codex broker block compatibility
(cherry picked from commit 7de50a84c3d46279e0249617e22ba22222ff8174)
2026-07-29 23:08:10 +02:00
Éverton Toffanettoandcan1357 5d82b77c6b fix(ai): normalize legacy Codex usage blocks
(cherry picked from commit 6c055ee2d0ee2a86893f65f5734d862fcd674202)
2026-07-29 23:07:53 +02:00
can1357 d1239fd3e5 test(ai): deterministically refreshed broker snapshot before asserting healed block
- The broker heals its store synchronously while serving /v1/usage, but the
  remote client snapshot only converges via the background long-poll; the
  assertion raced that poll and flaked on slow CI runners.
- Pull one explicit snapshot after fetchUsageReports, matching the sibling
  same-deadline re-upsert test.
2026-07-27 06:26:25 +02:00
Christian Stewart c9306c09b1 fix(ai): isolate Codex usage by meter
Codex reports one account-level limit flag alongside independent chat and Spark meters. Treating that flag, ranking windows, or persisted backoff as provider-wide made an exhausted meter block requests that still had headroom.

Scope exhaustion, ranking, and reactive backoff to the meter each request spends. Every selection path honors the request scope plus the legacy shared scope, including sibling availability, session pinning, and final OAuth resolution.

Reconciliation now evaluates and deletes each persisted meter block independently. The local and broker-backed stores support targeted deletion while the existing all-block deletion endpoint remains compatible.

Signed-off-by: Christian Stewart <christian@aperture.us>
2026-07-24 16:13:58 -07:00
eval e5dd488210 test(auth): step past usage-report TTL so the sticky-rerank regression exercises the headroom flip 2026-07-18 20:24:29 +02:00
eval 7b52485da4 merge baseline 449e402a into pr-5470: port sticky Codex promotion onto idle-gated/drain-ranked selection 2026-07-18 20:20:56 +02:00
can1357 973332f5d3 Merge PR #5961: fix(ai): normalize clockless usage drain ranking (@roboomp) 2026-07-18 19:42:52 +02:00
roboomp 2625b92dac fix(auth): scoped sticky idle gate to anthropic
The one-hour warm window comes from Anthropic's verified prompt-cache
retention. Applying it generically could re-rank Codex credentials while its
24-hour prompt cache remains warm, and other providers have no verified TTL.

- Applied the idle staleness gate only to Anthropic.
- Preserved indefinite stickiness for providers without a verified boundary.
- Added a Codex regression proving the pin survives more than one hour idle.

Fixes #5966
2026-07-18 06:31:39 +00:00
roboomp 401b7ee09e docs(auth): softened "expired" to "no longer guaranteed warm" for sticky idle gate
Post-TTL prompt-cache entries are deleted promptly but not instantaneously, so
"expired" overstated the guarantee. Wording-only change across the comment,
regression test, and changelog; no behavior change.

Fixes #5966
2026-07-18 06:26:36 +00:00
roboomp 817a08122b fix(auth): gated session credential pin on prompt-cache idle window
Session credential stickiness pinned a session to its last-used Anthropic
credential and skipped usage-based re-ranking whenever the pin was available,
using purely structural conditions (exists / refreshable / unblocked). The pin
carried no timestamp, so ranking was suppressed for up to 30 days even after the
=<1h prompt cache it protects had certainly expired, silently degrading
multi-account load balancing across long idle gaps.

- Store lastUsedAtMs in the pin (in-memory map + persisted JSON row).
- Gate the shouldRank short-circuit on staleness against a 1h warm window
  (SESSION_STICKY_CACHE_WARM_MS); idle-past-TTL sessions rank again.
- When ranking runs, seed the pinned credential first in the evaluation order
  as a tie-break instead of an absolute front-of-queue hoist, so a clearly
  better sibling wins while ties still keep the same account.

Fixes #5966
2026-07-18 06:21:34 +00:00
roboomp 51997706a4 fix(ai): normalized clockless usage drain ranking
- Scored clockless usage headroom over the full window duration.

- Added an Anthropic credential-selection regression test.

Fixes #5960
2026-07-18 05:10:42 +00:00
can1357 9ee329c9d7 chore: update changelogs 2026-07-18 06:40:52 +02:00
can1357 1f619dcf18 feat(ai): enhanced Codex rate-limit header ingestion and usage-based key ranking
- Added a Codex rate-limit parser for `x-codex-*` headers and registered it with the Codex usage provider.
- Updated auth-storage to require parsed usage headers before ingesting usage data, treated exhaustion as non-throttled, and renamed ranked candidate drain fields.
- Reworked key ranking math to use `headroom / remainingHours` with a 1-minute minimum, then applied measured-usage precedence with hot-window demotion behavior.
- Updated session handling and tests to support provider-aware header ingestion with deterministic, exhaustion-aware account selection.
2026-07-14 20:54:03 +02:00
roboomp c6cff316b5 fix(auth): kept plan-gated codex sessions on their sticky oauth account
Sol/Luna set a plan requirement, so #resolveOAuthSelection re-ranked OAuth
candidates every request even when the session-preferred credential was still
usable. #orderRankedOAuthCandidates mixes the stable session hash with
usage-derived weights, so when 5h/7d headroom flipped between two eligible Plus
accounts the same session hash landed on the sibling and #recordSessionCredential
overwrote the sticky binding — surfacing as /usage alternating accounts.

Promote the session-preferred candidate back to the front after ranking whenever
it is unblocked and (for plan-gated models) still plan-eligible, so a session
stays sticky unless the sticky account is blocked, exhausted, or ineligible.

Fixes #5203
2026-07-14 18:08:58 +00:00
can1357 54bafa1cce feat(coding-agent): implemented interactive fallback chain configuration
- Implemented model-specific keys and provider wildcards for `retry.fallbackChains` with updated resolution logic.
- Added interactive fallback chain management in the model roles UI, including support for reordering and editing.
- Improved fallback chain specificity rules and added comprehensive validation with startup warnings.
- Fixed mouse interaction alignment and hover state coordinate mapping in the roles view.
2026-07-11 22:03:35 +02:00
can1357 7cef4a769e fix(ai): improved OAuth credential resolution fallback logic
- Implement a multi-pass resolution ladder to handle scenarios where plan-eligible accounts are usage-blocked.
- Ensure that exhausted paid accounts are prioritized over unblocked free accounts for plan-gated models, allowing callers to receive proper usage-limit error semantics from the API provider.
- Add a test case to verify credential selection when all plan-eligible accounts are currently rate-limited.
2026-07-11 21:01:47 +02:00
can1357 3d082f7a2d Merge PR #4985: fix(ai): recheck codex blocks during selection 2026-07-10 12:37:35 +02:00
roboomp 6d7341b139 fix(ai): refreshed broker block guards
- Sent credential-block updatedAtMs through broker snapshots so same-deadline block refreshes are observable by remote clients.
- Refreshed RemoteAuthCredentialStore reconciliation guards when updatedAtMs changes even if blockedUntilMs is unchanged.
- Added broker regression coverage for same-deadline Codex block re-upserts after a local guard expires.

Fixes #4980
2026-07-09 23:18:36 +00:00
roboomp 4911ce02e8 fix(ai): persisted codex block guard
- Derived SQLite credential-block reconciliation delays from persisted updated_at so fresh blocks survive process restarts and sibling local stores.
- Added reopened-SQLite regression coverage for healthy usage lag after a persisted Codex 429 block.
- Aged explicit stale-block fixtures by moving updated_at outside the guard window.

Fixes #4980
2026-07-09 22:50:33 +00:00
roboomp d8745b62b4 fix(ai): protected initial broker blocks
- Protected Codex blocks present in RemoteAuthCredentialStore initial snapshots from immediate healthy-usage reconciliation.
- Added regression coverage for clients that start after a broker peer already persisted a fresh 429 block.
- Kept stale broker reconciliation explicit by expiring the test guard before the stale-block refresh path.

Fixes #4980
2026-07-09 22:23:07 +00:00
roboomp 04214a8c85 fix(ai): guarded broker codex blocks
- Preserved fresh broker-sourced credential blocks by exposing store-level reconciliation delays to AuthStorage.
- Tracked fresh block observations in SQLite and remote broker stores without protecting initial stale snapshots.
- Added broker sibling regression coverage for healthy usage lag after a shared 429 block.

Fixes #4980
2026-07-09 22:07:08 +00:00
roboomp 0ffc43bfc0 fix(ai): preserved fresh codex blocks
- Delayed healthy-usage reconciliation for newly-set local Codex blocks so lagging /usage responses cannot immediately undo a real 429 backoff.
- Added regression coverage for fresh usage-limit blocks that see healthy usage during selection.
- Kept broker stale-block reconciliation covered by seeding a persisted-only block.

Fixes #4980
2026-07-09 21:36:35 +00:00
roboomp 5b0d670d6b fix(ai): kept exhausted codex blocks
- Restored all-limit Codex block clearing so recovered primary windows do not clear blocks while another reported quota remains exhausted.
- Added regression coverage for primary-recovered/secondary-exhausted selection-path reconciliation.

Fixes #4980
2026-07-09 21:17:08 +00:00
roboomp c143185c01 fix(ai): rechecked codex blocks during selection
- Re-fetched usage for blocked Codex OAuth candidates during ranking so fresh recovered windows can clear stale persisted blocks.
- Relaxed Codex block reconciliation to trust live allowed/limitReached metadata with an available primary window.
- Added regression coverage for selection-path stale block recovery.

Fixes #4980
2026-07-09 21:03:25 +00:00
can1357 66cd994cba fix(ai): standardized tier classification and model routing logic
- Implemented plan-based tier classification for OpenAI Codex usage to ensure correct account routing.
- Updated authentication logic to normalize metadata and prioritize eligible accounts for GPT-5.6 models.
- Added fallback mechanisms to ensure standard usage ranking persists when specific tier requirements are not met.
- Validated routing behavior and model-specific selection through comprehensive unit test coverage.
2026-07-09 22:37:09 +02:00
can1357 3f0c2c63a0 fix(ai): reconciled codex self-heal with shared-scoped blocks
- markUsageLimitReached persists codex blocks under the strategy blockScope
  ("shared" since 0e259bb640); the healthy-usage reconcile guard read only
  unscoped state, so the self-heal from PR #4844 never fired on current main.
- Guard now resolves the ranking-strategy blockScope like selection does.
- Updated PR tests to write/read shared-scoped blocks.
2026-07-08 16:59:59 +02:00
can1357 93edb2ad42 merge PR #4844: fix(ai): self-heal stale Codex usage-limit blocks 2026-07-08 16:52:39 +02:00
Vlad Toie af86bd87eb fix(ai): self-heal stale Codex usage-limit blocks on healthy live usage 2026-07-08 16:16:19 +03:00
cagedbird043 0e259bb640 fix(auth): rotate codex accounts before model fallback 2026-07-08 01:48:34 +08:00
cagedbird043 4a48a03506 fix(auth): skip expired token-only sticky credentials 2026-07-08 01:48:34 +08:00
can1357 a17ec81477 feat(ai): integrated granular credential usage tracking and rate limiting
- Added client-side usage overlays to the auth broker to support granular, credential-specific usage reporting.
- Integrated Fable weekly usage windows and limits into the Claude rate-limiting and ranking strategies.
- Optimized rate-limit handling by caching null results during backoff and disabling retries for 429 status codes.
- Updated credential storage to ingest and persist overlay-based usage data for improved account selection.
2026-07-02 22:38:54 +02:00
can1357 56fbfdea96 fix(pr-3347): use worktree-local cleanup helper in ai tests 2026-06-27 02:04:51 +02:00
oldschoola e17f692af7 test(ai): migrate 24 test files from fs.rm to removeWithRetries
Batch-migrated all packages/ai/test/ files that used fs.rm/fs.rmSync
directly to use removeWithRetries/removeSyncWithRetries from
@oh-my-pi/pi-utils. This fixes EBUSY failures on Windows where SQLite
database files are still locked by the process when afterEach cleanup
hooks run.

Files migrated (24 total):
- 5 auth-broker test files (auth-broker-*.test.ts)
- 11 auth-storage test files (auth-storage-*.test.ts)
- 4 non-auth test files (aws-credentials, issue-1417, issue-957, model-cache)
- 3 remaining test files (remote-auth-store, request-debug, stream)
- 2 sync migration files (anthropic-alignment, image-limits)

Total: 28 fs.rm/fs.rmSync calls replaced with retry-enabled versions.
The retry logic: 40 retries, 25ms delay, EBUSY/EPERM/ENOTEMPTY on Windows.
2026-06-23 12:43:23 -07:00
roboomp dc20114dcb fix(ai): rotated codex oauth on quota 429
Recognized bare HTTP 429 and insufficient_quota payloads as credential-rotatable quota failures in the auth retry path.

Added regression coverage for Codex OAuth sibling rotation before content emission and temporary credential blocking.

Fixes #3231
2026-06-22 05:57:29 +00:00
can1357 9d457f73d9 test: migrated test imports to package subpath exports
- Replaced relative `../src` imports with `@oh-my-pi/pi-ai` and `@oh-my-pi/pi-agent-core` subpaths.
2026-06-08 19:03:55 +02:00
can1357 31b6f0bf31 refactor(ai): consolidated provider config into single-source registry
- Derived descriptors, default-model map, env keys, login list, and refresh dispatch from one ProviderDefinition per provider.
- Disabled OpenAI Codex stream obfuscation and interrupted whitespace-only tool-call argument deltas.
- Derived auth-broker callback ports and paste-code login set from the registry.
2026-06-08 18:48:43 +02:00
can1357 dad939c465 test(ai): de-flaked parallel oauth refresh test
The codex oauth ranking test asserted both `maxConcurrent === 3` and a wall-clock
bound (`elapsed < 2x refreshDelay`). The concurrency counter already proves parallel
execution deterministically — serial refreshes can never raise peak in-flight above
1 — while the wall-clock bound flaked on loaded CI runners (192ms vs 150ms) and
broke the 15.10.3 release. Dropped the redundant timing assertion.
2026-06-08 07:26:28 +02:00
can1357 b8a602ac2a test(auth): switched OAuth ranking tests to weighted selection
- Replaced top-rank assertions with weighted-preference distribution checks.
- Added cases for equal-priority balancing and 2x best-bucket cap.
- Added coding-agent snapshot-cache boot and seed tests.
2026-06-05 11:15:32 +02:00
can1357 363d88ca5c feat(auth): added session-weighted OAuth credential selection
- Distributed sessions across unblocked credentials via priority-weighted hashing.
- Bucketed candidates by ranking priority for proportional fallback weighting.
- Extracted candidate comparison and ordering into dedicated helpers.
2026-06-05 11:09:57 +02:00
can1357 b82d29c6ff fix: fixed VS16 emoji width handling on macOS
- Switched `grapheme_width_str` to compute multi-character widths from `UnicodeWidthStr::width` and then apply the macOS Hangul Compatibility Jamo correction on top of that result.
- Added regression tests in native and TUI text-width tests for VS16 emoji-presentation symbols, keycaps, and related bare-symbol cases.
- Adjusted the AuthStorage codex ranking timeout test fallback to 2s with a 1s elapsed assertion so slow aborted requests cannot mask the fast timeout path.
2026-06-02 23:06:35 +02:00
can1357 c3f5a60c22 feat(auth): added auth-broker for remote credential vault
- Added `AuthBrokerClient`, `RemoteAuthCredentialStore`, `AuthBrokerRefresher`, and `startAuthBroker` server in `packages/ai/src/auth-broker`.
- Renamed `AuthCredentialStore` class to `SqliteAuthCredentialStore`; extracted `AuthCredentialStore` as a persistence interface.
- Added `exportSnapshot`, `forceRefreshCredentialById`, `disableCredentialById`, and `upsertCredential` to `AuthStorage` for broker wire protocol.
- Added `omp auth-broker` CLI subcommand (serve, token, login, logout, import, status) and `discoverAuthStorage` broker-mode path keyed on `OMP_AUTH_BROKER_URL`.
2026-05-16 20:44:07 +02:00