@oh-my-pi/pi-ai 18.6.3 → 18.8.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/types/auth/sqlite-credential-store.d.ts +1 -0
  3. package/dist/types/auth/store.d.ts +6 -0
  4. package/dist/types/auth-broker/remote-store.d.ts +1 -0
  5. package/dist/types/auth-broker/snapshot-cache.d.ts +12 -0
  6. package/dist/types/auth-gateway/session-state.d.ts +6 -0
  7. package/dist/types/dialect/terminator-wait.d.ts +19 -0
  8. package/dist/types/env-api-key.d.ts +21 -0
  9. package/dist/types/images/index.d.ts +2 -3
  10. package/dist/types/images/shared.d.ts +6 -0
  11. package/dist/types/index.d.ts +1 -0
  12. package/dist/types/providers/connect-frame.d.ts +44 -0
  13. package/dist/types/providers/cursor/interaction-query.d.ts +0 -2
  14. package/dist/types/providers/google-auth.d.ts +4 -1
  15. package/dist/types/providers/mock.d.ts +3 -1
  16. package/dist/types/providers/openai-responses-wire.d.ts +0 -54
  17. package/dist/types/providers/openai-shared.d.ts +4 -1
  18. package/dist/types/registry/oauth/cursor.d.ts +9 -1
  19. package/dist/types/registry/oauth/index.d.ts +2 -0
  20. package/dist/types/stream.d.ts +0 -21
  21. package/dist/types/transcription/types.d.ts +2 -1
  22. package/dist/types/types.d.ts +32 -10
  23. package/dist/types/utils/aws-profile.d.ts +5 -0
  24. package/package.json +6 -6
  25. package/src/auth/affinity.ts +33 -24
  26. package/src/auth/blocks.ts +90 -14
  27. package/src/auth/cascade.ts +1 -1
  28. package/src/auth/select.ts +27 -2
  29. package/src/auth/sqlite-credential-store.ts +85 -42
  30. package/src/auth/store.ts +6 -0
  31. package/src/auth/usage-cache.ts +16 -5
  32. package/src/auth/usage.ts +1 -1
  33. package/src/auth-broker/discover.ts +5 -4
  34. package/src/auth-broker/remote-store.ts +117 -46
  35. package/src/auth-broker/server.ts +283 -123
  36. package/src/auth-broker/snapshot-cache.ts +142 -2
  37. package/src/auth-gateway/server.ts +19 -5
  38. package/src/auth-gateway/session-state.ts +51 -9
  39. package/src/dialect/deepseek.ts +10 -2
  40. package/src/dialect/gemini.ts +8 -2
  41. package/src/dialect/hermes.ts +8 -2
  42. package/src/dialect/kimi.ts +8 -2
  43. package/src/dialect/qwen-xml.ts +8 -2
  44. package/src/dialect/qwen3.ts +8 -2
  45. package/src/dialect/terminator-wait.ts +42 -0
  46. package/src/env-api-key.ts +78 -0
  47. package/src/images/index.ts +3 -17
  48. package/src/images/openai-hosted.ts +11 -4
  49. package/src/images/openai-images.ts +19 -13
  50. package/src/images/shared.ts +10 -2
  51. package/src/index.ts +1 -0
  52. package/src/providers/anthropic.ts +39 -13
  53. package/src/providers/apple-foundation-models.ts +10 -4
  54. package/src/providers/azure-openai-responses.ts +1 -1
  55. package/src/providers/connect-frame.ts +107 -0
  56. package/src/providers/cursor/interaction-query.ts +1 -9
  57. package/src/providers/cursor.ts +87 -47
  58. package/src/providers/devin.ts +32 -41
  59. package/src/providers/gitlab-duo-workflow.ts +5 -2
  60. package/src/providers/google-auth.ts +10 -3
  61. package/src/providers/google.ts +1 -1
  62. package/src/providers/mock.ts +4 -0
  63. package/src/providers/ollama.ts +1 -1
  64. package/src/providers/openai-codex-responses.ts +49 -45
  65. package/src/providers/openai-completions.ts +1 -1
  66. package/src/providers/openai-responses-wire.ts +0 -54
  67. package/src/providers/openai-responses.ts +5 -4
  68. package/src/providers/openai-shared.ts +73 -27
  69. package/src/providers/transcriptions-server.ts +1 -1
  70. package/src/providers/transform-messages.ts +17 -13
  71. package/src/registry/aws.ts +51 -14
  72. package/src/registry/cloudflare-ai-gateway.ts +24 -1
  73. package/src/registry/hooks/env.ts +2 -5
  74. package/src/registry/oauth/cursor.ts +57 -3
  75. package/src/registry/oauth/index.ts +5 -0
  76. package/src/stream.ts +3 -72
  77. package/src/transcription/types.ts +2 -1
  78. package/src/types.ts +52 -11
  79. package/src/usage/cursor.ts +14 -25
  80. package/src/usage/minimax-code.ts +8 -1
  81. package/src/utils/aws-profile.ts +10 -4
  82. package/src/utils/thinking-loop.ts +18 -3
  83. package/src/utils.ts +22 -6
