@oh-my-pi/pi-ai 18.7.0 → 18.8.1

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 (73) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/types/auth/affinity.d.ts +28 -3
  3. package/dist/types/auth/cascade.d.ts +12 -0
  4. package/dist/types/auth/sqlite-credential-store.d.ts +7 -0
  5. package/dist/types/auth/store.d.ts +6 -0
  6. package/dist/types/auth/types.d.ts +26 -0
  7. package/dist/types/auth-broker/remote-store.d.ts +1 -0
  8. package/dist/types/auth-broker/snapshot-cache.d.ts +12 -0
  9. package/dist/types/auth-gateway/session-state.d.ts +6 -0
  10. package/dist/types/auth-storage.d.ts +4 -4
  11. package/dist/types/dialect/terminator-wait.d.ts +19 -0
  12. package/dist/types/env-api-key.d.ts +21 -0
  13. package/dist/types/images/shared.d.ts +6 -0
  14. package/dist/types/index.d.ts +1 -0
  15. package/dist/types/providers/connect-frame.d.ts +44 -0
  16. package/dist/types/providers/cursor/interaction-query.d.ts +0 -2
  17. package/dist/types/stream.d.ts +0 -21
  18. package/dist/types/transcription/types.d.ts +2 -1
  19. package/dist/types/utils/aws-profile.d.ts +5 -0
  20. package/package.json +6 -6
  21. package/src/auth/affinity.ts +115 -34
  22. package/src/auth/blocks.ts +90 -14
  23. package/src/auth/cascade.ts +31 -3
  24. package/src/auth/oauth.ts +4 -3
  25. package/src/auth/rotation.ts +8 -2
  26. package/src/auth/select.ts +32 -4
  27. package/src/auth/sqlite-credential-store.ts +91 -42
  28. package/src/auth/store.ts +6 -0
  29. package/src/auth/types.ts +27 -0
  30. package/src/auth/usage-cache.ts +16 -5
  31. package/src/auth/usage.ts +1 -1
  32. package/src/auth-broker/discover.ts +5 -4
  33. package/src/auth-broker/remote-store.ts +117 -46
  34. package/src/auth-broker/server.ts +283 -123
  35. package/src/auth-broker/snapshot-cache.ts +142 -2
  36. package/src/auth-gateway/server.ts +19 -5
  37. package/src/auth-gateway/session-state.ts +51 -9
  38. package/src/auth-storage.ts +12 -6
  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/openai-hosted.ts +11 -4
  48. package/src/images/openai-images.ts +19 -13
  49. package/src/images/shared.ts +10 -2
  50. package/src/index.ts +1 -0
  51. package/src/providers/anthropic.ts +39 -13
  52. package/src/providers/apple-foundation-models.ts +10 -4
  53. package/src/providers/azure-openai-responses.ts +1 -1
  54. package/src/providers/connect-frame.ts +107 -0
  55. package/src/providers/cursor/interaction-query.ts +1 -9
  56. package/src/providers/cursor.ts +87 -47
  57. package/src/providers/devin.ts +32 -41
  58. package/src/providers/gitlab-duo-workflow.ts +5 -2
  59. package/src/providers/google.ts +1 -1
  60. package/src/providers/ollama.ts +1 -1
  61. package/src/providers/openai-codex-responses.ts +46 -27
  62. package/src/providers/openai-completions.ts +1 -1
  63. package/src/providers/openai-responses.ts +5 -4
  64. package/src/providers/openai-shared.ts +54 -19
  65. package/src/providers/transcriptions-server.ts +1 -1
  66. package/src/providers/transform-messages.ts +17 -13
  67. package/src/registry/aws.ts +51 -14
  68. package/src/registry/cloudflare-ai-gateway.ts +24 -1
  69. package/src/stream.ts +3 -72
  70. package/src/transcription/types.ts +2 -1
  71. package/src/utils/aws-profile.ts +10 -4
  72. package/src/utils/thinking-loop.ts +18 -3
  73. package/src/utils.ts +22 -6
