@oh-my-pi/pi-ai 16.2.1 → 16.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/dist/types/auth-gateway/server.d.ts +0 -19
- package/dist/types/auth-retry.d.ts +2 -10
- package/dist/types/auth-storage.d.ts +1 -2
- package/dist/types/dialect/demotion.d.ts +22 -0
- package/dist/types/dialect/index.d.ts +2 -0
- package/dist/types/error/abort.d.ts +14 -0
- package/dist/types/error/auth-classify.d.ts +16 -0
- package/dist/types/error/auth.d.ts +27 -0
- package/dist/types/error/aws.d.ts +23 -0
- package/dist/types/error/classes.d.ts +102 -0
- package/dist/types/error/finalize.d.ts +39 -0
- package/dist/types/error/flags.d.ts +70 -0
- package/dist/types/error/format.d.ts +20 -0
- package/dist/types/error/gateway.d.ts +20 -0
- package/dist/types/error/index.d.ts +13 -0
- package/dist/types/error/oauth.d.ts +43 -0
- package/dist/types/error/provider.d.ts +42 -0
- package/dist/types/{rate-limit-utils.d.ts → error/rate-limit.d.ts} +14 -1
- package/dist/types/error/retryable.d.ts +27 -0
- package/dist/types/error/validation.d.ts +32 -0
- package/dist/types/index.d.ts +1 -3
- package/dist/types/providers/amazon-bedrock.d.ts +0 -5
- package/dist/types/providers/anthropic-client.d.ts +2 -16
- package/dist/types/providers/anthropic.d.ts +6 -1
- package/dist/types/providers/aws-eventstream.d.ts +2 -1
- package/dist/types/providers/cursor.d.ts +8 -7
- package/dist/types/providers/google-gemini-cli.d.ts +0 -5
- package/dist/types/providers/google-shared.d.ts +0 -5
- package/dist/types/providers/ollama.d.ts +0 -5
- package/dist/types/providers/openai-codex/request-transformer.d.ts +2 -2
- package/dist/types/providers/openai-codex/response-handler.d.ts +1 -1
- package/dist/types/providers/openai-codex-responses.d.ts +2 -2
- package/dist/types/providers/openai-responses-server-schema.d.ts +6 -0
- package/dist/types/providers/openai-responses-wire.d.ts +1 -1
- package/dist/types/providers/openai-responses.d.ts +1 -0
- package/dist/types/providers/openai-shared.d.ts +8 -6
- package/dist/types/providers/pi-native-client.d.ts +0 -9
- package/dist/types/registry/oauth/xai-oauth.d.ts +0 -9
- package/dist/types/types.d.ts +6 -0
- package/dist/types/utils/block-symbols.d.ts +20 -0
- package/dist/types/utils/openai-http.d.ts +4 -8
- package/dist/types/utils/retry.d.ts +2 -14
- package/dist/types/utils/thinking-loop.d.ts +3 -1
- package/package.json +8 -4
- package/src/api-registry.ts +3 -1
- package/src/auth-broker/discover.ts +7 -2
- package/src/auth-broker/remote-store.ts +8 -7
- package/src/auth-gateway/server.ts +27 -115
- package/src/auth-retry.ts +9 -21
- package/src/auth-storage.ts +34 -49
- package/src/dialect/demotion.ts +31 -0
- package/src/dialect/factory.ts +0 -2
- package/src/dialect/index.ts +2 -0
- package/src/dialect/owned-stream.ts +0 -1
- package/src/dialect/thinking.ts +22 -10
- package/src/error/abort.ts +18 -0
- package/src/error/auth-classify.ts +30 -0
- package/src/error/auth.ts +48 -0
- package/src/error/aws.ts +31 -0
- package/src/error/classes.ts +186 -0
- package/src/error/finalize.ts +69 -0
- package/src/error/flags.ts +486 -0
- package/src/error/format.ts +36 -0
- package/src/error/gateway.ts +96 -0
- package/src/error/index.ts +13 -0
- package/src/error/oauth.ts +58 -0
- package/src/error/provider.ts +56 -0
- package/src/{rate-limit-utils.ts → error/rate-limit.ts} +9 -3
- package/src/error/retryable.ts +70 -0
- package/src/error/validation.ts +44 -0
- package/src/index.ts +1 -3
- package/src/providers/amazon-bedrock.ts +61 -57
- package/src/providers/anthropic-client.ts +13 -41
- package/src/providers/anthropic-messages-server.ts +9 -2
- package/src/providers/anthropic.ts +84 -147
- package/src/providers/aws-credentials.ts +41 -11
- package/src/providers/aws-eventstream.ts +12 -21
- package/src/providers/azure-openai-responses.ts +27 -17
- package/src/providers/cursor.ts +59 -53
- package/src/providers/devin.ts +28 -20
- package/src/providers/gitlab-duo-workflow.ts +30 -10
- package/src/providers/gitlab-duo.ts +22 -6
- package/src/providers/google-auth.ts +15 -5
- package/src/providers/google-gemini-cli.ts +46 -60
- package/src/providers/google-shared.ts +40 -38
- package/src/providers/google-vertex.ts +3 -2
- package/src/providers/google.ts +5 -1
- package/src/providers/mock.ts +10 -7
- package/src/providers/ollama.ts +34 -29
- package/src/providers/openai-chat-server.ts +2 -1
- package/src/providers/openai-codex/request-transformer.ts +13 -12
- package/src/providers/openai-codex/response-handler.ts +1 -1
- package/src/providers/openai-codex-responses.ts +931 -1012
- package/src/providers/openai-completions.ts +46 -36
- package/src/providers/openai-responses-server-schema.ts +3 -0
- package/src/providers/openai-responses-server.ts +82 -30
- package/src/providers/openai-responses-wire.ts +1 -1
- package/src/providers/openai-responses.ts +46 -22
- package/src/providers/openai-shared.ts +118 -51
- package/src/providers/pi-native-client.ts +12 -18
- package/src/providers/pi-native-server.ts +9 -6
- package/src/providers/register-builtins.ts +5 -2
- package/src/providers/transform-messages.ts +31 -63
- package/src/registry/alibaba-coding-plan.ts +6 -5
- package/src/registry/api-key-login.ts +4 -3
- package/src/registry/api-key-validation.ts +4 -3
- package/src/registry/cloudflare-ai-gateway.ts +4 -3
- package/src/registry/coreweave.ts +2 -1
- package/src/registry/deepseek.ts +2 -1
- package/src/registry/google-antigravity.ts +2 -1
- package/src/registry/google-gemini-cli.ts +2 -1
- package/src/registry/kagi.ts +4 -3
- package/src/registry/kilo.ts +32 -10
- package/src/registry/litellm.ts +4 -3
- package/src/registry/llama-cpp.ts +3 -2
- package/src/registry/lm-studio.ts +3 -2
- package/src/registry/nvidia.ts +7 -7
- package/src/registry/oauth/anthropic.ts +23 -6
- package/src/registry/oauth/callback-server.ts +5 -3
- package/src/registry/oauth/cursor.ts +18 -4
- package/src/registry/oauth/devin.ts +14 -3
- package/src/registry/oauth/github-copilot.ts +21 -10
- package/src/registry/oauth/gitlab-duo-workflow.ts +15 -3
- package/src/registry/oauth/gitlab-duo.ts +30 -6
- package/src/registry/oauth/google-antigravity.ts +14 -5
- package/src/registry/oauth/google-gemini-cli.ts +24 -7
- package/src/registry/oauth/google-oauth-shared.ts +6 -3
- package/src/registry/oauth/index.ts +19 -8
- package/src/registry/oauth/kimi.ts +40 -10
- package/src/registry/oauth/openai-codex.ts +26 -11
- package/src/registry/oauth/opencode.ts +4 -3
- package/src/registry/oauth/perplexity.ts +33 -11
- package/src/registry/oauth/xai-oauth.ts +62 -18
- package/src/registry/oauth/xiaomi.ts +21 -9
- package/src/registry/ollama-cloud.ts +5 -4
- package/src/registry/ollama.ts +3 -2
- package/src/registry/parallel.ts +4 -3
- package/src/registry/qwen-portal.ts +4 -3
- package/src/registry/tavily.ts +4 -3
- package/src/registry/vercel-ai-gateway.ts +4 -3
- package/src/registry/vllm.ts +3 -2
- package/src/stream.ts +79 -24
- package/src/types.ts +6 -0
- package/src/usage/claude.ts +2 -1
- package/src/usage/github-copilot.ts +4 -3
- package/src/usage/google-antigravity.ts +2 -1
- package/src/utils/abort.ts +4 -2
- package/src/utils/block-symbols.ts +32 -0
- package/src/utils/event-stream.ts +15 -3
- package/src/utils/http-inspector.ts +4 -4
- package/src/utils/idle-iterator.ts +6 -5
- package/src/utils/openai-http.ts +11 -46
- package/src/utils/parse-bind.ts +7 -5
- package/src/utils/proxy.ts +2 -1
- package/src/utils/retry.ts +7 -23
- package/src/utils/schema/normalize.ts +3 -2
- package/src/utils/thinking-loop.ts +15 -11
- package/src/utils/validation.ts +4 -3
- package/dist/types/dialect/pi.d.ts +0 -9
- package/dist/types/errors.d.ts +0 -24
- package/dist/types/utils/overflow.d.ts +0 -55
- package/src/dialect/pi.md +0 -55
- package/src/dialect/pi.ts +0 -600
- package/src/errors.ts +0 -32
- package/src/utils/overflow.ts +0 -140
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { attach, create, Flag } from "./flags";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What stage of an OAuth / device-code login flow failed. Discriminates the
|
|
5
|
+
* single {@link OAuthError} class so login flows don't each mint a bespoke
|
|
6
|
+
* error type.
|
|
7
|
+
*/
|
|
8
|
+
export type OAuthErrorKind =
|
|
9
|
+
/** Token-exchange / refresh / discovery HTTP response was non-2xx or unparseable. */
|
|
10
|
+
| "http"
|
|
11
|
+
/** Response body was missing required fields (token, account id, endpoints, …). */
|
|
12
|
+
| "validation"
|
|
13
|
+
/** Authorization-code → token exchange failed. */
|
|
14
|
+
| "token-exchange"
|
|
15
|
+
/** Refresh-token grant failed. */
|
|
16
|
+
| "token-refresh"
|
|
17
|
+
/** Device-code / authorization polling failed (server error, too many retries). */
|
|
18
|
+
| "polling"
|
|
19
|
+
/** The flow exceeded its deadline (device-code expiry, polling timeout). */
|
|
20
|
+
| "timeout"
|
|
21
|
+
/** Device authorization was denied or cancelled by the user/provider. */
|
|
22
|
+
| "device-auth"
|
|
23
|
+
/** Misconfiguration (bad redirect URI, missing projectId, callback bind, …). */
|
|
24
|
+
| "configuration"
|
|
25
|
+
/** Cloud project provisioning / onboarding (loadCodeAssist, onboardUser). */
|
|
26
|
+
| "provisioning"
|
|
27
|
+
/** OIDC / endpoint discovery failed. */
|
|
28
|
+
| "discovery";
|
|
29
|
+
|
|
30
|
+
export interface OAuthErrorOptions {
|
|
31
|
+
kind?: OAuthErrorKind;
|
|
32
|
+
provider?: string;
|
|
33
|
+
status?: number;
|
|
34
|
+
cause?: unknown;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A failure inside an interactive OAuth / device-code login flow. The `kind`
|
|
39
|
+
* pinpoints the stage. Timeout/polling are classified transient; everything
|
|
40
|
+
* else is a hard auth failure so the credential layer does not silently retry.
|
|
41
|
+
*/
|
|
42
|
+
export class OAuthError extends Error {
|
|
43
|
+
readonly kind: OAuthErrorKind;
|
|
44
|
+
readonly provider: string | undefined;
|
|
45
|
+
readonly status: number | undefined;
|
|
46
|
+
|
|
47
|
+
constructor(message: string, options: OAuthErrorOptions = {}) {
|
|
48
|
+
super(message, options.cause === undefined ? undefined : { cause: options.cause });
|
|
49
|
+
this.name = "OAuthError";
|
|
50
|
+
this.kind = options.kind ?? "http";
|
|
51
|
+
this.provider = options.provider;
|
|
52
|
+
this.status = options.status;
|
|
53
|
+
attach(
|
|
54
|
+
this,
|
|
55
|
+
this.kind === "timeout" || this.kind === "polling" ? create(Flag.Transient) : create(Flag.AuthFailed),
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ProviderHttpError } from "./classes";
|
|
2
|
+
import { attach, create, Flag } from "./flags";
|
|
3
|
+
|
|
4
|
+
/** Which part of a provider exchange produced a non-HTTP error. */
|
|
5
|
+
export type ProviderResponseErrorKind =
|
|
6
|
+
/** Stream closed before a terminal completion/response event. */
|
|
7
|
+
| "incomplete-stream"
|
|
8
|
+
/** Terminal event carried an error / unexpected stop reason. */
|
|
9
|
+
| "output"
|
|
10
|
+
/** Response body was empty/missing when content was required. */
|
|
11
|
+
| "empty-body"
|
|
12
|
+
/** Malformed wire envelope (unexpected message ordering / shape). */
|
|
13
|
+
| "envelope"
|
|
14
|
+
/** Content was blocked by a provider safety filter. */
|
|
15
|
+
| "content-blocked"
|
|
16
|
+
/** Runtime/namespace resolution or other provider-internal failure. */
|
|
17
|
+
| "runtime";
|
|
18
|
+
|
|
19
|
+
export interface ProviderResponseErrorOptions {
|
|
20
|
+
provider?: string;
|
|
21
|
+
kind?: ProviderResponseErrorKind;
|
|
22
|
+
cause?: unknown;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A non-HTTP provider failure: a truncated stream, an error stop reason, an
|
|
27
|
+
* empty body, a malformed envelope, or a runtime fault. For non-2xx HTTP
|
|
28
|
+
* responses use {@link ProviderHttpError} (or a provider subclass) instead.
|
|
29
|
+
*/
|
|
30
|
+
export class ProviderResponseError extends Error {
|
|
31
|
+
readonly provider: string | undefined;
|
|
32
|
+
readonly kind: ProviderResponseErrorKind;
|
|
33
|
+
|
|
34
|
+
constructor(message: string, options: ProviderResponseErrorOptions = {}) {
|
|
35
|
+
super(message, options.cause === undefined ? undefined : { cause: options.cause });
|
|
36
|
+
this.name = "ProviderResponseError";
|
|
37
|
+
this.provider = options.provider;
|
|
38
|
+
this.kind = options.kind ?? "output";
|
|
39
|
+
if (this.kind === "content-blocked") attach(this, create(Flag.ProviderFinishError));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Non-2xx response from the Devin API. */
|
|
44
|
+
export class DevinApiError extends ProviderHttpError {
|
|
45
|
+
override readonly name = "DevinApiError";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Non-2xx response from the GitLab Duo direct-access API. */
|
|
49
|
+
export class GitLabDuoApiError extends ProviderHttpError {
|
|
50
|
+
override readonly name = "GitLabDuoApiError";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Non-2xx response from the GitLab Duo Workflow API. */
|
|
54
|
+
export class GitLabDuoWorkflowApiError extends ProviderHttpError {
|
|
55
|
+
override readonly name = "GitLabDuoWorkflowApiError";
|
|
56
|
+
}
|
|
@@ -131,7 +131,7 @@ export function isUsageLimitStatus(status: number | undefined): boolean {
|
|
|
131
131
|
* credentials.
|
|
132
132
|
*/
|
|
133
133
|
export function isUsageLimitOutcome(status: number | undefined, message: string | undefined): boolean {
|
|
134
|
-
if (message &&
|
|
134
|
+
if (message && matchesUsageLimitText(message)) return true;
|
|
135
135
|
if (!isUsageLimitStatus(status)) return false;
|
|
136
136
|
if (!message || isOpaqueStatusBody(message)) return true;
|
|
137
137
|
return parseRateLimitReason(message) === "QUOTA_EXHAUSTED";
|
|
@@ -143,13 +143,19 @@ export function isUsageLimitOutcome(status: number | undefined, message: string
|
|
|
143
143
|
* generic punctuation. Anything else (retry hints, capacity wording, error
|
|
144
144
|
* descriptions) is informative enough to defer to the classifier.
|
|
145
145
|
*/
|
|
146
|
-
function isOpaqueStatusBody(message: string): boolean {
|
|
146
|
+
export function isOpaqueStatusBody(message: string): boolean {
|
|
147
147
|
const cleaned = message
|
|
148
148
|
.replace(/\b429\b/g, "")
|
|
149
149
|
.replace(/\b(?:http|https|status|error|code|response|message)\b/gi, "");
|
|
150
150
|
return !/[a-z\d]{3,}/i.test(cleaned);
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Internal text matcher for usage/quota-limit phrasing. NOT part of the public
|
|
155
|
+
* API — callers classify through {@link import("./flags").isUsageLimit} (the
|
|
156
|
+
* flag accessor). `flags.ts` consumes this to populate `Flag.UsageLimit`, and
|
|
157
|
+
* {@link isUsageLimitOutcome} uses it for the account-rotation decision.
|
|
158
|
+
*/
|
|
159
|
+
export function matchesUsageLimitText(errorMessage: string): boolean {
|
|
154
160
|
return USAGE_LIMIT_PATTERN.test(errorMessage) || ACCOUNT_RATE_LIMIT_PATTERN.test(errorMessage);
|
|
155
161
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { isRetryableError, isUnexpectedSocketCloseMessage } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import {
|
|
3
|
+
isRetryableStreamEnvelopeError,
|
|
4
|
+
isTransientStreamParseError,
|
|
5
|
+
isUsageLimit,
|
|
6
|
+
status,
|
|
7
|
+
TRANSIENT_TRANSPORT_PATTERN,
|
|
8
|
+
} from "./flags";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Whether a numeric HTTP status is in the canonical transient/retryable set:
|
|
12
|
+
* 408 (Request Timeout), 429 (Too Many Requests), and any 5xx.
|
|
13
|
+
*
|
|
14
|
+
* This is a pure predicate over a status code already in hand — distinct from
|
|
15
|
+
* {@link classify}, which inspects a whole error (including message text) and
|
|
16
|
+
* may match more. Use this when you only have a `status: number`.
|
|
17
|
+
*/
|
|
18
|
+
export function isTransientStatus(status: number | undefined): boolean {
|
|
19
|
+
return status !== undefined && (status === 408 || status === 429 || status >= 500);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Provider-stream transient phrasings not covered by the shared
|
|
23
|
+
// TRANSIENT_TRANSPORT_PATTERN (TLS record corruption, HTTP/2 peer stream
|
|
24
|
+
// errors, upstream code 1302). The shared pattern already covers rate-limit /
|
|
25
|
+
// overloaded / 5xx / timeout / first-event wording.
|
|
26
|
+
const PROVIDER_TRANSIENT_EXTRA_PATTERN = /bad record mac|stream error.*received from peer|1302/i;
|
|
27
|
+
|
|
28
|
+
function isTransientTransportMessage(message: string): boolean {
|
|
29
|
+
return message.includes("tls: bad record mac") || message.includes("type=server_error");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Hook for provider-specific transient detection that the error module must not import directly. */
|
|
33
|
+
export interface ProviderRetryableHooks {
|
|
34
|
+
/** Provider id of the failing request, used to gate provider-specific checks. */
|
|
35
|
+
provider?: string;
|
|
36
|
+
/** Provider-specific transient predicate (e.g. Copilot `model_not_supported`). */
|
|
37
|
+
isProviderTransient?: (error: Error) => boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Whether a provider stream error should be retried against the same credential.
|
|
42
|
+
*
|
|
43
|
+
* Account-level usage/quota limits are deliberately treated as **non**-retryable
|
|
44
|
+
* here — they are owned by the credential-rotation layer (auth-gateway /
|
|
45
|
+
* `streamSimple` a/b/c policy), not this seconds-scale provider backoff.
|
|
46
|
+
*
|
|
47
|
+
* Provider-specific transient cases are injected via {@link ProviderRetryableHooks}
|
|
48
|
+
* so this stays free of provider imports.
|
|
49
|
+
*/
|
|
50
|
+
export function isProviderRetryableError(error: unknown, hooks: ProviderRetryableHooks = {}): boolean {
|
|
51
|
+
if (!(error instanceof Error)) return false;
|
|
52
|
+
if (hooks.isProviderTransient?.(error)) return true;
|
|
53
|
+
if (isUsageLimit(error)) return false;
|
|
54
|
+
const httpStatus = status(error);
|
|
55
|
+
if (httpStatus !== undefined && httpStatus >= 400 && httpStatus < 500 && httpStatus !== 408 && httpStatus !== 429) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const msg = error.message.toLowerCase();
|
|
59
|
+
if (
|
|
60
|
+
isUnexpectedSocketCloseMessage(msg) ||
|
|
61
|
+
isTransientTransportMessage(msg) ||
|
|
62
|
+
TRANSIENT_TRANSPORT_PATTERN.test(msg) ||
|
|
63
|
+
PROVIDER_TRANSIENT_EXTRA_PATTERN.test(msg) ||
|
|
64
|
+
isTransientStreamParseError(error) ||
|
|
65
|
+
isRetryableStreamEnvelopeError(error)
|
|
66
|
+
) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
return isRetryableError(error);
|
|
70
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { attach, create, Flag } from "./flags";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Caller-supplied input failed validation before/while building a provider
|
|
5
|
+
* request: bad request body, malformed tool arguments, unsupported content
|
|
6
|
+
* type, a schema that cannot be normalized, an unknown tool, etc.
|
|
7
|
+
*
|
|
8
|
+
* This is a programmer/config/contract error, not a transient provider fault —
|
|
9
|
+
* it is never retried.
|
|
10
|
+
*/
|
|
11
|
+
export class ValidationError extends Error {
|
|
12
|
+
constructor(message: string, options?: { cause?: unknown }) {
|
|
13
|
+
super(message, options?.cause === undefined ? undefined : { cause: options.cause });
|
|
14
|
+
this.name = "ValidationError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** A referenced tool was not found in the active tool set. */
|
|
19
|
+
export class ToolNotFoundError extends ValidationError {
|
|
20
|
+
constructor(toolName: string) {
|
|
21
|
+
super(`Tool "${toolName}" not found`);
|
|
22
|
+
this.name = "ToolNotFoundError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Provider/auth configuration was missing or malformed (env var pointing at a
|
|
28
|
+
* missing file, missing projectId, bad bind string, mTLS half-configured, …).
|
|
29
|
+
*/
|
|
30
|
+
export class ConfigurationError extends Error {
|
|
31
|
+
constructor(message: string, options?: { cause?: unknown }) {
|
|
32
|
+
super(message, options?.cause === undefined ? undefined : { cause: options.cause });
|
|
33
|
+
this.name = "ConfigurationError";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** A request was abandoned because it exceeded a stream/idle/first-event deadline. */
|
|
38
|
+
export class StreamTimeoutError extends Error {
|
|
39
|
+
constructor(message = "Request timed out.", options?: { cause?: unknown }) {
|
|
40
|
+
super(message, options?.cause === undefined ? undefined : { cause: options.cause });
|
|
41
|
+
this.name = "StreamTimeoutError";
|
|
42
|
+
attach(this, create(Flag.Transient, Flag.Timeout));
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type { AuthGatewayBootOptions, ModelResolver } from "./auth-gateway/serve
|
|
|
6
6
|
export * from "./auth-gateway/types";
|
|
7
7
|
export * from "./auth-retry";
|
|
8
8
|
export * from "./auth-storage";
|
|
9
|
-
export * from "./
|
|
9
|
+
export * from "./error/rate-limit";
|
|
10
10
|
export * from "./provider-details";
|
|
11
11
|
export * from "./providers/anthropic";
|
|
12
12
|
export * from "./providers/anthropic-client";
|
|
@@ -24,7 +24,6 @@ export * from "./providers/openai-codex-responses";
|
|
|
24
24
|
export * from "./providers/openai-completions";
|
|
25
25
|
export * from "./providers/openai-responses";
|
|
26
26
|
export * from "./providers/synthetic";
|
|
27
|
-
export * from "./rate-limit-utils";
|
|
28
27
|
export * from "./registry";
|
|
29
28
|
export * from "./stream";
|
|
30
29
|
export * from "./types";
|
|
@@ -43,7 +42,6 @@ export * from "./usage/zai";
|
|
|
43
42
|
export * from "./utils/anthropic-auth";
|
|
44
43
|
export * from "./utils/event-stream";
|
|
45
44
|
export * from "./utils/openrouter-headers";
|
|
46
|
-
export * from "./utils/overflow";
|
|
47
45
|
export * from "./utils/retry";
|
|
48
46
|
export * from "./utils/schema";
|
|
49
47
|
export * from "./utils/thinking-loop";
|
|
@@ -10,15 +10,9 @@
|
|
|
10
10
|
import type { Effort } from "@oh-my-pi/pi-catalog/effort";
|
|
11
11
|
import { mapEffortToAnthropicAdaptiveEffort, requireSupportedEffort } from "@oh-my-pi/pi-catalog/model-thinking";
|
|
12
12
|
import { calculateCost } from "@oh-my-pi/pi-catalog/models";
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
extractHttpStatusFromError,
|
|
17
|
-
fetchWithRetry,
|
|
18
|
-
parseStreamingJson,
|
|
19
|
-
parseStreamingJsonThrottled,
|
|
20
|
-
} from "@oh-my-pi/pi-utils";
|
|
21
|
-
import { ProviderHttpError } from "../errors";
|
|
13
|
+
import { $env, $flag, fetchWithRetry, parseStreamingJson, parseStreamingJsonThrottled } from "@oh-my-pi/pi-utils";
|
|
14
|
+
import { renderDemotedThinking } from "../dialect/demotion";
|
|
15
|
+
import * as AIError from "../error";
|
|
22
16
|
import type {
|
|
23
17
|
Api,
|
|
24
18
|
AssistantMessage,
|
|
@@ -36,8 +30,14 @@ import type {
|
|
|
36
30
|
ToolResultMessage,
|
|
37
31
|
} from "../types";
|
|
38
32
|
import { normalizeToolCallId, resolveCacheRetention } from "../utils";
|
|
33
|
+
import {
|
|
34
|
+
clearStreamingPartialJson,
|
|
35
|
+
kStreamingBlockIndex,
|
|
36
|
+
kStreamingLastParseLen,
|
|
37
|
+
kStreamingPartialJson,
|
|
38
|
+
} from "../utils/block-symbols";
|
|
39
39
|
import { AssistantMessageEventStream } from "../utils/event-stream";
|
|
40
|
-
import {
|
|
40
|
+
import type { RawHttpRequestDump } from "../utils/http-inspector";
|
|
41
41
|
import { armPreResponseTimeout, getStreamFirstEventTimeoutMs } from "../utils/idle-iterator";
|
|
42
42
|
import { toolWireSchema } from "../utils/schema/wire";
|
|
43
43
|
import { invalidateAwsCredentialCache, resolveAwsCredentials } from "./aws-credentials";
|
|
@@ -45,11 +45,6 @@ import { decodeEventStream } from "./aws-eventstream";
|
|
|
45
45
|
import { signRequest } from "./aws-sigv4";
|
|
46
46
|
import { transformMessages } from "./transform-messages";
|
|
47
47
|
|
|
48
|
-
/** Non-2xx response (or in-stream exception event) from the Bedrock runtime API. */
|
|
49
|
-
export class BedrockApiError extends ProviderHttpError {
|
|
50
|
-
override readonly name = "BedrockApiError";
|
|
51
|
-
}
|
|
52
|
-
|
|
53
48
|
export type BedrockThinkingDisplay = "summarized" | "omitted";
|
|
54
49
|
|
|
55
50
|
export interface BedrockOptions extends StreamOptions {
|
|
@@ -164,9 +159,9 @@ function resolveBedrockRegion(modelId: string, options: BedrockOptions): string
|
|
|
164
159
|
}
|
|
165
160
|
|
|
166
161
|
type Block = (TextContent | ThinkingContent | ToolCall) & {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
162
|
+
[kStreamingBlockIndex]?: number;
|
|
163
|
+
[kStreamingPartialJson]?: string;
|
|
164
|
+
[kStreamingLastParseLen]?: number;
|
|
170
165
|
};
|
|
171
166
|
|
|
172
167
|
// ---------- Bedrock wire-format types ----------
|
|
@@ -288,7 +283,7 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream"> = (
|
|
|
288
283
|
const stream = new AssistantMessageEventStream();
|
|
289
284
|
|
|
290
285
|
(async () => {
|
|
291
|
-
const startTime =
|
|
286
|
+
const startTime = performance.now();
|
|
292
287
|
let firstTokenTime: number | undefined;
|
|
293
288
|
|
|
294
289
|
const output: AssistantMessage = {
|
|
@@ -421,11 +416,15 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream"> = (
|
|
|
421
416
|
invalidateAwsCredentialCache({ profile: options.profile, region });
|
|
422
417
|
}
|
|
423
418
|
const errBody = await response.text().catch(() => "");
|
|
424
|
-
throw new BedrockApiError(
|
|
425
|
-
|
|
426
|
-
|
|
419
|
+
throw new AIError.BedrockApiError(
|
|
420
|
+
`Bedrock HTTP ${response.status}: ${errBody.slice(0, 1000)}`,
|
|
421
|
+
response.status,
|
|
422
|
+
{
|
|
423
|
+
headers: response.headers,
|
|
424
|
+
},
|
|
425
|
+
);
|
|
427
426
|
}
|
|
428
|
-
if (!response.body) throw new
|
|
427
|
+
if (!response.body) throw new AIError.BedrockApiError("Bedrock response has no body", response.status);
|
|
429
428
|
|
|
430
429
|
// Track first event for the abort/diagnostic path (currently informational).
|
|
431
430
|
for await (const message of decodeEventStream(response.body)) {
|
|
@@ -437,14 +436,12 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream"> = (
|
|
|
437
436
|
const payload = safeParsePayload(message.payload) as { message?: string } | undefined;
|
|
438
437
|
const errorMessage = payload?.message || new TextDecoder().decode(message.payload);
|
|
439
438
|
const text = `${exceptionType}: ${errorMessage}`;
|
|
440
|
-
throw exceptionType
|
|
441
|
-
? new BedrockApiError(text, 400, { code: exceptionType })
|
|
442
|
-
: new Error(text);
|
|
439
|
+
throw new AIError.BedrockApiError(text, 400, { code: exceptionType });
|
|
443
440
|
}
|
|
444
441
|
if (messageType === "error") {
|
|
445
442
|
const code = message.headers[":error-code"] || "UnknownError";
|
|
446
443
|
const errorMessage = message.headers[":error-message"] || new TextDecoder().decode(message.payload);
|
|
447
|
-
throw new
|
|
444
|
+
throw new AIError.BedrockApiError(`${code}: ${errorMessage}`, 400, { code });
|
|
448
445
|
}
|
|
449
446
|
if (messageType !== "event") continue;
|
|
450
447
|
|
|
@@ -456,18 +453,21 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream"> = (
|
|
|
456
453
|
// no-op: first event marker is implicit by stream entry.
|
|
457
454
|
const ev = payload as MessageStartEvent;
|
|
458
455
|
if (ev.role !== "assistant") {
|
|
459
|
-
throw new
|
|
456
|
+
throw new AIError.BedrockApiError(
|
|
457
|
+
"Unexpected assistant message start but got user message start instead",
|
|
458
|
+
0,
|
|
459
|
+
);
|
|
460
460
|
}
|
|
461
461
|
stream.push({ type: "start", partial: output });
|
|
462
462
|
break;
|
|
463
463
|
}
|
|
464
464
|
case "contentBlockStart": {
|
|
465
|
-
if (!firstTokenTime) firstTokenTime =
|
|
465
|
+
if (!firstTokenTime) firstTokenTime = performance.now();
|
|
466
466
|
handleContentBlockStart(payload as ContentBlockStartEvent, blocks, output, stream, sentinelInjected);
|
|
467
467
|
break;
|
|
468
468
|
}
|
|
469
469
|
case "contentBlockDelta": {
|
|
470
|
-
if (!firstTokenTime) firstTokenTime =
|
|
470
|
+
if (!firstTokenTime) firstTokenTime = performance.now();
|
|
471
471
|
handleContentBlockDelta(payload as ContentBlockDeltaEvent, blocks, output, stream);
|
|
472
472
|
break;
|
|
473
473
|
}
|
|
@@ -496,23 +496,20 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream"> = (
|
|
|
496
496
|
}
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
-
if (options.signal?.aborted) throw new
|
|
499
|
+
if (options.signal?.aborted) throw new AIError.AbortError();
|
|
500
500
|
|
|
501
501
|
if (output.stopReason === "error" || output.stopReason === "aborted") {
|
|
502
|
-
throw new
|
|
502
|
+
throw new AIError.BedrockApiError(output.errorMessage ?? "An unknown error occurred", 0);
|
|
503
503
|
}
|
|
504
504
|
|
|
505
|
-
output.duration =
|
|
505
|
+
output.duration = performance.now() - startTime;
|
|
506
506
|
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
507
507
|
stream.push({ type: "done", reason: output.stopReason, message: output });
|
|
508
508
|
stream.end();
|
|
509
509
|
} catch (error) {
|
|
510
510
|
for (const block of output.content) {
|
|
511
|
-
|
|
512
|
-
delete (block as Block).partialJson;
|
|
511
|
+
if (block.type === "toolCall") clearStreamingPartialJson(block);
|
|
513
512
|
}
|
|
514
|
-
output.stopReason = options.signal?.aborted ? "aborted" : "error";
|
|
515
|
-
output.errorStatus = extractHttpStatusFromError(error);
|
|
516
513
|
const baseMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
|
517
514
|
// Enrich error with thinking block diagnostics for signature-related failures
|
|
518
515
|
let diagnostics = "";
|
|
@@ -534,8 +531,12 @@ export const streamBedrock: StreamFunction<"bedrock-converse-stream"> = (
|
|
|
534
531
|
diagnostics = `\n[thinking-diag] ${JSON.stringify(thinkingBlocks)}`;
|
|
535
532
|
}
|
|
536
533
|
}
|
|
537
|
-
|
|
538
|
-
output.
|
|
534
|
+
const result = await AIError.finalize(error, { api: model.api, signal: options.signal, rawRequestDump });
|
|
535
|
+
output.stopReason = result.stopReason;
|
|
536
|
+
output.errorStatus = result.status;
|
|
537
|
+
output.errorId = result.id;
|
|
538
|
+
output.errorMessage = result.message + diagnostics;
|
|
539
|
+
output.duration = performance.now() - startTime;
|
|
539
540
|
if (firstTokenTime) output.ttft = firstTokenTime - startTime;
|
|
540
541
|
stream.push({ type: "error", reason: output.stopReason, error: output });
|
|
541
542
|
stream.end();
|
|
@@ -575,8 +576,8 @@ function handleContentBlockStart(
|
|
|
575
576
|
id: normalizeToolCallId(start.toolUse.toolUseId || ""),
|
|
576
577
|
name: start.toolUse.name || "",
|
|
577
578
|
arguments: {},
|
|
578
|
-
|
|
579
|
-
index,
|
|
579
|
+
[kStreamingPartialJson]: "",
|
|
580
|
+
[kStreamingBlockIndex]: index,
|
|
580
581
|
};
|
|
581
582
|
output.content.push(block);
|
|
582
583
|
stream.push({ type: "toolcall_start", contentIndex: blocks.length - 1, partial: output });
|
|
@@ -591,13 +592,13 @@ function handleContentBlockDelta(
|
|
|
591
592
|
): void {
|
|
592
593
|
const contentBlockIndex = event.contentBlockIndex;
|
|
593
594
|
const delta = event.delta;
|
|
594
|
-
let index = blocks.findIndex(b => b
|
|
595
|
+
let index = blocks.findIndex(b => b[kStreamingBlockIndex] === contentBlockIndex);
|
|
595
596
|
let block = blocks[index];
|
|
596
597
|
|
|
597
598
|
if (delta?.text !== undefined) {
|
|
598
599
|
// If no text block exists yet, create one — `handleContentBlockStart` is not sent for text blocks
|
|
599
600
|
if (!block) {
|
|
600
|
-
const newBlock: Block = { type: "text", text: "",
|
|
601
|
+
const newBlock: Block = { type: "text", text: "", [kStreamingBlockIndex]: contentBlockIndex };
|
|
601
602
|
output.content.push(newBlock);
|
|
602
603
|
index = blocks.length - 1;
|
|
603
604
|
block = blocks[index];
|
|
@@ -608,11 +609,11 @@ function handleContentBlockDelta(
|
|
|
608
609
|
stream.push({ type: "text_delta", contentIndex: index, delta: delta.text, partial: output });
|
|
609
610
|
}
|
|
610
611
|
} else if (delta?.toolUse && block?.type === "toolCall") {
|
|
611
|
-
block
|
|
612
|
-
const throttled = parseStreamingJsonThrottled(block
|
|
612
|
+
block[kStreamingPartialJson] = (block[kStreamingPartialJson] || "") + (delta.toolUse.input || "");
|
|
613
|
+
const throttled = parseStreamingJsonThrottled(block[kStreamingPartialJson], block[kStreamingLastParseLen] ?? 0);
|
|
613
614
|
if (throttled) {
|
|
614
615
|
block.arguments = throttled.value;
|
|
615
|
-
block
|
|
616
|
+
block[kStreamingLastParseLen] = throttled.parsedLen;
|
|
616
617
|
}
|
|
617
618
|
stream.push({ type: "toolcall_delta", contentIndex: index, delta: delta.toolUse.input || "", partial: output });
|
|
618
619
|
} else if (delta?.reasoningContent) {
|
|
@@ -620,7 +621,12 @@ function handleContentBlockDelta(
|
|
|
620
621
|
let thinkingIndex = index;
|
|
621
622
|
|
|
622
623
|
if (!thinkingBlock) {
|
|
623
|
-
const newBlock: Block = {
|
|
624
|
+
const newBlock: Block = {
|
|
625
|
+
type: "thinking",
|
|
626
|
+
thinking: "",
|
|
627
|
+
thinkingSignature: "",
|
|
628
|
+
[kStreamingBlockIndex]: contentBlockIndex,
|
|
629
|
+
};
|
|
624
630
|
output.content.push(newBlock);
|
|
625
631
|
thinkingIndex = blocks.length - 1;
|
|
626
632
|
thinkingBlock = blocks[thinkingIndex];
|
|
@@ -662,10 +668,9 @@ function handleContentBlockStop(
|
|
|
662
668
|
output: AssistantMessage,
|
|
663
669
|
stream: AssistantMessageEventStream,
|
|
664
670
|
): void {
|
|
665
|
-
const index = blocks.findIndex(b => b
|
|
671
|
+
const index = blocks.findIndex(b => b[kStreamingBlockIndex] === event.contentBlockIndex);
|
|
666
672
|
const block = blocks[index];
|
|
667
673
|
if (!block) return;
|
|
668
|
-
delete (block as Block).index;
|
|
669
674
|
|
|
670
675
|
switch (block.type) {
|
|
671
676
|
case "text":
|
|
@@ -675,9 +680,8 @@ function handleContentBlockStop(
|
|
|
675
680
|
stream.push({ type: "thinking_end", contentIndex: index, content: block.thinking, partial: output });
|
|
676
681
|
break;
|
|
677
682
|
case "toolCall":
|
|
678
|
-
block.arguments = parseStreamingJson(block
|
|
679
|
-
|
|
680
|
-
delete (block as Block).lastParseLen;
|
|
683
|
+
block.arguments = parseStreamingJson(block[kStreamingPartialJson]);
|
|
684
|
+
clearStreamingPartialJson(block);
|
|
681
685
|
stream.push({ type: "toolcall_end", contentIndex: index, toolCall: block, partial: output });
|
|
682
686
|
break;
|
|
683
687
|
}
|
|
@@ -772,7 +776,7 @@ function convertMessages(
|
|
|
772
776
|
contentBlocks.push({ image: createImageBlock(c.mimeType, c.data) });
|
|
773
777
|
break;
|
|
774
778
|
default:
|
|
775
|
-
throw new
|
|
779
|
+
throw new AIError.ValidationError("Unknown user content type");
|
|
776
780
|
}
|
|
777
781
|
}
|
|
778
782
|
// Skip message if all blocks filtered out
|
|
@@ -820,11 +824,11 @@ function convertMessages(
|
|
|
820
824
|
});
|
|
821
825
|
} else {
|
|
822
826
|
// Model requires signature but we don't have one — demote to text
|
|
823
|
-
contentBlocks.push({ text:
|
|
827
|
+
contentBlocks.push({ text: renderDemotedThinking(model.id, c.thinking) });
|
|
824
828
|
}
|
|
825
829
|
break;
|
|
826
830
|
default:
|
|
827
|
-
throw new
|
|
831
|
+
throw new AIError.ValidationError("Unknown assistant content type");
|
|
828
832
|
}
|
|
829
833
|
}
|
|
830
834
|
// Skip if all content blocks were filtered out
|
|
@@ -870,7 +874,7 @@ function convertMessages(
|
|
|
870
874
|
break;
|
|
871
875
|
}
|
|
872
876
|
default:
|
|
873
|
-
throw new
|
|
877
|
+
throw new AIError.ValidationError("Unknown message role");
|
|
874
878
|
}
|
|
875
879
|
}
|
|
876
880
|
|
|
@@ -1032,7 +1036,7 @@ function createImageBlock(mimeType: string, data: string): ImageBlockWire["image
|
|
|
1032
1036
|
format = "webp";
|
|
1033
1037
|
break;
|
|
1034
1038
|
default:
|
|
1035
|
-
throw new
|
|
1039
|
+
throw new AIError.ValidationError(`Unknown image type: ${mimeType}`);
|
|
1036
1040
|
}
|
|
1037
1041
|
return { source: { bytes: data }, format };
|
|
1038
1042
|
}
|
|
@@ -21,7 +21,11 @@
|
|
|
21
21
|
* with up to 25% jitter).
|
|
22
22
|
*/
|
|
23
23
|
import { scheduler } from "node:timers/promises";
|
|
24
|
-
import
|
|
24
|
+
import * as AIError from "../error";
|
|
25
|
+
import { AnthropicApiError, AnthropicConnectionError, AnthropicConnectionTimeoutError } from "../error";
|
|
26
|
+
|
|
27
|
+
export { AnthropicApiError, AnthropicConnectionError, AnthropicConnectionTimeoutError };
|
|
28
|
+
|
|
25
29
|
import type { FetchImpl } from "../types";
|
|
26
30
|
import type { MessageCreateParamsStreaming } from "./anthropic-wire";
|
|
27
31
|
|
|
@@ -77,42 +81,8 @@ export interface AnthropicClientOptions {
|
|
|
77
81
|
fetchOptions?: AnthropicFetchOptions;
|
|
78
82
|
}
|
|
79
83
|
|
|
80
|
-
/** Non-2xx response from the Anthropic API. */
|
|
81
|
-
export class AnthropicApiError extends ProviderHttpError {
|
|
82
|
-
declare readonly headers: Headers;
|
|
83
|
-
readonly requestId: string | null;
|
|
84
|
-
|
|
85
|
-
constructor(status: number, message: string, headers: Headers) {
|
|
86
|
-
super(message, status, { headers });
|
|
87
|
-
this.name = "AnthropicApiError";
|
|
88
|
-
this.requestId = headers.get("request-id");
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
static async fromResponse(response: Response): Promise<AnthropicApiError> {
|
|
92
|
-
const body = await response.text().catch(() => "");
|
|
93
|
-
const detail = body.trim() || "status code (no body)";
|
|
94
|
-
return new AnthropicApiError(response.status, `${response.status} ${detail}`, response.headers);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** Network-level failure (DNS, TLS, socket reset) after retries were exhausted. */
|
|
99
|
-
export class AnthropicConnectionError extends Error {
|
|
100
|
-
constructor(cause: unknown) {
|
|
101
|
-
super("Connection error.", { cause });
|
|
102
|
-
this.name = "AnthropicConnectionError";
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** No response headers arrived within the configured request timeout. */
|
|
107
|
-
export class AnthropicConnectionTimeoutError extends Error {
|
|
108
|
-
constructor() {
|
|
109
|
-
super("Request timed out.");
|
|
110
|
-
this.name = "AnthropicConnectionTimeoutError";
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
84
|
function createAbortError(): Error {
|
|
115
|
-
return new
|
|
85
|
+
return new AIError.AbortError("Request was aborted.");
|
|
116
86
|
}
|
|
117
87
|
|
|
118
88
|
/** `x-should-retry` override, then 408/409/429/5xx. */
|
|
@@ -121,7 +91,9 @@ function shouldRetryResponse(response: Response): boolean {
|
|
|
121
91
|
if (shouldRetryHeader === "true") return true;
|
|
122
92
|
if (shouldRetryHeader === "false") return false;
|
|
123
93
|
const status = response.status;
|
|
124
|
-
|
|
94
|
+
// Canonical transient set (408/429/5xx) plus 409, which Anthropic's client
|
|
95
|
+
// also retries.
|
|
96
|
+
return AIError.isTransientStatus(status) || status === 409;
|
|
125
97
|
}
|
|
126
98
|
|
|
127
99
|
/** Server-suggested delay (`retry-after-ms`, then `retry-after` seconds or HTTP date). */
|
|
@@ -260,8 +232,8 @@ export class AnthropicMessagesClient implements AnthropicMessagesClientLike {
|
|
|
260
232
|
await this.#backoff(attempt, undefined, callerSignal);
|
|
261
233
|
continue;
|
|
262
234
|
}
|
|
263
|
-
if (error instanceof AnthropicConnectionTimeoutError) throw error;
|
|
264
|
-
throw new AnthropicConnectionError(error);
|
|
235
|
+
if (error instanceof AIError.AnthropicConnectionTimeoutError) throw error;
|
|
236
|
+
throw new AIError.AnthropicConnectionError(error);
|
|
265
237
|
}
|
|
266
238
|
|
|
267
239
|
if (response.ok) return response;
|
|
@@ -271,7 +243,7 @@ export class AnthropicMessagesClient implements AnthropicMessagesClientLike {
|
|
|
271
243
|
await this.#backoff(attempt, response.headers, callerSignal);
|
|
272
244
|
continue;
|
|
273
245
|
}
|
|
274
|
-
throw await AnthropicApiError.fromResponse(response);
|
|
246
|
+
throw await AIError.AnthropicApiError.fromResponse(response);
|
|
275
247
|
}
|
|
276
248
|
}
|
|
277
249
|
|
|
@@ -300,7 +272,7 @@ export class AnthropicMessagesClient implements AnthropicMessagesClientLike {
|
|
|
300
272
|
signal: controller.signal,
|
|
301
273
|
});
|
|
302
274
|
} catch (error) {
|
|
303
|
-
if (timedOut && !callerSignal?.aborted) throw new AnthropicConnectionTimeoutError();
|
|
275
|
+
if (timedOut && !callerSignal?.aborted) throw new AIError.AnthropicConnectionTimeoutError();
|
|
304
276
|
throw error;
|
|
305
277
|
} finally {
|
|
306
278
|
clearTimeout(timer);
|