@oh-my-pi/pi-ai 18.2.8 → 18.2.9

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 (45) hide show
  1. package/CHANGELOG.md +33 -18
  2. package/dist/types/auth-gateway/types.d.ts +5 -0
  3. package/dist/types/auth-storage.d.ts +35 -32
  4. package/dist/types/index.d.ts +1 -0
  5. package/dist/types/providers/amazon-bedrock.d.ts +7 -0
  6. package/dist/types/providers/claude-code-fingerprint.d.ts +22 -3
  7. package/dist/types/providers/google-gemini-cli.d.ts +0 -2
  8. package/dist/types/providers/openai-chat-server-schema.d.ts +2 -2
  9. package/dist/types/usage/claude-api.d.ts +22 -0
  10. package/dist/types/usage/claude-reset.d.ts +44 -0
  11. package/dist/types/usage.d.ts +111 -5
  12. package/dist/types/utils/schema/json-schema-validator.d.ts +5 -2
  13. package/dist/types/utils/tool-call-loop-guard.d.ts +1 -1
  14. package/package.json +6 -6
  15. package/src/auth/sqlite-credential-store.ts +44 -1
  16. package/src/auth-broker/remote-store.ts +6 -6
  17. package/src/auth-broker/wire-schemas.ts +14 -0
  18. package/src/auth-gateway/server.ts +4 -0
  19. package/src/auth-gateway/types.ts +5 -0
  20. package/src/auth-storage.ts +263 -140
  21. package/src/error/flags.ts +10 -0
  22. package/src/index.ts +1 -0
  23. package/src/providers/amazon-bedrock.ts +55 -5
  24. package/src/providers/anthropic.ts +45 -11
  25. package/src/providers/aws-credentials.ts +124 -11
  26. package/src/providers/claude-code-fingerprint.ts +55 -3
  27. package/src/providers/gitlab-duo.ts +20 -4
  28. package/src/providers/google-gemini-cli.ts +0 -8
  29. package/src/providers/google-shared.ts +1 -18
  30. package/src/providers/openai-chat-server-schema.ts +1 -1
  31. package/src/providers/openai-chat-server.ts +3 -1
  32. package/src/providers/openai-codex-responses.ts +27 -5
  33. package/src/providers/openai-completions.ts +122 -19
  34. package/src/providers/pi-native-server.ts +1 -0
  35. package/src/registry/oauth/anthropic.ts +2 -3
  36. package/src/stream.ts +13 -4
  37. package/src/usage/alibaba-token-plan.ts +7 -1
  38. package/src/usage/claude-api.ts +66 -0
  39. package/src/usage/claude-reset.ts +638 -0
  40. package/src/usage/claude.ts +37 -59
  41. package/src/usage/kimi.ts +32 -1
  42. package/src/usage.ts +52 -5
  43. package/src/utils/schema/json-schema-validator.ts +23 -10
  44. package/src/utils/tool-call-loop-guard.ts +2 -2
  45. package/src/utils/validation.ts +145 -50
