@oh-my-pi/pi-ai 18.2.11 → 18.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/THIRD-PARTY-NOTICES.txt +3 -3
  3. package/dist/types/auth/abort.d.ts +6 -0
  4. package/dist/types/auth/affinity.d.ts +68 -0
  5. package/dist/types/auth/blocks.d.ts +115 -0
  6. package/dist/types/auth/cascade.d.ts +147 -0
  7. package/dist/types/auth/health.d.ts +66 -0
  8. package/dist/types/auth/oauth.d.ts +93 -0
  9. package/dist/types/auth/policy.d.ts +27 -0
  10. package/dist/types/auth/pool.d.ts +214 -0
  11. package/dist/types/auth/rank.d.ts +53 -0
  12. package/dist/types/auth/refresh.d.ts +59 -0
  13. package/dist/types/auth/resets.d.ts +28 -0
  14. package/dist/types/auth/rotation.d.ts +66 -0
  15. package/dist/types/auth/select.d.ts +86 -0
  16. package/dist/types/auth/sqlite-credential-store.d.ts +11 -10
  17. package/dist/types/auth/store.d.ts +195 -0
  18. package/dist/types/auth/types.d.ts +1142 -0
  19. package/dist/types/auth/usage-cache.d.ts +73 -0
  20. package/dist/types/auth/usage-report.d.ts +32 -0
  21. package/dist/types/auth/usage.d.ts +109 -0
  22. package/dist/types/auth-broker/discover.d.ts +35 -1
  23. package/dist/types/auth-broker/refresher.d.ts +1 -1
  24. package/dist/types/auth-broker/remote-store.d.ts +8 -11
  25. package/dist/types/auth-broker/types.d.ts +1 -1
  26. package/dist/types/auth-gateway/dispatch.d.ts +1 -1
  27. package/dist/types/auth-gateway/types.d.ts +2 -0
  28. package/dist/types/auth-retry.d.ts +21 -21
  29. package/dist/types/auth-storage.d.ts +53 -1329
  30. package/dist/types/error/rate-limit.d.ts +3 -2
  31. package/dist/types/index.d.ts +3 -0
  32. package/dist/types/provider-session-state.d.ts +2 -2
  33. package/dist/types/providers/anthropic-client.d.ts +6 -0
  34. package/dist/types/providers/anthropic-compaction.d.ts +1 -1
  35. package/dist/types/providers/anthropic-slow-mode.d.ts +94 -0
  36. package/dist/types/providers/anthropic-user-profiles.d.ts +88 -0
  37. package/dist/types/providers/anthropic-wire.d.ts +24 -14
  38. package/dist/types/providers/anthropic.d.ts +3 -2
  39. package/dist/types/providers/apple-foundation-models.d.ts +37 -0
  40. package/dist/types/providers/mock.d.ts +3 -1
  41. package/dist/types/providers/openai-codex/access-programs.d.ts +13 -0
  42. package/dist/types/providers/openai-codex/live-steering.d.ts +77 -0
  43. package/dist/types/providers/openai-codex/request-transformer.d.ts +4 -0
  44. package/dist/types/providers/register-builtins.d.ts +2 -0
  45. package/dist/types/providers/transform-messages.d.ts +10 -2
  46. package/dist/types/registry/oauth/types.d.ts +1 -1
  47. package/dist/types/registry/types.d.ts +1 -1
  48. package/dist/types/types.d.ts +117 -23
  49. package/dist/types/usage/claude-reset.d.ts +3 -1
  50. package/dist/types/usage/registry.d.ts +10 -0
  51. package/dist/types/usage/xai-oauth.d.ts +6 -1
  52. package/dist/types/usage.d.ts +19 -3
  53. package/dist/types/utils/http-inspector.d.ts +6 -0
  54. package/dist/types/utils/schema/foundation-models.d.ts +15 -0
  55. package/dist/types/utils/schema/index.d.ts +1 -0
  56. package/package.json +10 -7
  57. package/src/api-registry.ts +1 -0
  58. package/src/auth/abort.ts +17 -0
  59. package/src/auth/affinity.ts +267 -0
  60. package/src/auth/blocks.ts +572 -0
  61. package/src/auth/cascade.ts +491 -0
  62. package/src/auth/health.ts +432 -0
  63. package/src/auth/oauth.ts +352 -0
  64. package/src/auth/policy.ts +162 -0
  65. package/src/auth/pool.ts +817 -0
  66. package/src/auth/rank.ts +146 -0
  67. package/src/auth/refresh.ts +575 -0
  68. package/src/auth/resets.ts +252 -0
  69. package/src/auth/rotation.ts +496 -0
  70. package/src/auth/select.ts +1058 -0
  71. package/src/auth/sqlite-credential-store.ts +22 -20
  72. package/src/auth/store.ts +242 -0
  73. package/src/auth/types.ts +1240 -0
  74. package/src/auth/usage-cache.ts +332 -0
  75. package/src/auth/usage-report.ts +269 -0
  76. package/src/auth/usage.ts +821 -0
  77. package/src/auth-broker/discover.ts +218 -40
  78. package/src/auth-broker/refresher.ts +7 -6
  79. package/src/auth-broker/remote-store.ts +12 -39
  80. package/src/auth-broker/server.ts +25 -25
  81. package/src/auth-broker/types.ts +1 -1
  82. package/src/auth-gateway/dispatch.ts +18 -14
  83. package/src/auth-gateway/http.ts +2 -1
  84. package/src/auth-gateway/routes/video.ts +1 -1
  85. package/src/auth-gateway/server.ts +3 -2
  86. package/src/auth-gateway/types.ts +2 -0
  87. package/src/auth-retry.ts +47 -30
  88. package/src/auth-storage.ts +233 -7587
  89. package/src/error/flags.ts +2 -1
  90. package/src/error/rate-limit.ts +8 -4
  91. package/src/index.ts +3 -0
  92. package/src/provider-session-state.ts +2 -2
  93. package/src/providers/anthropic-client.ts +31 -9
  94. package/src/providers/anthropic-compaction.ts +28 -11
  95. package/src/providers/anthropic-identity.ts +1 -1
  96. package/src/providers/anthropic-messages-server.ts +2 -0
  97. package/src/providers/anthropic-slow-mode.ts +195 -0
  98. package/src/providers/anthropic-user-profiles.ts +195 -0
  99. package/src/providers/anthropic-wire.ts +22 -12
  100. package/src/providers/anthropic.ts +830 -527
  101. package/src/providers/apple-foundation-models.ts +406 -0
  102. package/src/providers/cowork-fetch.ts +11 -4
  103. package/src/providers/cursor.ts +4 -3
  104. package/src/providers/google-gemini-cli.ts +2 -2
  105. package/src/providers/google-shared.ts +30 -7
  106. package/src/providers/inference-headers.ts +7 -1
  107. package/src/providers/mock.ts +4 -0
  108. package/src/providers/openai-codex/access-programs.ts +70 -0
  109. package/src/providers/openai-codex/live-steering.ts +237 -0
  110. package/src/providers/openai-codex/request-transformer.ts +2 -0
  111. package/src/providers/openai-codex-responses.ts +432 -74
  112. package/src/providers/pi-native-server.ts +3 -2
  113. package/src/providers/register-builtins.ts +6 -0
  114. package/src/providers/transform-messages.ts +36 -7
  115. package/src/registry/oauth/types.ts +1 -1
  116. package/src/registry/types.ts +1 -1
  117. package/src/stream.ts +49 -9
  118. package/src/types.ts +124 -20
  119. package/src/usage/claude-reset.ts +20 -1
  120. package/src/usage/claude.ts +14 -0
  121. package/src/usage/google-antigravity.ts +1 -0
  122. package/src/usage/openai-codex.ts +140 -5
  123. package/src/usage/opencode-go.ts +4 -0
  124. package/src/usage/registry.ts +73 -0
  125. package/src/usage/xai-oauth.ts +31 -1
  126. package/src/usage/zai.ts +1 -0
  127. package/src/usage.ts +20 -4
  128. package/src/utils/http-inspector.ts +21 -2
  129. package/src/utils/openrouter-headers.ts +3 -3
  130. package/src/utils/schema/foundation-models.ts +255 -0
  131. package/src/utils/schema/index.ts +1 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,30 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.3.1] - 2026-09-25