package/CHANGELOG.md CHANGED
@@ -2,6 +2,40 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.8.0] - 2026-10-07
6
+
7
+ ### Breaking Changes
8
+
9
+ - The environment API-key helpers (`getEnvApiKey`, `getEnvApiKeyName`, and `listProvidersWithEnvKey`) are no longer exported from `@oh-my-pi/pi-ai/stream`; import them from `@oh-my-pi/pi-ai` or `@oh-my-pi/pi-ai/env-api-key` instead.
10
+ - `TranscriptionRequest.audio` now accepts `Uint8Array | Blob`. Consumers must handle `Blob` values when reading transcription requests.
11
+
12
+ ### Changed
13
+
14
+ - Improved CPU and memory efficiency across streamed model responses, including Cursor, Devin, Codex, OpenAI Responses, and GitLab Duo Workflow.
15
+ - Improved request and authentication performance, including account ranking, OAuth preflight, credential rate-limit checks, credential synchronization, and auth gateway requests.
16
+ - Improved tool-call parsing performance for long calls and Apple Foundation Models requests.
17
+ - Improved Cloudflare AI Gateway request performance and AWS credential-source detection.
18
+ - Reduced memory usage when handling generated images and usage reports.
19
+
20
+ ### Fixed
21
+
22
+ - Fixed false thinking-loop detections for Gemini, DeepSeek, and Grok when responses contain repetitive code or markup such as VRML, SVG, or JSON; valid output is no longer discarded and retried.
23
+ - Fixed the Cursor provider retaining request resources after requests completed.
24
+ - Fixed session-affinity pins growing without bound in long-lived gateways; pins are now capped at 256 sessions per provider.
25
+ - Fixed Anthropic sessions failing every request with HTTP 400 ("role 'system' must precede an 'assistant' message") after a tool change coincided with compaction or an interrupted or failed reply; sessions already stuck this way recover on the next message ([#14746](https://github.com/can1357/oh-my-pi/issues/14746)).
26
+
27
+ ## [18.7.0] - 2026-10-06
28
+
29
+ ### Added
30
+
31
+ - Added `getOAuthCredentialProvider()` to resolve login aliases, such as `openai-codex-device`, to the provider where their credentials are stored.
32
+
33
+ ### Fixed
34
+
35
+ - Fixed Ultrafast service-tier billing and usage accounting: GPT-6 Astra now applies its published premium rates—6× on the OpenAI API and 8× included usage on Codex—and is counted toward the premium-request limit.
36
+ - Fixed Vertex AI authentication on Windows when credentials are created with `gcloud auth application-default login`.
37
+ - Fixed selecting Cursor accounts by email through `auth.accountPolicies` and `/session pin`; newly refreshed and existing accounts now retain the account email.
38
+
5
39
  ## [18.6.3] - 2026-10-06
6
40
 
7
41
  ### Added
@@ -60,6 +60,7 @@ export declare class SqliteAuthCredentialStore implements AuthCredentialStore {
60
60
  deleteCachePrefix(prefix: string): void;
61
61
  cleanExpiredCache(): void;
62
62
  getCredentialBlock(credentialId: number, providerKey: string, blockScope: string): number | undefined;
63
+ getCredentialBlockScopes(credentialId: number, providerKey: string): Map<string, number>;
63
64
  getCredentialBlockReconcileAfter(credentialId: number, providerKey: string, blockScope: string): number | undefined;
64
65
  upsertCredentialBlock(block: StoredCredentialBlock): void;
65
66
  deleteCredentialBlock(credentialId: number, providerKey: string, blockScope: string): void;
@@ -71,6 +71,12 @@ export interface CredentialCacheStore {
71
71
  export interface CredentialBlockStore {
72
72
  /** Non-expired block for one (credential, providerKey, scope) key, or undefined. */
73
73
  getCredentialBlock(credentialId: number, providerKey: string, blockScope: string): number | undefined;
74
+ /**
75
+ * Non-expired blocks for one credential and providerKey, keyed by block
76
+ * scope (`""` is unscoped), in one read. Optional: selectors fall back to
77
+ * {@link CredentialBlockStore.getCredentialBlock} per scope when absent.
78
+ */
79
+ getCredentialBlockScopes?(credentialId: number, providerKey: string): ReadonlyMap<string, number>;
74
80
  /** Earliest time a shared-store block should be eligible for live-usage reconciliation. */
75
81
  getCredentialBlockReconcileAfter(credentialId: number, providerKey: string, blockScope: string): number | undefined;
76
82
  /** Upsert with MAX semantics: keep the later blockedUntilMs on conflict. */
@@ -73,6 +73,7 @@ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
73
73
  /** Broker-backed disabled tombstones; empty against brokers predating the endpoint. */
74
74
  listDisabledCredentials(provider?: string, signal?: AbortSignal): Promise<DisabledCredentialSummary[]>;
75
75
  getCredentialBlock(credentialId: number, providerKey: string, blockScope: string): number | undefined;
76
+ getCredentialBlockScopes(credentialId: number, providerKey: string): Map<string, number>;
76
77
  getCredentialBlockReconcileAfter(credentialId: number, providerKey: string, blockScope: string): number | undefined;
77
78
  listCredentialBlocks(credentialIds: readonly number[]): StoredCredentialBlock[];
78
79
  upsertCredentialBlock(block: StoredCredentialBlock): void;
@@ -15,3 +15,15 @@ export interface WriteAuthBrokerSnapshotCacheOptions {
15
15
  }
16
16
  export declare function readAuthBrokerSnapshotCache(opts: ReadAuthBrokerSnapshotCacheOptions): Promise<SnapshotResponse | null>;
17
17
  export declare function writeAuthBrokerSnapshotCache(opts: WriteAuthBrokerSnapshotCacheOptions): Promise<void>;
18
+ /**
19
+ * Fire-and-forget cache write for snapshot callbacks. The first snapshot after
20
+ * a quiet period is written immediately; later ones within
21
+ * {@link WRITE_COALESCE_MS} collapse into a single trailing write of the
22
+ * newest. A snapshot whose generation and credential content match the last
23
+ * write is skipped (see {@link UNCHANGED_REWRITE_MS}). Pending writes are
24
+ * flushed on process shutdown and by {@link flushAuthBrokerSnapshotCacheWrites};
25
+ * failures are logged, never thrown.
26
+ */
27
+ export declare function scheduleAuthBrokerSnapshotCacheWrite(opts: WriteAuthBrokerSnapshotCacheOptions): void;
28
+ /** Write every pending scheduled snapshot now and wait for in-flight writes to settle. */
29
+ export declare function flushAuthBrokerSnapshotCacheWrites(): Promise<void>;
@@ -63,6 +63,12 @@ export interface AuthGatewaySessionStateRequest {
63
63
  * continues.
64
64
  */
65
65
  context: Context;
66
+ /**
67
+ * `JSON.stringify(context.tools)` when the caller already serialized it
68
+ * (the gateway derives its `sessionId` from the same string). Recomputed
69
+ * from `context` when absent.
70
+ */
71
+ toolsJson?: string;
66
72
  /**
67
73
  * Stable identity of the account this request's credential resolved to.
68
74
  * A change means the gateway switched the session to a sibling credential,
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Fast path for in-band scanners that sit inside a body waiting for one fixed
3
+ * terminator (a tool-call close tag) and emit nothing until it arrives.
4
+ *
5
+ * Appending each delta to the scanner's string buffer and calling `indexOf` on
6
+ * it flattens the growing rope on every delta, so a long in-band tool call cost
7
+ * O(n²) copying and scanning. While armed, deltas are set aside and only the new
8
+ * text plus the terminator-length overlap with what came before is searched;
9
+ * the buffer is rebuilt once, when the terminator shows up or the stream ends.
10
+ */
11
+ export declare class TerminatorWait {
12
+ #private;
13
+ /** Start deferring; `buffered` is the scanner's pending body, known not to contain `terminator`. */
14
+ arm(terminator: string, buffered: string): void;
15
+ /** Take `text` while the terminator is still absent; false means the caller must {@link release} and scan. */
16
+ absorb(text: string): boolean;
17
+ /** Stop deferring and return `buffered` with every absorbed delta appended. */
18
+ release(buffered: string): string;
19
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Get API key for provider from known environment variables, e.g. OPENAI_API_KEY.
3
+ *
4
+ * Will not return API keys for providers that require OAuth tokens.
5
+ * Checks Bun.env, then cwd/.env, then ~/.env.
6
+ */
7
+ export declare function getEnvApiKey(provider: string): string | undefined;
8
+ /**
9
+ * Name of the environment variable that backs `getEnvApiKey` for a provider,
10
+ * when that provider maps to a single named variable (e.g. `github-copilot` →
11
+ * `COPILOT_GITHUB_TOKEN`). Returns undefined for providers whose env fallback
12
+ * is computed (multi-var pickers, Vertex ADC / Bedrock probes, …) since no
13
+ * single variable name describes the source.
14
+ */
15
+ export declare function getEnvApiKeyName(provider: string): string | undefined;
16
+ /**
17
+ * Enumerate every provider that has an env-var fallback for `getEnvApiKey`.
18
+ * Used by `omp auth-broker migrate --include-env` to discover env-sourced keys
19
+ * that should be uploaded to the broker.
20
+ */
21
+ export declare function listProvidersWithEnvKey(): string[];
@@ -1,4 +1,4 @@
1
- import type { Api, Model } from "@oh-my-pi/pi-catalog/types";
1
+ import { type Api, type ImageGenerationApi, type Model } from "@oh-my-pi/pi-catalog/types";
2
2
  import type { ImageGenerationOptions, ImageGenerationRequest, ImageGenerationResult } from "./types.js";
3
3
  export * from "./google-antigravity.js";
4
4
  export * from "./google-generative-ai.js";
@@ -6,8 +6,7 @@ export * from "./openai-hosted.js";
6
6
  export * from "./openai-images.js";
7
7
  export * from "./openrouter-images.js";
8
8
  export * from "./types.js";
9
- /** Catalog APIs {@link generateImage} serves; the hosted Responses pair needs an explicit carrier model. */
10
- export type ImageGenerationApi = "openai-images" | "openrouter-images" | "google-generative-ai" | "google-gemini-cli" | "openai-responses" | "openai-codex-responses";
9
+ export type { ImageGenerationApi } from "@oh-my-pi/pi-catalog/types";
11
10
  /** Whether a catalog API generates images through one of the pi-ai image clients. */
12
11
  export declare function isImageGenerationApi(api: Api): api is ImageGenerationApi;
13
12
  /** Generate (or edit, when `request.inputImages` is set) images through the transport selected by the model's `api`. */
@@ -32,6 +32,12 @@ export declare function decodeImageResponse(value: unknown, fetch: FetchImpl, si
32
32
  images: GeneratedImage[];
33
33
  usage: Usage;
34
34
  }>;
35
+ /**
36
+ * Mime type of a base64 image, read from its header only. 64 base64 chars
37
+ * decode to 48 bytes, past every magic number `parseImageMetadata` checks, so
38
+ * multi-MB payloads are never fully decoded just to be labelled.
39
+ */
40
+ export declare function sniffBase64ImageMimeType(base64: string): string | undefined;
35
41
  export declare function toDataUrl(image: GeneratedImage): string;
36
42
  export declare function resolveOpenAIImageSize(aspectRatio?: string, imageSize?: string): string | undefined;
37
43
  export {};
@@ -39,6 +39,7 @@ export type * from "./providers/openai-responses.js";
39
39
  export type * from "./providers/synthetic.js";
40
40
  export * from "./registry/index.js";
41
41
  export { resolveCacheRetention } from "./utils.js";
42
+ export * from "./env-api-key.js";
42
43
  export * from "./stream.js";
43
44
  export * from "./types.js";
44
45
  export * from "./usage.js";
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Connect-protocol streaming envelope shared by the Cursor and Devin
3
+ * transports: 1 flag byte + 4-byte big-endian payload length + payload.
4
+ */
5
+ /** Flag bit: payload is compressed with the negotiated encoding (gzip). */
6
+ export declare const CONNECT_COMPRESSED_FLAG = 1;
7
+ /** Flag bit: payload is the end-of-stream JSON trailer. */
8
+ export declare const CONNECT_END_STREAM_FLAG = 2;
9
+ /** Wrap one Connect-protocol message: 1 flag byte + 4-byte big-endian length + payload. */
10
+ export declare function frameConnectMessage(data: Uint8Array, flags?: number): Buffer;
11
+ /** One decoded Connect envelope. */
12
+ export interface ConnectFrame {
13
+ flags: number;
14
+ payload: Buffer;
15
+ }
16
+ /** Options for {@link ConnectFrameDecoder}. */
17
+ export interface ConnectFrameDecoderOptions {
18
+ /**
19
+ * Payload cap: a length prefix above `maxPayloadBytes` throws `error(length)`
20
+ * before any of that payload is buffered. Uncapped when omitted.
21
+ */
22
+ limit?: {
23
+ maxPayloadBytes: number;
24
+ error: (length: number) => Error;
25
+ };
26
+ }
27
+ /**
28
+ * Incremental Connect frame decoder. Incoming chunks are kept as-is and a frame
29
+ * spanning several chunks is joined once, when the length the header announced
30
+ * has fully arrived — re-concatenating the pending bytes on every chunk made a
31
+ * multi-MB frame cost O(size × chunks).
32
+ *
33
+ * Payloads alias the chunk they came from whenever a frame fits in one chunk,
34
+ * so callers must not reuse chunk buffers they hand in.
35
+ */
36
+ export declare class ConnectFrameDecoder {
37
+ #private;
38
+ constructor(options?: ConnectFrameDecoderOptions);
39
+ /**
40
+ * Buffer `chunk` (if any) and yield every frame now complete, in wire order.
41
+ * An oversize length prefix throws after the frames that precede it.
42
+ */
43
+ decode(chunk?: Uint8Array): Generator<ConnectFrame, void, undefined>;
44
+ }
@@ -7,8 +7,6 @@ type ProtoUnknownField = {
7
7
  interface CursorInteractionWriter {
8
8
  write(frame: Uint8Array): void;
9
9
  }
10
- /** Wrap one Connect-protocol message: 1 flag byte + 4-byte big-endian length + payload. */
11
- export declare function frameConnectMessage(data: Uint8Array, flags?: number): Buffer;
12
10
  /** Well-formed protobuf-es `$unknown` entries on `message`; anything else on the bag is ignored. */
13
11
  export declare function protoUnknownFields(message: object): ProtoUnknownField[];
14
12
  /**
@@ -5,13 +5,16 @@
5
5
  * Sources, in priority order:
6
6
  * 1. `GOOGLE_APPLICATION_CREDENTIALS` env → file with `type: "service_account"` (RS256 JWT exchange)
7
7
  * or `type: "authorized_user"` (refresh-token exchange).
8
- * 2. `~/.config/gcloud/application_default_credentials.json` (user ADC, same authorized_user flow).
8
+ * 2. gcloud user ADC: `%APPDATA%\gcloud\application_default_credentials.json` on Windows,
9
+ * `~/.config/gcloud/application_default_credentials.json` elsewhere (authorized_user flow).
9
10
  * 3. GCE / Cloud Run metadata server (`metadata.google.internal`).
10
11
  *
11
12
  * Tokens are cached per source key and refreshed `GOOGLE_VERTEX_REFRESH_SKEW_MS` before expiry
12
13
  * (default 60s). Concurrent callers waiting on a refresh share the same in-flight promise.
13
14
  */
14
15
  import type { FetchImpl } from "../types.js";
16
+ /** gcloud's user ADC file: `%APPDATA%\gcloud\…` on Windows, `~/.config/gcloud/…` elsewhere. */
17
+ export declare function userAdcPath(platform?: typeof process.platform, appData?: string | undefined): string;
15
18
  /**
16
19
  * Returns a Bearer access token suitable for the `Authorization` header on Vertex AI calls.
17
20
  * The token is cached in module scope and refreshed `GOOGLE_VERTEX_REFRESH_SKEW_MS` ms before it expires.
@@ -41,7 +41,7 @@
41
41
  * // Inspect calls afterwards.
42
42
  * expect(mock.calls).toHaveLength(2);
43
43
  */
44
- import type { AnthropicFallbackCreditHandle, Api, Context, Model, SimpleStreamOptions, StopDetails, StopReason, Usage } from "../types.js";
44
+ import type { AnthropicFallbackCreditHandle, Api, Context, Model, ServiceTier, SimpleStreamOptions, StopDetails, StopReason, Usage } from "../types.js";
45
45
  import { AssistantMessageEventStream } from "../utils/event-stream.js";
46
46
  /** The API string this provider serves. */
47
47
  export declare const MOCK_API: "mock";
@@ -78,6 +78,8 @@ export interface MockResponse {
78
78
  usage?: Partial<Omit<Usage, "cost">> & {
79
79
  cost?: Partial<Usage["cost"]>;
80
80
  };
81
+ /** Service tier the mock reports serving the turn, as a real provider's response echo would. */
82
+ serviceTier?: ServiceTier;
81
83
  /** Pre-set responseId. */
82
84
  responseId?: string;
83
85
  /** If set, the stream emits a terminal error event instead of completing. */
@@ -906,60 +906,6 @@ export declare namespace Response {
906
906
  */
907
907
  type: "error";
908
908
  }
909
- /**
910
- * A moderation result produced for the response input or output.
911
- */
912
- interface ModerationResult {
913
- /**
914
- * A dictionary of moderation categories to booleans, True if the input is flagged
915
- * under this category.
916
- */
917
- categories: {
918
- [key: string]: boolean;
919
- };
920
- /**
921
- * Which modalities of input are reflected by the score for each category.
922
- */
923
- category_applied_input_types: {
924
- [key: string]: Array<"text" | "image">;
925
- };
926
- /**
927
- * A dictionary of moderation categories to scores.
928
- */
929
- category_scores: {
930
- [key: string]: number;
931
- };
932
- /**
933
- * A boolean indicating whether the content was flagged by any category.
934
- */
935
- flagged: boolean;
936
- /**
937
- * The moderation model that produced this result.
938
- */
939
- model: string;
940
- /**
941
- * The object type, which was always `moderation_result` for successful moderation
942
- * results.
943
- */
944
- type: "moderation_result";
945
- }
946
- /**
947
- * An error produced while attempting moderation for the response input or output.
948
- */
949
- interface Error {
950
- /**
951
- * The error code.
952
- */
953
- code: string;
954
- /**
955
- * The error message.
956
- */
957
- message: string;
958
- /**
959
- * The object type, which was always `error` for moderation failures.
960
- */
961
- type: "error";
962
- }
963
909
  }
964
910
  }
965
911
  /**
@@ -76,8 +76,11 @@ export declare function applyOpenAIServiceTier(params: {
76
76
  * resolved request tier. Scoped to `provider: "openai"` (the only standard
77
77
  * Responses biller) so an echoed `service_tier` from an Azure/OpenRouter/Copilot
78
78
  * proxy can never skew those costs.
79
+ *
80
+ * Returns the tier the turn ran on for the caller to record on the message, and
81
+ * counts the premium request the tier bills.
79
82
  */
80
- export declare function applyOpenAIResponsesServiceTierCost(model: Pick<Model, "provider" | "serviceTierCost">, usage: AssistantMessage["usage"], responseServiceTier: unknown, requestServiceTier: ServiceTier | null | undefined): void;
83
+ export declare function applyOpenAIResponsesServiceTierCost(model: Pick<Model, "provider" | "serviceTierCost" | "api" | "identity">, usage: AssistantMessage["usage"], responseServiceTier: unknown, requestServiceTier: ServiceTier | null | undefined): ServiceTier | undefined;
81
84
  /**
82
85
  * Reconcile token-price estimates with a gateway's authoritative account charge.
83
86
  * BYOK turns (`is_byok: true`) price from the provider spend in
@@ -1,3 +1,4 @@
1
+ import type { FetchImpl } from "../../types.js";
1
2
  import type { OAuthController, OAuthCredentials } from "./types.js";
2
3
  export interface CursorAuthParams {
3
4
  verifier: string;
@@ -13,6 +14,13 @@ export declare function pollCursorAuth(uuid: string, verifier: string): Promise<
13
14
  export declare function loginCursor(onAuthUrl: (url: string) => void, onPollStart?: () => void): Promise<OAuthCredentials>;
14
15
  export declare function loginCursorHook(callbacks: OAuthController): Promise<OAuthCredentials>;
15
16
  export declare function refreshCursorToken(apiKeyOrRefreshToken: string): Promise<OAuthCredentials>;
16
- export declare function refreshCursorHook(credentials: OAuthCredentials): Promise<OAuthCredentials>;
17
+ export declare function refreshCursorHook(credentials: OAuthCredentials, signal?: AbortSignal): Promise<OAuthCredentials>;
18
+ /** Request headers that present `accessToken` to cursor.com as its user's web session. */
19
+ export declare function cursorSessionHeaders(userId: string, accessToken: string): Record<string, string>;
20
+ /**
21
+ * Email of the Cursor account that owns `accessToken`, read from its cursor.com
22
+ * profile. Undefined when the token names no user or the profile names another.
23
+ */
24
+ export declare function fetchCursorAccountEmail(accessToken: string, fetchImpl?: FetchImpl, signal?: AbortSignal): Promise<string | undefined>;
17
25
  export declare function extractCursorAccessTokenUserId(accessToken: string): string | undefined;
18
26
  export declare function isCursorTokenExpiringSoon(token: string, thresholdSeconds?: number): boolean;
@@ -43,3 +43,5 @@ export declare function getOAuthApiKey(provider: OAuthProvider, credentials: Rec
43
43
  * Get list of OAuth providers.
44
44
  */
45
45
  export declare function getOAuthProviders(): OAuthProviderInfo[];
46
+ /** Provider id that stores `providerId`'s credentials: login aliases (`openai-codex-device`) map to their target (`openai-codex`). */
47
+ export declare function getOAuthCredentialProvider(providerId: string): string;
@@ -31,27 +31,6 @@ export declare const __providerInFlightForTesting: {
31
31
  captureStaleLockRelease(provider: string): Promise<(() => Promise<void>) | null>;
32
32
  captureLockDirRelease(provider: string): Promise<(() => Promise<void>) | null>;
33
33
  };
34
- /**
35
- * Get API key for provider from known environment variables, e.g. OPENAI_API_KEY.
36
- *
37
- * Will not return API keys for providers that require OAuth tokens.
38
- * Checks Bun.env, then cwd/.env, then ~/.env.
39
- */
40
- export declare function getEnvApiKey(provider: string): string | undefined;
41
- /**
42
- * Name of the environment variable that backs `getEnvApiKey` for a provider,
43
- * when that provider maps to a single named variable (e.g. `github-copilot` →
44
- * `COPILOT_GITHUB_TOKEN`). Returns undefined for providers whose env fallback
45
- * is computed (multi-var pickers, Vertex ADC / Bedrock probes, …) since no
46
- * single variable name describes the source.
47
- */
48
- export declare function getEnvApiKeyName(provider: string): string | undefined;
49
- /**
50
- * Enumerate every provider that has an env-var fallback for `getEnvApiKey`.
51
- * Used by `omp auth-broker migrate --include-env` to discover env-sourced keys
52
- * that should be uploaded to the broker.
53
- */
54
- export declare function listProvidersWithEnvKey(): string[];
55
34
  export declare function stream<TApi extends Api>(model: Model<TApi>, context: Context, options?: OptionsForApi<TApi>): AssistantMessageEventStream;
56
35
  export declare function complete<TApi extends Api>(model: Model<TApi>, context: Context, options?: OptionsForApi<TApi>): Promise<AssistantMessage>;
57
36
  export declare function streamSimple<TApi extends Api>(model: Model<TApi>, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream;
@@ -2,7 +2,8 @@ import type { Usage } from "@oh-my-pi/pi-catalog/types";
2
2
  export type TranscriptionResponseFormat = "json" | "verbose_json";
3
3
  export type TranscriptionTimestampGranularity = "word" | "segment";
4
4
  export interface TranscriptionRequest {
5
- audio: Uint8Array;
5
+ /** Audio bytes. A `Blob`/`File` (e.g. a parsed multipart upload) is sent without copying. */
6
+ audio: Uint8Array | Blob;
6
7
  mimeType: string;
7
8
  fileName?: string;
8
9
  language?: string;
@@ -157,18 +157,31 @@ export declare function shouldSendServiceTier(serviceTier: ServiceTier | null |
157
157
  */
158
158
  export declare function realizesPriorityServiceTier(serviceTier: ServiceTier | null | undefined, model: ServiceTierModel): boolean;
159
159
  /**
160
- * Premium-request weight contributed by a priority request to a provider that
161
- * realizes it and bills extra. Mirrors GitHub Copilot's `premiumRequests`
162
- * accounting so the "premium requests" stat aggregates priority traffic across
163
- * the OpenAI family, direct Anthropic fast mode, and Google priority.
160
+ * Premium-request weight contributed by a request a provider bills above
161
+ * standard. Priority (Fast mode) counts 1 on every provider that realizes it;
162
+ * `ultrafast` counts 1 on the OpenAI family, where it is a premium serving tier
163
+ * (its cost premium is recorded separately in `usage.cost`). Mirrors GitHub
164
+ * Copilot's `premiumRequests` accounting so the "premium requests" stat
165
+ * aggregates premium traffic across the OpenAI family, direct Anthropic fast
166
+ * mode, and Google priority.
164
167
  *
165
- * Returns 1 only when priority is actually realized on the wire for `model`
166
- * (see {@link realizesPriorityServiceTier}) and the provider bills it as a
167
- * premium request. OpenRouter is excluded — it bills per its own pricing, not
168
- * Copilot-premium semantics — as are Bedrock/Vertex Claude, where priority is
169
- * silently dropped.
168
+ * Returns 1 only when the tier is actually realized on the wire for `model`
169
+ * (see {@link realizesPriorityServiceTier} and {@link shouldSendServiceTier})
170
+ * and the provider bills it as a premium request. OpenRouter is excluded — it
171
+ * bills per its own pricing, not Copilot-premium semantics — as are
172
+ * Bedrock/Vertex Claude, where priority is silently dropped.
173
+ *
174
+ * Pass `served: true` when the tier is the one the provider reported serving
175
+ * (an assistant message's {@link AssistantMessage.serviceTier}) rather than a
176
+ * requested setting: realization is then already proven, so the wire gate is
177
+ * skipped and a model without discovery metadata (a stats-backfill row) still
178
+ * counts.
170
179
  */
171
- export declare function getPriorityPremiumRequests(serviceTier: ServiceTier | null | undefined, model: ServiceTierModel): number;
180
+ export declare function getPremiumServiceTierRequests(serviceTier: ServiceTier | null | undefined, model: ServiceTierModel, options?: {
181
+ served?: boolean;
182
+ }): number;
183
+ /** Parse a provider-reported `service_tier` echo into a known tier, or `undefined` for anything else. */
184
+ export declare function parseServiceTier(value: unknown): ServiceTier | undefined;
172
185
  /**
173
186
  * Coerce a persisted service-tier value to a {@link ServiceTierByFamily}. Newer
174
187
  * sessions store the family map directly; legacy sessions stored a single
@@ -965,6 +978,15 @@ export interface AssistantMessage {
965
978
  * other than what was requested.
966
979
  */
967
980
  upstreamModel?: string;
981
+ /**
982
+ * Service tier the provider reported serving this turn, when the API echoes
983
+ * one (`response.service_tier`), falling back to the tier the request carried
984
+ * when the response omits the echo. Absent when the provider reports no tier
985
+ * or the echo cannot be trusted (proxies). This is the tier the turn actually
986
+ * ran on, which is what cost, premium-request, and speed accounting key on —
987
+ * the session's live setting may already have changed.
988
+ */
989
+ serviceTier?: ServiceTier;
968
990
  usage: Usage;
969
991
  stopReason: StopReason;
970
992
  stopDetails?: StopDetails | null;
@@ -9,6 +9,11 @@ export declare function resolveAwsProfile(profile?: string): string;
9
9
  * the AWS SDK's `AWS_SDK_LOAD_CONFIG` opt-in.
10
10
  */
11
11
  export declare function shouldLoadAwsSharedConfig(profile?: string): boolean;
12
+ /** Shared credentials and config file locations, honoring their env overrides. */
13
+ export declare function awsSharedFilePaths(): {
14
+ credentialsPath: string;
15
+ configPath: string;
16
+ };
12
17
  export declare function resolveAwsProfileRegion(profile?: string): string | undefined;
13
18
  /** Region selected by the environment or active shared-config profile. */
14
19
  export declare function resolveAwsAmbientRegion(profile?: string): string | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-ai",
3
- "version": "18.6.3",
3
+ "version": "18.8.0",
4
4
  "description": "Unified LLM API with automatic model discovery and provider configuration",
5
5
  "keywords": [
6
6
  "ai",
@@ -155,11 +155,11 @@
155
155
  "fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
156
156
  },
157
157
  "dependencies": {
158
- "@oh-my-pi/omptype": "18.6.3",
159
- "@oh-my-pi/pi-catalog": "18.6.3",
160
- "@oh-my-pi/pi-natives": "18.6.3",
161
- "@oh-my-pi/pi-utils": "18.6.3",
162
- "@oh-my-pi/pi-wire": "18.6.3"
158
+ "@oh-my-pi/omptype": "18.8.0",
159
+ "@oh-my-pi/pi-catalog": "18.8.0",
160
+ "@oh-my-pi/pi-natives": "18.8.0",
161
+ "@oh-my-pi/pi-utils": "18.8.0",
162
+ "@oh-my-pi/pi-wire": "18.8.0"
163
163
  },
164
164
  "devDependencies": {
165
165
  "@types/bun": "^1.3.14"