@linxiraos/pi-ai 1.1.14 → 1.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/CHANGELOG.md +2 -74
  2. package/README.md +2 -0
  3. package/THIRD-PARTY-NOTICES.txt +54 -25
  4. package/dist/types/auth/sqlite-credential-store.d.ts +2 -1
  5. package/dist/types/auth-broker/remote-store.d.ts +17 -0
  6. package/dist/types/auth-gateway/index.d.ts +1 -0
  7. package/dist/types/auth-gateway/session-state.d.ts +118 -0
  8. package/dist/types/auth-storage.d.ts +27 -6
  9. package/dist/types/error/body-error.d.ts +15 -0
  10. package/dist/types/error/flags.d.ts +22 -0
  11. package/dist/types/error/index.d.ts +1 -0
  12. package/dist/types/index.d.ts +2 -0
  13. package/dist/types/judgment/chat.d.ts +23 -0
  14. package/dist/types/judgment/index.d.ts +4 -0
  15. package/dist/types/judgment/text.d.ts +59 -0
  16. package/dist/types/judgment/types.d.ts +103 -0
  17. package/dist/types/judgment/typesafe.d.ts +53 -0
  18. package/dist/types/oneshot-retry.d.ts +6 -0
  19. package/dist/types/provider-session-state.d.ts +46 -0
  20. package/dist/types/providers/amazon-bedrock.d.ts +3 -0
  21. package/dist/types/providers/anthropic-signature.d.ts +25 -0
  22. package/dist/types/providers/anthropic-wire.d.ts +44 -7
  23. package/dist/types/providers/anthropic.d.ts +42 -0
  24. package/dist/types/providers/aws-sigv4.d.ts +12 -0
  25. package/dist/types/providers/github-copilot-headers.d.ts +71 -1
  26. package/dist/types/providers/openai-codex/request-transformer.d.ts +27 -0
  27. package/dist/types/providers/openai-completions.d.ts +1 -1
  28. package/dist/types/providers/openai-responses.d.ts +15 -0
  29. package/dist/types/providers/openai-shared.d.ts +28 -3
  30. package/dist/types/providers/vision-guard.d.ts +16 -2
  31. package/dist/types/registry/engine/common.d.ts +1 -1
  32. package/dist/types/registry/oauth/github-copilot.d.ts +3 -6
  33. package/dist/types/registry/oauth/kimi.d.ts +2 -1
  34. package/dist/types/registry/oauth/muse-code.d.ts +4 -4
  35. package/dist/types/registry/oauth/perplexity.d.ts +1 -7
  36. package/dist/types/registry/oauth/types.d.ts +10 -0
  37. package/dist/types/registry/types.d.ts +2 -0
  38. package/dist/types/stream.d.ts +2 -0
  39. package/dist/types/types.d.ts +57 -3
  40. package/dist/types/usage/charm-hyper.d.ts +2 -0
  41. package/dist/types/usage/openai-codex.d.ts +3 -1
  42. package/dist/types/usage.d.ts +11 -1
  43. package/dist/types/utils/block-symbols.d.ts +77 -0
  44. package/dist/types/utils/openai-http.d.ts +2 -0
  45. package/dist/types/utils/retry-after.d.ts +2 -0
  46. package/dist/types/utils/schema/wire.d.ts +4 -5
  47. package/dist/types/utils.d.ts +9 -0
  48. package/package.json +10 -6
  49. package/src/auth/sqlite-credential-store.ts +8 -33
  50. package/src/auth-broker/remote-store.ts +73 -8
  51. package/src/auth-broker/wire-schemas.ts +1 -0
  52. package/src/auth-gateway/index.ts +1 -0
  53. package/src/auth-gateway/server.ts +187 -74
  54. package/src/auth-gateway/session-state.ts +312 -0
  55. package/src/auth-storage.ts +165 -22
  56. package/src/error/body-error.ts +310 -0
  57. package/src/error/finalize.ts +9 -2
  58. package/src/error/flags.ts +96 -1
  59. package/src/error/index.ts +1 -0
  60. package/src/error/rate-limit.ts +14 -1
  61. package/src/error/retryable.ts +4 -0
  62. package/src/index.ts +2 -0
  63. package/src/judgment/chat.ts +93 -0
  64. package/src/judgment/index.ts +4 -0
  65. package/src/judgment/text-judge-retry.md +3 -0
  66. package/src/judgment/text-judge-state.md +5 -0
  67. package/src/judgment/text-judge.md +41 -0
  68. package/src/judgment/text.ts +309 -0
  69. package/src/judgment/types.ts +128 -0
  70. package/src/judgment/typesafe.ts +173 -0
  71. package/src/oneshot-retry.ts +13 -3
  72. package/src/provider-session-state.ts +56 -0
  73. package/src/providers/amazon-bedrock.ts +55 -28
  74. package/src/providers/anthropic-messages-server.ts +104 -23
  75. package/src/providers/anthropic-signature.ts +106 -0
  76. package/src/providers/anthropic-wire.ts +42 -9
  77. package/src/providers/anthropic.ts +773 -94
  78. package/src/providers/aws-sigv4.ts +16 -5
  79. package/src/providers/cursor.ts +84 -29
  80. package/src/providers/devin.ts +83 -29
  81. package/src/providers/github-copilot-headers.ts +242 -1
  82. package/src/providers/google-gemini-cli.ts +1 -1
  83. package/src/providers/google-shared.ts +1 -1
  84. package/src/providers/ollama.ts +11 -2
  85. package/src/providers/openai-chat-server.ts +4 -0
  86. package/src/providers/openai-codex/request-transformer.ts +36 -0
  87. package/src/providers/openai-codex-responses.ts +42 -14
  88. package/src/providers/openai-completions.ts +90 -22
  89. package/src/providers/openai-reasoning-fallback.ts +76 -25
  90. package/src/providers/openai-responses-server.ts +2 -1
  91. package/src/providers/openai-responses.ts +85 -20
  92. package/src/providers/openai-shared.ts +226 -55
  93. package/src/providers/pi-native-server.ts +3 -0
  94. package/src/providers/transform-messages.ts +7 -3
  95. package/src/providers/vision-guard.ts +28 -2
  96. package/src/registry/build.ts +1 -0
  97. package/src/registry/engine/common.ts +2 -1
  98. package/src/registry/engine/oauth-code.ts +10 -2
  99. package/src/registry/engine/refresh.ts +5 -2
  100. package/src/registry/oauth/github-copilot.ts +30 -6
  101. package/src/registry/oauth/kimi.ts +4 -4
  102. package/src/registry/oauth/muse-code.ts +2 -2
  103. package/src/registry/oauth/openai-codex.ts +7 -8
  104. package/src/registry/oauth/perplexity.ts +94 -28
  105. package/src/registry/oauth/types.ts +11 -0
  106. package/src/registry/types.ts +2 -0
  107. package/src/stream.ts +66 -8
  108. package/src/types.ts +59 -2
  109. package/src/usage/charm-hyper.ts +95 -0
  110. package/src/usage/claude.ts +139 -12
  111. package/src/usage/google-antigravity.ts +8 -2
  112. package/src/usage/kimi.ts +11 -1
  113. package/src/usage/openai-codex.ts +94 -11
  114. package/src/usage.ts +8 -1
  115. package/src/utils/block-symbols.ts +104 -0
  116. package/src/utils/empty-completion-retry.ts +7 -4
  117. package/src/utils/http-inspector.ts +32 -3
  118. package/src/utils/openai-http.ts +39 -3
  119. package/src/utils/proxy.ts +4 -3
  120. package/src/utils/retry-after.ts +12 -0
  121. package/src/utils/schema/normalize.ts +3 -3
  122. package/src/utils/schema/stamps.ts +33 -45
  123. package/src/utils/schema/wire.ts +9 -7
  124. package/src/utils.ts +67 -22