6
+
7
+ ### Added
8
+
9
+ - Added live steering support for GPT-6 models, allowing queued user messages to be delivered during an active streaming response.
10
+ - Added the `anthropicSlowMode` stream option for first-party Claude OAuth requests, enabling slow-mode rate-limit handling, per-account rate-limit reporting, and server-paced retries during capacity limits.
11
+ - Added support for capturing and redeeming Anthropic fallback credit tokens, including prompt-cache repricing for classifier refusals.
12
+ - Added Vercel AI Gateway app attribution by sending `http-referer: https://omp.sh/` and `x-title: omp` by default; user-provided header values take precedence.
13
+
14
+ ### Fixed
15
+
16
+ - Fixed account selection for OpenCode Go and SuperGrok (xai-oauth) so accounts without available funds or included quota are skipped in favor of eligible accounts.
17
+ - Improved visibility into automatically disabled authentication credentials by logging a warning and including the affected account details in credential-disabled events.
18
+
19
+ ## [18.3.0] - 2026-09-24
20
+
21
+ ### Added
22
+
23
+ - Added support for Anthropic User Profiles, including schema-validated API responses.
24
+ - Added support for Apple Foundation Models running on-device, including tool calling and vision capabilities.
25
+ - Added multi-account authentication and authorization for Codex cyber access programs, including automatic request replay after access-program rejections.
26
+ - Added credential-aware authentication routing with per-account OAuth policies, deterministic account selection, protected quota reserves, persistent rate-limit tracking, automatic recovery, and sticky session-to-credential affinity.
27
+ - Added deprecated `getApiKey` and `reload` methods for backward compatibility.
28
+
5
29
  ## [18.2.11] - 2026-09-23
6
30
 
7
31
  ### Fixed
