@oh-my-pi/pi-ai 16.2.5 → 16.2.7

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 (31) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/types/auth-storage.d.ts +11 -10
  3. package/dist/types/providers/__tests__/kimi-code-thinking.test.d.ts +1 -0
  4. package/dist/types/providers/google-auth.d.ts +8 -0
  5. package/dist/types/providers/google-interactions.d.ts +65 -0
  6. package/dist/types/providers/google-shared.d.ts +20 -5
  7. package/dist/types/providers/google-types.d.ts +5 -0
  8. package/dist/types/providers/openai-codex/request-transformer.d.ts +1 -1
  9. package/dist/types/providers/openai-codex-responses.d.ts +1 -1
  10. package/dist/types/providers/openai-shared.d.ts +3 -3
  11. package/dist/types/types.d.ts +80 -30
  12. package/dist/types/utils/leaked-thinking-stream.d.ts +29 -0
  13. package/package.json +4 -4
  14. package/src/auth-storage.ts +56 -52
  15. package/src/providers/__tests__/kimi-code-thinking.test.ts +112 -0
  16. package/src/providers/anthropic.ts +11 -10
  17. package/src/providers/google-auth.ts +25 -0
  18. package/src/providers/google-gemini-cli.ts +90 -41
  19. package/src/providers/google-interactions.ts +753 -0
  20. package/src/providers/google-shared.ts +74 -13
  21. package/src/providers/google-types.ts +5 -1
  22. package/src/providers/google-vertex.ts +117 -26
  23. package/src/providers/google.ts +61 -19
  24. package/src/providers/openai-chat-server.ts +2 -2
  25. package/src/providers/openai-codex/request-transformer.ts +17 -4
  26. package/src/providers/openai-codex-responses.ts +23 -5
  27. package/src/providers/openai-shared.ts +5 -11
  28. package/src/stream.ts +34 -12
  29. package/src/types.ts +164 -51
  30. package/src/usage/google-antigravity.ts +59 -5
  31. package/src/utils/leaked-thinking-stream.ts +260 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,34 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.2.7] - 2026-06-30
