@linxiraos/pi-ai 1.1.27 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/CHANGELOG.md +2 -24
  2. package/README.md +1 -1
  3. package/dist/types/auth/affinity.d.ts +33 -6
  4. package/dist/types/auth/cascade.d.ts +25 -3
  5. package/dist/types/auth/oauth.d.ts +9 -6
  6. package/dist/types/auth/policy.d.ts +1 -0
  7. package/dist/types/auth/refresh.d.ts +1 -2
  8. package/dist/types/auth/select.d.ts +6 -4
  9. package/dist/types/auth/sqlite-credential-store.d.ts +21 -1
  10. package/dist/types/auth/store.d.ts +8 -2
  11. package/dist/types/auth/types.d.ts +87 -14
  12. package/dist/types/auth-broker/client.d.ts +3 -3
  13. package/dist/types/auth-broker/discover.d.ts +1 -1
  14. package/dist/types/auth-broker/remote-store.d.ts +6 -4
  15. package/dist/types/auth-broker/server.d.ts +2 -0
  16. package/dist/types/auth-broker/snapshot-cache.d.ts +12 -0
  17. package/dist/types/auth-gateway/dispatch.d.ts +7 -3
  18. package/dist/types/auth-gateway/http.d.ts +0 -2
  19. package/dist/types/auth-gateway/server.d.ts +3 -3
  20. package/dist/types/auth-gateway/session-state.d.ts +6 -0
  21. package/dist/types/auth-storage.d.ts +7 -6
  22. package/dist/types/dialect/terminator-wait.d.ts +19 -0
  23. package/dist/types/env-api-key.d.ts +21 -0
  24. package/dist/types/error/auth.d.ts +10 -0
  25. package/dist/types/error/flags.d.ts +23 -0
  26. package/dist/types/images/index.d.ts +2 -3
  27. package/dist/types/images/shared.d.ts +6 -0
  28. package/dist/types/index.d.ts +1 -0
  29. package/dist/types/judgment/index.d.ts +2 -1
  30. package/dist/types/judgment/native.d.ts +80 -0
  31. package/dist/types/judgment/openai-decisions.d.ts +3 -0
  32. package/dist/types/judgment/question-file.d.ts +52 -0
  33. package/dist/types/judgment/systemone.d.ts +7 -0
  34. package/dist/types/judgment/types.d.ts +2 -2
  35. package/dist/types/judgment/wire.d.ts +36 -0
  36. package/dist/types/provider-details.d.ts +1 -1
  37. package/dist/types/provider-session-state.d.ts +2 -2
  38. package/dist/types/providers/anthropic-client.d.ts +10 -0
  39. package/dist/types/providers/anthropic-state.d.ts +2 -0
  40. package/dist/types/providers/anthropic.d.ts +23 -1
  41. package/dist/types/providers/connect-frame.d.ts +44 -0
  42. package/dist/types/providers/cursor/interaction-query.d.ts +0 -2
  43. package/dist/types/providers/cursor.d.ts +8 -8
  44. package/dist/types/providers/google-auth.d.ts +4 -1
  45. package/dist/types/providers/google-shared.d.ts +24 -4
  46. package/dist/types/providers/inference-headers.d.ts +6 -0
  47. package/dist/types/providers/mock.d.ts +3 -1
  48. package/dist/types/providers/openai-codex/request-transformer.d.ts +2 -0
  49. package/dist/types/providers/openai-codex-responses.d.ts +1 -1
  50. package/dist/types/providers/openai-configuration-update.d.ts +20 -11
  51. package/dist/types/providers/openai-responses-wire.d.ts +1 -55
  52. package/dist/types/providers/openai-responses.d.ts +8 -0
  53. package/dist/types/providers/openai-shared.d.ts +16 -4
  54. package/dist/types/providers/pi-native-client.d.ts +1 -1
  55. package/dist/types/providers/transform-messages.d.ts +14 -0
  56. package/dist/types/providers/vision-guard.d.ts +1 -1
  57. package/dist/types/registry/oauth/cloudflare-workers-ai.d.ts +3 -0
  58. package/dist/types/registry/oauth/cursor.d.ts +10 -2
  59. package/dist/types/registry/oauth/index.d.ts +2 -0
  60. package/dist/types/stream.d.ts +0 -21
  61. package/dist/types/transcription/types.d.ts +2 -1
  62. package/dist/types/types.d.ts +76 -11
  63. package/dist/types/usage.d.ts +2 -0
  64. package/dist/types/utils/anthropic-auth.d.ts +21 -7
  65. package/dist/types/utils/aws-profile.d.ts +5 -0
  66. package/dist/types/utils/block-symbols.d.ts +14 -0
  67. package/dist/types/utils/glyph-codec.d.ts +1 -1
  68. package/dist/types/utils/leaked-thinking-stream.d.ts +1 -1
  69. package/dist/types/utils/resolve-peer.d.ts +2 -0
  70. package/dist/types/utils/retry-wait.d.ts +9 -0
  71. package/dist/types/utils/schema/normalize.d.ts +8 -3
  72. package/package.json +7 -7
  73. package/src/auth/affinity.ts +130 -37
  74. package/src/auth/blocks.ts +90 -14
  75. package/src/auth/cascade.ts +68 -9
  76. package/src/auth/health.ts +2 -2
  77. package/src/auth/oauth.ts +25 -10
  78. package/src/auth/policy.ts +10 -1
  79. package/src/auth/pool.ts +0 -5
  80. package/src/auth/refresh.ts +17 -12
  81. package/src/auth/resets.ts +1 -1
  82. package/src/auth/rotation.ts +8 -2
  83. package/src/auth/select.ts +99 -29
  84. package/src/auth/sqlite-credential-store.ts +119 -49
  85. package/src/auth/store.ts +8 -2
  86. package/src/auth/types.ts +96 -15
  87. package/src/auth/usage-cache.ts +16 -5
  88. package/src/auth/usage.ts +2 -2
  89. package/src/auth-broker/client.ts +7 -4
  90. package/src/auth-broker/discover.ts +6 -5
  91. package/src/auth-broker/remote-store.ts +200 -62
  92. package/src/auth-broker/server.ts +316 -130
  93. package/src/auth-broker/snapshot-cache.ts +142 -2
  94. package/src/auth-gateway/dispatch.ts +9 -5
  95. package/src/auth-gateway/http.ts +0 -8
  96. package/src/auth-gateway/routes/systemone.ts +16 -12
  97. package/src/auth-gateway/server.ts +34 -19
  98. package/src/auth-gateway/session-state.ts +51 -9
  99. package/src/auth-storage.ts +23 -9
  100. package/src/dialect/deepseek.ts +10 -2
  101. package/src/dialect/gemini.ts +8 -2
  102. package/src/dialect/hermes.ts +8 -2
  103. package/src/dialect/kimi.ts +8 -2
  104. package/src/dialect/qwen-xml.ts +8 -2
  105. package/src/dialect/qwen3.ts +8 -2
  106. package/src/dialect/terminator-wait.ts +42 -0
  107. package/src/env-api-key.ts +78 -0
  108. package/src/error/auth.ts +20 -0
  109. package/src/error/flags.ts +93 -0
  110. package/src/error/rate-limit.ts +8 -6
  111. package/src/images/index.ts +3 -17
  112. package/src/images/openai-hosted.ts +13 -4
  113. package/src/images/openai-images.ts +19 -13
  114. package/src/images/shared.ts +10 -2
  115. package/src/index.ts +1 -0
  116. package/src/judgment/index.ts +2 -1
  117. package/src/judgment/native.ts +333 -0
  118. package/src/judgment/openai-decisions-predicate.md +9 -0
  119. package/src/judgment/openai-decisions.ts +129 -0
  120. package/src/judgment/question-file.ts +90 -0
  121. package/src/judgment/systemone.ts +65 -0
  122. package/src/judgment/text.ts +9 -1
  123. package/src/judgment/types.ts +2 -2
  124. package/src/judgment/wire.ts +42 -0
  125. package/src/provider-details.ts +1 -1
  126. package/src/provider-session-state.ts +2 -2
  127. package/src/providers/amazon-bedrock.ts +19 -8
  128. package/src/providers/anthropic-client.ts +16 -1
  129. package/src/providers/anthropic-state.ts +6 -0
  130. package/src/providers/anthropic.ts +857 -202
  131. package/src/providers/apple-foundation-models.ts +10 -4
  132. package/src/providers/aws-credentials.ts +2 -2
  133. package/src/providers/azure-openai-responses.ts +1 -1
  134. package/src/providers/connect-frame.ts +107 -0
  135. package/src/providers/cursor/interaction-query.ts +1 -9
  136. package/src/providers/cursor.ts +510 -101
  137. package/src/providers/devin.ts +65 -57
  138. package/src/providers/factory-droid/gemini.ts +38 -51
  139. package/src/providers/gitlab-duo-workflow.ts +5 -2
  140. package/src/providers/google-auth.ts +10 -3
  141. package/src/providers/google-shared.ts +134 -105
  142. package/src/providers/google-vertex.ts +0 -1
  143. package/src/providers/google.ts +1 -1
  144. package/src/providers/inference-headers.ts +19 -0
  145. package/src/providers/mock.ts +4 -0
  146. package/src/providers/ollama.ts +1 -1
  147. package/src/providers/openai-codex/request-transformer.ts +16 -11
  148. package/src/providers/openai-codex-responses.ts +143 -70
  149. package/src/providers/openai-completions.ts +9 -2
  150. package/src/providers/openai-configuration-update.ts +54 -15
  151. package/src/providers/openai-responses-wire.ts +1 -55
  152. package/src/providers/openai-responses.ts +90 -29
  153. package/src/providers/openai-shared.ts +154 -43
  154. package/src/providers/pi-native-client.ts +2 -2
  155. package/src/providers/systemone-server.ts +1 -1
  156. package/src/providers/transcriptions-server.ts +1 -1
  157. package/src/providers/transform-messages.ts +238 -82
  158. package/src/providers/vision-guard.ts +1 -1
  159. package/src/registry/aws.ts +51 -14
  160. package/src/registry/cloudflare-ai-gateway.ts +26 -3
  161. package/src/registry/hooks/api-key.ts +1 -0
  162. package/src/registry/hooks/env.ts +2 -5
  163. package/src/registry/oauth/callback-server.ts +6 -1
  164. package/src/registry/oauth/cloudflare-ai-gateway.ts +2 -2
  165. package/src/registry/oauth/cloudflare-workers-ai.ts +32 -0
  166. package/src/registry/oauth/cursor.ts +80 -17
  167. package/src/registry/oauth/index.ts +5 -0
  168. package/src/registry/oauth/snowflake.ts +1 -1
  169. package/src/stream.ts +5 -72
  170. package/src/transcription/types.ts +2 -1
  171. package/src/types.ts +101 -12
  172. package/src/usage/claude.ts +16 -12
  173. package/src/usage/commandcode.ts +1 -1
  174. package/src/usage/cursor.ts +14 -25
  175. package/src/usage/github-copilot.ts +1 -1
  176. package/src/usage/kimi.ts +1 -1
  177. package/src/usage/minimax-code.ts +8 -1
  178. package/src/usage.ts +8 -0
  179. package/src/utils/anthropic-auth.ts +34 -10
  180. package/src/utils/aws-profile.ts +10 -4
  181. package/src/utils/block-symbols.ts +17 -0
  182. package/src/utils/empty-completion-retry.ts +2 -3
  183. package/src/utils/glyph-codec.ts +200 -7
  184. package/src/utils/leaked-thinking-stream.ts +47 -25
  185. package/src/utils/resolve-peer.ts +7 -0
  186. package/src/utils/retry-wait.ts +19 -0
  187. package/src/utils/schema/CONSTRAINTS.md +9 -7
  188. package/src/utils/schema/fields.ts +20 -0
  189. package/src/utils/schema/normalize.ts +65 -23
  190. package/src/utils/schema/wire.ts +3 -3
  191. package/src/utils/thinking-loop.ts +18 -3
  192. package/src/utils/transport-fetch.ts +1 -1
  193. package/src/utils.ts +22 -6
  194. package/dist/types/judgment/typesafe.d.ts +0 -49
  195. package/src/judgment/typesafe.ts +0 -183
