@oh-my-pi/pi-ai 15.1.1 → 15.1.2

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 (165) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/types/api-registry.d.ts +30 -0
  3. package/dist/types/auth-storage.d.ts +289 -0
  4. package/dist/types/cli.d.ts +2 -0
  5. package/dist/types/index.d.ts +44 -0
  6. package/dist/types/model-cache.d.ts +10 -0
  7. package/dist/types/model-manager.d.ts +62 -0
  8. package/dist/types/model-thinking.d.ts +71 -0
  9. package/dist/types/models.d.ts +12 -0
  10. package/dist/types/provider-details.d.ts +18 -0
  11. package/dist/types/provider-models/bundled-references.d.ts +4 -0
  12. package/dist/types/provider-models/descriptors.d.ts +48 -0
  13. package/dist/types/provider-models/google.d.ts +19 -0
  14. package/dist/types/provider-models/index.d.ts +5 -0
  15. package/dist/types/provider-models/ollama.d.ts +7 -0
  16. package/dist/types/provider-models/openai-compat.d.ts +225 -0
  17. package/dist/types/provider-models/special.d.ts +25 -0
  18. package/dist/types/providers/amazon-bedrock.d.ts +14 -0
  19. package/dist/types/providers/anthropic.d.ts +148 -0
  20. package/dist/types/providers/azure-openai-responses.d.ts +15 -0
  21. package/dist/types/providers/cursor/gen/agent_pb.d.ts +13022 -0
  22. package/dist/types/providers/cursor.d.ts +36 -0
  23. package/dist/types/providers/error-message.d.ts +27 -0
  24. package/dist/types/providers/github-copilot-headers.d.ts +40 -0
  25. package/dist/types/providers/gitlab-duo.d.ts +27 -0
  26. package/dist/types/providers/google-gemini-cli.d.ts +72 -0
  27. package/dist/types/providers/google-gemini-headers.d.ts +18 -0
  28. package/dist/types/providers/google-shared.d.ts +160 -0
  29. package/dist/types/providers/google-vertex.d.ts +7 -0
  30. package/dist/types/providers/google.d.ts +4 -0
  31. package/dist/types/providers/grammar.d.ts +1 -0
  32. package/dist/types/providers/kimi.d.ts +27 -0
  33. package/dist/types/providers/mock.d.ts +153 -0
  34. package/dist/types/providers/ollama.d.ts +6 -0
  35. package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
  36. package/dist/types/providers/openai-codex/constants.d.ts +26 -0
  37. package/dist/types/providers/openai-codex/request-transformer.d.ts +49 -0
  38. package/dist/types/providers/openai-codex/response-handler.d.ts +17 -0
  39. package/dist/types/providers/openai-codex-responses.d.ts +67 -0
  40. package/dist/types/providers/openai-completions-compat.d.ts +25 -0
  41. package/dist/types/providers/openai-completions.d.ts +33 -0
  42. package/dist/types/providers/openai-responses-shared.d.ts +65 -0
  43. package/dist/types/providers/openai-responses.d.ts +32 -0
  44. package/dist/types/providers/register-builtins.d.ts +31 -0
  45. package/dist/types/providers/synthetic.d.ts +26 -0
  46. package/dist/types/providers/transform-messages.d.ts +12 -0
  47. package/dist/types/providers/vision-guard.d.ts +8 -0
  48. package/dist/types/rate-limit-utils.d.ts +19 -0
  49. package/dist/types/stream.d.ts +17 -0
  50. package/dist/types/types.d.ts +670 -0
  51. package/dist/types/usage/claude.d.ts +3 -0
  52. package/dist/types/usage/gemini.d.ts +2 -0
  53. package/dist/types/usage/github-copilot.d.ts +7 -0
  54. package/dist/types/usage/google-antigravity.d.ts +2 -0
  55. package/dist/types/usage/kimi.d.ts +2 -0
  56. package/dist/types/usage/minimax-code.d.ts +2 -0
  57. package/dist/types/usage/openai-codex.d.ts +3 -0
  58. package/dist/types/usage/shared.d.ts +1 -0
  59. package/dist/types/usage/zai.d.ts +2 -0
  60. package/dist/types/usage.d.ts +117 -0
  61. package/dist/types/utils/abort.d.ts +19 -0
  62. package/dist/types/utils/anthropic-auth.d.ts +44 -0
  63. package/dist/types/utils/discovery/antigravity.d.ts +61 -0
  64. package/dist/types/utils/discovery/codex.d.ts +38 -0
  65. package/dist/types/utils/discovery/cursor.d.ts +23 -0
  66. package/dist/types/utils/discovery/gemini.d.ts +25 -0
  67. package/dist/types/utils/discovery/index.d.ts +5 -0
  68. package/dist/types/utils/discovery/openai-compatible.d.ts +72 -0
  69. package/dist/types/utils/event-stream.d.ts +28 -0
  70. package/dist/types/utils/fireworks-model-id.d.ts +2 -0
  71. package/dist/types/utils/foundry.d.ts +1 -0
  72. package/dist/types/utils/h2-fetch.d.ts +22 -0
  73. package/dist/types/utils/http-inspector.d.ts +31 -0
  74. package/dist/types/utils/idle-iterator.d.ts +58 -0
  75. package/dist/types/utils/json-parse.d.ts +10 -0
  76. package/dist/types/utils/oauth/alibaba-coding-plan.d.ts +18 -0
  77. package/dist/types/utils/oauth/anthropic.d.ts +22 -0
  78. package/dist/types/utils/oauth/api-key-login.d.ts +35 -0
  79. package/dist/types/utils/oauth/api-key-validation.d.ts +27 -0
  80. package/dist/types/utils/oauth/callback-server.d.ts +57 -0
  81. package/dist/types/utils/oauth/cerebras.d.ts +1 -0
  82. package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
  83. package/dist/types/utils/oauth/cursor.d.ts +15 -0
  84. package/dist/types/utils/oauth/fireworks.d.ts +1 -0
  85. package/dist/types/utils/oauth/github-copilot.d.ts +36 -0
  86. package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
  87. package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
  88. package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
  89. package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
  90. package/dist/types/utils/oauth/huggingface.d.ts +19 -0
  91. package/dist/types/utils/oauth/index.d.ts +35 -0
  92. package/dist/types/utils/oauth/kagi.d.ts +17 -0
  93. package/dist/types/utils/oauth/kilo.d.ts +5 -0
  94. package/dist/types/utils/oauth/kimi.d.ts +21 -0
  95. package/dist/types/utils/oauth/litellm.d.ts +18 -0
  96. package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
  97. package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
  98. package/dist/types/utils/oauth/moonshot.d.ts +1 -0
  99. package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
  100. package/dist/types/utils/oauth/nvidia.d.ts +18 -0
  101. package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
  102. package/dist/types/utils/oauth/ollama.d.ts +18 -0
  103. package/dist/types/utils/oauth/openai-codex.d.ts +14 -0
  104. package/dist/types/utils/oauth/opencode.d.ts +18 -0
  105. package/dist/types/utils/oauth/parallel.d.ts +17 -0
  106. package/dist/types/utils/oauth/perplexity.d.ts +9 -0
  107. package/dist/types/utils/oauth/pkce.d.ts +8 -0
  108. package/dist/types/utils/oauth/qianfan.d.ts +17 -0
  109. package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
  110. package/dist/types/utils/oauth/synthetic.d.ts +1 -0
  111. package/dist/types/utils/oauth/tavily.d.ts +17 -0
  112. package/dist/types/utils/oauth/together.d.ts +1 -0
  113. package/dist/types/utils/oauth/types.d.ts +44 -0
  114. package/dist/types/utils/oauth/venice.d.ts +18 -0
  115. package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
  116. package/dist/types/utils/oauth/vllm.d.ts +16 -0
  117. package/dist/types/utils/oauth/xiaomi.d.ts +19 -0
  118. package/dist/types/utils/oauth/zai.d.ts +18 -0
  119. package/dist/types/utils/oauth/zenmux.d.ts +1 -0
  120. package/dist/types/utils/overflow.d.ts +54 -0
  121. package/dist/types/utils/provider-response.d.ts +3 -0
  122. package/dist/types/utils/retry-after.d.ts +3 -0
  123. package/dist/types/utils/retry.d.ts +25 -0
  124. package/dist/types/utils/schema/adapt.d.ts +21 -0
  125. package/dist/types/utils/schema/compatibility.d.ts +30 -0
  126. package/dist/types/utils/schema/dereference.d.ts +11 -0
  127. package/dist/types/utils/schema/draft.d.ts +10 -0
  128. package/dist/types/utils/schema/equality.d.ts +4 -0
  129. package/dist/types/utils/schema/fields.d.ts +43 -0
  130. package/dist/types/utils/schema/index.d.ts +13 -0
  131. package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
  132. package/dist/types/utils/schema/meta-validator.d.ts +2 -0
  133. package/dist/types/utils/schema/normalize-cca.d.ts +17 -0
  134. package/dist/types/utils/schema/sanitize-google.d.ts +29 -0
  135. package/dist/types/utils/schema/stamps.d.ts +25 -0
  136. package/dist/types/utils/schema/strict-mode.d.ts +56 -0
  137. package/dist/types/utils/schema/types.d.ts +2 -0
  138. package/dist/types/utils/schema/wire.d.ts +24 -0
  139. package/dist/types/utils/sse-debug.d.ts +10 -0
  140. package/dist/types/utils/tool-call-healing.d.ts +71 -0
  141. package/dist/types/utils/tool-choice.d.ts +50 -0
  142. package/dist/types/utils/validation.d.ts +17 -0
  143. package/dist/types/utils.d.ts +28 -0
  144. package/package.json +22 -21
  145. package/src/providers/anthropic.ts +27 -1
  146. package/src/providers/{shared/error-message.ts → error-message.ts} +1 -1
  147. package/src/providers/gitlab-duo.ts +1 -1
  148. package/src/providers/mock.ts +30 -0
  149. package/src/providers/openai-anthropic-shim.ts +1 -1
  150. package/src/utils/schema/CONSTRAINTS.md +3 -2
  151. package/src/utils/schema/adapt.ts +19 -4
  152. package/src/utils/schema/compatibility.ts +70 -15
  153. package/src/utils/schema/dereference.ts +11 -6
  154. package/src/utils/schema/draft.ts +341 -0
  155. package/src/utils/schema/equality.ts +18 -14
  156. package/src/utils/schema/fields.ts +125 -114
  157. package/src/utils/schema/index.ts +1 -0
  158. package/src/utils/schema/json-schema-validator.ts +64 -51
  159. package/src/utils/schema/meta-validator.ts +41 -45
  160. package/src/utils/schema/normalize-cca.ts +87 -54
  161. package/src/utils/schema/sanitize-google.ts +71 -28
  162. package/src/utils/schema/stamps.ts +97 -0
  163. package/src/utils/schema/strict-mode.ts +215 -133
  164. package/src/utils/schema/wire.ts +24 -20
  165. package/src/utils/validation.ts +26 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [15.1.2] - 2026-05-15