package/CHANGELOG.md CHANGED
@@ -2,6 +2,39 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [18.8.1] - 2026-10-07
6
+
7
+ ### Added
8
+
9
+ - Added session restrictions for OAuth account pools via `AuthStorage.sessions.restrict`, limiting selection, fallback, rotation, and authentication to specified accounts until the returned lease is released with `sessions.unrestrict`. API keys and other accounts are not used when a session is restricted.
10
+ - Exported `resolveCredentialIdentityKey` for determining the identity key used to match credentials with broker account pools and session restrictions.
11
+
12
+ ### Fixed
13
+
14
+ - Fixed Codex Fast (`priority`) and Ultrafast usage being recorded, billed, and reported as Standard when the backend echoed a default service tier; the requested tier is now preserved in usage and performance records.
15
+
16
+ ## [18.8.0] - 2026-10-07
17
+
18
+ ### Breaking Changes
19
+
20
+ - 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.
21
+ - `TranscriptionRequest.audio` now accepts `Uint8Array | Blob`. Consumers must handle `Blob` values when reading transcription requests.
22
+
23
+ ### Changed
24
+
25
+ - Improved CPU and memory efficiency across streamed model responses, including Cursor, Devin, Codex, OpenAI Responses, and GitLab Duo Workflow.
26
+ - Improved request and authentication performance, including account ranking, OAuth preflight, credential rate-limit checks, credential synchronization, and auth gateway requests.
27
+ - Improved tool-call parsing performance for long calls and Apple Foundation Models requests.
28
+ - Improved Cloudflare AI Gateway request performance and AWS credential-source detection.
29
+ - Reduced memory usage when handling generated images and usage reports.
30
+
31
+ ### Fixed
32
+
33
+ - 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.
34
+ - Fixed the Cursor provider retaining request resources after requests completed.
35
+ - Fixed session-affinity pins growing without bound in long-lived gateways; pins are now capped at 256 sessions per provider.
36
+ - 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)).
37
+
5
38
  ## [18.7.0] - 2026-10-06
6
39
 
7
40
  ### Added
@@ -1,4 +1,4 @@
1
- import type { AuthCredential, OAuthCredential, SessionsApi } from "./types.js";
1
+ import type { AuthCredential, OAuthCredential, SessionRestrictionLease, SessionsApi } from "./types.js";
2
2
  import type { AuthCredentialStore } from "./store.js";
3
3
  import type { CredentialPool } from "./pool.js";
4
4
  import type { KeyOverrides } from "./cascade.js";
@@ -13,10 +13,30 @@ export type SessionCredential = {
13
13
  /** Set only by the public user-facing pin API; automatic warm affinity leaves it absent. */
14
14
  explicit?: true;
15
15
  };
16
+ /** One installed restriction: the allowed OAuth identity keys and the lease that lifts it. */
17
+ type SessionRestriction = {
18
+ readonly allowed: ReadonlySet<string>;
19
+ readonly lease: SessionRestrictionLease;
20
+ };
21
+ /**
22
+ * Provider → session id → installed restriction. Owned by `AuthStorage` so
23
+ * restrictions outlive store replacement, which rebuilds every store-bound
24
+ * module (pins included) around the same identities.
25
+ */
26
+ export type SessionRestrictions = Map<string, Map<string, SessionRestriction>>;
16
27
  /** Session → credential affinity (pins), persisted in the store cache. */
