1
>
/*---------------------------------------------------------------------------------------------
forwardedChatError.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import { CopilotApiError, COPILOT_API_ERROR_STATUS_STREAMING } from './copilotApiService.js';
7
>
8
>
/**
9
>
* Marker prefix used to smuggle a structured, serialized chat fetch error
10
>
* through the agent SDK subprocess boundary. The model proxies run in this
11
>
* (the agent host) process and hold the rich {@link CopilotApiError}, but the
12
>
* agent SDKs (Claude, Codex, Copilot CLI) run as child processes that only
13
>
* see an HTTP/SSE error. The proxy appends `VSCODE_PROXY_ERROR:<base64>` to
14
>
* the error message; the SDK forwards that text back verbatim, and the agent
15
>
* decodes it on the way out.
16
>
*
17
>
* Mirrors the Copilot Chat extension's `PROXY_ERROR_PREFIX`
18
>
* (`extensions/copilot/src/extension/chatSessions/claude/common/claudeMessageDispatch.ts`).
19
>
*/
20
>
export const PROXY_ERROR_PREFIX = 'VSCODE_PROXY_ERROR:';
21
>
22
>
/**
23
>
* Upper bound on the base64 marker payload we will decode. A forwarded chat
24
>
* error serializes to well under 1 KB; this cap prevents an oversized or
25
>
* adversarial marker riding along in model-influenced error text from driving
26
>
* an unbounded base64/JSON allocation.
27
>
*/
28
>
const MAX_FORWARDED_MARKER_B64_LENGTH = 8 * 1024;
29
>
30
>
/** Standard base64 alphabet with optional padding. */
31
>
const FORWARDED_MARKER_B64_PATTERN = /^[A-Za-z0-9+/]+={0,2}$/;
32
>
33
>
/**
34
>
* Serialized chat fetch error payload. This is the JSON shape forwarded over
35
>
* the protocol's `ErrorInfo._meta.chatError`. The core consumer
36
>
* (`src/vs/workbench/contrib/chat/common/chatErrorMessages.ts`) reads the same
37
>
* JSON shape to render localized, user-facing messages. The two definitions
38
>
* are intentionally decoupled (the platform/node layer cannot import workbench
39
>
* code), so any field change must be mirrored on both sides.
40
>
*/
41
>
export interface IForwardedChatFetchError {
42
>
/** Mirrors the extension's `ChatFetchResponseType` string value. */
43
>
readonly type: string;
44
>
readonly reason?: string;
45
>
readonly requestId?: string;
46
>
readonly serverRequestId?: string;
47
>
readonly category?: string;
48
>
readonly retryAfter?: number;
49
>
readonly isAuto?: boolean;
50
>
readonly capiError?: { readonly code?: string; readonly message?: string };
51
>
}
52
>
53
>
/**
54
>
* The full forwarded chat error placed at `ErrorInfo._meta.chatError`.
55
>
*/
56
>
export interface IForwardedChatError {
57
>
readonly fetchError: IForwardedChatFetchError;
58
>
readonly copilotPlan?: string;
59
>
readonly isUsageBasedBilling?: boolean;
60
>
readonly quotaResetDate?: string;
61
>
}
62
>
63
>
/**
64
>
* Maps a {@link CopilotApiError} HTTP status (or the mid-stream streaming
65
>
* sentinel) to the extension's `ChatFetchResponseType` string value. Kept in
66
>
* sync with the Copilot Chat extension's error classification so the core
67
>
* formatter produces identical messages.
68
>
*/
69
function statusToFetchType(status: number): string {
70
switch (status) {