6
+ ### Breaking Changes
7
+
8
+ - Rejected draft-07 tuple and dependency keywords (`items` arrays, `dependencies`, `additionalItems`) in JSON Schema validation
9
+
10
+ ### Added
11
+
12
+ - Added `responseHeaders`, `responseStatus`, and `responseRequestId` fields to `MockResponse` so mock providers can provide synthetic `ProviderResponseMetadata`
13
+ - Added `onResponse` metadata emission for mocks that sends lowercased headers and a default status of 200 before streaming when response headers are configured
14
+ - Added recursive strict-mode sanitization for array `prefixItems` entries so tuple schemas now enforce object constraints per item
15
+
16
+ ### Changed
17
+
18
+ - Normalized legacy draft-07 JSON Schema constructs used in tool parameters (`items` arrays, `additionalItems`, `definitions`, `dependencies`) to draft 2020-12 before OpenAI/Google/CCA sanitization, wire conversion, and argument validation
19
+ - Reworked OpenAI response schema adaptation to rewrite `oneOf` into `anyOf` while preserving existing `anyOf` branches
20
+ - Changed tuple array validation to validate per-index schemas from `prefixItems` and apply `items` only to remaining elements
21
+
22
+ ### Fixed
23
+
24
+ - Fixed validation of plain JSON Schema tool arguments that omitted a `$schema` URI so draft-07-shaped schemas now pass validation instead of being rejected
25
+ - Fixed tuple-array validation for legacy JSON Schema tool schemas to enforce `additionalItems: false` and per-position constraints after automatic draft upgrade
26
+ - Fixed Anthropic tool schema normalization to recurse into `prefixItems` so unsupported constraints inside tuple items are stripped in the generated input schema
27
+ - Fixed Anthropic tool-schema normalization stripping the body of explicit open `additionalProperties` (e.g. Zod's `z.record(z.string(), z.unknown())` compiling to `additionalProperties: {}`) by unconditionally overwriting it with `false`, which closed record-style fields and prevented models from supplying any key. The coding-agent's `resolve` tool exposes plan-approval titles via such a field, so Kimi K2 (and any other Anthropic-shaped provider) could not pass `extra: { title }`, blocking plan mode entirely ([#1104](https://github.com/can1357/oh-my-pi/issues/1104))
28
+ - Fixed Anthropic strict tool planning to leave tools with open `additionalProperties` maps non-strict instead of sending schemas Anthropic rejects.
29
+
5
30
  ## [15.1.0] - 2026-05-15
6
31
 
7
32
  ### Breaking Changes
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Custom API provider registry.
3
+ *
4
+ * Allows extensions to register streaming functions for custom API types
5
+ * (e.g., "vertex-claude-api") that are not built into stream.ts.
6
+ */
7
+ import type { Api, AssistantMessageEventStream, Context, Model, SimpleStreamOptions, StreamOptions } from "./types";
8
+ export type CustomStreamFn = (model: Model<Api>, context: Context, options?: StreamOptions) => AssistantMessageEventStream;
9
+ export type CustomStreamSimpleFn = (model: Model<Api>, context: Context, options?: SimpleStreamOptions) => AssistantMessageEventStream;
10
+ export interface RegisteredCustomApi {
11
+ stream: CustomStreamFn;
12
+ streamSimple: CustomStreamSimpleFn;
13
+ sourceId?: string;
14
+ }
15
+ /**
16
+ * Register a custom API streaming function.
17
+ */
18
+ export declare function registerCustomApi(api: string, streamSimple: CustomStreamSimpleFn, sourceId?: string, stream?: CustomStreamFn): void;
19
+ /**
20
+ * Get a custom API provider by API identifier.
21
+ */
22
+ export declare function getCustomApi(api: string): RegisteredCustomApi | undefined;
23
+ /**
24
+ * Remove all custom APIs registered by a specific source (e.g., extension path).
25
+ */
26
+ export declare function unregisterCustomApis(sourceId: string): void;
27
+ /**
28
+ * Clear all custom API registrations.
29
+ */
30
+ export declare function clearCustomApis(): void;
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Credential storage for API keys and OAuth tokens.
3
+ * Handles loading, saving, refreshing credentials, and usage tracking.
4
+ *
5
+ * This module defines:
6
+ * - `AuthCredentialStore` interface: abstracting persistence (SQLite, memory, etc.)
7
+ * - `AuthStorage` class: credential management with round-robin, usage limits, OAuth refresh
8
+ * - `AuthCredentialStore`: concrete SQLite-backed implementation
9
+ */
10
+ import { Database } from "bun:sqlite";
11
+ import type { Provider } from "./types";
12
+ import type { CredentialRankingStrategy, UsageLogger, UsageProvider, UsageReport } from "./usage";
13
+ import type { OAuthController, OAuthCredentials, OAuthProviderId } from "./utils/oauth/types";
14
+ export type ApiKeyCredential = {
15
+ type: "api_key";
16
+ key: string;
17
+ };
18
+ export type OAuthCredential = {
19
+ type: "oauth";
20
+ } & OAuthCredentials;
21
+ export type AuthCredential = ApiKeyCredential | OAuthCredential;
22
+ export type AuthCredentialEntry = AuthCredential | AuthCredential[];
23
+ export type AuthStorageData = Record<string, AuthCredentialEntry>;
24
+ /**
25
+ * Serialized representation of AuthStorage for passing to subagent workers.
26
+ * Contains only the essential credential data, not runtime state.
27
+ */
28
+ export interface SerializedAuthStorage {
29
+ credentials: Record<string, Array<{
30
+ id: number;
31
+ type: "api_key" | "oauth";
32
+ data: Record<string, unknown>;
33
+ }>>;
34
+ runtimeOverrides?: Record<string, string>;
35
+ dbPath?: string;
36
+ }
37
+ /**
38
+ * Auth credential with database row ID for updates/deletes.
39
+ * Wraps AuthCredential with storage metadata.
40
+ */
41
+ export interface StoredAuthCredential {
42
+ id: number;
43
+ provider: string;
44
+ credential: AuthCredential;
45
+ disabledCause: string | null;
46
+ }
47
+ /**
48
+ * Event payload describing a credential that was just soft-disabled.
49
+ *
50
+ * Today the only call site is OAuth refresh failures with a definitive cause
51
+ * (`invalid_grant`, `401/403` not from a network blip, etc.) — the
52
+ * disabled_cause string is the verbatim error captured for forensics.
53
+ *
54
+ * Subscribers can use this to surface a notification, banner, or auto-launch
55
+ * a re-login flow instead of letting the credential silently disappear.
56
+ */
57
+ export interface CredentialDisabledEvent {
58
+ provider: string;
59
+ disabledCause: string;
60
+ }
61
+ export type AuthStorageOptions = {
62
+ usageProviderResolver?: (provider: Provider) => UsageProvider | undefined;
63
+ rankingStrategyResolver?: (provider: Provider) => CredentialRankingStrategy | undefined;
64
+ usageFetch?: typeof fetch;
65
+ usageRequestTimeoutMs?: number;
66
+ usageLogger?: UsageLogger;
67
+ /**
68
+ * Resolve a config value (API key, header value, etc.) to an actual value.
69
+ * - coding-agent injects its resolveConfigValue (supports "!command" syntax via pi-natives)
70
+ * - Default: checks environment variable first, then treats as literal
71
+ */
72
+ configValueResolver?: (config: string) => Promise<string | undefined>;
73
+ /**
74
+ * Optional callback fired when AuthStorage automatically disables a
75
+ * credential because something detected it as no longer usable — today
76
+ * that's the OAuth refresh-failure path in `getApiKey`. NOT fired for
77
+ * user-initiated `remove()` (the user already knows) or dedup of
78
+ * duplicate credentials (uninteresting hygiene).
79
+ */
80
+ onCredentialDisabled?: (event: CredentialDisabledEvent) => void | Promise<void>;
81
+ };
82
+ type AuthApiKeyOptions = {
83
+ baseUrl?: string;
84
+ modelId?: string;
85
+ };
86
+ /**
87
+ * Credential storage backed by an AuthCredentialStore.
88
+ * Reads from storage on reload(), manages round-robin credential selection,
89
+ * usage limit tracking, and OAuth token refresh.
90
+ */
91
+ export declare class AuthStorage {
92
+ #private;
93
+ constructor(store: AuthCredentialStore, options?: AuthStorageOptions);
94
+ /**
95
+ * Create an AuthStorage instance backed by a AuthCredentialStore.
96
+ * Convenience factory for standalone use (e.g., pi-ai CLI).
97
+ * @param dbPath - Path to SQLite database
98
+ */
99
+ static create(dbPath: string, options?: AuthStorageOptions): Promise<AuthStorage>;
100
+ /**
101
+ * Close the underlying credential store.
102
+ *
103
+ * After calling this, the instance must not be reused.
104
+ */
105
+ close(): void;
106
+ /**
107
+ * Subscribe to {@link CredentialDisabledEvent}s. Multiple subscribers are supported and
108
+ * each fires for every disable event; subscribers are invoked in registration order with
109
+ * exceptions and async rejections isolated per-listener so a misbehaving subscriber
110
+ * cannot break the disable path or starve the rest of the chain.
111
+ *
112
+ * If `credential_disabled` events were emitted while no listener was subscribed, they are
113
+ * replayed (in insertion order) to the listener that triggers the empty→non-empty
114
+ * transition. The drain is one-shot — listeners that subscribe after that no longer see
115
+ * past events.
116
+ *
117
+ * Returns an unsubscribe function. The function is idempotent: calling it more than once
118
+ * is a no-op. After every subscriber has unsubscribed, subsequent disable events buffer
119
+ * again until the next subscribe.
120
+ *
121
+ * @param listener Callback invoked with each disable event. May be sync or async.
122
+ * @returns A function that removes this listener from the subscriber set.
123
+ */
124
+ onCredentialDisabled(listener: (event: CredentialDisabledEvent) => void | Promise<void>): () => void;
125
+ /**
126
+ * Set a runtime API key override (not persisted to disk).
127
+ * Used for CLI --api-key flag.
128
+ */
129
+ setRuntimeApiKey(provider: string, apiKey: string): void;
130
+ /**
131
+ * Remove a runtime API key override.
132
+ */
133
+ removeRuntimeApiKey(provider: string): void;
134
+ /**
135
+ * Set a fallback resolver for API keys not found in storage or env vars.
136
+ * Used for custom provider keys from models.json.
137
+ */
138
+ setFallbackResolver(resolver: (provider: string) => string | undefined): void;
139
+ /**
140
+ * Reload credentials from storage.
141
+ */
142
+ reload(): Promise<void>;
143
+ /**
144
+ * Get credential for a provider (first entry if multiple).
145
+ */
146
+ get(provider: string): AuthCredential | undefined;
147
+ /**
148
+ * Set credential for a provider.
149
+ */
150
+ set(provider: string, credential: AuthCredentialEntry): Promise<void>;
151
+ /**
152
+ * Remove credential for a provider.
153
+ */
154
+ remove(provider: string): Promise<void>;
155
+ /**
156
+ * List all providers with credentials.
157
+ */
158
+ list(): string[];
159
+ /**
160
+ * Check if credentials exist for a provider in storage.
161
+ */
162
+ has(provider: string): boolean;
163
+ /**
164
+ * Check if any form of auth is configured for a provider.
165
+ * Unlike getApiKey(), this doesn't refresh OAuth tokens.
166
+ */
167
+ hasAuth(provider: string): boolean;
168
+ /**
169
+ * Check if OAuth credentials are configured for a provider.
170
+ */
171
+ hasOAuth(provider: string): boolean;
172
+ /**
173
+ * Get OAuth credentials for a provider.
174
+ */
175
+ getOAuthCredential(provider: string): OAuthCredential | undefined;
176
+ /**
177
+ * Get the OAuth `accountId` for a provider, preferring the credential that is
178
+ * session-sticky for `sessionId` when multiple OAuth credentials are configured.
179
+ * Falls back to the first OAuth credential when no session preference exists (e.g.
180
+ * first call before any `getApiKey` has been issued, or single-credential setups).
181
+ * Returns `undefined` when no OAuth credential carries an `accountId`.
182
+ */
183
+ getOAuthAccountId(provider: string, sessionId?: string): string | undefined;
184
+ /**
185
+ * Get all credentials.
186
+ */
187
+ getAll(): AuthStorageData;
188
+ /**
189
+ * Login to an OAuth provider.
190
+ */
191
+ login(provider: OAuthProviderId, ctrl: OAuthController & {
192
+ /** onAuth is required by auth-storage but optional in OAuthController */
193
+ onAuth: (info: {
194
+ url: string;
195
+ instructions?: string;
196
+ }) => void;
197
+ /** onPrompt is required for some providers (github-copilot, openai-codex) */
198
+ onPrompt: (prompt: {
199
+ message: string;
200
+ placeholder?: string;
201
+ }) => Promise<string>;
202
+ }): Promise<void>;
203
+ /**
204
+ * Logout from a provider.
205
+ */
206
+ logout(provider: string): Promise<void>;
207
+ fetchUsageReports(options?: {
208
+ baseUrlResolver?: (provider: Provider) => string | undefined;
209
+ }): Promise<UsageReport[] | null>;
210
+ /**
211
+ * Marks the current session's credential as temporarily blocked due to usage limits.
212
+ * Uses usage reports to determine accurate reset time when available.
213
+ * Returns true if a credential was blocked, enabling automatic fallback to the next credential.
214
+ */
215
+ markUsageLimitReached(provider: string, sessionId: string | undefined, options?: {
216
+ retryAfterMs?: number;
217
+ baseUrl?: string;
218
+ }): Promise<boolean>;
219
+ /**
220
+ * Peek at API key for a provider without refreshing OAuth tokens.
221
+ * Used for model discovery where we only need to know if credentials exist
222
+ * and get a best-effort token. For GitHub Copilot we preserve enterprise
223
+ * routing metadata so discovery can hit the correct host.
224
+ */
225
+ peekApiKey(provider: string): Promise<string | undefined>;
226
+ /**
227
+ * Get API key for a provider.
228
+ * Priority:
229
+ * 1. Runtime override (CLI --api-key)
230
+ * 2. API key from storage
231
+ * 3. OAuth token from storage (auto-refreshed)
232
+ * 4. Environment variable
233
+ * 5. Fallback resolver (models.json custom providers)
234
+ */
235
+ getApiKey(provider: string, sessionId?: string, options?: AuthApiKeyOptions): Promise<string | undefined>;
236
+ }
237
+ /**
238
+ * Standalone SQLite-backed implementation of AuthCredentialStore interface.
239
+ * Used by the pi-ai CLI and as the default store for AuthStorage.create().
240
+ * Also has convenience methods for simple CRUD (saveOAuth, getOAuth, etc.).
241
+ */
242
+ export declare class AuthCredentialStore {
243
+ #private;
244
+ constructor(db: Database);
245
+ static open(dbPath?: string): Promise<AuthCredentialStore>;
246
+ listAuthCredentials(provider?: string): StoredAuthCredential[];
247
+ replaceAuthCredentialsForProvider(provider: string, credentials: AuthCredential[]): StoredAuthCredential[];
248
+ upsertAuthCredentialForProvider(provider: string, credential: AuthCredential): StoredAuthCredential[];
249
+ updateAuthCredential(id: number, credential: AuthCredential): void;
250
+ deleteAuthCredential(id: number, disabledCause: string): void;
251
+ /**
252
+ * CAS-style disable: only soft-deletes the row when its `data` column still
253
+ * matches `expectedData` and the row has not already been disabled. Used by
254
+ * the OAuth refresh-failure path to avoid clobbering a peer that rotated the
255
+ * row between our pre-check and the disable.
256
+ */
257
+ tryDisableAuthCredentialIfMatches(id: number, expectedData: string, disabledCause: string): boolean;
258
+ deleteAuthCredentialsForProvider(provider: string, disabledCause: string): void;
259
+ getCache(key: string): string | null;
260
+ setCache(key: string, value: string, expiresAtSec: number): void;
261
+ cleanExpiredCache(): void;
262
+ /**
263
+ * Save OAuth credentials for a provider.
264
+ * Preserves unrelated identities and replaces only the matching credential.
265
+ */
266
+ saveOAuth(provider: string, credentials: OAuthCredentials): void;
267
+ /**
268
+ * Get OAuth credentials for a provider.
269
+ */
270
+ getOAuth(provider: string): OAuthCredentials | null;
271
+ /**
272
+ * Save API key for a provider (replaces existing).
273
+ */
274
+ saveApiKey(provider: string, apiKey: string): void;
275
+ /**
276
+ * Get API key for a provider.
277
+ */
278
+ getApiKey(provider: string): string | null;
279
+ /**
280
+ * List all providers with credentials.
281
+ */
282
+ listProviders(): string[];
283
+ /**
284
+ * Delete all credentials for a provider.
285
+ */
286
+ deleteProvider(provider: string): void;
287
+ close(): void;
288
+ }
289
+ export {};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export {};
@@ -0,0 +1,44 @@
1
+ export { type ZodType, z } from "zod/v4";
2
+ export * from "./api-registry";
3
+ export * from "./auth-storage";
4
+ export * from "./model-cache";
5
+ export * from "./model-manager";
6
+ export * from "./model-thinking";
7
+ export * from "./models";
8
+ export * from "./provider-details";
9
+ export * from "./provider-models";
10
+ export * from "./providers/anthropic";
11
+ export * from "./providers/azure-openai-responses";
12
+ export type * from "./providers/cursor";
13
+ export * from "./providers/gitlab-duo";
14
+ export type * from "./providers/google";
15
+ export type * from "./providers/google-gemini-cli";
16
+ export * from "./providers/google-gemini-headers";
17
+ export type * from "./providers/google-vertex";
18
+ export * from "./providers/kimi";
19
+ export * from "./providers/mock";
20
+ export * from "./providers/ollama";
21
+ export * from "./providers/openai-codex-responses";
22
+ export * from "./providers/openai-completions";
23
+ export * from "./providers/openai-responses";
24
+ export * from "./providers/synthetic";
25
+ export * from "./rate-limit-utils";
26
+ export * from "./stream";
27
+ export * from "./types";
28
+ export * from "./usage";
29
+ export * from "./usage/claude";
30
+ export * from "./usage/gemini";
31
+ export * from "./usage/github-copilot";
32
+ export * from "./usage/google-antigravity";
33
+ export * from "./usage/kimi";
34
+ export * from "./usage/minimax-code";
35
+ export * from "./usage/openai-codex";
36
+ export * from "./usage/zai";
37
+ export * from "./utils/anthropic-auth";
38
+ export * from "./utils/discovery";
39
+ export * from "./utils/event-stream";
40
+ export * from "./utils/h2-fetch";
41
+ export * from "./utils/overflow";
42
+ export * from "./utils/retry";
43
+ export * from "./utils/schema";
44
+ export * from "./utils/validation";
@@ -0,0 +1,10 @@
1
+ import type { Api, Model } from "./types";
2
+ interface CacheEntry<TApi extends Api = Api> {
3
+ models: Model<TApi>[];
4
+ fresh: boolean;
5
+ authoritative: boolean;
6
+ updatedAt: number;
7
+ }
8
+ export declare function readModelCache<TApi extends Api>(providerId: string, ttlMs: number, now: () => number, dbPath?: string): CacheEntry<TApi> | null;
9
+ export declare function writeModelCache<TApi extends Api>(providerId: string, updatedAt: number, models: Model<TApi>[], authoritative: boolean, dbPath?: string): void;
10
+ export {};
@@ -0,0 +1,62 @@
1
+ import type { Api, Model, Provider } from "./types";
2
+ /**
3
+ * Controls when dynamic endpoint models should be fetched.
4
+ */
5
+ export type ModelRefreshStrategy = "online" | "offline" | "online-if-uncached";
6
+ /**
7
+ * Hook for loading and mapping models.dev fallback data into canonical model objects.
8
+ */
9
+ export interface ModelsDevFallback<TApi extends Api = Api, TPayload = unknown> {
10
+ /** Fetches raw fallback payload (for example from models.dev). */
11
+ fetch(): Promise<TPayload>;
12
+ /** Maps payload into provider models. */
13
+ map(payload: TPayload, providerId: Provider): readonly Model<TApi>[];
14
+ }
15
+ /**
16
+ * Configuration for provider model resolution.
17
+ */
18
+ export interface ModelManagerOptions<TApi extends Api = Api, TModelsDevPayload = unknown> {
19
+ /** Provider id used for static lookup and cache namespacing. */
20
+ providerId: Provider;
21
+ /** Optional static list override. When omitted, bundled models.json is used. */
22
+ staticModels?: readonly Model<TApi>[];
23
+ /** Optional override for the cache database path. Default: <agent-dir>/models.db. */
24
+ cacheDbPath?: string;
25
+ /** Maximum cache age in milliseconds before considered stale. Default: 24h. */
26
+ cacheTtlMs?: number;
27
+ /** Optional dynamic endpoint fetcher. */
28
+ fetchDynamicModels?: () => Promise<readonly Model<TApi>[] | null>;
29
+ /** Optional models.dev fallback hook. */
30
+ modelsDev?: ModelsDevFallback<TApi, TModelsDevPayload>;
31
+ /** Clock override for deterministic tests. */
32
+ now?: () => number;
33
+ }
34
+ /**
35
+ * Resolution result.
36
+ *
37
+ * `stale` is false when the resolved catalog is authoritative for the selected provider:
38
+ * - dynamic endpoint data was fetched in this call,
39
+ * - a still-fresh authoritative cache was reused in `online-if-uncached` mode, or
40
+ * - the provider has no dynamic fetcher configured.
41
+ */
42
+ export interface ModelResolutionResult<TApi extends Api = Api> {
43
+ models: Model<TApi>[];
44
+ stale: boolean;
45
+ }
46
+ /**
47
+ * Stateful facade over provider model resolution.
48
+ */
49
+ export interface ModelManager<TApi extends Api = Api> {
50
+ refresh(strategy?: ModelRefreshStrategy): Promise<ModelResolutionResult<TApi>>;
51
+ }
52
+ /**
53
+ * Creates a reusable provider model manager.
54
+ */
55
+ export declare function createModelManager<TApi extends Api = Api, TModelsDevPayload = unknown>(options: ModelManagerOptions<TApi, TModelsDevPayload>): ModelManager<TApi>;
56
+ /**
57
+ * Resolves provider models with source precedence:
58
+ * static -> models.dev -> cache -> dynamic.
59
+ *
60
+ * Later sources override earlier ones by model id.
61
+ */
62
+ export declare function resolveProviderModels<TApi extends Api = Api, TModelsDevPayload = unknown>(options: ModelManagerOptions<TApi, TModelsDevPayload>, strategy?: ModelRefreshStrategy): Promise<ModelResolutionResult<TApi>>;
@@ -0,0 +1,71 @@
1
+ import type { Api, Model as ApiModel } from "./types";
2
+ /** User-facing thinking levels, ordered least to most intensive. */
3
+ export declare const enum Effort {
4
+ Minimal = "minimal",
5
+ Low = "low",
6
+ Medium = "medium",
7
+ High = "high",
8
+ XHigh = "xhigh"
9
+ }
10
+ export declare const THINKING_EFFORTS: readonly Effort[];
11
+ /**
12
+ * Static fallback model injected when Cloudflare AI Gateway discovery
13
+ * returns no results. Ensures the provider always has at least one usable
14
+ * model entry in the catalog.
15
+ */
16
+ export declare const CLOUDFLARE_FALLBACK_MODEL: ApiModel<"anthropic-messages">;
17
+ /**
18
+ * Returns a copy of the model with canonical thinking metadata attached.
19
+ *
20
+ * This helper belongs to catalog enrichment only. Runtime consumers should
21
+ * trust `model.thinking` and avoid inferring capabilities on demand.
22
+ */
23
+ export declare function enrichModelThinking<TApi extends Api>(model: ApiModel<TApi>): ApiModel<TApi>;
24
+ /**
25
+ * Returns a copy of the model with thinking metadata recomputed from the
26
+ * canonical rules, replacing any existing `thinking`.
27
+ */
28
+ export declare function refreshModelThinking<TApi extends Api>(model: ApiModel<TApi>): ApiModel<TApi>;
29
+ /**
30
+ * Apply upstream metadata corrections to a mutable array of models.
31
+ *
32
+ * Each model is first normalized through `refreshModelThinking()` so generated
33
+ * catalogs keep canonical thinking metadata and policy fixes in one pass.
34
+ */
35
+ export declare function applyGeneratedModelPolicies(models: ApiModel<Api>[]): void;
36
+ /**
37
+ * Link OpenAI model variants to their context promotion targets.
38
+ *
39
+ * When a model's context is exhausted, the agent can promote to a sibling
40
+ * model with a larger context window on the same provider:
41
+ * - `codex-spark` variants promote to `gpt-5.5`.
42
+ * - `gpt-5.5` (270K input) promotes to `gpt-5.4` (1M input).
43
+ */
44
+ export declare function linkOpenAIPromotionTargets(models: ApiModel<Api>[]): void;
45
+ /**
46
+ * Returns the supported thinking efforts declared on the model metadata.
47
+ *
48
+ * Catalog enrichment is responsible for normalizing bundled model metadata up front.
49
+ * Runtime callers must treat explicit `model.thinking` on custom models as authoritative
50
+ * so proxy-specific overrides from `models.yml` survive request construction.
51
+ *
52
+ * @throws Error when a reasoning-capable model is missing thinking metadata
53
+ */
54
+ export declare function getSupportedEfforts<TApi extends Api>(model: ApiModel<TApi>): readonly Effort[];
55
+ /**
56
+ * Clamps a requested thinking level against explicit model metadata.
57
+ *
58
+ * Non-reasoning models always resolve to `undefined`.
59
+ */
60
+ export declare function clampThinkingLevelForModel<TApi extends Api>(model: ApiModel<TApi> | undefined, requested: Effort | undefined): Effort | undefined;
61
+ export declare function requireSupportedEffort<TApi extends Api>(model: ApiModel<TApi>, effort: Effort): Effort;
62
+ /** Maps a normalized thinking effort to Google's `thinkingLevel` enum values. */
63
+ export declare function mapEffortToGoogleThinkingLevel<TApi extends Api>(model: ApiModel<TApi>, effort: Effort): "MINIMAL" | "LOW" | "MEDIUM" | "HIGH";
64
+ /** Maps a normalized thinking effort to Anthropic adaptive effort values. */
65
+ export declare function mapEffortToAnthropicAdaptiveEffort<TApi extends Api>(model: ApiModel<TApi>, effort: Effort): "low" | "medium" | "high" | "xhigh" | "max";
66
+ /**
67
+ * Returns true for Anthropic models with Opus 4.7 API restrictions:
68
+ * - Sampling parameters (temperature/top_p/top_k) return 400 error
69
+ * - Thinking content is omitted by default (needs display: "summarized")
70
+ */
71
+ export declare function hasOpus47ApiRestrictions(modelId: string): boolean;
@@ -0,0 +1,12 @@
1
+ import MODELS from "./models.json";
2
+ import type { Api, KnownProvider, Model, Usage } from "./types";
3
+ export type GeneratedProvider = keyof typeof MODELS;
4
+ export declare function getBundledModel<TApi extends Api = Api>(provider: GeneratedProvider, modelId: string): Model<TApi>;
5
+ export declare function getBundledProviders(): KnownProvider[];
6
+ export declare function getBundledModels(provider: GeneratedProvider): Model<Api>[];
7
+ export declare function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage): Usage["cost"];
8
+ /**
9
+ * Check if two models are equal by comparing both their id and provider.
10
+ * Returns false if either model is null or undefined.
11
+ */
12
+ export declare function modelsAreEqual<TApi extends Api>(a: Model<TApi> | null | undefined, b: Model<TApi> | null | undefined): boolean;
@@ -0,0 +1,18 @@
1
+ import type { Api, Model, Provider, ProviderSessionState } from "./types";
2
+ export interface ProviderDetailField {
3
+ label: string;
4
+ value: string;
5
+ }
6
+ export interface ProviderDetails {
7
+ provider: Provider;
8
+ api: Api;
9
+ fields: ProviderDetailField[];
10
+ }
11
+ export interface ProviderDetailsContext {
12
+ model: Model<Api>;
13
+ sessionId?: string;
14
+ authMode?: string;
15
+ preferWebsockets?: boolean;
16
+ providerSessionState?: Map<string, ProviderSessionState>;
17
+ }
18
+ export declare function getProviderDetails(context: ProviderDetailsContext): ProviderDetails;
@@ -0,0 +1,4 @@
1
+ import { getBundledModels } from "../models";
2
+ import type { Api, Model } from "../types";
3
+ export declare function createBundledReferenceMap<TApi extends Api>(provider: Parameters<typeof getBundledModels>[0]): Map<string, Model<TApi>>;
4
+ export declare function createReferenceResolver<TApi extends Api>(providerRefs: Map<string, Model<TApi>>): (modelId: string) => Model<TApi> | undefined;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Unified provider descriptors — single source of truth for provider metadata
3
+ * used by both runtime model discovery (model-registry.ts) and catalog
4
+ * generation (generate-models.ts).
5
+ */
6
+ import type { ModelManagerOptions } from "../model-manager";
7
+ import type { Api, KnownProvider } from "../types";
8
+ import type { OAuthProvider } from "../utils/oauth/types";
9
+ /** Catalog discovery configuration for providers that support endpoint-based model listing. */
10
+ export interface CatalogDiscoveryConfig {
11
+ /** Human-readable name for log messages. */
12
+ label: string;
13
+ /** Environment variables to check for API keys during catalog generation. */
14
+ envVars: string[];
15
+ /** OAuth provider for credential refresh during catalog generation. */
16
+ oauthProvider?: OAuthProvider;
17
+ /** When true, catalog discovery proceeds even without credentials. */
18
+ allowUnauthenticated?: boolean;
19
+ }
20
+ /** Unified provider descriptor used by both runtime discovery and catalog generation. */
21
+ export interface ProviderDescriptor {
22
+ providerId: KnownProvider;
23
+ createModelManagerOptions(config: {
24
+ apiKey?: string;
25
+ baseUrl?: string;
26
+ }): ModelManagerOptions<Api>;
27
+ /** Preferred model ID when no explicit selection is made. */
28
+ defaultModel: string;
29
+ /** When true, the runtime creates a model manager even without a valid API key (e.g. ollama). */
30
+ allowUnauthenticated?: boolean;
31
+ /** Catalog discovery configuration. Only providers with this field participate in generate-models.ts. */
32
+ catalogDiscovery?: CatalogDiscoveryConfig;
33
+ }
34
+ /** A provider descriptor that has catalog discovery configured. */
35
+ export type CatalogProviderDescriptor = ProviderDescriptor & {
36
+ catalogDiscovery: CatalogDiscoveryConfig;
37
+ };
38
+ /** Type guard for descriptors with catalog discovery. */
39
+ export declare function isCatalogDescriptor(d: ProviderDescriptor): d is CatalogProviderDescriptor;
40
+ /** Whether catalog discovery may run without provider credentials. */
41
+ export declare function allowsUnauthenticatedCatalogDiscovery(descriptor: CatalogProviderDescriptor): boolean;
42
+ /**
43
+ * All standard providers. Special providers (google-antigravity, google-gemini-cli,
44
+ * openai-codex) are handled separately because they require different config shapes.
45
+ */
46
+ export declare const PROVIDER_DESCRIPTORS: readonly ProviderDescriptor[];
47
+ /** Default model IDs for all known providers, built from descriptors + special providers. */
48
+ export declare const DEFAULT_MODEL_PER_PROVIDER: Record<KnownProvider, string>;
@@ -0,0 +1,19 @@
1
+ import type { ModelManagerOptions } from "../model-manager";
2
+ export interface GoogleModelManagerConfig {
3
+ apiKey?: string;
4
+ }
5
+ export interface GoogleVertexModelManagerConfig {
6
+ apiKey?: string;
7
+ }
8
+ export interface GoogleAntigravityModelManagerConfig {
9
+ oauthToken?: string;
10
+ endpoint?: string;
11
+ }
12
+ export interface GoogleGeminiCliModelManagerConfig {
13
+ oauthToken?: string;
14
+ endpoint?: string;
15
+ }
16
+ export declare function googleModelManagerOptions(config?: GoogleModelManagerConfig): ModelManagerOptions<"google-generative-ai">;
17
+ export declare function googleVertexModelManagerOptions(_config?: GoogleVertexModelManagerConfig): ModelManagerOptions<"google-vertex">;
18
+ export declare function googleAntigravityModelManagerOptions(config?: GoogleAntigravityModelManagerConfig): ModelManagerOptions<"google-gemini-cli">;
19
+ export declare function googleGeminiCliModelManagerOptions(config?: GoogleGeminiCliModelManagerConfig): ModelManagerOptions<"google-gemini-cli">;
@@ -0,0 +1,5 @@
1
+ export * from "./descriptors";
2
+ export * from "./google";
3
+ export * from "./ollama";
4
+ export * from "./openai-compat";
5
+ export * from "./special";