@kenkaiiii/gg-ai 5.81.0 → 5.83.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/dist/index.d.cts CHANGED
@@ -223,6 +223,10 @@ interface StreamOptions {
223
223
  promptCacheKey?: string;
224
224
  /** OpenAI service tier for latency-sensitive requests. Only sent to first-party OpenAI API calls. */
225
225
  serviceTier?: "auto" | "default" | "flex" | "priority";
226
+ /** Provider speed tier. "fast" sends Anthropic `speed: "fast"` (first-party API
227
+ * only) or OpenAI/Codex `service_tier: "priority"`. Set automatically by
228
+ * `stream()` for fast-mode model ids (see `resolveFastModeModel`). */
229
+ speed?: "standard" | "fast";
226
230
  /** Codex endpoint only: send the Responses-Lite request shape (lite header,
227
231
  * `parallel_tool_calls: false`, all-turns reasoning context). Unset follows
228
232
  * the model family (on for gpt-5.6/gpt-6 models). Lite allows only one tool
@@ -430,7 +434,43 @@ declare function localWireModelId(id: string): string;
430
434
  * const response = await stream({ provider: "openai", model: "gpt-4.1", messages });
431
435
  * ```
432
436
  */
433
- declare function stream(options: StreamOptions): StreamResult;
437
+ declare function stream(requested: StreamOptions): StreamResult;
438
+
439
+ /**
440
+ * Fast-mode model ids: `<base model id>` + this suffix selects the same model
441
+ * at its provider's faster speed tier. The suffixed id is a registry/UI concept
442
+ * only — `stream()` rewrites it to the base id plus `speed: "fast"` before any
443
+ * provider sees it, so every model-id check downstream still matches.
444
+ */
445
+ declare const FAST_MODE_SUFFIX = "-fast";
446
+ interface FastModeResolution {
447
+ /** The real model id to send on the wire. */
448
+ model: string;
449
+ /** True when the id selected a fast speed tier. */
450
+ fast: boolean;
451
+ }
452
+ /**
453
+ * Split a fast-mode model id into its base model. Ids without the suffix, or
454
+ * whose base doesn't support fast mode for `provider`, pass through unchanged.
455
+ */
456
+ declare function resolveFastModeModel(provider: Provider, model: string): FastModeResolution;
457
+ interface FastModeRejection {
458
+ /** Anthropic's reason code (`unknown` when it sent none). */
459
+ reason: string;
460
+ /** Short, factual headline for the error card. */
461
+ headline: string;
462
+ /** What the user can do about it. */
463
+ guidance: string;
464
+ /** "billing": credits ran out or hit a cap. "access": credits are off or not offered. */
465
+ kind: "billing" | "access";
466
+ }
467
+ /** Describe a fast-mode rejection reason in user terms. */
468
+ declare function describeFastModeRejection(reason: string | undefined): FastModeRejection;
469
+ /**
470
+ * Recover the rejection from an error message: gg-ai's canonical message, or
471
+ * Anthropic's raw fast-mode wording (when it reaches a caller unnormalized).
472
+ */
473
+ declare function parseFastModeRejection(message: string): FastModeRejection | undefined;
434
474
 
435
475
  /** What the embedded text will be used for. See `EmbedOptions.inputType`. */
436
476
  type EmbedInputType = "query" | "document";
@@ -1031,4 +1071,4 @@ declare function palsuEmbedding(text: string, dimensions?: number): number[];
1031
1071
  /** Deterministic fake relevance: the share of distinct query words found in the document (0–1). */
1032
1072
  declare function palsuRerankScore(query: string, document: string): number;
1033
1073
 
1034
- export { type AssistantMessage, type CacheRetention, type ChatErrorReason, type ContentPart, type DoneEvent, type EmbedInputType, type EmbedOptions, type EmbedResult, type EmbedUsage, type ErrorEvent, type ErrorSource, EventStream, type FormattedChatError, type FormattedError, GGAIError, type ImageContent, type Message, type MessageProvenance, type MessageProvenanceKind, type MessageProvenanceSource, type MessageProvenanceVisibility, type OpenRouterProviderPreferences, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type PreparedContext, type Provider, type ProviderCapability, type ProviderDiagnosticFn, type ProviderEmbedFn, type ProviderEmbedRequest, type ProviderEmbedResponse, type ProviderEntry, ProviderError, type ProviderOptions, type ProviderRerankFn, type ProviderRerankRequest, type ProviderRerankResponse, type ProviderStreamFn, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, type RerankOptions, type RerankResponse, type RerankResult, type RerankUsage, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, TOOL_CALL_NAME_RULES, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolCallNameRule, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, clampProviderContextImages, classifyProviderError, continuesTurn, dropInvalidToolCalls, embed, environmentSecrets, formatChatError, formatError, formatErrorForDisplay, hasLoneSurrogate, isHardBillingMessage, isUsageLimitError, isValidToolCallName, localWireModelId, opensTurn, palsuAssistantMessage, palsuEmbedding, palsuRerankScore, palsuText, palsuThinking, palsuToolCall, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, rerank, resolveToolSchema, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText, toolCallNameRuleFor, usesResponsesLite };
1074
+ export { type AssistantMessage, type CacheRetention, type ChatErrorReason, type ContentPart, type DoneEvent, type EmbedInputType, type EmbedOptions, type EmbedResult, type EmbedUsage, type ErrorEvent, type ErrorSource, EventStream, FAST_MODE_SUFFIX, type FastModeRejection, type FastModeResolution, type FormattedChatError, type FormattedError, GGAIError, type ImageContent, type Message, type MessageProvenance, type MessageProvenanceKind, type MessageProvenanceSource, type MessageProvenanceVisibility, type OpenRouterProviderPreferences, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type PreparedContext, type Provider, type ProviderCapability, type ProviderDiagnosticFn, type ProviderEmbedFn, type ProviderEmbedRequest, type ProviderEmbedResponse, type ProviderEntry, ProviderError, type ProviderOptions, type ProviderRerankFn, type ProviderRerankRequest, type ProviderRerankResponse, type ProviderStreamFn, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, type RerankOptions, type RerankResponse, type RerankResult, type RerankUsage, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, TOOL_CALL_NAME_RULES, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolCallNameRule, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, clampProviderContextImages, classifyProviderError, continuesTurn, describeFastModeRejection, dropInvalidToolCalls, embed, environmentSecrets, formatChatError, formatError, formatErrorForDisplay, hasLoneSurrogate, isHardBillingMessage, isUsageLimitError, isValidToolCallName, localWireModelId, opensTurn, palsuAssistantMessage, palsuEmbedding, palsuRerankScore, palsuText, palsuThinking, palsuToolCall, parseFastModeRejection, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, rerank, resolveFastModeModel, resolveToolSchema, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText, toolCallNameRuleFor, usesResponsesLite };
package/dist/index.d.ts CHANGED
@@ -223,6 +223,10 @@ interface StreamOptions {
223
223
  promptCacheKey?: string;
224
224
  /** OpenAI service tier for latency-sensitive requests. Only sent to first-party OpenAI API calls. */
225
225
  serviceTier?: "auto" | "default" | "flex" | "priority";
226
+ /** Provider speed tier. "fast" sends Anthropic `speed: "fast"` (first-party API
227
+ * only) or OpenAI/Codex `service_tier: "priority"`. Set automatically by
228
+ * `stream()` for fast-mode model ids (see `resolveFastModeModel`). */
229
+ speed?: "standard" | "fast";
226
230
  /** Codex endpoint only: send the Responses-Lite request shape (lite header,
227
231
  * `parallel_tool_calls: false`, all-turns reasoning context). Unset follows
228
232
  * the model family (on for gpt-5.6/gpt-6 models). Lite allows only one tool
@@ -430,7 +434,43 @@ declare function localWireModelId(id: string): string;
430
434
  * const response = await stream({ provider: "openai", model: "gpt-4.1", messages });
431
435
  * ```
432
436
  */
433
- declare function stream(options: StreamOptions): StreamResult;
437
+ declare function stream(requested: StreamOptions): StreamResult;
438
+
439
+ /**
440
+ * Fast-mode model ids: `<base model id>` + this suffix selects the same model
441
+ * at its provider's faster speed tier. The suffixed id is a registry/UI concept
442
+ * only — `stream()` rewrites it to the base id plus `speed: "fast"` before any
443
+ * provider sees it, so every model-id check downstream still matches.
444
+ */
445
+ declare const FAST_MODE_SUFFIX = "-fast";
446
+ interface FastModeResolution {
447
+ /** The real model id to send on the wire. */
448
+ model: string;
449
+ /** True when the id selected a fast speed tier. */
450
+ fast: boolean;
451
+ }
452
+ /**
453
+ * Split a fast-mode model id into its base model. Ids without the suffix, or
454
+ * whose base doesn't support fast mode for `provider`, pass through unchanged.
455
+ */
456
+ declare function resolveFastModeModel(provider: Provider, model: string): FastModeResolution;
457
+ interface FastModeRejection {
458
+ /** Anthropic's reason code (`unknown` when it sent none). */
459
+ reason: string;
460
+ /** Short, factual headline for the error card. */
461
+ headline: string;
462
+ /** What the user can do about it. */
463
+ guidance: string;
464
+ /** "billing": credits ran out or hit a cap. "access": credits are off or not offered. */
465
+ kind: "billing" | "access";
466
+ }
467
+ /** Describe a fast-mode rejection reason in user terms. */
468
+ declare function describeFastModeRejection(reason: string | undefined): FastModeRejection;
469
+ /**
470
+ * Recover the rejection from an error message: gg-ai's canonical message, or
471
+ * Anthropic's raw fast-mode wording (when it reaches a caller unnormalized).
472
+ */
473
+ declare function parseFastModeRejection(message: string): FastModeRejection | undefined;
434
474
 
435
475
  /** What the embedded text will be used for. See `EmbedOptions.inputType`. */
436
476
  type EmbedInputType = "query" | "document";
@@ -1031,4 +1071,4 @@ declare function palsuEmbedding(text: string, dimensions?: number): number[];
1031
1071
  /** Deterministic fake relevance: the share of distinct query words found in the document (0–1). */
1032
1072
  declare function palsuRerankScore(query: string, document: string): number;
1033
1073
 
1034
- export { type AssistantMessage, type CacheRetention, type ChatErrorReason, type ContentPart, type DoneEvent, type EmbedInputType, type EmbedOptions, type EmbedResult, type EmbedUsage, type ErrorEvent, type ErrorSource, EventStream, type FormattedChatError, type FormattedError, GGAIError, type ImageContent, type Message, type MessageProvenance, type MessageProvenanceKind, type MessageProvenanceSource, type MessageProvenanceVisibility, type OpenRouterProviderPreferences, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type PreparedContext, type Provider, type ProviderCapability, type ProviderDiagnosticFn, type ProviderEmbedFn, type ProviderEmbedRequest, type ProviderEmbedResponse, type ProviderEntry, ProviderError, type ProviderOptions, type ProviderRerankFn, type ProviderRerankRequest, type ProviderRerankResponse, type ProviderStreamFn, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, type RerankOptions, type RerankResponse, type RerankResult, type RerankUsage, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, TOOL_CALL_NAME_RULES, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolCallNameRule, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, clampProviderContextImages, classifyProviderError, continuesTurn, dropInvalidToolCalls, embed, environmentSecrets, formatChatError, formatError, formatErrorForDisplay, hasLoneSurrogate, isHardBillingMessage, isUsageLimitError, isValidToolCallName, localWireModelId, opensTurn, palsuAssistantMessage, palsuEmbedding, palsuRerankScore, palsuText, palsuThinking, palsuToolCall, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, rerank, resolveToolSchema, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText, toolCallNameRuleFor, usesResponsesLite };
1074
+ export { type AssistantMessage, type CacheRetention, type ChatErrorReason, type ContentPart, type DoneEvent, type EmbedInputType, type EmbedOptions, type EmbedResult, type EmbedUsage, type ErrorEvent, type ErrorSource, EventStream, FAST_MODE_SUFFIX, type FastModeRejection, type FastModeResolution, type FormattedChatError, type FormattedError, GGAIError, type ImageContent, type Message, type MessageProvenance, type MessageProvenanceKind, type MessageProvenanceSource, type MessageProvenanceVisibility, type OpenRouterProviderPreferences, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type PreparedContext, type Provider, type ProviderCapability, type ProviderDiagnosticFn, type ProviderEmbedFn, type ProviderEmbedRequest, type ProviderEmbedResponse, type ProviderEntry, ProviderError, type ProviderOptions, type ProviderRerankFn, type ProviderRerankRequest, type ProviderRerankResponse, type ProviderStreamFn, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, type RerankOptions, type RerankResponse, type RerankResult, type RerankUsage, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, TOOL_CALL_NAME_RULES, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolCallNameRule, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, clampProviderContextImages, classifyProviderError, continuesTurn, describeFastModeRejection, dropInvalidToolCalls, embed, environmentSecrets, formatChatError, formatError, formatErrorForDisplay, hasLoneSurrogate, isHardBillingMessage, isUsageLimitError, isValidToolCallName, localWireModelId, opensTurn, palsuAssistantMessage, palsuEmbedding, palsuRerankScore, palsuText, palsuThinking, palsuToolCall, parseFastModeRejection, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, rerank, resolveFastModeModel, resolveToolSchema, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText, toolCallNameRuleFor, usesResponsesLite };
package/dist/index.js CHANGED
@@ -1,3 +1,93 @@
1
+ // src/fast-mode.ts
2
+ var FAST_MODE_SUFFIX = "-fast";
3
+ var FAST_MODE_BASE_MODELS = {
4
+ anthropic: ["claude-opus-5-5"],
5
+ openai: ["gpt-6-astra", "gpt-6.1-sol", "gpt-6-luna"]
6
+ };
7
+ function resolveFastModeModel(provider, model) {
8
+ if (!model.endsWith(FAST_MODE_SUFFIX)) return { model, fast: false };
9
+ const base = model.slice(0, -FAST_MODE_SUFFIX.length);
10
+ return FAST_MODE_BASE_MODELS[provider]?.includes(base) ? { model: base, fast: true } : { model, fast: false };
11
+ }
12
+ var FAST_MODE_REJECTION_HEADER = "anthropic-ratelimit-unified-overage-disabled-reason";
13
+ var FAST_MODE_REJECTION_PREFIX = "Fast mode unavailable";
14
+ var USAGE_PAGE = "claude.ai/settings/usage";
15
+ var STANDARD_SPEED_FALLBACK = "or switch to Claude Opus 5.5 (standard speed), which uses your plan";
16
+ function describeFastModeRejection(reason) {
17
+ const code = reason?.trim() || "unknown";
18
+ const of = (headline, guidance, kind) => ({ reason: code, headline, guidance, kind });
19
+ switch (code) {
20
+ case "overage_not_provisioned":
21
+ case "no_limits_configured":
22
+ return of(
23
+ "Claude usage credits are turned off",
24
+ `Fast mode bills your Claude usage credits, never your plan. Turn usage credits on at ${USAGE_PAGE}, ${STANDARD_SPEED_FALLBACK}.`,
25
+ "access"
26
+ );
27
+ case "out_of_credits":
28
+ return of(
29
+ "Your Claude usage credits have run out",
30
+ `Fast mode bills your Claude usage credits, never your plan, and the balance is empty. Add funds or turn on auto-reload at ${USAGE_PAGE}, ${STANDARD_SPEED_FALLBACK}.`,
31
+ "billing"
32
+ );
33
+ case "org_level_disabled_until":
34
+ case "org_spend_cap_reached":
35
+ return of(
36
+ "Claude usage credit limit reached",
37
+ `Fast mode bills your Claude usage credits and this period's spend limit is used up. Raise the limit at ${USAGE_PAGE}, ${STANDARD_SPEED_FALLBACK}.`,
38
+ "billing"
39
+ );
40
+ case "org_level_disabled":
41
+ case "org_service_level_disabled":
42
+ return of(
43
+ "Your organization turned Claude usage credits off",
44
+ `Fast mode needs usage credits. Ask an admin to turn them on, ${STANDARD_SPEED_FALLBACK}.`,
45
+ "access"
46
+ );
47
+ case "member_level_disabled":
48
+ return of(
49
+ "Claude usage credits are off for your account",
50
+ `Fast mode needs usage credits. Ask your organization's admin to turn them on for you, ${STANDARD_SPEED_FALLBACK}.`,
51
+ "access"
52
+ );
53
+ case "seat_tier_level_disabled":
54
+ case "seat_tier_zero_credit_limit":
55
+ case "member_zero_credit_limit":
56
+ case "group_zero_credit_limit":
57
+ return of(
58
+ "Claude usage credits aren't available on your plan",
59
+ `Fast mode needs usage credits, which your seat doesn't include. Ask your admin about access, ${STANDARD_SPEED_FALLBACK}.`,
60
+ "access"
61
+ );
62
+ case "fast_mode_org_disabled":
63
+ return of(
64
+ "Your organization turned fast mode off",
65
+ `An Owner can enable fast mode for the organization, ${STANDARD_SPEED_FALLBACK}.`,
66
+ "access"
67
+ );
68
+ default:
69
+ return of(
70
+ "Fast mode needs Claude usage credits",
71
+ `Fast mode bills your Claude usage credits, never your plan, and Anthropic couldn't charge them. Check usage credits at ${USAGE_PAGE}, ${STANDARD_SPEED_FALLBACK}.`,
72
+ "billing"
73
+ );
74
+ }
75
+ }
76
+ function fastModeRejectionMessage(rejection) {
77
+ return `${FAST_MODE_REJECTION_PREFIX} (${rejection.reason}): ${rejection.headline}.`;
78
+ }
79
+ function parseFastModeRejection(message) {
80
+ const canonical = /fast mode unavailable \(([a-z_]+)\)/i.exec(message);
81
+ if (canonical) return describeFastModeRejection(canonical[1]);
82
+ if (/usage credits are required for fast mode/i.test(message)) {
83
+ return describeFastModeRejection(void 0);
84
+ }
85
+ if (/fast mode (?:has been |is )?disabled by your organization/i.test(message)) {
86
+ return describeFastModeRejection("fast_mode_org_disabled");
87
+ }
88
+ return void 0;
89
+ }
90
+
1
91
  // src/errors.ts
2
92
  function readHeader(headers, ...names) {
3
93
  if (!headers) return void 0;
@@ -77,7 +167,8 @@ function isUsageLimitError(err) {
77
167
  }
78
168
  function isHardBillingMessage(message) {
79
169
  const lower = message.toLowerCase();
80
- return lower.includes("insufficient balance") || lower.includes("insufficient credits") || lower.includes("more credits") || lower.includes("insufficient_quota") || lower.includes("exceeded your current quota") || lower.includes("quota exceeded") || lower.includes("no resource package") || lower.includes("recharge") || lower.includes("balance is too low") || lower.includes("out of credits") || lower.includes("arrears") || lower.includes("arrearage") || lower.includes("token quota") || lower.includes("exceeded_current_quota_error") || lower.includes("check your account balance") || lower.includes("does not yet include access") || lower.includes("subscription plan") || lower.includes("billing");
170
+ return lower.includes("insufficient balance") || lower.includes("insufficient credits") || lower.includes("more credits") || lower.includes("insufficient_quota") || lower.includes("exceeded your current quota") || lower.includes("quota exceeded") || lower.includes("no resource package") || lower.includes("recharge") || lower.includes("balance is too low") || lower.includes("out of credits") || // Anthropic fast mode when usage credits can't pay (see fast-mode.ts).
171
+ lower.includes("usage credits are required") || lower.includes("fast mode unavailable") || lower.includes("arrears") || lower.includes("arrearage") || lower.includes("token quota") || lower.includes("exceeded_current_quota_error") || lower.includes("check your account balance") || lower.includes("does not yet include access") || lower.includes("subscription plan") || lower.includes("billing");
81
172
  }
82
173
  function formatResetTime(resetsAt) {
83
174
  const when = new Date(resetsAt * 1e3);
@@ -130,6 +221,18 @@ function formatError(err) {
130
221
  guidance: "Request access via your Anthropic account team (see platform.claude.com/docs/en/about-claude/models/overview), or switch to Claude Fable 5.1 via the model selector \u2014 same underlying model, generally available."
131
222
  };
132
223
  }
224
+ const fastRejection = err.provider === "anthropic" ? parseFastModeRejection(err.message) : void 0;
225
+ if (fastRejection) {
226
+ return {
227
+ headline: `${fastRejection.headline}.`,
228
+ source: "provider",
229
+ message: cleanMessage,
230
+ provider: err.provider,
231
+ statusCode: err.statusCode,
232
+ ...err.requestId ? { requestId: err.requestId } : {},
233
+ guidance: fastRejection.guidance
234
+ };
235
+ }
133
236
  if (isUsageLimitError(err)) {
134
237
  const resetClause = err.resetsAt ? ` It resets at ${formatResetTime(err.resetsAt)}.` : "";
135
238
  return {
@@ -1306,7 +1409,7 @@ function isAdaptiveThinkingModel(model) {
1306
1409
  function toAnthropicThinking(level, maxTokens, model) {
1307
1410
  if (isAdaptiveThinkingModel(model)) {
1308
1411
  let effort = level;
1309
- if (effort === "xhigh" && !/opus-5|opus-4-8|opus-4-7|sonnet-5[-.]5|haiku-5[-.]5/.test(model)) {
1412
+ if (effort === "xhigh" && !/fable-5|mythos-5|opus-5|opus-4-8|opus-4-7|sonnet-5[-.]5|haiku-5[-.]5/.test(model)) {
1310
1413
  effort = "high";
1311
1414
  }
1312
1415
  return {
@@ -1574,6 +1677,7 @@ function fineGrainedToolStreamingEnabled() {
1574
1677
  return v === "1" || v === "true" || v === "yes" || v === "on";
1575
1678
  }
1576
1679
  var SERVER_FALLBACK_BETA = "server-side-fallback-2026-07-01";
1680
+ var FAST_MODE_BETA = "fast-mode-2026-02-01";
1577
1681
  var anthropicServerFallback = {
1578
1682
  disabled: /* @__PURE__ */ new Set(),
1579
1683
  reset() {
@@ -1716,6 +1820,7 @@ async function* runStream(options) {
1716
1820
  const { system: rawSystem, messages } = toAnthropicMessages(downgradedMessages, cacheControl, {
1717
1821
  fallbackBlocks: useServerFallback
1718
1822
  });
1823
+ const useFastMode = options.speed === "fast" && options.provider === "anthropic" && isDirectAnthropicApi(options.baseUrl);
1719
1824
  const system = isOAuth ? [
1720
1825
  {
1721
1826
  type: "text",
@@ -1786,6 +1891,7 @@ async function* runStream(options) {
1786
1891
  return contextEdits.length ? { context_management: { edits: contextEdits } } : {};
1787
1892
  })(),
1788
1893
  ...useServerFallback ? { fallbacks: "default" } : {},
1894
+ ...useFastMode ? { speed: "fast" } : {},
1789
1895
  stream: useStreaming
1790
1896
  };
1791
1897
  const params = mergeProviderOptions(baseParams, options.providerOptions);
@@ -1804,7 +1910,8 @@ async function* runStream(options) {
1804
1910
  // so a pre-warmed cache expires before the user's first turn. cacheControl.ttl
1805
1911
  // is only "1h" on the first-party endpoint (see toAnthropicCacheControl).
1806
1912
  ...cacheControl?.ttl === "1h" ? ["extended-cache-ttl-2025-04-11"] : [],
1807
- ...useServerFallback ? [SERVER_FALLBACK_BETA] : []
1913
+ ...useServerFallback ? [SERVER_FALLBACK_BETA] : [],
1914
+ ...useFastMode ? [FAST_MODE_BETA] : []
1808
1915
  ];
1809
1916
  const toRequestOptions = (betas) => ({
1810
1917
  signal: options.signal ?? void 0,
@@ -1842,7 +1949,7 @@ async function* runStream(options) {
1842
1949
  yield* synthesizeEventsFromMessage(message);
1843
1950
  return messageToResponse(message);
1844
1951
  } catch (err) {
1845
- throw toError(err);
1952
+ throw toError(err, { fastMode: useFastMode });
1846
1953
  }
1847
1954
  }
1848
1955
  const contentParts = [];
@@ -2059,7 +2166,7 @@ async function* runStream(options) {
2059
2166
  }
2060
2167
  }
2061
2168
  } catch (err) {
2062
- throw toError(err);
2169
+ throw toError(err, { fastMode: useFastMode });
2063
2170
  }
2064
2171
  if (!receivedAnyEvent) {
2065
2172
  throw new ProviderError("anthropic", "Stream ended without producing any events.", {
@@ -2189,6 +2296,13 @@ function messageToResponse(message) {
2189
2296
  }
2190
2297
  };
2191
2298
  }
2299
+ function readFastModeRejection(err, message, fastMode) {
2300
+ const reason = readHeader(err.headers, FAST_MODE_REJECTION_HEADER);
2301
+ if (fastMode && err.status === 429 && reason) return describeFastModeRejection(reason);
2302
+ const fromBody = parseFastModeRejection(message);
2303
+ if (!fromBody) return void 0;
2304
+ return reason ? describeFastModeRejection(reason) : fromBody;
2305
+ }
2192
2306
  function readUnifiedRateLimit(headers) {
2193
2307
  const status = readHeader(headers, "anthropic-ratelimit-unified-status");
2194
2308
  const resetRaw = readHeader(
@@ -2201,7 +2315,7 @@ function readUnifiedRateLimit(headers) {
2201
2315
  const resetsAt = Number.isFinite(resetNum) && resetNum > 0 ? resetNum : void 0;
2202
2316
  return { rejected: status === "rejected", ...resetsAt ? { resetsAt } : {} };
2203
2317
  }
2204
- function toError(err) {
2318
+ function toError(err, context) {
2205
2319
  if (err instanceof ProviderError) return err;
2206
2320
  if (err instanceof Anthropic.APIError) {
2207
2321
  const errorBody = err.error;
@@ -2212,6 +2326,15 @@ function toError(err) {
2212
2326
  const fallbackMessage = isRawJsonErrorEcho(err.message) ? emptyProviderErrorMessage(err.status) : err.message;
2213
2327
  const messageCandidate = bodyMessage ?? err.message;
2214
2328
  const message = isRawHtmlErrorEcho(messageCandidate) ? providerHtmlErrorMessage(err.status) : bodyType && bodyMessage ? `${bodyType}: ${bodyMessage}` : bodyMessage ?? fallbackMessage;
2329
+ const fastRejection = readFastModeRejection(err, message, context?.fastMode === true);
2330
+ if (fastRejection) {
2331
+ return new ProviderError("anthropic", fastModeRejectionMessage(fastRejection), {
2332
+ statusCode: err.status,
2333
+ ...requestId ? { requestId } : {},
2334
+ hint: fastRejection.guidance,
2335
+ cause: err
2336
+ });
2337
+ }
2215
2338
  if (err.status === 429) {
2216
2339
  const limit = readUnifiedRateLimit(err.headers);
2217
2340
  const farOff = limit.resetsAt != null && limit.resetsAt * 1e3 - Date.now() > 6e4;
@@ -2467,8 +2590,9 @@ async function* runStream2(options) {
2467
2590
  if (options.provider === "sakana" && options.model === "fugu-ultra" && (options.thinking === "max" || options.thinking === "ultra")) {
2468
2591
  params.reasoning_effort = "max";
2469
2592
  }
2470
- if (options.provider === "openai" && options.serviceTier) {
2471
- params.service_tier = options.serviceTier;
2593
+ const serviceTier = options.serviceTier ?? (options.speed === "fast" ? "priority" : void 0);
2594
+ if (options.provider === "openai" && serviceTier) {
2595
+ params.service_tier = serviceTier;
2472
2596
  }
2473
2597
  if (isKimiK3) {
2474
2598
  const paramsAny = params;
@@ -2506,10 +2630,16 @@ async function* runStream2(options) {
2506
2630
  `
2507
2631
  );
2508
2632
  }
2633
+ const requestHeaders = options.provider === "xai" ? {
2634
+ headers: {
2635
+ "x-grok-conv-id": normalizePromptCacheKey(options.promptCacheKey ?? "ggcoder")
2636
+ }
2637
+ } : {};
2509
2638
  if (!useStreaming) {
2510
2639
  try {
2511
2640
  const completion = await client.chat.completions.create(requestParams, {
2512
- signal: options.signal ?? void 0
2641
+ signal: options.signal ?? void 0,
2642
+ ...requestHeaders
2513
2643
  });
2514
2644
  yield* synthesizeEventsFromCompletion(completion, !!options.thinking, endpointKey);
2515
2645
  return completionToResponse(completion, endpointKey);
@@ -2520,7 +2650,8 @@ async function* runStream2(options) {
2520
2650
  let stream2;
2521
2651
  try {
2522
2652
  stream2 = await client.chat.completions.create(requestParams, {
2523
- signal: options.signal ?? void 0
2653
+ signal: options.signal ?? void 0,
2654
+ ...requestHeaders
2524
2655
  });
2525
2656
  } catch (err) {
2526
2657
  throw toError2(err, providerName);
@@ -2978,6 +3109,9 @@ async function* runStream3(options, retriedWithoutReasoning = false) {
2978
3109
  if (options.temperature != null && !options.thinking) {
2979
3110
  body.temperature = options.temperature;
2980
3111
  }
3112
+ if (options.speed === "fast") {
3113
+ body.service_tier = "priority";
3114
+ }
2981
3115
  body.reasoning = {
2982
3116
  // GPT-5.6/6 require at least low; older models still support thinking off.
2983
3117
  // Apply the floor here for every caller, including one-off prompt rewrites.
@@ -3560,6 +3694,9 @@ var CODE_ASSIST_SUPPORTED_MODELS = /* @__PURE__ */ new Set([
3560
3694
  "gemma-4-31b-it",
3561
3695
  "gemma-4-26b-a4b-it"
3562
3696
  ]);
3697
+ function isGeminiApiKeyRoute(options) {
3698
+ return options.baseUrl?.includes("generativelanguage.googleapis.com") === true;
3699
+ }
3563
3700
  function getGoogleProject(options) {
3564
3701
  const env = getEnvironment();
3565
3702
  return options.projectId ?? env?.GOOGLE_CLOUD_PROJECT ?? env?.GOOGLE_CLOUD_PROJECT_ID;
@@ -3592,8 +3729,28 @@ function accountGatedHint(model) {
3592
3729
  if (model === "gemini-3.8-flash" || model === "gemini-3.5-flash-lite") {
3593
3730
  return "Use /model to select Gemini 3.1 Flash Lite, or retry once Google enables this model through Code Assist for your account.";
3594
3731
  }
3595
- return `Newer Gemini models (3.7 Flash, 3.5 Flash, 3.1 Pro Preview) are available only to Code Assist Standard/Enterprise accounts with preview/GA access enabled by a cloud admin \u2014 free/personal accounts usually can't call them. Switch to Gemini 3.1 Flash Lite (it works on this account) with /model, or sign in with a Code Assist Standard/Enterprise account that has preview access.`;
3732
+ return `Newer Gemini models (3.5 Flash, 3.1 Pro Preview) are available only to Code Assist Standard/Enterprise accounts with preview/GA access enabled by a cloud admin. Try Gemini 3.1 Flash Lite with /model, or sign in with a Code Assist Standard/Enterprise account that has preview access.`;
3596
3733
  }
3734
+ function isCodeAssistLicenseRequired(status, body) {
3735
+ if (status !== 403) return false;
3736
+ try {
3737
+ const parsed = JSON.parse(body);
3738
+ const details = typeof parsed === "object" && parsed !== null && "error" in parsed ? parsed.error?.details : void 0;
3739
+ return Array.isArray(details) && details.some(
3740
+ (detail) => typeof detail === "object" && detail !== null && detail.reason === "SUBSCRIPTION_REQUIRED"
3741
+ );
3742
+ } catch {
3743
+ return false;
3744
+ }
3745
+ }
3746
+ function isInvalidGeminiApiKey(status, body) {
3747
+ if (status !== 400 && status !== 401 && status !== 403) return false;
3748
+ return /"reason"\s*:\s*"API_KEY_INVALID"/.test(body) || /API key not valid/i.test(body);
3749
+ }
3750
+ var INVALID_API_KEY_MESSAGE = "Google rejected the Gemini API key: it is not valid.";
3751
+ var INVALID_API_KEY_HINT = "Create a key at aistudio.google.com/apikey and add it again under Gemini in Providers (or `ggcoder login`).";
3752
+ var LICENSE_REQUIRED_MESSAGE = "This Google account has no Gemini Code Assist licence. Google stopped serving Gemini through Code Assist to personal accounts (Google AI Pro/Ultra and the free individual tier) on June 18, 2026, so every Gemini model is refused, not just this one.";
3753
+ var LICENSE_REQUIRED_HINT = "Sign in to Gemini with a Google account that has a Gemini Code Assist Standard or Enterprise licence, or pick a model from another provider with /model.";
3597
3754
  function formatErrorMessage(status, body, model) {
3598
3755
  if (status === 404 && !CODE_ASSIST_SUPPORTED_MODELS.has(model)) {
3599
3756
  return `Gemini API error (404): ${body}
@@ -3817,7 +3974,29 @@ function buildCodeAssistRequest(options, request, projectId) {
3817
3974
  request
3818
3975
  };
3819
3976
  }
3977
+ var API_KEY_MODEL_IDS = {
3978
+ "gemini-3-flash": "gemini-3.5-flash"
3979
+ };
3980
+ function buildApiKeyRequestPlan(options, method) {
3981
+ const { session_id: _sessionId, ...request } = mergeProviderOptions(
3982
+ buildGenerateRequest(options),
3983
+ options.providerOptions
3984
+ );
3985
+ const base = (options.baseUrl ?? "").replace(/\/+$/, "");
3986
+ return {
3987
+ url: new URL(
3988
+ `${base}/models/${encodeURIComponent(API_KEY_MODEL_IDS[options.model] ?? options.model)}:${method}`
3989
+ ),
3990
+ headers: {
3991
+ "Content-Type": "application/json",
3992
+ "x-goog-api-key": options.apiKey ?? ""
3993
+ },
3994
+ body: request,
3995
+ route: "api-key"
3996
+ };
3997
+ }
3820
3998
  function buildRequestPlan(options, method) {
3999
+ if (isGeminiApiKeyRoute(options)) return buildApiKeyRequestPlan(options, method);
3821
4000
  if (!CODE_ASSIST_SUPPORTED_MODELS.has(options.model)) {
3822
4001
  throw new ProviderError("gemini", formatUnsupportedModelMessage(options.model));
3823
4002
  }
@@ -3831,7 +4010,8 @@ function buildRequestPlan(options, method) {
3831
4010
  "User-Agent": GEMINI_CLI_USER_AGENT,
3832
4011
  "X-Goog-Api-Client": GEMINI_CLI_API_CLIENT
3833
4012
  },
3834
- body: buildCodeAssistRequest(options, request, projectId)
4013
+ body: buildCodeAssistRequest(options, request, projectId),
4014
+ route: "code-assist"
3835
4015
  };
3836
4016
  }
3837
4017
  function normalizeGeminiStopReason(reason) {
@@ -3917,8 +4097,11 @@ async function fetchCodeAssist(plan, options) {
3917
4097
  if (!response.ok) {
3918
4098
  const text = await response.text().catch(() => "");
3919
4099
  const quota = parseGeminiQuota(response.status, text);
3920
- const accountGated = response.status === 404 && ACCOUNT_GATED_MODELS.has(options.model);
3921
- let message = accountGated ? accountGatedMessage(options.model) : formatErrorMessage(response.status, text, options.model);
4100
+ const codeAssist = plan.route === "code-assist";
4101
+ const accountGated = codeAssist && response.status === 404 && ACCOUNT_GATED_MODELS.has(options.model);
4102
+ const licenseRequired = codeAssist && isCodeAssistLicenseRequired(response.status, text);
4103
+ const invalidKey = !codeAssist && isInvalidGeminiApiKey(response.status, text);
4104
+ let message = invalidKey ? INVALID_API_KEY_MESSAGE : licenseRequired ? LICENSE_REQUIRED_MESSAGE : accountGated ? accountGatedMessage(options.model) : formatErrorMessage(response.status, text, options.model);
3922
4105
  let resetsAt;
3923
4106
  if (quota?.exhausted) {
3924
4107
  message = `Gemini quota exhausted \u2014 usage limit reached. ${message}`;
@@ -3928,7 +4111,7 @@ async function fetchCodeAssist(plan, options) {
3928
4111
  throw new ProviderError("gemini", message, {
3929
4112
  statusCode: response.status,
3930
4113
  ...resetsAt !== void 0 ? { resetsAt } : {},
3931
- ...accountGated ? { hint: accountGatedHint(options.model) } : {}
4114
+ ...invalidKey ? { hint: INVALID_API_KEY_HINT, source: "auth" } : licenseRequired ? { hint: LICENSE_REQUIRED_HINT, source: "auth" } : accountGated ? { hint: accountGatedHint(options.model) } : {}
3932
4115
  });
3933
4116
  }
3934
4117
  return response;
@@ -4815,7 +4998,7 @@ providerRegistry.register("sakana", {
4815
4998
  providerRegistry.register("xai", {
4816
4999
  // xAI's public API (console.x.ai key) is OpenAI-compatible — ride the Chat
4817
5000
  // Completions transport like Moonshot/DeepSeek. Grok reasoning models take
4818
- // top-level `reasoning_effort` (low/medium/high), which the shared thinking
5001
+ // top-level `reasoning_effort` (low/medium/high/xhigh), which the shared thinking
4819
5002
  // path already sends.
4820
5003
  //
4821
5004
  // Subscription OAuth (SuperGrok / X Premium) routes to the Grok CLI chat proxy
@@ -4887,7 +5070,9 @@ function requireLocalBaseUrl(baseUrl) {
4887
5070
  }
4888
5071
  return baseUrl;
4889
5072
  }
4890
- function stream(options) {
5073
+ function stream(requested) {
5074
+ const fastMode = resolveFastModeModel(requested.provider, requested.model);
5075
+ const options = fastMode.fast ? { ...requested, model: fastMode.model, speed: "fast" } : requested;
4891
5076
  const entry = providerRegistry.get(options.provider);
4892
5077
  if (!entry) {
4893
5078
  throw new GGAIError(
@@ -5102,6 +5287,14 @@ function formatChatError(error) {
5102
5287
  "Update the app, or choose another model."
5103
5288
  );
5104
5289
  }
5290
+ const fastRejection = base.provider === "anthropic" ? parseFastModeRejection(raw) : void 0;
5291
+ if (fastRejection) {
5292
+ return present(
5293
+ fastRejection.kind === "billing" ? "billing" : "model_access",
5294
+ fastRejection.headline,
5295
+ fastRejection.guidance
5296
+ );
5297
+ }
5105
5298
  if (/insufficient.*(?:balance|credits?)|(?:balance|credits?).*(?:insufficient|exhausted|depleted)|credit balance is too low|payment_required/.test(
5106
5299
  text
5107
5300
  )) {
@@ -5518,6 +5711,7 @@ function palsuRerankScore(query, document) {
5518
5711
  }
5519
5712
  export {
5520
5713
  EventStream,
5714
+ FAST_MODE_SUFFIX,
5521
5715
  GGAIError,
5522
5716
  ProviderError,
5523
5717
  REDACTED as REDACTION_MARKER,
@@ -5526,6 +5720,7 @@ export {
5526
5720
  clampProviderContextImages,
5527
5721
  classifyProviderError,
5528
5722
  continuesTurn,
5723
+ describeFastModeRejection,
5529
5724
  dropInvalidToolCalls,
5530
5725
  embed,
5531
5726
  environmentSecrets,
@@ -5544,12 +5739,14 @@ export {
5544
5739
  palsuText,
5545
5740
  palsuThinking,
5546
5741
  palsuToolCall,
5742
+ parseFastModeRejection,
5547
5743
  prewarmAnthropicCache,
5548
5744
  providerRegistry,
5549
5745
  redactText,
5550
5746
  redactValue,
5551
5747
  registerPalsuProvider,
5552
5748
  rerank,
5749
+ resolveFastModeModel,
5553
5750
  resolveToolSchema,
5554
5751
  sanitizeMessagesForWire,
5555
5752
  setProviderDiagnostic,