6
+
7
+ ### Added
8
+
9
+ - Added service tier support for Google Gemini and Vertex AI, including model-specific service tier configurations via ServiceTierByFamily.
10
+ - Added Google Vertex AI Interactions API support for Gemini 3+ models by default, with automatic fallback to :streamGenerateContent and a useInteractionsApi: false option to force standard generation.
11
+ - Added support for explicit Vertex bearer access tokens via GOOGLE_CLOUD_ACCESS_TOKEN or CLOUDSDK_AUTH_ACCESS_TOKEN environment variables.
12
+
13
+ ### Changed
14
+
15
+ - Updated service tier logic to use per-provider configurations instead of global scopes.
16
+ - Refactored priority request billing and accounting to better align with specific provider capabilities.
17
+ - Updated API key resolution precedence so explicit environment variables (e.g., GEMINI_API_KEY) override stored or broker-migrated static API keys, while deliberate OAuth logins still take highest precedence.
18
+
19
+ ### Fixed
20
+
21
+ - Improved Vertex AI reliability by automatically falling back to global endpoints on 404 errors.
22
+ - Fixed safety setting application for Google Vertex AI models.
23
+ - Fixed Kimi Code's Anthropic-compatible request path to keep thinking enabled and downgrade forced tool choice for Kimi K2.7 Code title generation.
24
+ - Fixed leaked reasoning fences (such as ```thinking or <think>) across all providers by splitting them into structured thinking blocks during streaming.
25
+ - Fixed Codex requests failing with unsupported all_turns errors on older models (gpt-5.1 and gpt-5.3) by gating the reasoning.context: "all_turns" default to gpt-5.4+ models.
26
+
27
+ ## [16.2.6] - 2026-06-29
28
+
29
+ ### Fixed
30
+
31
+ - Fixed Antigravity usage reporting to correctly infer daily and weekly quota windows from unlabeled reset-only rows, preventing Cloud Code Assist payloads from collapsing these counters into the default category.
32
+
5
33
  ## [16.2.5] - 2026-06-28
6
34
 
7
35
  ### Fixed
@@ -650,8 +650,8 @@ export declare class AuthStorage {
650
650
  /**
651
651
  * Classify where a provider's auth comes from, following the same precedence
652
652
  * as {@link AuthStorage.getApiKey}: runtime override → config override →
653
- * stored credential (api_key before oauth, matching getApiKey)env var
654
- * fallback resolver. Returns undefined when no auth is configured.
653
+ * stored OAuth env var stored api_key fallback resolver. Returns
654
+ * undefined when no auth is configured.
655
655
  *
656
656
  * Compact, structured counterpart to {@link describeCredentialSource}.
657
657
  */
@@ -778,12 +778,12 @@ export declare class AuthStorage {
778
778
  peekApiKey(provider: string): Promise<string | undefined>;
779
779
  /**
780
780
  * Get API key for a provider.
781
- * Priority:
781
+ * Priority (first match wins):
782
782
  * 1. Runtime override (CLI --api-key)
783
783
  * 2. Config override (models.yml `providers.<name>.apiKey`)
784
- * 3. API key from storage
785
- * 4. OAuth token from storage (auto-refreshed)
786
- * 5. Environment variable
784
+ * 3. OAuth token from storage (auto-refreshed)
785
+ * 4. Environment variable
786
+ * 5. Stored API key (e.g. a broker-migrated copy) — last resort, so an explicit env var wins
787
787
  * 6. Fallback resolver (models.yml custom providers, last-resort)
788
788
  */
789
789
  getApiKey(provider: string, sessionId?: string, options?: AuthApiKeyOptions): Promise<string | undefined>;
@@ -945,12 +945,13 @@ export declare class AuthStorage {
945
945
  /**
946
946
  * Describe where the active credential for a provider came from.
947
947
  *
948
- * Surfaces four layers, highest precedence first:
948
+ * Mirrors {@link AuthStorage.getApiKey} precedence, highest first:
949
949
  * 1. Runtime override (`--api-key`).
950
950
  * 2. Config override (`models.yml` `providers.<name>.apiKey`).
951
- * 3. Stored credential (the one this session is currently sticky to, or the
952
- * one round-robin would pick next when no session id is supplied).
953
- * 4. Env var / fallback resolver — when no stored credential exists.
951
+ * 3. Stored OAuth credential.
952
+ * 4. Env var overrides a stored static api_key (e.g. a stale broker copy).
953
+ * 5. Stored api_key credential.
954
+ * 6. Fallback resolver.
954
955
  *
955
956
  * The string is purely informational; consumers must not parse it.
956
957
  */
@@ -22,3 +22,11 @@ export declare function getVertexAccessToken(options?: {
22
22
  }): Promise<string>;
23
23
  /** Test seam: clears every cached token. */
24
24
  export declare function __resetVertexTokenCache(): void;
25
+ /**
26
+ * Sync best-effort probe for a usable Vertex bearer credential source — an explicit access-token
27
+ * env var, `GOOGLE_APPLICATION_CREDENTIALS`, a user ADC file, or a GCP runtime whose metadata
28
+ * server can mint ADC (GCE/Cloud Run/App Engine/Functions). Lets callers prefer the bearer
29
+ * Interactions transport only when ADC is actually reachable, without paying the async
30
+ * metadata-probe cost for API-key-only setups.
31
+ */
32
+ export declare function hasVertexBearerCredentialsHint(): boolean;
@@ -0,0 +1,65 @@
1
+ import type { Context, FetchImpl, Model, ProviderSessionState } from "../types";
2
+ import { AssistantMessageEventStream } from "../utils/event-stream";
3
+ import { type GoogleSharedStreamOptions } from "./google-shared";
4
+ type GoogleInteractionsApi = "google-generative-ai" | "google-vertex";
5
+ /** Provider session state storing the last Gemini Interactions response id. */
6
+ export interface GoogleInteractionsProviderSessionState extends ProviderSessionState {
7
+ lastInteractionId?: string;
8
+ }
9
+ /** Conversation anchor for continuing an Interactions turn from a prior assistant response. */
10
+ export interface InteractionAnchor {
11
+ id?: string;
12
+ messageIndex?: number;
13
+ }
14
+ /** Provider-specific URL, headers, and fetch implementation for an Interactions request. */
15
+ export interface GoogleInteractionsPlan {
16
+ url: string;
17
+ headers: Record<string, string>;
18
+ fetch?: FetchImpl;
19
+ }
20
+ /**
21
+ * Streams Gemini Interactions API model-mode responses for direct Google and Vertex providers.
22
+ *
23
+ * `fallback`, when supplied, is the legacy `:streamGenerateContent` stream factory. It runs
24
+ * transparently — forwarding its events into this stream — when the Interactions attempt fails
25
+ * before any content is emitted with a signal that the model/endpoint does not support
26
+ * Interactions (HTTP 404/400). Provide it only for auto-selected Interactions requests so an
27
+ * explicit `useInteractionsApi: true` still surfaces failures.
28
+ */
29
+ export declare function streamGoogleInteractions<T extends GoogleInteractionsApi>(args: {
30
+ model: Model<T>;
31
+ context: Context;
32
+ options: GoogleSharedStreamOptions | undefined;
33
+ api: T;
34
+ anchor: InteractionAnchor;
35
+ state: GoogleInteractionsProviderSessionState | undefined;
36
+ prepare: () => GoogleInteractionsPlan | Promise<GoogleInteractionsPlan>;
37
+ fallback?: () => AssistantMessageEventStream;
38
+ }): AssistantMessageEventStream;
39
+ /**
40
+ * Whether a model is served by the Gemini Interactions API. Interactions is a Gemini 3-era
41
+ * transport, so the catalog subset that supports it is Gemini 3.0+. Older Gemini and non-Gemini
42
+ * ids keep `:streamGenerateContent`, which covers the full catalog.
43
+ */
44
+ export declare function modelSupportsInteractions(model: Pick<Model, "id">): boolean;
45
+ /**
46
+ * Resolves whether a Google provider call should use Interactions and which lineage anchor to send.
47
+ *
48
+ * Precedence: explicit `useInteractionsApi: false` always wins (force generateContent); otherwise
49
+ * Interactions engages when explicitly requested, when continuing a stored interaction
50
+ * (`previousInteractionId`/assistant lineage/session state), or when `autoEligible` (the
51
+ * zero-config default for the capable model subset on the official endpoint). `auto` flags the
52
+ * last case for the caller — it is the only mode that wires up the generateContent fallback.
53
+ */
54
+ export declare function resolveInteractionDispatch(args: {
55
+ context: Context;
56
+ options: GoogleSharedStreamOptions | undefined;
57
+ provider: string;
58
+ autoEligible: boolean;
59
+ }): {
60
+ useInteractions: boolean;
61
+ auto: boolean;
62
+ anchor: InteractionAnchor;
63
+ state: GoogleInteractionsProviderSessionState | undefined;
64
+ };
65
+ export {};
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Shared utilities for Google Generative AI and Google Cloud Code Assist providers.
3
3
  */
4
- import type { AssistantMessage, Context, FetchImpl, Model, StopReason, StreamOptions, TextContent, ThinkingContent, Tool, ToolCall } from "../types";
4
+ import type { AssistantMessage, Context, FetchImpl, Model, ServiceTier, StopReason, StreamOptions, TextContent, ThinkingContent, Tool, ToolCall } from "../types";
5
5
  import { AssistantMessageEventStream } from "../utils/event-stream";
6
6
  import { normalizeSchemaForGoogle } from "../utils/schema";
7
7
  import type { Content, FinishReason, FunctionCallingConfigMode, GenerateContentParameters, GenerateContentResponse, Part } from "./google-types";
@@ -33,6 +33,21 @@ export interface GoogleSharedStreamOptions extends StreamOptions {
33
33
  budgetTokens?: number;
34
34
  level?: GoogleThinkingLevel;
35
35
  };
36
+ /** Gemini/Vertex serving tier (`flex`/`priority`); other values are omitted. */
37
+ serviceTier?: ServiceTier;
38
+ /**
39
+ * Continues a Gemini Interactions API conversation from a stored interaction.
40
+ * When set on the direct Google provider, the request uses `/interactions`
41
+ * with `previous_interaction_id` instead of the legacy generateContent stream.
42
+ */
43
+ previousInteractionId?: string;
44
+ /**
45
+ * Uses the Gemini Interactions API for direct Google requests, storing the
46
+ * returned interaction id on the assistant response for follow-up turns.
47
+ */
48
+ useInteractionsApi?: boolean;
49
+ /** Overrides Interactions API request storage; default is the API default (`true`). */
50
+ storeInteraction?: boolean;
36
51
  }
37
52
  /**
38
53
  * Determines whether a streamed Gemini `Part` should be treated as "thinking".
@@ -60,10 +75,6 @@ export declare function isThinkingPart(part: Pick<Part, "thought" | "thoughtSign
60
75
  * a signature from being overwritten with `undefined` within the same streamed block.
61
76
  */
62
77
  export declare function retainThoughtSignature(existing: string | undefined, incoming: string | undefined): string | undefined;
63
- /**
64
- * Claude models via Google APIs require explicit tool call IDs in function calls/responses.
65
- */
66
- export declare function requiresToolCallId(modelId: string): boolean;
67
78
  /**
68
79
  * Convert internal messages to Gemini Content[] format.
69
80
  */
@@ -127,6 +138,8 @@ export declare function pushToolCallEvents(toolCall: ToolCall, contentIndex: num
127
138
  * `text_start` / `thinking_start` event. `onBeforeStartEvent` lets the SSE consumer
128
139
  * inject its `ensureStarted()` first-token side effect into the canonical event order.
129
140
  */
141
+ export declare function startTextOrThinkingBlock(isThinking: true, output: AssistantMessage, stream: AssistantMessageEventStream, onBeforeStartEvent?: () => void): ThinkingContent;
142
+ export declare function startTextOrThinkingBlock(isThinking: false, output: AssistantMessage, stream: AssistantMessageEventStream, onBeforeStartEvent?: () => void): TextContent;
130
143
  export declare function startTextOrThinkingBlock(isThinking: boolean, output: AssistantMessage, stream: AssistantMessageEventStream, onBeforeStartEvent?: () => void): TextContent | ThinkingContent;
131
144
  /**
132
145
  * Drives the chunked `generateContentStream` iterator into an `AssistantMessage` and
@@ -178,6 +191,8 @@ export interface GoogleGenAIRequestPlan {
178
191
  url: string;
179
192
  headers: Record<string, string>;
180
193
  fetch?: FetchImpl;
194
+ /** Optional URL retried once when {@link url} returns 404 (regional Vertex endpoint missing a global-only model). */
195
+ fallbackUrl?: string;
181
196
  }
182
197
  export declare function streamGoogleGenAI<T extends "google-generative-ai" | "google-vertex">(args: {
183
198
  model: Model<T>;
@@ -106,6 +106,11 @@ export interface GenerateContentConfig {
106
106
  safetySettings?: Array<Record<string, unknown>>;
107
107
  cachedContent?: string;
108
108
  thinkingConfig?: ThinkingConfig;
109
+ /**
110
+ * Gemini/Vertex serving tier. Serialized to the request body root as
111
+ * `serviceTier` (camelCase) by the transformer in `google-shared.ts`.
112
+ */
113
+ serviceTier?: "auto" | "default" | "flex" | "scale" | "priority";
109
114
  abortSignal?: AbortSignal;
110
115
  }
111
116
  /** Top-level argument to `generateContentStream`. */
@@ -9,7 +9,7 @@ export interface ReasoningConfig {
9
9
  export interface CodexRequestOptions {
10
10
  reasoningEffort?: ReasoningConfig["effort"];
11
11
  reasoningSummary?: ReasoningConfig["summary"] | null;
12
- /** Explicit `reasoning.context` override; defaults to `all_turns` for every Codex request when unset. */
12
+ /** Explicit `reasoning.context` override; defaults to `all_turns` when unset. The `all_turns` value is gated to gpt-5.4+ Codex models older ids reject it, so it is suppressed and `context` omitted. */
13
13
  reasoningContext?: CodexReasoningContext;
14
14
  textVerbosity?: "low" | "medium" | "high";
15
15
  include?: string[];
@@ -4,7 +4,7 @@ import type { ResponseInput } from "./openai-responses-wire";
4
4
  export interface OpenAICodexResponsesOptions extends StreamOptions {
5
5
  reasoning?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh";
6
6
  reasoningSummary?: "auto" | "concise" | "detailed" | null;
7
- /** `reasoning.context` replay scope; defaults to `all_turns` for every Codex request when unset. */
7
+ /** `reasoning.context` replay scope; defaults to `all_turns` when unset. The `all_turns` value is gated to gpt-5.4+ Codex models older ids reject it, so it is suppressed and `context` omitted. */
8
8
  reasoningContext?: CodexReasoningContext;
9
9
  textVerbosity?: "low" | "medium" | "high";
10
10
  include?: string[];
@@ -1,5 +1,5 @@
1
1
  import type { OpenAICompat, OpenAIReasoningDisableMode, OpenAIStreamMarkupHealingPattern, OpenRouterRouting, ResolvedOpenAICompat, ResolvedOpenAIResponsesCompat, ResolvedOpenAISharedCompat, VercelGatewayRouting } from "@oh-my-pi/pi-catalog/types";
2
- import { type Api, type AssistantMessage, type CacheRetention, type Context, type ImageContent, type Message, type MessageAttribution, type Model, type Provider, type ResolvedServiceTier, type ServiceTier, type StopReason, type StreamOptions, type TextContent, type TextSignatureV1, type ThinkingContent, type Tool, type ToolCall, type ToolResultMessage } from "../types";
2
+ import { type Api, type AssistantMessage, type CacheRetention, type Context, type ImageContent, type Message, type MessageAttribution, type Model, type Provider, type ServiceTier, type StopReason, type StreamOptions, type TextContent, type TextSignatureV1, type ThinkingContent, type Tool, type ToolCall, type ToolResultMessage } from "../types";
3
3
  import { kStreamingLastParseLen, kStreamingPartialJson } from "../utils/block-symbols";
4
4
  import type { AssistantMessageEventStream } from "../utils/event-stream";
5
5
  import type { CapturedHttpErrorResponse } from "../utils/http-inspector";
@@ -55,7 +55,7 @@ export interface OpenAIRequestSetup {
55
55
  }
56
56
  export declare function resolveOpenAIRequestSetup(model: OpenAIRequestSetupModel, options: OpenAIRequestSetupOptions): OpenAIRequestSetup;
57
57
  export declare function applyOpenAIServiceTier(params: {
58
- service_tier?: ResolvedServiceTier | "auto" | "default" | null | undefined;
58
+ service_tier?: ServiceTier | null | undefined;
59
59
  }, serviceTier: ServiceTier | null | undefined, provider: Provider | undefined): void;
60
60
  /**
61
61
  * Adjust resolved cost by the service tier OpenAI actually billed — parity with
@@ -207,7 +207,7 @@ export type OpenAICompletionsParams = Omit<ChatCompletionCreateParamsStreaming,
207
207
  enabled: false;
208
208
  };
209
209
  reasoning_effort?: string | null;
210
- service_tier?: ResolvedServiceTier;
210
+ service_tier?: ServiceTier;
211
211
  tool_stream?: boolean;
212
212
  provider?: OpenAICompat["openRouterRouting"];
213
213
  providerOptions?: {
@@ -73,48 +73,82 @@ export type ToolChoice = "auto" | "none" | "any" | "required" | {
73
73
  };
74
74
  export type CacheRetention = "none" | "short" | "long";
75
75
  /**
76
- * Service tier hint for processing priority / cost control.
76
+ * Service tier hint for processing priority / cost control. These are the
77
+ * values providers consume on the wire:
77
78
  *
78
- * The unscoped values (`"auto"`, `"default"`, `"flex"`, `"scale"`,
79
- * `"priority"`) are passed through to providers that understand them
80
- * (OpenAI's `service_tier` field directly; Anthropic translates
81
- * `"priority"` into `speed: "fast"` on supported Opus models).
79
+ * - OpenAI / OpenAI-Codex: sent verbatim as the `service_tier` field
80
+ * (`flex`/`scale`/`priority`).
81
+ * - Google (Gemini API + Vertex AI): sent as the top-level `serviceTier`
82
+ * field (`flex`/`priority`).
83
+ * - OpenRouter: passed through as `service_tier`; OpenRouter realizes it for
84
+ * the OpenAI- and Google-family upstreams it supports and ignores it
85
+ * otherwise.
86
+ * - Direct Anthropic: `"priority"` is translated into `speed: "fast"` plus the
87
+ * fast-mode beta on supported Opus models. Other tiers are ignored.
82
88
  *
83
- * The scoped values target a specific provider family and behave as the
84
- * unscoped value on the matching provider, or `undefined` everywhere else.
85
- * They let users opt into priority on one family without paying premium
86
- * costs on the other when switching models mid-session.
89
+ * Per-family scoping is expressed by {@link ServiceTierByFamily}, not by
90
+ * scoped sentinel values see {@link serviceTierFamily}.
91
+ */
92
+ export type ServiceTier = "auto" | "default" | "flex" | "scale" | "priority";
93
+ /** Provider families that expose an independent service-tier knob. */
94
+ export type ServiceTierFamily = "openai" | "anthropic" | "google";
95
+ /**
96
+ * Per-family service-tier selection. A request consults only the entry for the
97
+ * family its model belongs to (see {@link resolveModelServiceTier}), so a user
98
+ * can opt one family into priority without affecting the others when switching
99
+ * models mid-session.
100
+ */
101
+ export type ServiceTierByFamily = Partial<Record<ServiceTierFamily, ServiceTier>>;
102
+ /**
103
+ * Classify a model into the service-tier family whose knob governs it, or
104
+ * `undefined` when the model exposes no serving-priority control.
87
105
  *
88
- * - `"openai-only"` `"priority"` on `openai` and `openai-codex`; ignored elsewhere.
89
- * - `"claude-only"` `"priority"` on direct `anthropic` (not Bedrock/Vertex Claude).
106
+ * OpenRouter models are classified by id namespace (`anthropic/`, `google/`,
107
+ * `openai/`); Claude on Bedrock/Vertex (api `anthropic-messages`) is the
108
+ * anthropic family even though its provider is `amazon-bedrock`/`google-vertex`.
90
109
  */
91
- export type ServiceTier = "auto" | "default" | "flex" | "scale" | "priority" | "openai-only" | "claude-only";
92
- /** Resolved tier — one of the values that providers actually consume on the wire. */
93
- export type ResolvedServiceTier = Exclude<ServiceTier, "openai-only" | "claude-only">;
110
+ export declare function serviceTierFamily(model: Pick<Model, "provider" | "api" | "id">): ServiceTierFamily | undefined;
94
111
  /**
95
- * Resolves a possibly scoped `ServiceTier` to the effective tier for the
96
- * given provider. Scoped values match their target family and otherwise
97
- * collapse to `undefined`; unscoped values pass through unchanged.
112
+ * Reduce a per-family tier map to the single wire tier for `model` — the entry
113
+ * for the model's family, or `undefined` when the model has no family.
98
114
  */
99
- export declare function resolveServiceTier(serviceTier: ServiceTier | null | undefined, provider: Provider | undefined): ResolvedServiceTier | undefined;
115
+ export declare function resolveModelServiceTier(tiers: ServiceTierByFamily | null | undefined, model: Pick<Model, "provider" | "api" | "id">): ServiceTier | undefined;
100
116
  /**
101
- * True when the (possibly scoped) tier should be sent on the wire as the
102
- * `service_tier` request field for the given provider. OpenAI / OpenAI-Codex
103
- * accept `flex`/`scale`/`priority`; Fireworks Serverless realizes only its
104
- * Priority serving path (`service_tier: "priority"`) on the OpenAI-compatible
105
- * chat-completions endpoint. Unsupported tiers (`"auto"`, `"default"`), other
106
- * providers, and scope mismatches all return false.
117
+ * True when the tier should be sent on the wire as the provider's service-tier
118
+ * request field. OpenAI / OpenAI-Codex accept `flex`/`scale`/`priority`; Google
119
+ * (Gemini API + Vertex) and OpenRouter accept `flex`/`priority`; Fireworks
120
+ * Serverless realizes only its Priority serving path. Anthropic is absent it
121
+ * realizes `priority` via `speed: "fast"`, not a service-tier field.
107
122
  */
108
123
  export declare function shouldSendServiceTier(serviceTier: ServiceTier | null | undefined, provider: Provider | undefined): boolean;
109
124
  /**
110
- * Premium-request weight contributed by sending priority to a provider
111
- * that supports it. Mirrors GitHub Copilot's `premiumRequests` accounting
112
- * so the "premium requests" stat aggregates priority traffic across the
113
- * OpenAI family and Anthropic fast-mode realizations.
125
+ * True when `priority` will actually be realized on the wire for `model`.
126
+ * Direct Anthropic realizes fast mode; OpenAI/Google/Fireworks emit the
127
+ * service-tier field; OpenRouter realizes it only for its OpenAI- and
128
+ * Google-family upstreams. Bedrock/Vertex Claude and OpenRouter Anthropic
129
+ * models do not realize priority and return `false`.
130
+ */
131
+ export declare function realizesPriorityServiceTier(serviceTier: ServiceTier | null | undefined, model: Pick<Model, "provider" | "api" | "id">): boolean;
132
+ /**
133
+ * Premium-request weight contributed by a priority request to a provider that
134
+ * realizes it and bills extra. Mirrors GitHub Copilot's `premiumRequests`
135
+ * accounting so the "premium requests" stat aggregates priority traffic across
136
+ * the OpenAI family, direct Anthropic fast mode, and Google priority.
114
137
  *
115
- * Returns 1 per resolved priority request, 0 otherwise.
138
+ * Returns 1 only when priority is actually realized on the wire for `model`
139
+ * (see {@link realizesPriorityServiceTier}) and the provider bills it as a
140
+ * premium request. OpenRouter is excluded — it bills per its own pricing, not
141
+ * Copilot-premium semantics — as are Bedrock/Vertex Claude, where priority is
142
+ * silently dropped.
143
+ */
144
+ export declare function getPriorityPremiumRequests(serviceTier: ServiceTier | null | undefined, model: Pick<Model, "provider" | "api" | "id">): number;
145
+ /**
146
+ * Coerce a persisted service-tier value to a {@link ServiceTierByFamily}. Newer
147
+ * sessions store the family map directly; legacy sessions stored a single
148
+ * scalar — `"priority"` applied everywhere, `"openai-only"`/`"claude-only"`
149
+ * scoped to one family, and the remaining values were OpenAI-only semantics.
116
150
  */
117
- export declare function getPriorityPremiumRequests(serviceTier: ServiceTier | null | undefined, provider: Provider | undefined): number;
151
+ export declare function coerceServiceTierByFamily(value: unknown): ServiceTierByFamily | undefined;
118
152
  export interface ProviderSessionState {
119
153
  close(): void;
120
154
  }
@@ -204,6 +238,22 @@ export interface StreamOptions {
204
238
  * Providers can use this to persist transport/session state between turns.
205
239
  */
206
240
  providerSessionState?: Map<string, ProviderSessionState>;
241
+ /**
242
+ * Force Gemini model-mode Interactions API transport for providers that support it.
243
+ * When unset, those providers may still use Interactions to continue known
244
+ * server-side conversation lineage via `previousInteractionId` or stored state.
245
+ */
246
+ useInteractionsApi?: boolean;
247
+ /**
248
+ * Whether supported Interactions transports should store server-side conversation
249
+ * state and return response ids for follow-up turns. Defaults to true.
250
+ */
251
+ storeInteraction?: boolean;
252
+ /**
253
+ * Explicit Interactions response id to continue. Mutually exclusive with
254
+ * `storeInteraction: false` because the follow-up itself must be storable.
255
+ */
256
+ previousInteractionId?: string;
207
257
  /**
208
258
  * Optional per-provider concurrent request cap for LLM stream calls. Keys are
209
259
  * provider ids (`model.provider`); positive numeric values cap in-flight
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Central live healing for leaked reasoning markup in the visible text channel.
3
+ *
4
+ * Some providers emit their canonical reasoning idioms (` ```thinking `,
5
+ * `<think>`, Gemma/Harmony channels, …) into the *visible* text stream instead
6
+ * of a structured thinking part. {@link wrapLeakedThinkingStream} re-projects any
7
+ * provider stream into a fresh {@link AssistantMessageEventStream}, splitting the
8
+ * leaked fences out into proper `thinking` blocks *live* as deltas arrive — so
9
+ * every provider gets the same healing, not just the three with provider-local
10
+ * {@link StreamMarkupHealing} loops.
11
+ *
12
+ * The healing is idempotent: a second pass over already-clean text finds no
13
+ * fences, so wrapping a provider that already heals (or wrapping twice) is a
14
+ * harmless pass-through. Signatures are load-bearing for Google/Gemini/Vertex
15
+ * thought round-tripping, so text sub-blocks carry the source `textSignature`,
16
+ * forwarded thinking blocks their `thinkingSignature`, and forwarded tool calls
17
+ * their `thoughtSignature`.
18
+ *
19
+ * Modeled on {@link wrapInbandToolStream} / `InbandStreamProjector` in
20
+ * `../dialect/owned-stream.ts`, minus all in-band tool-call grammar: tool-call
21
+ * events are forwarded verbatim.
22
+ */
23
+ import { AssistantMessageEventStream } from "./event-stream";
24
+ /**
25
+ * Wrap a provider stream so leaked reasoning fences are healed into thinking
26
+ * blocks live, for every provider. Returns a new stream that re-projects the
27
+ * inner one; the inner stream is fully consumed.
28
+ */
29
+ export declare function wrapLeakedThinkingStream(inner: AssistantMessageEventStream): AssistantMessageEventStream;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-ai",
4
- "version": "16.2.5",
4
+ "version": "16.2.7",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -38,9 +38,9 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@bufbuild/protobuf": "^2.12.0",
41
- "@oh-my-pi/pi-catalog": "16.2.5",
42
- "@oh-my-pi/pi-utils": "16.2.5",
43
- "@oh-my-pi/pi-wire": "16.2.5",
41
+ "@oh-my-pi/pi-catalog": "16.2.7",
42
+ "@oh-my-pi/pi-utils": "16.2.7",
43
+ "@oh-my-pi/pi-wire": "16.2.7",
44
44
  "arktype": "^2.2.0",
45
45
  "zod": "^4"
46
46
  },