@oh-my-pi/pi-ai 18.2.0 → 18.2.2
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 +53 -0
- package/README.md +2 -0
- package/dist/types/auth/sqlite-credential-store.d.ts +2 -1
- package/dist/types/auth-broker/remote-store.d.ts +17 -0
- package/dist/types/auth-gateway/index.d.ts +1 -0
- package/dist/types/auth-gateway/session-state.d.ts +118 -0
- package/dist/types/auth-storage.d.ts +17 -0
- package/dist/types/error/body-error.d.ts +15 -0
- package/dist/types/error/flags.d.ts +16 -0
- package/dist/types/error/index.d.ts +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/oneshot-retry.d.ts +6 -0
- package/dist/types/provider-session-state.d.ts +46 -0
- package/dist/types/providers/amazon-bedrock.d.ts +3 -0
- package/dist/types/providers/aws-sigv4.d.ts +12 -0
- package/dist/types/providers/openai-codex/request-transformer.d.ts +27 -0
- package/dist/types/providers/openai-responses.d.ts +15 -0
- package/dist/types/providers/openai-shared.d.ts +20 -3
- package/dist/types/registry/oauth/perplexity.d.ts +1 -7
- package/dist/types/registry/oauth/types.d.ts +8 -0
- package/dist/types/stream.d.ts +2 -0
- package/dist/types/types.d.ts +3 -1
- package/dist/types/usage/openai-codex.d.ts +3 -1
- package/dist/types/usage.d.ts +11 -1
- package/dist/types/utils/block-symbols.d.ts +36 -0
- package/dist/types/utils/openai-http.d.ts +2 -0
- package/dist/types/utils/retry-after.d.ts +2 -0
- package/dist/types/utils/schema/wire.d.ts +4 -5
- package/dist/types/utils.d.ts +9 -0
- package/package.json +6 -6
- package/src/auth/sqlite-credential-store.ts +8 -33
- package/src/auth-broker/remote-store.ts +73 -8
- package/src/auth-broker/wire-schemas.ts +1 -0
- package/src/auth-gateway/index.ts +1 -0
- package/src/auth-gateway/server.ts +186 -74
- package/src/auth-gateway/session-state.ts +312 -0
- package/src/auth-storage.ts +146 -15
- package/src/error/body-error.ts +310 -0
- package/src/error/flags.ts +63 -13
- package/src/error/index.ts +1 -0
- package/src/error/retryable.ts +2 -0
- package/src/index.ts +1 -0
- package/src/oneshot-retry.ts +13 -3
- package/src/provider-session-state.ts +56 -0
- package/src/providers/amazon-bedrock.ts +20 -3
- package/src/providers/anthropic-messages-server.ts +104 -23
- package/src/providers/anthropic-signature.ts +5 -2
- package/src/providers/anthropic.ts +101 -15
- package/src/providers/aws-sigv4.ts +16 -5
- package/src/providers/cursor.ts +60 -10
- package/src/providers/devin.ts +82 -28
- package/src/providers/openai-chat-server.ts +4 -0
- package/src/providers/openai-codex/request-transformer.ts +36 -0
- package/src/providers/openai-codex-responses.ts +35 -12
- package/src/providers/openai-completions.ts +49 -12
- package/src/providers/openai-reasoning-fallback.ts +6 -6
- package/src/providers/openai-responses-server.ts +2 -1
- package/src/providers/openai-responses.ts +52 -4
- package/src/providers/openai-shared.ts +199 -51
- package/src/registry/oauth/perplexity.ts +94 -28
- package/src/registry/oauth/types.ts +9 -0
- package/src/stream.ts +23 -2
- package/src/types.ts +3 -0
- package/src/usage/claude.ts +33 -0
- package/src/usage/google-antigravity.ts +8 -2
- package/src/usage/openai-codex.ts +94 -11
- package/src/usage.ts +8 -1
- package/src/utils/block-symbols.ts +57 -0
- package/src/utils/http-inspector.ts +20 -0
- package/src/utils/openai-http.ts +39 -3
- package/src/utils/retry-after.ts +12 -0
- package/src/utils/schema/normalize.ts +3 -3
- package/src/utils/schema/stamps.ts +33 -45
- package/src/utils/schema/wire.ts +9 -7
- package/src/utils.ts +67 -22
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,59 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.2.2] - 2026-09-16
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added configurable `baseUrl` support for `bedrock-converse-stream` requests, enabling Amazon Bedrock providers and compatible custom providers to use VPC or PrivateLink endpoints, FIPS hosts, and internal gateways, including endpoints mounted under a path or authenticated with query parameters.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Corrupt credential databases are now backed up privately and recreated instead of preventing startup; signing in again restores credentials.
|
|
14
|
+
- Fixed malformed Anthropic thinking signatures that could freeze sessions at 100% CPU.
|
|
15
|
+
- Fixed Anthropic-compatible gateway tool-call handling so client-declared tools are reported with `stop_reason: "tool_use"` and already-executed native provider tools are not exposed for clients to run again.
|
|
16
|
+
- Fixed gateway session isolation when clients omit a session key, preventing one conversation's retained provider state from affecting another.
|
|
17
|
+
- Fixed retained provider state across credential switches so account-specific capabilities are re-evaluated while reusable endpoint capabilities remain available.
|
|
18
|
+
- Fixed session retention limits closing provider state while a request is still streaming.
|
|
19
|
+
- ChatGPT accounts that have exhausted a plan's usage window but still have available Codex credit can now continue to be selected for Codex requests.
|
|
20
|
+
- Cursor requests now honor explicit max-mode markers on wire-backed models instead of inferring the mode from the model suffix.
|
|
21
|
+
- OpenAI-compatible chat responses containing only structured tool calls now report time to first token correctly.
|
|
22
|
+
|
|
23
|
+
## [18.2.1] - 2026-09-15
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- Added support for Cerebras Qwen 3.8-27b with improved reasoning effort control
|
|
28
|
+
- Added optional host browser-session callbacks for Perplexity SSO login, keeping browser automation out of pi-ai and preserving email and authenticator-code login.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Fixed the auth-gateway sending a model's own reasoning back to Anthropic as demoted plain text, which tripped the `reasoning_extraction` classifier on Fable, leaked reasoning into visible answers on Opus, Sonnet and Haiku, and broke the prompt cache prefix on every tool-calling turn. Replayed assistant turns now carry the model id the request resolves to and a `stopReason` derived from the turn's own tool calls, so same-model thinking blocks keep their signatures and replay natively ([#12115](https://github.com/can1357/oh-my-pi/pull/12115) by [@Zhu-Aemon](https://github.com/Zhu-Aemon)).
|
|
33
|
+
- Fixed custom OpenAI-compatible Responses streams crashing on omitted delta payloads or reasoning-summary fields, and recovered text delivered only in completed snapshots ([#11863](https://github.com/can1357/oh-my-pi/pull/11863) by [@moodiness](https://github.com/moodiness)).
|
|
34
|
+
- Fixed streaming CPU blowup on long Responses turns: per-delta content-index lookups are now O(1) instead of re-scanning the accumulated content blocks, eliminating the quadratic work that could freeze the TUI for tens of seconds to minutes while a subagent streams ([#10605](https://github.com/can1357/oh-my-pi/issues/10605)).
|
|
35
|
+
- Fixed sessions permanently wedged by `400 Invalid signature in thinking block` after a failover proxy swapped upstream models mid-conversation (e.g. Claude -> GLM -> Claude): when the unsigned-demotion retry fails identically, the anthropic-messages transport now retries once with replayed thinking dropped and pins that mode for the session, so the conversation continues without starting a new session ([#12006](https://github.com/can1357/oh-my-pi/pull/12006) by [@Damin-Lee](https://github.com/Damin-Lee)).
|
|
36
|
+
- Fixed OpenAI Codex backend rejecting requests with HTTP 400 (`string_above_max_length`) when replaying tool call IDs exceeding 64 characters or containing composite delimiters (`|`, `\n`) by sanitizing and deterministically clamping call IDs on the wire ([#11342](https://github.com/can1357/oh-my-pi/pull/11342)).
|
|
37
|
+
- Fixed OpenRouter multi-turn tool-call sessions failing with `400 Referenced reasoning item ... was not found or has expired` on Meta Muse Spark models by suppressing reasoning reconstruction when history is filtered and synthetic replay is disallowed, while preserving Anthropic and DeepSeek replay ([#10966](https://github.com/can1357/oh-my-pi/issues/10966)).
|
|
38
|
+
- The auth gateway now keeps provider session state per session, so a model reached through it stops re-learning the same rejection every turn. Sticky fallbacks such as strict-tools and fast mode previously did nothing on the `pi-native` transport used by containerized and robomp deployments, because the state cannot cross the wire and the gateway kept none of its own ([#12058](https://github.com/can1357/oh-my-pi/pull/12058) by [@camjac251](https://github.com/camjac251)).
|
|
39
|
+
- Fixed full OpenAI Responses request-body timeout recovery so the exact HTTP 408 is surfaced for a changed-request recovery instead of repeated unchanged transport retries when eligible tool-result history can be safely elided ([#11878](https://github.com/can1357/oh-my-pi/pull/11878) by [@hellofrommorgan](https://github.com/hellofrommorgan)).
|
|
40
|
+
- Fixed Codex sessions producing unrelated visible output on later turns after a progress-only response. ([#11466](https://github.com/can1357/oh-my-pi/issues/11466))
|
|
41
|
+
- Fixed OpenRouter reasoning models (e.g. Meta Muse Spark) rejecting every turn with `400 Provider returned error` after the session history contains a tool-call turn from another provider, by no longer sending a fabricated reasoning item id ([#11791](https://github.com/can1357/oh-my-pi/pull/11791) by [@brndnmtthws](https://github.com/brndnmtthws)).
|
|
42
|
+
- Fixed statusless stream-drop diagnostics (stream disconnected/closed before `response.completed`, upstream stream interrupted or ended before its terminal chunk, socket disconnected before the secure TLS handshake) classifying as terminal errors, so they now retry like their status-tagged twins instead of settling the turn ([#11805](https://github.com/can1357/oh-my-pi/issues/11805)).
|
|
43
|
+
- OpenAI-compatible endpoints that report `ReasoningEffort` in CamelCase now trigger effort-downgrade retries instead of terminating turns with HTTP 400 ([#11804](https://github.com/can1357/oh-my-pi/issues/11804)).
|
|
44
|
+
- Fixed openai-responses replay wedging a repaired orphan tool-result note between another call's `function_call` and `function_call_output`, which broke round pairing on strict validators (e.g. DeepSeek) with `400 No tool output found for tool call …`: orphan-output/call repair now runs before the interleaved-message hoist, so any injected note is relocated out of the tool-call batch ([#11473](https://github.com/can1357/oh-my-pi/issues/11473)).
|
|
45
|
+
- A stale Anthropic tier block (`tier:fable`, `tier:mythos`) is now cleared once a live usage report shows headroom on both the tier row and the shared windows, instead of idling a usable account until the reported reset. Healing requires a live report, and a credential held by an unscoped block spends no usage request on a probe that cannot lift it ([#11334](https://github.com/can1357/oh-my-pi/pull/11334) by [@AshishKumar4](https://github.com/AshishKumar4)).
|
|
46
|
+
- A running session now picks up credentials another process committed: adding an account in a second terminal is visible to credential selection and rotation without restarting the session, and a session's pinned account is re-resolved by row id so a row another process deleted cannot hand its slot to a sibling ([#11329](https://github.com/can1357/oh-my-pi/pull/11329) by [@AshishKumar4](https://github.com/AshishKumar4)).
|
|
47
|
+
- Fixed rate-limit/overload failures that arrive *inside* an HTTP 200 body (Azure, LiteLLM-style aggregators, and reverse proxies that already committed to the stream) not advancing `retry.fallbackChains`: a `{"error":{…}}`/`{"code":429}` chunk or a plain-text throttle frame (`429 Too Many Requests`, an nginx page) is now classified as a retryable 429/5xx through the same path an HTTP-status 429 takes, so a busy provider backs off and fails over instead of ending the session. Only bodies the provider actually reported are used: no status is inferred from error wording, and an unreadable body can no longer consume a credential.
|
|
48
|
+
- Fixed tool schema normalization and cycle detection for frozen, sealed, and nonextensible schemas.
|
|
49
|
+
- Reduced memory retained by `complete()` and `completeSimple()` while streaming responses.
|
|
50
|
+
- Antigravity quota summaries now identify Claude/GPT routing copies as one shared upstream pool while preserving model-specific quota selection ([#11268](https://github.com/can1357/oh-my-pi/issues/11268)).
|
|
51
|
+
- Fixed the auth-gateway rejecting `content: null` on `/v1/responses` and `/v1/chat/completions` message items with a 400; Codex and other OpenAI clients that emit null content on empty turns now work, matching OpenAI's tolerance ([#10956](https://github.com/can1357/oh-my-pi/issues/10956)).
|
|
52
|
+
- Fixed Azure GPT-6 Astra Chat Completions requests with function tools sending a non-`none` reasoning effort, which Azure rejects with HTTP 400 ([#11052](https://github.com/can1357/oh-my-pi/issues/11052)).
|
|
53
|
+
- Fixed Z.AI and Zhipu usage-limit credential blocks and oneshot completion retries (titles, summaries, classifiers) resolving eight hours late when provider responses omit the reset timestamp timezone ([#11014](https://github.com/can1357/oh-my-pi/issues/11014)).
|
|
54
|
+
- Fixed provider requests failing with `ENOENT` when another process removes a stale shared concurrency lock during acquisition.
|
|
55
|
+
- Fixed Devin-hosted Gemini models rejecting turns that include nullable tool parameters by normalizing tool schemas to Gemini's supported JSON Schema dialect ([#8647](https://github.com/can1357/oh-my-pi/issues/8647), [#10233](https://github.com/can1357/oh-my-pi/pull/10233) by [@will-bogusz](https://github.com/will-bogusz)).
|
|
56
|
+
- Fixed Devin gateway failures leaking raw proxy HTML into turn errors; HTTP status and retry metadata remain available for recovery ([#10233](https://github.com/can1357/oh-my-pi/pull/10233) by [@will-bogusz](https://github.com/will-bogusz)).
|
|
57
|
+
|
|
5
58
|
## [18.2.0] - 2026-09-15
|
|
6
59
|
|
|
7
60
|
### Added
|
package/README.md
CHANGED
|
@@ -1084,6 +1084,8 @@ omp auth-broker logout # interactive — pick a stored credential to
|
|
|
1084
1084
|
|
|
1085
1085
|
Credentials are saved to `agent.db` in the agent directory. `/login qianfan` opens the Qianfan console and stores the pasted API key.
|
|
1086
1086
|
|
|
1087
|
+
If SQLite reports corruption during startup, the damaged database and remaining journal sidecars are preserved beside it as private `agent.db.corrupt-<timestamp>-<id>*` backups before a fresh database is created. The log records the backup path. This restores startup, not unreadable credentials: log in again; retain the backups for manual data recovery. Lock contention and other non-corruption errors never reset the database.
|
|
1088
|
+
|
|
1087
1089
|
`login` supports OAuth providers (Anthropic, OpenAI Codex, GitHub Copilot, Gemini CLI, Antigravity) and API-key onboarding flows.
|
|
1088
1090
|
|
|
1089
1091
|
For the current API-key onboarding flows, the library covers Together, Moonshot, Qianfan, NVIDIA, NanoGPT, Novita, DeepInfra, Hugging Face, Venice, Xiaomi, vLLM, LiteLLM, Cloudflare AI Gateway, Qwen Portal, and Ollama Cloud. Ollama remains the local runtime integration; set `OLLAMA_API_KEY` only when your local or self-hosted deployment enforces bearer auth.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* The public AuthCredentialStore interface remains in ../auth-storage so local
|
|
5
5
|
* and remote stores share the same contract.
|
|
6
6
|
*/
|
|
7
|
-
import { Database } from "bun:sqlite";
|
|
7
|
+
import type { Database } from "bun:sqlite";
|
|
8
8
|
import { isSqliteBusyError, isSqliteCorruptionError } from "@oh-my-pi/pi-utils";
|
|
9
9
|
import type { AuthCredential, AuthCredentialStore, CredentialRefreshLeaseFence, DisabledCredentialSummary, StoredAuthCredential, StoredCredentialBlock } from "../auth-storage.js";
|
|
10
10
|
import type { OAuthCredentials } from "../registry/oauth/types.js";
|
|
@@ -29,6 +29,7 @@ export declare function resolveCredentialIdentityKey(provider: string, credentia
|
|
|
29
29
|
export declare class SqliteAuthCredentialStore implements AuthCredentialStore {
|
|
30
30
|
#private;
|
|
31
31
|
constructor(db: Database);
|
|
32
|
+
/** Opens credential storage with bounded busy retries and one-shot corruption recovery. */
|
|
32
33
|
static open(dbPath?: string): Promise<SqliteAuthCredentialStore>;
|
|
33
34
|
listAuthCredentials(provider?: string): StoredAuthCredential[];
|
|
34
35
|
listDisabledCredentials(provider?: string): Promise<DisabledCredentialSummary[]>;
|
|
@@ -51,6 +51,23 @@ export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
|
|
|
51
51
|
get snapshot(): SnapshotResponse;
|
|
52
52
|
/** Re-hydrate the in-memory snapshot from the broker. */
|
|
53
53
|
refreshSnapshot(): Promise<SnapshotResponse>;
|
|
54
|
+
/**
|
|
55
|
+
* Stateful probe for broker-side credential changes, mirroring
|
|
56
|
+
* {@link SqliteAuthCredentialStore.pollExternalChanges} so long-lived broker
|
|
57
|
+
* clients (notably `auth-gateway serve`) pick up logins/logouts made by
|
|
58
|
+
* another process without a restart.
|
|
59
|
+
*
|
|
60
|
+
* Compares a local content revision, not the broker's numeric generation:
|
|
61
|
+
* generation is an in-memory counter that resets when the broker process
|
|
62
|
+
* restarts, so a reconnecting stream can deliver a different credential set
|
|
63
|
+
* under a repeated (or lower) generation. {@link #refreshCredentialRevision}
|
|
64
|
+
* bumps the revision whenever the applied credential material actually
|
|
65
|
+
* changes, catching those cases too. Records foreground activity first: a
|
|
66
|
+
* low-traffic client's background sync parks after `#backgroundIdleMs`, and
|
|
67
|
+
* without this wakeup it would never fetch the new snapshot to report in the
|
|
68
|
+
* first place.
|
|
69
|
+
*/
|
|
70
|
+
pollExternalChanges(): boolean;
|
|
54
71
|
listAuthCredentials(provider?: string): StoredAuthCredential[];
|
|
55
72
|
/** Broker-backed disabled tombstones; empty against brokers predating the endpoint. */
|
|
56
73
|
listDisabledCredentials(provider?: string, signal?: AbortSignal): Promise<DisabledCredentialSummary[]>;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-owned provider session state for the auth-gateway.
|
|
3
|
+
*
|
|
4
|
+
* `SimpleStreamOptions.providerSessionState` is how a provider keeps what it
|
|
5
|
+
* learned about an endpoint across turns of one conversation: Anthropic's
|
|
6
|
+
* sticky `strictToolsDisabled` / `fastModeDisabled` /
|
|
7
|
+
* `replayUnsignedThinkingDisabled` flags and dropped-thinking-prefix set,
|
|
8
|
+
* OpenAI's strict-tools and reasoning-effort fallbacks, Codex's WebSocket and
|
|
9
|
+
* turn-state sessions. An in-process omp session owns that `Map` for its whole
|
|
10
|
+
* lifetime, so a grammar-too-large 400 or a fast-mode rejection costs one
|
|
11
|
+
* wasted round-trip per session rather than one per turn.
|
|
12
|
+
*
|
|
13
|
+
* The map is deliberately non-serializable — `Set`/`Map` fields, live sockets,
|
|
14
|
+
* a `close()` method — so `pi-native-client` strips it from the wire and
|
|
15
|
+
* `pi-native-server` never accepts it. Gateway clients therefore cannot bring
|
|
16
|
+
* their own, and without a server-side owner every containerized / robomp turn
|
|
17
|
+
* re-learns every lesson from a fresh upstream rejection.
|
|
18
|
+
*
|
|
19
|
+
* A plain `Map<sessionId, …>` in a long-lived server process is a leak: nothing
|
|
20
|
+
* ever reclaims an entry, and the entries own timers and sockets. This store is
|
|
21
|
+
* an LRU with a hard entry ceiling that calls `close()` on everything it drops
|
|
22
|
+
* and on everything it still holds at shutdown — but it only ever drops an
|
|
23
|
+
* entry no request is holding, because `close()` on a live entry tears down
|
|
24
|
+
* state an in-flight stream is still streaming through.
|
|
25
|
+
*/
|
|
26
|
+
import type { Api, Context, Model, ProviderSessionState } from "../types.js";
|
|
27
|
+
/**
|
|
28
|
+
* Retained logical sessions. Each entry is a handful of small provider records
|
|
29
|
+
* plus, for Codex, a WebSocket session — cheap to keep, but not free, so the
|
|
30
|
+
* ceiling is what turns "one entry per session id forever" into a bounded cost.
|
|
31
|
+
* Eviction is least-recently-used, so the ceiling only ever drops sessions that
|
|
32
|
+
* have been quiet longer than the 256 most recent ones.
|
|
33
|
+
*/
|
|
34
|
+
export declare const AUTH_GATEWAY_MAX_SESSION_STATES = 256;
|
|
35
|
+
/**
|
|
36
|
+
* One request's claim on a retained session.
|
|
37
|
+
*
|
|
38
|
+
* `release()` is what makes the entry evictable again, so it MUST run for every
|
|
39
|
+
* outcome of the request — a `finally` at the call site for the synchronous
|
|
40
|
+
* paths, stream completion for the streaming ones. It is idempotent, so the
|
|
41
|
+
* two can overlap.
|
|
42
|
+
*/
|
|
43
|
+
export interface AuthGatewaySessionStateLease {
|
|
44
|
+
/** The map to hand to `streamSimple` as `providerSessionState`. */
|
|
45
|
+
readonly states: Map<string, ProviderSessionState>;
|
|
46
|
+
/** Reset account-scoped records if an in-request auth retry switches accounts. */
|
|
47
|
+
updateAccount(account: string): void;
|
|
48
|
+
/** Give up this request's claim. Idempotent. */
|
|
49
|
+
release(): void;
|
|
50
|
+
}
|
|
51
|
+
/** Everything the store needs to place one request on a retained session. */
|
|
52
|
+
export interface AuthGatewaySessionStateRequest {
|
|
53
|
+
/**
|
|
54
|
+
* The client's own session key (`prompt_cache_key` / `sessionId`), or
|
|
55
|
+
* `undefined` when it sent none — blank counts as none. A supplied key is
|
|
56
|
+
* authoritative: the client is telling us which conversation this is.
|
|
57
|
+
*/
|
|
58
|
+
clientKey: string | undefined;
|
|
59
|
+
model: Model<Api>;
|
|
60
|
+
/**
|
|
61
|
+
* System prompt, tools and message history of this request. Used only when
|
|
62
|
+
* `clientKey` is absent, to place the request on the conversation it
|
|
63
|
+
* continues.
|
|
64
|
+
*/
|
|
65
|
+
context: Context;
|
|
66
|
+
/**
|
|
67
|
+
* Stable identity of the account this request's credential resolved to.
|
|
68
|
+
* A change means the gateway switched the session to a sibling credential,
|
|
69
|
+
* so the account-dependent lessons in the retained map are re-probed. The
|
|
70
|
+
* comparison happens on acquire and whenever an in-request auth retry
|
|
71
|
+
* resolves a sibling credential.
|
|
72
|
+
*/
|
|
73
|
+
account: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Bounded per-session provider state, owned by one gateway server instance.
|
|
77
|
+
*
|
|
78
|
+
* Two gateways in the same process get separate stores, so neither can hand a
|
|
79
|
+
* request another gateway's learned state or close it out from under one.
|
|
80
|
+
*
|
|
81
|
+
* The recency order is this class's own (a `Map` iterates in insertion order,
|
|
82
|
+
* and every acquire re-inserts) rather than `LRUCache`'s, because the policy
|
|
83
|
+
* needs two things a general cache cannot express: an entry that a request is
|
|
84
|
+
* still holding must be skipped when picking a victim, and an entry must be
|
|
85
|
+
* able to change key — `LRUCache` disposes on every removal, which is precisely
|
|
86
|
+
* the `close()` we must not run here.
|
|
87
|
+
*/
|
|
88
|
+
export declare class AuthGatewaySessionStateStore {
|
|
89
|
+
#private;
|
|
90
|
+
constructor(max?: number);
|
|
91
|
+
/** Retained logical sessions. */
|
|
92
|
+
get size(): number;
|
|
93
|
+
/**
|
|
94
|
+
* Claim the provider-session map for one request, created on first use and
|
|
95
|
+
* returned by reference so provider mutations persist into the next request.
|
|
96
|
+
*
|
|
97
|
+
* Keyed by provider + model + conversation (see {@link sessionKeys}). A
|
|
98
|
+
* client is free to reuse one session id across models, and the coarsest
|
|
99
|
+
* provider entries do not separate models themselves (`openai-responses`
|
|
100
|
+
* keys its strict-tools / history-replay record by provider alone,
|
|
101
|
+
* Antigravity by a single constant), so the model belongs in the key here.
|
|
102
|
+
* Endpoint is deliberately absent: every provider whose learning is
|
|
103
|
+
* endpoint-specific already sub-keys it internally
|
|
104
|
+
* (`anthropic-messages:${baseUrl}\0${modelId}`,
|
|
105
|
+
* `openai-completions:${provider}:${baseUrl}:${modelId}`), and repeating it
|
|
106
|
+
* would only fragment the map. The credential is absent for the same reason
|
|
107
|
+
* — most of what is retained is true of the endpoint whoever calls it, and
|
|
108
|
+
* Codex already sub-keys its transport by account and bearer — so a
|
|
109
|
+
* credential switch resets the account-dependent subset instead of
|
|
110
|
+
* splitting the entry (see `resetAccountScopedProviderSessionState`).
|
|
111
|
+
*
|
|
112
|
+
* The returned lease MUST be released; until then the entry cannot be
|
|
113
|
+
* evicted.
|
|
114
|
+
*/
|
|
115
|
+
acquire(request: AuthGatewaySessionStateRequest): AuthGatewaySessionStateLease;
|
|
116
|
+
/** Close and drop every retained state. Called when the gateway shuts down. */
|
|
117
|
+
close(): void;
|
|
118
|
+
}
|
|
@@ -502,6 +502,11 @@ export { isDefinitiveOAuthFailure } from "./error/auth-classify.js";
|
|
|
502
502
|
* the usage report reveals. Callers that wait the account out (instead of
|
|
503
503
|
* rotating) must sleep until this, not the error-text hint alone.
|
|
504
504
|
*
|
|
505
|
+
* `requestedBlockedUntilMs` (epoch ms) is this mark call's initial deadline,
|
|
506
|
+
* before usage-report correction and longest-wins merging. Callers use it to
|
|
507
|
+
* distinguish the call's replaceable heuristic from a longer merged block
|
|
508
|
+
* that credential selection will continue enforcing.
|
|
509
|
+
*
|
|
505
510
|
* `priorBlockedUntilMs` (epoch ms) is the live block deadline the map already
|
|
506
511
|
* stored for this credential before this call. The merged `blockedUntilMs`
|
|
507
512
|
* masks a pre-existing block shorter than this call's own heuristic
|
|
@@ -527,6 +532,8 @@ export interface UsageLimitMarkResult {
|
|
|
527
532
|
switched: boolean;
|
|
528
533
|
retryAtMs?: number;
|
|
529
534
|
blockedUntilMs?: number;
|
|
535
|
+
/** This mark call's initial deadline, before report correction and merging. */
|
|
536
|
+
requestedBlockedUntilMs?: number;
|
|
530
537
|
priorBlockedUntilMs?: number;
|
|
531
538
|
priorBlockedUntilTimed?: boolean;
|
|
532
539
|
reportResetAtMs?: number;
|
|
@@ -969,6 +976,7 @@ export declare class AuthStorage {
|
|
|
969
976
|
ingestUsageHeaders(provider: Provider, headers: Record<string, string>, options?: {
|
|
970
977
|
sessionId?: string;
|
|
971
978
|
baseUrl?: string;
|
|
979
|
+
responseStatus?: number;
|
|
972
980
|
}): boolean;
|
|
973
981
|
/**
|
|
974
982
|
* The {@link UsageProvider} registered for `provider`, or undefined when the
|
|
@@ -1116,6 +1124,15 @@ export declare class AuthStorage {
|
|
|
1116
1124
|
pinSessionOAuthAccount(provider: string, sessionId: string, credentialId: number, options?: {
|
|
1117
1125
|
lastUsedAtMs?: number;
|
|
1118
1126
|
}): boolean;
|
|
1127
|
+
/**
|
|
1128
|
+
* Copy every stored credential affinity from one live session to another.
|
|
1129
|
+
*
|
|
1130
|
+
* The target receives its own sticky entries, so request resolution, usage
|
|
1131
|
+
* blocking, credential rotation, metadata, and persisted pins all continue
|
|
1132
|
+
* through the target session id without retaining a live dependency on the
|
|
1133
|
+
* source session.
|
|
1134
|
+
*/
|
|
1135
|
+
inheritSessionCredentials(sourceSessionId: string, targetSessionId: string): number;
|
|
1119
1136
|
/**
|
|
1120
1137
|
* Resolve every stored OAuth credential for `provider` independently.
|
|
1121
1138
|
*
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the classified error for an in-band failure frame, or `undefined` when
|
|
3
|
+
* the frame is not a retryable in-band failure (in which case the caller keeps
|
|
4
|
+
* its existing handling and message).
|
|
5
|
+
*
|
|
6
|
+
* @param frame decoded SSE `data:` payload, or the `{ error, response }` subset of one
|
|
7
|
+
*/
|
|
8
|
+
export declare function createInBandProviderError(frame: unknown): Error | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Build the classified error for a non-JSON SSE frame: gateways and reverse
|
|
11
|
+
* proxies that answer `data: 429 Too Many Requests` or an HTML throttle page
|
|
12
|
+
* instead of an OpenAI envelope. `undefined` when the text is not recognisable
|
|
13
|
+
* as a throttle, so genuinely malformed payloads keep failing loudly.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createInBandProviderErrorFromText(text: string): Error | undefined;
|
|
@@ -34,6 +34,15 @@ export declare const PYTHON_HTTP2_STREAM_RESET_PATTERN: RegExp;
|
|
|
34
34
|
export declare const PYTHON_HTTP_INCOMPLETE_CHUNK_PATTERN: RegExp;
|
|
35
35
|
/** reqwest body-frame failures forwarded by the Codex HTTP proxy. */
|
|
36
36
|
export declare const CODEX_HTTP_BODY_READ_ERROR_PATTERN: RegExp;
|
|
37
|
+
/** Exact HTTP request-body-read timeout diagnostic. */
|
|
38
|
+
export declare function isRequestBodyReadTimeout(status: number | undefined, message: string | undefined): boolean;
|
|
39
|
+
/** Exact pre-output Responses 408 that needs a changed-request recovery path. */
|
|
40
|
+
export declare function isResponsesRequestBodyReadTimeout(message: {
|
|
41
|
+
api?: Api;
|
|
42
|
+
errorStatus?: number;
|
|
43
|
+
errorMessage?: string;
|
|
44
|
+
requestBodyReadTimeoutFullReplay?: boolean;
|
|
45
|
+
}): boolean;
|
|
37
46
|
export declare const TRANSIENT_TRANSPORT_PATTERN: RegExp;
|
|
38
47
|
/**
|
|
39
48
|
* Local llama.cpp / Ollama deterministic tool-call argument JSON parse failure.
|
|
@@ -131,6 +140,13 @@ export declare function stringify(id: number | undefined): string;
|
|
|
131
140
|
* low-signal to trust once detached from a live transport `Error`, which keeps the broad pattern.
|
|
132
141
|
*/
|
|
133
142
|
export declare function isTransientStreamParseError(error: unknown): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Transport stream-drop diagnostic (see {@link STREAM_DROP_PATTERN}). Unlike
|
|
145
|
+
* {@link isTransientStreamParseError}, one pattern serves both the live `Error`
|
|
146
|
+
* and the persisted-string forms: the phrasings are high-signal enough to trust
|
|
147
|
+
* detached from a transport `Error`.
|
|
148
|
+
*/
|
|
149
|
+
export declare function isTransientStreamDropError(error: unknown): boolean;
|
|
134
150
|
/** Any malformed stream-envelope error (prefix-tagged or out-of-order events). */
|
|
135
151
|
export declare function isStreamEnvelopeError(error: unknown): boolean;
|
|
136
152
|
/** Stream-envelope errors safe to retry against the provider (event ordering only). */
|
package/dist/types/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export * from "./auth-storage.js";
|
|
|
8
8
|
export * from "./error/rate-limit.js";
|
|
9
9
|
export * from "./oneshot-retry.js";
|
|
10
10
|
export * from "./provider-details.js";
|
|
11
|
+
export * from "./provider-session-state.js";
|
|
11
12
|
export * from "./providers/anthropic.js";
|
|
12
13
|
export * from "./providers/anthropic-client.js";
|
|
13
14
|
export * from "./providers/azure-openai-responses.js";
|
|
@@ -63,6 +63,12 @@ export interface OneshotRetryOptions {
|
|
|
63
63
|
* Thrown errors need no wiring — headers are recovered from the error itself.
|
|
64
64
|
*/
|
|
65
65
|
getResponseHeaders?: () => HeadersLike;
|
|
66
|
+
/**
|
|
67
|
+
* Provider id of the model being retried. Selects the catalog-declared
|
|
68
|
+
* timezone for a timezone-naive absolute reset stamp (Z.AI/Zhipu report
|
|
69
|
+
* Beijing time), so an over-cap wait is not misread as UTC and discarded.
|
|
70
|
+
*/
|
|
71
|
+
provider?: string;
|
|
66
72
|
/** Observability hook. Fires immediately before sleeping. */
|
|
67
73
|
onRetry?: (info: OneshotRetryInfo) => void;
|
|
68
74
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential-rotation handling for a retained `providerSessionState` map.
|
|
3
|
+
*
|
|
4
|
+
* A host that keeps one provider-session map per logical conversation (the
|
|
5
|
+
* auth-gateway's server-owned store, an in-process omp session) can outlive the
|
|
6
|
+
* credential that filled it: `AuthStorage.markUsageLimitReached` and the
|
|
7
|
+
* auth-retry resolver both switch a session to a sibling account mid-flight.
|
|
8
|
+
* Most of what a provider learns is a property of the *endpoint*, so rebuilding
|
|
9
|
+
* the whole map on a switch would re-pay every rejected round-trip the map
|
|
10
|
+
* exists to avoid. A minority is a property of the *account*, and keeping that
|
|
11
|
+
* across a switch is a bug.
|
|
12
|
+
*
|
|
13
|
+
* Audit of what the retained records hold, per provider:
|
|
14
|
+
*
|
|
15
|
+
* - **Anthropic** — `fastModeDisabled` is account-scoped: the rejection reads
|
|
16
|
+
* "this model does not support fast mode for your account", i.e. a plan
|
|
17
|
+
* entitlement, so a switch to an entitled sibling must re-probe. Its
|
|
18
|
+
* siblings are endpoint-scoped and stay: `strictToolsDisabled`
|
|
19
|
+
* (grammar-too-large 400 for the model's tool schema),
|
|
20
|
+
* `replayUnsignedThinkingDisabled` / `thinkingReplayDisabled` (the endpoint
|
|
21
|
+
* is a signing proxy), `prefixDroppedThinkingBlocks` (blocks the API itself
|
|
22
|
+
* dropped), `controlStates` (per-conversation control baselines).
|
|
23
|
+
* - **OpenAI Responses** — the `previous_response_id` chain baselines are
|
|
24
|
+
* account-scoped: a stored response belongs to the account that created it.
|
|
25
|
+
* Strict-tools / reasoning-effort fallbacks, replay warmup and the chaining
|
|
26
|
+
* circuit breaker are endpoint-scoped and stay.
|
|
27
|
+
* - **OpenAI Completions** — strict-tools and reasoning-effort fallbacks only;
|
|
28
|
+
* both endpoint-scoped. Nothing to reset.
|
|
29
|
+
* - **Codex** — already sub-keys its WebSocket sessions by account id AND
|
|
30
|
+
* bearer (`getCodexWebSocketSessionKey`), so a switch naturally lands on a
|
|
31
|
+
* fresh transport session while the old one stays reachable for teardown.
|
|
32
|
+
* Resetting from the outside would close a socket a retry may still be on.
|
|
33
|
+
* - **Antigravity** — `lastGoodEndpoint` is endpoint-scoped; the agent /
|
|
34
|
+
* conversation ids are conversation-scoped. Neither depends on the account.
|
|
35
|
+
* - **GitLab Duo** — the active workflow is account-bound, but it is a live
|
|
36
|
+
* server-side workflow plus socket, and the switch happens *inside* the
|
|
37
|
+
* request that may still be resuming it. Tearing it down here would abort the
|
|
38
|
+
* very turn that rotated; it stays on its existing session-close path.
|
|
39
|
+
*/
|
|
40
|
+
import type { ProviderSessionState } from "./types.js";
|
|
41
|
+
/**
|
|
42
|
+
* Reset the account-dependent lessons in `states`, keeping everything a
|
|
43
|
+
* provider learned about the endpoint. Call when a retained map is about to be
|
|
44
|
+
* reused for a session whose credential now resolves to a different account.
|
|
45
|
+
*/
|
|
46
|
+
export declare function resetAccountScopedProviderSessionState(states: Map<string, ProviderSessionState>): void;
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
* SigV4 signing and decodes the `application/vnd.amazon.eventstream` response.
|
|
6
6
|
* No `@aws-sdk/*`, no `@smithy/*`, no `proxy-agent`. Proxies are honored via
|
|
7
7
|
* Bun's native `HTTPS_PROXY` support.
|
|
8
|
+
*
|
|
9
|
+
* A `models.yml` `baseUrl` is the request origin verbatim (VPC endpoint, gateway, …);
|
|
10
|
+
* only AWS's own regional host is re-pointed at the resolved region. SigV4 unaffected.
|
|
8
11
|
*/
|
|
9
12
|
import type { Effort } from "@oh-my-pi/pi-catalog/effort";
|
|
10
13
|
import type { StreamFunction, StreamOptions, ThinkingBudgets } from "../types.js";
|
|
@@ -45,6 +45,18 @@ export declare function formatAmzDate(d: Date): {
|
|
|
45
45
|
longDate: string;
|
|
46
46
|
shortDate: string;
|
|
47
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* AWS's canonical-request spec encodes each name/value first, THEN sorts by
|
|
50
|
+
* the encoded form ("Sort the encoded parameter names by character code" —
|
|
51
|
+
* https://docs.aws.amazon.com/IAM/latest/UserGuide/create-canonical-request.html).
|
|
52
|
+
* Sorting the decoded form instead gives the wrong order whenever encoding
|
|
53
|
+
* changes a character's relative position — e.g. raw key `%7B` (decodes to
|
|
54
|
+
* `{`, 0x7B) vs `x` (0x78): decoded, `x` < `{`; encoded, `%` (0x25) < `x`, so
|
|
55
|
+
* `%7B` sorts first. A gateway that validates SigV4 (or AWS itself) computes
|
|
56
|
+
* the signature over ITS OWN canonicalization and rejects ours if the two
|
|
57
|
+
* disagree on order.
|
|
58
|
+
*/
|
|
59
|
+
export declare function canonicalQuery(query: string | undefined): string;
|
|
48
60
|
export interface SignedHeaders {
|
|
49
61
|
host: string;
|
|
50
62
|
"x-amz-date": string;
|
|
@@ -74,6 +74,33 @@ export interface RequestBody {
|
|
|
74
74
|
* explicit option; normal inference defaults to the full Responses contract.
|
|
75
75
|
*/
|
|
76
76
|
export declare function resolveCodexResponsesLite(requested: boolean | undefined): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Repair both halves of unpaired tool exchanges so the Responses input grammar
|
|
79
|
+
* stays valid — the API rejects either orphan with a 400:
|
|
80
|
+
*
|
|
81
|
+
* - `function_call_output` / `custom_tool_call_output` with no matching call →
|
|
82
|
+
* folded into an assistant message (`400 No tool call found for … output`).
|
|
83
|
+
* Regression of #472 / #1351.
|
|
84
|
+
* - `function_call` / `custom_tool_call` with no matching `*_output` → a
|
|
85
|
+
* placeholder output is synthesized immediately after the call
|
|
86
|
+
* (`400 No tool output found for function call …`). Hit when the user
|
|
87
|
+
* branches/navigates the session tree to a node that ends on a tool call (the
|
|
88
|
+
* tool-result child is dropped from the reconstructed history) or when a turn
|
|
89
|
+
* is aborted/crashes after the call streamed but before its result persisted.
|
|
90
|
+
*/
|
|
91
|
+
/**
|
|
92
|
+
* Sanitize an OpenAI Responses/Codex tool call ID to <= 64 characters and valid charset.
|
|
93
|
+
* Composite IDs with '|' or '\n' have their secondary/item part stripped.
|
|
94
|
+
* Hashing is anchored on the canonical base part so assistant and result composites
|
|
95
|
+
* with different item halves stay identical. Short lossy changes include a hash suffix
|
|
96
|
+
* to preserve collision resistance across distinct IDs.
|
|
97
|
+
*/
|
|
98
|
+
export declare function sanitizeCodexCallId(rawCallId: string): string;
|
|
99
|
+
/**
|
|
100
|
+
* In-place mutates the `call_id` property on every input item in the array to conform
|
|
101
|
+
* to the OpenAI Responses/Codex 64-character limit and valid charset constraints.
|
|
102
|
+
*/
|
|
103
|
+
export declare function sanitizeInputCallIds(input: InputItem[]): void;
|
|
77
104
|
/**
|
|
78
105
|
* Structural view of a Responses-style body mutated by the Lite rewrite.
|
|
79
106
|
* Loose (`unknown`) property types let the turn transformer (`RequestBody`)
|
|
@@ -85,6 +85,21 @@ interface OpenAIResponsesChainState {
|
|
|
85
85
|
/** Set once chaining is judged unsupported for this session (circuit breaker). */
|
|
86
86
|
disabled: boolean;
|
|
87
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Drop the account-bound half of every retained `openai-responses` record in
|
|
90
|
+
* `states`: the stateful `previous_response_id` chain baselines.
|
|
91
|
+
*
|
|
92
|
+
* Chaining stores the turn server-side under the account that created it, so a
|
|
93
|
+
* baseline minted by one credential is dead weight the moment the session is
|
|
94
|
+
* switched to a sibling account — the next delta request answers
|
|
95
|
+
* `Previous response not found` and burns a turn re-learning that. Everything
|
|
96
|
+
* else this record holds describes the *deployment*, not the account
|
|
97
|
+
* (strict-tools demotion, reasoning-effort fallback, native-history-replay
|
|
98
|
+
* warmup, the chaining circuit breaker), and is deliberately preserved:
|
|
99
|
+
* re-learning an endpoint's limits on every credential switch is the cost this
|
|
100
|
+
* state exists to avoid.
|
|
101
|
+
*/
|
|
102
|
+
export declare function resetOpenAIResponsesAccountScopedState(states: Map<string, ProviderSessionState>): void;
|
|
88
103
|
type OpenRouterAnthropicCacheControl = {
|
|
89
104
|
type: "ephemeral";
|
|
90
105
|
ttl?: "1h";
|
|
@@ -6,7 +6,7 @@ import { kStreamingLastParseLen, kStreamingPartialJson } from "../utils/block-sy
|
|
|
6
6
|
import type { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
7
7
|
import type { CapturedHttpErrorResponse } from "../utils/http-inspector.js";
|
|
8
8
|
import type { ChatCompletionCreateParamsStreaming } from "./openai-chat-wire.js";
|
|
9
|
-
import type
|
|
9
|
+
import { type InputItem } from "./openai-codex/request-transformer.js";
|
|
10
10
|
import type { ResponseComputerToolCall, ResponseContentPartAddedEvent, ResponseCreateParamsStreaming, ResponseInput, ResponseInputContent, ResponseInputItem, ResponseOutputItem, ResponseOutputMessage, ResponseReasoningItem, ResponseStatus, ResponseStreamEvent } from "./openai-responses-wire.js";
|
|
11
11
|
/**
|
|
12
12
|
* Keyless-provider sentinel. Custom providers configured with `auth: none`
|
|
@@ -222,6 +222,21 @@ export interface OpenAIExtraBodyOptions {
|
|
|
222
222
|
export declare function applyOpenAIExtraBody<P extends object>(params: P & {
|
|
223
223
|
venice_parameters?: Record<string, unknown>;
|
|
224
224
|
}, extraBody: Record<string, unknown> | undefined, options?: OpenAIExtraBodyOptions): void;
|
|
225
|
+
/**
|
|
226
|
+
* Normalize `content: null` to `[]` in place across a list of inbound wire
|
|
227
|
+
* message items.
|
|
228
|
+
*
|
|
229
|
+
* Codex (and other OpenAI clients) emit `content: null` on empty message items
|
|
230
|
+
* during multi-turn/tool turns; OpenAI tolerates it. Normalizing before the
|
|
231
|
+
* auth-gateway's request schema validation lets the item take the same path as
|
|
232
|
+
* an explicit empty content array — for both validation and any native
|
|
233
|
+
* history-replay clone — instead of 400ing. Shared by the `/v1/responses`
|
|
234
|
+
* (`input[]`) and `/v1/chat/completions` (`messages[]`) routes.
|
|
235
|
+
*
|
|
236
|
+
* `isEligible` lets a route skip items whose content is not array-typed, e.g.
|
|
237
|
+
* the chat `function` role whose content is `string | null`. See issue #10956.
|
|
238
|
+
*/
|
|
239
|
+
export declare function coerceNullMessageContentInPlace(items: unknown, isEligible?: (item: Record<string, unknown>) => boolean): void;
|
|
225
240
|
/**
|
|
226
241
|
* Chat Completions streaming request body shaped by the OpenAI-family providers.
|
|
227
242
|
* (binary `thinking`, Qwen `enable_thinking`/`chat_template_kwargs`, Venice
|
|
@@ -273,7 +288,7 @@ export interface ChatCompletionsReasoningOptions {
|
|
|
273
288
|
thinkingBudgets?: Partial<Record<Effort, number>>;
|
|
274
289
|
}
|
|
275
290
|
export type OpenAICompatEndpoint = "chat-completions" | "responses";
|
|
276
|
-
export type OpenAIReasoningDisableReason = "caller" | "forced-tool-choice" | "tool-choice" | "not-requested";
|
|
291
|
+
export type OpenAIReasoningDisableReason = "caller" | "forced-tool-choice" | "tool-choice" | "tools" | "not-requested";
|
|
277
292
|
export type OpenAICompatPolicyCompat = ResolvedOpenAISharedCompat & Partial<ResolvedOpenAICompat> & Partial<ResolvedOpenAIResponsesCompat>;
|
|
278
293
|
export interface ResolveOpenAICompatPolicyOptions {
|
|
279
294
|
endpoint: OpenAICompatEndpoint;
|
|
@@ -281,6 +296,7 @@ export interface ResolveOpenAICompatPolicyOptions {
|
|
|
281
296
|
reasoning?: string;
|
|
282
297
|
disableReasoning?: boolean;
|
|
283
298
|
toolChoice?: unknown;
|
|
299
|
+
hasTools?: boolean;
|
|
284
300
|
strictResponsesPairing?: boolean;
|
|
285
301
|
includeEncryptedReasoning?: boolean;
|
|
286
302
|
filterReasoningHistory?: boolean;
|
|
@@ -351,6 +367,7 @@ export declare function resolveOpenAICompatPolicy<TApi extends Api>(model: Model
|
|
|
351
367
|
export declare function applyChatCompletionsCompatPolicy(params: OpenAICompletionsParams, policy: OpenAICompatPolicy): void;
|
|
352
368
|
export declare function applyChatCompletionsReasoningParams(params: OpenAICompletionsParams, model: Model<"openai-completions">, compat: ResolvedOpenAICompat, options: (ChatCompletionsReasoningOptions & {
|
|
353
369
|
toolChoice?: unknown;
|
|
370
|
+
hasTools?: boolean;
|
|
354
371
|
}) | undefined): void;
|
|
355
372
|
export declare function disableChatCompletionsReasoningForDialect(params: OpenAICompletionsParams, compat: ResolvedOpenAICompat): void;
|
|
356
373
|
/**
|
|
@@ -550,7 +567,7 @@ type ResponsesToolCallBlock = ToolCall & {
|
|
|
550
567
|
[kStreamingPartialJson]: string;
|
|
551
568
|
[kStreamingLastParseLen]?: number;
|
|
552
569
|
};
|
|
553
|
-
export declare function appendReasoningSummaryPart(item: ResponseReasoningItem, part: ResponseReasoningItem["summary"][number]): void;
|
|
570
|
+
export declare function appendReasoningSummaryPart(item: ResponseReasoningItem, part: ResponseReasoningItem["summary"][number] | undefined): void;
|
|
554
571
|
/**
|
|
555
572
|
* Response-global accumulator for the sequential-cutoff summary contract.
|
|
556
573
|
*
|
|
@@ -1,9 +1,3 @@
|
|
|
1
1
|
import type { OAuthController, OAuthCredentials } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
* Login to Perplexity.
|
|
4
|
-
*
|
|
5
|
-
* Tries auto-extraction from the desktop app, then runs HTTP email OTP login.
|
|
6
|
-
*
|
|
7
|
-
* No browser/manual token paste fallback is used.
|
|
8
|
-
*/
|
|
2
|
+
/** Prefer legacy app borrowing, then offer browser SSO when the host supports it. */
|
|
9
3
|
export declare function loginPerplexity(ctrl: OAuthController): Promise<OAuthCredentials>;
|
|
@@ -63,12 +63,20 @@ export interface OAuthProviderInfo {
|
|
|
63
63
|
*/
|
|
64
64
|
storeCredentialsAs?: string;
|
|
65
65
|
}
|
|
66
|
+
/** Sign-in URL and accepted cookies for an isolated, host-owned browser. */
|
|
67
|
+
export type OAuthBrowserSessionRequest = {
|
|
68
|
+
url: string;
|
|
69
|
+
/** Cookie names in preference order; return the first non-empty matching value. */
|
|
70
|
+
cookieNames: readonly string[];
|
|
71
|
+
};
|
|
66
72
|
export interface OAuthController {
|
|
67
73
|
onAuth?(info: OAuthAuthInfo): void;
|
|
68
74
|
onProgress?(message: string): void;
|
|
69
75
|
/** Request pasted callback input; stop any visible prompt when `signal` aborts. */
|
|
70
76
|
onManualCodeInput?(signal?: AbortSignal): Promise<string>;
|
|
71
77
|
onPrompt?(prompt: OAuthPrompt): Promise<string>;
|
|
78
|
+
/** Complete browser login and return one matching cookie value privately. Reject on cancellation or failure. */
|
|
79
|
+
onBrowserSession?(request: OAuthBrowserSessionRequest, signal?: AbortSignal): Promise<string>;
|
|
72
80
|
signal?: AbortSignal;
|
|
73
81
|
fetch?: FetchImpl;
|
|
74
82
|
}
|
package/dist/types/stream.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export declare const __providerInFlightForTesting: {
|
|
|
17
17
|
setHeartbeatWriter(writer: ((writeProviderInFlightInfo: () => Promise<void>) => Promise<void>) | undefined): void;
|
|
18
18
|
setLeaseRemover(remover: ((leasePath: string) => Promise<void>) | undefined): void;
|
|
19
19
|
setWaitObserver(observer: ((provider: string) => void) | undefined): void;
|
|
20
|
+
setLockCreatedObserver(observer: ((lockDir: string) => Promise<void>) | undefined): void;
|
|
21
|
+
setLockIdentifiedObserver(observer: ((lockDir: string) => Promise<void>) | undefined): void;
|
|
20
22
|
providerDir(provider: string): string;
|
|
21
23
|
lockDir(provider: string): string;
|
|
22
24
|
captureStaleLockRelease(provider: string): Promise<(() => Promise<void>) | null>;
|
package/dist/types/types.d.ts
CHANGED
|
@@ -853,6 +853,8 @@ export interface AssistantMessage {
|
|
|
853
853
|
errorMessage?: string;
|
|
854
854
|
/** Stable recovery-classification text when errorMessage includes display-only diagnostics. */
|
|
855
855
|
errorClassificationMessage?: string;
|
|
856
|
+
/** True only when an exact request-body-read timeout failed on a full Responses replay, not a previous-response delta. */
|
|
857
|
+
requestBodyReadTimeoutFullReplay?: boolean;
|
|
856
858
|
/** Per-tool abort messages used when an aborted assistant turn needs different placeholder results per tool call. */
|
|
857
859
|
toolCallAbortMessages?: Record<string, string>;
|
|
858
860
|
/** HTTP status surfaced by the provider when the request failed. Populated by every provider's catch block alongside `errorMessage` so consumers (auth retry, telemetry, UI) can branch without regex-scraping the message. */
|
|
@@ -973,7 +975,7 @@ export interface CursorTodoSnapshot {
|
|
|
973
975
|
* provider persists this value verbatim. When no handler is registered at all,
|
|
974
976
|
* the provider falls back to its own summary-only result.
|
|
975
977
|
*/
|
|
976
|
-
export type CursorTodoSyncHandler = (snapshot: CursorTodoSnapshot | null, toolCallId: string, error: string | null) => ToolResultMessage;
|
|
978
|
+
export type CursorTodoSyncHandler = (snapshot: CursorTodoSnapshot | null, toolCallId: string, error: string | null, origin?: "read" | "update") => ToolResultMessage;
|
|
977
979
|
export interface CursorShellStreamCallbacks {
|
|
978
980
|
onStdout(data: string): void;
|
|
979
981
|
onStderr(data: string): void;
|