Commit Graph

31 Commits

Author SHA1 Message Date
can1357 bc39ffa265 feat: introduced omptype validation package and migrated workspace dependencies
- Introduce `@oh-my-pi/omptype` as a new ArkType-compatible schema validation package featuring a lazy JIT runtime, JSON Schema emission, and compatibility adapters.
- Replace `arktype` across workspace packages and test utilities with `@oh-my-pi/omptype`.
- Add benchmark suites, tests, and documentation for the new validation engine and adapters.
- Update workspace build, test runner, and release configurations to include the new package.
2026-08-03 21:56:48 +02:00
roboomp af11e78796 fix(ai): rejected broker block writes after corruption
Fail broker-facing block mutations on the first corrupt SQLite write and every later latched call instead of returning a false durability acknowledgement. Internal request-path persistence remains an in-memory no-op, preserving local availability.

Verify RemoteAuthCredentialStore keeps its optimistic rate-limit block and does not refresh an empty snapshot when the broker rejects persistence.
2026-08-01 19:13:42 +00:00
can1357 1d74bc73e3 refactor(ai): optimized credential lookup and stream chunk processing
- Memoize credential lookup and filtered usage report output in RemoteAuthCredentialStore for O(1) steady-state performance.
- Optimize Devin stream chunk processing to avoid redundant buffer copies during steady-state reads.
- Add comprehensive integration test covering usage report filter memoization and cache invalidation on snapshot changes.
2026-07-27 20:33:37 +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
Alex TYRODE e6ab870d37 fix(ai): close auth broker account pool gaps 2026-07-23 21:28:17 +00:00
Alex TYRODE faabe089e8 feat(ai): add process-scoped OAuth account pools 2026-07-23 19:30:49 +00:00
can1357 b0d04e5173 fix(ai): fixed snapshot validation for login-sourced API keys
- Added optional `source?` field with value `'login'` to `apiKeyCredentialSchema` so snapshots accept login-sourced API keys.
- Updated CHANGELOG with a fixed entry describing the correction.
- Added a test verifying that a snapshot containing `source: "login"` passes client wire validation.
2026-07-17 04:15:58 +02:00
can1357 6ae7cdbf97 feat(ai): added automatic credential rotation for invalidated OAuth tokens
- Implement `isInvalidatedOAuthTokenError` to identify specific upstream auth failures.
- Enable automatic credential rotation in `AuthStorage` and stream retries when an invalidated token is detected.
- Update `proxy.test.ts` to correctly handle `NO_PROXY` and `no_proxy` environment variables during testing.
2026-07-16 05:39:37 +02:00
can1357 c11545f23f fix(ai): match legacy broker usage by identity 2026-07-14 18:29:15 +02:00
can1357 7f9a2777f9 Merge PR #5170: fix(ai): scope Anthropic credential identity by organization, not just email (@chan1103) 2026-07-14 18:29:14 +02:00
can1357 43f8999a9b feat(ai): added cache invalidation for usage reports
- Introduced a `POST /v1/usage/stale` endpoint to allow remote clients to invalidate server-side usage caches.
- Updated `AuthCredentialStore` to include an optional `invalidateUsageCache` hook.
- Added `invalidateUsageCache` method to `AuthStorage` for local cache invalidation and notification of remote stores.
2026-07-11 20:53:58 +02:00
chan1103 fd122f7ea6 fix(ai): org-presence mismatch is a non-match in broker routing, both directions
Final internal gate review on 6b061b41e:

- matchUsageReport/findMatchingReportIndex no longer fall back to org-less
  aggregate reports for an org-scoped credential/overlay. With a scoped
  row plus an org-less legacy row (a supported state), the legacy row's
  sole surviving report could be handed to the scoped credential without
  any base-identity check and rank/block it on the wrong pool; an
  org-scoped overlay could likewise merge into that org-less report.
  Presence mismatch now yields no-match in both directions, matching the
  rule used everywhere else. Regression test included.
