@oh-my-pi/pi-ai 17.0.0 → 17.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +13 -0
- package/dist/types/auth-storage.d.ts +2 -0
- package/dist/types/error/auth-classify.d.ts +2 -0
- package/dist/types/error/rate-limit.d.ts +9 -5
- package/dist/types/providers/cursor.d.ts +2 -0
- package/dist/types/providers/openai-codex/request-transformer.d.ts +9 -3
- package/dist/types/providers/openai-shared.d.ts +12 -6
- package/dist/types/providers/transform-messages.d.ts +5 -9
- package/dist/types/types.d.ts +6 -1
- package/dist/types/utils/empty-completion-retry.d.ts +3 -3
- package/dist/types/utils/schema/normalize.d.ts +3 -1
- package/package.json +4 -4
- package/src/auth-broker/wire-schemas.ts +1 -0
- package/src/auth-retry.ts +2 -2
- package/src/auth-storage.ts +120 -79
- package/src/dialect/owned-stream.ts +11 -0
- package/src/dialect/thinking.ts +186 -16
- package/src/error/auth-classify.ts +13 -0
- package/src/error/flags.ts +2 -2
- package/src/error/rate-limit.ts +28 -9
- package/src/providers/__tests__/kimi-code-thinking.test.ts +62 -7
- package/src/providers/anthropic.ts +82 -25
- package/src/providers/cursor.ts +53 -30
- package/src/providers/gitlab-duo-workflow.ts +6 -2
- package/src/providers/kimi.ts +1 -4
- package/src/providers/openai-codex/request-transformer.ts +12 -3
- package/src/providers/openai-codex-responses.ts +22 -4
- package/src/providers/openai-completions.ts +28 -22
- package/src/providers/openai-responses.ts +5 -1
- package/src/providers/openai-shared.ts +66 -14
- package/src/providers/transform-messages.ts +171 -1
- package/src/stream.ts +2 -0
- package/src/types.ts +9 -1
- package/src/utils/empty-completion-retry.ts +6 -3
- package/src/utils/leaked-thinking-stream.ts +19 -1
- package/src/utils/proxy.ts +1 -1
- package/src/utils/schema/CONSTRAINTS.md +1 -0
- package/src/utils/schema/fields.ts +3 -0
- package/src/utils/schema/normalize.ts +94 -24
- package/src/utils.ts +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [17.0.2] - 2026-07-17
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Automatically invalidate and rotate OAuth credentials when an "invalidated oauth token" error occurs.
|
|
10
|
+
- Fixed auth-broker snapshot validation rejecting API keys stored via the `/login` flow, restoring support for gateway/broker setups serving login-sourced keys on custom hosts.
|
|
11
|
+
- Fixed an issue where literal reasoning tags (e.g., `<think>`) inside Markdown code blocks or inline code were incorrectly treated as reasoning boundaries, which corrupted the rendered Markdown.
|
|
12
|
+
- Classified HTTP 402 and "balance exhausted" quota responses as persistent usage limits, enabling automatic rotation of multi-account requests to a sibling credential.
|
|
13
|
+
- Fixed `kimi-code` Anthropic-format requests ignoring custom provider base URLs.
|
|
14
|
+
- Fixed an issue where GPT-5.6 Codex Responses-Lite requests failed with an HTTP 400 error due to invalid `tool_choice` parameters after tools were rewritten, by automatically downgrading forced hosted choices to `tool_choice: "auto"` while preserving explicit tool-use constraints.
|
|
15
|
+
- Fixed Cursor streams prematurely reporting success before late CONNECT or gRPC terminal failures were observed, and resolved issues rejecting transport ends without a `turnEnded` signal.
|
|
16
|
+
|
|
17
|
+
## [17.0.1] - 2026-07-16
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Fixed OpenRouter cost reporting to use the provider's authoritative account charge instead of catalog token-price estimates on both Responses and Chat Completions streams.
|
|
22
|
+
- Fixed OpenAI Responses and Chat Completions requests forwarding unsupported sampling parameters such as `temperature` to o-series and GPT-5+ models, preventing 400 errors for mnemopi memory calls through GitHub Copilot GPT-5.6 Luna. ([#5606](https://github.com/can1357/oh-my-pi/issues/5606))
|
|
23
|
+
- Fixed boolean JSON Schema subschemas (`true`/`false`) in MCP tool inputs triggering `400 INVALID_ARGUMENT` on the Google/Cloud Code Assist (Antigravity) transport by coercing them to their object equivalents (`true` → `{}`, `false` → `{ not: {} }`) before sending ([#5604](https://github.com/can1357/oh-my-pi/issues/5604)).
|
|
24
|
+
- Fixed thinking-enabled Claude requests routed to `google-vertex` sending the `effort-2025-11-24` beta as an `anthropic-beta` HTTP header, which Vertex rawPredict rejects with a 400. The effort beta and the `output_config.effort` field are now gated off the Vertex path the same way `context-management-2025-06-27` already is ([#5614](https://github.com/can1357/oh-my-pi/issues/5614)).
|
|
25
|
+
- Fixed custom and Foundry-routed Anthropic endpoints receiving first-party eager/legacy tool-streaming controls ([#5572](https://github.com/can1357/oh-my-pi/issues/5572)).
|
|
26
|
+
- Parsed Ollama NDJSON response bytes directly instead of decoding and buffering every network chunk as text. ([#5542](https://github.com/can1357/oh-my-pi/issues/5542))
|
|
27
|
+
- Fixed Amazon Bedrock stream error handling for non-`Error` values that `JSON.stringify` cannot serialize ([#5539](https://github.com/can1357/oh-my-pi/issues/5539)).
|
|
28
|
+
- Fixed concurrent provider OAuth refreshes by serializing rotating-token updates across processes, fencing stale writes, and preventing background usage probes from disabling otherwise usable credentials ([#5396](https://github.com/can1357/oh-my-pi/issues/5396)).
|
|
29
|
+
- Fixed OpenAI Codex WebSocket connections ignoring `PI_PROXY`, provider-specific proxy settings, and standard HTTPS/ALL proxy variables ([#5384](https://github.com/can1357/oh-my-pi/issues/5384)).
|
|
30
|
+
- Fixed Anthropic account quota exhaustion (`This request would exceed your account's monthly spend limit`) hanging until the local deadline instead of surfacing the error: the `rate_limit_error` "spend limit" wording is now classified as a persistent usage limit, so it fails fast and rotates to a sibling credential rather than looping in the provider retry backoff. ([#4787](https://github.com/can1357/oh-my-pi/issues/4787))
|
|
31
|
+
- Fixed OpenRouter daily free-model allowance errors (`free-models-per-day`) being treated as transient rate limits, so requests rotate from an exhausted API key to a healthy sibling credential. ([#4832](https://github.com/can1357/oh-my-pi/issues/4832))
|
|
32
|
+
|
|
5
33
|
## [17.0.0] - 2026-07-15
|
|
6
34
|
|
|
7
35
|
### Changed
|
|
@@ -29,6 +29,7 @@ export declare const remoteOauthCredentialSchema: import("arktype/internal/varia
|
|
|
29
29
|
export declare const apiKeyCredentialSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
30
30
|
type: "api_key";
|
|
31
31
|
key: string;
|
|
32
|
+
source?: "login" | undefined;
|
|
32
33
|
}, {}>;
|
|
33
34
|
/** Discriminated union accepted on POST /v1/credential (writes). */
|
|
34
35
|
export declare const writableAuthCredentialSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
@@ -46,6 +47,7 @@ export declare const writableAuthCredentialSchema: import("arktype/internal/vari
|
|
|
46
47
|
} | {
|
|
47
48
|
type: "api_key";
|
|
48
49
|
key: string;
|
|
50
|
+
source?: "login" | undefined;
|
|
49
51
|
}, {}>;
|
|
50
52
|
/** Discriminated union returned in snapshots (refresh is sentinel for OAuth). */
|
|
51
53
|
export declare const snapshotCredentialSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
@@ -63,6 +65,7 @@ export declare const snapshotCredentialSchema: import("arktype/internal/variants
|
|
|
63
65
|
} | {
|
|
64
66
|
type: "api_key";
|
|
65
67
|
key: string;
|
|
68
|
+
source?: "login" | undefined;
|
|
66
69
|
}, {}>;
|
|
67
70
|
export declare const credentialSnapshotEntrySchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
68
71
|
id: number;
|
|
@@ -82,6 +85,7 @@ export declare const credentialSnapshotEntrySchema: import("arktype/internal/var
|
|
|
82
85
|
} | {
|
|
83
86
|
type: "api_key";
|
|
84
87
|
key: string;
|
|
88
|
+
source?: "login" | undefined;
|
|
85
89
|
};
|
|
86
90
|
identityKey: string | null;
|
|
87
91
|
}, {}>;
|
|
@@ -109,6 +113,7 @@ export declare const snapshotEntrySchema: import("arktype/internal/variants/obje
|
|
|
109
113
|
} | {
|
|
110
114
|
type: "api_key";
|
|
111
115
|
key: string;
|
|
116
|
+
source?: "login" | undefined;
|
|
112
117
|
};
|
|
113
118
|
identityKey: string | null;
|
|
114
119
|
rotatesInMs: number | null;
|
|
@@ -153,6 +158,7 @@ export declare const snapshotResponseSchema: import("arktype/internal/variants/o
|
|
|
153
158
|
} | {
|
|
154
159
|
type: "api_key";
|
|
155
160
|
key: string;
|
|
161
|
+
source?: "login" | undefined;
|
|
156
162
|
};
|
|
157
163
|
identityKey: string | null;
|
|
158
164
|
rotatesInMs: number | null;
|
|
@@ -193,6 +199,7 @@ export declare const snapshotStreamSnapshotEventSchema: import("arktype/internal
|
|
|
193
199
|
} | {
|
|
194
200
|
type: "api_key";
|
|
195
201
|
key: string;
|
|
202
|
+
source?: "login" | undefined;
|
|
196
203
|
};
|
|
197
204
|
identityKey: string | null;
|
|
198
205
|
rotatesInMs: number | null;
|
|
@@ -234,6 +241,7 @@ export declare const snapshotStreamEntryEventSchema: import("arktype/internal/va
|
|
|
234
241
|
} | {
|
|
235
242
|
type: "api_key";
|
|
236
243
|
key: string;
|
|
244
|
+
source?: "login" | undefined;
|
|
237
245
|
};
|
|
238
246
|
identityKey: string | null;
|
|
239
247
|
rotatesInMs: number | null;
|
|
@@ -287,6 +295,7 @@ export declare const snapshotStreamEventSchema: import("arktype/internal/variant
|
|
|
287
295
|
} | {
|
|
288
296
|
type: "api_key";
|
|
289
297
|
key: string;
|
|
298
|
+
source?: "login" | undefined;
|
|
290
299
|
};
|
|
291
300
|
identityKey: string | null;
|
|
292
301
|
rotatesInMs: number | null;
|
|
@@ -326,6 +335,7 @@ export declare const snapshotStreamEventSchema: import("arktype/internal/variant
|
|
|
326
335
|
} | {
|
|
327
336
|
type: "api_key";
|
|
328
337
|
key: string;
|
|
338
|
+
source?: "login" | undefined;
|
|
329
339
|
};
|
|
330
340
|
identityKey: string | null;
|
|
331
341
|
rotatesInMs: number | null;
|
|
@@ -427,6 +437,7 @@ export declare const credentialRefreshResponseSchema: import("arktype/internal/v
|
|
|
427
437
|
} | {
|
|
428
438
|
type: "api_key";
|
|
429
439
|
key: string;
|
|
440
|
+
source?: "login" | undefined;
|
|
430
441
|
};
|
|
431
442
|
identityKey: string | null;
|
|
432
443
|
};
|
|
@@ -469,6 +480,7 @@ export declare const credentialUploadRequestSchema: import("arktype/internal/var
|
|
|
469
480
|
} | {
|
|
470
481
|
type: "api_key";
|
|
471
482
|
key: string;
|
|
483
|
+
source?: "login" | undefined;
|
|
472
484
|
};
|
|
473
485
|
}, {}>;
|
|
474
486
|
export declare const credentialUploadResponseSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
|
@@ -490,6 +502,7 @@ export declare const credentialUploadResponseSchema: import("arktype/internal/va
|
|
|
490
502
|
} | {
|
|
491
503
|
type: "api_key";
|
|
492
504
|
key: string;
|
|
505
|
+
source?: "login" | undefined;
|
|
493
506
|
};
|
|
494
507
|
identityKey: string | null;
|
|
495
508
|
}[];
|
|
@@ -559,6 +559,8 @@ export interface InvalidateCredentialMatchingOptions {
|
|
|
559
559
|
}
|
|
560
560
|
/** Options for refreshing one stored OAuth row through durable ownership. */
|
|
561
561
|
export interface StoredOAuthRefreshOptions<T extends OAuthCredential = OAuthCredential> {
|
|
562
|
+
/** Stable row id when a provider has multiple OAuth credentials. */
|
|
563
|
+
credentialId?: number;
|
|
562
564
|
observedCredential?: T;
|
|
563
565
|
credentialFromRow: (credential: OAuthCredential) => T | undefined;
|
|
564
566
|
forceRefresh?: boolean;
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* `@oh-my-pi/pi-ai` entrypoint name used by the coding agent and auth-broker.
|
|
6
6
|
*/
|
|
7
7
|
export declare function isDefinitiveOAuthFailure(errorMsg: string): boolean;
|
|
8
|
+
/** Whether an upstream response explicitly says the supplied OAuth bearer was invalidated. */
|
|
9
|
+
export declare function isInvalidatedOAuthTokenError(error: unknown): boolean;
|
|
8
10
|
/**
|
|
9
11
|
* Whether an upstream failure should rotate to a sibling credential: a hard
|
|
10
12
|
* `401`, a body-classified usage limit (Codex `usage_limit_reached`, Anthropic
|
|
@@ -20,6 +20,9 @@ export declare function calculateRateLimitBackoffMs(reason: RateLimitReason): nu
|
|
|
20
20
|
/**
|
|
21
21
|
* HTTP status codes that, absent richer body classification, represent an
|
|
22
22
|
* account-local usage cap rather than a bad credential or a transient blip.
|
|
23
|
+
* HTTP 402 Payment Required is categorically an account-billing cap (xAI
|
|
24
|
+
* Grok Build "usage balance exhausted", DeepSeek "Insufficient Balance",
|
|
25
|
+
* OpenRouter credit exhaustion) — never a transient blip or bad credential.
|
|
23
26
|
* Always combine with {@link isUsageLimitOutcome} when a message is available
|
|
24
27
|
* — a 429 carrying transient rate-limit wording is NOT a usage cap.
|
|
25
28
|
*/
|
|
@@ -31,7 +34,7 @@ export declare function isUsageLimitStatus(status: number | undefined): boolean;
|
|
|
31
34
|
* 1. Body matches {@link isUsageLimitError} (Codex `usage_limit_reached`,
|
|
32
35
|
* Anthropic account rate-limit, Google `resource_exhausted`, OpenAI
|
|
33
36
|
* `insufficient_quota`, …) → rotate.
|
|
34
|
-
* 2. Status is not 429 → backoff (caller's domain).
|
|
37
|
+
* 2. Status is not a usage-limit status (429/402) → backoff (caller's domain).
|
|
35
38
|
* 3. Body is absent or {@link isOpaqueStatusBody opaque} (just the status,
|
|
36
39
|
* empty JSON, HTTP framing only) → rotate conservatively: the server
|
|
37
40
|
* gave us nothing else to go on.
|
|
@@ -44,10 +47,11 @@ export declare function isUsageLimitStatus(status: number | undefined): boolean;
|
|
|
44
47
|
*/
|
|
45
48
|
export declare function isUsageLimitOutcome(status: number | undefined, message: string | undefined): boolean;
|
|
46
49
|
/**
|
|
47
|
-
* A
|
|
48
|
-
* empty, whitespace-only, the status digits with HTTP/JSON
|
|
49
|
-
* generic punctuation. Anything else (retry hints, capacity
|
|
50
|
-
* descriptions) is informative enough to defer to the
|
|
50
|
+
* A usage-limit status body is opaque when it carries no signal beyond the
|
|
51
|
+
* status itself — empty, whitespace-only, the status digits with HTTP/JSON
|
|
52
|
+
* framing, or generic punctuation. Anything else (retry hints, capacity
|
|
53
|
+
* wording, error descriptions) is informative enough to defer to the
|
|
54
|
+
* classifier.
|
|
51
55
|
*/
|
|
52
56
|
export declare function isOpaqueStatusBody(message: string): boolean;
|
|
53
57
|
/**
|
|
@@ -29,6 +29,8 @@ export interface BlockState {
|
|
|
29
29
|
[kStreamingBlockIndex]: number;
|
|
30
30
|
}) | null;
|
|
31
31
|
currentToolCall: ToolCallState | null;
|
|
32
|
+
/** MCP call IDs executed through Cursor's exec channel before their stream block arrives. */
|
|
33
|
+
resolvedMcpToolCallIds: Set<string>;
|
|
32
34
|
firstTokenTime: number | undefined;
|
|
33
35
|
setTextBlock: (b: (TextContent & {
|
|
34
36
|
[kStreamingBlockIndex]: number;
|
|
@@ -77,6 +77,7 @@ export declare function resolveCodexResponsesLite(model: Model<"openai-codex-res
|
|
|
77
77
|
export interface CodexLiteShapedBody {
|
|
78
78
|
instructions?: unknown;
|
|
79
79
|
tools?: unknown;
|
|
80
|
+
tool_choice?: unknown;
|
|
80
81
|
input?: unknown;
|
|
81
82
|
parallel_tool_calls?: unknown;
|
|
82
83
|
}
|
|
@@ -85,9 +86,14 @@ export interface CodexLiteShapedBody {
|
|
|
85
86
|
* `build_responses_request` with `use_responses_lite`): strips pinned image
|
|
86
87
|
* detail, forces parallel tool calling off, moves tools into a leading
|
|
87
88
|
* `additional_tools` developer item and the base instructions into a
|
|
88
|
-
* developer message, then omits top-level `instructions`/`tools`.
|
|
89
|
-
*
|
|
90
|
-
*
|
|
89
|
+
* developer message, then omits top-level `instructions`/`tools`. Because the
|
|
90
|
+
* rewrite removes top-level `tools`, a forced hosted-tool choice (e.g.
|
|
91
|
+
* `{ type: "web_search" }`) would leave the backend unable to validate the
|
|
92
|
+
* choice against a tools collection and it rejects the request with HTTP 400
|
|
93
|
+
* (#5771). Such choices must fall back to `"auto"`; explicit string constraints
|
|
94
|
+
* such as `"none"` and `"required"` remain valid. Shared by normal turns and
|
|
95
|
+
* both remote-compaction paths — codex-rs routes `/responses/compact` through
|
|
96
|
+
* the same builder.
|
|
91
97
|
*/
|
|
92
98
|
export declare function applyCodexResponsesLiteShape(body: CodexLiteShapedBody): void;
|
|
93
99
|
export declare function transformRequestBody(body: RequestBody, model: Model<"openai-codex-responses">, options?: CodexRequestOptions, prompt?: {
|
|
@@ -68,6 +68,8 @@ export declare function applyOpenAIServiceTier(params: {
|
|
|
68
68
|
* proxy can never skew those costs.
|
|
69
69
|
*/
|
|
70
70
|
export declare function applyOpenAIResponsesServiceTierCost(model: Pick<Model, "provider">, usage: AssistantMessage["usage"], responseServiceTier: unknown, requestServiceTier: ServiceTier | null | undefined): void;
|
|
71
|
+
/** Reconcile token-price estimates with OpenRouter's authoritative account charge. */
|
|
72
|
+
export declare function applyOpenRouterReportedCost(model: Pick<Model, "provider">, usage: Usage, rawUsage: unknown): void;
|
|
71
73
|
export interface OpenAIUsageAccountingInput {
|
|
72
74
|
promptTokens: number;
|
|
73
75
|
outputTokens: number;
|
|
@@ -295,12 +297,14 @@ export declare function applyChatCompletionsReasoningParams(params: OpenAIComple
|
|
|
295
297
|
}) | undefined): void;
|
|
296
298
|
export declare function disableChatCompletionsReasoningForDialect(params: OpenAICompletionsParams, compat: ResolvedOpenAICompat): void;
|
|
297
299
|
/**
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
300
|
+
* Provider-specific Chat Completions output clamp.
|
|
301
|
+
*
|
|
302
|
+
* Most OpenAI-compatible endpoints retain the conservative 64k ceiling from
|
|
303
|
+
* {@link resolveOpenAIOutputTokenParam}. Z.AI/GLM-5.2 reasoning and native
|
|
304
|
+
* Moonshot K3 explicitly accept their full advertised model caps, so those
|
|
305
|
+
* routes clamp to `model.maxTokens` instead.
|
|
302
306
|
*/
|
|
303
|
-
export declare function
|
|
307
|
+
export declare function resolveOpenAICompletionsOutputClamp(model: Model<"openai-completions">, compat: ResolvedOpenAICompat): number | undefined;
|
|
304
308
|
/**
|
|
305
309
|
* Enable `tool_stream` for Z.AI/GLM-5.2 reasoning models when tools are present
|
|
306
310
|
* (GLM-5.2 streams tool-call arguments incrementally and needs the flag to do so).
|
|
@@ -500,7 +504,9 @@ type CommonSamplingOptions = Pick<StreamOptions, "temperature" | "topP" | "topK"
|
|
|
500
504
|
* can let the upstream apply its own default instead of 400-ing on `maxTokens` values that
|
|
501
505
|
* reflect the model's context window rather than the upstream output limit.
|
|
502
506
|
*/
|
|
503
|
-
export declare function applyCommonResponsesSamplingParams<P extends CommonResponsesParams>(params: P, options: CommonSamplingOptions | undefined, model: Pick<Model, "provider" | "api" | "id" | "omitMaxOutputTokens" | "maxTokens">
|
|
507
|
+
export declare function applyCommonResponsesSamplingParams<P extends CommonResponsesParams>(params: P, options: CommonSamplingOptions | undefined, model: Pick<Model, "provider" | "api" | "id" | "omitMaxOutputTokens" | "maxTokens"> & {
|
|
508
|
+
compat: Pick<ResolvedOpenAISharedCompat, "supportsSamplingParams">;
|
|
509
|
+
}): void;
|
|
504
510
|
type ReasoningOptions = {
|
|
505
511
|
reasoning?: string;
|
|
506
512
|
reasoningSummary?: "auto" | "detailed" | "concise" | null;
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type { Api, AssistantMessage, Message, Model } from "../types.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* For aborted/errored turns, this function:
|
|
8
|
-
* - Preserves tool call structure (unlike converting to text summaries)
|
|
9
|
-
* - Injects synthetic "aborted" tool results
|
|
10
|
-
*/
|
|
2
|
+
export declare function redactSensitiveCredentials(text: string): string;
|
|
3
|
+
export declare function redactSensitiveInObject(val: unknown): {
|
|
4
|
+
result: unknown;
|
|
5
|
+
changed: boolean;
|
|
6
|
+
};
|
|
11
7
|
export declare function transformMessages<TApi extends Api>(messages: Message[], model: Model<TApi>, normalizeToolCallId?: (id: string, model: Model<TApi>, source: AssistantMessage) => string, maxNormalizedToolCallIdLength?: number, duplicateToolCallIdSuffixPrefix?: string, targetCompat?: Model<TApi>["compat"]): Message[];
|
package/dist/types/types.d.ts
CHANGED
|
@@ -525,7 +525,7 @@ export interface ContextSnapshot {
|
|
|
525
525
|
}
|
|
526
526
|
export interface AssistantMessage {
|
|
527
527
|
role: "assistant";
|
|
528
|
-
content: (TextContent | ThinkingContent | RedactedThinkingContent | AnthropicFallbackContent | ToolCall)[];
|
|
528
|
+
content: (TextContent | ThinkingContent | RedactedThinkingContent | AnthropicFallbackContent | ImageContent | ToolCall)[];
|
|
529
529
|
api: Api;
|
|
530
530
|
provider: Provider;
|
|
531
531
|
model: string;
|
|
@@ -716,6 +716,11 @@ export type AssistantMessageEvent = {
|
|
|
716
716
|
contentIndex: number;
|
|
717
717
|
content: string;
|
|
718
718
|
partial: AssistantMessage;
|
|
719
|
+
} | {
|
|
720
|
+
type: "image_end";
|
|
721
|
+
contentIndex: number;
|
|
722
|
+
content: ImageContent;
|
|
723
|
+
partial: AssistantMessage;
|
|
719
724
|
} | {
|
|
720
725
|
type: "toolcall_start";
|
|
721
726
|
contentIndex: number;
|
|
@@ -3,9 +3,9 @@ import { AssistantMessageEventStream } from "./event-stream.js";
|
|
|
3
3
|
export declare const MAX_EMPTY_COMPLETION_RETRIES = 2;
|
|
4
4
|
export declare const EMPTY_COMPLETION_BASE_DELAY_MS = 500;
|
|
5
5
|
/**
|
|
6
|
-
* Whether a completed assistant message carries content worth delivering:
|
|
7
|
-
* call or any non-whitespace text. An empty/whitespace-only message
|
|
8
|
-
* that only ever produced thinking — is the "empty response" failure.
|
|
6
|
+
* Whether a completed assistant message carries content worth delivering: an
|
|
7
|
+
* image, tool call, or any non-whitespace text. An empty/whitespace-only message
|
|
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
11
|
interface EmptyCompletionRetryOptions {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { type DescriptionSpillFormat } from "./spill.js";
|
|
2
2
|
import { type JsonObject } from "./types.js";
|
|
3
|
-
export type ResidualSchemaIncompatibility = "type-array" | "type-null" | "nullable" | "combiners";
|
|
3
|
+
export type ResidualSchemaIncompatibility = "type-array" | "type-null" | "nullable" | "combiners" | "not";
|
|
4
4
|
export interface NormalizeSchemaOptions {
|
|
5
|
+
/** Coerce JSON Schema boolean subschemas for providers whose wire cannot encode them. */
|
|
6
|
+
coerceBooleanSubschemas?: boolean;
|
|
5
7
|
unsupportedFields: (key: string) => boolean;
|
|
6
8
|
normalizeFieldNames: boolean;
|
|
7
9
|
collapseNullFields: boolean;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-ai",
|
|
4
|
-
"version": "17.0.
|
|
4
|
+
"version": "17.0.2",
|
|
5
5
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@bufbuild/protobuf": "^2.12.1",
|
|
41
|
-
"@oh-my-pi/pi-catalog": "17.0.
|
|
42
|
-
"@oh-my-pi/pi-utils": "17.0.
|
|
43
|
-
"@oh-my-pi/pi-wire": "17.0.
|
|
41
|
+
"@oh-my-pi/pi-catalog": "17.0.2",
|
|
42
|
+
"@oh-my-pi/pi-utils": "17.0.2",
|
|
43
|
+
"@oh-my-pi/pi-wire": "17.0.2",
|
|
44
44
|
"arktype": "2.2.3",
|
|
45
45
|
"zod": "^4"
|
|
46
46
|
},
|
package/src/auth-retry.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { OAuthAccess } from "./auth-storage";
|
|
2
2
|
import * as AIError from "./error";
|
|
3
|
-
import { isAuthRetryableError } from "./error/auth-classify";
|
|
3
|
+
import { isAuthRetryableError, isInvalidatedOAuthTokenError } from "./error/auth-classify";
|
|
4
4
|
import { isUsageLimit } from "./error/flags";
|
|
5
5
|
import { isUsageLimitOutcome } from "./error/rate-limit";
|
|
6
6
|
|
|
@@ -90,7 +90,7 @@ export const AUTH_RETRY_STEPS: readonly boolean[] = [false, true];
|
|
|
90
90
|
export const AUTH_RETRY_MAX_ATTEMPTS = 64;
|
|
91
91
|
|
|
92
92
|
function isDirectCredentialRotationError(error: unknown): boolean {
|
|
93
|
-
if (isUsageLimit(error)) return true;
|
|
93
|
+
if (isUsageLimit(error) || isInvalidatedOAuthTokenError(error)) return true;
|
|
94
94
|
const status = AIError.status(error);
|
|
95
95
|
const message = error instanceof Error ? error.message : typeof error === "string" ? error : undefined;
|
|
96
96
|
return isUsageLimitOutcome(status, message);
|