@@ -17,6 +17,8 @@ export interface AuthGatewayRouteOptions {
17
17
  resolveModel: ModelResolver;
18
18
  /** Optional supplier for `/v1/models` listing. Returns the full model array. */
19
19
  listModels?: () => Iterable<Model<Api>>;
20
+ /** Providers the host does not serve; `/v1/usage` and `/v1/credentials/check` leave their accounts out. */
21
+ excludeProviders?: ReadonlySet<string>;
20
22
  /** Upstream transport for every provider call; defaults to global `fetch`. Test seam. */
21
23
  fetch?: FetchImpl;
22
24
  }
@@ -63,9 +65,11 @@ export declare function resolveGatewayApiKey(storage: AuthStorage, model: Model<
63
65
  * to a sibling (usage-limit block vs credential invalidation by error class).
64
66
  *
65
67
  * `lastKey` tracks the most recent bearer so the switch step invalidates the
66
- * credential that actually failed. `onResolvedKey` observes every rotation;
67
- * routes that retain provider session state use it to re-key the account
68
- * lease, one-shot routes pass `undefined`.
68
+ * credential that actually failed; a retry context's `previousKey` wins, since
69
+ * concurrent operations sharing one resolver (split judgment chunks) each know
70
+ * the bearer they sent. `onResolvedKey` observes every rotation; routes that
71
+ * retain provider session state use it to re-key the account lease, one-shot
72
+ * routes pass `undefined`.
69
73
  */
70
74
  export declare function buildGatewayApiKeyResolver(storage: AuthStorage, model: Model<Api>, sessionId: string, initialKey: ResolvedApiKey, requestSignal: AbortSignal, format: string, peer: string, onResolvedKey?: (apiKey: string) => void): ApiKeyResolver;
71
75
  /**
@@ -16,8 +16,6 @@ export declare function gatewayResponseHeaders(model: Model<Api>, info: {
16
16
  costUsd?: number;
17
17
  startedAt?: number;
18
18
  }): Record<string, string>;
19
- /** Use the socket peer unless the gateway explicitly trusts its reverse proxy. */
20
- export declare function resolvePeer(req: Request, socketAddress: string, trustProxyHeaders?: boolean): string;
21
19
  /** Keep configured gateway credentials out of URL and forwarded/logged request fields. */
22
20
  export declare function hasMisplacedBearer(req: Request, url: URL, tokens: ReadonlySet<string>): boolean;
23
21
  /**
@@ -1,12 +1,12 @@
1
1
  /**
2
- * zeta auth-gateway router and HTTP server.
2
+ * zetacode auth-gateway router and HTTP server.
3
3
  *
4
4
  * Accepts any provider-format request (OpenAI chat-completions, Anthropic
5
5
  * messages, OpenAI Responses) and dispatches through pi-ai's `streamSimple()`
6
6
  * — which handles credential injection, anthropic-beta headers, codex
7
7
  * websocket transport, and all the per-provider intricacies. The gateway is
8
- * pure protocol translation: foreign wire → zeta Context → pi-ai stream() →
9
- * zeta events → foreign wire.
8
+ * pure protocol translation: foreign wire → omp Context → pi-ai stream() →
9
+ * omp events → foreign wire.
10
10
  *
11
11
  * Endpoints:
12
12
  * GET /healthz → unauth; ok + version
@@ -63,6 +63,12 @@ export interface AuthGatewaySessionStateRequest {
63
63
  * continues.
64
64
  */
65
65
  context: Context;
66
+ /**
67
+ * `JSON.stringify(context.tools)` when the caller already serialized it
68
+ * (the gateway derives its `sessionId` from the same string). Recomputed
69
+ * from `context` when absent.
70
+ */
71
+ toolsJson?: string;
66
72
  /**
67
73
  * Stable identity of the account this request's credential resolved to.
68
74
  * A change means the gateway switched the session to a sibling credential,
@@ -1,6 +1,6 @@
1
1
  import type { AuthCredentialStore } from "./auth/store.js";
2
2
  import type { AuthAccountPolicies, AuthApiKeyOptions, AuthStorageOptions, BlocksApi, CredentialsApi, HealthApi, KeysApi, LimitsApi, OAuthApi, ResetsApi, SessionsApi, UsageApi } from "./auth/types.js";
3
- export { isSqliteBusyError, isSqliteCorruptionError, SqliteAuthCredentialStore } from "./auth/sqlite-credential-store.js";
3
+ export { isSameOAuthAccount, isSqliteBusyError, isSqliteCorruptionError, matchesReplacementCredential, resolveCredentialIdentityKey, SqliteAuthCredentialStore, } from "./auth/sqlite-credential-store.js";
4
4
  export * from "./auth/store.js";
5
5
  export * from "./auth/types.js";
6
6
  /**
@@ -35,8 +35,9 @@ export declare class AuthStorage {
35
35
  /**
36
36
  * Apply new account routing policy (live `auth.accountPolicies` /
37
37
  * `retry.usageReservePct` change). Throws a configuration error, leaving the
38
- * active policy untouched, when the policy is malformed or does not match the
39
- * stored OAuth accounts.
38
+ * active policy untouched, when a policy is malformed, a selector matches
39
+ * several stored OAuth accounts, or two policies claim the same account; a
40
+ * policy naming an absent account stays inactive and logs a warning.
40
41
  */
41
42
  setAccountPolicies(config: {
42
43
  accountPolicies: AuthAccountPolicies;
@@ -46,9 +47,9 @@ export declare class AuthStorage {
46
47
  * Swap the backing credential store in place (live `auth.broker.url` change).
47
48
  * Loads `store` into fresh store-bound state — pins, blocks, and usage caches are
48
49
  * keyed by the old store's row ids — then closes the previous store. Runtime key
49
- * overrides, account policies, usage-provider overrides, and credential event
50
- * subscribers carry over. On a load failure `store` is closed and the current
51
- * store stays active.
50
+ * overrides, account policies, session account restrictions, usage-provider
51
+ * overrides, and credential event subscribers carry over. On a load failure
52
+ * `store` is closed and the current store stays active.
52
53
  */
53
54
  replaceStore(store: AuthCredentialStore, options?: {
54
55
  sourceLabel?: string;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Fast path for in-band scanners that sit inside a body waiting for one fixed
3
+ * terminator (a tool-call close tag) and emit nothing until it arrives.
4
+ *
5
+ * Appending each delta to the scanner's string buffer and calling `indexOf` on
6
+ * it flattens the growing rope on every delta, so a long in-band tool call cost
7
+ * O(n²) copying and scanning. While armed, deltas are set aside and only the new
8
+ * text plus the terminator-length overlap with what came before is searched;
9
+ * the buffer is rebuilt once, when the terminator shows up or the stream ends.
10
+ */
11
+ export declare class TerminatorWait {
12
+ #private;
13
+ /** Start deferring; `buffered` is the scanner's pending body, known not to contain `terminator`. */
14
+ arm(terminator: string, buffered: string): void;
15
+ /** Take `text` while the terminator is still absent; false means the caller must {@link release} and scan. */
16
+ absorb(text: string): boolean;
17
+ /** Stop deferring and return `buffered` with every absorbed delta appended. */
18
+ release(buffered: string): string;
19
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Get API key for provider from known environment variables, e.g. OPENAI_API_KEY.
3
+ *
4
+ * Will not return API keys for providers that require OAuth tokens.
5
+ * Checks Bun.env, then cwd/.env, then ~/.env.
6
+ */
7
+ export declare function getEnvApiKey(provider: string): string | undefined;
8
+ /**
9
+ * Name of the environment variable that backs `getEnvApiKey` for a provider,
10
+ * when that provider maps to a single named variable (e.g. `github-copilot` →
11
+ * `COPILOT_GITHUB_TOKEN`). Returns undefined for providers whose env fallback
12
+ * is computed (multi-var pickers, Vertex ADC / Bedrock probes, …) since no
13
+ * single variable name describes the source.
14
+ */
15
+ export declare function getEnvApiKeyName(provider: string): string | undefined;
16
+ /**
17
+ * Enumerate every provider that has an env-var fallback for `getEnvApiKey`.
18
+ * Used by `zetacode auth-broker migrate --include-env` to discover env-sourced keys
19
+ * that should be uploaded to the broker.
20
+ */
21
+ export declare function listProvidersWithEnvKey(): string[];
@@ -10,6 +10,16 @@ export declare class MissingApiKeyError extends Error {
10
10
  readonly provider: string | undefined;
11
11
  constructor(provider?: string, message?: string);
12
12
  }
13
+ /**
14
+ * Every usable OAuth credential for a provider failed to refresh with a
15
+ * retryable error (network blip, timeout, 5xx). The stored credentials are
16
+ * intact, so this is classified transient: retrying the request can succeed,
17
+ * unlike {@link MissingApiKeyError}. The refresh failure is kept as `cause`.
18
+ */
19
+ export declare class OAuthRefreshUnavailableError extends Error {
20
+ readonly provider: string;
21
+ constructor(provider: string, cause: unknown);
22
+ }
13
23
  /** A user-facing login flow required an `onPrompt` callback that was not supplied. */
14
24
  export declare class OnPromptRequiredError extends Error {
15
25
  constructor(providerLabel: string);
@@ -23,6 +23,16 @@ export declare const Flag: {
23
23
  readonly FastModeUnsupported: 536870912;
24
24
  /** OAuth refresh failed definitively — the stored grant is dead, re-login required. */
25
25
  readonly OAuthExpiry: 1073741824;
26
+ /**
27
+ * An Anthropic-compatible endpoint rejected the `cache_control` field with a
28
+ * 400, so prompt-cache breakpoints must be dropped for it.
29
+ *
30
+ * Every bit from {@link Flag.Class} up is already taken, so this claims a low
31
+ * bit instead. Those belong to the raw-status lane — an unclassified id is an
32
+ * HTTP status (100-599, see `statusFromId`) — and 0x800 is 2048, above every
33
+ * status value, so no raw status id can set it.
34
+ */
35
+ readonly CacheControlUnsupported: 2048;
26
36
  /** HTTP 413 byte/media rejection — token compaction cannot shrink bytes or media budgets (#9235). */
27
37
  readonly PayloadRejected: 2147483648;
28
38
  };
@@ -113,6 +123,19 @@ export declare function isGrammarError(error: unknown): boolean;
113
123
  * Accessor for {@link Flag.FastModeUnsupported}.
114
124
  */
115
125
  export declare function isFastModeUnsupported(error: unknown): boolean;
126
+ /**
127
+ * An Anthropic-compatible endpoint returned a 400 rejecting something about
128
+ * `cache_control`. Whether it refused the field or one nested option is not
129
+ * decidable here (see {@link CACHE_CONTROL_FIELD_PATTERN}); the caller's retry
130
+ * ladder settles it by replaying.
131
+ * Accessor for {@link Flag.CacheControlUnsupported}.
132
+ *
133
+ * Unlike the high-bit accessors this also requires a classified id. The flag
134
+ * sits in the raw-status lane (see {@link Flag.CacheControlUnsupported}), and
135
+ * while no HTTP status reaches 0x800, `is` is a bare bit test — the extra gate
136
+ * keeps a stray non-HTTP status out of the retry path.
137
+ */
138
+ export declare function isCacheControlUnsupported(error: unknown): boolean;
116
139
  /**
117
140
  * Cline's gateway gates some roster entries (certain free-tier models) to its
118
141
  * own product surfaces with a 403. The API key is valid — the restriction is
@@ -1,4 +1,4 @@
1
- import type { Api, Model } from "@linxiraos/pi-catalog/types";
1
+ import { type Api, type ImageGenerationApi, type Model } from "@linxiraos/pi-catalog/types";
2
2
  import type { ImageGenerationOptions, ImageGenerationRequest, ImageGenerationResult } from "./types.js";
3
3
  export * from "./google-antigravity.js";
4
4
  export * from "./google-generative-ai.js";
@@ -6,8 +6,7 @@ export * from "./openai-hosted.js";
6
6
  export * from "./openai-images.js";
7
7
  export * from "./openrouter-images.js";
8
8
  export * from "./types.js";
9
- /** Catalog APIs {@link generateImage} serves; the hosted Responses pair needs an explicit carrier model. */
10
- export type ImageGenerationApi = "openai-images" | "openrouter-images" | "google-generative-ai" | "google-gemini-cli" | "openai-responses" | "openai-codex-responses";
9
+ export type { ImageGenerationApi } from "@linxiraos/pi-catalog/types";
11
10
  /** Whether a catalog API generates images through one of the pi-ai image clients. */
12
11
  export declare function isImageGenerationApi(api: Api): api is ImageGenerationApi;
13
12
  /** Generate (or edit, when `request.inputImages` is set) images through the transport selected by the model's `api`. */
@@ -32,6 +32,12 @@ export declare function decodeImageResponse(value: unknown, fetch: FetchImpl, si
32
32
  images: GeneratedImage[];
33
33
  usage: Usage;
34
34
  }>;
35
+ /**
36
+ * Mime type of a base64 image, read from its header only. 64 base64 chars
37
+ * decode to 48 bytes, past every magic number `parseImageMetadata` checks, so
38
+ * multi-MB payloads are never fully decoded just to be labelled.
39
+ */
40
+ export declare function sniffBase64ImageMimeType(base64: string): string | undefined;
35
41
  export declare function toDataUrl(image: GeneratedImage): string;
36
42
  export declare function resolveOpenAIImageSize(aspectRatio?: string, imageSize?: string): string | undefined;
37
43
  export {};
@@ -39,6 +39,7 @@ export type * from "./providers/openai-responses.js";
39
39
  export type * from "./providers/synthetic.js";
40
40
  export * from "./registry/index.js";
41
41
  export { resolveCacheRetention } from "./utils.js";
42
+ export * from "./env-api-key.js";
42
43
  export * from "./stream.js";
43
44
  export * from "./types.js";
44
45
  export * from "./usage.js";
@@ -1,4 +1,5 @@
1
1
  export * from "./chat.js";
2
+ export * from "./native.js";
3
+ export * from "./question-file.js";
2
4
  export * from "./text.js";
3
5
  export * from "./types.js";
4
- export * from "./typesafe.js";
@@ -0,0 +1,80 @@
1
+ import type { Api, FetchImpl } from "@linxiraos/pi-catalog/types";
2
+ import { type ApiKey } from "../auth-retry.js";
3
+ import * as AIError from "../error/index.js";
4
+ import type { Model, Usage } from "../types.js";
5
+ import { type Judge, type JudgeOptions, type JudgmentRequest, type JudgmentResult, type Questions } from "./types.js";
6
+ import type { JudgmentWire } from "./wire.js";
7
+ export declare const TYPESAFE_PROVIDER = "typesafe";
8
+ export declare const TYPESAFE_DEFAULT_MODEL = "jev-latest";
9
+ declare const JUDGMENT_WIRES: {
10
+ readonly typesafe: JudgmentWire;
11
+ readonly "openrouter-decisions": JudgmentWire;
12
+ readonly "workers-ai-systemone": JudgmentWire;
13
+ readonly "openai-decisions": JudgmentWire;
14
+ };
15
+ /** APIs {@link NativeJudge} can serve. */
16
+ export type JudgmentApi = keyof typeof JUDGMENT_WIRES;
17
+ /** Whether a catalog API answers judgments natively. */
18
+ export declare function isJudgmentApi(api: Api): api is JudgmentApi;
19
+ /** `TYPESAFE_BASE_URL` when set, else the public API root; trailing slashes stripped. */
20
+ export declare function typesafeBaseUrl(): string;
21
+ /** `TYPESAFE_DEFAULT_MODEL` when set, else {@link TYPESAFE_DEFAULT_MODEL}. */
22
+ export declare function typesafeModel(): string;
23
+ /** Credential and transport overrides for a judge; see {@link createNativeJudge}. */
24
+ export interface NativeJudgeConnection {
25
+ apiKey: ApiKey;
26
+ /** Static headers attached to judgment requests (e.g. proxy routing, gateway auth). */
27
+ headers?: Record<string, string>;
28
+ fetch?: FetchImpl;
29
+ }
30
+ export interface NativeJudgeOptions extends NativeJudgeConnection {
31
+ /** Wire dialect; defaults to TypeSafe's own API. */
32
+ api?: JudgmentApi;
33
+ /** Catalog provider reported on results; defaults to {@link TYPESAFE_PROVIDER}. */
34
+ provider?: string;
35
+ /** Defaults to {@link typesafeBaseUrl}. */
36
+ baseUrl?: string;
37
+ /** Wire model id; defaults to {@link typesafeModel}. */
38
+ model?: string;
39
+ /** Per-attempt timeout; defaults to {@link DEFAULT_TIMEOUT_MS}. */
40
+ timeoutMs?: number;
41
+ /**
42
+ * Most questions per request the endpoint accepts, a positive integer; larger
43
+ * requests are split. Unset: no cap.
44
+ */
45
+ maxQuestions?: number;
46
+ }
47
+ /** Per-call options for {@link NativeJudge.judge}. */
48
+ export interface NativeJudgeCallOptions extends JudgeOptions {
49
+ /**
50
+ * Called before a split judgment rejects, with the summed usage of the chunks that had already
51
+ * succeeded: billed upstream, but their answers are discarded with the failure. Not called when
52
+ * no chunk succeeded or the request was not split.
53
+ */
54
+ onPartialUsage?: (usage: Usage) => void;
55
+ }
56
+ /** Non-2xx response from a native judgment API. */
57
+ export declare class JudgmentApiError extends AIError.ProviderHttpError {
58
+ readonly name = "JudgmentApiError";
59
+ }
60
+ export declare class NativeJudge implements Judge {
61
+ #private;
62
+ readonly label: string;
63
+ readonly api: JudgmentApi;
64
+ readonly provider: string;
65
+ /** Wire model id sent with every request. */
66
+ readonly model: string;
67
+ readonly baseUrl: string;
68
+ constructor(options: NativeJudgeOptions);
69
+ judge<Q extends Questions>(request: JudgmentRequest<Q>, options?: NativeJudgeCallOptions): Promise<JudgmentResult<Q>>;
70
+ }
71
+ /**
72
+ * The {@link NativeJudge} for a catalog judge model: its API's dialect, wire id
73
+ * (`requestModelId ?? id`), base URL, and catalog question cap
74
+ * (`judgment-questions-max`). Shared by the coding agent's judge chain and the
75
+ * auth-gateway System One route so both address a model the same way.
76
+ *
77
+ * @throws ConfigurationError when the model's API is not a judgment API.
78
+ */
79
+ export declare function createNativeJudge(model: Model, connection: NativeJudgeConnection): NativeJudge;
80
+ export {};
@@ -0,0 +1,3 @@
1
+ import { type JudgmentWire } from "./wire.js";
2
+ /** OpenAI's `/v1/decisions` route. */
3
+ export declare const openaiDecisionsWire: JudgmentWire;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Judge questions authored as JSON files: `instructions` plus optional
3
+ * `criteria`, keyed by question id. A JSON import widens every string, so a
4
+ * question's kind follows from the shape of its `criteria` rather than a
5
+ * `type` field — the same rule at compile time ({@link QuestionFor}) and at
6
+ * load ({@link judgeQuestions}):
7
+ * - a list of levels, lowest first → {@link ScoreQuestion}
8
+ * - absent, or only `true`/`false` rubrics → {@link NoulQuestion}
9
+ * - any other labels → {@link ChoiceQuestion} over them; `{}` when the caller
10
+ * supplies every label (table rows, labels shared with another question)
11
+ *
12
+ * Instructions may be Handlebars templates; {@link renderQuestion} fills them.
13
+ *
14
+ * @example
15
+ * ```ts ignore
16
+ * import graph from "./auto-graph.json" with { type: "json" };
17
+ * const QUESTIONS = judgeQuestions(graph);
18
+ * QUESTIONS.shading; // ChoiceQuestion<"shared" | "series" | "row">
19
+ * renderQuestion(QUESTIONS.order, { column: "latency" });
20
+ * ```
21
+ */
22
+ import { prompt } from "@linxiraos/pi-utils";
23
+ import type { ChoiceQuestion, NoulQuestion, Question, ScoreQuestion } from "./types.js";
24
+ /** One question as a JSON question file writes it; {@link QuestionFor} gives its kind. */
25
+ export interface QuestionSpec {
26
+ instructions: string;
27
+ criteria?: string[] | {
28
+ readonly [label: string]: string | null;
29
+ };
30
+ }
31
+ /** A JSON question file: {@link QuestionSpec}s keyed by question id. */
32
+ export interface QuestionFile {
33
+ readonly [id: string]: QuestionSpec;
34
+ }
35
+ /** The question a {@link QuestionSpec} declares, with choice labels taken from its criteria keys. */
36
+ export type QuestionFor<S extends QuestionSpec> = S extends {
37
+ criteria: string[];
38
+ } ? ScoreQuestion : S extends {
39
+ criteria: infer C extends object;
40
+ } ? [keyof C] extends [never] ? ChoiceQuestion : [keyof C] extends ["true" | "false"] ? NoulQuestion : ChoiceQuestion<Extract<keyof C, string>> : NoulQuestion;
41
+ /** Every question a {@link QuestionFile} declares, keyed as in the file. */
42
+ export type QuestionsFor<F extends QuestionFile> = {
43
+ [K in keyof F]: QuestionFor<F[K]>;
44
+ };
45
+ /**
46
+ * The typed questions of a JSON question file; answers to them come back typed
47
+ * through {@link JudgmentResult}.
48
+ * @throws when a score question lists fewer than two levels.
49
+ */
50
+ export declare function judgeQuestions<F extends QuestionFile>(file: F): QuestionsFor<F>;
51
+ /** `question` with its instructions rendered as a Handlebars template over `context`. */
52
+ export declare function renderQuestion<Q extends Question>(question: Q, context: prompt.TemplateContext): Q;
@@ -0,0 +1,7 @@
1
+ import { type JudgmentWire } from "./wire.js";
2
+ /** TypeSafe's own route, shared by every System One server. */
3
+ export declare const typesafeWire: JudgmentWire;
4
+ /** OpenRouter Decisions: the System One body under `/api/alpha`. */
5
+ export declare const openrouterDecisionsWire: JudgmentWire;
6
+ /** Cloudflare Workers AI decision models (Clef) through the account-scoped `ai/run` route. */
7
+ export declare const workersAiWire: JudgmentWire;
@@ -7,7 +7,7 @@
7
7
  * — about one {@link JudgmentState}. Every question in a request sees the same
8
8
  * state and is answered independently, so callers batch independent questions
9
9
  * into one call. The shape mirrors TypeSafe's System One API so the native
10
- * backend ({@link TypeSafeJudge}) forwards requests verbatim, while the text
10
+ * backend ({@link NativeJudge}) forwards requests verbatim, while the text
11
11
  * bridge ({@link TextJudge}) renders the same questions into keyword prompts
12
12
  * for an ordinary chat model.
13
13
  */
@@ -75,7 +75,7 @@ export interface JudgmentRequest<Q extends Questions = Questions> {
75
75
  questions: Q;
76
76
  }
77
77
  export interface JudgmentResult<Q extends Questions = Questions> {
78
- /** Transport that produced the answers (`typesafe`, or the chat model's api). */
78
+ /** Transport that produced the answers (a judgment api such as `typesafe`, or the chat model's api). */
79
79
  api: string;
80
80
  provider: string;
81
81
  model: string;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Wire dialects of the native judgment APIs: how {@link NativeJudge} addresses,
3
+ * encodes, and decodes one request for each API it serves. Internal to the
4
+ * judgment module; `native.ts` maps every judgment API to its dialect.
5
+ */
6
+ import type { Usage } from "../types.js";
7
+ import type { JudgmentRequest } from "./types.js";
8
+ /** Where one attempt posts and which bearer token it sends. */
9
+ export interface JudgmentTarget {
10
+ url: string;
11
+ token: string;
12
+ }
13
+ /** One decoded response. */
14
+ export interface DecodedJudgment {
15
+ /** Model that answered, when the response names one. */
16
+ model: string | undefined;
17
+ /** Wire answers keyed by question id; {@link NativeJudge} checks each against its question's type. */
18
+ answers: Readonly<Record<string, unknown>>;
19
+ /** Question ids the model declined to answer. */
20
+ refused: readonly string[];
21
+ usage: Usage;
22
+ }
23
+ /** How one judgment API addresses, encodes, and decodes a request. */
24
+ export interface JudgmentWire {
25
+ /**
26
+ * Target of one attempt made with credential `key` against `model`.
27
+ * Throws when the credential cannot address the endpoint (e.g. no account id).
28
+ */
29
+ target(baseUrl: string, model: string, key: string): JudgmentTarget;
30
+ /** Request body for `model`. */
31
+ encode(request: JudgmentRequest, model: string): unknown;
32
+ /** The response's answers and usage; `undefined` when the payload is not this API's response shape. */
33
+ decode(payload: unknown): DecodedJudgment | undefined;
34
+ }
35
+ /** `value` when it is a finite number. */
36
+ export declare function finiteNumber(value: unknown): number | undefined;
@@ -14,7 +14,7 @@ export interface ProviderDetailsContext {
14
14
  authMode?: string;
15
15
  /**
16
16
  * Human-readable description of the active credential, e.g.
17
- * `"broker http://omp.internal:8765 · oauth #5 (foo@bar.com)"`.
17
+ * `"broker http://zeta.internal:8765 · oauth #5 (foo@bar.com)"`.
18
18
  * Rendered as a `Source` field; omitted when undefined.
19
19
  */
20
20
  credentialSource?: string;
@@ -18,8 +18,8 @@
18
18
  * siblings are endpoint-scoped and stay: `strictToolsDisabled`
19
19
  * (grammar-too-large 400 for the model's tool schema),
20
20
  * `replayUnsignedThinkingDisabled` / `thinkingReplayDisabled` (the endpoint
21
- * is a signing proxy), `prefixDroppedThinkingBlocks` (blocks the API itself
22
- * dropped).
21
+ * is a signing proxy), `prefixDroppedThinkingBlocks` (blocks a prefix-binding
22
+ * 400 made the client strip).
23
23
  * - **OpenAI Responses** — the `previous_response_id` chain baselines are
24
24
  * account-scoped: a stored response belongs to the account that created it.
25
25
  * Strict-tools / reasoning-effort fallbacks, replay warmup and the chaining
@@ -94,6 +94,13 @@ export interface AnthropicMessagesClientLike {
94
94
  create(params: MessageCreateParams, options?: AnthropicRequestOptions): unknown;
95
95
  };
96
96
  };
97
+ /**
98
+ * Endpoint the client targets, when it exposes one. SDK-style clients
99
+ * (`Anthropic`, `AnthropicVertex`) and {@link AnthropicMessagesClient}
100
+ * publish it; a client that exposes none keeps its transport opaque, and the
101
+ * provider must not assume the model's own routing on its behalf.
102
+ */
103
+ baseURL?: string;
97
104
  }
98
105
  export declare class AnthropicMessagesClient implements AnthropicMessagesClientLike {
99
106
  #private;
@@ -101,12 +108,15 @@ export declare class AnthropicMessagesClient implements AnthropicMessagesClientL
101
108
  readonly beta: {
102
109
  readonly messages: AnthropicMessages;
103
110
  };
111
+ /** Endpoint shared with the HTTP transport. */
112
+ get baseURL(): string;
104
113
  constructor(options: AnthropicClientOptions);
105
114
  request(path: string, params: MessageCreateParams, options?: AnthropicRequestOptions): AnthropicApiRequest;
106
115
  }
107
116
  /** Shared Anthropic HTTP transport for Messages and resource APIs. */
108
117
  export declare class AnthropicHttpClient {
109
118
  #private;
119
+ readonly baseURL: string;
110
120
  constructor(options: AnthropicClientOptions);
111
121
  request(method: "GET" | "POST", path: string, params?: unknown, options?: AnthropicRequestOptions): Promise<Response>;
112
122
  }
@@ -1,6 +1,8 @@
1
1
  import type { Api, Model, ProviderSessionState } from "../types.js";
2
2
  /** Root key for Anthropic's per-session provider state. */
3
3
  export declare const ANTHROPIC_PROVIDER_SESSION_STATE_KEY = "anthropic-messages";
4
+ /** Caller-map anchor for session-scoped opaque injected clients. */
5
+ export declare const ANTHROPIC_OPAQUE_CLIENT_ANCHOR_KEY = "anthropic-opaque-clients";
4
6
  /** Normalize an Anthropic base URL to its origin path without `/v1`. */
5
7
  export declare function normalizeAnthropicBaseUrl(baseUrl?: string): string | undefined;
6
8
  /** Resolve the endpoint for a first-party Anthropic model without loading its provider implementation. */
@@ -135,6 +135,13 @@ export type AnthropicClientOptionsArgs = {
135
135
  thinkingEnabled?: boolean;
136
136
  thinkingDisplay?: AnthropicThinkingDisplay;
137
137
  disableStrictTools?: boolean;
138
+ /**
139
+ * Withhold the prompt-cache betas (see `buildClaudeCodeBetas`). Set when the
140
+ * request carries no breakpoint at all, and also when it carries breakpoints
141
+ * stripped of `ttl`/`scope`: both betas govern those options, so a body
142
+ * without them must advertise neither.
143
+ */
144
+ dropPromptCacheBetas?: boolean;
138
145
  fetch?: FetchImpl;
139
146
  maxRetryDelayMs?: number;
140
147
  sessionId?: string;
@@ -169,6 +176,12 @@ export type AnthropicClientOptionsResult = {
169
176
  * omitted there.
170
177
  */
171
178
  export declare function resolveAnthropicCustomHeadersForBaseUrl(baseUrl: string | undefined): Record<string, string> | undefined;
179
+ /**
180
+ * Merge headers case-insensitively; later sources win and preserve their key casing.
181
+ * Undefined sources are ignored. Differently cased duplicates are removed so the
182
+ * Headers constructor cannot join competing values comma-separated on the wire.
183
+ */
184
+ export declare function mergeHeaders(...headerSources: (Record<string, string> | undefined)[]): Record<string, string>;
172
185
  export type AnthropicUsageLike = {
173
186
  cache_creation?: {
174
187
  ephemeral_5m_input_tokens?: number | null;
@@ -212,8 +225,17 @@ type SystemBlockOptions = {
212
225
  extraInstructions?: string[];
213
226
  /** Text of the first conversational wire user turn, used as the billing fingerprint seed. */
214
227
  firstUserMessageText?: string;
215
- /** Cache lifetime shared by the OAuth system breakpoint and later message breakpoints. */
228
+ /**
229
+ * Cache lifetime shared by the OAuth system breakpoint and later message
230
+ * breakpoints. Omitted → the identity block keeps its default `ephemeral`
231
+ * breakpoint; see `dropCacheControl` to emit none at all.
232
+ */
216
233
  cacheControl?: AnthropicCacheControl;
234
+ /**
235
+ * Emit no `cache_control` on any block: the endpoint rejected the field.
236
+ * Distinct from an undefined `cacheControl`, which only means "default".
237
+ */
238
+ dropCacheControl?: boolean;
217
239
  };
218
240
  export declare function buildAnthropicSystemBlocks(systemPrompt: readonly string[] | undefined, options?: SystemBlockOptions): AnthropicSystemBlock[] | undefined;
219
241
  export declare function normalizeExtraBetas(betas?: string[] | string): string[];
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Connect-protocol streaming envelope shared by the Cursor and Devin
3
+ * transports: 1 flag byte + 4-byte big-endian payload length + payload.
4
+ */
5
+ /** Flag bit: payload is compressed with the negotiated encoding (gzip). */
6
+ export declare const CONNECT_COMPRESSED_FLAG = 1;
7
+ /** Flag bit: payload is the end-of-stream JSON trailer. */
8
+ export declare const CONNECT_END_STREAM_FLAG = 2;
9
+ /** Wrap one Connect-protocol message: 1 flag byte + 4-byte big-endian length + payload. */
10
+ export declare function frameConnectMessage(data: Uint8Array, flags?: number): Buffer;
11
+ /** One decoded Connect envelope. */
12
+ export interface ConnectFrame {
13
+ flags: number;
14
+ payload: Buffer;
15
+ }
16
+ /** Options for {@link ConnectFrameDecoder}. */
17
+ export interface ConnectFrameDecoderOptions {
18
+ /**
19
+ * Payload cap: a length prefix above `maxPayloadBytes` throws `error(length)`
20
+ * before any of that payload is buffered. Uncapped when omitted.
21
+ */
22
+ limit?: {
23
+ maxPayloadBytes: number;
24
+ error: (length: number) => Error;
25
+ };
26
+ }
27
+ /**
28
+ * Incremental Connect frame decoder. Incoming chunks are kept as-is and a frame
29
+ * spanning several chunks is joined once, when the length the header announced
30
+ * has fully arrived — re-concatenating the pending bytes on every chunk made a
31
+ * multi-MB frame cost O(size × chunks).
32
+ *
33
+ * Payloads alias the chunk they came from whenever a frame fits in one chunk,
34
+ * so callers must not reuse chunk buffers they hand in.
35
+ */
36
+ export declare class ConnectFrameDecoder {
37
+ #private;
38
+ constructor(options?: ConnectFrameDecoderOptions);
39
+ /**
40
+ * Buffer `chunk` (if any) and yield every frame now complete, in wire order.
41
+ * An oversize length prefix throws after the frames that precede it.
42
+ */
43
+ decode(chunk?: Uint8Array): Generator<ConnectFrame, void, undefined>;
44
+ }
@@ -7,8 +7,6 @@ type ProtoUnknownField = {
7
7
  interface CursorInteractionWriter {
8
8
  write(frame: Uint8Array): void;
9
9
  }
10
- /** Wrap one Connect-protocol message: 1 flag byte + 4-byte big-endian length + payload. */
11
- export declare function frameConnectMessage(data: Uint8Array, flags?: number): Buffer;
12
10
  /** Well-formed protobuf-es `$unknown` entries on `message`; anything else on the bag is ignored. */
13
11
  export declare function protoUnknownFields(message: object): ProtoUnknownField[];
14
12
  /**