@linxiraos/pi-ai 1.1.4 → 1.1.5

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 CHANGED
@@ -2,11 +2,9 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
- ## [1.1.4] - 2026-08-26
5
+ ## [1.1.5] - 2026-08-26
6
6
 
7
- ### Changed
8
-
9
- - 同步 1.1.4 发布线(与 1.1.3 无功能差异)。
7
+ - 同步上游 OMP v18.0.5 / v18.0.6:新增 Yolo-Auto / OpenRouter 浏览器登录与 DeepInfra 支持,空补全重试重构(withReplaySafeStreamRetry)。
10
8
 
11
9
  ## [1.1.3] - 2026-08-25
12
10
 
package/README.md CHANGED
@@ -60,6 +60,7 @@ Unified LLM API with automatic model discovery, provider configuration, token an
60
60
  - **NVIDIA** (requires `NVIDIA_API_KEY`)
61
61
  - **NanoGPT** (requires `NANO_GPT_API_KEY`)
62
62
  - **Novita** (requires `NOVITA_API_KEY`)
63
+ - **DeepInfra** (requires `DEEPINFRA_API_KEY`)
63
64
  - **Hugging Face Inference**
64
65
  - **xAI**
65
66
  - **Venice** (requires `VENICE_API_KEY`)
@@ -943,6 +944,7 @@ In Node.js environments, you can set environment variables to avoid passing API
943
944
  | NVIDIA | `NVIDIA_API_KEY` |
944
945
  | NanoGPT | `NANO_GPT_API_KEY` |
945
946
  | Novita | `NOVITA_API_KEY` |
947
+ | DeepInfra | `DEEPINFRA_API_KEY` |
946
948
  | Venice | `VENICE_API_KEY` |
947
949
  | Moonshot | `MOONSHOT_API_KEY` |
948
950
  | xAI | `XAI_API_KEY` |
@@ -983,6 +985,7 @@ Provider endpoint defaults for the current OpenAI-compatible integrations:
983
985
  - NVIDIA: `https://integrate.api.nvidia.com/v1`
984
986
  - NanoGPT: `https://nano-gpt.com/api/v1`
985
987
  - Novita: `https://api.novita.ai/openai/v1`
988
+ - DeepInfra: `https://api.deepinfra.com/v1/openai`
986
989
  - Hugging Face Inference: `https://router.huggingface.co/v1`
987
990
  - Venice: `https://api.venice.ai/api/v1`
988
991
  - Xiaomi MiMo: `https://api.xiaomimimo.com/anthropic`
@@ -1084,7 +1087,7 @@ Credentials are saved to `agent.db` in the agent directory. `/login qianfan` ope
1084
1087
 
1085
1088
  `login` supports OAuth providers (Anthropic, OpenAI Codex, GitHub Copilot, Gemini CLI, Antigravity) and API-key onboarding flows.
1086
1089
 
1087
- For the current API-key onboarding flows, the library covers Together, Moonshot, Qianfan, NVIDIA, NanoGPT, Novita, 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.
1090
+ 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.
1088
1091
 
1089
1092
  ### Programmatic OAuth
1090
1093
 
@@ -35,6 +35,14 @@ export interface RemoteAuthCredentialStoreOptions {
35
35
  accountPool?: AuthBrokerAccountPool;
36
36
  /** Flush cadence for batched observed-usage reports. Default 10s. */
37
37
  observedUsageFlushMs?: number;
38
+ /**
39
+ * Idle window after the last foreground store use before background
40
+ * snapshot sync (SSE stream / long-poll) disconnects and parks. A parked
41
+ * store holds no timers or sockets, so an unclosed store never keeps the
42
+ * process alive longer than one idle window. Sync resumes transparently on
43
+ * the next use. Default 20s.
44
+ */
45
+ backgroundIdleMs?: number;
38
46
  }