- Changelog wording: omp token --list labels rows with the org; it does
  not mark an active row (that is /logout's selector).
2026-07-11 22:49:12 +09:00
chan1103 e095af3be0 fix(ai): require member identity within a shared org for report routing, overlays, and coverage
Codex review round 7 on e90a72bdd flagged that broker usage-report
matching, header-overlay keying, and omp-usage coverage all treated a
matching organization as a sufficient match. Two Team members share the
org id while drawing on per-user pools, so the first same-org report
(or a lone sibling report) was handed to the wrong member. The org is
now a gate: within the same-org subset the member's own base identity
(account/email/project) must still match, with org-only entities (no
base identifiers) matching on the org alone when unambiguous. The
overlay merger (findMatchingReportIndex) had the identical same-org
flaw and receives the symmetric fix. Org-presence-mismatch semantics
are unchanged: org-scoped vs org-less stays fall-through/unreported,
and both-org-less keeps the legacy base-identity fallback.
2026-07-11 22:49:12 +09:00
chan1103 c2456d882f fix(ai): org-qualify account/project fallback identities; org-decisive routing on either side
Addresses the fourth review round (Codex no-email finding on d37e3992c,
confirmed and scoped by internal review):

- resolveProviderCredentialIdentityKey: the anthropic org qualifier now
  rides on whichever base identity exists (email > account > project),
  not only email. The account UUID is identical across the orgs of one
  login account, so the bare account fallback let a second subscription
  replace the first whenever the email could not be recovered (token
  response omits it AND bootstrap fails). Org-only credentials key on
  the org alone instead of losing identity entirely.
- matchesReplacementCredential: the one-way legacy claim strips a
  trailing |org: from ANY anthropic base key (account/project included);
  only anthropic keys carry the qualifier, so other providers are
  unaffected.
- Usage-report dedupe falls back to the org-qualified account for
  no-email anthropic reports instead of returning no identifiers.
- Broker report/overlay routing (matchUsageReport/findMatchingReportIndex)
  is org-decisive on EITHER side: an org-less legacy credential no longer
  receives an org-attributed sibling's pool via the lone-candidate or
  email/account fallback, and an org-less overlay only merges into
  org-less reports.
- omp usage unreported-account attribution follows the same either-side
  rule, so a legacy row whose fetch failed surfaces as 'no usage data'
  instead of being hidden by a sibling's report.
- Regression tests: no-email identity coexistence/replace/claim, no-email
  report dedupe, org-less broker routing, either-side unreported
  attribution.
2026-07-11 22:49:12 +09:00
chan1103 044d722a36 fix(ai): scope Anthropic credential identity by organization
One Anthropic account email can hold multiple organizations (a Team seat
plus a personal Max plan), each with its own org-scoped OAuth token and
independent 5h/7d limit pools. Credentials were deduped by bare email, so
logging in with the second subscription silently replaced the first, and
usage reports from the two pools merged into one row with mixed numbers.

- capture organization uuid/name at login (token exchange response, with
  a claude_cli/bootstrap fallback); token refreshes never rewrite it
- key anthropic credential identity as email + org; a legacy email-keyed
  row is claimed in place by the first org-scoped login with the same
  email, and org-less credentials never clobber org-scoped rows
- partition usage-report dedupe and the per-credential usage cache by
  org so the two subscriptions' limit pools stay distinct for rotation
- show the organization in omp usage (redaction-safe) and name the
  stored account/org in the login success message
2026-07-11 22:49:12 +09: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
can1357 b6e33f6ed3 feat(ai): implemented persistent storage and synchronization for credential blocks
- Implemented persistent storage for credential rate-limit blocks with automatic expiry and pruning.
- Added broker API routes and client methods to manage, persist, and synchronize credential block states.
- Integrated rate-limit checks into the credential selection logic, specifically refining Fable/Mythos tier exhaustion gating.
- Extended schema versioning to include the new credential block table and verified persistence via comprehensive unit testing.
2026-07-04 11:22:04 +02:00
can1357 d82b9bdc5f feat(agent): allowed dynamic model resolution per LLM call
- Added `getModel` to `AgentLoopConfig` to allow runtime model resolution.
- Updated `streamAssistantResponse` to resolve the model dynamically per provider call instead of using the stale configuration snapshot.
- Enabled mid-run model switches to take effect immediately for context promotion and retry fallbacks.
2026-07-02 22:43:11 +02: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
roboomp f4055690ea style: bun run fix 2026-07-01 05:18:21 +00:00
roboomp c39dd86fba fix(auth-broker): cache /v1/usage failures for documented 15s TTL
RemoteAuthCredentialStore.#loadUsageReports() only wrote the 15s cache on
success, so every sequential fetchUsageReports()/getUsageReport() call
after a broker failure kicked off a fresh client.fetchUsage() — the exact
opposite of the 'client absorbs transient broker outages … re-attempting
after the 15s window' contract in docs/auth-broker-gateway.md.

Extend UsageCacheEntry.reports to UsageReport[] | null, write the null
result in the .catch branch alongside fetchedAt = Date.now(), and let
the existing TTL check serve later callers. Single-flight coalescing
and successful-path caching are unchanged.

Fixes #4045
2026-07-01 05:17:55 +00: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
can1357 2a92ff8a98 refactor(coding-agent): optimized module exports and configuration
- Refactor deep imports by targeting specific sub-modules in `@oh-my-pi/pi-ai` to reduce barrel file overhead.
- Utilize jitless ArkType scopes in schema definitions to reduce startup JIT codegen costs by approximately 65%.
- Reorganize internal `auth-storage` exports to maintain clean boundaries between core and broker-specific functionality.
2026-06-18 19:33:48 +02: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 a9a2c8516d fix(ai): applied broker refresh result to suspect credential snapshot
- Updated markCredentialSuspect to apply the credential entry returned from refreshCredential and throw when the broker returns a non-OAuth credential.
- Added #applyCredentialEntry to replace or append a credential in the in-memory snapshot for immediate state updates.
- Added a test covering suspect-credential refresh snapshot updates and token refresh invocation.
2026-05-25 20:03:32 +02:00
can1357 e5d38f0832 fix(ai): persisted broker auth writes via remote credential endpoints
- Added remote-write hooks to `AuthCredentialStore` and routed `AuthStorage` set/upsert/remove flows through them when present.
- Implemented `RemoteAuthCredentialStore` methods to upsert, replace, and delete credentials via broker endpoints and refresh local snapshots in-place.
- Added integration coverage for broker-backed API-key replacement and provider logout disabling all remote credentials.
2026-05-21 15:57:32 +09:00
can1357 6db7d6af92 feat(ai): added auth-broker snapshot contract with generation checks
- Added generation-aware snapshot contracts with generation, serverNowMs, refresher, and rotatesInMs fields.
- Reworked /v1/snapshot serving and client fetching for If-None-Match long-poll with 304/200 status handling.
- Added status checks in remote-store and SDK/CLI snapshot paths, applying updates only when fetch returns 200.
- Added StreamOptions.onAuthError and stream one-shot 401 retry dispatch using refreshed credentials.
2026-05-17 04:54:30 +02:00
can1357 484fca9c01 feat: added auth-gateway usage cache with single-flight 15s ttl fallback
- Added AbortSignal propagation and timeout-race handling for broker health, usage, refresh, and snapshot calls.
- Added single-flight usage-report caching with 15s TTL, per-caller abort races, and null-on-fail fallback.
- Expanded provider schemas and parse/build logic for cache metadata, headers, stop controls, and image/file content.
- Hardened auth flows by rejecting refresh sentinels and using timing-safe bearer-token comparisons.
2026-05-17 01:10:25 +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