package/CHANGELOG.md CHANGED
@@ -2,79 +2,7 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
- ## [1.1.14] - 2026-09-12
5
+ ## [1.1.16] - 2026-09-19
6
6
 
7
- - 随 1.1.14 版本线发布:bazel 构建面(crates/*/BUILD.bazel)版本号纳入一致性检查,CI 原生构建与桌面冒烟守卫修复。
7
+ - 上游 v18.2.5 同步:stencil.so OAuth 认证回调、流式 JSON 代理解析优化。
8
8
 
9
- ## [1.1.13] - 2026-09-10
10
-
11
- - 上游 v18.1.16 同步:AuthStorage 合并封锁契约——凭据级 `blockedUntilMs` 与 `providerTimed` 时间线合并,先到的更长封锁在短提示到来时保持有效;GitHub Copilot OAuth 拆分公共 GitHub / GHE 双 client-id;Codex WebSocket 传输 abort 携带 cause 链。
12
-
13
- ## [1.1.12] - 2026-09-10
14
-
15
- - 品牌与合并工具链维护版本;无本包用户可见变更。
16
-
17
- ## [1.1.11] - 2026-09-08
18
-
19
- ### Added
20
-
21
- - Muse Code subscription sign-in, credential refresh, inference, and quota reporting in `/usage`, with durable rate-limit backoff so quota refresh recovers instead of repeatedly retrying.
22
-
23
- ## [1.1.10-omp18.1.12] - 2026-09-06
24
-
25
- ### Added
26
-
27
- - Added Muse Code subscription sign-in, credential refresh, inference, and quota reporting in `/usage`, with durable rate-limit backoff so quota refresh recovers instead of repeatedly retrying.
28
-
29
- ## [1.1.10-omp18.1.11] - 2026-09-05
30
-
31
- ### Fixed
32
-
33
- - Fixed OpenCode Go usage polls (`GET /zen/go/v1/usage`) missing `x-opencode-session` and omp's `User-Agent`: background polls now attribute with the stable install id so the requests OpenCode flags as `Bun fetch` carry the required session header.
34
- - GitHub Copilot sign-in now requests only basic profile access, restoring login for Enterprise organizations that reject repository, gist, and Codespaces permissions ([#10656](https://github.com/can1357/oh-my-pi/issues/10656)).
35
-
36
- ## [1.1.10] - 2026-09-07
37
-
38
- - GitHub Copilot sign-in now requests only basic profile access, restoring login for Enterprise organizations that reject repository, gist, and Codespaces permissions.
39
- - Transient gateway stream failures are now retried instead of surfacing as session errors.
40
-
41
- ## [1.1.9] - 2026-09-05
42
-
43
- - Z.ai OAuth key name sends zeta (merge restored the upstream oh-my-pi literal in tests); xAI/OpenAI-compatible requests send the zeta User-Agent again.
44
-
45
- ## [1.1.6] - 2026-08-30
46
-
47
- - 同步上游 OMP v18.0.9(`cc14e04f075d`)。
48
-
49
- ## [1.1.5] - 2026-08-26
50
-
51
- - 同步上游 OMP v18.0.5 / v18.0.6:新增 Yolo-Auto / OpenRouter 浏览器登录与 DeepInfra 支持,空补全重试重构(withReplaySafeStreamRetry)。
52
-
53
- ## [1.1.2] - 2026-08-25
54
-
55
- ### Fixed
56
-
57
- - Republished as 1.1.2 to reset the `latest` tag after the broken 1.1.0 (no functional change over 1.1.1).
58
-
59
- ## [1.1.1] - 2026-08-25
60
-
61
- ### Fixed
62
-
63
- - Published tarballs now carry real dependency versions instead of Bun's `catalog:` protocol (1.1.0 installs failed with "Unsupported URL Type catalog:").
64
-
65
- ## [1.1.0] - 2026-08-25
66
-
67
- ### Changed
68
-
69
- - 同步上游 OMP v18.0.3 / v18.0.4(内部运行时与构建改进,无独立用户可见变更)。
70
-
71
- ## [1.0.1] - 2026-08-14
72
-
73
- - Reset the version to 1.0.0 and republished under the `@linxiraos/*` scope, breaking from the `@linxiraos` version lineage.
74
-
75
- ## [1.0.0] - 2026-08-13
76
-
77
- ### Changed
78
-
79
- - Reset the version to 1.0.0 and republished under the `@linxiraos/*` scope, breaking from the `@linxiraos` version lineage.
80
- - Fixed Gemini thought summaries occasionally leaking a raw `` ```thinking `` / `` ``````thinking `` fence delimiter into the reasoning block, so it no longer shows up as fence spam in the thinking display or persisted transcripts ([#8719](https://github.com/can1357/oh-my-pi/issues/8719)).
package/README.md CHANGED
@@ -1084,6 +1084,8 @@ zeta 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.
@@ -10843,7 +10843,7 @@ RUST RUNTIME DEPENDENCY LICENSES
10843
10843
 
10844
10844
  Generated from Cargo.lock by cargo-about 0.8.2 in locked, offline, workspace, all-feature, all-target mode, then restricted using cargo metadata to normal and build edges reachable from the workspace (development-only edges are excluded). cargo-deny independently evaluates the complete all-target graph.
10845
10845
 
10846
- Native Opus (audiopus/audiopus_sys) and PCRE2 (pcre2/pcre2-sys) are covered by the exact crate license payloads below. inferno 0.12.8 is package-scoped as CDDL-1.0: its CDDL-covered source remains available in the locked crates.io source archive at https://crates.io/crates/inferno/0.12.8 and https://github.com/jonhoo/inferno. The full locked license text follows below.
10846
+ Native Opus (opus/opusic-sys) and PCRE2 (pcre2/pcre2-sys) are covered by the exact crate license payloads below. inferno 0.12.8 is package-scoped as CDDL-1.0: its CDDL-covered source remains available in the locked crates.io source archive at https://crates.io/crates/inferno/0.12.8 and https://github.com/jonhoo/inferno. The full locked license text follows below.
10847
10847
 
10848
10848
  -------------------------------------------------------------------------------
10849
10849
  License: Apache License 2.0 (Apache-2.0)
@@ -12509,6 +12509,58 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
12509
12509
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
12510
12510
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12511
12511
 
12512
+ -------------------------------------------------------------------------------
12513
+ License: BSD 3-Clause "New" or "Revised" License (BSD-3-Clause)
12514
+ Used by:
12515
+ - opusic-sys 0.7.5 (https://github.com/DoumanAsh/opusic-sys)
12516
+
12517
+ Full license text:
12518
+
12519
+ Copyright 2001-2023 Xiph.Org, Skype Limited, Octasic,
12520
+ Jean-Marc Valin, Timothy B. Terriberry,
12521
+ CSIRO, Gregory Maxwell, Mark Borgerding,
12522
+ Erik de Castro Lopo, Mozilla, Amazon
12523
+
12524
+ Redistribution and use in source and binary forms, with or without
12525
+ modification, are permitted provided that the following conditions
12526
+ are met:
12527
+
12528
+ - Redistributions of source code must retain the above copyright
12529
+ notice, this list of conditions and the following disclaimer.
12530
+
12531
+ - Redistributions in binary form must reproduce the above copyright
12532
+ notice, this list of conditions and the following disclaimer in the
12533
+ documentation and/or other materials provided with the distribution.
12534
+
12535
+ - Neither the name of Internet Society, IETF or IETF Trust, nor the
12536
+ names of specific contributors, may be used to endorse or promote
12537
+ products derived from this software without specific prior written
12538
+ permission.
12539
+
12540
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
12541
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
12542
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
12543
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
12544
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
12545
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
12546
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
12547
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
12548
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
12549
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
12550
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12551
+
12552
+ Opus is subject to the royalty-free patent licenses which are
12553
+ specified at:
12554
+
12555
+ Xiph.Org Foundation:
12556
+ https://datatracker.ietf.org/ipr/1524/
12557
+
12558
+ Microsoft Corporation:
12559
+ https://datatracker.ietf.org/ipr/1914/
12560
+
12561
+ Broadcom Corporation:
12562
+ https://datatracker.ietf.org/ipr/1526/
12563
+
12512
12564
  -------------------------------------------------------------------------------
12513
12565
  License: BSD 3-Clause "New" or "Revised" License (BSD-3-Clause)
12514
12566
  Used by:
@@ -13290,29 +13342,6 @@ jurisdiction of the Federal Courts of the Northern District of
13290
13342
  California and the state courts of the State of California, with
13291
13343
  venue lying in Santa Clara County, California.
13292
13344
 
13293
- -------------------------------------------------------------------------------
13294
- License: ISC License (ISC)
13295
- Used by:
13296
- - audiopus_sys 0.2.2 (https://github.com/lakelezz/audiopus_sys.git)
13297
-
13298
- Full license text:
13299
-
13300
- ISC License
13301
-
13302
- Copyright (c) 2019, Lakelezz
13303
-
13304
- Permission to use, copy, modify, and/or distribute this software for any
13305
- purpose with or without fee is hereby granted, provided that the above
13306
- copyright notice and this permission notice appear in all copies.
13307
-
13308
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13309
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13310
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13311
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13312
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13313
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13314
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
13315
-
13316
13345
  -------------------------------------------------------------------------------
13317
13346
  License: ISC License (ISC)
13318
13347
  Used by:
@@ -18734,7 +18763,7 @@ DEALINGS IN THE SOFTWARE.
18734
18763
  -------------------------------------------------------------------------------
18735
18764
  License: MIT License (MIT)
18736
18765
  Used by:
18737
- - opus 0.3.1 (https://github.com/SpaceManiac/opus-rs)
18766
+ - opus 0.4.0 (https://github.com/SpaceManiac/opus-rs)
18738
18767
 
18739
18768
  Full license text:
18740
18769
 
@@ -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 "@linxiraos/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[]>;
@@ -1,3 +1,4 @@
1
1
  export * from "./http.js";
2
+ export * from "./session-state.js";
2
3
  export * from "./server.js";
3
4
  export * from "./types.js";
@@ -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
+ }
@@ -1,5 +1,5 @@
1
1
  import type { ApiKeyResolver } from "./auth-retry.js";
2
- import type { OAuthAuthInfo, OAuthController, OAuthCredentials, OAuthProviderId } from "./registry/oauth/types.js";
2
+ import type { OAuthAuthInfo, OAuthController, OAuthCredentials, OAuthPrompt, OAuthProviderId } from "./registry/oauth/types.js";
3
3
  import type { Provider } from "./types.js";
4
4
  import type { ClientUsageIdentity, ClientUsageReport, ClientUsageSummary, CredentialRankingStrategy, ObservedUsageEntry, UsageHistoryEntry, UsageHistoryQuery, UsageLogger, UsageProvider, UsageReport } from "./usage.js";
5
5
  import { type CodexResetConsumeCode, type CodexResetCredit } from "./usage/openai-codex-reset.js";
@@ -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;
@@ -793,7 +800,7 @@ export declare class AuthStorage {
793
800
  * Lower priority than {@link setRuntimeApiKey} so a CLI `--api-key`
794
801
  * still wins for the duration of a single invocation.
795
802
  */
796
- setConfigApiKey(provider: string, apiKey: string): void;
803
+ setConfigApiKey(provider: string, apiKeyConfig: string): void;
797
804
  /**
798
805
  * Remove a single config-sourced API key override.
799
806
  */
@@ -808,6 +815,13 @@ export declare class AuthStorage {
808
815
  * Used for custom provider keys from models.json.
809
816
  */
810
817
  setFallbackResolver(resolver: (provider: string) => string | undefined): void;
818
+ /**
819
+ * Install the host's async config-value resolver. Coding-agent uses this so
820
+ * every stored/config credential reference shares command caching,
821
+ * failure backoff, and process hardening even when AuthStorage was created
822
+ * independently and later attached to a registry.
823
+ */
824
+ setConfigValueResolver(resolver: (config: string) => Promise<string | undefined>): void;
811
825
  /**
812
826
  * Reload credentials from storage.
813
827
  */
@@ -928,10 +942,7 @@ export declare class AuthStorage {
928
942
  /** onAuth is required by auth-storage but optional in OAuthController */
929
943
  onAuth: (info: OAuthAuthInfo) => void;
930
944
  /** onPrompt is required for some providers (github-copilot, openai-codex) */
931
- onPrompt: (prompt: {
932
- message: string;
933
- placeholder?: string;
934
- }) => Promise<string>;
945
+ onPrompt: (prompt: OAuthPrompt) => Promise<string>;
935
946
  }): Promise<OAuthLoginIdentity | undefined>;
936
947
  /**
937
948
  * Logout from a provider.
@@ -969,6 +980,7 @@ export declare class AuthStorage {
969
980
  ingestUsageHeaders(provider: Provider, headers: Record<string, string>, options?: {
970
981
  sessionId?: string;
971
982
  baseUrl?: string;
983
+ responseStatus?: number;
972
984
  }): boolean;
973
985
  /**
974
986
  * The {@link UsageProvider} registered for `provider`, or undefined when the
@@ -1116,6 +1128,15 @@ export declare class AuthStorage {
1116
1128
  pinSessionOAuthAccount(provider: string, sessionId: string, credentialId: number, options?: {
1117
1129
  lastUsedAtMs?: number;
1118
1130
  }): boolean;
1131
+ /**
1132
+ * Copy every stored credential affinity from one live session to another.
1133
+ *
1134
+ * The target receives its own sticky entries, so request resolution, usage
1135
+ * blocking, credential rotation, metadata, and persisted pins all continue
1136
+ * through the target session id without retaining a live dependency on the
1137
+ * source session.
1138
+ */
1139
+ inheritSessionCredentials(sourceSessionId: string, targetSessionId: string): number;
1119
1140
  /**
1120
1141
  * Resolve every stored OAuth credential for `provider` independently.
1121
1142
  *
@@ -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;
@@ -28,6 +28,21 @@ export declare const Flag: {
28
28
  };
29
29
  export type Flag = (typeof Flag)[keyof typeof Flag];
30
30
  export declare const STREAM_READ_ERROR_PATTERN: RegExp;
31
+ /** Python h2/httpx diagnostics forwarded through provider or proxy error events. */
32
+ export declare const PYTHON_HTTP2_STREAM_RESET_PATTERN: RegExp;
33
+ /** Python h11/httpx EOF while reading an HTTP/1.1 chunked response body. */
34
+ export declare const PYTHON_HTTP_INCOMPLETE_CHUNK_PATTERN: RegExp;
35
+ /** reqwest body-frame failures forwarded by the Codex HTTP proxy. */
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;
31
46
  export declare const TRANSIENT_TRANSPORT_PATTERN: RegExp;
32
47
  /**
33
48
  * Local llama.cpp / Ollama deterministic tool-call argument JSON parse failure.
@@ -125,6 +140,13 @@ export declare function stringify(id: number | undefined): string;
125
140
  * low-signal to trust once detached from a live transport `Error`, which keeps the broad pattern.
126
141
  */
127
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;
128
150
  /** Any malformed stream-envelope error (prefix-tagged or out-of-order events). */
129
151
  export declare function isStreamEnvelopeError(error: unknown): boolean;
130
152
  /** Stream-envelope errors safe to retry against the provider (event ordering only). */
@@ -2,6 +2,7 @@ export * from "./abort.js";
2
2
  export * from "./auth.js";
3
3
  export * from "./auth-classify.js";
4
4
  export * from "./aws.js";
5
+ export * from "./body-error.js";
5
6
  export * from "./classes.js";
6
7
  export * from "./finalize.js";
7
8
  export * from "./flags.js";
@@ -6,8 +6,10 @@ export * from "./auth-gateway/types.js";
6
6
  export * from "./auth-retry.js";
7
7
  export * from "./auth-storage.js";
8
8
  export * from "./error/rate-limit.js";
9
+ export * from "./judgment/index.js";
9
10
  export * from "./oneshot-retry.js";
10
11
  export * from "./provider-details.js";
12
+ export * from "./provider-session-state.js";
11
13
  export * from "./providers/anthropic.js";
12
14
  export * from "./providers/anthropic-client.js";
13
15
  export * from "./providers/azure-openai-responses.js";
@@ -0,0 +1,23 @@
1
+ import type { Api, AssistantMessage, Model, SimpleStreamOptions } from "../types.js";
2
+ import type { TextBackend } from "./text.js";
3
+ /**
4
+ * Output budget for keyword replies. Sized against two independent constraints:
5
+ * - Backends that ignore `disableReasoning` still emit a thinking preamble
6
+ * (e.g. Qwen3 via llama.cpp catalogued `reasoning: false` but still thinking;
7
+ * Anthropic via LiteLLM/Vertex, whose `openai-completions` route downgrades a
8
+ * disabled request to the lowest reasoning effort instead of turning thinking
9
+ * off). The keyword must have room to land after that preamble (issue #4355).
10
+ * - Anthropic-dialect proxies reject `max_tokens <= thinking.budget_tokens`. The
11
+ * pinned lowest effort maps to at least Anthropic's 1024-token minimum budget,
12
+ * so the cap MUST comfortably exceed 1024 or every call 400s with
13
+ * `max_tokens must be greater than thinking.budget_tokens` (issue #8610).
14
+ * `maxTokens` is a hard cap — non-thinking completions still return in a handful
15
+ * of tokens.
16
+ */
17
+ export declare const JUDGMENT_CHAT_MAX_TOKENS = 4096;
18
+ export type ChatTextBackendOptions = Pick<SimpleStreamOptions, "apiKey" | "sessionId" | "metadata"> & {
19
+ /** Receives every completed attempt (including transient failures) for usage accounting. */
20
+ onAttempt?: (message: AssistantMessage) => void;
21
+ };
22
+ /** Chat completions with reasoning disabled, temperature 0, and transient-failure retry. */
23
+ export declare function chatTextBackend(model: Model<Api>, options: ChatTextBackendOptions): TextBackend;
@@ -0,0 +1,4 @@
1
+ export * from "./chat.js";
2
+ export * from "./text.js";
3
+ export * from "./types.js";
4
+ export * from "./typesafe.js";
@@ -0,0 +1,59 @@
1
+ import type { Usage } from "../types.js";
2
+ import { type Answer, type Judge, type JudgeOptions, type JudgmentRequest, type JudgmentResult, type JudgmentState, type Question, type Questions } from "./types.js";
3
+ export interface TextPrompt {
4
+ system: string;
5
+ user: string;
6
+ /** Format-correction attempt; chat backends may enforce tool suppression on the wire. */
7
+ retry?: boolean;
8
+ }
9
+ export interface TextCompletion {
10
+ text: string;
11
+ /** Omitted by backends that do not meter tokens (on-device workers). */
12
+ usage?: Usage;
13
+ }
14
+ /** Completes a rendered judgment prompt; identifies itself for usage attribution. */
15
+ export interface TextBackend {
16
+ readonly api: string;
17
+ readonly provider: string;
18
+ readonly model: string;
19
+ /** State guard for agent-tuned chat models; on-device classifier workers may disable it. */
20
+ readonly guardState?: boolean;
21
+ /** Format-correction retries after a completion cannot be parsed. */
22
+ readonly parseRetries?: number;
23
+ complete(prompt: TextPrompt, options: JudgeOptions): Promise<TextCompletion>;
24
+ }
25
+ /** Render judgment state as top-level XML fields; nested values use block YAML. */
26
+ export declare function renderJudgmentState(state: JudgmentState): string;
27
+ /**
28
+ * Render a request: the system prompt carries the preamble and question
29
+ * definitions (constant across states, so prompt caches hit); the user message
30
+ * carries XML-field state followed by the answer-format cue. Small models act
31
+ * on a bare request (answer it, emit tool calls) instead of classifying it —
32
+ * explicit tags and the trailing cue keep them on task.
33
+ */
34
+ export declare function renderJudgmentPrompt(request: JudgmentRequest, options?: {
35
+ guardState?: boolean;
36
+ }): TextPrompt;
37
+ /**
38
+ * Earliest option label mentioned in `text`; a longer label wins a tie at the
39
+ * same position (so `xhigh` beats `high` where both start together).
40
+ */
41
+ export declare function parseChoiceReply<L extends string>(text: string, labels: readonly L[]): L | undefined;
42
+ /** `true` when a yes-word precedes any no-word, `false` for the reverse, `undefined` when neither appears. */
43
+ export declare function parseNoulReply(text: string): boolean | undefined;
44
+ /** First standalone integer in `[0, levels)`, or `undefined`. */
45
+ export declare function parseScoreReply(text: string, levels: number): number | undefined;
46
+ /**
47
+ * Split a multi-question reply into `id → answer text`. Lines are matched as
48
+ * `<id>: <answer>` (also `=` / `-` separators and quoted ids); unknown ids are
49
+ * ignored so a chatty preamble does not poison parsing.
50
+ */
51
+ export declare function splitAnswerLines(text: string, ids: readonly string[]): Map<string, string>;
52
+ /** Parse one question's keyword reply into its typed, one-hot answer. */
53
+ export declare function parseAnswer(id: string, question: Question, reply: string): Answer;
54
+ export declare class TextJudge implements Judge {
55
+ #private;
56
+ readonly label: string;
57
+ constructor(backend: TextBackend);
58
+ judge<Q extends Questions>(request: JudgmentRequest<Q>, options?: JudgeOptions): Promise<JudgmentResult<Q>>;
59
+ }