39
47
  export declare class RemoteAuthCredentialStore implements AuthCredentialStore {
40
48
  #private;
@@ -218,11 +218,8 @@ export declare function isInvalidThinkingSignatureError(message: string): boolea
218
218
  */
219
219
  export declare function maybeAddReplayUnsignedThinkingHint(model: Model<"anthropic-messages">, message: string): string;
220
220
  /**
221
- * Public entry: wrap the single-attempt streamer with bounded empty-completion
222
- * retries (a benign terminal stop carrying no content/usage would otherwise
223
- * stall the agent loop). The inner attempt keeps its own provider-failure retry
224
- * loop; this layer only re-issues a fresh request on an empty success. Shared
225
- * with the OpenAI-completions provider via `withEmptyCompletionRetry`.
221
+ * Public entry: retry benign empty completions before they reach the agent
222
+ * loop. The inner attempt owns Anthropic provider-failure retries.
226
223
  */
227
224
  export declare const streamAnthropic: StreamFunction<"anthropic-messages">;
228
225
  export type AnthropicSystemBlock = {
@@ -12,6 +12,9 @@ export interface AzureOpenAIResponsesOptions extends StreamOptions {
12
12
  disableReasoning?: boolean;
13
13
  }
14
14
  /**
15
- * Generate function for Azure OpenAI Responses API
15
+ * Retries transient Azure stream failures only before assistant output commits
16
+ * the attempt. The unsupported explicit prompt-cache config is rejected
17
+ * synchronously here — callers of the direct entrypoint get the immediate
18
+ * `ConfigurationError` rather than a stream whose `.result()` rejects later.
16
19
  */
17
20
  export declare const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses">;
@@ -38,10 +38,8 @@ export interface OpenAICompletionsOptions extends StreamOptions {
38
38
  promptCache?: OpenAIPromptCacheOptions;
39
39
  }
40
40
  /**
41
- * Public entry: wrap the single-attempt streamer with bounded empty-completion
42
- * retries flaky gateways occasionally 200 with `delta: {}` + `finish_reason:
43
- * "stop"` and no usage, which would otherwise stall the agent loop. Shared with
44
- * the Anthropic provider via `withEmptyCompletionRetry`.
41
+ * Retries benign empty completions and transient provider failures only before
42
+ * assistant output commits the attempt.
45
43
  */
46
44
  export declare const streamOpenAICompletions: StreamFunction<"openai-completions">;
47
45
  export declare function parseChunkUsage(rawUsage: object, model: Model<"openai-completions">, premiumRequests: number | undefined): AssistantMessage["usage"];
@@ -106,10 +106,9 @@ type OpenAIResponsesSamplingParams = ResponseCreateParamsStreaming & {
106
106
  cache_ttl?: "5m" | "1h";
107
107
  };
108
108
  /**
109
- * Public entry: wrap the single-attempt Responses streamer with bounded
110
- * empty-completion retries a `response.completed` carrying no content/usage
111
- * would otherwise stall the agent loop. Shared with the OpenAI-completions and
112
- * Anthropic providers via `withEmptyCompletionRetry`.
109
+ * Public entry: retry benign empty completions before they reach the agent
110
+ * loop. Transient stream failures are retried inside the attempt so stateful
111
+ * Responses request metadata remains stable.
113
112
  */
114
113
  export declare const streamOpenAIResponses: StreamFunction<"openai-responses">;
115
114
  export declare function buildParams(model: Model<"openai-responses">, context: Context, options: OpenAIResponsesOptions | undefined, providerSessionState: OpenAIResponsesProviderSessionState | undefined, strictToolsScope?: OpenAIStrictToolsScope, disableStrictToolsOverride?: boolean, statefulCacheBaseline?: ResponseInput): {
@@ -234,6 +234,7 @@ export type OpenAICompletionsParams = Omit<ChatCompletionCreateParamsStreaming,
234
234
  preserve_thinking?: boolean;
235
235
  chat_template_kwargs?: {
236
236
  enable_thinking?: boolean;
237
+ thinking?: boolean;
237
238
  preserve_thinking?: boolean;
238
239
  reasoning_effort?: string;
239
240
  };
@@ -684,4 +685,4 @@ export declare function buildResponsesDeltaInput<TItem extends ResponseInputItem
684
685
  input?: TItem[];
685
686
  } | undefined, previousResponseItems: readonly TItem[] | undefined, current: {
686
687
  input?: TItem[];
687
- }): TItem[] | null;
688
+ }, additionalTopLevelExcludeMap?: Readonly<Record<string, boolean>>): TItem[] | null;
@@ -0,0 +1,6 @@
1
+ export declare const loginDeepinfra: (options: import("./oauth/index.js").OAuthController) => Promise<string>;
2
+ export declare const deepinfraProvider: {
3
+ id: "deepinfra";
4
+ name: string;
5
+ login: (options: import("./oauth/index.js").OAuthController) => Promise<string>;
6
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Sign in with OpenRouter (OAuth PKCE).
3
+ *
4
+ * No client registration: the S256 PKCE challenge is the only proof of
5
+ * identity. The browser authorizes at `https://openrouter.ai/auth`, redirects
6
+ * back to the loopback callback with `?code=`, and the code + verifier
7
+ * exchange at `/api/v1/auth/keys` mints a durable `sk-or-…` API key.
8
+ *
9
+ * OpenRouter never echoes a `state` parameter (the redirect only appends
10
+ * `?code=` to the callback URL), so the flow runs with an empty expected
11
+ * state — callback-state validation is disabled and the PKCE verifier binds
12
+ * the exchange instead.
13
+ *
14
+ * The manual-input race doubles as the API-key paste path: pasted `sk-or-…`
15
+ * keys skip the PKCE exchange and are validated against `/api/v1/auth/key`
16
+ * (the canonical "who am I" endpoint — `/api/v1/models` returns 200 for any
17
+ * bearer), so one login entry covers both browser sign-in and key paste.
18
+ */
19
+ import type { FetchImpl } from "../../types.js";
20
+ import { OAuthCallbackFlow } from "./callback-server.js";
21
+ import type { OAuthController, OAuthCredentials } from "./types.js";
22
+ /** Exchange an authorization code + PKCE verifier for a durable OpenRouter API key. */
23
+ export declare function exchangeOpenRouterCode(code: string, codeVerifier: string, fetchImpl?: FetchImpl): Promise<string>;
24
+ export declare class OpenRouterOAuthFlow extends OAuthCallbackFlow {
25
+ #private;
26
+ constructor(ctrl: OAuthController);
27
+ /** OpenRouter never echoes `state`; empty state disables callback-state validation. */
28
+ generateState(): string;
29
+ generateAuthUrl(_state: string, redirectUri: string): Promise<{
30
+ url: string;
31
+ instructions?: string;
32
+ }>;
33
+ exchangeToken(code: string): Promise<OAuthCredentials>;
34
+ }
35
+ /** Log in with Sign in with OpenRouter (PKCE); mints a durable API key. */
36
+ export declare function loginOpenRouterOAuth(ctrl: OAuthController): Promise<OAuthCredentials>;
@@ -1,13 +1,14 @@
1
1
  import type { OAuthLoginCallbacks } from "./oauth/types.js";
2
- /** OpenRouter login flow (API key paste, validated via /auth/key).
3
- *
4
- * `/api/v1/models` is public and returns 200 for any bearer (including bogus),
5
- * so it cannot validate auth. `/api/v1/auth/key` is the canonical "who am I"
6
- * endpoint 200 for valid keys, 401 otherwise.
2
+ /**
3
+ * OpenRouter login: Sign in with OpenRouter (OAuth PKCE) that mints a durable
4
+ * `sk-or-…` API key, with the manual-input race accepting a pasted existing
5
+ * key (validated via `/api/v1/auth/key`). Either path resolves to a plain API
6
+ * key string, stored as an `api_key` credential.
7
7
  */
8
- export declare const loginOpenRouter: (options: import("./oauth/index.js").OAuthController) => Promise<string>;
9
8
  export declare const openrouterProvider: {
10
9
  readonly id: "openrouter";
11
10
  readonly name: "OpenRouter";
12
11
  readonly login: (cb: OAuthLoginCallbacks) => Promise<string>;
12
+ readonly callbackPort: 54549;
13
+ readonly pasteCodeFlow: true;
13
14
  };
@@ -82,6 +82,10 @@ declare const ALL: ({
82
82
  readonly name: "Cursor (Claude, GPT, etc.)";
83
83
  readonly login: (cb: import("./oauth/index.js").OAuthLoginCallbacks) => Promise<import("./oauth/index.js").OAuthCredentials>;
84
84
  readonly refreshToken: (credentials: import("./oauth/index.js").OAuthCredentials) => Promise<import("./oauth/index.js").OAuthCredentials>;
85
+ } | {
86
+ id: "deepinfra";
87
+ name: string;
88
+ login: (options: import("./oauth/index.js").OAuthController) => Promise<string>;
85
89
  } | {
86
90
  readonly id: "deepseek";
87
91
  readonly name: "DeepSeek";
@@ -254,6 +258,8 @@ declare const ALL: ({
254
258
  readonly id: "openrouter";
255
259
  readonly name: "OpenRouter";
256
260
  readonly login: (cb: import("./oauth/index.js").OAuthLoginCallbacks) => Promise<string>;
261
+ readonly callbackPort: 54549;
262
+ readonly pasteCodeFlow: true;
257
263
  } | {
258
264
  readonly id: "parallel";
259
265
  readonly name: "Parallel";
@@ -342,6 +348,10 @@ declare const ALL: ({
342
348
  readonly id: "xiaomi-token-plan-sgp";
343
349
  readonly name: "Xiaomi Token Plan (Singapore)";
344
350
  readonly login: (cb: import("./oauth/index.js").OAuthLoginCallbacks) => Promise<string>;
351
+ } | {
352
+ readonly id: "yolo-auto";
353
+ readonly name: "Yolo-Auto";
354
+ readonly login: (cb: import("./oauth/index.js").OAuthLoginCallbacks) => Promise<string>;
345
355
  } | {
346
356
  readonly id: "zai";
347
357
  readonly name: "Z.AI (GLM Coding Plan)";
@@ -0,0 +1,15 @@
1
+ import type { OAuthLoginCallbacks } from "./oauth/types.js";
2
+ /**
3
+ * Yolo-Auto login flow (API key paste, validated via `/v1/models`).
4
+ *
5
+ * Yolo-Auto is a flat-rate OpenAI-compatible API. `GET /v1/models` 401s any
6
+ * missing or invalid bearer (verified against the live endpoint), so it doubles
7
+ * as the canonical "who am I" check — the same role OpenRouter's `/auth/key`
8
+ * plays there.
9
+ */
10
+ export declare const loginYoloAuto: (options: import("./oauth/index.js").OAuthController) => Promise<string>;
11
+ export declare const yoloAutoProvider: {
12
+ readonly id: "yolo-auto";
13
+ readonly name: "Yolo-Auto";
14
+ readonly login: (cb: OAuthLoginCallbacks) => Promise<string>;
15
+ };
@@ -8,15 +8,24 @@ export declare const EMPTY_COMPLETION_BASE_DELAY_MS = 500;
8
8
  * — or one that only ever produced thinking — is the "empty response" failure.
9
9
  */
10
10
  export declare function hasVisibleAssistantContent(message: AssistantMessage): boolean;
11
- interface EmptyCompletionRetryOptions {
11
+ interface StreamRetryOptions {
12
12
  signal?: AbortSignal;
13
13
  providerRetryWait?: (delayMs: number, signal?: AbortSignal) => Promise<void>;
14
14
  acceptEmptyResponse?: boolean;
15
15
  }
16
+ /** Controls which replay-safe provider results may issue a fresh request. */
17
+ export interface ReplaySafeStreamRetryPolicy {
18
+ /** Retry benign terminal stops that contain no visible output. */
19
+ retryEmptyCompletion?: boolean;
20
+ /** Retry transient provider errors before output is committed. */
21
+ retryProviderErrors?: boolean;
22
+ /** Maximum transient provider-error retries; empty completions keep their shared fixed budget. */
23
+ maxProviderErrorRetries?: number;
24
+ }
16
25
  /**
17
- * Wrap a single-attempt provider stream with bounded empty-completion retries.
18
- * `attempt` MUST create a fresh request (and its own output message) on each
19
- * call so a retry never inherits stale metadata from an empty attempt.
26
+ * Re-issues a fresh provider request only while the current attempt remains
27
+ * replay-safe. Buffered pre-output events from discarded attempts never reach
28
+ * consumers.
20
29
  */
21
- export declare function withEmptyCompletionRetry<M, O extends EmptyCompletionRetryOptions>(model: M, context: Context, options: O | undefined, attempt: (model: M, context: Context, options?: O) => AssistantMessageEventStream): AssistantMessageEventStream;
30
+ export declare function withReplaySafeStreamRetry<M, O extends StreamRetryOptions>(model: M, context: Context, options: O | undefined, attempt: (model: M, context: Context, options?: O) => AssistantMessageEventStream, policy: ReplaySafeStreamRetryPolicy): AssistantMessageEventStream;
22
31
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@linxiraos/pi-ai",
4
- "version": "1.1.4",
4
+ "version": "1.1.5",
5
5
  "description": "Unified LLM API with automatic model discovery and provider configuration",
6
6
  "homepage": "https://linxira-os.github.io/zeta/",
7
7
  "author": "Can Boluk",
@@ -37,10 +37,10 @@
37
37
  "fmt": "biome format --write ."
38
38
  },
39
39
  "dependencies": {
40
- "@linxiraos/pi-omptype": "1.1.4",
41
- "@linxiraos/pi-catalog": "1.1.4",
42
- "@linxiraos/pi-utils": "1.1.4",
43
- "@linxiraos/pi-wire": "1.1.4"
40
+ "@linxiraos/pi-omptype": "1.1.5",
41
+ "@linxiraos/pi-catalog": "1.1.5",
42
+ "@linxiraos/pi-utils": "1.1.5",
43
+ "@linxiraos/pi-wire": "1.1.5"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/bun": "^1.3.14"