@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.
- package/CHANGELOG.md +33 -0
- package/dist/types/auth/affinity.d.ts +28 -3
- package/dist/types/auth/cascade.d.ts +12 -0
- package/dist/types/auth/sqlite-credential-store.d.ts +7 -0
- package/dist/types/auth/store.d.ts +6 -0
- package/dist/types/auth/types.d.ts +26 -0
- package/dist/types/auth-broker/remote-store.d.ts +1 -0
- package/dist/types/auth-broker/snapshot-cache.d.ts +12 -0
- package/dist/types/auth-gateway/session-state.d.ts +6 -0
- package/dist/types/auth-storage.d.ts +4 -4
- package/dist/types/dialect/terminator-wait.d.ts +19 -0
- package/dist/types/env-api-key.d.ts +21 -0
- package/dist/types/images/shared.d.ts +6 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/providers/connect-frame.d.ts +44 -0
- package/dist/types/providers/cursor/interaction-query.d.ts +0 -2
- package/dist/types/stream.d.ts +0 -21
- package/dist/types/transcription/types.d.ts +2 -1
- package/dist/types/utils/aws-profile.d.ts +5 -0
- package/package.json +6 -6
- package/src/auth/affinity.ts +115 -34
- package/src/auth/blocks.ts +90 -14
- package/src/auth/cascade.ts +31 -3
- package/src/auth/oauth.ts +4 -3
- package/src/auth/rotation.ts +8 -2
- package/src/auth/select.ts +32 -4
- package/src/auth/sqlite-credential-store.ts +91 -42
- package/src/auth/store.ts +6 -0
- package/src/auth/types.ts +27 -0
- package/src/auth/usage-cache.ts +16 -5
- package/src/auth/usage.ts +1 -1
- package/src/auth-broker/discover.ts +5 -4
- package/src/auth-broker/remote-store.ts +117 -46
- package/src/auth-broker/server.ts +283 -123
- package/src/auth-broker/snapshot-cache.ts +142 -2
- package/src/auth-gateway/server.ts +19 -5
- package/src/auth-gateway/session-state.ts +51 -9
- package/src/auth-storage.ts +12 -6
- package/src/dialect/deepseek.ts +10 -2
- package/src/dialect/gemini.ts +8 -2
- package/src/dialect/hermes.ts +8 -2
- package/src/dialect/kimi.ts +8 -2
- package/src/dialect/qwen-xml.ts +8 -2
- package/src/dialect/qwen3.ts +8 -2
- package/src/dialect/terminator-wait.ts +42 -0
- package/src/env-api-key.ts +78 -0
- package/src/images/openai-hosted.ts +11 -4
- package/src/images/openai-images.ts +19 -13
- package/src/images/shared.ts +10 -2
- package/src/index.ts +1 -0
- package/src/providers/anthropic.ts +39 -13
- package/src/providers/apple-foundation-models.ts +10 -4
- package/src/providers/azure-openai-responses.ts +1 -1
- package/src/providers/connect-frame.ts +107 -0
- package/src/providers/cursor/interaction-query.ts +1 -9
- package/src/providers/cursor.ts +87 -47
- package/src/providers/devin.ts +32 -41
- package/src/providers/gitlab-duo-workflow.ts +5 -2
- package/src/providers/google.ts +1 -1
- package/src/providers/ollama.ts +1 -1
- package/src/providers/openai-codex-responses.ts +46 -27
- package/src/providers/openai-completions.ts +1 -1
- package/src/providers/openai-responses.ts +5 -4
- package/src/providers/openai-shared.ts +54 -19
- package/src/providers/transcriptions-server.ts +1 -1
- package/src/providers/transform-messages.ts +17 -13
- package/src/registry/aws.ts +51 -14
- package/src/registry/cloudflare-ai-gateway.ts +24 -1
- package/src/stream.ts +3 -72
- package/src/transcription/types.ts +2 -1
- package/src/utils/aws-profile.ts +10 -4
- package/src/utils/thinking-loop.ts +18 -3
- 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
|
-
/**
|
|
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
|
|
50
|
-
* subscribers carry over. On a load failure
|
|
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 {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -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
|
/**
|
package/dist/types/stream.d.ts
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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.
|
|
159
|
-
"@oh-my-pi/pi-catalog": "18.
|
|
160
|
-
"@oh-my-pi/pi-natives": "18.
|
|
161
|
-
"@oh-my-pi/pi-utils": "18.
|
|
162
|
-
"@oh-my-pi/pi-wire": "18.
|
|
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"
|