@gajae-code/ai 0.16.1 → 0.16.4
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 +25 -0
- package/dist/types/auth-gateway/server.d.ts +4 -2
- package/dist/types/bedrock-claude-cache-policy.d.ts +21 -0
- package/dist/types/openai-completions-compat.d.ts +22 -0
- package/dist/types/providers/amazon-bedrock.d.ts +17 -2
- package/dist/types/providers/anthropic.d.ts +1 -0
- package/dist/types/providers/openai-completions-compat.d.ts +1 -1
- package/dist/types/providers/opencode-go-session.d.ts +5 -0
- package/dist/types/types.d.ts +7 -0
- package/dist/types/utils/codex-entitlement.d.ts +22 -0
- package/package.json +3 -3
- package/src/auth-gateway/server.ts +5 -0
- package/src/auth-storage.ts +31 -8
- package/src/bedrock-claude-cache-policy.d.ts +21 -0
- package/src/bedrock-claude-cache-policy.ts +68 -0
- package/src/model-pricing.ts +11 -0
- package/src/model-thinking.ts +31 -7
- package/src/models.json +37 -0
- package/src/openai-completions-compat.d.ts +22 -0
- package/src/openai-completions-compat.ts +77 -3
- package/src/providers/amazon-bedrock.d.ts +17 -2
- package/src/providers/amazon-bedrock.ts +9 -9
- package/src/providers/anthropic.d.ts +1 -0
- package/src/providers/anthropic.ts +38 -21
- package/src/providers/cursor.ts +12 -6
- package/src/providers/openai-codex/response-handler.ts +1 -1
- package/src/providers/openai-codex-responses.ts +14 -5
- package/src/providers/openai-completions-compat.d.ts +1 -1
- package/src/providers/openai-completions-compat.ts +8 -1
- package/src/providers/openai-completions.ts +14 -1
- package/src/providers/openai-responses.ts +11 -1
- package/src/providers/opencode-go-session.d.ts +5 -0
- package/src/providers/opencode-go-session.ts +57 -0
- package/src/stream.ts +1 -0
- package/src/types.d.ts +7 -0
- package/src/types.ts +7 -0
- package/src/utils/codex-entitlement.d.ts +22 -0
- package/src/utils/codex-entitlement.ts +57 -0
- package/src/utils/discovery/antigravity.ts +2 -1
- package/src/utils/discovery/gemini.ts +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.16.4] - 2026-09-05
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Bundled `openai-codex/gpt-6-astra` from the authenticated Codex catalog so eligible ChatGPT accounts can select Astra before a live discovery refresh. The reviewed snapshot records Codex's 272K prompt budget, 128K output cap, text-and-image input, websocket preference, low-through-max reasoning efforts, freeform `apply_patch`, and published tiered OpenAI pricing.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- OpenAI Codex HTTP failures with an empty response body and empty status text now include the HTTP status in the surfaced message instead of the opaque `Request failed`, while structured provider errors retain their existing messages and classification.
|
|
14
|
+
- Direct xAI reasoning effort now requires the exact production HTTPS `api.x.ai` origin: HTTP, userinfo, query/fragment components, and explicit non-default ports fail closed. Bedrock Claude cache-pricing metadata now shares the request prompt-caching generation policy, retaining only Claude 3.5 Haiku, Claude 3.7 Sonnet, and Claude 4+ support.
|
|
15
|
+
|
|
16
|
+
- OpenCode Go requests across chat completions, Responses, and Anthropic-compatible models now send the provider-required `x-opencode-session` header at their exact canonical Go endpoints using the coding-agent's existing opaque provider session id. The provider-owned identity is typed separately from generic cache affinity, so auth-gateway prompt-derived cache keys cannot become the header. The value remains stable across turns and every retry layer in one conversation, differs with the conversation lifecycle, cannot be injected or replaced by caller/model request headers or transforms on unauthorized routes, and is never added to OpenCode Zen or unrelated compatible endpoints (#5295).
|
|
17
|
+
- Bedrock prompt caching is now gated on the Claude generation parsed from the model id instead of version-literal fragments (`-4-`/`-4.`, `claude-haiku`, and two 3.x literals). A future generation's Bedrock id (`us.anthropic.claude-opus-5-…`, or a new model kind) matched none of the literals, so cache points were silently omitted and every request re-paid full input pricing. Behavior for the documented support set — 3.5 Haiku, 3.7 Sonnet, and 4.x naming including `us.`/`eu.`/`au.`/`jp.`/`global.` inference profiles — is unchanged, per AWS's prompt-caching support matrix. A bundled-catalog tripwire now fails when a regenerated catalog introduces a Claude id shape the parser cannot read, so shape drift is loud instead of silently disabling caching.
|
|
18
|
+
|
|
19
|
+
- Direct-xAI `reasoning_effort` support is now derived from a strictly parsed canonical grok generation (4.5+) instead of the exact ids `grok-4.5`/`grok-4.6` in the compat layer and the coding-agent thinking-choice gate; a future grok release failed the id list, so `supportsReasoningEffort` stayed `false` and the user's thinking level was silently dropped from requests with no error. The generated-policy `reasoning` pin stays scoped to the two rows whose upstream metadata shipped stale — a per-row data correction, not a family rule — so catalog `reasoning: false` flags (including the bundled grok `-non-reasoning` variants) remain authoritative for everything else. Direct capability requires the official xAI origin; private and proxy OpenAI-compatible origins fail closed unless explicitly configured, while reseller routes such as OpenRouter keep their existing audited transport behavior.
|
|
20
|
+
|
|
21
|
+
- Cursor payload hooks now receive protobuf requests as JSON-safe values, await asynchronous inspection or replacement, and validate replacement payloads before transport. Checkpoint state containing 64-bit protobuf fields no longer makes hook-side `JSON.stringify` fail on JavaScript `bigint` values.
|
|
22
|
+
- The OpenAI Codex GPT-5.6 Sol entitlement preflight no longer rejects Business, Enterprise, or Team ChatGPT OAuth accounts. Eligibility was decided by `plan_type.includes("pro")`, so a `business`/`enterprise`/`team` plan (which is entitled to Sol on the backend) failed credential selection before dispatch with a spurious "cannot use model" error, even though a direct request to the ChatGPT Codex backend succeeds for those plans. A shared classifier now recognizes exact Pro/Business/Enterprise/Team tier names and known Free/Plus denials. Missing or unfamiliar plan names remain unknown and reach the provider instead of gaining entitlement through a substring match or being rejected by a client-side guess.
|
|
23
|
+
|
|
24
|
+
## [0.16.3] - 2026-09-04
|
|
25
|
+
|
|
26
|
+
## [0.16.2] - 2026-09-04
|
|
27
|
+
|
|
28
|
+
- OpenAI Codex GPT-5.6 Sol selections now reject a known non-Pro ChatGPT OAuth account before dispatch, instead of allowing a binding that fails later with the provider's raw entitlement error. The same rejection is normalized for HTTP and streaming provider responses with guidance to choose a callable model or use an API-key credential.
|
|
29
|
+
|
|
5
30
|
## [0.16.1] - 2026-09-03
|
|
6
31
|
|
|
7
32
|
### Added
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
* POST /v1/responses → OpenAI Responses in/out
|
|
19
19
|
*/
|
|
20
20
|
import type { AuthStorage } from "../auth-storage";
|
|
21
|
-
import type { Api, AssistantMessageEventStream, Model, Provider } from "../types";
|
|
22
|
-
import type { AuthGatewayServerHandle, AuthGatewayServerOptions } from "./types";
|
|
21
|
+
import type { Api, AssistantMessageEventStream, Model, Provider, SimpleStreamOptions } from "../types";
|
|
22
|
+
import type { AuthGatewayServerHandle, AuthGatewayServerOptions, AuthGatewayParsedRequest as ParsedFormatRequest } from "./types";
|
|
23
23
|
export type ModelResolver = (modelId: string) => Model<Api> | undefined;
|
|
24
24
|
export interface AuthGatewayBootOptions extends AuthGatewayServerOptions {
|
|
25
25
|
/** Source of credentials. Caller wires this to a broker-backed AuthStorage. */
|
|
@@ -66,5 +66,7 @@ export declare function isAuthGatewayModelBrokerConsumable(model: Pick<Model<Api
|
|
|
66
66
|
*/
|
|
67
67
|
export declare function createAuthGatewayModelCatalog(provider: Provider, models: Iterable<Model<Api>>): AuthGatewayModelCatalog;
|
|
68
68
|
export declare function releaseGatewayCredentialLeaseOnAdmission(events: Pick<AssistantMessageEventStream, "result">, release: () => void, signal?: AbortSignal): void;
|
|
69
|
+
/** Test seam for verifying translated gateway requests never acquire agent-owned provider identity. */
|
|
70
|
+
export declare function buildAuthGatewayStreamOptionsForTest(parsed: ParsedFormatRequest, api: Api): SimpleStreamOptions;
|
|
69
71
|
export declare function startAuthGateway(opts: AuthGatewayBootOptions): AuthGatewayServerHandle;
|
|
70
72
|
export declare function isSafeProviderScope(provider: unknown): provider is string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type BedrockClaudeGeneration = {
|
|
2
|
+
generation: {
|
|
3
|
+
major: number;
|
|
4
|
+
minor: number;
|
|
5
|
+
};
|
|
6
|
+
kind: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Bedrock Claude ids come in two shapes:
|
|
10
|
+
* - family-first (3.x era): anthropic.claude-3-5-haiku-20241022-v1:0
|
|
11
|
+
* - kind-first (4+ era): anthropic.claude-opus-4-20250514-v1:0,
|
|
12
|
+
* anthropic.claude-haiku-4-5-20251001-v1:0
|
|
13
|
+
* Cross-region profiles (us./eu./au./jp./apac./global. prefixes) and inference-profile
|
|
14
|
+
* ARNs keep the canonical model id as their final path segment.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseBedrockClaudeGeneration(id: string): BedrockClaudeGeneration | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Returns undefined for non-Claude ids, false for malformed or unsupported
|
|
19
|
+
* Claude ids, and true only for AWS's documented cache-capable generations.
|
|
20
|
+
*/
|
|
21
|
+
export declare function supportsBedrockClaudePromptCaching(id: string): boolean | undefined;
|
|
@@ -1,10 +1,32 @@
|
|
|
1
1
|
import type { Model, OpenAICompat } from "./types";
|
|
2
2
|
type ResolvedToolStrictMode = NonNullable<OpenAICompat["toolStrictMode"]> | "mixed";
|
|
3
|
+
export type GrokGeneration = {
|
|
4
|
+
major: number;
|
|
5
|
+
minor: number;
|
|
6
|
+
};
|
|
3
7
|
/** Returns whether the request endpoint is an audited reasoning-control transport. */
|
|
4
8
|
export declare function isAuditedOpenAIReasoningTransport(model: {
|
|
5
9
|
provider: string;
|
|
6
10
|
baseUrl?: string;
|
|
7
11
|
}, resolvedBaseUrl?: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* xAI's first-party API accepts `reasoning_effort` on Grok 4.5 and later.
|
|
14
|
+
* Provider labels are user-configurable, so both the provider and the official
|
|
15
|
+
* API origin must match. Unknown variants fail closed instead of inheriting a
|
|
16
|
+
* capability from a loose model-id prefix.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseDirectXaiReasoningEffortGeneration(model: {
|
|
19
|
+
provider: string;
|
|
20
|
+
id: string;
|
|
21
|
+
api?: string;
|
|
22
|
+
baseUrl?: string;
|
|
23
|
+
}, resolvedBaseUrl?: string): GrokGeneration | undefined;
|
|
24
|
+
export declare function isDirectXaiReasoningEffortModel(model: {
|
|
25
|
+
provider: string;
|
|
26
|
+
id: string;
|
|
27
|
+
api?: string;
|
|
28
|
+
baseUrl?: string;
|
|
29
|
+
}, resolvedBaseUrl?: string): boolean;
|
|
8
30
|
export type ResolvedOpenAICompat = Required<Omit<OpenAICompat, "openRouterRouting" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolChoiceSupport" | "supportsResponsesSessionAffinity" | "supportsServiceTier" | "reservedToolNames">> & {
|
|
9
31
|
openRouterRouting?: OpenAICompat["openRouterRouting"];
|
|
10
32
|
vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"];
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* No `@aws-sdk/*`, no `@smithy/*`, no `proxy-agent`. Proxies are honored via
|
|
7
7
|
* Bun's native `HTTPS_PROXY` support.
|
|
8
8
|
*/
|
|
9
|
+
import { parseBedrockClaudeGeneration } from "../bedrock-claude-cache-policy";
|
|
9
10
|
import type { Effort } from "../model-thinking";
|
|
10
|
-
import type { StreamFunction, StreamOptions, ThinkingBudgets, Tool, ToolChoice } from "../types";
|
|
11
|
+
import type { Model, StreamFunction, StreamOptions, ThinkingBudgets, Tool, ToolChoice } from "../types";
|
|
11
12
|
export type BedrockThinkingDisplay = "summarized" | "omitted";
|
|
12
13
|
export interface BedrockOptions extends StreamOptions {
|
|
13
14
|
region?: string;
|
|
@@ -51,10 +52,24 @@ interface WireToolConfig {
|
|
|
51
52
|
toolChoice?: WireToolChoice;
|
|
52
53
|
}
|
|
53
54
|
export declare const streamBedrock: StreamFunction<"bedrock-converse-stream">;
|
|
55
|
+
/**
|
|
56
|
+
* Check if the model supports prompt caching.
|
|
57
|
+
* Supported: Claude 3.5 Haiku, Claude 3.7 Sonnet, and every later Claude
|
|
58
|
+
* generation:
|
|
59
|
+
* https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html
|
|
60
|
+
*
|
|
61
|
+
* For base models and system-defined inference profiles the model ID / ARN
|
|
62
|
+
* contains the model name, so we can decide locally.
|
|
63
|
+
*
|
|
64
|
+
* For application inference profiles (whose ARNs don't contain the model name),
|
|
65
|
+
* set AWS_BEDROCK_FORCE_CACHE=1 to enable cache points. Amazon Nova models
|
|
66
|
+
* have automatic caching and don't need explicit cache points.
|
|
67
|
+
*/
|
|
68
|
+
export declare function supportsPromptCaching(model: Model<"bedrock-converse-stream">): boolean;
|
|
69
|
+
export { parseBedrockClaudeGeneration };
|
|
54
70
|
export declare function stripBedrockForcedToolChoiceForRetry<T extends {
|
|
55
71
|
toolConfig?: {
|
|
56
72
|
toolChoice?: unknown;
|
|
57
73
|
};
|
|
58
74
|
}>(body: T): T;
|
|
59
75
|
export declare function convertToolConfig(tools: Tool[] | undefined, toolChoice: BedrockOptions["toolChoice"]): WireToolConfig | undefined;
|
|
60
|
-
export {};
|
|
@@ -203,6 +203,7 @@ export type AnthropicClientOptionsArgs = {
|
|
|
203
203
|
maxRetryDelayMs?: number;
|
|
204
204
|
streamFirstEventTimeoutMs?: number;
|
|
205
205
|
streamIdleTimeoutMs?: number;
|
|
206
|
+
providerSessionId?: string;
|
|
206
207
|
};
|
|
207
208
|
export type AnthropicClientOptionsResult = {
|
|
208
209
|
isOAuthToken: boolean;
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
* the core-safe module so model metadata can use it without loading provider
|
|
4
4
|
* implementations during startup.
|
|
5
5
|
*/
|
|
6
|
-
export { detectOpenAICompat, type ResolvedOpenAICompat, resolveOpenAICompat } from "../openai-completions-compat";
|
|
6
|
+
export { detectOpenAICompat, type GrokGeneration, isDirectXaiReasoningEffortModel, parseDirectXaiReasoningEffortGeneration, type ResolvedOpenAICompat, resolveOpenAICompat, } from "../openai-completions-compat";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { FetchImpl, Model } from "../types";
|
|
2
|
+
export type OpenCodeGoApiFamily = "openai" | "anthropic";
|
|
3
|
+
export declare function resolveOpenCodeGoSessionId(model: Pick<Model, "provider">, baseUrl: string | undefined, providerSessionId: string | undefined, apiFamily: OpenCodeGoApiFamily): string | undefined;
|
|
4
|
+
export declare function applyOpenCodeGoSessionHeader(headers: Record<string, string>, sessionId: string | undefined): Record<string, string>;
|
|
5
|
+
export declare function wrapFetchForOpenCodeGoSession(baseFetch: FetchImpl, sessionId: string | undefined): FetchImpl;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -239,6 +239,13 @@ export interface StreamOptions {
|
|
|
239
239
|
* session-aware features. Ignored by providers that don't support it.
|
|
240
240
|
*/
|
|
241
241
|
sessionId?: string;
|
|
242
|
+
/**
|
|
243
|
+
* Opaque conversation identity owned by the calling agent/session lifecycle.
|
|
244
|
+
* Unlike `sessionId`, this MUST NOT be synthesized from prompts, credentials,
|
|
245
|
+
* paths, cache keys, or other request content. Providers with a dedicated
|
|
246
|
+
* conversation header may use this only when their endpoint policy permits it.
|
|
247
|
+
*/
|
|
248
|
+
providerSessionId?: string;
|
|
242
249
|
/**
|
|
243
250
|
* Provider-scoped mutable state store for this agent session.
|
|
244
251
|
* Providers can use this to persist transport/session state between turns.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model entitlement facts shared by Codex credential selection and provider
|
|
3
|
+
* error presentation.
|
|
4
|
+
*
|
|
5
|
+
* GPT-5.6 Sol is a Pro-tier ChatGPT Codex model. The usage endpoint is the
|
|
6
|
+
* authority for the account tier; this module only names the model policy and
|
|
7
|
+
* keeps the provider's deterministic rejection wording in one place.
|
|
8
|
+
*/
|
|
9
|
+
export type OpenAICodexProEntitlement = "entitled" | "denied" | "unknown";
|
|
10
|
+
/**
|
|
11
|
+
* Classify a ChatGPT `plan_type` for strict Pro-tier Codex models.
|
|
12
|
+
*
|
|
13
|
+
* The usage endpoint remains authoritative: only exact, documented tier names
|
|
14
|
+
* are classified. Known Free/Plus tiers can be rejected locally, while missing
|
|
15
|
+
* or unfamiliar values stay unknown and reach the provider instead of being
|
|
16
|
+
* guessed from a substring.
|
|
17
|
+
*/
|
|
18
|
+
export declare function classifyOpenAICodexProEntitlement(planType: string | undefined): OpenAICodexProEntitlement;
|
|
19
|
+
export declare function requiresOpenAICodexProModel(provider: string, modelId: string | undefined): boolean;
|
|
20
|
+
export declare function requiresStrictOpenAICodexProModel(provider: string, modelId: string | undefined): boolean;
|
|
21
|
+
export declare function isOpenAICodexChatGPTEntitlementError(message: string | undefined, code?: string): boolean;
|
|
22
|
+
export declare function formatOpenAICodexChatGPTEntitlementError(modelId: string | undefined): string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/ai",
|
|
4
|
-
"version": "0.16.
|
|
4
|
+
"version": "0.16.4",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://gajae-code.com",
|
|
7
7
|
"author": "Yeachan-Heo and Gajae Code Contributors",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@anthropic-ai/sdk": "^0.94.0",
|
|
42
42
|
"@bufbuild/protobuf": "^2.12.0",
|
|
43
|
-
"@gajae-code/natives": "0.16.
|
|
44
|
-
"@gajae-code/utils": "0.16.
|
|
43
|
+
"@gajae-code/natives": "0.16.4",
|
|
44
|
+
"@gajae-code/utils": "0.16.4",
|
|
45
45
|
"openai": "^6.36.0",
|
|
46
46
|
"partial-json": "^0.1.7",
|
|
47
47
|
"zod": "4.4.3"
|
|
@@ -469,6 +469,11 @@ function buildStreamOptions(parsed: ParsedFormatRequest, api: Api, signal: Abort
|
|
|
469
469
|
return opts;
|
|
470
470
|
}
|
|
471
471
|
|
|
472
|
+
/** Test seam for verifying translated gateway requests never acquire agent-owned provider identity. */
|
|
473
|
+
export function buildAuthGatewayStreamOptionsForTest(parsed: ParsedFormatRequest, api: Api): SimpleStreamOptions {
|
|
474
|
+
return buildStreamOptions(parsed, api, new AbortController().signal);
|
|
475
|
+
}
|
|
476
|
+
|
|
472
477
|
/**
|
|
473
478
|
* Classify an upstream / gateway-internal error into a status code and a
|
|
474
479
|
* provider-style error type tag. Used by `handleFormatEndpoint` /
|
package/src/auth-storage.ts
CHANGED
|
@@ -26,6 +26,12 @@ import type {
|
|
|
26
26
|
UsageReport,
|
|
27
27
|
} from "./usage";
|
|
28
28
|
|
|
29
|
+
import {
|
|
30
|
+
classifyOpenAICodexProEntitlement,
|
|
31
|
+
formatOpenAICodexChatGPTEntitlementError,
|
|
32
|
+
requiresOpenAICodexProModel,
|
|
33
|
+
requiresStrictOpenAICodexProModel,
|
|
34
|
+
} from "./utils/codex-entitlement";
|
|
29
35
|
import { getOAuthApiKey, getOAuthProvider, refreshOAuthToken, resolveOAuthStorageProvider } from "./utils/oauth";
|
|
30
36
|
import { loginDeepInfra } from "./utils/oauth/deepinfra";
|
|
31
37
|
import { loginDeepSeek } from "./utils/oauth/deepseek";
|
|
@@ -1140,10 +1146,6 @@ export function readBrokerErrorBody(error: unknown): string | undefined {
|
|
|
1140
1146
|
}
|
|
1141
1147
|
}
|
|
1142
1148
|
|
|
1143
|
-
function requiresOpenAICodexProModel(provider: string, modelId: string | undefined): boolean {
|
|
1144
|
-
return provider === "openai-codex" && typeof modelId === "string" && modelId.includes("-spark");
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
1149
|
function getUsagePlanType(report: UsageReport | null): string | undefined {
|
|
1148
1150
|
const metadata = report?.metadata;
|
|
1149
1151
|
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) return undefined;
|
|
@@ -1152,13 +1154,18 @@ function getUsagePlanType(report: UsageReport | null): string | undefined {
|
|
|
1152
1154
|
}
|
|
1153
1155
|
|
|
1154
1156
|
function getOpenAICodexPlanPriority(report: UsageReport | null): number {
|
|
1155
|
-
const
|
|
1156
|
-
if (
|
|
1157
|
-
|
|
1157
|
+
const entitlement = classifyOpenAICodexProEntitlement(getUsagePlanType(report));
|
|
1158
|
+
if (entitlement === "entitled") return 0;
|
|
1159
|
+
if (entitlement === "denied") return 2;
|
|
1160
|
+
return 1;
|
|
1158
1161
|
}
|
|
1159
1162
|
|
|
1160
1163
|
function hasOpenAICodexProPlan(report: UsageReport | null): boolean {
|
|
1161
|
-
return getUsagePlanType(report)
|
|
1164
|
+
return classifyOpenAICodexProEntitlement(getUsagePlanType(report)) === "entitled";
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
function hasKnownOpenAICodexNonProPlan(report: UsageReport | null): boolean {
|
|
1168
|
+
return classifyOpenAICodexProEntitlement(getUsagePlanType(report)) === "denied";
|
|
1162
1169
|
}
|
|
1163
1170
|
|
|
1164
1171
|
function resolveDefaultRankingStrategy(provider: Provider): CredentialRankingStrategy | undefined {
|
|
@@ -1620,6 +1627,7 @@ export class AuthStorage {
|
|
|
1620
1627
|
*/
|
|
1621
1628
|
setRuntimeApiKey(provider: string, apiKey: string): void {
|
|
1622
1629
|
const storageProvider = resolveOAuthStorageProvider(provider);
|
|
1630
|
+
if (this.#runtimeOverrides.get(storageProvider) === apiKey) return;
|
|
1623
1631
|
this.#runtimeOverrides.set(storageProvider, apiKey);
|
|
1624
1632
|
this.#bumpGeneration("set-runtime-api-key", storageProvider);
|
|
1625
1633
|
}
|
|
@@ -1936,6 +1944,8 @@ export class AuthStorage {
|
|
|
1936
1944
|
throw new Error(`Preferred credential selector cannot be combined with a credential selector for ${provider}`);
|
|
1937
1945
|
}
|
|
1938
1946
|
this.#assertPreferredCredentialSelectorUsable(storageProvider, selector);
|
|
1947
|
+
const existing = this.#runtimePreferredCredentialSelectors.get(storageProvider);
|
|
1948
|
+
if (existing?.kind === selector.kind && existing.value === selector.value) return;
|
|
1939
1949
|
this.#runtimePreferredCredentialSelectors.set(storageProvider, selector);
|
|
1940
1950
|
this.#bumpGeneration("set-runtime-preferred-credential-selector", provider);
|
|
1941
1951
|
}
|
|
@@ -4955,6 +4965,19 @@ export class AuthStorage {
|
|
|
4955
4965
|
// non-Pro accounts can still attempt Spark requests (e.g. trial/grandfathered access).
|
|
4956
4966
|
const enforceProRequirement =
|
|
4957
4967
|
requiresProModel && candidates.some(candidate => hasOpenAICodexProPlan(candidate.usage));
|
|
4968
|
+
// Spark retains its historical Plus fallback for grandfathered accounts.
|
|
4969
|
+
// Sol is different: confirmed Free/Plus plans cannot call it, so reject the
|
|
4970
|
+
// model before returning an OAuth bearer and letting the turn fail remotely.
|
|
4971
|
+
// Unknown plan names still reach the provider because the usage endpoint is
|
|
4972
|
+
// authoritative and future tiers must not be denied by a client-side guess.
|
|
4973
|
+
const strictProRequirement = requiresStrictOpenAICodexProModel(provider, options?.modelId);
|
|
4974
|
+
if (
|
|
4975
|
+
strictProRequirement &&
|
|
4976
|
+
candidates.length > 0 &&
|
|
4977
|
+
candidates.every(candidate => hasKnownOpenAICodexNonProPlan(candidate.usage))
|
|
4978
|
+
) {
|
|
4979
|
+
throw new Error(formatOpenAICodexChatGPTEntitlementError(options?.modelId));
|
|
4980
|
+
}
|
|
4958
4981
|
|
|
4959
4982
|
const fallback = candidates[0];
|
|
4960
4983
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type BedrockClaudeGeneration = {
|
|
2
|
+
generation: {
|
|
3
|
+
major: number;
|
|
4
|
+
minor: number;
|
|
5
|
+
};
|
|
6
|
+
kind: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Bedrock Claude ids come in two shapes:
|
|
10
|
+
* - family-first (3.x era): anthropic.claude-3-5-haiku-20241022-v1:0
|
|
11
|
+
* - kind-first (4+ era): anthropic.claude-opus-4-20250514-v1:0,
|
|
12
|
+
* anthropic.claude-haiku-4-5-20251001-v1:0
|
|
13
|
+
* Cross-region profiles (us./eu./au./jp./apac./global. prefixes) and inference-profile
|
|
14
|
+
* ARNs keep the canonical model id as their final path segment.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseBedrockClaudeGeneration(id: string): BedrockClaudeGeneration | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Returns undefined for non-Claude ids, false for malformed or unsupported
|
|
19
|
+
* Claude ids, and true only for AWS's documented cache-capable generations.
|
|
20
|
+
*/
|
|
21
|
+
export declare function supportsBedrockClaudePromptCaching(id: string): boolean | undefined;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export type BedrockClaudeGeneration = {
|
|
2
|
+
generation: { major: number; minor: number };
|
|
3
|
+
kind: string;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
function extractBedrockModelId(id: string): string | undefined {
|
|
7
|
+
if (id !== id.toLowerCase()) return undefined;
|
|
8
|
+
if (id.startsWith("arn:")) {
|
|
9
|
+
const arn =
|
|
10
|
+
/^arn:(?:aws|aws-us-gov|aws-cn|aws-iso|aws-iso-b|aws-eusc):bedrock:[a-z0-9-]+:(?:\d{12})?:(?:foundation-model|inference-profile)\/([^/]+)$/.exec(
|
|
11
|
+
id,
|
|
12
|
+
);
|
|
13
|
+
return arn?.[1];
|
|
14
|
+
}
|
|
15
|
+
return id.includes("/") ? undefined : id;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Bedrock Claude ids come in two shapes:
|
|
20
|
+
* - family-first (3.x era): anthropic.claude-3-5-haiku-20241022-v1:0
|
|
21
|
+
* - kind-first (4+ era): anthropic.claude-opus-4-20250514-v1:0,
|
|
22
|
+
* anthropic.claude-haiku-4-5-20251001-v1:0
|
|
23
|
+
* Cross-region profiles (us./eu./au./jp./apac./global. prefixes) and inference-profile
|
|
24
|
+
* ARNs keep the canonical model id as their final path segment.
|
|
25
|
+
*/
|
|
26
|
+
export function parseBedrockClaudeGeneration(id: string): BedrockClaudeGeneration | undefined {
|
|
27
|
+
const modelId = extractBedrockModelId(id);
|
|
28
|
+
if (modelId === undefined) return undefined;
|
|
29
|
+
const prefix = "(?:(?:us|eu|au|jp|apac|global)\\.)?anthropic\\.claude-";
|
|
30
|
+
const component = "(?:0|[1-9]\\d?)";
|
|
31
|
+
const suffix = "(?:-(?:[a-z][a-z0-9]*(?::[a-z0-9]+)?|\\d{8}))*";
|
|
32
|
+
const familyFirst = new RegExp(`^${prefix}([1-9]\\d?)(?:-(${component}))?-([a-z][a-z0-9]*)${suffix}$`).exec(modelId);
|
|
33
|
+
if (familyFirst) {
|
|
34
|
+
return {
|
|
35
|
+
generation: {
|
|
36
|
+
major: Number(familyFirst[1]),
|
|
37
|
+
minor: familyFirst[2] === undefined ? 0 : Number(familyFirst[2]),
|
|
38
|
+
},
|
|
39
|
+
kind: familyFirst[3]!,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const kindFirst = new RegExp(`^${prefix}([a-z][a-z0-9]*)-([1-9]\\d?)(?:[.-](${component}))?${suffix}$`).exec(
|
|
43
|
+
modelId,
|
|
44
|
+
);
|
|
45
|
+
if (kindFirst) {
|
|
46
|
+
return {
|
|
47
|
+
generation: { major: Number(kindFirst[2]), minor: kindFirst[3] === undefined ? 0 : Number(kindFirst[3]) },
|
|
48
|
+
kind: kindFirst[1]!,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns undefined for non-Claude ids, false for malformed or unsupported
|
|
56
|
+
* Claude ids, and true only for AWS's documented cache-capable generations.
|
|
57
|
+
*/
|
|
58
|
+
export function supportsBedrockClaudePromptCaching(id: string): boolean | undefined {
|
|
59
|
+
if (!id.toLowerCase().includes("anthropic.claude")) return undefined;
|
|
60
|
+
const claude = parseBedrockClaudeGeneration(id);
|
|
61
|
+
if (claude === undefined) return false;
|
|
62
|
+
if (claude.generation.major >= 4) return true;
|
|
63
|
+
if (claude.generation.major !== 3) return false;
|
|
64
|
+
return (
|
|
65
|
+
(claude.generation.minor === 5 && claude.kind === "haiku") ||
|
|
66
|
+
(claude.generation.minor === 7 && claude.kind === "sonnet")
|
|
67
|
+
);
|
|
68
|
+
}
|
package/src/model-pricing.ts
CHANGED
|
@@ -15,8 +15,19 @@ const GPT_5_6_SOL_PRICING: TieredPricing = {
|
|
|
15
15
|
},
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
// GPT-6 Astra: $10/$50 standard, cache read $1, cache write $12.50; inputs past
|
|
19
|
+
// 272K apply 2x to input/cache and 1.5x to output.
|
|
20
|
+
const GPT_6_ASTRA_PRICING: TieredPricing = {
|
|
21
|
+
cost: { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 },
|
|
22
|
+
longContextPricing: {
|
|
23
|
+
threshold: LONG_CONTEXT_THRESHOLD,
|
|
24
|
+
cost: { input: 20, output: 75, cacheRead: 2, cacheWrite: 25 },
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
18
28
|
// OpenAI Standard pricing: https://developers.openai.com/api/docs/pricing
|
|
19
29
|
const OPENAI_GPT_5_6_PRICING: ReadonlyMap<string, TieredPricing> = new Map([
|
|
30
|
+
["gpt-6-astra", GPT_6_ASTRA_PRICING],
|
|
20
31
|
["gpt-5.6", GPT_5_6_SOL_PRICING],
|
|
21
32
|
["gpt-5.6-sol", GPT_5_6_SOL_PRICING],
|
|
22
33
|
[
|
package/src/model-thinking.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { supportsBedrockClaudePromptCaching } from "./bedrock-claude-cache-policy";
|
|
1
2
|
import {
|
|
2
3
|
CODEX_GENERIC_CONTEXT_WINDOW,
|
|
3
4
|
CODEX_GPT_5_6_CONTEXT_CAP,
|
|
@@ -5,7 +6,11 @@ import {
|
|
|
5
6
|
isCodexProductTransport,
|
|
6
7
|
} from "./context-cap-policy";
|
|
7
8
|
import { applyOpenAIModelPricing } from "./model-pricing";
|
|
8
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
isAuditedOpenAIReasoningTransport,
|
|
11
|
+
parseDirectXaiReasoningEffortGeneration,
|
|
12
|
+
resolveOpenAICompat,
|
|
13
|
+
} from "./openai-completions-compat";
|
|
9
14
|
import type { Api, Model as ApiModel, ThinkingConfig } from "./types";
|
|
10
15
|
import { isClaudeForcedToolChoiceIncapableModelId } from "./utils/tool-choice-capability";
|
|
11
16
|
|
|
@@ -63,6 +68,12 @@ const KIMI_K3_EFFORTS: readonly Effort[] = [Effort.Low, Effort.High, Effort.Max]
|
|
|
63
68
|
const DEEPSEEK_V4_FLASH_0731_EFFORTS: readonly Effort[] = [Effort.Low, Effort.High, Effort.Max];
|
|
64
69
|
const GROK_4_5_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High];
|
|
65
70
|
const GROK_4_6_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High, Effort.XHigh];
|
|
71
|
+
const GROK_4_20_EFFORTS: readonly Effort[] = [Effort.Minimal, Effort.Low, Effort.Medium, Effort.High];
|
|
72
|
+
const GROK_4_20_REASONING_MODEL_IDS = new Set([
|
|
73
|
+
"grok-4.20-0309-reasoning",
|
|
74
|
+
"grok-4.20-beta-latest-reasoning",
|
|
75
|
+
"grok-4.20-multi-agent-beta-latest",
|
|
76
|
+
]);
|
|
66
77
|
|
|
67
78
|
const GPT_5_1_CODEX_MINI_EFFORTS: readonly Effort[] = [Effort.Medium, Effort.High];
|
|
68
79
|
const CLOUDFLARE_AI_GATEWAY_BASE_URL = "https://gateway.ai.cloudflare.com/v1/<account>/<gateway>/anthropic";
|
|
@@ -76,6 +87,7 @@ type SemVer = {
|
|
|
76
87
|
type GeminiKind = "pro" | "flash";
|
|
77
88
|
type AnthropicKind = "opus" | "sonnet" | "fable";
|
|
78
89
|
type OpenAIVariant =
|
|
90
|
+
| "astra"
|
|
79
91
|
| "base"
|
|
80
92
|
| "codex"
|
|
81
93
|
| "codex-max"
|
|
@@ -539,6 +551,13 @@ function applyGeneratedModelPolicy(model: ApiModel<Api>): void {
|
|
|
539
551
|
if (parsedModel.family === "openai") {
|
|
540
552
|
applyOpenAICatalogPolicy(model, parsedModel);
|
|
541
553
|
}
|
|
554
|
+
if (model.provider === "amazon-bedrock" && model.api === "bedrock-converse-stream") {
|
|
555
|
+
const cacheSupport = supportsBedrockClaudePromptCaching(model.id);
|
|
556
|
+
if (cacheSupport === false) {
|
|
557
|
+
model.cost.cacheRead = 0;
|
|
558
|
+
model.cost.cacheWrite = 0;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
542
561
|
// GLM-5.2 (Zhipu/ZAI): ships a 1M lossless context window, but the bundled
|
|
543
562
|
// catalog copied GLM-5.1's 200K and that stale value survives generate-models
|
|
544
563
|
// (provider-scoped models bypass the models.dev refresh in applyGlobalModelsDevFallback).
|
|
@@ -655,7 +674,10 @@ function inferGeneratedApplyPatchToolType(
|
|
|
655
674
|
model: ApiModel<Api>,
|
|
656
675
|
parsedModel: ParsedModel,
|
|
657
676
|
): ApiModel<Api>["applyPatchToolType"] {
|
|
658
|
-
if (
|
|
677
|
+
if (
|
|
678
|
+
parsedModel.family !== "openai" ||
|
|
679
|
+
(parsedModel.version.major !== 5 && !(parsedModel.version.major === 6 && parsedModel.variant === "astra"))
|
|
680
|
+
) {
|
|
659
681
|
return undefined;
|
|
660
682
|
}
|
|
661
683
|
if (model.provider === "openai" && model.api === "openai-responses") {
|
|
@@ -808,12 +830,14 @@ function expandEffortRange(thinking: ThinkingConfig): readonly Effort[] {
|
|
|
808
830
|
}
|
|
809
831
|
|
|
810
832
|
function inferSupportedEfforts<TApi extends Api>(parsedModel: ParsedModel, model: ApiModel<TApi>): readonly Effort[] {
|
|
811
|
-
|
|
833
|
+
const grokGeneration = parseDirectXaiReasoningEffortGeneration(model);
|
|
834
|
+
if (grokGeneration !== undefined) {
|
|
835
|
+
if (grokGeneration.major === 4 && grokGeneration.minor === 6) return GROK_4_6_EFFORTS;
|
|
836
|
+
if (GROK_4_20_REASONING_MODEL_IDS.has(model.id)) {
|
|
837
|
+
return GROK_4_20_EFFORTS;
|
|
838
|
+
}
|
|
812
839
|
return GROK_4_5_EFFORTS;
|
|
813
840
|
}
|
|
814
|
-
if (model.provider === "xai" && model.id === "grok-4.6") {
|
|
815
|
-
return GROK_4_6_EFFORTS;
|
|
816
|
-
}
|
|
817
841
|
if (model.provider === "kimi-code" && model.id === "k3") {
|
|
818
842
|
return KIMI_K3_EFFORTS;
|
|
819
843
|
}
|
|
@@ -1002,7 +1026,7 @@ function parseAnthropicModel(modelId: string): AnthropicModel | null {
|
|
|
1002
1026
|
|
|
1003
1027
|
function parseOpenAIModel(modelId: string): OpenAIModel | null {
|
|
1004
1028
|
const match =
|
|
1005
|
-
/gpt-(\d+(?:\.\d+){0,2})(?:-(codex-spark|codex-mini|codex-max|codex|luna|mini|max|nano|sol|terra))?$/.exec(
|
|
1029
|
+
/gpt-(\d+(?:\.\d+){0,2})(?:-(astra|codex-spark|codex-mini|codex-max|codex|luna|mini|max|nano|sol|terra))?$/.exec(
|
|
1006
1030
|
modelId,
|
|
1007
1031
|
);
|
|
1008
1032
|
if (!match) {
|
package/src/models.json
CHANGED
|
@@ -65461,6 +65461,43 @@
|
|
|
65461
65461
|
},
|
|
65462
65462
|
"applyPatchToolType": "freeform"
|
|
65463
65463
|
},
|
|
65464
|
+
"gpt-6-astra": {
|
|
65465
|
+
"id": "gpt-6-astra",
|
|
65466
|
+
"name": "GPT-6-Astra",
|
|
65467
|
+
"api": "openai-codex-responses",
|
|
65468
|
+
"provider": "openai-codex",
|
|
65469
|
+
"baseUrl": "https://chatgpt.com/backend-api",
|
|
65470
|
+
"reasoning": true,
|
|
65471
|
+
"input": [
|
|
65472
|
+
"text",
|
|
65473
|
+
"image"
|
|
65474
|
+
],
|
|
65475
|
+
"cost": {
|
|
65476
|
+
"input": 10,
|
|
65477
|
+
"output": 50,
|
|
65478
|
+
"cacheRead": 1,
|
|
65479
|
+
"cacheWrite": 12.5
|
|
65480
|
+
},
|
|
65481
|
+
"contextWindow": 272000,
|
|
65482
|
+
"maxTokens": 128000,
|
|
65483
|
+
"preferWebsockets": true,
|
|
65484
|
+
"priority": 1,
|
|
65485
|
+
"thinking": {
|
|
65486
|
+
"mode": "effort",
|
|
65487
|
+
"minLevel": "low",
|
|
65488
|
+
"maxLevel": "max"
|
|
65489
|
+
},
|
|
65490
|
+
"longContextPricing": {
|
|
65491
|
+
"threshold": 272000,
|
|
65492
|
+
"cost": {
|
|
65493
|
+
"input": 20,
|
|
65494
|
+
"output": 75,
|
|
65495
|
+
"cacheRead": 2,
|
|
65496
|
+
"cacheWrite": 25
|
|
65497
|
+
}
|
|
65498
|
+
},
|
|
65499
|
+
"applyPatchToolType": "freeform"
|
|
65500
|
+
},
|
|
65464
65501
|
"gpt-daybreak-blue-latest": {
|
|
65465
65502
|
"id": "gpt-daybreak-blue-latest",
|
|
65466
65503
|
"name": "Daybreak Blue",
|
|
@@ -1,10 +1,32 @@
|
|
|
1
1
|
import type { Model, OpenAICompat } from "./types";
|
|
2
2
|
type ResolvedToolStrictMode = NonNullable<OpenAICompat["toolStrictMode"]> | "mixed";
|
|
3
|
+
export type GrokGeneration = {
|
|
4
|
+
major: number;
|
|
5
|
+
minor: number;
|
|
6
|
+
};
|
|
3
7
|
/** Returns whether the request endpoint is an audited reasoning-control transport. */
|
|
4
8
|
export declare function isAuditedOpenAIReasoningTransport(model: {
|
|
5
9
|
provider: string;
|
|
6
10
|
baseUrl?: string;
|
|
7
11
|
}, resolvedBaseUrl?: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* xAI's first-party API accepts `reasoning_effort` on Grok 4.5 and later.
|
|
14
|
+
* Provider labels are user-configurable, so both the provider and the official
|
|
15
|
+
* API origin must match. Unknown variants fail closed instead of inheriting a
|
|
16
|
+
* capability from a loose model-id prefix.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseDirectXaiReasoningEffortGeneration(model: {
|
|
19
|
+
provider: string;
|
|
20
|
+
id: string;
|
|
21
|
+
api?: string;
|
|
22
|
+
baseUrl?: string;
|
|
23
|
+
}, resolvedBaseUrl?: string): GrokGeneration | undefined;
|
|
24
|
+
export declare function isDirectXaiReasoningEffortModel(model: {
|
|
25
|
+
provider: string;
|
|
26
|
+
id: string;
|
|
27
|
+
api?: string;
|
|
28
|
+
baseUrl?: string;
|
|
29
|
+
}, resolvedBaseUrl?: string): boolean;
|
|
8
30
|
export type ResolvedOpenAICompat = Required<Omit<OpenAICompat, "openRouterRouting" | "vercelGatewayRouting" | "extraBody" | "toolStrictMode" | "toolChoiceSupport" | "supportsResponsesSessionAffinity" | "supportsServiceTier" | "reservedToolNames">> & {
|
|
9
31
|
openRouterRouting?: OpenAICompat["openRouterRouting"];
|
|
10
32
|
vercelGatewayRouting?: OpenAICompat["vercelGatewayRouting"];
|