@oh-my-pi/pi-ai 18.3.5 → 18.4.0
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.
- package/CHANGELOG.md +29 -48
- package/dist/types/auth/blocks.d.ts +10 -19
- package/dist/types/auth/cascade.d.ts +1 -1
- package/dist/types/auth/rotation.d.ts +6 -3
- package/dist/types/auth/types.d.ts +23 -3
- package/dist/types/auth/usage-cache.d.ts +14 -2
- package/dist/types/auth/usage.d.ts +2 -2
- package/dist/types/auth-broker/client.d.ts +2 -1
- package/dist/types/auth-broker/remote-store.d.ts +5 -6
- package/dist/types/auth-broker/types.d.ts +3 -1
- package/dist/types/auth-broker/wire-schemas.d.ts +2 -1
- package/dist/types/auth-retry.d.ts +22 -13
- package/dist/types/images/types.d.ts +9 -0
- package/dist/types/judgment/types.d.ts +3 -2
- package/dist/types/providers/cursor/exec-modern.d.ts +1 -1
- package/dist/types/providers/cursor-pi-args.d.ts +10 -0
- package/dist/types/providers/cursor.d.ts +6 -2
- package/dist/types/providers/google-shared.d.ts +13 -2
- package/dist/types/usage/claude-reset.d.ts +6 -0
- package/dist/types/usage/claude.d.ts +6 -0
- package/dist/types/usage.d.ts +2 -0
- package/dist/types/utils/proxy.d.ts +2 -2
- package/package.json +6 -6
- package/src/auth/blocks.ts +79 -37
- package/src/auth/cascade.ts +5 -4
- package/src/auth/resets.ts +104 -40
- package/src/auth/rotation.ts +62 -21
- package/src/auth/select.ts +9 -2
- package/src/auth/types.ts +28 -3
- package/src/auth/usage-cache.ts +45 -2
- package/src/auth/usage.ts +52 -25
- package/src/auth-broker/client.ts +13 -0
- package/src/auth-broker/remote-store.ts +128 -27
- package/src/auth-broker/server.ts +20 -0
- package/src/auth-broker/types.ts +4 -1
- package/src/auth-broker/wire-schemas.ts +7 -0
- package/src/auth-retry.ts +50 -28
- package/src/images/openai-hosted.ts +18 -3
- package/src/images/types.ts +9 -0
- package/src/judgment/types.ts +10 -6
- package/src/judgment/typesafe.ts +2 -2
- package/src/providers/anthropic.ts +53 -13
- package/src/providers/cursor/exec-modern.ts +1 -0
- package/src/providers/cursor/proto/agent.proto +5 -0
- package/src/providers/cursor-pi-args.ts +14 -0
- package/src/providers/cursor.ts +66 -28
- package/src/providers/google-gemini-cli.ts +2 -19
- package/src/providers/google-shared.ts +30 -22
- package/src/providers/ollama.ts +2 -0
- package/src/registry/oauth/oauth.html +206 -185
- package/src/usage/claude-reset.ts +45 -11
- package/src/usage/claude.ts +79 -49
- package/src/usage.ts +2 -0
- package/src/utils/proxy.ts +3 -3
- package/src/utils/schema/CONSTRAINTS.md +30 -28
- package/src/utils/schema/normalize.ts +1 -1
- package/src/utils/schema/wire.ts +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.4.0] - 2026-09-28
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- Changed `LimitsApi.rotate()` to return a `CredentialRotation` object (`{ switched, afterSiblingWait? }`) instead of a boolean. Check `.switched` explicitly, since the returned object is always truthy.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added image metadata to hosted OpenAI image-generation results, including the model used and each generated image’s dimensions and quality.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Redesigned the browser page displayed during OAuth login.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Fixed Anthropic accounts remaining blocked after quota resets, including for broker-connected clients, while preserving independent authentication and model-limit restrictions.
|
|
22
|
+
- Fixed concurrent usage refreshes repeatedly probing providers after failures, reducing unnecessary usage-endpoint requests.
|
|
23
|
+
- Fixed Gemini and Antigravity usage and cost reporting when upstream responses omit prompt-token counts or report more cached tokens than prompt tokens.
|
|
24
|
+
- Fixed credential failover after authentication errors so stored credentials rotate through every distinct sibling instead of stopping after one attempt; rotation can also wait briefly for a temporarily blocked healthy sibling to become available.
|
|
25
|
+
- Fixed native judge responses without token counts producing invalid usage and cost values.
|
|
26
|
+
- Fixed Cursor usage, cost, and context accounting to include final input, cache, reasoning, and output metrics, improving compaction and handoff sizing.
|
|
27
|
+
- Fixed Cursor MCP tool calls routed through external executors being returned as text instead of tool calls.
|
|
28
|
+
- Fixed Cursor shell-tool timeouts being displayed in milliseconds rather than seconds.
|
|
29
|
+
- Fixed fetch requests over Unix sockets when `PI_PROXY` is configured.
|
|
30
|
+
- Fixed Ollama chat turns being recorded with zero cost; usage is now priced using the model’s cost information.
|
|
31
|
+
- Fixed Anthropic requests failing after native compaction when per-message effort settings were present; effort controls are now handled correctly with compaction.
|
|
32
|
+
|
|
5
33
|
## [18.3.5] - 2026-09-27
|
|
6
34
|
|
|
7
35
|
### Breaking Changes
|
|
@@ -2276,51 +2304,4 @@
|
|
|
2276
2304
|
- Fixed explicit request-debug mode to overwrite existing `.res.log` files for the requested path instead of failing when they already exist
|
|
2277
2305
|
- Fixed OpenAI Responses `previous_response_id` chaining on Zero Data Retention orgs: the in-provider retry classifier missed the ZDR-specific 400 ("Previous response cannot be used for this organization due to Zero Data Retention"), so chained turns kept failing every other request after a brief recovery — the chain was reset but not disabled, so the next successful full-replay turn re-armed it. The ZDR phrasing is now classified categorically: one strike disables chaining for the session (skipping the three-strike circuit breaker) and the in-call retry drops `store: true`/`previous_response_id` and replays the full transcript instead ([#2341](https://github.com/can1357/oh-my-pi/issues/2341)).
|
|
2278
2306
|
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
### Added
|
|
2282
|
-
|
|
2283
|
-
- Codex/Responses providers now map `end_turn: false` on the terminal stream event (Codex backend signal for "response ended, turn didn't" — commentary-only progress updates) to `stopDetails: { type: "pause_turn" }` with stopReason `"stop"`, so the agent loop can re-sample instead of ending the turn. Wired in `openai-codex-responses` and `processResponsesStream` (`openai-responses`/`azure-openai-responses`); inert for backends that never send the field.
|
|
2284
|
-
- Added Codex upstream protocol features to `openai-codex-responses` (tracking codex-rs as of June 2026): `onModerationMetadata` callback surfacing `response.metadata` → `openai_chatgpt_moderation_metadata` on both transports; `reasoningContext` option emitting `reasoning.context` (`auto`/`current_turn`/`all_turns`); `clientMetadata` option emitting `client_metadata` in the request body (canonical `x-codex-turn-metadata` envelope) without breaking the websocket append fast-path; and an opt-in `responsesLite` mode mirroring codex-rs — lite header on HTTP requests and the websocket upgrade, `ws_request_header_*` marker in `response.create` client metadata, lite-keyed socket pooling, image-detail stripping, forced serial tool calls, and `reasoning.context: all_turns` default. Dormant until OpenAI flips `use_responses_lite` in the model catalog.
|
|
2285
|
-
- Added `withOAuthAccess` — the `withAuth` counterpart for OAuth-access consumers: runs an operation through the central a/b/c auth-retry policy (resolve → force-refresh same account → rotate to a sibling) while handing the attempt the full `OAuthAccess` (bearer plus `accountId`/`projectId`/`enterpriseUrl` identity metadata). Use it instead of hand-rolled `getOAuthAccess` + fetch flows so 401s and usage-limits rotate credentials instead of failing the call.
|
|
2286
|
-
- Added `ProviderHttpError` — a typed HTTP error carrying `status`, `headers`, and `code` — replacing the ad-hoc `as Error & { status?... }` / `Object.assign` hacks at provider throw sites, with per-provider subclasses `CodexApiError`, `AuthGatewayError`, `GoogleApiError`, `GeminiCliApiError`, `OllamaApiError`, and `BedrockApiError`; `AnthropicApiError` now extends it. Google, Gemini CLI, Ollama, and Bedrock HTTP errors now also carry response headers, so server-suggested `retry-after` delays are visible to retry classification on those paths. The internal `withHttpStatus` helper was removed.
|
|
2287
|
-
- Added stateful SSE turn chaining for OpenAI Codex (on by default; disable with `PI_CODEX_STATEFUL=0` or `statefulResponses: false`): SSE requests now reuse `previous_response_id` with delta-only input instead of replaying the full transcript, mirroring the websocket fast-path via a shared transport-aware builder. Any history mutation or option change falls back to a full replay; a server-side `previous_response_not_found` (HTTP or in-stream) resets the chain and retries the turn with full context, and three consecutive stale failures disable chaining for the session.
|
|
2288
|
-
- Added stateful `previous_response_id` chaining to the platform OpenAI Responses provider (`openai-responses`): on by default against the official api.openai.com endpoint (forces `store: true`, which chaining requires), off for other Responses endpoints; override with `statefulResponses` or `PI_OPENAI_STATEFUL`. Chain detection compares the wire form of the conversation arguments alone — per-turn trailing scaffolding such as the GPT-5 "Juice: 0" developer item is excluded from the append-baseline prefix check and re-appended to the delta — and a rejected/stale previous response falls back to a one-shot full replay with the same circuit breaker.
|
|
2289
|
-
- Added `AuthStorage.getOAuthAccountIdentity()` and the `OAuthAccountIdentity` type — a read-only lookup returning the `accountId`/`email`/`projectId` of the OAuth credential a session is currently routed to, for display and metadata paths.
|
|
2290
|
-
|
|
2291
|
-
### Changed
|
|
2292
|
-
|
|
2293
|
-
- The GPT-5 "Juice: 0" no-reasoning developer item in `applyResponsesReasoningParams` is now gated on the resolved `compat.requiresJuiceZeroHack` flag (auto-detected from GPT-5-family model names by `@oh-my-pi/pi-catalog`, overridable per model) instead of an inline model-name check.
|
|
2294
|
-
|
|
2295
|
-
### Fixed
|
|
2296
|
-
|
|
2297
|
-
- Fixed websocket append fast-path to remain usable when only `client_metadata` changes between turns
|
|
2298
|
-
- Fixed `onModerationMetadata` handling so exceptions thrown by callback observers no longer terminate the response stream
|
|
2299
|
-
- Fixed local SQLite OAuth credential caches returning a stale Anthropic access token after another `omp` process refreshed and persisted the same row. `AuthStorage` now syncs the selected row from storage before returning or force-refreshing OAuth credentials, so concurrent sessions pick up peer-rotated tokens instead of surfacing a one-turn `401 Invalid authentication credentials`.
|
|
2300
|
-
- Fixed forced OAuth preflight refresh failures being swallowed silently in credential selection; they now emit a debug log (`OAuth preflight refresh failed`) so stale-refresh-token replays from concurrent sessions are diagnosable.
|
|
2301
|
-
|
|
2302
|
-
## [15.11.3] - 2026-06-11
|
|
2303
|
-
|
|
2304
|
-
### Fixed
|
|
2305
|
-
|
|
2306
|
-
- Fixed GitHub Copilot long-context model requests to use the upstream `requestModelId` when calling Anthropic, OpenAI Responses, and OpenAI Completions APIs
|
|
2307
|
-
- Fixed GitHub Copilot model enablement to deduplicate catalog variants by upstream model ID when enabling all models
|
|
2308
|
-
|
|
2309
|
-
## [15.11.2] - 2026-06-11
|
|
2310
|
-
|
|
2311
|
-
### Fixed
|
|
2312
|
-
|
|
2313
|
-
- Fixed Anthropic encoding of error tool results with whitespace-only content so requests no longer 400 with `tool_result: content cannot be empty if is_error is true`
|
|
2314
|
-
|
|
2315
|
-
## [15.11.1] - 2026-06-11
|
|
2316
|
-
|
|
2317
|
-
### Changed
|
|
2318
|
-
|
|
2319
|
-
- Exported `resolveAnthropicMetadataUserId` so non-streaming Anthropic Messages consumers (e.g. the coding-agent web search provider) can produce the same Claude-Code-shaped `metadata.user_id` as the main streaming path.
|
|
2320
|
-
|
|
2321
|
-
### Fixed
|
|
2322
|
-
|
|
2323
|
-
- Preserved Anthropic `stop_details` on assistant messages so refusal and sensitive classifier stops remain structurally visible to callers. ([#2290](https://github.com/can1357/oh-my-pi/issues/2290))
|
|
2324
|
-
- Fixed OpenAI Responses, Azure OpenAI Responses, and OpenAI Completions streams hanging until the 120s idle watchdog errored the turn when a provider delivers the terminal frame but never sends `[DONE]` nor closes the connection. `processResponsesStream` now breaks out of the event loop on `response.completed`/`response.incomplete` (mirroring the Codex websocket/SSE terminal break), and the completions consumer breaks once `finish_reason` plus a usage payload arrived — or, for hosts that never send usage, ends the stream cleanly via a short post-finish grace window (`iterateWithTerminalGrace`) that aborts the transport to release the socket.
|
|
2325
|
-
|
|
2326
|
-
Older entries are archived in [packages/ai/CHANGELOG.md@d58593a30902](https://github.com/can1357/oh-my-pi/blob/d58593a3090258473304608d68ffd1f620e6b695/packages/ai/CHANGELOG.md).
|
|
2307
|
+
Older entries are archived in [packages/ai/CHANGELOG.md@dfbf3cc34eeb](https://github.com/can1357/oh-my-pi/blob/dfbf3cc34eeb5653580f51bfbcae558a9840f697/packages/ai/CHANGELOG.md).
|
|
@@ -11,6 +11,10 @@ export declare const DEFAULT_BLOCK_MS = 60000;
|
|
|
11
11
|
export declare function providerTypeKey(provider: string, type: AuthCredential["type"]): string;
|
|
12
12
|
/** Scoped backoff map key used by the credential block store. */
|
|
13
13
|
export declare function scopedBackoffKey(providerKey: string, blockScope: string | undefined): string;
|
|
14
|
+
/** Authentication backoffs apply to every model and cannot be healed by quota evidence. */
|
|
15
|
+
export declare const AUTH_BLOCK_SCOPE = "auth";
|
|
16
|
+
/** Account-policy backoffs apply to every model and survive quota resets. */
|
|
17
|
+
export declare const ACCOUNT_POLICY_BLOCK_SCOPE = "account-policy";
|
|
14
18
|
/** Scope key for one model-specific account-policy block, shared by selectors and rate limits. */
|
|
15
19
|
export declare function modelAccountPolicyBlockScope(provider: string, modelId: string | undefined): string | undefined;
|
|
16
20
|
/** Scope keys that a request must check, including model-policy constraints. */
|
|
@@ -67,26 +71,15 @@ export declare class CredentialBlocks implements BlocksApi {
|
|
|
67
71
|
* that `markUsageLimitReached` set for the now-obsolete reset time.
|
|
68
72
|
*/
|
|
69
73
|
clearAll(provider: string, credentialId: number): void;
|
|
70
|
-
/**
|
|
71
|
-
|
|
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;
|
|
74
|
+
/** Clear exactly one quota scope, preserving unrelated account and model blocks. */
|
|
75
|
+
clearScope(provider: string, credentialId: number, providerKey: string, blockScope: string | undefined): boolean;
|
|
79
76
|
/** Providers whose stale usage-limit blocks a healthy live report may clear. */
|
|
80
77
|
supportsHealing(provider: Provider): boolean;
|
|
81
78
|
/**
|
|
82
79
|
* Whether a fresh report could lift what currently blocks this credential.
|
|
83
80
|
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
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.
|
|
81
|
+
* Claude reports can heal legacy account-wide quota blocks too. Explicit
|
|
82
|
+
* auth/account-policy blocks never justify a usage probe.
|
|
90
83
|
*/
|
|
91
84
|
canHeal(provider: Provider, providerKey: string, credentialIndex: number, blockScopeOrScopes: string | readonly string[] | undefined): boolean;
|
|
92
85
|
/**
|
|
@@ -107,9 +100,7 @@ export declare class CredentialBlocks implements BlocksApi {
|
|
|
107
100
|
* Broker-server seam: persist one credential block and notify snapshot waiters.
|
|
108
101
|
*/
|
|
109
102
|
upsert(block: StoredCredentialBlock): void;
|
|
110
|
-
/**
|
|
111
|
-
|
|
112
|
-
*/
|
|
113
|
-
delete(credentialId: number, providerKey: string, blockScope: string): void;
|
|
103
|
+
/** Broker-server seam: clear exactly one persisted and local block and notify snapshot waiters. */
|
|
104
|
+
delete(credentialId: number, providerKey: string, blockScope: string, invalidateUsage?: boolean): void;
|
|
114
105
|
deleteAll(credentialId: number): void;
|
|
115
106
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ApiKeyResolver, type ResolvedApiKey } from "../auth-retry.js";
|
|
2
2
|
import type { SessionAffinity } from "./affinity.js";
|
|
3
3
|
import type { CredentialPool } from "./pool.js";
|
|
4
4
|
import type { CredentialSelector } from "./select.js";
|
|
@@ -5,7 +5,7 @@ import type { KeyOverrides } from "./cascade.js";
|
|
|
5
5
|
import type { SessionAffinity } from "./affinity.js";
|
|
6
6
|
import type { CredentialPool } from "./pool.js";
|
|
7
7
|
import type { AuthCredentialStore } from "./store.js";
|
|
8
|
-
import type { InvalidateCredentialMatchingOptions, LimitsApi, MarkUsageLimitOptions, RotateCredentialOptions, UsageLimitMarkResult } from "./types.js";
|
|
8
|
+
import type { CredentialRotation, InvalidateCredentialMatchingOptions, LimitsApi, MarkUsageLimitOptions, RotateCredentialOptions, UsageLimitMarkResult } from "./types.js";
|
|
9
9
|
import type { UsageService } from "./usage.js";
|
|
10
10
|
/** Routing scope and strategy for one failed credential. */
|
|
11
11
|
export type CredentialBlockRouting = {
|
|
@@ -60,7 +60,10 @@ export declare class RateLimits implements LimitsApi {
|
|
|
60
60
|
* reload when no broker hook is wired) and block it, then drop matching
|
|
61
61
|
* sticky state.
|
|
62
62
|
*
|
|
63
|
-
*
|
|
63
|
+
* For usage-limit and account-policy failures with no free sibling, sleeps
|
|
64
|
+
* until the earliest sibling unblocks when that is at most
|
|
65
|
+
* {@link SIBLING_UNBLOCK_WAIT_MAX_MS} away, then reports `afterSiblingWait`.
|
|
66
|
+
* Aborting `options.signal` during that wait rejects.
|
|
64
67
|
*/
|
|
65
|
-
rotate(provider: string, sessionId: string | undefined, options?: RotateCredentialOptions): Promise<
|
|
68
|
+
rotate(provider: string, sessionId: string | undefined, options?: RotateCredentialOptions): Promise<CredentialRotation>;
|
|
66
69
|
}
|
|
@@ -564,6 +564,10 @@ export interface ResetCreditRedeemOutcome {
|
|
|
564
564
|
/** One stored account's live saved-reset status, from {@link AuthStorage.resets.list}. */
|
|
565
565
|
export interface ResetCreditAccountStatus extends UsageResetCredits {
|
|
566
566
|
provider: string;
|
|
567
|
+
/** Live quota evidence from this exact account's reset-discovery response. */
|
|
568
|
+
report?: UsageReport;
|
|
569
|
+
/** Provider-requested wait before retrying throttled reset discovery (not redemption). */
|
|
570
|
+
retryAfterMs?: number;
|
|
567
571
|
credentialId: number;
|
|
568
572
|
accountId?: string;
|
|
569
573
|
email?: string;
|
|
@@ -627,6 +631,20 @@ export type RotateCredentialOptions = {
|
|
|
627
631
|
credentialId?: number;
|
|
628
632
|
signal?: AbortSignal;
|
|
629
633
|
};
|
|
634
|
+
/**
|
|
635
|
+
* Outcome of {@link LimitsApi.rotate}.
|
|
636
|
+
*
|
|
637
|
+
* `switched` is `true` when a usable same-type sibling credential is available,
|
|
638
|
+
* so the caller's next resolve hands it out. `afterSiblingWait` is `true` when
|
|
639
|
+
* no sibling was free at the failure but rotation slept out a sibling's short
|
|
640
|
+
* block (e.g. a Cloud Code Assist capacity 429 that resets in under a second);
|
|
641
|
+
* the freed credential may be one the caller already sent in this request, so
|
|
642
|
+
* attempted-bearer dedupe must let it through once.
|
|
643
|
+
*/
|
|
644
|
+
export interface CredentialRotation {
|
|
645
|
+
switched: boolean;
|
|
646
|
+
afterSiblingWait?: boolean;
|
|
647
|
+
}
|
|
630
648
|
/** Filter saved reset credits by provider and session. */
|
|
631
649
|
export type ListResetCreditsOptions = {
|
|
632
650
|
provider?: string;
|
|
@@ -1107,9 +1125,11 @@ export interface LimitsApi {
|
|
|
1107
1125
|
* reload when no broker hook is wired) and block it, then drop matching
|
|
1108
1126
|
* sticky state.
|
|
1109
1127
|
*
|
|
1110
|
-
*
|
|
1128
|
+
* For usage-limit and account-policy failures with no free sibling, waits
|
|
1129
|
+
* (abortable via `options.signal`) when a sibling's block expires within a
|
|
1130
|
+
* few seconds, then reports `afterSiblingWait`.
|
|
1111
1131
|
*/
|
|
1112
|
-
rotate(provider: string, sessionId: string | undefined, options?: RotateCredentialOptions): Promise<
|
|
1132
|
+
rotate(provider: string, sessionId: string | undefined, options?: RotateCredentialOptions): Promise<CredentialRotation>;
|
|
1113
1133
|
/** Invalidate a credential matching an API key after authentication failure. */
|
|
1114
1134
|
invalidateMatching(provider: string, apiKey: string, options?: InvalidateCredentialMatchingOptions): Promise<boolean>;
|
|
1115
1135
|
}
|
|
@@ -1134,7 +1154,7 @@ export interface BlocksApi {
|
|
|
1134
1154
|
*/
|
|
1135
1155
|
upsert(block: StoredCredentialBlock): void;
|
|
1136
1156
|
/**
|
|
1137
|
-
* Broker-server seam: clear
|
|
1157
|
+
* Broker-server seam: clear one exact persisted block and notify snapshot waiters.
|
|
1138
1158
|
*/
|
|
1139
1159
|
delete(credentialId: number, providerKey: string, blockScope: string): void;
|
|
1140
1160
|
/** Delete all persisted blocks for a credential. */
|
|
@@ -8,8 +8,8 @@ export declare const USAGE_HEADER_INGEST_INTERVAL_MS = 60000;
|
|
|
8
8
|
/**
|
|
9
9
|
* Per-credential cool-down after a usage fetch fails. While this window is
|
|
10
10
|
* active we serve the last successful value to avoid dropping the credential
|
|
11
|
-
* from the report; without a previous value we
|
|
12
|
-
*
|
|
11
|
+
* from the report; without a previous value we return null until the
|
|
12
|
+
* cooldown expires. Report invalidation does not bypass this cooldown.
|
|
13
13
|
*/
|
|
14
14
|
export declare const USAGE_FAILURE_BACKOFF_MS = 10000;
|
|
15
15
|
/** Default usage fetch timeout; used by the AuthStorage facade. */
|
|
@@ -44,6 +44,16 @@ export declare class UsageCache {
|
|
|
44
44
|
constructor(store: AuthCredentialStore, pool: CredentialPool, usageProviders: (provider: Provider) => UsageProvider | undefined);
|
|
45
45
|
get epoch(): number;
|
|
46
46
|
bumpEpoch(): void;
|
|
47
|
+
/** Identifies confirmed recoveries that supersede an in-flight failed probe. */
|
|
48
|
+
recoveryEpoch(provider: Provider): number;
|
|
49
|
+
/**
|
|
50
|
+
* Changes when a user refresh, confirmed reset, or usage-implementation swap
|
|
51
|
+
* makes an in-flight probe too old to answer. Block marks do not change it:
|
|
52
|
+
* they stop a racing report from being cached, never trigger a re-probe.
|
|
53
|
+
*/
|
|
54
|
+
refreshEpoch(provider: Provider): number;
|
|
55
|
+
/** Failure cooldowns survive report invalidation and process restarts. */
|
|
56
|
+
failureKey(reportKey: string): string;
|
|
47
57
|
get<T>(key: string): UsageCacheEntry<T> | undefined;
|
|
48
58
|
getStale<T>(key: string): UsageCacheEntry<T> | undefined;
|
|
49
59
|
set<T>(key: string, entry: UsageCacheEntry<T>): void;
|
|
@@ -58,6 +68,8 @@ export declare class UsageCache {
|
|
|
58
68
|
* `/usage` reflects a freshly-redeemed reset instead of stale numbers.
|
|
59
69
|
*/
|
|
60
70
|
invalidate(provider: string, baseUrl?: string): void;
|
|
71
|
+
/** A confirmed reset permits one fresh probe even during a pre-reset failure cooldown. */
|
|
72
|
+
invalidateAfterReset(provider: Provider, baseUrl?: string): void;
|
|
61
73
|
/**
|
|
62
74
|
* Expire cached reports for a provider after its runtime usage implementation changes.
|
|
63
75
|
* This keeps a newly installed extension provider from serving a built-in snapshot.
|
|
@@ -102,8 +102,8 @@ export declare class UsageService implements UsageApi {
|
|
|
102
102
|
}): Promise<UsageReport[] | null>;
|
|
103
103
|
/**
|
|
104
104
|
* Discard cached usage reports before a user-requested refresh. The next
|
|
105
|
-
* read probes upstream serially per provider
|
|
106
|
-
*
|
|
105
|
+
* read probes upstream serially per provider unless a failure cooldown is
|
|
106
|
+
* active. Failed probes never replay an invalidated last-good snapshot.
|
|
107
107
|
*/
|
|
108
108
|
invalidate(provider?: string, signal?: AbortSignal): Promise<void>;
|
|
109
109
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* `/v1/healthz` require a bearer token.
|
|
7
7
|
*/
|
|
8
8
|
import type { AuthCredential, DisabledCredentialSummary } from "../auth-storage.js";
|
|
9
|
-
import type { ClientUsageReportRequest, ClientUsageReportResponse, ClientUsageSummaryResponse, CredentialBlockRequest, CredentialBlockResponse, CredentialBlocksDeleteResponse, CredentialDisableResponse, CredentialRefreshResponse, CredentialUploadResponse, HealthzResponse, SnapshotResponse, SnapshotStreamEvent, UsageHistoryResponse, UsageResponse, UsageStaleResponse } from "./types.js";
|
|
9
|
+
import type { ClientUsageReportRequest, ClientUsageReportResponse, ClientUsageSummaryResponse, CredentialBlockDeleteRequest, CredentialBlockRequest, CredentialBlockResponse, CredentialBlocksDeleteResponse, CredentialDisableResponse, CredentialRefreshResponse, CredentialUploadResponse, HealthzResponse, SnapshotResponse, SnapshotStreamEvent, UsageHistoryResponse, UsageResponse, UsageStaleResponse } from "./types.js";
|
|
10
10
|
export interface AuthBrokerClientOptions {
|
|
11
11
|
/** Base URL (e.g. `https://broker.tailnet:8765`). Trailing slashes are trimmed. */
|
|
12
12
|
url: string;
|
|
@@ -96,5 +96,6 @@ export declare class AuthBrokerClient {
|
|
|
96
96
|
listDisabledCredentials(provider?: string, signal?: AbortSignal): Promise<DisabledCredentialSummary[]>;
|
|
97
97
|
uploadCredential(provider: string, credential: AuthCredential, signal?: AbortSignal): Promise<CredentialUploadResponse>;
|
|
98
98
|
upsertCredentialBlock(id: number, block: CredentialBlockRequest, signal?: AbortSignal): Promise<CredentialBlockResponse>;
|
|
99
|
+
deleteCredentialBlock(id: number, block: CredentialBlockDeleteRequest, signal?: AbortSignal): Promise<CredentialBlocksDeleteResponse>;
|
|
99
100
|
deleteCredentialBlocks(id: number, signal?: AbortSignal): Promise<CredentialBlocksDeleteResponse>;
|
|
100
101
|
}
|
|
@@ -76,7 +76,7 @@ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
76
76
|
getCredentialBlockReconcileAfter(credentialId: number, providerKey: string, blockScope: string): number | undefined;
|
|
77
77
|
listCredentialBlocks(credentialIds: readonly number[]): StoredCredentialBlock[];
|
|
78
78
|
upsertCredentialBlock(block: StoredCredentialBlock): void;
|
|
79
|
-
deleteCredentialBlock(
|
|
79
|
+
deleteCredentialBlock(credentialId: number, providerKey: string, blockScope: string): void;
|
|
80
80
|
deleteCredentialBlocks(credentialId: number): void;
|
|
81
81
|
cleanExpiredCredentialBlocks(nowMs: number): void;
|
|
82
82
|
/**
|
|
@@ -131,9 +131,8 @@ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
131
131
|
refreshOAuthCredential(_provider: Provider, credentialId: number, _credential: OAuthCredential, signal?: AbortSignal): Promise<OAuthCredentials>;
|
|
132
132
|
/**
|
|
133
133
|
* Store-level hook consumed by `AuthStorage.usage.reports()` — proxies
|
|
134
|
-
* to the broker's `/v1/usage` endpoint.
|
|
135
|
-
*
|
|
136
|
-
* residential laptop is, so all credentials surface every cycle.
|
|
134
|
+
* to the broker's `/v1/usage` endpoint. Shared per-credential caches and
|
|
135
|
+
* cooldowns keep separate clients from multiplying provider probes.
|
|
137
136
|
*/
|
|
138
137
|
fetchUsageReports(signal?: AbortSignal): Promise<UsageReport[] | null>;
|
|
139
138
|
/**
|
|
@@ -142,8 +141,8 @@ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
142
141
|
* same response (coalesced + cached), then overlays any client-observed
|
|
143
142
|
* header hints for the matching credential.
|
|
144
143
|
*
|
|
145
|
-
* The broker
|
|
146
|
-
*
|
|
144
|
+
* The broker caches each credential independently; the short client TTL
|
|
145
|
+
* also folds sequential consumers into one broker round-trip.
|
|
147
146
|
*/
|
|
148
147
|
getUsageReport(provider: Provider, credential: OAuthCredential, signal?: AbortSignal): Promise<UsageReport | null>;
|
|
149
148
|
ingestUsageReport(provider: Provider, credential: OAuthCredential, report: UsageReport): boolean;
|
|
@@ -73,11 +73,13 @@ export interface DisabledCredentialsResponse {
|
|
|
73
73
|
}
|
|
74
74
|
/** POST /v1/credential/:id/block request body. */
|
|
75
75
|
export type CredentialBlockRequest = CredentialBlockSnapshot;
|
|
76
|
+
/** DELETE /v1/credential/:id/block request body; empty scope targets only the global row. */
|
|
77
|
+
export type CredentialBlockDeleteRequest = Pick<CredentialBlockSnapshot, "providerKey" | "blockScope">;
|
|
76
78
|
/** POST /v1/credential/:id/block response body. */
|
|
77
79
|
export interface CredentialBlockResponse {
|
|
78
80
|
ok: boolean;
|
|
79
81
|
}
|
|
80
|
-
/** DELETE /v1/credential/:id/blocks response body. */
|
|
82
|
+
/** DELETE /v1/credential/:id/block or /blocks response body. */
|
|
81
83
|
export interface CredentialBlocksDeleteResponse {
|
|
82
84
|
ok: boolean;
|
|
83
85
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { type FluentType } from "@oh-my-pi/omptype";
|
|
16
16
|
import { type ApiKeyCredential, type AuthCredential, type AuthCredentialSnapshotEntry, type DisabledCredentialSummary, type OAuthCredential, type RemoteOAuthCredential, type SnapshotCredential } from "../auth-storage.js";
|
|
17
|
-
import type { ClientUsageReportRequest, ClientUsageReportResponse, ClientUsageSummaryResponse, CredentialBlockRequest, CredentialBlockResponse, CredentialBlockSnapshot, CredentialBlocksDeleteResponse, CredentialDisableResponse, CredentialRefreshResponse, CredentialUploadRequest, CredentialUploadResponse, DisabledCredentialsResponse, HealthzResponse, RefresherSchedule, SnapshotEntry, SnapshotResponse, SnapshotStreamEntryEvent, SnapshotStreamEvent, SnapshotStreamRemovedEvent, SnapshotStreamSnapshotEvent, UsageHistoryResponse, UsageResponse, UsageStaleResponse } from "./types.js";
|
|
17
|
+
import type { ClientUsageReportRequest, ClientUsageReportResponse, ClientUsageSummaryResponse, CredentialBlockDeleteRequest, CredentialBlockRequest, CredentialBlockResponse, CredentialBlockSnapshot, CredentialBlocksDeleteResponse, CredentialDisableResponse, CredentialRefreshResponse, CredentialUploadRequest, CredentialUploadResponse, DisabledCredentialsResponse, HealthzResponse, RefresherSchedule, SnapshotEntry, SnapshotResponse, SnapshotStreamEntryEvent, SnapshotStreamEvent, SnapshotStreamRemovedEvent, SnapshotStreamSnapshotEvent, UsageHistoryResponse, UsageResponse, UsageStaleResponse } from "./types.js";
|
|
18
18
|
/** Real OAuth credential (broker-side) — refresh token is the actual upstream value. */
|
|
19
19
|
export declare const oauthCredentialSchema: FluentType<OAuthCredential>;
|
|
20
20
|
/** OAuth credential as it appears in broker snapshots — refresh replaced with sentinel. */
|
|
@@ -62,6 +62,7 @@ export declare const disabledCredentialSummarySchema: FluentType<DisabledCredent
|
|
|
62
62
|
/** Broker `GET /v1/credentials/disabled` response. */
|
|
63
63
|
export declare const disabledCredentialsResponseSchema: FluentType<DisabledCredentialsResponse>;
|
|
64
64
|
export declare const credentialBlockRequestSchema: FluentType<CredentialBlockRequest>;
|
|
65
|
+
export declare const credentialBlockDeleteRequestSchema: FluentType<CredentialBlockDeleteRequest>;
|
|
65
66
|
export declare const credentialBlockResponseSchema: FluentType<CredentialBlockResponse>;
|
|
66
67
|
export declare const credentialBlocksDeleteResponseSchema: FluentType<CredentialBlocksDeleteResponse>;
|
|
67
68
|
export declare const usageStaleResponseSchema: FluentType<UsageStaleResponse>;
|
|
@@ -13,10 +13,10 @@ import { isAuthRetryableError } from "./error/auth-classify.js";
|
|
|
13
13
|
* - `error !== undefined && lastChance` → **step (c): switch account**
|
|
14
14
|
* (invalidate/usage-limit the current credential and rotate to a sibling).
|
|
15
15
|
*
|
|
16
|
-
* Current drivers
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* cycles, or hits {@link AUTH_RETRY_MAX_ATTEMPTS}.
|
|
16
|
+
* Current drivers give an ordinary 401/auth failure one step (b) before
|
|
17
|
+
* repeating step (c) through distinct siblings. Account-scoped policy denials,
|
|
18
|
+
* 403s, and usage-limit failures skip refresh. Rotation stops when the resolver
|
|
19
|
+
* returns `undefined`, cycles, or hits {@link AUTH_RETRY_MAX_ATTEMPTS}.
|
|
20
20
|
*/
|
|
21
21
|
export interface ApiKeyResolveContext {
|
|
22
22
|
/** True when the resolver should rotate to a sibling credential. */
|
|
@@ -36,11 +36,23 @@ export interface ResolvedApiKey {
|
|
|
36
36
|
apiKey: string;
|
|
37
37
|
/** Durable row id of the credential that supplied this bearer, when known. */
|
|
38
38
|
credentialId?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Resolved after `LimitsApi.rotate` slept out a sibling's short block
|
|
41
|
+
* (`afterSiblingWait`): the driver accepts this bearer even if the request
|
|
42
|
+
* already sent it before that block.
|
|
43
|
+
*/
|
|
44
|
+
afterSiblingWait?: boolean;
|
|
39
45
|
}
|
|
40
46
|
export type ApiKeyResolution = string | ResolvedApiKey | undefined;
|
|
41
47
|
export type ApiKeyResolver = (ctx: ApiKeyResolveContext) => Promise<ApiKeyResolution> | ApiKeyResolution;
|
|
42
48
|
/** Extract the bearer while preserving optional credential provenance for streaming callers. */
|
|
43
49
|
export declare function resolvedApiKeyBearer(resolved: ApiKeyResolution): string | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Mark a post-rotation resolution as following a sibling-unblock wait so the
|
|
52
|
+
* retry driver may resend a bearer it already tried. Used by the rotating
|
|
53
|
+
* resolvers (`KeyCascade.resolver`, coding-agent `createApiKeyResolver`).
|
|
54
|
+
*/
|
|
55
|
+
export declare function markAfterSiblingWait(resolved: ApiKeyResolution): ApiKeyResolution;
|
|
44
56
|
/** A static bearer string, or a {@link ApiKeyResolver} that mints/rotates one. */
|
|
45
57
|
export type ApiKey = string | ApiKeyResolver;
|
|
46
58
|
/** Keyless-provider credential marker; transports must not send it in authentication headers. */
|
|
@@ -63,9 +75,8 @@ export declare function resolveApiKeyOnce(key: ApiKey | undefined, signal?: Abor
|
|
|
63
75
|
export declare function seedApiKeyResolver(seed: ApiKeyResolution, resolver: ApiKeyResolver): ApiKeyResolver;
|
|
64
76
|
export { isAuthRetryableError };
|
|
65
77
|
/**
|
|
66
|
-
* Legacy
|
|
67
|
-
* `false` → refresh-same, `true` → rotate/switch. Current drivers
|
|
68
|
-
* once for ordinary 401/auth failures; usage/account-limit failures may repeat
|
|
78
|
+
* Legacy a/b/c retry sequence retained for public compatibility:
|
|
79
|
+
* `false` → refresh-same, `true` → rotate/switch. Current drivers may repeat
|
|
69
80
|
* sibling rotation until a termination guard fires.
|
|
70
81
|
*/
|
|
71
82
|
export declare const AUTH_RETRY_STEPS: readonly boolean[];
|
|
@@ -79,8 +90,6 @@ export interface AuthRetryKeyState {
|
|
|
79
90
|
lastKey: string;
|
|
80
91
|
/** Whether the current credential already consumed its 401 refresh-same retry. */
|
|
81
92
|
refreshedCurrent: boolean;
|
|
82
|
-
/** Whether the legacy non-usage auth path already switched to one sibling. */
|
|
83
|
-
legacyAuthSwitchUsed: boolean;
|
|
84
93
|
/** Whether this operation already replayed once after an explicit token-refresh request. */
|
|
85
94
|
tokenRefreshReplayUsed?: boolean;
|
|
86
95
|
/** Total outbound attempts accepted for this logical operation, including the initial request. */
|
|
@@ -97,9 +106,9 @@ export declare function resolveNextAuthRetryKey(state: AuthRetryKeyState, resolv
|
|
|
97
106
|
* applicable policy is exhausted, the resolver declines or cycles, or the
|
|
98
107
|
* operation reaches {@link AUTH_RETRY_MAX_ATTEMPTS}. An explicit typed
|
|
99
108
|
* token-refresh request gets exactly one refresh-current replay and never
|
|
100
|
-
* enters sibling rotation. Ordinary 401/auth failures
|
|
101
|
-
*
|
|
102
|
-
*
|
|
109
|
+
* enters sibling rotation. Ordinary 401/auth failures get one refresh-same,
|
|
110
|
+
* then rotate through distinct siblings; 403/usage-limit failures skip the
|
|
111
|
+
* refresh and rotate directly.
|
|
103
112
|
*
|
|
104
113
|
* Used by non-streaming consumers (image generation, web search, completion
|
|
105
114
|
* helpers). The streaming driver in `stream.ts` implements the same policy with
|
|
@@ -142,7 +151,7 @@ export interface WithOAuthAccessOptions {
|
|
|
142
151
|
* - initial → `getOAuthAccess` (or `opts.seed`).
|
|
143
152
|
* - typed token-refresh request → one forced refresh-current replay, then stop.
|
|
144
153
|
* - 401/auth failure → one `getOAuthAccess` with `forceRefresh: true` for the
|
|
145
|
-
* current account, then sibling rotation.
|
|
154
|
+
* current account, then sibling rotation through distinct credentials.
|
|
146
155
|
* - 403/usage-limit failure → `rotateSessionCredential` directly, without a
|
|
147
156
|
* force-refresh detour.
|
|
148
157
|
*
|
|
@@ -14,11 +14,20 @@ export interface ImageGenerationRequest {
|
|
|
14
14
|
export interface GeneratedImage {
|
|
15
15
|
data: string;
|
|
16
16
|
mimeType: string;
|
|
17
|
+
/** Output dimensions (`WIDTHxHEIGHT`) the provider reports for this image, which may differ from the request. */
|
|
18
|
+
size?: string;
|
|
19
|
+
/** Rendering quality the provider reports for this image. */
|
|
20
|
+
quality?: string;
|
|
17
21
|
}
|
|
18
22
|
export interface ImageGenerationResult {
|
|
19
23
|
images: GeneratedImage[];
|
|
20
24
|
text?: string;
|
|
21
25
|
usage: Usage;
|
|
26
|
+
/**
|
|
27
|
+
* Image model the provider reports having run. Hosted backends may substitute their own model for the
|
|
28
|
+
* selected catalog entry (the ChatGPT/Codex backend does), so callers should prefer this over the catalog id.
|
|
29
|
+
*/
|
|
30
|
+
model?: string;
|
|
22
31
|
}
|
|
23
32
|
export interface ImageGenerationOptions {
|
|
24
33
|
apiKey: ApiKey;
|
|
@@ -101,6 +101,7 @@ export declare class JudgmentParseError extends Error {
|
|
|
101
101
|
}
|
|
102
102
|
/**
|
|
103
103
|
* Usage from a backend that reports token counts and, optionally, one billed
|
|
104
|
-
* USD amount.
|
|
104
|
+
* USD amount. Missing or non-finite amounts contribute zero to session totals.
|
|
105
|
+
* Judgment pricing is input-only, so the amount lands on `input`.
|
|
105
106
|
*/
|
|
106
|
-
export declare function tokenUsage(input: number, output: number, cost?: number): Usage;
|
|
107
|
+
export declare function tokenUsage(input: number | undefined, output: number | undefined, cost?: number): Usage;
|
|
@@ -17,7 +17,7 @@ import type { ToolResultMessage } from "../../types.js";
|
|
|
17
17
|
* virtual registry. Re-exported here because this is where the frame builders
|
|
18
18
|
* and their translation are consumed together.
|
|
19
19
|
*/
|
|
20
|
-
export { cursorEditOwnedReadPath, cursorRawReadPath, omitUndefinedArgs, piEscapeRegexLiteral, piGrepSkip, piJoinPath, piLimit, piLsPath, piReadDisplayPath, piReadPath, piReadPathHasRange, piTimeout, } from "../cursor-pi-args.js";
|
|
20
|
+
export { cursorEditOwnedReadPath, cursorRawReadPath, omitUndefinedArgs, piEscapeRegexLiteral, piGrepSkip, piJoinPath, piLimit, piLsPath, piReadDisplayPath, piReadPath, piReadPathHasRange, piTimeout, shellTimeoutSeconds, } from "../cursor-pi-args.js";
|
|
21
21
|
/** Flatten a tool result's content into the single `output` string the Pi frames carry. */
|
|
22
22
|
export declare function piOutputText(toolResult: ToolResultMessage): string;
|
|
23
23
|
/**
|
|
@@ -124,6 +124,16 @@ export declare function piLimit(limit: number | undefined): number | undefined;
|
|
|
124
124
|
* Negative values have no local meaning and fall back to the default.
|
|
125
125
|
*/
|
|
126
126
|
export declare function piTimeout(timeout: number | undefined): number | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* Convert a legacy `ShellArgs`/`ShellStreamArgs` timeout into bash-tool seconds.
|
|
129
|
+
*
|
|
130
|
+
* Cursor states that budget in milliseconds — its own `ShellTimeout` result
|
|
131
|
+
* echoes it as `timeout_ms`, and `hard_timeout` documents the same unit — while
|
|
132
|
+
* the bash tool takes seconds and rejects anything past 3600, so forwarding the
|
|
133
|
+
* raw value turned a model-requested 15 s into `requested 15000s`. Sub-second
|
|
134
|
+
* budgets round up: 0 seconds means "no deadline" to the bash tool.
|
|
135
|
+
*/
|
|
136
|
+
export declare function shellTimeoutSeconds(timeoutMs: number | undefined): number | undefined;
|
|
127
137
|
/**
|
|
128
138
|
* Drop keys whose value is `undefined` so optional local-tool kwargs stay
|
|
129
139
|
* absent rather than present-as-undefined.
|
|
@@ -211,11 +211,15 @@ export declare function mergeCursorMcpToolCallArgs(streamed: Record<string, unkn
|
|
|
211
211
|
* `agent-loop.ts` execution pass skips it — Cursor's server-driven exec
|
|
212
212
|
* channel already ran the tool via the bridge and buffered the result, so
|
|
213
213
|
* treating this block as runnable would re-execute the same side-effecting
|
|
214
|
-
* tool a second time.
|
|
214
|
+
* tool a second time. Pass `{ executed: false }` for a frame nothing ran: a
|
|
215
|
+
* call handed to an external executor is only a handoff while the marker is
|
|
216
|
+
* absent, and the consumer that runs it needs a runnable block.
|
|
215
217
|
*
|
|
216
218
|
* Exported for tests to exercise ordering with adjacent text/thinking blocks.
|
|
217
219
|
*/
|
|
218
|
-
export declare function synthesizeCursorExecToolCall(output: AssistantMessage, stream: AssistantMessageEventStream, state: BlockState, toolCallId: string, toolName: string, args: Record<string, unknown
|
|
220
|
+
export declare function synthesizeCursorExecToolCall(output: AssistantMessage, stream: AssistantMessageEventStream, state: BlockState, toolCallId: string, toolName: string, args: Record<string, unknown>, { executed }?: {
|
|
221
|
+
executed?: boolean;
|
|
222
|
+
}): void;
|
|
219
223
|
/** Exported for tests: drives one Cursor interaction update through the streaming state machine. */
|
|
220
224
|
export declare function processInteractionUpdate(update: any, output: AssistantMessage, stream: AssistantMessageEventStream, state: BlockState, usageState: UsageState): void;
|
|
221
225
|
/**
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared utilities for Google Generative AI and Google Cloud Code Assist providers.
|
|
3
3
|
*/
|
|
4
|
-
import type { AssistantMessage, Context, FetchImpl, Model, ServiceTier, StopReason, StreamOptions, TextContent, ThinkingContent, Tool, ToolCall } from "../types.js";
|
|
4
|
+
import type { AssistantMessage, Context, FetchImpl, Model, ServiceTier, StopReason, StreamOptions, TextContent, ThinkingContent, Tool, ToolCall, Usage } from "../types.js";
|
|
5
5
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
6
6
|
import { normalizeSchemaForGoogle } from "../utils/schema/index.js";
|
|
7
|
-
import type { Content, FinishReason, FunctionCallingConfigMode, GenerateContentParameters, GenerateContentResponse, Part } from "./google-types.js";
|
|
7
|
+
import type { Content, FinishReason, FunctionCallingConfigMode, GenerateContentParameters, GenerateContentResponse, Part, UsageMetadata } from "./google-types.js";
|
|
8
8
|
export type { Content, FunctionCallingConfigMode, GenerateContentParameters, GenerateContentResponse, ThinkingConfig, } from "./google-types.js";
|
|
9
9
|
export { normalizeSchemaForGoogle };
|
|
10
10
|
type GoogleApiType = "google-generative-ai" | "google-gemini-cli" | "google-vertex";
|
|
@@ -120,6 +120,17 @@ export declare const EMPTY_STREAM_BASE_DELAY_MS = 500;
|
|
|
120
120
|
* must be retried instead of surfaced.
|
|
121
121
|
*/
|
|
122
122
|
export declare function hasMeaningfulGoogleContent(output: AssistantMessage): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Maps Gemini `usageMetadata` onto {@link Usage} (cost zeroed for `calculateCost`).
|
|
125
|
+
*
|
|
126
|
+
* `promptTokenCount` includes `cachedContentTokenCount`, so input = prompt − cached,
|
|
127
|
+
* matching the OpenAI convention where input + cacheRead = total prompt tokens.
|
|
128
|
+
* Upstream sometimes omits `promptTokenCount` or reports a cache count above the
|
|
129
|
+
* prompt (Antigravity), so the prompt falls back to `total − candidates − thoughts`
|
|
130
|
+
* and cached tokens are clamped to it: input is never negative.
|
|
131
|
+
* Ref: https://ai.google.dev/api/generate-content#v1beta.GenerateContentResponse.UsageMetadata
|
|
132
|
+
*/
|
|
133
|
+
export declare function mapGoogleUsage(metadata: UsageMetadata): Usage;
|
|
123
134
|
export declare function nextToolCallId(name: string): string;
|
|
124
135
|
/**
|
|
125
136
|
* Push the appropriate `text_end` / `thinking_end` event for the given block.
|
|
@@ -5,6 +5,10 @@ export declare function claudeResetClearedBlockScopes(cleared: readonly string[]
|
|
|
5
5
|
/** OAuth credential and transport used for an account's Claude reset operations. */
|
|
6
6
|
export interface ClaudeResetAuth {
|
|
7
7
|
accessToken: string;
|
|
8
|
+
/** Observe a safe discovery read's throttle without retrying any mutation. */
|
|
9
|
+
onRateLimited?: (retryAfterMs: number | undefined) => void;
|
|
10
|
+
accountId?: string;
|
|
11
|
+
email?: string;
|
|
8
12
|
orgId?: string;
|
|
9
13
|
baseUrl?: string;
|
|
10
14
|
fetch: FetchImpl;
|
|
@@ -13,6 +17,8 @@ export interface ClaudeResetAuth {
|
|
|
13
17
|
/** Live reset eligibility plus the exact organization and host used for redemption. */
|
|
14
18
|
export interface ClaudeResetCreditList extends UsageResetCredits {
|
|
15
19
|
credits: UsageResetCredit[];
|
|
20
|
+
/** Quota evidence parsed from the same successful discovery response. */
|
|
21
|
+
report?: UsageReport;
|
|
16
22
|
orgId?: string;
|
|
17
23
|
/** OAuth API base that answered discovery; pass back as consume `baseUrl`. */
|
|
18
24
|
baseUrl?: string;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { type CredentialRankingStrategy, type UsageProvider, type UsageReport } from "../usage.js";
|
|
2
2
|
export declare function parseClaudeRateLimitHeaders(headers: Record<string, string>, now?: number): UsageReport | null;
|
|
3
|
+
/** Parse the quota evidence in one live usage response, without any additional requests. */
|
|
4
|
+
export declare function parseClaudeUsagePayload(raw: unknown, identity?: {
|
|
5
|
+
accountId?: string;
|
|
6
|
+
email?: string;
|
|
7
|
+
orgId?: string;
|
|
8
|
+
}, endpoint?: string, fetchedAt?: number): UsageReport | null;
|
|
3
9
|
export declare const claudeUsageProvider: UsageProvider;
|
|
4
10
|
export declare const claudeRankingStrategy: CredentialRankingStrategy;
|
package/dist/types/usage.d.ts
CHANGED
|
@@ -669,6 +669,8 @@ export interface CredentialRankingStrategy {
|
|
|
669
669
|
limits: UsageLimit[];
|
|
670
670
|
healthy?: boolean;
|
|
671
671
|
}[];
|
|
672
|
+
/** Whether fresh reports can heal legacy account-wide quota backoffs. */
|
|
673
|
+
healsGlobalBlocks?: boolean;
|
|
672
674
|
/** Fallback window durations (ms) when limits don't specify durationMs. */
|
|
673
675
|
windowDefaults: {
|
|
674
676
|
primaryMs: number;
|
|
@@ -23,8 +23,8 @@ export declare function getProxyForUrl(provider: string, url: URL): string | und
|
|
|
23
23
|
/**
|
|
24
24
|
* Return `init` with `proxy: proxyUrl` set when the request should tunnel.
|
|
25
25
|
* A caller-supplied `init.proxy` always wins (the innermost, most specific
|
|
26
|
-
* decision); local/metadata hosts, NO_PROXY matches, and
|
|
27
|
-
* pass through unchanged.
|
|
26
|
+
* decision); Unix sockets, local/metadata hosts, NO_PROXY matches, and
|
|
27
|
+
* unparseable URLs pass through unchanged.
|
|
28
28
|
*/
|
|
29
29
|
export declare function withProxyInit(input: string | URL | Request, init: RequestInit | undefined, proxyUrl: string): RequestInit | undefined;
|
|
30
30
|
/**
|