package/CHANGELOG.md CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.2.9] - 2026-09-22
6
+
7
+ ### Added
8
+
9
+ - Added Claude saved-reset discovery and redemption, including session-only resets, grant eligibility, expiry, and safe retry handling.
10
+
11
+ ### Fixed
12
+
13
+ - Fixed custom OpenAI-compatible extension streamers failing when no compatibility configuration was provided.
14
+ - Fixed local provider sign-in for LM Studio, llama.cpp, and vLLM so an empty API key is not treated as successful authentication.
15
+ - Fixed Vercel AI Gateway models backed by non-Anthropic providers failing tool calls because of strict schema validation; requests now retry with compatible non-strict tool handling.
16
+ - Improved AWS Bedrock authentication by refreshing expired AWS SSO sessions automatically, reducing the need to run `aws sso login` again.
17
+ - Fixed Bedrock tool-enabled requests when tool descriptions are included in the system prompt.
18
+ - Improved Alibaba Token Plan (Beijing) quota reporting across workspaces and made gateway rejection codes visible in error logs.
19
+ - Fixed the tool-call loop guard so repeated identical calls continue to be redirected after the detection threshold is reached.
20
+ - Fixed valid required null values inside tool argument unions being removed before dispatch ([#12523](https://github.com/can1357/oh-my-pi/pull/12523) by [@cswenor](https://github.com/cswenor)).
21
+ - Signing in to a local provider (lm-studio, llama.cpp, vllm) with an empty key paste no longer reports the provider as logged in while its requests go out unauthenticated. ([#12436](https://github.com/can1357/oh-my-pi/pull/12436) by [@xiechimon](https://github.com/xiechimon))
22
+ - Fixed every turn failing with `400 Invalid schema for function '<tool>' … Missing '<param>'` on Vercel AI Gateway models served from a non-Anthropic upstream (e.g. `openai/gpt-5.6-sol`): the translated strict-tool rejection now triggers the existing non-strict retry instead of failing the turn ([#12760](https://github.com/can1357/oh-my-pi/pull/12760) by [@primitive-type](https://github.com/primitive-type)).
23
+ - Expired AWS SSO access tokens are now refreshed via the SSO OIDC `refresh_token` grant instead of failing with `sso-token-expired`, so Bedrock profiles keep working between `aws sso login` runs the same way the AWS CLI does ([#12736](https://github.com/can1357/oh-my-pi/pull/12736) by [@nwbb](https://github.com/nwbb)).
24
+ - Fixed Bedrock rejecting tool-enabled requests when tool descriptions are inlined into the system prompt ([#12732](https://github.com/can1357/oh-my-pi/pull/12732) by [@mustafaabidali](https://github.com/mustafaabidali)).
25
+ - Alibaba Token Plan (Beijing) quota reporting no longer pins requests to a single workspace, and HTTP-200 gateway rejections now log their error code ([#12395](https://github.com/can1357/oh-my-pi/pull/12395) by [@Dante-dan](https://github.com/Dante-dan)).
26
+ - The tool-call loop guard keeps redirecting when a model continues the same identical call past the detection threshold instead of firing only once ([#12709](https://github.com/can1357/oh-my-pi/pull/12709) by [@F0Rextasy](https://github.com/F0Rextasy)).
27
+ - Fixed OpenAI-compatible Gemini gateways losing message-level thought signatures when replaying tool-call history.
28
+ - Added support for explicitly disabling reasoning with `reasoning_effort: "none"` through Chat Completions authentication gateways.
29
+ - Improved Bedrock resilience by retrying transient in-stream internal server, service unavailable, and throttling errors.
30
+ - Fixed Anthropic prompt-cache keep-alive refreshes for turns that used forced tool selection.
31
+ - Fixed auth-broker usage reports incorrectly sharing usage limits between Team members with shared workspace and organization identifiers.
32
+ - Fixed OpenAI Codex requests hanging when an error response body is delayed.
33
+ - Fixed Kimi usage reporting so monthly totals and code quotas are shown alongside the five-hour usage window.
34
+ - Bedrock no longer sends provider-invalid payloads when an errored tool result contains an image; the image is hoisted into a sibling block ([#12865](https://github.com/can1357/oh-my-pi/pull/12865) by [@roboomp](https://github.com/roboomp)).
35
+ - Gemini, Vertex, and Cloud Code Assist requests no longer include the unsupported `minP`/`repetitionPenalty` sampling fields, which caused 400s when set globally ([#12850](https://github.com/can1357/oh-my-pi/pull/12850) by [@roboomp](https://github.com/roboomp)).
36
+
5
37
  ## [18.2.8] - 2026-09-21
6
38
 
7
39
  ### Added
@@ -2255,21 +2287,4 @@
2255
2287
  - Made the openai-completions non-strict retry reachable for `"mixed"` strict mode (previously gated to `all_strict`, i.e. Cerebras only) and taught it to recognize upstream tool-schema validation 400s (`Invalid tool parameters schema …`, `Invalid schema for function …`). A matching rejection now retries the request with base (non-strict) schemas and persists `strictToolsDisabled` on the provider session, so later requests skip the doomed strict attempt instead of paying a 400 + retry round-trip each turn. ([#2270](https://github.com/can1357/oh-my-pi/issues/2270))
2256
2288
  - Cross-model `anthropic-messages → anthropic-messages` continuations now preserve prior assistant turns' reasoning chains end-to-end: every prior `thinking`/`redactedThinking` block survives (not just the latest surviving assistant), and third-party ↔ third-party replays keep their signatures intact so the reasoning chain stays signed for the next turn. Signatures are stripped (and any `redacted_thinking` sibling without a native landing spot is dropped) only when an official Anthropic endpoint is on either end of the replay — official Anthropic cryptographically binds reasoning signatures to its key+session+model, while compatible reasoning endpoints (Z.AI, DeepSeek, custom anthropic-messages providers configured via `models.yaml`) treat them as opaque continuation hints. Source-side official detection uses the canonical catalog provider id `"anthropic"` (assistant messages carry no `baseUrl`); target-side detection reuses the baked `compat.officialEndpoint` flag. Latest-turn byte-for-byte behavior (Anthropic's "thinking blocks in the latest assistant message cannot be modified" rule) and existing aborted/errored last-block sanitization are unchanged. ([#2257](https://github.com/can1357/oh-my-pi/issues/2257), [#2265](https://github.com/can1357/oh-my-pi/issues/2265))
2257
2289
 
2258
- ## [15.10.12] - 2026-06-10
2259
-
2260
- ### Added
2261
-
2262
- - Added `antigravityRankingStrategy` and registered it for `google-antigravity` in `DEFAULT_RANKING_STRATEGIES`, so new sessions are routed to OAuth credentials with quota headroom for the requested model backend (lowest relevant `remainingFraction` counter as the sole ranked window, 24h `windowDefaults` matching `daily-cloudcode-pa.googleapis.com` resets). Without it, the existing `antigravityUsageProvider` data never reached credential selection. ([#2198](https://github.com/can1357/oh-my-pi/issues/2198))
2263
-
2264
- ### Changed
2265
-
2266
- - Updated MiniMax and MiniMax Token Plan defaults to `MiniMax-M3` and refreshed Token Plan login copy/links ([#1725](https://github.com/can1357/oh-my-pi/issues/1725)).
2267
-
2268
- ### Fixed
2269
-
2270
- - Fixed OpenAI Responses and Azure OpenAI Responses streams silently surfacing incomplete output as successful when a custom/proxy provider drops the connection without sending a terminal `response.completed`/`response.incomplete` event. Both providers now detect premature stream closure and throw with `stopReason: "error"` ([#2184](https://github.com/can1357/oh-my-pi/pull/2184))
2271
- - Fixed `isUsageLimitError` missing Antigravity / Cloud Code Assist's `Individual quota reached` 429 phrasing. The `USAGE_LIMIT_PATTERN` only knew `quota.?exceeded` / `limit_reached`, so `auth-retry` and `AuthStorage.markUsageLimitReached` treated the response as a terminal provider error and pinned sessions to the exhausted OAuth account instead of rotating to a sibling credential. The pattern now also matches `quota.?reached`. ([#2198](https://github.com/can1357/oh-my-pi/issues/2198))
2272
- - Scoped Antigravity usage blocking and ranking by model family (`gemini-*`/`gemma-*` → Google, `claude-*` → Anthropic, `gpt-*`/`openai/*` → OpenAI), so an exhausted Gemini counter no longer makes a healthy Claude/OpenAI Antigravity credential unavailable until reset. ([#2198](https://github.com/can1357/oh-my-pi/issues/2198))
2273
- - Fixed no-model Antigravity credential lookups (e.g. image-provider discovery) inheriting provider-wide exhaustion: `scopeLimits` now returns no limits without a concrete backend counter, and `blockScope` always returns a counter scope so missing model context can never fall through to AuthStorage's provider-wide block bucket. ([#2198](https://github.com/can1357/oh-my-pi/issues/2198))
2274
-
2275
- Older entries are archived in [packages/ai/CHANGELOG.md@8a9097246135](https://github.com/can1357/oh-my-pi/blob/8a9097246135bd572ff96fb552121fe1194d2906/packages/ai/CHANGELOG.md).
2290
+ Older entries are archived in [packages/ai/CHANGELOG.md@1f7329fc2c7c](https://github.com/can1357/oh-my-pi/blob/1f7329fc2c7c366b38731738e0db9c170f9bb348/packages/ai/CHANGELOG.md).
@@ -47,6 +47,11 @@ export interface AuthGatewayParsedRequestOptions {
47
47
  reasoning?: Effort;
48
48
  /** Force-disable reasoning (Anthropic `thinking: { type: "disabled" }`). */
49
49
  disableReasoning?: boolean;
50
+ /**
51
+ * Preserve an explicit wire-level reasoning-off request through providers
52
+ * that distinguish it from the generic disable hint.
53
+ */
54
+ forceReasoningOff?: boolean;
50
55
  /**
51
56
  * Explicit Anthropic `thinking.budget_tokens`. Mirrors Rust's
52
57
  * `resolve_thinking_budget`: pins onto whichever effort the client
@@ -1,8 +1,7 @@
1
1
  import type { ApiKeyResolver } from "./auth-retry.js";
2
2
  import type { OAuthAuthInfo, OAuthController, OAuthCredentials, OAuthPrompt, OAuthProviderId } from "./registry/oauth/types.js";
3
3
  import type { Provider } from "./types.js";
4
- import type { ClientUsageIdentity, ClientUsageReport, ClientUsageSummary, CredentialRankingStrategy, ObservedUsageEntry, UsageHistoryEntry, UsageHistoryQuery, UsageLogger, UsageProvider, UsageReport } from "./usage.js";
5
- import { type CodexResetConsumeCode, type CodexResetCredit } from "./usage/openai-codex-reset.js";
4
+ import type { ClientUsageIdentity, ClientUsageReport, ClientUsageSummary, CredentialRankingStrategy, ObservedUsageEntry, UsageHistoryEntry, UsageHistoryQuery, UsageLogger, UsageProvider, UsageReport, UsageResetCredit, UsageResetCredits } from "./usage.js";
6
5
  export { isSqliteBusyError, isSqliteCorruptionError, SqliteAuthCredentialStore } from "./auth/sqlite-credential-store.js";
7
6
  export type ApiKeyCredential = {
8
7
  type: "api_key";
@@ -685,14 +684,15 @@ export interface StoredOAuthRefreshResult<T extends OAuthCredential = OAuthCrede
685
684
  refreshed: boolean;
686
685
  removed: boolean;
687
686
  }
688
- /**
689
- * Identifies which stored account to redeem a saved rate-limit reset for.
690
- * Any one field is enough; `credentialId` is the most precise.
691
- */
687
+ /** A saved-reset option bound to one provider and durable stored credential. */
692
688
  export interface ResetCreditTarget {
693
- credentialId?: number;
689
+ provider: string;
690
+ credentialId: number;
691
+ /** Grant selected by the caller; a changed offer must be confirmed again. */
692
+ creditId?: string;
694
693
  accountId?: string;
695
694
  email?: string;
695
+ orgId?: string;
696
696
  }
697
697
  /** Outcome of {@link AuthStorage.redeemResetCredit}. */
698
698
  export interface ResetCreditRedeemOutcome {
@@ -706,20 +706,27 @@ export interface ResetCreditRedeemOutcome {
706
706
  * retryable, unlike a genuine `no_credit`), `http_<status>` (unexpected
707
707
  * HTTP).
708
708
  */
709
- code: CodexResetConsumeCode;
709
+ code: string;
710
+ provider?: string;
710
711
  accountId?: string;
711
712
  email?: string;
713
+ orgId?: string;
714
+ /** Provider explanation for an unavailable or refused reset. */
715
+ reason?: string;
716
+ /** Normalized usage limit IDs the provider confirmed it cleared. */
717
+ cleared?: string[];
712
718
  /** The credit that was spent (when one was). */
713
719
  creditId?: string;
714
720
  }
715
721
  /** One stored account's live saved-reset status, from {@link AuthStorage.listResetCredits}. */
716
- export interface ResetCreditAccountStatus {
717
- credentialId?: number;
722
+ export interface ResetCreditAccountStatus extends UsageResetCredits {
723
+ provider: string;
724
+ credentialId: number;
718
725
  accountId?: string;
719
726
  email?: string;
720
- /** Resets redeemable for this account right now (live, not cached). */
721
- availableCount: number;
722
- credits: CodexResetCredit[];
727
+ orgId?: string;
728
+ orgName?: string;
729
+ credits: UsageResetCredit[];
723
730
  /** Whether this is the given session's active account. */
724
731
  active: boolean;
725
732
  /** Set when the account's token refresh or list call failed. */
@@ -858,11 +865,23 @@ export declare class AuthStorage {
858
865
  * Check if credentials exist for a provider in storage.
859
866
  */
860
867
  has(provider: string): boolean;
868
+ /**
869
+ * True when the provider has stored credentials but none of them carries
870
+ * auth — i.e. its only credential is the KDL `empty-fallback` keyless-mode
871
+ * marker (an empty paste at an optional-key login prompt). Such a provider
872
+ * is configured-but-keyless: model availability treats it like an
873
+ * `auth: none` endpoint instead of locking it out (issue #12281).
874
+ */
875
+ hasKeylessPlaceholder(provider: string): boolean;
861
876
  /**
862
877
  * Dedicated auth for default-model availability (picker / `getAvailable`).
863
878
  * Unlike {@link getApiKey}, this does not refresh OAuth tokens, and unlike
864
879
  * {@link hasResolvableAuth} it ignores cross-provider env aliases so
865
880
  * `XAI_API_KEY` does not auto-select SuperGrok (`xai-oauth`).
881
+ *
882
+ * A stored keyless-fallback marker (empty paste at an optional-key login)
883
+ * does not count: it never reaches the wire as a bearer, so treating it as
884
+ * auth would present the provider as signed-in while requests go out bare.
866
885
  */
867
886
  hasAuth(provider: string): boolean;
868
887
  /**
@@ -1170,16 +1189,7 @@ export declare class AuthStorage {
1170
1189
  * explicit runtime/config API-key override suppresses OAuth.
1171
1190
  */
1172
1191
  getOAuthAccessByCredentialId(provider: string, credentialId: number, options?: AuthApiKeyOptions): Promise<OAuthAccessResolution | undefined>;
1173
- /**
1174
- * List saved rate-limit resets for every stored OAuth account of `provider`
1175
- * (Codex), fetched LIVE from the dedicated `rate-limit-reset-credits` route.
1176
- *
1177
- * This deliberately bypasses the usage-report cache: `/wham/usage` is
1178
- * IP-rate-limited and may serve stale (or pre-feature) snapshots when many
1179
- * accounts are polled, which would hide redeemable credits. One entry per
1180
- * account, with the session's active account flagged and unreachable
1181
- * accounts carrying an `error`.
1182
- */
1192
+ /** List live saved-reset balances and eligibility for one provider's stored OAuth accounts. */
1183
1193
  listResetCredits(options?: {
1184
1194
  provider?: string;
1185
1195
  sessionId?: string;
@@ -1187,18 +1197,11 @@ export declare class AuthStorage {
1187
1197
  signal?: AbortSignal;
1188
1198
  }): Promise<ResetCreditAccountStatus[]>;
1189
1199
  /**
1190
- * Redeem one saved rate-limit reset (OpenAI Codex "saved resets") for a
1191
- * specific stored account.
1192
- *
1193
- * Resolves a fresh access token for the target account, picks an available
1194
- * credit (the given `creditId`, else the first redeemable one), spends it,
1195
- * and invalidates the cached usage report so the next `/usage` reflects the
1196
- * reset. Never throws for business outcomes — inspect the returned `code`.
1200
+ * Redeem a stored account's saved reset after checking its live offer.
1201
+ * Business refusals return a code; transport errors may throw without losing Claude's request ID.
1197
1202
  */
1198
1203
  redeemResetCredit(options: {
1199
1204
  target: ResetCreditTarget;
1200
- provider?: string;
1201
- creditId?: string;
1202
1205
  baseUrlResolver?: (provider: string) => string | undefined;
1203
1206
  signal?: AbortSignal;
1204
1207
  }): Promise<ResetCreditRedeemOutcome>;
@@ -39,6 +39,7 @@ export * from "./stream.js";
39
39
  export * from "./types.js";
40
40
  export * from "./usage.js";
41
41
  export * from "./usage/claude.js";
42
+ export * from "./usage/claude-reset.js";
42
43
  export * from "./usage/cursor.js";
43
44
  export * from "./usage/gemini.js";
44
45
  export * from "./usage/github-copilot.js";
@@ -11,6 +11,13 @@
11
11
  */
12
12
  import type { Effort } from "@oh-my-pi/pi-catalog/effort";
13
13
  import type { StreamFunction, StreamOptions, ThinkingBudgets } from "../types.js";
14
+ /**
15
+ * Resolve the service-model status for an in-stream exception/error code.
16
+ * Frame headers carry the bare shape name in either camelCase
17
+ * (`internalServerException`) or PascalCase (`InternalServerException`); both
18
+ * normalize to the same map key. Unknown shapes default to 400.
19
+ */
20
+ export declare function bedrockStreamExceptionStatus(code: string): number;
14
21
  export type BedrockThinkingDisplay = "summarized" | "omitted";
15
22
  /** Bedrock guardrail trace verbosity, mirrors the Converse `guardrailConfig.trace` values. */
16
23
  export type BedrockGuardrailTrace = "enabled" | "disabled" | "enabled_full";
@@ -7,12 +7,31 @@
7
7
  * `registry` → `registry/oauth/anthropic` → back into the still-initializing
8
8
  * provider module.
9
9
  */
10
- /** Current Claude Code CLI version represented on the Anthropic wire. */
11
- export declare const claudeCodeVersion = "2.1.257";
10
+ /**
11
+ * Pinned Claude Code CLI version: the offline fallback for {@link getClaudeCodeVersion}.
12
+ * Bumped to the latest npm release by `bun run check-spoofed-versions --update`.
13
+ */
14
+ export declare const DEFAULT_CLAUDE_CODE_VERSION = "2.1.280";
12
15
  /** `@anthropic-ai/sdk` version bundled by the current Claude Code release. */
13
16
  export declare const claudeCodeSdkVersion = "0.112.1";
17
+ /**
18
+ * Claude Code CLI version represented on the Anthropic wire (User-Agent, billing
19
+ * header): `PI_AI_CLAUDE_CODE_VERSION` → version adopted from a server rejection
20
+ * (see {@link adoptRequiredClaudeCodeVersion}) → {@link DEFAULT_CLAUDE_CODE_VERSION}.
21
+ */
22
+ export declare function getClaudeCodeVersion(): string;
14
23
  /** User-Agent emitted by Claude Code's CLI inference entrypoint. */
15
- export declare const claudeCodeUserAgent = "claude-cli/2.1.257 (external, cli)";
24
+ export declare function getClaudeCodeUserAgent(): string;
25
+ /**
26
+ * Adopts the minimum version named by an Anthropic `claude_code_version_too_old`
27
+ * rejection for the rest of the process, so the pinned fallback going stale costs
28
+ * one rejected request instead of a hard failure.
29
+ *
30
+ * Returns true only when the wire version actually increased — callers retry on
31
+ * true, so a repeated rejection at the same version cannot loop. Always false
32
+ * while `PI_AI_CLAUDE_CODE_VERSION` pins the version explicitly.
33
+ */
34
+ export declare function adoptRequiredClaudeCodeVersion(error: unknown): boolean;
16
35
  /** Prefix used to isolate custom Anthropic OAuth tools from built-in tools. */
17
36
  export declare const claudeToolPrefix: string;
18
37
  /** Identity block prepended by Claude Code's CLI runtime. */
@@ -95,9 +95,7 @@ interface CloudCodeAssistRequest {
95
95
  temperature?: number;
96
96
  topP?: number;
97
97
  topK?: number;
98
- minP?: number;
99
98
  presencePenalty?: number;
100
- repetitionPenalty?: number;
101
99
  thinkingConfig?: ThinkingConfig;
102
100
  };
103
101
  tools?: {
@@ -1048,7 +1048,7 @@ export declare const openaiChatRequestSchema: import("@oh-my-pi/omptype").Fluent
1048
1048
  prediction?: unknown;
1049
1049
  presence_penalty?: number | undefined;
1050
1050
  prompt_cache_key?: unknown;
1051
- reasoning_effort?: "high" | "low" | "max" | "medium" | "minimal" | "xhigh" | undefined;
1051
+ reasoning_effort?: "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh" | undefined;
1052
1052
  response_format?: unknown;
1053
1053
  safety_identifier?: unknown;
1054
1054
  seed?: number | undefined;
@@ -1263,7 +1263,7 @@ export declare const openaiChatRequestSchema: import("@oh-my-pi/omptype").Fluent
1263
1263
  prediction?: unknown;
1264
1264
  presence_penalty?: number | undefined;
1265
1265
  prompt_cache_key?: unknown;
1266
- reasoning_effort?: "high" | "low" | "max" | "medium" | "minimal" | "xhigh" | undefined;
1266
+ reasoning_effort?: "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh" | undefined;
1267
1267
  response_format?: unknown;
1268
1268
  safety_identifier?: unknown;
1269
1269
  seed?: number | undefined;
@@ -0,0 +1,22 @@
1
+ /** Canonical host for Claude's first-party account API. */
2
+ export declare const DEFAULT_CLAUDE_API_BASE_URL = "https://api.anthropic.com";
3
+ /** Canonical subscription usage and profile endpoint. */
4
+ export declare const DEFAULT_CLAUDE_OAUTH_BASE_URL = "https://api.anthropic.com/api/oauth";
5
+ /** OAuth protocol beta required by Claude's account routes. */
6
+ export declare const CLAUDE_OAUTH_BETA = "oauth-2025-04-20";
7
+ /**
8
+ * Normalize Messages (`/v1`) and OAuth (`/api/oauth`) endpoints to the common
9
+ * API root used by both usage and reset routes. Custom path prefixes survive.
10
+ */
11
+ export declare function normalizeClaudeApiBaseUrl(baseUrl?: string): string;
12
+ /** Resolve the OAuth API base while retaining a configured proxy path prefix. */
13
+ export declare function claudeOAuthBaseUrl(baseUrl?: string): string;
14
+ /** Configured OAuth endpoint followed by canonical fallback, without duplicates. */
15
+ export declare function claudeOAuthBaseUrls(baseUrl?: string): readonly string[];
16
+ /** Resolve a first-party account route against the configured Claude API root. */
17
+ export declare function claudeApiUrl(baseUrl: string | undefined, path: string): string;
18
+ /** Shared OAuth and CLI identity headers for Claude usage, profile, and resets. */
19
+ export declare function buildClaudeOAuthHeaders(accessToken: string, options?: {
20
+ beta?: string;
21
+ json?: boolean;
22
+ }): Record<string, string>;
@@ -0,0 +1,44 @@
1
+ import type { UsageResetCredit, UsageResetCredits } from "../usage.js";
2
+ import type { FetchImpl } from "../types.js";
3
+ /** OAuth credential and transport used for an account's Claude reset operations. */
4
+ export interface ClaudeResetAuth {
5
+ accessToken: string;
6
+ orgId?: string;
7
+ baseUrl?: string;
8
+ fetch: FetchImpl;
9
+ signal?: AbortSignal;
10
+ }
11
+ /** Live reset eligibility plus the exact organization and host used for redemption. */
12
+ export interface ClaudeResetCreditList extends UsageResetCredits {
13
+ credits: UsageResetCredit[];
14
+ orgId?: string;
15
+ /** OAuth API base that answered discovery; pass back as consume `baseUrl`. */
16
+ baseUrl?: string;
17
+ }
18
+ /** Confirmed reset outcome; transport uncertainty never reports a successful spend. */
19
+ export interface ClaudeResetConsumeResult {
20
+ ok: boolean;
21
+ code: string;
22
+ status: number;
23
+ cleared?: string[];
24
+ reason?: string;
25
+ raw?: unknown;
26
+ }
27
+ /**
28
+ * Reuse program blocks when a normal usage response actually includes them.
29
+ * A lone non-redeemable Cedar block is inconclusive because Juniper requires
30
+ * the separate at-wall read, so callers must still perform discovery.
31
+ *
32
+ * @internal
33
+ */
34
+ export declare function parseClaudeResetCreditsFromUsagePayload(payload: unknown, orgId?: string, baseUrl?: string): ClaudeResetCreditList | null;
35
+ /**
36
+ * Discover Claude's saved Cedar grant first, then its Juniper session reset.
37
+ * `null` means discovery failed; a zero-count object is an authoritative answer.
38
+ */
39
+ export declare function listClaudeResetCredits(auth: ClaudeResetAuth): Promise<ClaudeResetCreditList | null>;
40
+ /** Spend exactly the server-selected Claude reset. Mutation requests are never retried. */
41
+ export declare function consumeClaudeResetCredit(auth: ClaudeResetAuth & {
42
+ credit: UsageResetCredit;
43
+ redeemRequestId?: string;
44
+ }): Promise<ClaudeResetConsumeResult>;
@@ -62,11 +62,29 @@ export interface UsageLimit {
62
62
  * Per-credit detail for a saved/banked rate-limit reset.
63
63
  *
64
64
  * Populated when the provider's listing endpoint returns individual credit
65
- * metadata (e.g. OpenAI Codex `wham/rate-limit-reset-credits`). Callers that
65
+ * metadata (e.g. OpenAI Codex credits or Claude Cedar grants). Callers that
66
66
  * only need the count can ignore this; display layers use `expiresAt` to show
67
67
  * when banked resets expire ([#3339](https://github.com/can1357/oh-my-pi/issues/3339)).
68
68
  */
69
69
  export interface UsageResetCreditDetail {
70
+ /** Opaque provider credit/grant identifier. */
71
+ id?: string;
72
+ /** Human-facing name for the reset. */
73
+ title?: string;
74
+ /** Provider reset program/family. */
75
+ program?: string;
76
+ /** Resets still banked in this credit/grant. */
77
+ remainingCount?: number;
78
+ /** Whether the provider says this credit can be redeemed now. */
79
+ usable?: boolean;
80
+ /** Whether redemption requires an exhausted covered limit. */
81
+ requiresLimit?: boolean;
82
+ /** Normalized {@link UsageLimit.id}s this credit resets. */
83
+ clears?: string[];
84
+ /** Normalized limit ids currently preventing redemption. */
85
+ blocking?: string[];
86
+ /** Used fractions for covered limits, keyed by normalized limit id. */
87
+ usedFractions?: Record<string, number>;
70
88
  /** ISO timestamp when the credit was granted. */
71
89
  grantedAt?: string;
72
90
  /** ISO timestamp when the credit expires and can no longer be redeemed. */
@@ -74,17 +92,31 @@ export interface UsageResetCreditDetail {
74
92
  /** Backend status, e.g. `available`, `redeemed`. */
75
93
  status?: string;
76
94
  }
95
+ /** Reset credit carrying the provider id required by its consume endpoint. */
96
+ export interface UsageResetCredit extends UsageResetCreditDetail {
97
+ id: string;
98
+ }
77
99
  /**
78
100
  * Saved/banked rate-limit resets an account can redeem on demand.
79
101
  *
80
102
  * Surfaced by providers that let users defer a usage-window reset and spend it
81
- * later (OpenAI Codex "saved rate limit resets"). The redeem itself is a
82
- * separate, provider-specific action; this is the read-only count for display.
103
+ * later (OpenAI Codex and Claude Cedar resets). The redeem itself is a
104
+ * separate, provider-specific action; this is the read-only state for display.
83
105
  */
84
106
  export interface UsageResetCredits {
85
- /** Number of resets available to redeem right now. */
107
+ /** Number of banked resets, including grants that are not currently usable. */
86
108
  availableCount: number;
87
- /** Individual credit details (expiry dates, etc.) when the provider exposes them. */
109
+ /** Number of resets the provider says can be redeemed now. */
110
+ redeemableCount?: number;
111
+ /** Provider-selected credit/grant eligible for the next redemption. */
112
+ nextCreditId?: string;
113
+ /** Whether this account is eligible for the reset program. */
114
+ eligible?: boolean;
115
+ /** Provider reason the program or its credits are unavailable. */
116
+ reason?: string;
117
+ /** ISO timestamp until which redemption is cooling down. */
118
+ cooldownUntil?: string;
119
+ /** Individual credit details (expiry dates, coverage, etc.) when exposed. */
88
120
  credits?: UsageResetCreditDetail[];
89
121
  }
90
122
  /** Aggregated usage report for a provider. */
@@ -321,28 +353,74 @@ export declare const usageLimitSchema: import("@oh-my-pi/omptype").FluentType<{
321
353
  } | undefined;
322
354
  }>;
323
355
  export declare const usageResetCreditDetailSchema: import("@oh-my-pi/omptype").FluentType<{
356
+ blocking?: string[] | undefined;
357
+ clears?: string[] | undefined;
324
358
  expiresAt?: string | undefined;
325
359
  grantedAt?: string | undefined;
360
+ id?: string | undefined;
361
+ program?: string | undefined;
362
+ remainingCount?: number | undefined;
363
+ requiresLimit?: boolean | undefined;
326
364
  status?: string | undefined;
365
+ title?: string | undefined;
366
+ usable?: boolean | undefined;
367
+ usedFractions?: Record<string, number> | undefined;
327
368
  }, {
369
+ blocking?: string[] | undefined;
370
+ clears?: string[] | undefined;
328
371
  expiresAt?: string | undefined;
329
372
  grantedAt?: string | undefined;
373
+ id?: string | undefined;
374
+ program?: string | undefined;
375
+ remainingCount?: number | undefined;
376
+ requiresLimit?: boolean | undefined;
330
377
  status?: string | undefined;
378
+ title?: string | undefined;
379
+ usable?: boolean | undefined;
380
+ usedFractions?: Record<string, number> | undefined;
331
381
  }>;
332
382
  export declare const usageResetCreditsSchema: import("@oh-my-pi/omptype").FluentType<{
333
383
  availableCount: number;
384
+ cooldownUntil?: string | undefined;
334
385
  credits?: {
386
+ blocking?: string[] | undefined;
387
+ clears?: string[] | undefined;
335
388
  expiresAt?: string | undefined;
336
389
  grantedAt?: string | undefined;
390
+ id?: string | undefined;
391
+ program?: string | undefined;
392
+ remainingCount?: number | undefined;
393
+ requiresLimit?: boolean | undefined;
337
394
  status?: string | undefined;
395
+ title?: string | undefined;
396
+ usable?: boolean | undefined;
397
+ usedFractions?: Record<string, number> | undefined;
338
398
  }[] | undefined;
399
+ eligible?: boolean | undefined;
400
+ nextCreditId?: string | undefined;
401
+ reason?: string | undefined;
402
+ redeemableCount?: number | undefined;
339
403
  }, {
340
404
  availableCount: number;
405
+ cooldownUntil?: string | undefined;
341
406
  credits?: {
407
+ blocking?: string[] | undefined;
408
+ clears?: string[] | undefined;
342
409
  expiresAt?: string | undefined;
343
410
  grantedAt?: string | undefined;
411
+ id?: string | undefined;
412
+ program?: string | undefined;
413
+ remainingCount?: number | undefined;
414
+ requiresLimit?: boolean | undefined;
344
415
  status?: string | undefined;
416
+ title?: string | undefined;
417
+ usable?: boolean | undefined;
418
+ usedFractions?: Record<string, number> | undefined;
345
419
  }[] | undefined;
420
+ eligible?: boolean | undefined;
421
+ nextCreditId?: string | undefined;
422
+ reason?: string | undefined;
423
+ redeemableCount?: number | undefined;
346
424
  }>;
347
425
  export declare const usageReportSchema: import("@oh-my-pi/omptype").FluentType<{
348
426
  fetchedAt: number;
@@ -384,11 +462,25 @@ export declare const usageReportSchema: import("@oh-my-pi/omptype").FluentType<{
384
462
  raw?: unknown;
385
463
  resetCredits?: {
386
464
  availableCount: number;
465
+ cooldownUntil?: string | undefined;
387
466
  credits?: {
467
+ blocking?: string[] | undefined;
468
+ clears?: string[] | undefined;
388
469
  expiresAt?: string | undefined;
389
470
  grantedAt?: string | undefined;
471
+ id?: string | undefined;
472
+ program?: string | undefined;
473
+ remainingCount?: number | undefined;
474
+ requiresLimit?: boolean | undefined;
390
475
  status?: string | undefined;
476
+ title?: string | undefined;
477
+ usable?: boolean | undefined;
478
+ usedFractions?: Record<string, number> | undefined;
391
479
  }[] | undefined;
480
+ eligible?: boolean | undefined;
481
+ nextCreditId?: string | undefined;
482
+ reason?: string | undefined;
483
+ redeemableCount?: number | undefined;
392
484
  } | undefined;
393
485
  }, {
394
486
  fetchedAt: number;
@@ -430,11 +522,25 @@ export declare const usageReportSchema: import("@oh-my-pi/omptype").FluentType<{
430
522
  raw?: unknown;
431
523
  resetCredits?: {
432
524
  availableCount: number;
525
+ cooldownUntil?: string | undefined;
433
526
  credits?: {
527
+ blocking?: string[] | undefined;
528
+ clears?: string[] | undefined;
434
529
  expiresAt?: string | undefined;
435
530
  grantedAt?: string | undefined;
531
+ id?: string | undefined;
532
+ program?: string | undefined;
533
+ remainingCount?: number | undefined;
534
+ requiresLimit?: boolean | undefined;
436
535
  status?: string | undefined;
536
+ title?: string | undefined;
537
+ usable?: boolean | undefined;
538
+ usedFractions?: Record<string, number> | undefined;
437
539
  }[] | undefined;
540
+ eligible?: boolean | undefined;
541
+ nextCreditId?: string | undefined;
542
+ reason?: string | undefined;
543
+ redeemableCount?: number | undefined;
438
544
  } | undefined;
439
545
  }>;
440
546
  /** Optional logger for usage fetchers. */
@@ -16,7 +16,10 @@ export interface JsonSchemaValidationResult {
16
16
  success: boolean;
17
17
  issues: JsonSchemaValidationIssue[];
18
18
  }
19
+ /** The unique discriminator-selected branch, or undefined when selection is ambiguous or absent. */
20
+ export declare function getTagSelectedUnionBranch(branches: readonly unknown[], value: unknown): unknown;
19
21
  /** Whether any same-instance schema declaration or constraint owns this property name. */
20
22
  export declare function schemaDefinesProperty(schema: unknown, key: string): boolean;
21
- export declare function validateJsonSchemaValue(schema: unknown, value: unknown): JsonSchemaValidationResult;
22
- export declare function isJsonSchemaValueValid(schema: unknown, value: unknown): boolean;
23
+ export declare function validateJsonSchemaValue(schema: unknown, value: unknown, root?: unknown): JsonSchemaValidationResult;
24
+ /** Validate a subschema using its complete schema's local-reference context. */
25
+ export declare function isJsonSchemaValueValid(schema: unknown, value: unknown, root?: unknown): boolean;
@@ -21,6 +21,6 @@ export interface RepeatedToolCallDetection {
21
21
  export declare class ToolCallLoopGuard {
22
22
  #private;
23
23
  constructor(options: ToolCallLoopGuardOptions);
24
- /** Records one completed turn and returns the threshold hit, if any. */
24
+ /** Records one completed turn and reports repetitions at or beyond the threshold. */
25
25
  recordTurn(turn: ToolCallLoopTurn): RepeatedToolCallDetection | null;
26
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-ai",
3
- "version": "18.2.8",
3
+ "version": "18.2.9",
4
4
  "description": "Unified LLM API with automatic model discovery and provider configuration",
5
5
  "keywords": [
6
6
  "ai",
@@ -152,11 +152,11 @@
152
152
  "fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
153
153
  },
154
154
  "dependencies": {
155
- "@oh-my-pi/omptype": "18.2.8",
156
- "@oh-my-pi/pi-catalog": "18.2.8",
157
- "@oh-my-pi/pi-natives": "18.2.8",
158
- "@oh-my-pi/pi-utils": "18.2.8",
159
- "@oh-my-pi/pi-wire": "18.2.8"
155
+ "@oh-my-pi/omptype": "18.2.9",
156
+ "@oh-my-pi/pi-catalog": "18.2.9",
157
+ "@oh-my-pi/pi-natives": "18.2.9",
158
+ "@oh-my-pi/pi-utils": "18.2.9",
159
+ "@oh-my-pi/pi-wire": "18.2.9"
160
160
  },
161
161
  "devDependencies": {
162
162
  "@types/bun": "^1.3.14"