17
28
  export declare class SessionAffinity implements SessionsApi {
18
29
  #private;
19
- constructor(store: AuthCredentialStore, pool: CredentialPool, overrides: KeyOverrides);
30
+ constructor(store: AuthCredentialStore, pool: CredentialPool, overrides: KeyOverrides, restrictions: SessionRestrictions);
31
+ restrict(provider: string, sessionId: string, identityKeys: readonly string[]): SessionRestrictionLease;
32
+ unrestrict(provider: string, sessionId: string, lease: SessionRestrictionLease): void;
33
+ /** True when {@link restrict} limits `sessionId` for `provider`. */
34
+ isRestricted(provider: string, sessionId: string | undefined): boolean;
35
+ /**
36
+ * True when `credential` may serve `sessionId`: always for an unrestricted
37
+ * session, otherwise only an OAuth credential whose identity key is allowed.
38
+ */
39
+ allows(provider: string, sessionId: string | undefined, credential: AuthCredential): boolean;
20
40
  /** Drop every pin for a provider, both in memory and in the persisted cache. */
21
41
  clearProvider(provider: string): void;
22
42
  /** Drop only this in-memory session pin after OAuth selection falls through. */
@@ -33,7 +53,11 @@ export declare class SessionAffinity implements SessionsApi {
33
53
  * rewrites were pure database churn.
34
54
  */
35
55
  record(provider: string, sessionId: string | undefined, type: AuthCredential["type"], index: number, lastUsedAtMs?: number, explicit?: boolean): void;
36
- /** Retrieves the last credential used by a session. */
56
+ /**
57
+ * Retrieves the last credential used by a session. A restricted session
58
+ * never sees a pin outside its allowlist — inherited, restored, or recorded
59
+ * before the restriction — so it re-ranks inside the allowlist instead.
60
+ */
37
61
  get(provider: string, sessionId: string | undefined): SessionCredential | undefined;
38
62
  /** Clears the last credential used by a session for a provider. */
39
63
  clear(provider: string, sessionId: string | undefined): void;
@@ -71,3 +95,4 @@ export declare class SessionAffinity implements SessionsApi {
71
95
  */
72
96
  release(provider: string, sessionId: string): boolean;
73
97
  }
98
+ export {};
@@ -8,6 +8,14 @@ export declare class KeyOverrides {
8
8
  #private;
9
9
  constructor(resolver?: (config: string) => Promise<string | undefined>);
10
10
  has(provider: string): boolean;
11
+ /**
12
+ * Whether an override replaces OAuth for a session. Any override does for an
13
+ * unrestricted session. A restricted session skips the runtime key, but a
14
+ * config key still blocks OAuth: it marks the provider's endpoint (often a
15
+ * proxy) as taking that key, so the session fails closed instead of sending
16
+ * a pooled OAuth token there (see `KeyCascade.get`).
17
+ */
18
+ suppressesOAuth(provider: string, restricted: boolean): boolean;
11
19
  runtimeKey(provider: string): string | undefined;
12
20
  configKey(provider: string): string | undefined;
13
21
  /** Config value consulted only after stored OAuth/login credentials. */
@@ -115,6 +123,10 @@ export declare class KeyCascade implements KeysApi {
115
123
  * Get API key for a provider.
116
124
  * Priority (first match wins): runtime override, config override, OAuth,
117
125
  * login API key, environment variable, then another stored API key.
126
+ * A session restricted by `sessions.restrict` resolves only its allowed
127
+ * OAuth accounts and throws {@link AIError.MissingApiKeyError} when none
128
+ * can serve or a config key (a models.yml `apiKey`, often for a proxy
129
+ * `baseUrl`) owns the provider, rather than using any other credential.
118
130
  */
119
131
  get(provider: string, sessionId?: string, options?: AuthApiKeyOptions, onCredentialId?: (id: number, identity?: OAuthRequestIdentity) => void): Promise<string | undefined>;
120
132
  /**
@@ -18,6 +18,12 @@ type SerializedCredentialRecord = {
18
18
  };
19
19
  export { isSqliteBusyError, isSqliteCorruptionError };
20
20
  export declare function serializeCredential(provider: string, credential: AuthCredential): SerializedCredentialRecord | null;
21
+ /**
22
+ * Identity key of a credential: the `identityKey` that broker snapshots carry
23
+ * and that broker account pools and `sessions.restrict` match, such as
24
+ * `email:<address>|org:<id>` for org-scoped providers. `null` for an API key or
25
+ * an OAuth credential without any account, email, project, or org identity.
26
+ */
21
27
  export declare function resolveCredentialIdentityKey(provider: string, credential: AuthCredential): string | null;
22
28
  /**
23
29
  * Default SQLite-backed implementation of {@link AuthCredentialStore}.
@@ -60,6 +66,7 @@ export declare class SqliteAuthCredentialStore implements AuthCredentialStore {
60
66
  deleteCachePrefix(prefix: string): void;
61
67
  cleanExpiredCache(): void;
62
68
  getCredentialBlock(credentialId: number, providerKey: string, blockScope: string): number | undefined;
69
+ getCredentialBlockScopes(credentialId: number, providerKey: string): Map<string, number>;
63
70
  getCredentialBlockReconcileAfter(credentialId: number, providerKey: string, blockScope: string): number | undefined;
64
71
  upsertCredentialBlock(block: StoredCredentialBlock): void;
65
72
  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. */
@@ -998,6 +998,11 @@ export interface OAuthApi {
998
998
  */
999
999
  refreshStored<T extends OAuthCredential = OAuthCredential>(provider: string, options: StoredOAuthRefreshOptions<T>): Promise<StoredOAuthRefreshResult<T>>;
1000
1000
  }
1001
+ /**
1002
+ * Handle for one {@link SessionsApi.restrict} call. {@link SessionsApi.unrestrict}
1003
+ * lifts a restriction only with the lease of the call that installed it.
1004
+ */
1005
+ export type SessionRestrictionLease = symbol;
1001
1006
  /** Session credential affinity operations. */
1002
1007
  export interface SessionsApi {
1003
1008
  /**
@@ -1025,6 +1030,27 @@ export interface SessionsApi {
1025
1030
  * source session.
1026
1031
  */
1027
1032
  inherit(sourceSessionId: string, targetSessionId: string): number;
1033
+ /**
1034
+ * Restrict one session's credentials for `provider` to the OAuth accounts
1035
+ * whose identity key (`email:<address>|org:<id>` for org-scoped providers;
1036
+ * otherwise `account:`, `email:`, or `project:` — the keys broker account
1037
+ * pools use) is listed. Selection, session pins, inherited affinity,
1038
+ * fallback passes, and rotation never leave the list, and runtime, config,
1039
+ * environment, and stored API keys are not used for that session; when no
1040
+ * listed account can serve, key resolution fails instead of borrowing
1041
+ * another account. An empty list allows no account. Replaces any earlier
1042
+ * restriction for the same provider and session; {@link inherit} does not
1043
+ * copy restrictions. Restrictions are never evicted, because that would
1044
+ * widen a live session; the owner passes the returned lease to
1045
+ * {@link unrestrict} when the session ends.
1046
+ */
1047
+ restrict(provider: string, sessionId: string, identityKeys: readonly string[]): SessionRestrictionLease;
1048
+ /**
1049
+ * Lift the restriction that `lease` installed. Once a later {@link restrict}
1050
+ * call has replaced it for the same provider and session, this does nothing,
1051
+ * so a stale owner never lifts the restriction a newer owner relies on.
1052
+ */
1053
+ unrestrict(provider: string, sessionId: string, lease: SessionRestrictionLease): void;
1028
1054
  /**
1029
1055
  * Release a session's sticky credential so its next {@link getApiKey} call
1030
1056
  * re-runs native pool ranking. This never blocks or penalizes the released
@@ -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,
@@ -1,6 +1,6 @@
1
1
  import type { AuthCredentialStore } from "./auth/store.js";
2
2
  import type { AuthAccountPolicies, AuthApiKeyOptions, AuthStorageOptions, BlocksApi, CredentialsApi, HealthApi, KeysApi, LimitsApi, OAuthApi, ResetsApi, SessionsApi, UsageApi } from "./auth/types.js";
3
- export { isSqliteBusyError, isSqliteCorruptionError, SqliteAuthCredentialStore } from "./auth/sqlite-credential-store.js";
3
+ export { isSqliteBusyError, isSqliteCorruptionError, resolveCredentialIdentityKey, SqliteAuthCredentialStore, } from "./auth/sqlite-credential-store.js";
4
4
  export * from "./auth/store.js";
5
5
  export * from "./auth/types.js";
6
6
  /**
@@ -46,9 +46,9 @@ export declare class AuthStorage {
46
46
  * Swap the backing credential store in place (live `auth.broker.url` change).
47
47
  * Loads `store` into fresh store-bound state — pins, blocks, and usage caches are
48
48
  * keyed by the old store's row ids — then closes the previous store. Runtime key
49
- * overrides, account policies, usage-provider overrides, and credential event
50
- * subscribers carry over. On a load failure `store` is closed and the current
51
- * store stays active.
49
+ * overrides, account policies, session account restrictions, usage-provider
50
+ * overrides, and credential event subscribers carry over. On a load failure
51
+ * `store` is closed and the current store stays active.
52
52
  */
53
53
  replaceStore(store: AuthCredentialStore, options?: {
54
54
  sourceLabel?: string;
@@ -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[];
@@ -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
  /**
@@ -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;
@@ -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.7.0",
3
+ "version": "18.8.1",
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.7.0",
159
- "@oh-my-pi/pi-catalog": "18.7.0",
160
- "@oh-my-pi/pi-natives": "18.7.0",
161
- "@oh-my-pi/pi-utils": "18.7.0",
162
- "@oh-my-pi/pi-wire": "18.7.0"
158
+ "@oh-my-pi/omptype": "18.8.1",
159
+ "@oh-my-pi/pi-catalog": "18.8.1",
160
+ "@oh-my-pi/pi-natives": "18.8.1",
161
+ "@oh-my-pi/pi-utils": "18.8.1",
162
+ "@oh-my-pi/pi-wire": "18.8.1"
163
163
  },
164
164
  "devDependencies": {
165
165
  "@types/bun": "^1.3.14"