@@ -78,8 +78,8 @@ below.
78
78
  uutils coreutils (https://github.com/uutils/coreutils), MIT
79
79
  --------------------------------------------------------------------------------
80
80
  Covers: base32, base64, basename, cat, cksum (shared checksum machinery),
81
- b2sum, md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum, comm, cut,
82
- date, dirname, head, hostname, ln, ls, mkdir, mktemp, mv, nproc, paste,
81
+ b2sum, md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum, comm, cp,
82
+ cut, date, dirname, head, hostname, ln, ls, mkdir, mktemp, mv, nproc, paste,
83
83
  printenv, readlink, realpath, rm, seq, sort, stat, tac, tail, tee, touch, tr,
84
84
  truncate, uname, uniq, wc, whoami, yes.
85
85
 
@@ -293,7 +293,7 @@ MIT License
293
293
  Copyright (c) 2026 Sander Land
294
294
  (measured tokenizer vocabulary data, reconstruction model, and reference
295
295
  implementation: https://github.com/sanderland/ctok)
296
- Copyright (c) 2026 Can Bölük and the Oh My Pi contributors
296
+ Copyright (c) 2026 Can Bölük and the omp contributors
297
297
  Copyright (c) 2026 Stencil Labs, Inc.
298
298
  (Rust implementation and the compact binary vocabulary encoding in
299
299
  crates/pi-natives/src/utok/claude)
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Race `promise` against `signal`, rejecting only this caller when the signal
3
+ * fires. The underlying promise keeps running so other awaiters on the same
4
+ * single-flight operation aren't punished by a peer's cancel.
5
+ */
6
+ export declare function raceSignal<T>(promise: Promise<T>, signal: AbortSignal | undefined, message: string): Promise<T>;
@@ -0,0 +1,68 @@
1
+ import type { AuthCredential, OAuthCredential, SessionsApi } from "./types.js";
2
+ import type { AuthCredentialStore } from "./store.js";
3
+ import type { CredentialPool } from "./pool.js";
4
+ import type { KeyOverrides } from "./cascade.js";
5
+ /** Prefix for persisted session-to-credential affinity. */
6
+ export declare const SESSION_STICKY_CACHE_PREFIX = "session:sticky:";
7
+ /** A session's pinned credential (resolved index + durable row id). */
8
+ export type SessionCredential = {
9
+ type: AuthCredential["type"];
10
+ index: number;
11
+ credentialId?: number;
12
+ lastUsedAtMs?: number;
13
+ /** Set only by the public user-facing pin API; automatic warm affinity leaves it absent. */
14
+ explicit?: true;
15
+ };
16
+ /** Session → credential affinity (pins), persisted in the store cache. */
17
+ export declare class SessionAffinity implements SessionsApi {
18
+ #private;
19
+ constructor(store: AuthCredentialStore, pool: CredentialPool, overrides: KeyOverrides);
20
+ /** Drop every pin for a provider, both in memory and in the persisted cache. */
21
+ clearProvider(provider: string): void;
22
+ /** Drop only this in-memory session pin after OAuth selection falls through. */
23
+ forget(provider: string, sessionId: string): void;
24
+ /**
25
+ * Records which credential was used for a session (for rate-limit switching).
26
+ * `lastUsedAtMs` backdates the sticky (session-file pin restores on resume);
27
+ * it defaults to now for live selections. Automatic re-recording of the same
28
+ * durable row preserves an explicit user pin.
29
+ */
30
+ record(provider: string, sessionId: string | undefined, type: AuthCredential["type"], index: number, lastUsedAtMs?: number, explicit?: boolean): void;
31
+ /** Retrieves the last credential used by a session. */
32
+ get(provider: string, sessionId: string | undefined): SessionCredential | undefined;
33
+ /** Clears the last credential used by a session for a provider. */
34
+ clear(provider: string, sessionId: string | undefined): void;
35
+ activeOAuth(provider: string, sessionId?: string): OAuthCredential | undefined;
36
+ /**
37
+ * Pin one stored OAuth account as this session's preferred credential.
38
+ *
39
+ * The durable credential id keeps the pin stable across credential refreshes,
40
+ * storage reordering, and process restarts. By default this is an explicit
41
+ * user pin: ranking and account reserve never evict it; hard unavailability
42
+ * and auth retry may still route around it.
43
+ *
44
+ * `options.restoredAtMs` instead restores an automatic affinity recorded by a
45
+ * persisted session, backdated to its last use, so it keeps the provider's
46
+ * warm-window semantics: a resume inside the prompt-cache TTL reuses the
47
+ * account, a stale resume re-ranks.
48
+ */
49
+ pin(provider: string, sessionId: string, credentialId: number, options?: {
50
+ restoredAtMs?: number;
51
+ }): boolean;
52
+ /**
53
+ * Copy every stored credential affinity from one live session to another.
54
+ *
55
+ * The target receives its own sticky entries, so request resolution, usage
56
+ * blocking, credential rotation, metadata, and persisted pins all continue
57
+ * through the target session id without retaining a live dependency on the
58
+ * source session.
59
+ */
60
+ inherit(sourceSessionId: string, targetSessionId: string): number;
61
+ /**
62
+ * Release a session's sticky credential so its next `KeyCascade.get` call
63
+ * re-runs native pool ranking. This never blocks or penalizes the released
64
+ * account; usage-aware routing uses it when another sibling has more
65
+ * headroom, before considering a model/provider fallback.
66
+ */
67
+ release(provider: string, sessionId: string): boolean;
68
+ }
@@ -0,0 +1,115 @@
1
+ import type { Provider } from "../types.js";
2
+ import type { CredentialRankingContext, CredentialRankingStrategy, UsageReport } from "../usage.js";
3
+ import type { RankingStrategyResolver } from "../usage/registry.js";
4
+ import type { CredentialPool } from "./pool.js";
5
+ import type { AuthCredentialStore } from "./store.js";
6
+ import type { UsageCache, UsageRequestDescriptor } from "./usage-cache.js";
7
+ import type { AuthCredential, BlocksApi, StoredCredentialBlock } from "./types.js";
8
+ /** Default block when no provider reset time is known; used by selectors and rate limits. */
9
+ export declare const DEFAULT_BLOCK_MS = 60000;
10
+ /** Composite key for round-robin tracking: "<provider>:oauth" or "<provider>:api_key". */
11
+ export declare function providerTypeKey(provider: string, type: AuthCredential["type"]): string;
12
+ /** Scoped backoff map key used by the credential block store. */
13
+ export declare function scopedBackoffKey(providerKey: string, blockScope: string | undefined): string;
14
+ /** Scope key for one model-specific account-policy block, shared by selectors and rate limits. */
15
+ export declare function modelAccountPolicyBlockScope(provider: string, modelId: string | undefined): string | undefined;
16
+ /** Scope keys that a request must check, including model-policy constraints. */
17
+ export declare function credentialBlockScopesForRequest(provider: string, strategy: CredentialRankingStrategy | undefined, rankingContext: CredentialRankingContext, blockScope: string | undefined): readonly string[];
18
+ /** Latch for unrecoverably corrupt persisted block stores, shared with the credential pool. */
19
+ export declare class BlockStoreHealth {
20
+ #private;
21
+ constructor(sourceLabel: string | undefined);
22
+ get damaged(): boolean;
23
+ handle(err: unknown): boolean;
24
+ assertWritable(): void;
25
+ }
26
+ /** Dependencies for persisted rate-limit blocks and usage-report healing. */
27
+ export interface CredentialBlocksDeps {
28
+ store: AuthCredentialStore;
29
+ pool: CredentialPool;
30
+ health: BlockStoreHealth;
31
+ usageCache: UsageCache;
32
+ strategies: RankingStrategyResolver;
33
+ }
34
+ /** Temporary rate-limit blocks: id-keyed in memory, mirrored to the store, healed by live usage. */
35
+ export declare class CredentialBlocks implements BlocksApi {
36
+ #private;
37
+ constructor(deps: CredentialBlocksDeps);
38
+ /** Returns block expiry timestamp for a credential, checking unscoped and scoped blocks. */
39
+ blockedUntil(provider: string, providerKey: string, credentialIndex: number, blockScopeOrScopes?: string | readonly string[] | undefined): number | undefined;
40
+ /** Checks if a credential is temporarily blocked due to usage limits. */
41
+ isBlocked(provider: string, providerKey: string, credentialIndex: number, blockScope?: string | readonly string[] | undefined): boolean;
42
+ /**
43
+ * Whether the in-memory block currently sitting at exactly `deadline` for
44
+ * this credential was written with provider-stated timing. Mirrors the
45
+ * scope enumeration of {@link CredentialBlocks.blockedUntil}.
46
+ * A deadline with no matching in-memory entry came from the persisted
47
+ * store, which carries no provenance — a stale persisted heuristic guess
48
+ * (pre-restart hintless response) must not outrank a fresh complete usage
49
+ * report, so persisted-only deadlines count as untimed. Persisted
50
+ * deadlines longer than this call's own request still win through the
51
+ * merged `blockedUntilMs` comparison, which needs no provenance.
52
+ */
53
+ isTimed(providerKey: string, blockScopeOrScopes: string | readonly string[] | undefined, credentialId: number, deadline: number): boolean;
54
+ /**
55
+ * Marks a credential as blocked until the specified time. `providerTimed`
56
+ * records whether the requested deadline comes from provider-stated
57
+ * timing (a parsed retry hint or a usage-report reset) rather than a
58
+ * heuristic/default guess; the stored block keeps the provenance of
59
+ * whichever deadline wins the longest-wins merge.
60
+ */
61
+ mark(provider: string, providerKey: string, credentialIndex: number, blockedUntilMs: number, blockScope?: string | undefined, providerTimed?: boolean): void;
62
+ /**
63
+ * Lift any temporary backoff blocks on one credential (across the bare
64
+ * `provider:oauth` key and its scoped `\0`-suffixed derivatives). Called
65
+ * after a saved reset is redeemed so the just-reset account is immediately
66
+ * selectable again instead of being skipped/under-ranked by a stale block
67
+ * that `markUsageLimitReached` set for the now-obsolete reset time.
68
+ */
69
+ clearAll(provider: string, credentialId: number): void;
70
+ /**
71
+ * Clear one backoff scope. The in-memory backoff is per scope so it is
72
+ * dropped directly; the persisted store deletes a credential's blocks as a
73
+ * unit, so it is only purged once no other scope still holds a live block.
74
+ * Leaving a persisted row behind is safe: the scope it belongs to is
75
+ * unblocked in memory, and the row heals on the pass where its own meter
76
+ * recovers.
77
+ */
78
+ clearScope(provider: string, credentialId: number, providerKey: string, blockScope: string | undefined): void;
79
+ /** Providers whose stale usage-limit blocks a healthy live report may clear. */
80
+ supportsHealing(provider: Provider): boolean;
81
+ /**
82
+ * Whether a fresh report could lift what currently blocks this credential.
83
+ *
84
+ * A strategy that names healable scopes can only vouch for those scopes, so
85
+ * a live unscoped block — an Opus/Sonnet usage limit, a refresh failure —
86
+ * keeps the credential unusable whatever the report says about a tier. A
87
+ * probe then cannot change the outcome and must not be spent; the tier scope
88
+ * heals on a later pass, once the block that actually holds the credential
89
+ * has lifted.
90
+ */
91
+ canHeal(provider: Provider, providerKey: string, credentialIndex: number, blockScopeOrScopes: string | readonly string[] | undefined): boolean;
92
+ /**
93
+ * Self-heal stale usage-limit blocks: when a fresh live usage report says a
94
+ * scope is below every limit gating it, drop its persisted and in-memory
95
+ * blocks so credential selection re-includes the recovered account before
96
+ * the block expires by clock. Providers declare their scopes and any meter
97
+ * verdicts via {@link CredentialRankingStrategy.healableBlockScopes}.
98
+ */
99
+ reconcile(provider: Provider, credentialId: number, report: UsageReport): void;
100
+ reconcileRequest(request: UsageRequestDescriptor, report: UsageReport): void;
101
+ reconcileReports(reports: UsageReport[]): void;
102
+ /**
103
+ * Broker-server seam: list non-expired persisted blocks for snapshot entries.
104
+ */
105
+ list(credentialIds: readonly number[]): StoredCredentialBlock[];
106
+ /**
107
+ * Broker-server seam: persist one credential block and notify snapshot waiters.
108
+ */
109
+ upsert(block: StoredCredentialBlock): void;
110
+ /**
111
+ * Broker-server seam: clear all persisted blocks for one credential and notify snapshot waiters.
112
+ */
113
+ delete(credentialId: number, providerKey: string, blockScope: string): void;
114
+ deleteAll(credentialId: number): void;
115
+ }
@@ -0,0 +1,147 @@
1
+ import type { ApiKeyResolver, ResolvedApiKey } from "../auth-retry.js";
2
+ import type { SessionAffinity } from "./affinity.js";
3
+ import type { CredentialPool } from "./pool.js";
4
+ import type { CredentialSelector } from "./select.js";
5
+ import type { AuthApiKeyOptions, AuthCredential, AuthSource, AuthSourceOptions, KeysApi, LimitsApi } from "./types.js";
6
+ /** Runtime (--api-key) and config (models.yml) key overrides plus the config-value resolver. */
7
+ export declare class KeyOverrides {
8
+ #private;
9
+ constructor(resolver?: (config: string) => Promise<string | undefined>);
10
+ has(provider: string): boolean;
11
+ runtimeKey(provider: string): string | undefined;
12
+ configKey(provider: string): string | undefined;
13
+ /** Resolve a config value (env var name, "!command", literal) to the secret. */
14
+ resolve(config: string): Promise<string | undefined>;
15
+ /**
16
+ * Set a runtime API key override (not persisted to disk).
17
+ * Used for CLI --api-key flag.
18
+ */
19
+ setRuntime(provider: string, apiKey: string): void;
20
+ /**
21
+ * Remove a runtime API key override.
22
+ */
23
+ removeRuntime(provider: string): void;
24
+ /**
25
+ * Register a per-provider API key sourced from user configuration
26
+ * (e.g. `models.yml` `providers.<name>.apiKey`). Higher priority than
27
+ * stored credentials and OAuth tokens — when the user pins a key in
28
+ * config, that key is what authenticates outbound requests, regardless
29
+ * of whatever the broker happens to have loaded for that provider.
30
+ *
31
+ * Lower priority than {@link KeyOverrides.setRuntime} so a CLI `--api-key`
32
+ * still wins for the duration of a single invocation.
33
+ */
34
+ setConfig(provider: string, apiKeyConfig: string): void;
35
+ /**
36
+ * Remove a single config-sourced API key override.
37
+ */
38
+ removeConfig(provider: string): void;
39
+ /**
40
+ * Drop every config-sourced API key. Called by `ModelRegistry` before
41
+ * re-parsing `models.yml` so removed entries actually disappear.
42
+ */
43
+ clearConfig(): void;
44
+ /**
45
+ * Install the host's async config-value resolver. Coding-agent uses this so
46
+ * every stored/config credential reference shares command caching,
47
+ * failure backoff, and process hardening even when AuthStorage was created
48
+ * independently and later attached to a registry.
49
+ */
50
+ setResolver(resolver: (config: string) => Promise<string | undefined>): void;
51
+ }
52
+ /** Dependencies of the provider key precedence cascade. */
53
+ export interface KeyCascadeDeps {
54
+ pool: CredentialPool;
55
+ overrides: KeyOverrides;
56
+ selector: CredentialSelector;
57
+ affinity: SessionAffinity;
58
+ /** LimitsApi.rotate, injected to avoid a cascade↔rotation import cycle. */
59
+ rotate: LimitsApi["rotate"];
60
+ sourceLabel?: string;
61
+ }
62
+ /** The provider auth precedence cascade (runtime → config → OAuth → login key → env → stored key). */
63
+ export declare class KeyCascade implements KeysApi {
64
+ #private;
65
+ constructor(deps: KeyCascadeDeps);
66
+ /**
67
+ * True when a stored credential is the provider's KDL `empty-fallback`
68
+ * keyless-mode marker — what an empty paste at an "Optional: paste API key"
69
+ * login prompt stores (e.g. `lm-studio-local` for lm-studio). The wire layer
70
+ * never sends these as a bearer (`isDiscoveryBearerApiKey` strips them), so
71
+ * auth-status surfaces must not count them either; otherwise the model hub
72
+ * and `/login` report the provider as authenticated while every request
73
+ * goes out bare (issue #12281). The credential itself stays stored: `/logout`
74
+ * can still remove it, and availability treats the provider as keyless.
75
+ */
76
+ isKeylessFallback(provider: string, credential: AuthCredential): boolean;
77
+ /**
78
+ * True when the provider has stored credentials but none of them carries
79
+ * auth — i.e. its only credential is the KDL `empty-fallback` keyless-mode
80
+ * marker (an empty paste at an optional-key login prompt). Such a provider
81
+ * is configured-but-keyless: model availability treats it like an
82
+ * `auth: none` endpoint instead of locking it out (issue #12281).
83
+ */
84
+ keyless(provider: string): boolean;
85
+ /**
86
+ * Classify where a provider's auth comes from, following the same precedence
87
+ * as {@link KeyCascade.get}: runtime override → config override →
88
+ * stored OAuth → login-stored api_key → env var → stored api_key.
89
+ * Returns undefined when no auth is configured.
90
+ *
91
+ * Compact, structured counterpart to {@link KeyCascade.describe}; `env`
92
+ * selects dedicated-only, alias-aware, or no environment fallback.
93
+ */
94
+ source(provider: string, { env }?: AuthSourceOptions): AuthSource | undefined;
95
+ /**
96
+ * Peek at API key for a provider without refreshing OAuth tokens.
97
+ * Used for model discovery where we only need to know if credentials exist
98
+ * and get a best-effort token. GitHub Copilot's peek must preserve
99
+ * enterprise routing metadata because discovery needs a structured
100
+ * credential to reach the correct host.
101
+ */
102
+ peek(provider: string): Promise<string | undefined>;
103
+ /** Resolve a bearer together with the stored row that supplied it. */
104
+ getWithCredential(provider: string, sessionId?: string, options?: AuthApiKeyOptions): Promise<ResolvedApiKey | undefined>;
105
+ /**
106
+ * Get API key for a provider.
107
+ * Priority (first match wins): runtime override, config override, OAuth,
108
+ * login API key, environment variable, then another stored API key.
109
+ */
110
+ get(provider: string, sessionId?: string, options?: AuthApiKeyOptions, onCredentialId?: (id: number) => void): Promise<string | undefined>;
111
+ /**
112
+ * Build an {@link ApiKeyResolver} backed by this storage, implementing the
113
+ * central a/b/c auth-retry policy:
114
+ *
115
+ * - initial (`error: undefined`) → resolve the session credential.
116
+ * - step (b) `!lastChance` → force-refresh the SAME session-sticky credential.
117
+ * - step (c) `lastChance` → rotate to a sibling and re-resolve, unless quota exhaustion has no sibling.
118
+ *
119
+ * Used by web-search providers and other consumers that hold a KeyCascade
120
+ * directly (no ModelRegistry in scope).
121
+ */
122
+ resolver(provider: string, options?: {
123
+ sessionId?: string;
124
+ baseUrl?: string;
125
+ modelId?: string;
126
+ }): ApiKeyResolver;
127
+ /**
128
+ * Describe where the active credential for a provider came from.
129
+ *
130
+ * Mirrors {@link KeyCascade.get} precedence, highest first:
131
+ * 1. Runtime override (`--api-key`).
132
+ * 2. Config override (`models.yml` `providers.<name>.apiKey`).
133
+ * 3. Stored OAuth credential.
134
+ * 4. API key persisted by a successful `/login`.
135
+ * 5. Env var — overrides a stored static api_key (e.g. a stale broker copy).
136
+ * 6. Stored api_key credential.
137
+ *
138
+ * The string is purely informational; consumers must not parse it.
139
+ */
140
+ describe(provider: string, sessionId?: string): string | undefined;
141
+ setRuntime(provider: string, apiKey: string): void;
142
+ removeRuntime(provider: string): void;
143
+ setConfig(provider: string, apiKeyConfig: string): void;
144
+ removeConfig(provider: string): void;
145
+ clearConfig(): void;
146
+ setResolver(resolver: (config: string) => Promise<string | undefined>): void;
147
+ }
@@ -0,0 +1,66 @@
1
+ import type { Provider } from "../types.js";
2
+ import type { RankingStrategyResolver } from "../usage/registry.js";
3
+ import type { SessionAffinity } from "./affinity.js";
4
+ import type { CredentialBlocks } from "./blocks.js";
5
+ import type { KeyCascade, KeyOverrides } from "./cascade.js";
6
+ import type { AccountPolicies } from "./policy.js";
7
+ import type { CredentialPool } from "./pool.js";
8
+ import type { OAuthRefresher } from "./refresh.js";
9
+ import type { AuthCredentialStore } from "./store.js";
10
+ import type { CheckCredentialsOptions, CredentialHealthResult, HealthApi, ModelUsageHealth, ModelUsageHealthOptions } from "./types.js";
11
+ import type { UsageService } from "./usage.js";
12
+ /** Dependencies for model pool health and stored credential probes. */
13
+ export interface CredentialHealthDeps {
14
+ store: AuthCredentialStore;
15
+ pool: CredentialPool;
16
+ keys: KeyCascade;
17
+ policies: AccountPolicies;
18
+ blocks: CredentialBlocks;
19
+ affinity: SessionAffinity;
20
+ usage: UsageService;
21
+ refresher: OAuthRefresher;
22
+ overrides: KeyOverrides;
23
+ strategies: RankingStrategyResolver;
24
+ }
25
+ /** Model-level pool health and per-credential auth probes. */
26
+ export declare class CredentialHealth implements HealthApi {
27
+ #private;
28
+ constructor(deps: CredentialHealthDeps);
29
+ /**
30
+ * Inspect the credential pool that {@link getApiKey} would use for one model
31
+ * without advancing round-robin state or changing session stickiness.
32
+ *
33
+ * Pool aggregation is deliberately conservative: one healthy sibling makes
34
+ * the model healthy, while any unknown sibling prevents a depleted/reserve
35
+ * conclusion. Static runtime/config/env credentials return unknown because
36
+ * they bypass the managed account pool.
37
+ */
38
+ model(provider: Provider, options: ModelUsageHealthOptions): Promise<ModelUsageHealth>;
39
+ /**
40
+ * Probe each stored credential against its provider's auth-verifying usage
41
+ * endpoint and report per-credential auth health.
42
+ *
43
+ * Surfaces the identity of failing credentials so callers running a
44
+ * multi-account pool (e.g. a broker-backed auth-gateway) can tell which
45
+ * row is producing 401s. The probe mirrors the per-credential fan-out
46
+ * inside {@link UsageService.reports} (OAuth refresh-on-expiry,
47
+ * then `UsageProvider.fetchUsage`) but does NOT swallow errors — every
48
+ * credential gets either `ok: true`, `ok: false` with `reason`, or
49
+ * `ok: null` when no probe is configured for the provider.
50
+ *
51
+ * Iterates sequentially to avoid synchronized N-account fan-out that
52
+ * upstream `/usage` rate limiters (per source IP) treat as a burst.
53
+ *
54
+ * Only inspects active rows from {@link AuthCredentialStore.listAuthCredentials};
55
+ * soft-disabled rows are already known-bad and don't need a network probe.
56
+ * Environment-variable API keys are not enumerated — the caller's intent
57
+ * here is "which of my stored credentials is broken".
58
+ *
59
+ * Pass {@link CheckCredentialsOptions.completionProbe} to additionally
60
+ * exercise each credential against the provider's chat-completion endpoint
61
+ * (strict mode). The result lands on
62
+ * {@link CredentialHealthResult.completion}; the usage `ok` field is
63
+ * unchanged so callers can tell the two signals apart.
64
+ */
65
+ check(options?: CheckCredentialsOptions): Promise<CredentialHealthResult[]>;
66
+ }
@@ -0,0 +1,93 @@
1
+ import type { OAuthProviderId } from "../registry/oauth/types.js";
2
+ import type { SessionAffinity } from "./affinity.js";
3
+ import type { KeyOverrides } from "./cascade.js";
4
+ import type { AccountPolicies } from "./policy.js";
5
+ import type { CredentialPool } from "./pool.js";
6
+ import type { OAuthRefresher } from "./refresh.js";
7
+ import type { CredentialSelector } from "./select.js";
8
+ import type { AuthAccountPolicy, AuthApiKeyOptions, OAuthAccess, OAuthAccessResolution, OAuthAccountIdentity, OAuthAccountSummary, OAuthApi, OAuthCredential, OAuthLoginController, OAuthLoginIdentity, StoredOAuthRefreshOptions, StoredOAuthRefreshResult, AuthCredentialSnapshotEntry } from "./types.js";
9
+ /** Dependencies used by the OAuth account operations. */
10
+ export interface OAuthAccountsDeps {
11
+ pool: CredentialPool;
12
+ overrides: KeyOverrides;
13
+ policies: AccountPolicies;
14
+ selector: CredentialSelector;
15
+ affinity: SessionAffinity;
16
+ refresher: OAuthRefresher;
17
+ }
18
+ /** OAuth login, per-account access resolution, and account listings. */
19
+ export declare class OAuthAccounts implements OAuthApi {
20
+ #private;
21
+ constructor(deps: OAuthAccountsDeps);
22
+ /**
23
+ * Login to an OAuth provider. Resolves with the stored credential's
24
+ * identity slice (or `undefined` when nothing was stored) so callers can
25
+ * surface which account — and for Anthropic, which organization — the
26
+ * login registered.
27
+ */
28
+ login(provider: OAuthProviderId, ctrl: OAuthLoginController): Promise<OAuthLoginIdentity | undefined>;
29
+ /**
30
+ * Resolve the OAuth credential for `provider`, refreshing through the same
31
+ * pipeline as API-key resolution but returning the refreshed
32
+ * {@link OAuthAccess} (raw access token + identity metadata) instead of
33
+ * the API-key bytes.
34
+ *
35
+ * Use this when the caller needs to inject identity headers alongside the
36
+ * bearer (Codex `chatgpt-account-id`, Google `project`, GitHub
37
+ * `enterpriseUrl`). For pure "give me the bytes for `Authorization`"
38
+ * scenarios, prefer API-key resolution.
39
+ *
40
+ * Returns `undefined` when no OAuth credential is available, the
41
+ * credential fails to refresh, or runtime/config overrides have replaced
42
+ * OAuth with an explicit API key.
43
+ */
44
+ access(provider: string, sessionId?: string, options?: AuthApiKeyOptions): Promise<OAuthAccess | undefined>;
45
+ /**
46
+ * Read-only list of stored OAuth accounts for `provider` in stable storage
47
+ * order, WITHOUT refreshing any token. The array position (0-based) is the
48
+ * selector displayed by a "pick the Nth account" UI as `position + 1`.
49
+ *
50
+ * When `sessionId` is supplied, the session-sticky OAuth credential is marked
51
+ * `active`. No account is active before that session has resolved or pinned a
52
+ * credential.
53
+ */
54
+ accounts(provider: string, sessionId?: string): OAuthAccountSummary[];
55
+ /**
56
+ * Resolve every stored OAuth credential for `provider` independently.
57
+ *
58
+ * Refreshes credentials through the same broker/local path as
59
+ * {@link OAuthAccounts.access}, but does not rank, round-robin, or
60
+ * stop after the first usable account. Intended for diagnostics that must
61
+ * exercise each stored account exactly once.
62
+ */
63
+ accessAll(provider: string, options?: AuthApiKeyOptions): Promise<OAuthAccessResolution[]>;
64
+ /**
65
+ * Resolve one stored OAuth credential by its durable storage row id.
66
+ *
67
+ * Unlike the normal session resolver, this method never ranks, rotates, or
68
+ * falls back to sibling credentials. A forced refresh re-mints only the
69
+ * requested row, preserving exact-account affinity for operations whose
70
+ * provenance and policy boundary are tied to one workspace.
71
+ *
72
+ * Returns `undefined` when the row does not exist for `provider` or an
73
+ * explicit runtime/config API-key override suppresses OAuth.
74
+ */
75
+ accessById(provider: string, credentialId: number, options?: AuthApiKeyOptions): Promise<OAuthAccessResolution | undefined>;
76
+ /**
77
+ * Get the OAuth account identity for a provider, preferring the credential that
78
+ * is session-sticky for `sessionId`. This is a read-only lookup for display and
79
+ * metadata paths; it does not refresh tokens, rank usage, or advance selection.
80
+ */
81
+ identity(provider: string, sessionId?: string): OAuthAccountIdentity | undefined;
82
+ /**
83
+ * Return the configured account policy matching an OAuth identity.
84
+ *
85
+ * This is a read-only diagnostics surface: it performs the same conjunctive
86
+ * selector match as routing and never refreshes, ranks, or mutates credentials.
87
+ */
88
+ policy(provider: string, identity: OAuthAccountIdentity): AuthAccountPolicy | undefined;
89
+ /** Force-refresh one stored credential by its durable row id. */
90
+ refresh(id: number, signal?: AbortSignal): Promise<AuthCredentialSnapshotEntry>;
91
+ /** Refresh one stored OAuth credential through the durable ownership path. */
92
+ refreshStored<T extends OAuthCredential = OAuthCredential>(provider: string, options: StoredOAuthRefreshOptions<T>): Promise<StoredOAuthRefreshResult<T>>;
93
+ }
@@ -0,0 +1,27 @@
1
+ import type { AuthAccountPolicies, AuthAccountPolicy, AuthAccountSelector, AuthCredential, OAuthAccountIdentity } from "./types.js";
2
+ /** Whether every identity field set on `selector` matches `identity`. */
3
+ export declare function matchesAuthAccountSelector(selector: AuthAccountSelector, identity: OAuthAccountIdentity): boolean;
4
+ /** Validated per-account routing policies (priority/reserve) plus the global reserve fallback. */
5
+ export declare class AccountPolicies {
6
+ #private;
7
+ constructor(policies: AuthAccountPolicies, defaultReservePct: number | undefined);
8
+ /** Global usage reserve (0–100) for accounts without a per-account `reservePct`. */
9
+ get defaultReservePct(): number;
10
+ /**
11
+ * Replace the policy set and global reserve in place (live settings change).
12
+ * Validates the configuration and every provider in `storedCredentials` before
13
+ * committing; on error the previous policies stay active.
14
+ */
15
+ replace(policies: AuthAccountPolicies, defaultReservePct: number | undefined, storedCredentials?: ReadonlyMap<string, readonly AuthCredential[]>): void;
16
+ validateUsageCapability(provider: string, canFetchUsage: boolean): void;
17
+ validateFor(provider: string, credentials: readonly AuthCredential[]): void;
18
+ /**
19
+ * Return the configured account policy matching an OAuth identity.
20
+ *
21
+ * This is a read-only diagnostics surface: it performs the same conjunctive
22
+ * selector match as routing and never refreshes, ranks, or mutates credentials.
23
+ */
24
+ find(provider: string, identity: OAuthAccountIdentity): AuthAccountPolicy | undefined;
25
+ /** Return the configured policy for a stored OAuth credential. */
26
+ forCredential(provider: string, credential: AuthCredential): AuthAccountPolicy | undefined;
27
+ }