@x-otto/provider 0.1.0-alpha.0
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/README.md +103 -0
- package/dist/index.d.ts +2129 -0
- package/dist/index.js +6 -0
- package/package.json +32 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2129 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { URL, URLSearchParams as URLSearchParams$1 } from "node:url";
|
|
3
|
+
import { Duplex, Readable, Writable } from "node:stream";
|
|
4
|
+
import { EventEmitter } from "node:events";
|
|
5
|
+
import { Blob, File } from "node:buffer";
|
|
6
|
+
import { ConnectionOptions, TLSSocket } from "node:tls";
|
|
7
|
+
import { IpcNetConnectOpts, Socket, TcpNetConnectOpts } from "node:net";
|
|
8
|
+
|
|
9
|
+
//#region ../interchange/dist/index.d.ts
|
|
10
|
+
//#region src/message.d.ts
|
|
11
|
+
/** Message: AgentMessage/UserMessage/SystemMessage interchange types. */
|
|
12
|
+
type Timestamp = number;
|
|
13
|
+
type KnownApi = 'openai-completions' | 'openai-responses' | 'azure-openai-responses' | 'openai-codex-responses' | 'anthropic-messages' | 'bedrock-converse-stream' | 'google-generative-ai' | 'google-gemini-cli' | 'google-vertex';
|
|
14
|
+
type Api = KnownApi | (string & {});
|
|
15
|
+
type KnownProvider = 'anthropic' | 'openai' | 'google' | 'amazon-bedrock' | 'github-copilot' | 'xai' | 'groq' | 'openrouter' | 'deepseek' | 'ollama' | 'moonshot' | 'custom';
|
|
16
|
+
type Provider = KnownProvider | (string & {});
|
|
17
|
+
type StopReason = 'end_turn' | 'max_tokens' | 'tool_use' | 'stop_sequence' | 'refusal';
|
|
18
|
+
interface Usage {
|
|
19
|
+
inputTokens: number;
|
|
20
|
+
outputTokens: number;
|
|
21
|
+
cacheReadTokens: number;
|
|
22
|
+
cacheWriteTokens: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 结构化的 zod 兼容垫片——协议层不直接依赖 zod,靠结构类型让 provider/工具定义喂入真 zod schema。
|
|
26
|
+
*/
|
|
27
|
+
interface ZodType<T = unknown> {
|
|
28
|
+
parse(data: unknown): T;
|
|
29
|
+
safeParse(data: unknown): {
|
|
30
|
+
success: boolean;
|
|
31
|
+
data?: T;
|
|
32
|
+
error?: unknown;
|
|
33
|
+
};
|
|
34
|
+
toJSONSchema?: () => unknown;
|
|
35
|
+
}
|
|
36
|
+
interface TextContent {
|
|
37
|
+
type: 'text';
|
|
38
|
+
text: string;
|
|
39
|
+
signature?: string;
|
|
40
|
+
}
|
|
41
|
+
interface ImageContent {
|
|
42
|
+
type: 'image';
|
|
43
|
+
mime: string;
|
|
44
|
+
source: string;
|
|
45
|
+
}
|
|
46
|
+
interface ThinkingContent {
|
|
47
|
+
type: 'thinking';
|
|
48
|
+
text: string;
|
|
49
|
+
signature?: string;
|
|
50
|
+
}
|
|
51
|
+
interface ToolCall {
|
|
52
|
+
type: 'tool_call';
|
|
53
|
+
id: string;
|
|
54
|
+
name: string;
|
|
55
|
+
arguments: Record<string, unknown>;
|
|
56
|
+
/**
|
|
57
|
+
* 流式参数 JSON 解析失败标记(RFC-142 D4)——`stopReason: max_tokens` 截断半截
|
|
58
|
+
* JSON 时 `parseToolArguments` 置位,runtime 责任链据此把该调用转为明确错误
|
|
59
|
+
* tool_result 而非带空参数进入 zod 校验(与污染类错误分离错误通道)。
|
|
60
|
+
*
|
|
61
|
+
* **进程内标记,不进 wire**:各 provider 序列化发给模型时均为显式字段拾取
|
|
62
|
+
* (`{type, id, name, input: arguments}`,无 spread),本字段天然剥除——有测试钉住
|
|
63
|
+
* (RFC-142 重要事项规则4)。
|
|
64
|
+
*/
|
|
65
|
+
argumentsParseFailed?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A2UI content block(RFC-105 D6/M105-5b):agent 生成的声明式 UI payload。
|
|
69
|
+
* 对齐 a2ui-project/a2ui(v0.9)的核心哲学——扁平组件列表 + ID 引用 + 受信组件 catalog、
|
|
70
|
+
* 纯数据非代码、未知组件类型文本降级。
|
|
71
|
+
*
|
|
72
|
+
* 组件类型(TUI 终端安全子集,首阶段只读 display):
|
|
73
|
+
* - Text:纯文本(text 字段)。
|
|
74
|
+
* - Card:带标题容器(title + children ID 引用)。
|
|
75
|
+
* - List:条目列表(items ID 引用 + ordered 标志)。
|
|
76
|
+
* - Progress:ASCII 进度条(value 0-100,label 可选)。
|
|
77
|
+
* - Chip:内联彩色标签(text + color)。
|
|
78
|
+
* - Button:交互按钮(RFC-105 D6 F5/M105-5c,数字键触发 a2ui action;只读 display 通过
|
|
79
|
+
* renderA2uiBlock 提取为 A2uiButtonInfo 元数据)。
|
|
80
|
+
* - Form:交互式表单(RFC-211 M1:字段定义 + TUI 弹窗填写 + web-ui 原生表单)。
|
|
81
|
+
* 字段类型 text/select/toggle,payload 原样回流,不可执行代码。
|
|
82
|
+
* 未知 type → 文本摘要表示(不崩,fail-soft,R7)。
|
|
83
|
+
*/
|
|
84
|
+
interface A2uiComponent {
|
|
85
|
+
id: string;
|
|
86
|
+
type: 'Text' | 'Card' | 'List' | 'Progress' | 'Chip' | 'Button' | 'Form' | (string & {});
|
|
87
|
+
text?: string;
|
|
88
|
+
title?: string;
|
|
89
|
+
children?: string[];
|
|
90
|
+
items?: string[];
|
|
91
|
+
ordered?: boolean;
|
|
92
|
+
value?: number;
|
|
93
|
+
max?: number;
|
|
94
|
+
label?: string;
|
|
95
|
+
color?: 'accent' | 'green' | 'amber' | 'red' | 'gray';
|
|
96
|
+
action?: string;
|
|
97
|
+
shortcut?: string;
|
|
98
|
+
/** 表单标题(弹窗标题 + 对话流摘要标题)。 */
|
|
99
|
+
formTitle?: string;
|
|
100
|
+
/** 表单字段定义。 */
|
|
101
|
+
fields?: A2uiFormField[];
|
|
102
|
+
}
|
|
103
|
+
/** 单个表单字段(`A2uiComponent.type === 'Form'` 时使用)。 */
|
|
104
|
+
interface A2uiFormField {
|
|
105
|
+
/** 字段 id(Form 内唯一,submit payload 的 key)。 */
|
|
106
|
+
id: string;
|
|
107
|
+
/** 字段类型。 */
|
|
108
|
+
type: 'text' | 'select' | 'toggle';
|
|
109
|
+
/** 显示标签。 */
|
|
110
|
+
label: string;
|
|
111
|
+
/** 默认值(text=字符串, select=option id, toggle=boolean)。 */
|
|
112
|
+
defaultValue?: string | boolean;
|
|
113
|
+
/** 占位符(text 类型)。 */
|
|
114
|
+
placeholder?: string;
|
|
115
|
+
/** 选项列表(select 类型必填)。 */
|
|
116
|
+
options?: Array<{
|
|
117
|
+
id: string;
|
|
118
|
+
label: string;
|
|
119
|
+
}>;
|
|
120
|
+
/** 是否必填(渲染提示,不做前端校验——非目标)。 */
|
|
121
|
+
required?: boolean;
|
|
122
|
+
}
|
|
123
|
+
interface A2uiContent {
|
|
124
|
+
type: 'a2ui';
|
|
125
|
+
/** A2UI 协议版本(v0.9 snapshot),供未来版本迁移用。 */
|
|
126
|
+
version: string;
|
|
127
|
+
/** 扁平组件列表,ID 引用构建组件树,增量子集可追加/替换。 */
|
|
128
|
+
components: A2uiComponent[];
|
|
129
|
+
}
|
|
130
|
+
type ContentPart = TextContent | ImageContent | ThinkingContent | ToolCall | A2uiContent;
|
|
131
|
+
interface UserMessage {
|
|
132
|
+
role: 'user';
|
|
133
|
+
content: string | ContentPart[];
|
|
134
|
+
timestamp: Timestamp;
|
|
135
|
+
uuid?: string;
|
|
136
|
+
/**
|
|
137
|
+
* RFC-050 REV-1:引擎注入的内部消息(如预算收尾 steering、截断续写提示),模型需要看到、
|
|
138
|
+
* 但**不应渲染给用户**(否则 resume 时显示成用户从未输入的发言)。provider 序列化忽略此字段。
|
|
139
|
+
*/
|
|
140
|
+
internal?: boolean;
|
|
141
|
+
}
|
|
142
|
+
interface AssistantMessage {
|
|
143
|
+
role: 'assistant';
|
|
144
|
+
/**
|
|
145
|
+
* 消息内容。A2uiContent 是前向兼容新增(RFC-155 M2 结案后的协议层收口):
|
|
146
|
+
* provider 序列化层仅消费 text/tool_call/thinking,a2ui 块被静默跳过不出进 LLM 请求体;
|
|
147
|
+
* 渲染层(message-lines.ts)经 `renderA2uiBlock` 渲染。
|
|
148
|
+
*/
|
|
149
|
+
content: (TextContent | ThinkingContent | ToolCall | A2uiContent)[];
|
|
150
|
+
api: Api;
|
|
151
|
+
provider: Provider;
|
|
152
|
+
model: string;
|
|
153
|
+
usage: Usage;
|
|
154
|
+
stopReason: StopReason;
|
|
155
|
+
uuid?: string;
|
|
156
|
+
}
|
|
157
|
+
interface ToolResultMessage<T extends unknown = unknown> {
|
|
158
|
+
role: 'tool_result';
|
|
159
|
+
toolCallId: string;
|
|
160
|
+
toolName: string;
|
|
161
|
+
/**
|
|
162
|
+
* 工具结果内容。A2uiContent 是前向兼容新增(RFC-155 M2 结案后的协议层收口):
|
|
163
|
+
* provider 序列化仅消费 text,a2ui 块被静默跳过;渲染层(message-lines.ts)经
|
|
164
|
+
* `renderA2uiBlock` 渲染为终端卡片。
|
|
165
|
+
*/
|
|
166
|
+
content: (TextContent | ImageContent | A2uiContent)[];
|
|
167
|
+
details: T;
|
|
168
|
+
isError: boolean;
|
|
169
|
+
timestamp: Timestamp;
|
|
170
|
+
uuid?: string;
|
|
171
|
+
/** RFC-050 REV-1:引擎合成的内部 tool_result(如预算耗尽未执行的占位),不渲染给用户。 */
|
|
172
|
+
internal?: boolean;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* RFC-144 M1:mid-conversation system 通知消息——**真正进 provider 请求**的协议消息类型
|
|
176
|
+
* (区别于 `@otto/hook-contracts` 的 `SystemAgentMessage`,后者是 hooks/UI 域、
|
|
177
|
+
* convertToLLM 类型边界显式过滤、绝不进 provider 请求)。
|
|
178
|
+
*
|
|
179
|
+
* 用途:lifecycleAsync 工具(RFC-144)真正完成时,追加一条独立消息告知 LLM"运营方观察到
|
|
180
|
+
* 的状态变化"(Anthropic mid-conversation system message 官方场景之一),不修改/替换任何
|
|
181
|
+
* 历史消息(纯追加语义),LLM 在下一轮推理中作为权威事实处理。
|
|
182
|
+
*
|
|
183
|
+
* provider 序列化:
|
|
184
|
+
* - Anthropic(原生支持,Claude Opus 4.8+)→ `{role: 'system', content}` 追加进 messages 数组,
|
|
185
|
+
* 放置规则见 RFC-144 重要事项规则 5(必须紧跟携带 tool_result 的 user turn 之后)。
|
|
186
|
+
* - 不支持该特性的模型/provider(如 OpenAI,或 Anthropic 旧模型)→ 降级为等价的
|
|
187
|
+
* `role: 'user'` 消息 + 显式文本前缀(牺牲"运营方权威"语义,保留基本可用性),
|
|
188
|
+
* 降级逻辑归属 provider adapter 层(本类型定义不关心降级细节)。
|
|
189
|
+
*
|
|
190
|
+
* 不可变性(RFC-144 禁区):一旦追加,绝不编辑或删除已发送的 system 通知——结果更新一律
|
|
191
|
+
* 追加新消息,不改写旧消息(Anthropic 官方限制:编辑会使该点之后的 prompt cache 失效)。
|
|
192
|
+
*/
|
|
193
|
+
interface SystemNotificationMessage {
|
|
194
|
+
role: 'system_notification';
|
|
195
|
+
/** 通知正文(如 "[Tool completion] pnpm build finished: exit 0")。 */
|
|
196
|
+
content: string;
|
|
197
|
+
/**
|
|
198
|
+
* 该通知对应的工具执行是否失败——显式字段,供消费方(渲染层/审计)直接读取,不必解析
|
|
199
|
+
* `content` 文案判断状态(RFC-144 M2:文案格式可能演进,靠字符串匹配脆弱且易误判)。
|
|
200
|
+
*/
|
|
201
|
+
isError?: boolean;
|
|
202
|
+
/** 关联的 lifecycleAsync 工具调用 id,供消费方(渲染层/审计)溯源。 */
|
|
203
|
+
relatedToolCallId?: string;
|
|
204
|
+
timestamp: Timestamp;
|
|
205
|
+
uuid?: string;
|
|
206
|
+
}
|
|
207
|
+
type Message = UserMessage | AssistantMessage | ToolResultMessage | SystemNotificationMessage;
|
|
208
|
+
/**
|
|
209
|
+
* 历史压缩摘要消息的标记前缀——单一真相源(跨包协议常量)。
|
|
210
|
+
* 生产者 @otto/memory 注入摘要消息时用、压缩去重(isSummaryMessage)时识别;消费者
|
|
211
|
+
* @otto/agent 的 ContextPipeline 从会话树恢复摘要时用同一前缀重建摘要消息。放在协议叶子,
|
|
212
|
+
* 避免双份字面量漂移导致 isSummaryMessage 失配。
|
|
213
|
+
*/
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region src/stream.d.ts
|
|
216
|
+
/**
|
|
217
|
+
* 供应商 usage 快照(状态栏「周/小时额度」展示,RFC 无编号临时功能——状态栏 provider usage)。
|
|
218
|
+
*
|
|
219
|
+
* 仅 Anthropic OAuth 订阅计划(Claude Pro/Max)请求会带 anthropic-ratelimit-unified-* 响应头族;
|
|
220
|
+
* API key 走标准 RPM/TPM 限流不带此头族,故 provider/ai 层解析不到时返回 null,调用方天然
|
|
221
|
+
* 实现"API key 不显示"(见 packages/ai/src/provider-usage.ts extractProviderUsageFromHeaders
|
|
222
|
+
* 与 packages/ai/src/auth-store.ts getAuthSource)。
|
|
223
|
+
*
|
|
224
|
+
* usedPercent 未经 Anthropic 官方文档确认(仅有 status/representative-claim/reset 三个字段有
|
|
225
|
+
* SDK 源码级证据),探测不到时为 undefined——UI 侧绝不显示猜测/编造的百分比数字。
|
|
226
|
+
*/
|
|
227
|
+
interface ProviderUsageSnapshot {
|
|
228
|
+
/**
|
|
229
|
+
* 订阅配额状态。'allowed'/'allowed_warning'/'rejected' 来自 Anthropic unified 头族的
|
|
230
|
+
* 真实语义;**'unknown' = 无订阅配额数据**(RFC-118 小修 S11:OpenAI 只有标准
|
|
231
|
+
* x-ratelimit-* 头无配额语义,此前重载 'allowed' 造成同字段双语义——UI 按
|
|
232
|
+
* status!=='rejected' 判「额度 OK」会让 OpenAI 用户永远看不到预警)。
|
|
233
|
+
* 消费端对 'unknown' 应展示中性态(不判额度充足也不报警)。
|
|
234
|
+
*/
|
|
235
|
+
status: 'allowed' | 'allowed_warning' | 'rejected' | 'unknown';
|
|
236
|
+
limitType?: 'five_hour' | 'seven_day' | 'seven_day_opus' | 'seven_day_sonnet' | 'seven_day_overage_included';
|
|
237
|
+
/** Unix 时间戳(秒)——配额重置时刻。 */
|
|
238
|
+
resetsAt?: number;
|
|
239
|
+
/** 已用百分比(0-100)。未探测到时 undefined。 */
|
|
240
|
+
usedPercent?: number;
|
|
241
|
+
/**
|
|
242
|
+
* Overage(额外用量池)状态。
|
|
243
|
+
* 仅当标准额度已耗尽(status='rejected')且 overage 可用(overageStatus='allowed'/'allowed_warning')
|
|
244
|
+
* 时有意义——此时 isUsingOverage = true,状态栏应展示 overage 标识而非 rejected 错误态。
|
|
245
|
+
* 无 overage 头族的请求(API key / 未开通 overage)此字段为 undefined。
|
|
246
|
+
*/
|
|
247
|
+
overageStatus?: 'allowed' | 'allowed_warning' | 'rejected';
|
|
248
|
+
/** Overage 池重置时刻(Unix 秒)。 */
|
|
249
|
+
overageResetsAt?: number;
|
|
250
|
+
/** Overage 不可用原因(仅在 overageStatus='rejected' 时可能有值)。 */
|
|
251
|
+
overageDisabledReason?: string;
|
|
252
|
+
/**
|
|
253
|
+
* 标准 API 限流快照(x-ratelimit-* 头族,有官方文档)。与 Anthropic unified 订阅配额
|
|
254
|
+
* 不同——这里表示的是分钟级请求/Token 的 token bucket 限流,任何认证方式的请求都返回
|
|
255
|
+
* (Anthropic API key + OpenAI API key + OAuth 订阅)。undefined = 没有标准限流头。
|
|
256
|
+
*
|
|
257
|
+
* 格式来自 OpenAI Rate Limits 文档(x-ratelimit-limit-requests/remaining-requests/
|
|
258
|
+
* reset-requests/-limit-tokens/-remaining-tokens/-reset-tokens),Anthropic 也用
|
|
259
|
+
* 同名头族但加上 `anthropic-` 前缀。
|
|
260
|
+
*/
|
|
261
|
+
standardLimits?: {
|
|
262
|
+
remainingRequests?: number;
|
|
263
|
+
remainingTokens?: number;
|
|
264
|
+
limitRequests?: number;
|
|
265
|
+
limitTokens?: number;
|
|
266
|
+
resetRequestsMs?: number;
|
|
267
|
+
resetTokensMs?: number;
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* 流式增量事件——provider converse() 的统一产物面。RFC-067 M111(A5):所有 provider 都必须
|
|
272
|
+
* 发齐 text/thinking/tool_call 的 start/delta/end 包络(end 带累积 content),否则下游
|
|
273
|
+
* 「完成通知」会丢内容。单一真相源避免 anthropic 全发 12 变体而 OpenAI 系发不全的漂移。
|
|
274
|
+
*/
|
|
275
|
+
type StreamEvent = {
|
|
276
|
+
type: 'start';
|
|
277
|
+
partial: AssistantMessage;
|
|
278
|
+
} | {
|
|
279
|
+
type: 'text_start';
|
|
280
|
+
index: number;
|
|
281
|
+
partial: AssistantMessage;
|
|
282
|
+
} | {
|
|
283
|
+
type: 'text_delta';
|
|
284
|
+
index: number;
|
|
285
|
+
delta: string;
|
|
286
|
+
partial: AssistantMessage;
|
|
287
|
+
} | {
|
|
288
|
+
type: 'text_end';
|
|
289
|
+
index: number;
|
|
290
|
+
content: string;
|
|
291
|
+
partial: AssistantMessage;
|
|
292
|
+
} | {
|
|
293
|
+
type: 'thinking_start';
|
|
294
|
+
index: number;
|
|
295
|
+
partial: AssistantMessage;
|
|
296
|
+
} | {
|
|
297
|
+
type: 'thinking_delta';
|
|
298
|
+
index: number;
|
|
299
|
+
delta: string;
|
|
300
|
+
partial: AssistantMessage;
|
|
301
|
+
} | {
|
|
302
|
+
type: 'thinking_end';
|
|
303
|
+
index: number;
|
|
304
|
+
content: string;
|
|
305
|
+
partial: AssistantMessage;
|
|
306
|
+
} | {
|
|
307
|
+
type: 'tool_call_start';
|
|
308
|
+
index: number;
|
|
309
|
+
partial: AssistantMessage;
|
|
310
|
+
} | {
|
|
311
|
+
type: 'tool_call_delta';
|
|
312
|
+
index: number;
|
|
313
|
+
delta: string;
|
|
314
|
+
partial: AssistantMessage;
|
|
315
|
+
} | {
|
|
316
|
+
type: 'tool_call_end';
|
|
317
|
+
index: number;
|
|
318
|
+
toolCall: ToolCall;
|
|
319
|
+
partial: AssistantMessage;
|
|
320
|
+
} | {
|
|
321
|
+
type: 'done';
|
|
322
|
+
reason: StopReason;
|
|
323
|
+
message: AssistantMessage; /** 本轮成功响应解析出的供应商 usage 快照(仅 Anthropic OAuth 订阅计划非 null)。 */
|
|
324
|
+
providerUsage?: ProviderUsageSnapshot | null;
|
|
325
|
+
} | {
|
|
326
|
+
type: 'error';
|
|
327
|
+
error: Error;
|
|
328
|
+
}; //#endregion
|
|
329
|
+
//#region src/model.d.ts
|
|
330
|
+
/**
|
|
331
|
+
* 推理投入档(reasoning effort)——RFC-235 对齐 Claude Code 词表:`low/medium/high/xhigh/max`。
|
|
332
|
+
* 去除历史遗留的 `minimal`(无对应厂商语义,存量配置载入时迁移为 `low`),新增 `max`(Claude
|
|
333
|
+
* Code 最高档 + DeepSeek `reasoning_effort:'max'` 顶档)。各模型真实支持的子集由 manifest 的
|
|
334
|
+
* `Model.thinkingLevels` 声明,provider 组装请求体时按"≤该档最高支持档"降级(见 RFC-235 §3.3)。
|
|
335
|
+
*/
|
|
336
|
+
type ThinkingLevel = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
337
|
+
/**
|
|
338
|
+
* 模型能力优势标签(供大模型为 subagent 选型)。非 /models API 返回——由
|
|
339
|
+
* model-capabilities 据「精选家族图 + 启发式」推导。
|
|
340
|
+
* planning=方案/架构 · knowledge=知识/通识 · coding=编码 · reasoning=深度推理
|
|
341
|
+
* · vision=视觉 · speed=低延迟 · long-context=长上下文
|
|
342
|
+
*/
|
|
343
|
+
type ModelStrength = 'planning' | 'knowledge' | 'coding' | 'reasoning' | 'vision' | 'speed' | 'long-context';
|
|
344
|
+
interface Cost {
|
|
345
|
+
input: number;
|
|
346
|
+
output: number;
|
|
347
|
+
cacheRead: number;
|
|
348
|
+
cacheWrite: number;
|
|
349
|
+
}
|
|
350
|
+
interface Model<T = Api> {
|
|
351
|
+
id: string;
|
|
352
|
+
name: string;
|
|
353
|
+
api: T;
|
|
354
|
+
provider: Provider;
|
|
355
|
+
baseUrl: string;
|
|
356
|
+
reasoning: boolean;
|
|
357
|
+
input: ('text' | 'image')[];
|
|
358
|
+
/**
|
|
359
|
+
* 美元 / 百万 token 定价(终局修复:改为可选,不再强制归零)。三家主流供应商
|
|
360
|
+
* (Anthropic/OpenAI/GitHub Copilot,逐一核实过官方文档+SDK 源码)的 `/models` 列表接口
|
|
361
|
+
* 均不返回定价——这不是接口设计缺陷,是行业普遍现状:`/models` 回答"能用哪些模型",
|
|
362
|
+
* 定价只写在面向人类阅读的文档页(会随时间调整),没有供应商把它做成程序化查询接口。
|
|
363
|
+
* 缺省(`undefined`)= 该模型没有已知定价来源(如运行时从供应商接口动态发现的新型号),
|
|
364
|
+
* UI 层应据此不显示开销估算,而非显示误导性的 $0(用户可能误以为模型免费,实际正常计费)。
|
|
365
|
+
* 有值 = 人工核实过的真实历史定价(当前来自各插件 manifest 声明)。
|
|
366
|
+
*/
|
|
367
|
+
cost?: Cost;
|
|
368
|
+
contextWindow: number;
|
|
369
|
+
maxOutputTokens: number;
|
|
370
|
+
thinkingLevels?: ThinkingLevel[];
|
|
371
|
+
/**
|
|
372
|
+
* thinking 配置格式声明:
|
|
373
|
+
* - 'enabled'(缺省):标准 Anthropic `{ type: 'enabled', budget_tokens: N }`
|
|
374
|
+
* - 'adaptive':`{ type: 'adaptive' }` + 顶层 `output_config.effort`(部分网关要求此格式)
|
|
375
|
+
*/
|
|
376
|
+
thinkingMode?: 'enabled' | 'adaptive';
|
|
377
|
+
/** 能力优势标签(供 subagent 选型);由 model-capabilities 推导,非内置硬编码真源。 */
|
|
378
|
+
strengths?: ModelStrength[];
|
|
379
|
+
/**
|
|
380
|
+
* 图片约束声明(RFC-148 M5):单请求最大图片数 + 超阈值后的单图最大边长约束。
|
|
381
|
+
* 由插件 manifest 的模型条目声明(供应商专属约束,如 Anthropic 官方规则"单请求
|
|
382
|
+
* >maxImagesPerRequest 张图时单图任一边 > maxDimensionPxIfOverLimit 即 400",
|
|
383
|
+
* 见 `packages/agent/src/image-degradation.ts` 消费方)。缺省 = 无已知约束
|
|
384
|
+
* (引擎侧不主动截断,行为等价于约束不存在——不臆造保守默认值)。
|
|
385
|
+
*/
|
|
386
|
+
imageConstraints?: {
|
|
387
|
+
maxImagesPerRequest: number;
|
|
388
|
+
maxDimensionPxIfOverLimit?: number;
|
|
389
|
+
};
|
|
390
|
+
/**
|
|
391
|
+
* 工具调用支持声明(RFC-130 M131-2,同 `imageConstraints` 声明化模式):该模型/provider
|
|
392
|
+
* 是否支持客户端工具委托。缺省 `undefined` = 支持(向后兼容——绝大多数 provider 支持工具,
|
|
393
|
+
* 不臆造保守默认值破坏存量行为)。仅当 provider 协议层明确不支持工具委托时(如 Cursor
|
|
394
|
+
* agent API 只服务端自跑内置工具,M131-3-00b 已证伪双向映射可行性)声明 `false`,宿主
|
|
395
|
+
* (`session-config-resolver.ts`)据此剥离工具集,避免 provider 抛协议错误——引擎侧
|
|
396
|
+
* 只读布尔声明,不识别具体厂商字符串(终局判据,同 RFC-148 系列的 zero-vendor-knowledge
|
|
397
|
+
* 原则)。
|
|
398
|
+
*/
|
|
399
|
+
supportsTools?: boolean;
|
|
400
|
+
/**
|
|
401
|
+
* Responses API 请求体策略声明(RFC-213):供 `openai-responses` 协议实现按声明覆盖
|
|
402
|
+
* 标准请求体字段,替代此前失效的 `model.api === 'openai-codex-responses'` 字符串判断
|
|
403
|
+
* (RFC-122 provider 插件化迁移后该字面量已物理不可达,是死代码——见 RFC-213 背景的
|
|
404
|
+
* 逐层源码追溯)。缺省 = 标准行为(不设置 `store`、按
|
|
405
|
+
* `context.maxTokens ?? model.maxOutputTokens` 发送 `max_output_tokens`)。
|
|
406
|
+
*/
|
|
407
|
+
responseBodyPolicy?: {
|
|
408
|
+
/** 显式设置 body.store(如 ZDR 合规场景需要 false)。缺省不设置该字段(沿用 API 默认)。 */store?: boolean;
|
|
409
|
+
/**
|
|
410
|
+
* false = 不发送 max_output_tokens 字段。官方 `openai/codex` CLI 源码(`ResponsesApiRequest`
|
|
411
|
+
* 结构体)从不发送该字段(用 `reasoning`/`text` 控制输出),且社区证据(reasoning 模型
|
|
412
|
+
* 系列经 Responses API 收到该字段会被 400 拒绝)表明这不是可选的风格差异。缺省 true(发送)。
|
|
413
|
+
*/
|
|
414
|
+
sendMaxOutputTokens?: boolean;
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
//#endregion
|
|
418
|
+
//#region src/types.d.ts
|
|
419
|
+
type StreamFunction = (context: StreamContext, signal: AbortSignal) => AsyncIterable<StreamEvent> & {
|
|
420
|
+
result(): Promise<AssistantMessage>;
|
|
421
|
+
};
|
|
422
|
+
interface ToolDefinition<TArgs = unknown> {
|
|
423
|
+
name: string;
|
|
424
|
+
description: string;
|
|
425
|
+
parameters: ZodType<TArgs>;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* system prompt 的缓存稳定性分层段。仅用于 Anthropic 动态断点定位——
|
|
429
|
+
* provider 在「最后一个 stable 段」之后挂 cache_control,volatile 段照发但不进缓存前缀。
|
|
430
|
+
* content 的真相源仍是 StreamContext.systemPrompt(完整扁平串,供其它 provider 消费)。
|
|
431
|
+
*/
|
|
432
|
+
interface SystemPromptSegment {
|
|
433
|
+
text: string;
|
|
434
|
+
/** 'stable'(默认)=会话内冻结、进缓存前缀;'volatile'=每轮可变、落在断点之后。 */
|
|
435
|
+
cache?: 'stable' | 'volatile';
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* prompt cache 保留档(决定 Anthropic ephemeral 断点的 TTL):
|
|
439
|
+
* - 'none':不放任何缓存断点(一次性/eval 请求,省去缓存写开销);
|
|
440
|
+
* - 'short'(缺省语义):5 分钟 TTL;
|
|
441
|
+
* - 'long':1 小时 TTL(长会话——思考久/工具轮多/有交互空档时命中率更高)。
|
|
442
|
+
*/
|
|
443
|
+
type CacheRetention = 'none' | 'short' | 'long';
|
|
444
|
+
interface StreamContext {
|
|
445
|
+
model: Model;
|
|
446
|
+
/** 完整 system 文本(stable + volatile 已拼接)。所有 provider 的 content 真相源。 */
|
|
447
|
+
systemPrompt: string;
|
|
448
|
+
/**
|
|
449
|
+
* 可选的缓存分层视图。仅 Anthropic 据此动态放断点;省略时退化为单块尾部断点(旧行为)。
|
|
450
|
+
* 各段 text 拼接应等价于 systemPrompt。
|
|
451
|
+
*/
|
|
452
|
+
systemPromptSegments?: SystemPromptSegment[];
|
|
453
|
+
messages: Message[];
|
|
454
|
+
tools?: ToolDefinition[];
|
|
455
|
+
thinkingLevel?: ThinkingLevel;
|
|
456
|
+
maxTokens?: number;
|
|
457
|
+
temperature?: number;
|
|
458
|
+
cacheRetention?: CacheRetention;
|
|
459
|
+
}
|
|
460
|
+
interface StreamOptions {
|
|
461
|
+
signal?: AbortSignal;
|
|
462
|
+
timeout?: number;
|
|
463
|
+
/**
|
|
464
|
+
* SSE 流的**空闲**超时(毫秒,仅 stream()):每收到一个 chunk 重置;连续此 ms 内无任何
|
|
465
|
+
* 字节到达即 abort。与 `timeout`(整请求墙钟上限)不同——专治「连接活着但 provider
|
|
466
|
+
* 静默不再吐字节」的挂死。缺省 120s。
|
|
467
|
+
*
|
|
468
|
+
* RFC-XX reasoning-thinking:reasoning 模型(kimi-k3/GLM-5.2 等)的 thinking 阶段可
|
|
469
|
+
* 长达分钟级零 visible token——中间无任何 SSE chunk,默认 120s idle 会无差别单边坑
|
|
470
|
+
* 所有 reasoning 模型(实测 turn 3 触发:thinking_start → 零输出 → stream.retry×2 →
|
|
471
|
+
* 崩)。调用方应据此在转产 conversational function 具调用(work-loop 等里)显式加大。
|
|
472
|
+
*/
|
|
473
|
+
idleTimeout?: number;
|
|
474
|
+
}
|
|
475
|
+
interface ProviderStream {
|
|
476
|
+
readonly id: string;
|
|
477
|
+
readonly displayName: string;
|
|
478
|
+
/**
|
|
479
|
+
* 统一鉴权解析(RFC-140 D5):此前 4 个 provider 实现(当时在本包,RFC-148 M2 后
|
|
480
|
+
* anthropic-messages/openai-responses/openai-completions 已迁至
|
|
481
|
+
* extensions/plugin-otto-wire-protocols/src/,github-copilot 在
|
|
482
|
+
* extensions/plugin-github-copilot/src/provider.ts)各自的凭据解析签名各不相同——
|
|
483
|
+
* anthropic 是 `resolveAuthCredential(): Promise<ResolvedAuth>`(唯一带 mode/beta 的
|
|
484
|
+
* 完整版,未走接口声明的 `resolveKey`),其余三个各自实现
|
|
485
|
+
* `resolveKey(): Promise<string>` 但入参/来源不统一。新 provider 作者(含第三方代码式
|
|
486
|
+
* 插件)不知道该实现哪一个。统一为单一签名:`ResolvedAuth` 已含 token/mode/beta,语义
|
|
487
|
+
* 完整,解析失败时 reject(不返回 null——沿用各实现既有的 PROVIDER_AUTH_MISSING
|
|
488
|
+
* 错误纹理)。
|
|
489
|
+
*
|
|
490
|
+
* 可选(`?`)保留是因为 `ProviderRegistry`/`AuthStore` 侧的调用路径本就允许 provider
|
|
491
|
+
* 不声明鉴权解析(极少数场景,如未来的零凭据本地 provider);四个内置 wire 实现全部
|
|
492
|
+
* 实现该方法。
|
|
493
|
+
*/
|
|
494
|
+
resolveAuth?(model: Model): Promise<ResolvedAuth>;
|
|
495
|
+
converse(model: Model<Api>, context: StreamContext, options: StreamOptions, signal: AbortSignal): AsyncIterable<StreamEvent>;
|
|
496
|
+
/**
|
|
497
|
+
* 可选清理钩子(RFC-105 D2/评审 F8):卸载时释放 HTTP 连接池/流等资源。
|
|
498
|
+
* 内置 provider 目前均无持久资源,可不实现;插件 provider 卸载时
|
|
499
|
+
* `ProviderRegistry.unregisterBySource` 会调用(存在则调用)。
|
|
500
|
+
*/
|
|
501
|
+
dispose?(): void | Promise<void>;
|
|
502
|
+
}
|
|
503
|
+
type ProviderFactory = () => ProviderStream;
|
|
504
|
+
/**
|
|
505
|
+
* JWT claim 派生 header 配置(RFC-122 D3)。结构对齐 openai-responses/openai-completions
|
|
506
|
+
* 各自的同名本地定义——本类型仅供 `WireProtocolFactoryInput` 使用(RFC-148 新增的协议中立层
|
|
507
|
+
* 入口);两个协议实现随 RFC-148 M2 物理迁移至 extensions/plugin-otto-wire-protocols/src/。
|
|
508
|
+
*/
|
|
509
|
+
interface TokenDerivedHeader {
|
|
510
|
+
header: string;
|
|
511
|
+
source: {
|
|
512
|
+
kind: 'jwt-claim';
|
|
513
|
+
claim: string;
|
|
514
|
+
namespace?: string;
|
|
515
|
+
tokenSources?: Array<'id_token' | 'access_token'>;
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Wire 协议实现的注册契约(RFC-148 D1)——`@otto/ai` 的 `WireProtocolRegistry` 与
|
|
520
|
+
* `@otto/plugin` 的 `PluginModule.wireProtocols` 轴共用同一份类型定义,避免跨包重复。
|
|
521
|
+
* 定义在协议中立层(`@otto/provider`)而非 `@otto/ai`:两个消费方(宿主注册表 + 插件 SDK)
|
|
522
|
+
* 都已 type-only 依赖本包,符合既有 `AnthropicRequestCustomizeInput` 的分层先例。
|
|
523
|
+
*/
|
|
524
|
+
interface WireRequestCustomizeInput {
|
|
525
|
+
auth: {
|
|
526
|
+
mode: 'api_key' | 'oauth';
|
|
527
|
+
beta?: string;
|
|
528
|
+
};
|
|
529
|
+
sessionId: string;
|
|
530
|
+
}
|
|
531
|
+
/** 通用 system 文本块最小结构(`Anthropic.TextBlockParam` 的子集,SDK 无关,见 WireRequestCustomization.transformSystemBlocks)。 */
|
|
532
|
+
interface WireSystemTextBlock {
|
|
533
|
+
type: 'text';
|
|
534
|
+
text: string;
|
|
535
|
+
cache_control?: unknown;
|
|
536
|
+
}
|
|
537
|
+
interface WireRequestCustomization {
|
|
538
|
+
defaultHeaders?: Record<string, string>;
|
|
539
|
+
/** system 数组变换(如插入身份前缀块);非全部协议都支持——不支持的协议实现忽略该字段。 */
|
|
540
|
+
transformSystemBlocks?: (blocks: WireSystemTextBlock[] | undefined) => WireSystemTextBlock[] | undefined;
|
|
541
|
+
metadata?: Record<string, unknown>;
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* 插件侧协议实现的日志端口(RFC-185 D3)。宿主注入(走宿主进程的单一 pino 单例 →
|
|
545
|
+
* 日志总线/文件),插件源码**禁止**自建 `createLogger`——esbuild bundle 会把
|
|
546
|
+
* `@otto/shared` logger 整体复制成第二份单例,宿主的级别/通道控制够不着它,直写
|
|
547
|
+
* stderr 破坏 TUI(findings-backlog「2026-07-13 TUI 残影回归」根因环 2)。
|
|
548
|
+
* `debug` 档是宿主↔协议实现的内部约定(`PluginContext.logger` 对外仍是
|
|
549
|
+
* info/warn/error 三档 + 可选 debug)。
|
|
550
|
+
*/
|
|
551
|
+
interface WireProtocolLogger {
|
|
552
|
+
/** 首参兼容 pino 两种惯用形态:结构化对象(mergingObject)或格式化字符串。 */
|
|
553
|
+
debug: (objOrMsg: string | Record<string, unknown>, ...args: unknown[]) => void;
|
|
554
|
+
info: (objOrMsg: string | Record<string, unknown>, ...args: unknown[]) => void;
|
|
555
|
+
warn: (objOrMsg: string | Record<string, unknown>, ...args: unknown[]) => void;
|
|
556
|
+
error: (objOrMsg: string | Record<string, unknown>, ...args: unknown[]) => void;
|
|
557
|
+
}
|
|
558
|
+
interface WireProtocolFactoryInput {
|
|
559
|
+
resolveAuth: () => Promise<{
|
|
560
|
+
token: string;
|
|
561
|
+
mode: 'api_key' | 'oauth';
|
|
562
|
+
beta?: string;
|
|
563
|
+
} | undefined>;
|
|
564
|
+
resolveBaseUrl: () => Promise<string | undefined>;
|
|
565
|
+
headers?: Record<string, string>;
|
|
566
|
+
tokenDerivedHeaders?: TokenDerivedHeader[];
|
|
567
|
+
/** 请求定制点——厂商个性注入唯一通道(如 plugin-anthropic 的 Claude Code 伪装)。 */
|
|
568
|
+
customizeRequest?: (input: WireRequestCustomizeInput) => WireRequestCustomization;
|
|
569
|
+
/**
|
|
570
|
+
* RFC-270 D3:允许 manifest 静态头/JWT 派生头/拦截器覆盖鉴权头(`authorization`/`x-api-key`)。
|
|
571
|
+
* 缺省 `undefined` = 不允许(默认丢弃 + warn)——otto 的 manifest 可由第三方插件分发,
|
|
572
|
+
* 静默替换 Authorization 等于把用户凭据路由到任意端点。企业网关确需换鉴权时由 provider
|
|
573
|
+
* 在 manifest 显式声明 `allowAuthHeaderOverride: true`,装载期 warn 一条保证可审计。
|
|
574
|
+
*/
|
|
575
|
+
allowAuthHeaderOverride?: boolean;
|
|
576
|
+
sessionId?: string;
|
|
577
|
+
/**
|
|
578
|
+
* RFC-185 D3:宿主注入的日志端口。可选字段(向后兼容,不 bump PLUGIN_API_VERSION);
|
|
579
|
+
* 缺省时协议实现必须 fallback 到 no-op——绝不 fallback 到 createLogger(复活第二单例)。
|
|
580
|
+
*/
|
|
581
|
+
logger?: WireProtocolLogger;
|
|
582
|
+
}
|
|
583
|
+
/** 协议注册携带的能力元数据(RFC-147 B-1:替代 `CACHE_REPORTING_APIS` 硬编码白名单)。 */
|
|
584
|
+
interface WireProtocolMeta {
|
|
585
|
+
/** 该协议的 usage 是否携带 cache token 字段。缺省 = false(不上报)。 */
|
|
586
|
+
reportsCacheTokens?: boolean;
|
|
587
|
+
}
|
|
588
|
+
interface WireProtocolRegistration {
|
|
589
|
+
create: (input: WireProtocolFactoryInput) => ProviderStream;
|
|
590
|
+
meta?: WireProtocolMeta;
|
|
591
|
+
}
|
|
592
|
+
type OAuthCredentials = {
|
|
593
|
+
refresh: string;
|
|
594
|
+
access: string;
|
|
595
|
+
expires: number; /** GitHub Enterprise host(如 company.ghe.com);持久化以便后续刷新仍打到企业域而非默认 github.com。 */
|
|
596
|
+
domain?: string;
|
|
597
|
+
[key: string]: unknown;
|
|
598
|
+
};
|
|
599
|
+
type OAuthProviderId = string;
|
|
600
|
+
interface OAuthInfo {
|
|
601
|
+
url: string;
|
|
602
|
+
code?: string;
|
|
603
|
+
instructions?: string;
|
|
604
|
+
}
|
|
605
|
+
interface OAuthPrompt {
|
|
606
|
+
message: string;
|
|
607
|
+
placeholder?: string;
|
|
608
|
+
allowEmpty?: boolean;
|
|
609
|
+
}
|
|
610
|
+
interface OAuthLoginOptions {
|
|
611
|
+
onAuth: (info: OAuthInfo) => void;
|
|
612
|
+
onPrompt: (prompt: OAuthPrompt) => Promise<string>;
|
|
613
|
+
onProgress?: (message: string) => void;
|
|
614
|
+
/**
|
|
615
|
+
* 手动粘贴授权码兜底通道。`signal` 由 provider 在自动通道(loopback 回调)
|
|
616
|
+
* 先完成时触发——实现方应据此关闭粘贴输入框并 resolve 空串。
|
|
617
|
+
*/
|
|
618
|
+
onManualCode?: (signal?: AbortSignal) => Promise<string>;
|
|
619
|
+
signal?: AbortSignal;
|
|
620
|
+
}
|
|
621
|
+
interface OAuthRefreshTokenOptions extends OAuthCredentials {
|
|
622
|
+
domain?: string;
|
|
623
|
+
}
|
|
624
|
+
interface OAuthProvider {
|
|
625
|
+
readonly id: OAuthProviderId;
|
|
626
|
+
readonly name: string;
|
|
627
|
+
usesCallbackServer?: boolean;
|
|
628
|
+
/**
|
|
629
|
+
* 以 OAuth token 调用对应 API 时必带的 beta 头(如 Anthropic 的 `oauth-2025-04-20`)。
|
|
630
|
+
* provider 据此在 oauth 模式下附加 `anthropic-beta`(M8-04/05)。
|
|
631
|
+
*/
|
|
632
|
+
readonly oauthBeta?: string;
|
|
633
|
+
/**
|
|
634
|
+
* 此 OAuth 令牌是否绑定到某个**产品订阅**(如 Anthropic 的 Claude Code 订阅 token
|
|
635
|
+
* `sk-ant-oat`)。这类令牌在用于该产品自身 system prompt 之外的请求时会被服务端限流
|
|
636
|
+
* (HTTP 429),因此**不适合**用作 subagent 委派的可用模型来源(RFC-061 §3 D2)。
|
|
637
|
+
* 由 usability gate(`@otto/ai/model-usability`)消费;供 api_key 凭证不受此影响——
|
|
638
|
+
* provider 一旦持有真 API key,`getAuthSource` 返回 `api_key`,此标志即不被查询。
|
|
639
|
+
*/
|
|
640
|
+
readonly subscriptionScoped?: boolean;
|
|
641
|
+
login(options: OAuthLoginOptions): Promise<OAuthCredentials>;
|
|
642
|
+
refreshToken(options: OAuthRefreshTokenOptions): Promise<OAuthCredentials>;
|
|
643
|
+
getAccessKey(credentials: OAuthCredentials): string;
|
|
644
|
+
}
|
|
645
|
+
type OAuthProviderFactory = () => OAuthProvider;
|
|
646
|
+
type AuthMode = 'api_key' | 'oauth';
|
|
647
|
+
interface ResolvedAuth {
|
|
648
|
+
/** 实际用于鉴权的令牌(API key 或 OAuth access token)。 */
|
|
649
|
+
token: string;
|
|
650
|
+
/** 鉴权模式。 */
|
|
651
|
+
mode: AuthMode;
|
|
652
|
+
/** OAuth 模式下需附带的 beta 头(来源于 OAuthProvider.oauthBeta)。 */
|
|
653
|
+
beta?: string;
|
|
654
|
+
}
|
|
655
|
+
//#endregion
|
|
656
|
+
//#region src/provider/chat-completions.d.ts
|
|
657
|
+
declare function buildChatCompletionsMessages(context: StreamContext): unknown[];
|
|
658
|
+
declare function buildChatCompletionsBody(model: Model, context: StreamContext, opts?: {
|
|
659
|
+
modelName?: string;
|
|
660
|
+
}): Record<string, unknown>;
|
|
661
|
+
//#endregion
|
|
662
|
+
//#region src/provider/thinking-effort.d.ts
|
|
663
|
+
/**
|
|
664
|
+
* 把用户请求的档位降级到模型真实支持的档位子集里"≤请求档的最高档"。
|
|
665
|
+
*
|
|
666
|
+
* - `supported` 未声明/为空 → 原样返回 `requested`(无约束,向后兼容:模型没声明支持集时
|
|
667
|
+
* 不主动改写用户意图,交给协议翻译表兜底)。
|
|
668
|
+
* - `requested` 已在 `supported` 里 → 原样返回。
|
|
669
|
+
* - 否则返回 `supported` 中 order ≤ requested 的最高档;若没有更低的支持档(如模型只支持
|
|
670
|
+
* `max` 而用户选 `low`),返回 `supported` 中的最低档(不臆造更低值)。
|
|
671
|
+
*/
|
|
672
|
+
declare function clampThinkingLevel(requested: ThinkingLevel, supported: readonly ThinkingLevel[] | undefined): ThinkingLevel;
|
|
673
|
+
//#endregion
|
|
674
|
+
//#region src/provider/chat-completions-stream.d.ts
|
|
675
|
+
/**
|
|
676
|
+
* chat-completions-stream.ts — OpenAI Chat-Completions 兼容 SSE 流的单一实现(RFC-074 R-AICHAT)。
|
|
677
|
+
*
|
|
678
|
+
* openai-completions 与 github-copilot 此前各自维护一份 ~95% 相同的 SSE 解析循环且已漂移
|
|
679
|
+
* (finish_reason 映射、`!delta` 早返位置不一致 → B5 类 bug)。本模块收敛为唯一发射器:
|
|
680
|
+
* 各 provider 只提供 url/headers/body 与消息身份(api/provider/model),循环逻辑只此一处。
|
|
681
|
+
*/
|
|
682
|
+
/** finish_reason → StopReason 的单一映射(取代两份漂移的 switch)。未知值兜底 end_turn 并告警。 */
|
|
683
|
+
declare function mapChatFinishReason(reason: string): StopReason;
|
|
684
|
+
interface ChatCompletionsStreamParams {
|
|
685
|
+
url: string;
|
|
686
|
+
headers: Record<string, string>;
|
|
687
|
+
body: Record<string, unknown>;
|
|
688
|
+
/** 组装 partial/最终 AssistantMessage 的身份(各 provider 不同)。 */
|
|
689
|
+
identity: {
|
|
690
|
+
api: Api;
|
|
691
|
+
provider: Provider;
|
|
692
|
+
model: string;
|
|
693
|
+
};
|
|
694
|
+
signal: AbortSignal;
|
|
695
|
+
timeout?: number;
|
|
696
|
+
/**
|
|
697
|
+
* SSE **空闲**超时(毫秒)——每收到一个 chunk 重置;连续此 ms 无字节即 abort。
|
|
698
|
+
* 缺省 120s。对 reasoning 模型(thinking 阶段可能长达分钟级零 visible token)应加大。
|
|
699
|
+
*/
|
|
700
|
+
idleTimeout?: number;
|
|
701
|
+
/**
|
|
702
|
+
* 可选旁路回调(RFC-140 D5):SSE 建流成功后同步收到响应 Headers,供调用方做额外的
|
|
703
|
+
* 旁路观测(如日志/埋点)。`streamChatCompletions` 自身**始终**内部捕获响应头并通过
|
|
704
|
+
* `extractStandardRateLimitHeaders` 计算标准 `x-ratelimit-*` 限流快照,随 `done`
|
|
705
|
+
* 事件的 `providerUsage` 字段透出——此前 chat-completions 形(copilot/openai-completions/
|
|
706
|
+
* deepseek)走本函数但从未暴露响应头,用户在这些 provider 下永远看不到任何 usage 信息,
|
|
707
|
+
* 现已零调用方改动自动闭合(`extractStandardRateLimitHeaders` 对非 OpenAI 厂商的
|
|
708
|
+
* 兼容响应头一样适用——它只解析标准 `x-ratelimit-*` 头族,无厂商专属逻辑)。
|
|
709
|
+
*/
|
|
710
|
+
onResponse?: (headers: Headers) => void;
|
|
711
|
+
/**
|
|
712
|
+
* RFC-232(终局修正):已注册工具名集合,供 `recoverLiteralInvokeToolCalls` 在 `done`
|
|
713
|
+
* 事件前救回"模型把工具调用写成字面文本 XML"的违约响应(见 stream-state.ts 头注释)。
|
|
714
|
+
* 可选字段——未传入(如历史调用方/replay-provider 快照重放)时该救回步骤原样跳过
|
|
715
|
+
* (registeredToolNames(undefined) 派生空集合,函数内部白名单校验天然不命中,零行为
|
|
716
|
+
* 变化,向后兼容)。
|
|
717
|
+
*/
|
|
718
|
+
registeredToolNames?: ReadonlySet<string>;
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* 驱动一条 Chat-Completions SSE 流,产出标准 StreamEvent 序列
|
|
722
|
+
* (start → text/thinking/tool_call 的 start/delta/end → done;异常 → error)。
|
|
723
|
+
*/
|
|
724
|
+
declare function streamChatCompletions(params: ChatCompletionsStreamParams): AsyncIterable<StreamEvent>;
|
|
725
|
+
//#endregion
|
|
726
|
+
//#region src/provider/sanitize-tool-roundtrips.d.ts
|
|
727
|
+
/**
|
|
728
|
+
* Provider 无关的工具往返配对修复——这条不变量的单一真源。
|
|
729
|
+
*
|
|
730
|
+
* OpenAI/DeepSeek/Anthropic 等聊天线协议都要求:每条工具结果必须应答前一条 assistant
|
|
731
|
+
* 宣告的 tool_call,且每个 tool_call 必须被应答,否则 400(例如 DeepSeek 的
|
|
732
|
+
* "Messages with role 'tool' must be a response to a preceding message with 'tool_calls'")。
|
|
733
|
+
* 会话历史在 abort、流式解析丢块、非压缩硬截断等路径下可能产生:
|
|
734
|
+
* - 孤儿 tool_result——toolCallId 指向的 assistant tool_call 已不在窗口内;
|
|
735
|
+
* - 悬空 tool_call——assistant 宣告了工具调用但其结果被丢。
|
|
736
|
+
* 把这种序列直接发给 provider 就会 400。各 provider 在构建自己的线格式前先过本函数归一。
|
|
737
|
+
*
|
|
738
|
+
* 修复策略:
|
|
739
|
+
* - 丢弃孤儿 tool_result(toolCallId 不在前驱 assistant 的 tool_call 集合中)。
|
|
740
|
+
* - 为悬空 tool_call 合成占位 tool_result(isError=true),插在下一条 user/assistant 之前。
|
|
741
|
+
* - 任一修复触发都打 warn——这是兜底,但必须发声;否则它会静默掩盖"上游为什么产生
|
|
742
|
+
* 无效序列"的真正 bug。真出问题时,warn 里的 toolCallId 是定位上游来源的唯一线索。
|
|
743
|
+
*
|
|
744
|
+
* 幂等:已配对的输入原样返回(无 warn)。
|
|
745
|
+
*/
|
|
746
|
+
declare function sanitizeToolRoundtrips(messages: Message[]): Message[];
|
|
747
|
+
/**
|
|
748
|
+
* RFC-144 M2:system_notification 消息的降级序列化文本——不支持原生 mid-conversation
|
|
749
|
+
* system message 的 provider/模型统一走 `role:'user'` + 本前缀(决策 1 已述权衡:牺牲
|
|
750
|
+
* "运营方权威"语义,保留基本可用性)。Provider 无关的单一真源,供
|
|
751
|
+
* extensions/plugin-otto-wire-protocols 的 anthropic-messages/openai-responses 与本包
|
|
752
|
+
* chat-completions.ts 三处共同导入复用(不各自重复定义)。
|
|
753
|
+
*/
|
|
754
|
+
declare function degradedSystemNotificationText(content: string): string;
|
|
755
|
+
/**
|
|
756
|
+
* RFC-144 M2 遗留 bug 修复(2026-07 真机日志核实):Anthropic 官方文档明确写明
|
|
757
|
+
* "Consecutive system messages are not allowed; merge instructions into one message or
|
|
758
|
+
* wait for the next user turn before appending"(docs.anthropic.com/en/docs/build-with-
|
|
759
|
+
* claude/mid-conversation-system-messages)——原设计"多个 lifecycleAsync 工具同时完成时
|
|
760
|
+
* 按完成顺序追加多条 system 消息,不合并"直接违反该硬约束,会被 Anthropic 400 拒绝
|
|
761
|
+
* (原实现只把 `assertSystemNotificationPlacement` 的 successor 检查限定"必须是末尾或紧
|
|
762
|
+
* 跟 assistant",从未检查过"两条 system_notification 相邻"这一违规本身,只告警不修复)。
|
|
763
|
+
*
|
|
764
|
+
* 本函数在原生 mid-conversation system message 序列化前合并相邻的
|
|
765
|
+
* `system_notification` 消息为一条(content 用换行拼接、isError 取任一为真、
|
|
766
|
+
* relatedToolCallId 保留首条——仅供审计溯源,非强约束)。仅原生路径需要(降级路径每条
|
|
767
|
+
* system_notification 各自变成独立 `role:'user'` 消息,Anthropic 对连续 user 消息无此
|
|
768
|
+
* 限制,不需要合并)。
|
|
769
|
+
*/
|
|
770
|
+
declare function mergeConsecutiveSystemNotifications(messages: Message[]): Message[];
|
|
771
|
+
/**
|
|
772
|
+
* RFC-144 M2:mid-conversation system message 放置规则断言——Provider 无关的共享检查。
|
|
773
|
+
*
|
|
774
|
+
* Anthropic 官方约束(docs.anthropic.com/en/docs/build-with-claude/
|
|
775
|
+
* mid-conversation-system-messages):`system` 消息必须紧跟在携带 tool_result 的 user
|
|
776
|
+
* turn 之后(或以 server tool use 结尾的 assistant turn 之后),且必须是 messages 数组
|
|
777
|
+
* 最后一条或紧跟一个 assistant turn;不能插在 assistant tool_use 与其 tool_result 之间。
|
|
778
|
+
*
|
|
779
|
+
* **层次纠正(独立评审发现,2026-07-11)**:原实现检查 `prev.role === 'user'`——这是错的。
|
|
780
|
+
* Anthropic 的规则是对**序列化后的 wire 格式**而言("user turn carrying tool_result
|
|
781
|
+
* blocks"),而 otto 内部消息模型里 `tool_result` 是独立的顶层 role(非嵌入 user 消息内)。
|
|
782
|
+
* `buildAnthropicMessages`(extensions/plugin-otto-wire-protocols/src/anthropic-messages.ts)
|
|
783
|
+
* 把 otto 的 `role:'tool_result'` 序列化为
|
|
784
|
+
* Anthropic wire 的 `{role:'user', content:[{type:'tool_result',...}]}`——这才是规则里
|
|
785
|
+
* "携带 tool_result 的 user turn"。otto 内部的纯文本 `role:'user'` 消息序列化后同样是
|
|
786
|
+
* wire `role:'user'`,但**不携带 tool_result block**,理论上不满足严格放置规则(真实运行
|
|
787
|
+
* 路径中不会发生——system_notification 只在 work-loop.ts 的 lifecycleAsync 完成回调里追加,
|
|
788
|
+
* 其直接前驱恒为本轮已推入的 tool_result(占位符或其他同轮工具结果)或 assistant——但
|
|
789
|
+
* 断言的检查目标必须是 otto 内部层的真实等价物,不能对 wire 层描述做字面照抄)。
|
|
790
|
+
*
|
|
791
|
+
* 因此本函数检查 `prev.role === 'tool_result' || prev.role === 'assistant'`(otto 内部
|
|
792
|
+
* role),而非 `'user'`——`tool_result` 是唯一序列化后携带 tool_result block 的内部角色。
|
|
793
|
+
*
|
|
794
|
+
* 本仓的追加时机(work-loop.ts 的 runTools 内,工具 promise resolve 时 push)天然满足
|
|
795
|
+
* 该约束——落库固定发生在下一次 runTurn 前的静默期,不会插在 tool_use↔tool_result 之间。
|
|
796
|
+
* 本函数是**防御性断言**(RFC-144 M2 TODO 拆解要求):不满足则告警但不阻断请求(宁可
|
|
797
|
+
* 尝试失败被 provider 拒绝并记录,也不能静默丢弃工具完成通知,见 RFC-144 M2 TODO 拆解原文)。
|
|
798
|
+
*
|
|
799
|
+
* 同时检查后继约束(Anthropic 规则的第二半):`system_notification` 必须是数组末尾,
|
|
800
|
+
* 或紧跟一个 assistant turn——否则同样告警不阻断。
|
|
801
|
+
*
|
|
802
|
+
* 检查数组内**每一条** `system_notification` 消息(而非仅末尾)——每条都需独立满足放置约束。
|
|
803
|
+
*
|
|
804
|
+
* 2026-07 修正:一轮 `runTools` 可能有多个 lifecycleAsync 工具先后完成、在持久数组里连续
|
|
805
|
+
* 追加多条通知消息,但 Anthropic 官方文档明确写明 "Consecutive system messages are not
|
|
806
|
+
* allowed"——原 M2 TODO 拆解"不合并、每条独立追加"的设计违反该约束,会被真实 API 拒绝
|
|
807
|
+
* (非仅本函数的告警误报)。现原生路径在调用本函数前先经 `mergeConsecutiveSystemNotifications`
|
|
808
|
+
* 合并相邻通知(见 extensions/plugin-otto-wire-protocols 的 `buildAnthropicMessages`),
|
|
809
|
+
* 故本函数运行时**不会再遇到**两条相邻
|
|
810
|
+
* `system_notification` 的输入——但检查逻辑本身保留(防御纵深:万一未来有调用方跳过合并
|
|
811
|
+
* 直接调用本函数,仍能捕获该违规并告警)。
|
|
812
|
+
*/
|
|
813
|
+
declare function assertSystemNotificationPlacement(messages: readonly Message[]): void;
|
|
814
|
+
//#endregion
|
|
815
|
+
//#region src/provider/stream-state.d.ts
|
|
816
|
+
/**
|
|
817
|
+
* 公共流式状态机基座(M7-05)。
|
|
818
|
+
*
|
|
819
|
+
* 4 个 provider(anthropic / github-copilot / openai-completions / openai-responses)
|
|
820
|
+
* 此前各持一份「累积态 + buildAssistantMessage」,此处收敛出"累积 → AssistantMessage"的
|
|
821
|
+
* 共同语义(扁平累积/块累积两种形态 + 半截 JSON 容忍解析 + usage 计数 + 末段组装)。
|
|
822
|
+
* RFC-148 M2 后 anthropic-messages/openai-responses 已物理迁至
|
|
823
|
+
* extensions/plugin-otto-wire-protocols/src/(各自内联累积逻辑,不再引用本文件);本文件当前
|
|
824
|
+
* 唯一真实消费方是同包 `chat-completions.ts`(Chat Completions 扁平累积形,供
|
|
825
|
+
* openai-completions 与 github-copilot 复用)。
|
|
826
|
+
*/
|
|
827
|
+
type AssistantContent = (TextContent | ThinkingContent | ToolCall)[];
|
|
828
|
+
interface StreamUsage {
|
|
829
|
+
inputTokens: number;
|
|
830
|
+
outputTokens: number;
|
|
831
|
+
cacheReadTokens: number;
|
|
832
|
+
cacheWriteTokens: number;
|
|
833
|
+
}
|
|
834
|
+
declare function initStreamUsage(): StreamUsage;
|
|
835
|
+
/**
|
|
836
|
+
* 流式工具参数 JSON 解析(RFC-142 D4 修订)。
|
|
837
|
+
*
|
|
838
|
+
* 旧行为:解析失败静默返回 `{}`——半截 JSON(max_tokens 截断)产出的空参数流到
|
|
839
|
+
* zod 层报出与上下文污染类错误(RFC-142 事故)同文案的 `Invalid arguments`,两个
|
|
840
|
+
* 根因正交的问题共享同一错误表象,诊断成本极高。
|
|
841
|
+
*
|
|
842
|
+
* 新行为:返回显式解析状态。**必须区分"合法空对象 `{}`"与"解析失败返回的 `{}`"**
|
|
843
|
+
* (RFC-142 重要事项规则9)——仅凭 arguments 为空判断会误伤真实的无参工具调用。
|
|
844
|
+
* 消费方据 `parseFailed` 在 ToolCall 上置 `argumentsParseFailed` 进程内标记,
|
|
845
|
+
* runtime 责任链(handleMaxTokensWithBrokenToolCall)拦截转为明确错误 tool_result。
|
|
846
|
+
*/
|
|
847
|
+
declare function parseToolArgumentsWithStatus(json: string, toolName?: string): {
|
|
848
|
+
args: Record<string, unknown>;
|
|
849
|
+
parseFailed: boolean;
|
|
850
|
+
};
|
|
851
|
+
declare function parseToolArguments(json: string, toolName?: string): Record<string, unknown>;
|
|
852
|
+
/** 从解析状态构造 ToolCall(parseFailed 时附加进程内标记,序列化发给模型前天然剥除)。 */
|
|
853
|
+
/** 从 `StreamContext.tools`(`ToolDefinition[] | undefined`)派生名字集合——4 个 wire 协议
|
|
854
|
+
* 实现调用 `recoverLiteralInvokeToolCalls` 前的共同准备步骤,避免各自重复映射。 */
|
|
855
|
+
declare function registeredToolNames(tools: readonly ToolDefinition[] | undefined): ReadonlySet<string>;
|
|
856
|
+
declare function toolCallFromParsed(id: string, name: string, argumentsJson: string): ToolCall;
|
|
857
|
+
/**
|
|
858
|
+
* RFC-232(终局修正,2026-07-25):跨 wire 协议救回"模型把工具调用写成字面文本 XML"的
|
|
859
|
+
* 违约响应(`<invoke name="X"><parameter name="Y">Z</parameter>...</invoke>`,事故会话
|
|
860
|
+
* f9bab4c0 复现 8+ 次)。
|
|
861
|
+
*
|
|
862
|
+
* **为何是协议中立公共函数,不下沉到单个 provider 插件**:复现证据显示该行为跨两个完全
|
|
863
|
+
* 不同的 wire 协议(anthropic-messages 的 Claude Opus 4.8、openai-completions 的 GLM-5.2)
|
|
864
|
+
* ——多个厂商/协议出现同一种字面量格式,是模型侧对 Claude 系工具调用 XML 语法(早期/部分
|
|
865
|
+
* 微调格式)的训练残留泄漏,不是任一协议解析器的 bug,也不是任一厂商的专属怪癖。凡跨
|
|
866
|
+
* provider 相似的行为都是公共逻辑,不应重复放进每个 provider 插件各自声明一遍(会导致
|
|
867
|
+
* 声明式插件——如本仓 plugin-oxygen 纯 manifest 无代码——完全没有地方挂这类修正)。
|
|
868
|
+
* 修复层级必须匹配问题层级:`@otto/provider` 是全部 4 个 wire 协议实现
|
|
869
|
+
* (anthropic-messages/openai-responses/chat-completions-stream[openai-completions+
|
|
870
|
+
* copilot+deepseek]/cursor)共同依赖的协议中立层,本函数是它们组装 `done` 事件 message
|
|
871
|
+
* 前的对称接入点——一次实现、全协议生效。
|
|
872
|
+
*
|
|
873
|
+
* **判据**(不依赖 stopReason,provider-agnostic):content 内最后一个 text block 的
|
|
874
|
+
* 文本(trimEnd 后)以结构完整的 `<invoke name="X">...</invoke>` 块收尾(允许内部任意个
|
|
875
|
+
* `<parameter name="Y">Z</parameter>` 子块),且 X 在调用方传入的已注册工具名集合内。
|
|
876
|
+
* 8 条真实复现样本 100% 符合"消息以裸露 XML 块收尾"(非讨论引用中间提及诸如"应该调用
|
|
877
|
+
* edit 工具"这类正常文本),白名单排除模型讨论不存在工具名的误伤(如虚构/占位工具名)。
|
|
878
|
+
*
|
|
879
|
+
* **救回而非仅报错**:解析成功时把提取的调用追加为 `tool_call` content block(原 text
|
|
880
|
+
* block 保留但截掉尾部的 XML 片段,避免同一调用同时以文本和结构化两种形式重复出现在
|
|
881
|
+
* 上下文里),使消费方 `hasToolCalls()` 变为 true,走正常工具执行路径而非兜底重试——
|
|
882
|
+
* 零额外轮次、模型/wire 协议切换均不受影响。
|
|
883
|
+
*
|
|
884
|
+
* 不满足判据(无 XML、工具名不在白名单、XML 结构不完整)→ 原样返回 message,不做任何
|
|
885
|
+
* 修改;判据不满足时的兜底(重试/终止)由引擎层 `handleToolCallProtocolMismatch`
|
|
886
|
+
* (`@otto/agent` work-loop-turn-outcome.ts,RFC-232 D1)接管——两层纵深防御。
|
|
887
|
+
*/
|
|
888
|
+
declare function recoverLiteralInvokeToolCalls(message: AssistantMessage, registeredToolNames: ReadonlySet<string>): AssistantMessage;
|
|
889
|
+
/**
|
|
890
|
+
* 检测文本是否以完整闭合的 `<invoke name="X">...</invoke>` 块收尾并提取参数。
|
|
891
|
+
* 不满足(无匹配、工具名不在白名单)返回 null。协议/厂商无关的纯字符串解析,无 I/O。
|
|
892
|
+
*/
|
|
893
|
+
/**
|
|
894
|
+
* 检测文本是否以完整闭合的 `<invoke name="X">...</invoke>` 块收尾(不提取参数,纯判定)。
|
|
895
|
+
* 供引擎层次级兜底复用同一判据(`@otto/agent` work-loop-turn-outcome.ts 的
|
|
896
|
+
* `handleToolCallProtocolMismatch`,RFC-232 D1)——wire 层 `recoverLiteralInvokeToolCalls`
|
|
897
|
+
* 救回失败(XML 不完整/工具名不在白名单)时的残留违约态,由引擎层注入纠正提示重试。
|
|
898
|
+
*/
|
|
899
|
+
declare function hasTrailingInvokeXml(text: string, registeredToolNames: ReadonlySet<string>): boolean;
|
|
900
|
+
interface FlatToolCallAcc {
|
|
901
|
+
id: string;
|
|
902
|
+
name: string;
|
|
903
|
+
argumentsJson: string;
|
|
904
|
+
}
|
|
905
|
+
interface FlatStreamState extends StreamUsage {
|
|
906
|
+
textContent: string;
|
|
907
|
+
thinkingText: string;
|
|
908
|
+
toolCalls: Map<number, FlatToolCallAcc>;
|
|
909
|
+
stopReason: StopReason;
|
|
910
|
+
}
|
|
911
|
+
declare function initFlatStreamState(): FlatStreamState;
|
|
912
|
+
declare function flatContent(state: FlatStreamState, final?: boolean): AssistantContent;
|
|
913
|
+
type StreamBlock = {
|
|
914
|
+
kind: 'text';
|
|
915
|
+
text: string;
|
|
916
|
+
} | {
|
|
917
|
+
kind: 'thinking';
|
|
918
|
+
text: string;
|
|
919
|
+
signature?: string;
|
|
920
|
+
} | {
|
|
921
|
+
kind: 'tool_call';
|
|
922
|
+
id: string;
|
|
923
|
+
name: string;
|
|
924
|
+
argumentsJson: string;
|
|
925
|
+
};
|
|
926
|
+
declare function blocksContent(blocks: Map<number, StreamBlock>, final?: boolean): AssistantContent;
|
|
927
|
+
interface AssistantMessageMeta {
|
|
928
|
+
api: Api;
|
|
929
|
+
provider: Provider;
|
|
930
|
+
model: string;
|
|
931
|
+
}
|
|
932
|
+
declare function assembleAssistantMessage(meta: AssistantMessageMeta, content: AssistantContent, usage: StreamUsage, stopReason: StopReason): AssistantMessage;
|
|
933
|
+
//#endregion
|
|
934
|
+
//#region src/provider/encoding.d.ts
|
|
935
|
+
/**
|
|
936
|
+
* Provider 载荷编码工具——多个 provider 在构造请求体时共用的纯函数。
|
|
937
|
+
*
|
|
938
|
+
* 收敛镜像债:sanitizeSurrogates / toJsonSchema 原先在 chat-completions 与
|
|
939
|
+
* openai-responses 各抄一份(字节一致),统一为单源以防分叉漂移。
|
|
940
|
+
*/
|
|
941
|
+
/**
|
|
942
|
+
* 将落单的 UTF-16 代理项(lone surrogate)替换为 U+FFFD。
|
|
943
|
+
*
|
|
944
|
+
* JSON 序列化前必须做:模型流式输出可能在多字节字符中途切片,留下落单高/低代理,
|
|
945
|
+
* 直接 `JSON.stringify` 会产出非法 UTF-8 被服务端 400 拒。
|
|
946
|
+
*/
|
|
947
|
+
declare function sanitizeSurrogates(text: string): string;
|
|
948
|
+
/** 把带可选 `toJSONSchema()` 的 schema 对象转为 JSON Schema;无该方法时退回空对象。 */
|
|
949
|
+
declare function toJsonSchema(schema: {
|
|
950
|
+
toJSONSchema?: () => unknown;
|
|
951
|
+
}): unknown;
|
|
952
|
+
//#endregion
|
|
953
|
+
//#region src/request-headers.d.ts
|
|
954
|
+
interface RequestHeaderSources {
|
|
955
|
+
/** ① 协议实现自身的默认头。 */
|
|
956
|
+
protocolDefaults?: Record<string, string>;
|
|
957
|
+
/** ② manifest 声明的静态头(`PluginProviderEntry.headers`)。 */
|
|
958
|
+
staticHeaders?: Record<string, string>;
|
|
959
|
+
/** ③ JWT claim 派生头(RFC-122 D3)。`token` 为待扫描的凭据。 */
|
|
960
|
+
tokenDerived?: {
|
|
961
|
+
headers: readonly TokenDerivedHeader[];
|
|
962
|
+
token: string;
|
|
963
|
+
};
|
|
964
|
+
/** ④ 程序化拦截器产出(`WireRequestCustomization.defaultHeaders`)。 */
|
|
965
|
+
customized?: Record<string, string>;
|
|
966
|
+
/**
|
|
967
|
+
* ⑤ 鉴权头。**裸 fetch 协议**传入(write-last 形态);**SDK 托管协议**省略
|
|
968
|
+
* (filter-output 形态,鉴权由 SDK 构造参数承担)。两种形态下 ②③④ 的鉴权族过滤都照常执行。
|
|
969
|
+
*/
|
|
970
|
+
auth?: Record<string, string>;
|
|
971
|
+
/**
|
|
972
|
+
* RFC-270 D3 逃生口:manifest 显式声明 `allowAuthHeaderOverride: true` 后,
|
|
973
|
+
* 允许 ②③④ 覆盖鉴权族头(企业网关换鉴权的真实场景),装载期与此处各 warn 一条(可审计)。
|
|
974
|
+
*/
|
|
975
|
+
allowAuthHeaderOverride?: boolean;
|
|
976
|
+
/** 诊断日志端口(缺省静默)。 */
|
|
977
|
+
logger?: WireProtocolLogger;
|
|
978
|
+
/** 日志上下文标识(provider id / 协议名),仅用于 warn 文案定位。 */
|
|
979
|
+
diagnosticLabel?: string;
|
|
980
|
+
}
|
|
981
|
+
/**
|
|
982
|
+
* 按五档优先级合并出站请求头,统一消毒并保护鉴权族头。
|
|
983
|
+
*
|
|
984
|
+
* @returns 最终请求头(键为各来源书写的原始大小写;内部按小写判定覆盖,HTTP 头名大小写不敏感)
|
|
985
|
+
*/
|
|
986
|
+
declare function buildRequestHeaders(sources: RequestHeaderSources): Record<string, string>;
|
|
987
|
+
//#endregion
|
|
988
|
+
//#region ../../node_modules/.pnpm/undici@8.7.0/node_modules/undici/types/utility.d.ts
|
|
989
|
+
type AutocompletePrimitiveBaseType<T> = T extends string ? string : T extends number ? number : T extends boolean ? boolean : never;
|
|
990
|
+
type Autocomplete<T> = T | (AutocompletePrimitiveBaseType<T> & Record<never, never>);
|
|
991
|
+
//#endregion
|
|
992
|
+
//#region ../../node_modules/.pnpm/undici@8.7.0/node_modules/undici/types/header.d.ts
|
|
993
|
+
/**
|
|
994
|
+
* The header type declaration of `undici`.
|
|
995
|
+
*/
|
|
996
|
+
type IncomingHttpHeaders = Record<string, string | string[] | undefined>;
|
|
997
|
+
/**
|
|
998
|
+
* The header type declaration of `undici` for outgoing requests.
|
|
999
|
+
*/
|
|
1000
|
+
type OutgoingHttpHeaders = Record<string, number | string | string[] | undefined>;
|
|
1001
|
+
type HeaderNames = Autocomplete<'Accept' | 'Accept-CH' | 'Accept-Charset' | 'Accept-Encoding' | 'Accept-Language' | 'Accept-Patch' | 'Accept-Post' | 'Accept-Ranges' | 'Access-Control-Allow-Credentials' | 'Access-Control-Allow-Headers' | 'Access-Control-Allow-Methods' | 'Access-Control-Allow-Origin' | 'Access-Control-Expose-Headers' | 'Access-Control-Max-Age' | 'Access-Control-Request-Headers' | 'Access-Control-Request-Method' | 'Age' | 'Allow' | 'Alt-Svc' | 'Alt-Used' | 'Authorization' | 'Cache-Control' | 'Clear-Site-Data' | 'Connection' | 'Content-Disposition' | 'Content-Encoding' | 'Content-Language' | 'Content-Length' | 'Content-Location' | 'Content-Range' | 'Content-Security-Policy' | 'Content-Security-Policy-Report-Only' | 'Content-Type' | 'Cookie' | 'Cross-Origin-Embedder-Policy' | 'Cross-Origin-Opener-Policy' | 'Cross-Origin-Resource-Policy' | 'Date' | 'Device-Memory' | 'ETag' | 'Expect' | 'Expect-CT' | 'Expires' | 'Forwarded' | 'From' | 'Host' | 'If-Match' | 'If-Modified-Since' | 'If-None-Match' | 'If-Range' | 'If-Unmodified-Since' | 'Keep-Alive' | 'Last-Modified' | 'Link' | 'Location' | 'Max-Forwards' | 'Origin' | 'Permissions-Policy' | 'Priority' | 'Proxy-Authenticate' | 'Proxy-Authorization' | 'Range' | 'Referer' | 'Referrer-Policy' | 'Retry-After' | 'Sec-Fetch-Dest' | 'Sec-Fetch-Mode' | 'Sec-Fetch-Site' | 'Sec-Fetch-User' | 'Sec-Purpose' | 'Sec-WebSocket-Accept' | 'Server' | 'Server-Timing' | 'Service-Worker-Navigation-Preload' | 'Set-Cookie' | 'SourceMap' | 'Strict-Transport-Security' | 'TE' | 'Timing-Allow-Origin' | 'Trailer' | 'Transfer-Encoding' | 'Upgrade' | 'Upgrade-Insecure-Requests' | 'User-Agent' | 'Vary' | 'Via' | 'WWW-Authenticate' | 'X-Content-Type-Options' | 'X-Frame-Options'>;
|
|
1002
|
+
type IANARegisteredMimeType = Autocomplete<'audio/aac' | 'video/x-msvideo' | 'image/avif' | 'video/av1' | 'application/octet-stream' | 'image/bmp' | 'text/css' | 'text/csv' | 'application/vnd.ms-fontobject' | 'application/epub+zip' | 'image/gif' | 'application/gzip' | 'text/html' | 'image/x-icon' | 'text/calendar' | 'image/jpeg' | 'text/javascript' | 'application/json' | 'application/ld+json' | 'audio/x-midi' | 'audio/mpeg' | 'video/mp4' | 'video/mpeg' | 'audio/ogg' | 'video/ogg' | 'application/ogg' | 'audio/opus' | 'font/otf' | 'application/pdf' | 'image/png' | 'application/rtf' | 'image/svg+xml' | 'image/tiff' | 'video/mp2t' | 'font/ttf' | 'text/plain' | 'application/wasm' | 'video/webm' | 'audio/webm' | 'image/webp' | 'font/woff' | 'font/woff2' | 'application/xhtml+xml' | 'application/xml' | 'application/zip' | 'video/3gpp' | 'video/3gpp2' | 'model/gltf+json' | 'model/gltf-binary'>;
|
|
1003
|
+
type KnownHeaderValues = {
|
|
1004
|
+
'content-type': IANARegisteredMimeType;
|
|
1005
|
+
};
|
|
1006
|
+
type HeaderRecord = { [K in HeaderNames | Lowercase<HeaderNames>]?: Lowercase<K> extends keyof KnownHeaderValues ? KnownHeaderValues[Lowercase<K>] : string };
|
|
1007
|
+
//#endregion
|
|
1008
|
+
//#region ../../node_modules/.pnpm/undici@8.7.0/node_modules/undici/types/readable.d.ts
|
|
1009
|
+
declare class BodyReadable extends Readable {
|
|
1010
|
+
constructor(opts: {
|
|
1011
|
+
resume: (this: Readable, size: number) => void | null;
|
|
1012
|
+
abort: () => void | null;
|
|
1013
|
+
contentType?: string;
|
|
1014
|
+
contentLength?: number;
|
|
1015
|
+
highWaterMark?: number;
|
|
1016
|
+
});
|
|
1017
|
+
/** Consumes and returns the body as a string
|
|
1018
|
+
* https://fetch.spec.whatwg.org/#dom-body-text
|
|
1019
|
+
*/
|
|
1020
|
+
text(): Promise<string>;
|
|
1021
|
+
/** Consumes and returns the body as a JavaScript Object
|
|
1022
|
+
* https://fetch.spec.whatwg.org/#dom-body-json
|
|
1023
|
+
*/
|
|
1024
|
+
json(): Promise<unknown>;
|
|
1025
|
+
/** Consumes and returns the body as a Blob
|
|
1026
|
+
* https://fetch.spec.whatwg.org/#dom-body-blob
|
|
1027
|
+
*/
|
|
1028
|
+
blob(): Promise<Blob>;
|
|
1029
|
+
/** Consumes and returns the body as an Uint8Array
|
|
1030
|
+
* https://fetch.spec.whatwg.org/#dom-body-bytes
|
|
1031
|
+
*/
|
|
1032
|
+
bytes(): Promise<Uint8Array>;
|
|
1033
|
+
/** Consumes and returns the body as an ArrayBuffer
|
|
1034
|
+
* https://fetch.spec.whatwg.org/#dom-body-arraybuffer
|
|
1035
|
+
*/
|
|
1036
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
1037
|
+
/** Not implemented
|
|
1038
|
+
*
|
|
1039
|
+
* https://fetch.spec.whatwg.org/#dom-body-formdata
|
|
1040
|
+
*/
|
|
1041
|
+
formData(): Promise<never>;
|
|
1042
|
+
/** Returns true if the body is not null and the body has been consumed
|
|
1043
|
+
*
|
|
1044
|
+
* Otherwise, returns false
|
|
1045
|
+
*
|
|
1046
|
+
* https://fetch.spec.whatwg.org/#dom-body-bodyused
|
|
1047
|
+
*/
|
|
1048
|
+
readonly bodyUsed: boolean;
|
|
1049
|
+
/**
|
|
1050
|
+
* If body is null, it should return null as the body
|
|
1051
|
+
*
|
|
1052
|
+
* If body is not null, should return the body as a ReadableStream
|
|
1053
|
+
*
|
|
1054
|
+
* https://fetch.spec.whatwg.org/#dom-body-body
|
|
1055
|
+
*/
|
|
1056
|
+
readonly body: never | undefined;
|
|
1057
|
+
/** Dumps the response body by reading `limit` number of bytes.
|
|
1058
|
+
* @param opts.limit Number of bytes to read (optional) - Default: 131072
|
|
1059
|
+
* @param opts.signal AbortSignal to cancel the operation (optional)
|
|
1060
|
+
*/
|
|
1061
|
+
dump(opts?: {
|
|
1062
|
+
limit: number;
|
|
1063
|
+
signal?: AbortSignal;
|
|
1064
|
+
}): Promise<void>;
|
|
1065
|
+
}
|
|
1066
|
+
//#endregion
|
|
1067
|
+
//#region ../../node_modules/.pnpm/undici@8.7.0/node_modules/undici/types/fetch.d.ts
|
|
1068
|
+
type BodyInit = ArrayBuffer | AsyncIterable<Uint8Array> | Blob | FormData | Iterable<Uint8Array> | NodeJS.ArrayBufferView | URLSearchParams$1 | null | string;
|
|
1069
|
+
interface SpecIterator<T, TReturn = any, TNext = undefined> {
|
|
1070
|
+
next(...args: [] | [TNext]): IteratorResult<T, TReturn>;
|
|
1071
|
+
}
|
|
1072
|
+
interface SpecIteratorObject<T, TReturn = undefined, TNext = unknown> extends SpecIterator<T, TReturn, TNext> {
|
|
1073
|
+
[Symbol.iterator](): SpecIteratorObject<T, TReturn, TNext>;
|
|
1074
|
+
map<U>(callbackfn: (value: T, index: number) => U): SpecIteratorObject<U>;
|
|
1075
|
+
filter<S extends T>(predicate: (value: T, index: number) => value is S): SpecIteratorObject<S>;
|
|
1076
|
+
filter(predicate: (value: T, index: number) => unknown): SpecIteratorObject<T>;
|
|
1077
|
+
take(limit: number): SpecIteratorObject<T>;
|
|
1078
|
+
drop(count: number): SpecIteratorObject<T>;
|
|
1079
|
+
flatMap<U>(callbackfn: (value: T, index: number) => Iterator<U> | Iterable<U>): SpecIteratorObject<U>;
|
|
1080
|
+
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number) => T): T;
|
|
1081
|
+
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number) => T, initialValue: T): T;
|
|
1082
|
+
reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number) => U, initialValue: U): U;
|
|
1083
|
+
toArray(): T[];
|
|
1084
|
+
forEach(callbackfn: (value: T, index: number) => void): void;
|
|
1085
|
+
some(predicate: (value: T, index: number) => unknown): boolean;
|
|
1086
|
+
every(predicate: (value: T, index: number) => unknown): boolean;
|
|
1087
|
+
find<S extends T>(predicate: (value: T, index: number) => value is S): S | undefined;
|
|
1088
|
+
find(predicate: (value: T, index: number) => unknown): T | undefined;
|
|
1089
|
+
readonly [Symbol.toStringTag]: string;
|
|
1090
|
+
}
|
|
1091
|
+
interface SpecIterableIterator<T> extends SpecIteratorObject<T> {
|
|
1092
|
+
[Symbol.iterator](): SpecIterableIterator<T>;
|
|
1093
|
+
}
|
|
1094
|
+
interface SpecIterable<T> {
|
|
1095
|
+
[Symbol.iterator](): SpecIterableIterator<T>;
|
|
1096
|
+
}
|
|
1097
|
+
type HeadersInit = [string, string][] | HeaderRecord | Headers$1;
|
|
1098
|
+
declare class Headers$1 implements SpecIterable<[string, string]> {
|
|
1099
|
+
constructor(init?: HeadersInit);
|
|
1100
|
+
readonly append: (name: string, value: string) => void;
|
|
1101
|
+
readonly delete: (name: string) => void;
|
|
1102
|
+
readonly get: (name: string) => string | null;
|
|
1103
|
+
readonly has: (name: string) => boolean;
|
|
1104
|
+
readonly set: (name: string, value: string) => void;
|
|
1105
|
+
readonly getSetCookie: () => string[];
|
|
1106
|
+
readonly forEach: (callbackfn: (value: string, key: string, iterable: Headers$1) => void, thisArg?: unknown) => void;
|
|
1107
|
+
readonly keys: () => SpecIterableIterator<string>;
|
|
1108
|
+
readonly values: () => SpecIterableIterator<string>;
|
|
1109
|
+
readonly entries: () => SpecIterableIterator<[string, string]>;
|
|
1110
|
+
readonly [Symbol.iterator]: () => SpecIterableIterator<[string, string]>;
|
|
1111
|
+
}
|
|
1112
|
+
//#endregion
|
|
1113
|
+
//#region ../../node_modules/.pnpm/undici@8.7.0/node_modules/undici/types/formdata.d.ts
|
|
1114
|
+
/**
|
|
1115
|
+
* A `string` or `File` that represents a single value from a set of `FormData` key-value pairs.
|
|
1116
|
+
*/
|
|
1117
|
+
declare type FormDataEntryValue = string | File;
|
|
1118
|
+
/**
|
|
1119
|
+
* Provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using fetch().
|
|
1120
|
+
*/
|
|
1121
|
+
declare class FormData {
|
|
1122
|
+
/**
|
|
1123
|
+
* Appends a new value onto an existing key inside a FormData object,
|
|
1124
|
+
* or adds the key if it does not already exist.
|
|
1125
|
+
*
|
|
1126
|
+
* The difference between `set()` and `append()` is that if the specified key already exists, `set()` will overwrite all existing values with the new one, whereas `append()` will append the new value onto the end of the existing set of values.
|
|
1127
|
+
*
|
|
1128
|
+
* @param name The name of the field whose data is contained in `value`.
|
|
1129
|
+
* @param value The field's value. This can be [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
|
|
1130
|
+
or [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File). If none of these are specified the value is converted to a string.
|
|
1131
|
+
* @param fileName The filename reported to the server, when a Blob or File is passed as the second parameter. The default filename for Blob objects is "blob". The default filename for File objects is the file's filename.
|
|
1132
|
+
*/
|
|
1133
|
+
append(name: string, value: unknown, fileName?: string): void;
|
|
1134
|
+
/**
|
|
1135
|
+
* Set a new value for an existing key inside FormData,
|
|
1136
|
+
* or add the new field if it does not already exist.
|
|
1137
|
+
*
|
|
1138
|
+
* @param name The name of the field whose data is contained in `value`.
|
|
1139
|
+
* @param value The field's value. This can be [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
|
|
1140
|
+
or [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File). If none of these are specified the value is converted to a string.
|
|
1141
|
+
* @param fileName The filename reported to the server, when a Blob or File is passed as the second parameter. The default filename for Blob objects is "blob". The default filename for File objects is the file's filename.
|
|
1142
|
+
*
|
|
1143
|
+
*/
|
|
1144
|
+
set(name: string, value: unknown, fileName?: string): void;
|
|
1145
|
+
/**
|
|
1146
|
+
* Returns the first value associated with a given key from within a `FormData` object.
|
|
1147
|
+
* If you expect multiple values and want all of them, use the `getAll()` method instead.
|
|
1148
|
+
*
|
|
1149
|
+
* @param {string} name A name of the value you want to retrieve.
|
|
1150
|
+
*
|
|
1151
|
+
* @returns A `FormDataEntryValue` containing the value. If the key doesn't exist, the method returns null.
|
|
1152
|
+
*/
|
|
1153
|
+
get(name: string): FormDataEntryValue | null;
|
|
1154
|
+
/**
|
|
1155
|
+
* Returns all the values associated with a given key from within a `FormData` object.
|
|
1156
|
+
*
|
|
1157
|
+
* @param {string} name A name of the value you want to retrieve.
|
|
1158
|
+
*
|
|
1159
|
+
* @returns An array of `FormDataEntryValue` whose key matches the value passed in the `name` parameter. If the key doesn't exist, the method returns an empty list.
|
|
1160
|
+
*/
|
|
1161
|
+
getAll(name: string): FormDataEntryValue[];
|
|
1162
|
+
/**
|
|
1163
|
+
* Returns a boolean stating whether a `FormData` object contains a certain key.
|
|
1164
|
+
*
|
|
1165
|
+
* @param name A string representing the name of the key you want to test for.
|
|
1166
|
+
*
|
|
1167
|
+
* @return A boolean value.
|
|
1168
|
+
*/
|
|
1169
|
+
has(name: string): boolean;
|
|
1170
|
+
/**
|
|
1171
|
+
* Deletes a key and its value(s) from a `FormData` object.
|
|
1172
|
+
*
|
|
1173
|
+
* @param name The name of the key you want to delete.
|
|
1174
|
+
*/
|
|
1175
|
+
delete(name: string): void;
|
|
1176
|
+
/**
|
|
1177
|
+
* Executes given callback function for each field of the FormData instance
|
|
1178
|
+
*/
|
|
1179
|
+
forEach: (callbackfn: (value: FormDataEntryValue, key: string, iterable: FormData) => void, thisArg?: unknown) => void;
|
|
1180
|
+
/**
|
|
1181
|
+
* Returns an [`iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) allowing to go through all keys contained in this `FormData` object.
|
|
1182
|
+
* Each key is a `string`.
|
|
1183
|
+
*/
|
|
1184
|
+
keys: () => SpecIterableIterator<string>;
|
|
1185
|
+
/**
|
|
1186
|
+
* Returns an [`iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) allowing to go through all values contained in this object `FormData` object.
|
|
1187
|
+
* Each value is a [`FormDataValue`](https://developer.mozilla.org/en-US/docs/Web/API/FormDataEntryValue).
|
|
1188
|
+
*/
|
|
1189
|
+
values: () => SpecIterableIterator<FormDataEntryValue>;
|
|
1190
|
+
/**
|
|
1191
|
+
* Returns an [`iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) allowing to go through the `FormData` key/value pairs.
|
|
1192
|
+
* The key of each pair is a string; the value is a [`FormDataValue`](https://developer.mozilla.org/en-US/docs/Web/API/FormDataEntryValue).
|
|
1193
|
+
*/
|
|
1194
|
+
entries: () => SpecIterableIterator<[string, FormDataEntryValue]>;
|
|
1195
|
+
/**
|
|
1196
|
+
* An alias for FormData#entries()
|
|
1197
|
+
*/
|
|
1198
|
+
[Symbol.iterator]: () => SpecIterableIterator<[string, FormDataEntryValue]>;
|
|
1199
|
+
readonly [Symbol.toStringTag]: string;
|
|
1200
|
+
}
|
|
1201
|
+
//#endregion
|
|
1202
|
+
//#region ../../node_modules/.pnpm/undici@8.7.0/node_modules/undici/types/connector.d.ts
|
|
1203
|
+
declare function buildConnector(options?: buildConnector.BuildOptions): buildConnector.connector;
|
|
1204
|
+
declare namespace buildConnector {
|
|
1205
|
+
export type BuildOptions = (ConnectionOptions | TcpNetConnectOpts | IpcNetConnectOpts) & {
|
|
1206
|
+
allowH2?: boolean;
|
|
1207
|
+
preferH2?: boolean;
|
|
1208
|
+
maxCachedSessions?: number | null;
|
|
1209
|
+
socketPath?: string | null;
|
|
1210
|
+
timeout?: number | null;
|
|
1211
|
+
port?: number;
|
|
1212
|
+
keepAlive?: boolean | null;
|
|
1213
|
+
keepAliveInitialDelay?: number | null;
|
|
1214
|
+
typeOfService?: number | null;
|
|
1215
|
+
};
|
|
1216
|
+
export interface Options {
|
|
1217
|
+
hostname: string;
|
|
1218
|
+
host?: string;
|
|
1219
|
+
protocol: string;
|
|
1220
|
+
port: string;
|
|
1221
|
+
servername?: string;
|
|
1222
|
+
localAddress?: string | null;
|
|
1223
|
+
socketPath?: string | null;
|
|
1224
|
+
httpSocket?: Socket;
|
|
1225
|
+
}
|
|
1226
|
+
export type Callback = (...args: CallbackArgs) => void;
|
|
1227
|
+
type CallbackArgs = [null, Socket | TLSSocket] | [Error, null];
|
|
1228
|
+
export interface connector {
|
|
1229
|
+
(options: buildConnector.Options, callback: buildConnector.Callback): void;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
//#endregion
|
|
1233
|
+
//#region ../../node_modules/.pnpm/undici@8.7.0/node_modules/undici/types/client-stats.d.ts
|
|
1234
|
+
declare class ClientStats {
|
|
1235
|
+
constructor(pool: Client);
|
|
1236
|
+
/** If socket has open connection. */
|
|
1237
|
+
connected: boolean;
|
|
1238
|
+
/** Number of open socket connections in this client that do not have an active request. */
|
|
1239
|
+
pending: number;
|
|
1240
|
+
/** Number of currently active requests of this client. */
|
|
1241
|
+
running: number;
|
|
1242
|
+
/** Number of active, pending, or queued requests of this client. */
|
|
1243
|
+
size: number;
|
|
1244
|
+
}
|
|
1245
|
+
//#endregion
|
|
1246
|
+
//#region ../../node_modules/.pnpm/undici@8.7.0/node_modules/undici/types/client.d.ts
|
|
1247
|
+
type ClientConnectOptions<TOpaque = null> = Omit<Dispatcher.ConnectOptions<TOpaque>, 'origin'>;
|
|
1248
|
+
/**
|
|
1249
|
+
* A basic HTTP/1.1 client, mapped on top a single TCP/TLS connection. Pipelining is disabled by default.
|
|
1250
|
+
*/
|
|
1251
|
+
declare class Client extends Dispatcher {
|
|
1252
|
+
constructor(url: string | URL, options?: Client.Options);
|
|
1253
|
+
/** Property to get and set the pipelining factor. */
|
|
1254
|
+
pipelining: number;
|
|
1255
|
+
/** `true` after `client.close()` has been called. */
|
|
1256
|
+
closed: boolean;
|
|
1257
|
+
/** `true` after `client.destroyed()` has been called or `client.close()` has been called and the client shutdown has completed. */
|
|
1258
|
+
destroyed: boolean;
|
|
1259
|
+
/** Aggregate stats for a Client. */
|
|
1260
|
+
readonly stats: ClientStats; // Override dispatcher APIs.
|
|
1261
|
+
override connect<TOpaque = null>(options: ClientConnectOptions<TOpaque>): Promise<Dispatcher.ConnectData<TOpaque>>;
|
|
1262
|
+
override connect<TOpaque = null>(options: ClientConnectOptions<TOpaque>, callback: (err: Error | null, data: Dispatcher.ConnectData<TOpaque>) => void): void;
|
|
1263
|
+
}
|
|
1264
|
+
declare namespace Client {
|
|
1265
|
+
export interface Options {
|
|
1266
|
+
/** The maximum length of request headers in bytes. Default: Node.js' `--max-http-header-size` or `16384` (16KiB). */
|
|
1267
|
+
maxHeaderSize?: number;
|
|
1268
|
+
/** The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers (Node 14 and above only). Default: `300e3` milliseconds (300s). */
|
|
1269
|
+
headersTimeout?: number;
|
|
1270
|
+
/** @deprecated unsupported socketTimeout, use headersTimeout & bodyTimeout instead */
|
|
1271
|
+
socketTimeout?: never;
|
|
1272
|
+
/** @deprecated unsupported requestTimeout, use headersTimeout & bodyTimeout instead */
|
|
1273
|
+
requestTimeout?: never;
|
|
1274
|
+
/** The timeout for establishing a socket connection, in milliseconds. Use `0` to disable it entirely. Default: `10e3` milliseconds (10s). */
|
|
1275
|
+
connectTimeout?: number;
|
|
1276
|
+
/** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Default: `300e3` milliseconds (300s). */
|
|
1277
|
+
bodyTimeout?: number;
|
|
1278
|
+
/** @deprecated unsupported idleTimeout, use keepAliveTimeout instead */
|
|
1279
|
+
idleTimeout?: never;
|
|
1280
|
+
/** @deprecated unsupported keepAlive, use pipelining=0 instead */
|
|
1281
|
+
keepAlive?: never;
|
|
1282
|
+
/** the timeout, in milliseconds, after which a socket without active requests will time out. Monitors time between activity on a connected socket. This value may be overridden by *keep-alive* hints from the server. Default: `4e3` milliseconds (4s). */
|
|
1283
|
+
keepAliveTimeout?: number;
|
|
1284
|
+
/** @deprecated unsupported maxKeepAliveTimeout, use keepAliveMaxTimeout instead */
|
|
1285
|
+
maxKeepAliveTimeout?: never;
|
|
1286
|
+
/** the maximum allowed `idleTimeout`, in milliseconds, when overridden by *keep-alive* hints from the server. Default: `600e3` milliseconds (10min). */
|
|
1287
|
+
keepAliveMaxTimeout?: number;
|
|
1288
|
+
/** A number of milliseconds subtracted from server *keep-alive* hints when overriding `idleTimeout` to account for timing inaccuracies caused by e.g. transport latency. Default: `1e3` milliseconds (1s). */
|
|
1289
|
+
keepAliveTimeoutThreshold?: number;
|
|
1290
|
+
/** An IPC endpoint, either a Unix domain socket or Windows named pipe. Default: `null`. */
|
|
1291
|
+
socketPath?: string;
|
|
1292
|
+
/** The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Only enable values greater than `1` when the remote server is trusted. Default: `1`. */
|
|
1293
|
+
pipelining?: number;
|
|
1294
|
+
/** @deprecated use the connect option instead */
|
|
1295
|
+
tls?: never;
|
|
1296
|
+
/** If `true`, an error is thrown when the request content-length header doesn't match the length of the request body. Default: `true`. */
|
|
1297
|
+
strictContentLength?: boolean;
|
|
1298
|
+
/** Maximum number of TLS cached sessions used by the built-in connector. Use `0` to disable TLS session caching. Default: `100`. */
|
|
1299
|
+
maxCachedSessions?: number;
|
|
1300
|
+
/** Connector options passed to `buildConnector`, or a custom connector function. Default: `null`. */
|
|
1301
|
+
connect?: Partial<buildConnector.BuildOptions> | buildConnector.connector;
|
|
1302
|
+
/** The maximum number of requests to send over a single connection before it is reset. Use `0` to disable this limit. Default: `null`. */
|
|
1303
|
+
maxRequestsPerClient?: number;
|
|
1304
|
+
/** Local IP address the socket should connect from. */
|
|
1305
|
+
localAddress?: string;
|
|
1306
|
+
/** Max response body size in bytes, -1 is disabled */
|
|
1307
|
+
maxResponseSize?: number;
|
|
1308
|
+
/** WebSocket-specific options */
|
|
1309
|
+
webSocket?: Client.WebSocketOptions;
|
|
1310
|
+
/** Enables a family autodetection algorithm that loosely implements section 5 of RFC 8305. */
|
|
1311
|
+
autoSelectFamily?: boolean;
|
|
1312
|
+
/** The amount of time in milliseconds to wait for a connection attempt to finish before trying the next address when using the `autoSelectFamily` option. */
|
|
1313
|
+
autoSelectFamilyAttemptTimeout?: number;
|
|
1314
|
+
/**
|
|
1315
|
+
* @description Enables support for H2 if the server has assigned bigger priority to it through ALPN negotiation.
|
|
1316
|
+
* @default true
|
|
1317
|
+
*/
|
|
1318
|
+
allowH2?: boolean;
|
|
1319
|
+
/**
|
|
1320
|
+
* @description Dictates the maximum number of concurrent streams for a single H2 session. It can be overridden by a SETTINGS remote frame.
|
|
1321
|
+
* @default 100
|
|
1322
|
+
*/
|
|
1323
|
+
maxConcurrentStreams?: number;
|
|
1324
|
+
/**
|
|
1325
|
+
* @description Sets the HTTP/2 stream-level flow-control window size (SETTINGS_INITIAL_WINDOW_SIZE).
|
|
1326
|
+
* @default 262144
|
|
1327
|
+
*/
|
|
1328
|
+
initialWindowSize?: number;
|
|
1329
|
+
/**
|
|
1330
|
+
* @description Sets the HTTP/2 connection-level flow-control window size (ClientHttp2Session.setLocalWindowSize).
|
|
1331
|
+
* @default 524288
|
|
1332
|
+
*/
|
|
1333
|
+
connectionWindowSize?: number;
|
|
1334
|
+
/**
|
|
1335
|
+
* @description Time interval between PING frames dispatch
|
|
1336
|
+
* @default 60000
|
|
1337
|
+
*/
|
|
1338
|
+
pingInterval?: number;
|
|
1339
|
+
}
|
|
1340
|
+
export interface SocketInfo {
|
|
1341
|
+
localAddress?: string;
|
|
1342
|
+
localPort?: number;
|
|
1343
|
+
remoteAddress?: string;
|
|
1344
|
+
remotePort?: number;
|
|
1345
|
+
remoteFamily?: string;
|
|
1346
|
+
timeout?: number;
|
|
1347
|
+
bytesWritten?: number;
|
|
1348
|
+
bytesRead?: number;
|
|
1349
|
+
}
|
|
1350
|
+
export interface WebSocketOptions {
|
|
1351
|
+
/**
|
|
1352
|
+
* Maximum number of fragments in a message. Set to 0 to disable the limit.
|
|
1353
|
+
* @default 131072
|
|
1354
|
+
*/
|
|
1355
|
+
maxFragments?: number;
|
|
1356
|
+
/**
|
|
1357
|
+
* Maximum allowed payload size in bytes for WebSocket messages.
|
|
1358
|
+
* Applied to uncompressed messages, compressed frame payloads, and decompressed (permessage-deflate) messages.
|
|
1359
|
+
* Set to 0 to disable the limit.
|
|
1360
|
+
* @default 134217728 (128 MB)
|
|
1361
|
+
*/
|
|
1362
|
+
maxPayloadSize?: number;
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
//#endregion
|
|
1366
|
+
//#region ../../node_modules/.pnpm/undici@8.7.0/node_modules/undici/types/errors.d.ts
|
|
1367
|
+
declare namespace Errors {
|
|
1368
|
+
export class UndiciError extends Error {
|
|
1369
|
+
name: string;
|
|
1370
|
+
code: string;
|
|
1371
|
+
}
|
|
1372
|
+
/** Connect timeout error. */
|
|
1373
|
+
export class ConnectTimeoutError extends UndiciError {
|
|
1374
|
+
name: 'ConnectTimeoutError';
|
|
1375
|
+
code: 'UND_ERR_CONNECT_TIMEOUT';
|
|
1376
|
+
}
|
|
1377
|
+
/** A header exceeds the `headersTimeout` option. */
|
|
1378
|
+
export class HeadersTimeoutError extends UndiciError {
|
|
1379
|
+
name: 'HeadersTimeoutError';
|
|
1380
|
+
code: 'UND_ERR_HEADERS_TIMEOUT';
|
|
1381
|
+
}
|
|
1382
|
+
/** Headers overflow error. */
|
|
1383
|
+
export class HeadersOverflowError extends UndiciError {
|
|
1384
|
+
name: 'HeadersOverflowError';
|
|
1385
|
+
code: 'UND_ERR_HEADERS_OVERFLOW';
|
|
1386
|
+
}
|
|
1387
|
+
/** A body exceeds the `bodyTimeout` option. */
|
|
1388
|
+
export class BodyTimeoutError extends UndiciError {
|
|
1389
|
+
name: 'BodyTimeoutError';
|
|
1390
|
+
code: 'UND_ERR_BODY_TIMEOUT';
|
|
1391
|
+
}
|
|
1392
|
+
export class ResponseError extends UndiciError {
|
|
1393
|
+
constructor(message: string, code: number, options: {
|
|
1394
|
+
headers?: IncomingHttpHeaders | string[] | null;
|
|
1395
|
+
body?: null | Record<string, any> | string;
|
|
1396
|
+
});
|
|
1397
|
+
name: 'ResponseError';
|
|
1398
|
+
code: 'UND_ERR_RESPONSE';
|
|
1399
|
+
statusCode: number;
|
|
1400
|
+
body: null | Record<string, any> | string;
|
|
1401
|
+
headers: IncomingHttpHeaders | string[] | null;
|
|
1402
|
+
}
|
|
1403
|
+
/** Passed an invalid argument. */
|
|
1404
|
+
export class InvalidArgumentError extends UndiciError {
|
|
1405
|
+
name: 'InvalidArgumentError';
|
|
1406
|
+
code: 'UND_ERR_INVALID_ARG';
|
|
1407
|
+
}
|
|
1408
|
+
/** Returned an invalid value. */
|
|
1409
|
+
export class InvalidReturnValueError extends UndiciError {
|
|
1410
|
+
name: 'InvalidReturnValueError';
|
|
1411
|
+
code: 'UND_ERR_INVALID_RETURN_VALUE';
|
|
1412
|
+
}
|
|
1413
|
+
/** The request has been aborted by the user. */
|
|
1414
|
+
export class RequestAbortedError extends UndiciError {
|
|
1415
|
+
name: 'AbortError';
|
|
1416
|
+
code: 'UND_ERR_ABORTED';
|
|
1417
|
+
}
|
|
1418
|
+
/** Expected error with reason. */
|
|
1419
|
+
export class InformationalError extends UndiciError {
|
|
1420
|
+
name: 'InformationalError';
|
|
1421
|
+
code: 'UND_ERR_INFO';
|
|
1422
|
+
}
|
|
1423
|
+
/** Request body length does not match content-length header. */
|
|
1424
|
+
export class RequestContentLengthMismatchError extends UndiciError {
|
|
1425
|
+
name: 'RequestContentLengthMismatchError';
|
|
1426
|
+
code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH';
|
|
1427
|
+
}
|
|
1428
|
+
/** Response body length does not match content-length header. */
|
|
1429
|
+
export class ResponseContentLengthMismatchError extends UndiciError {
|
|
1430
|
+
name: 'ResponseContentLengthMismatchError';
|
|
1431
|
+
code: 'UND_ERR_RES_CONTENT_LENGTH_MISMATCH';
|
|
1432
|
+
}
|
|
1433
|
+
/** Trying to use a destroyed client. */
|
|
1434
|
+
export class ClientDestroyedError extends UndiciError {
|
|
1435
|
+
name: 'ClientDestroyedError';
|
|
1436
|
+
code: 'UND_ERR_DESTROYED';
|
|
1437
|
+
}
|
|
1438
|
+
/** Trying to use a closed client. */
|
|
1439
|
+
export class ClientClosedError extends UndiciError {
|
|
1440
|
+
name: 'ClientClosedError';
|
|
1441
|
+
code: 'UND_ERR_CLOSED';
|
|
1442
|
+
}
|
|
1443
|
+
/** There is an error with the socket. */
|
|
1444
|
+
export class SocketError extends UndiciError {
|
|
1445
|
+
name: 'SocketError';
|
|
1446
|
+
code: 'UND_ERR_SOCKET';
|
|
1447
|
+
socket: Client.SocketInfo | null;
|
|
1448
|
+
}
|
|
1449
|
+
/** Encountered unsupported functionality. */
|
|
1450
|
+
export class NotSupportedError extends UndiciError {
|
|
1451
|
+
name: 'NotSupportedError';
|
|
1452
|
+
code: 'UND_ERR_NOT_SUPPORTED';
|
|
1453
|
+
}
|
|
1454
|
+
/** No upstream has been added to the BalancedPool. */
|
|
1455
|
+
export class BalancedPoolMissingUpstreamError extends UndiciError {
|
|
1456
|
+
name: 'MissingUpstreamError';
|
|
1457
|
+
code: 'UND_ERR_BPL_MISSING_UPSTREAM';
|
|
1458
|
+
}
|
|
1459
|
+
export class HTTPParserError extends UndiciError {
|
|
1460
|
+
name: 'HTTPParserError';
|
|
1461
|
+
code: string;
|
|
1462
|
+
}
|
|
1463
|
+
/** The response exceed the length allowed. */
|
|
1464
|
+
export class ResponseExceededMaxSizeError extends UndiciError {
|
|
1465
|
+
name: 'ResponseExceededMaxSizeError';
|
|
1466
|
+
code: 'UND_ERR_RES_EXCEEDED_MAX_SIZE';
|
|
1467
|
+
}
|
|
1468
|
+
export class RequestRetryError extends UndiciError {
|
|
1469
|
+
constructor(message: string, statusCode: number, headers?: IncomingHttpHeaders | string[] | null, body?: null | Record<string, any> | string);
|
|
1470
|
+
name: 'RequestRetryError';
|
|
1471
|
+
code: 'UND_ERR_REQ_RETRY';
|
|
1472
|
+
statusCode: number;
|
|
1473
|
+
data: {
|
|
1474
|
+
count: number;
|
|
1475
|
+
};
|
|
1476
|
+
headers: Record<string, string | string[]>;
|
|
1477
|
+
}
|
|
1478
|
+
export class SecureProxyConnectionError extends UndiciError {
|
|
1479
|
+
constructor(cause?: Error, message?: string, options?: Record<any, any>);
|
|
1480
|
+
name: 'SecureProxyConnectionError';
|
|
1481
|
+
code: 'UND_ERR_PRX_TLS';
|
|
1482
|
+
}
|
|
1483
|
+
export class ProxyConnectionError extends UndiciError {
|
|
1484
|
+
constructor(cause?: Error, message?: string, options?: Record<any, any>);
|
|
1485
|
+
name: 'ProxyConnectionError';
|
|
1486
|
+
code: 'UND_ERR_PRX_CONN';
|
|
1487
|
+
}
|
|
1488
|
+
export class MaxOriginsReachedError extends UndiciError {
|
|
1489
|
+
name: 'MaxOriginsReachedError';
|
|
1490
|
+
code: 'UND_ERR_MAX_ORIGINS_REACHED';
|
|
1491
|
+
}
|
|
1492
|
+
/** SOCKS5 proxy related error. */
|
|
1493
|
+
export class Socks5ProxyError extends UndiciError {
|
|
1494
|
+
constructor(message?: string, code?: string);
|
|
1495
|
+
name: 'Socks5ProxyError';
|
|
1496
|
+
code: string;
|
|
1497
|
+
}
|
|
1498
|
+
/** WebSocket decompressed message exceeded maximum size. */
|
|
1499
|
+
export class MessageSizeExceededError extends UndiciError {
|
|
1500
|
+
name: 'MessageSizeExceededError';
|
|
1501
|
+
code: 'UND_ERR_WS_MESSAGE_SIZE_EXCEEDED';
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
//#endregion
|
|
1505
|
+
//#region ../../node_modules/.pnpm/undici@8.7.0/node_modules/undici/types/dispatcher.d.ts
|
|
1506
|
+
type UndiciHeaders = OutgoingHttpHeaders | string[] | Iterable<[string, string | string[] | undefined]> | null;
|
|
1507
|
+
/** Dispatcher is the core API used to dispatch requests. */
|
|
1508
|
+
declare class Dispatcher extends EventEmitter {
|
|
1509
|
+
/** Dispatches a request. This API is expected to evolve through semver-major versions and is less stable than the preceding higher level APIs. It is primarily intended for library developers who implement higher level APIs on top of this. */
|
|
1510
|
+
dispatch(options: Dispatcher.DispatchOptions, handler: Dispatcher.DispatchHandler): boolean;
|
|
1511
|
+
/** Starts two-way communications with the requested resource. */
|
|
1512
|
+
connect<TOpaque = null>(options: Dispatcher.ConnectOptions<TOpaque>, callback: (err: Error | null, data: Dispatcher.ConnectData<TOpaque>) => void): void;
|
|
1513
|
+
connect<TOpaque = null>(options: Dispatcher.ConnectOptions<TOpaque>): Promise<Dispatcher.ConnectData<TOpaque>>;
|
|
1514
|
+
/** Compose a chain of dispatchers */
|
|
1515
|
+
compose(dispatchers: Dispatcher.DispatcherComposeInterceptor[]): Dispatcher.ComposedDispatcher;
|
|
1516
|
+
compose(...dispatchers: Dispatcher.DispatcherComposeInterceptor[]): Dispatcher.ComposedDispatcher;
|
|
1517
|
+
/** Performs an HTTP request. */
|
|
1518
|
+
request<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>, callback: (err: Error | null, data: Dispatcher.ResponseData<TOpaque>) => void): void;
|
|
1519
|
+
request<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>): Promise<Dispatcher.ResponseData<TOpaque>>;
|
|
1520
|
+
/** For easy use with `stream.pipeline`. */
|
|
1521
|
+
pipeline<TOpaque = null>(options: Dispatcher.PipelineOptions<TOpaque>, handler: Dispatcher.PipelineHandler<TOpaque>): Duplex;
|
|
1522
|
+
/** A faster version of `Dispatcher.request`. */
|
|
1523
|
+
stream<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>, factory: Dispatcher.StreamFactory<TOpaque>, callback: (err: Error | null, data: Dispatcher.StreamData<TOpaque>) => void): void;
|
|
1524
|
+
stream<TOpaque = null>(options: Dispatcher.RequestOptions<TOpaque>, factory: Dispatcher.StreamFactory<TOpaque>): Promise<Dispatcher.StreamData<TOpaque>>;
|
|
1525
|
+
/** Upgrade to a different protocol. */
|
|
1526
|
+
upgrade(options: Dispatcher.UpgradeOptions, callback: (err: Error | null, data: Dispatcher.UpgradeData) => void): void;
|
|
1527
|
+
upgrade(options: Dispatcher.UpgradeOptions): Promise<Dispatcher.UpgradeData>;
|
|
1528
|
+
/** Closes the client and gracefully waits for enqueued requests to complete before invoking the callback (or returning a promise if no callback is provided). */
|
|
1529
|
+
close(callback: () => void): void;
|
|
1530
|
+
close(): Promise<void>;
|
|
1531
|
+
/** Destroy the client abruptly with the given err. All the pending and running requests will be asynchronously aborted and error. Waits until socket is closed before invoking the callback (or returning a promise if no callback is provided). Since this operation is asynchronously dispatched there might still be some progress on dispatched requests. */
|
|
1532
|
+
destroy(err: Error | null, callback: () => void): void;
|
|
1533
|
+
destroy(callback: () => void): void;
|
|
1534
|
+
destroy(err: Error | null): Promise<void>;
|
|
1535
|
+
destroy(): Promise<void>;
|
|
1536
|
+
on(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
|
1537
|
+
on(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1538
|
+
on(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1539
|
+
on(eventName: 'drain', callback: (origin: URL) => void): this;
|
|
1540
|
+
once(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
|
1541
|
+
once(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1542
|
+
once(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1543
|
+
once(eventName: 'drain', callback: (origin: URL) => void): this;
|
|
1544
|
+
off(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
|
1545
|
+
off(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1546
|
+
off(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1547
|
+
off(eventName: 'drain', callback: (origin: URL) => void): this;
|
|
1548
|
+
addListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
|
1549
|
+
addListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1550
|
+
addListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1551
|
+
addListener(eventName: 'drain', callback: (origin: URL) => void): this;
|
|
1552
|
+
removeListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
|
1553
|
+
removeListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1554
|
+
removeListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1555
|
+
removeListener(eventName: 'drain', callback: (origin: URL) => void): this;
|
|
1556
|
+
prependListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
|
1557
|
+
prependListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1558
|
+
prependListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1559
|
+
prependListener(eventName: 'drain', callback: (origin: URL) => void): this;
|
|
1560
|
+
prependOnceListener(eventName: 'connect', callback: (origin: URL, targets: readonly Dispatcher[]) => void): this;
|
|
1561
|
+
prependOnceListener(eventName: 'disconnect', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1562
|
+
prependOnceListener(eventName: 'connectionError', callback: (origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void): this;
|
|
1563
|
+
prependOnceListener(eventName: 'drain', callback: (origin: URL) => void): this;
|
|
1564
|
+
listeners(eventName: 'connect'): ((origin: URL, targets: readonly Dispatcher[]) => void)[];
|
|
1565
|
+
listeners(eventName: 'disconnect'): ((origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void)[];
|
|
1566
|
+
listeners(eventName: 'connectionError'): ((origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void)[];
|
|
1567
|
+
listeners(eventName: 'drain'): ((origin: URL) => void)[];
|
|
1568
|
+
rawListeners(eventName: 'connect'): ((origin: URL, targets: readonly Dispatcher[]) => void)[];
|
|
1569
|
+
rawListeners(eventName: 'disconnect'): ((origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void)[];
|
|
1570
|
+
rawListeners(eventName: 'connectionError'): ((origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError) => void)[];
|
|
1571
|
+
rawListeners(eventName: 'drain'): ((origin: URL) => void)[];
|
|
1572
|
+
emit(eventName: 'connect', origin: URL, targets: readonly Dispatcher[]): boolean;
|
|
1573
|
+
emit(eventName: 'disconnect', origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError): boolean;
|
|
1574
|
+
emit(eventName: 'connectionError', origin: URL, targets: readonly Dispatcher[], error: Errors.UndiciError): boolean;
|
|
1575
|
+
emit(eventName: 'drain', origin: URL): boolean;
|
|
1576
|
+
}
|
|
1577
|
+
declare namespace Dispatcher {
|
|
1578
|
+
export interface ComposedDispatcher extends Dispatcher {}
|
|
1579
|
+
export type Dispatch = Dispatcher['dispatch'];
|
|
1580
|
+
export type DispatcherComposeInterceptor = (dispatch: Dispatch) => Dispatch;
|
|
1581
|
+
export interface DispatchOptions {
|
|
1582
|
+
origin?: string | URL;
|
|
1583
|
+
path: string;
|
|
1584
|
+
method: HttpMethod;
|
|
1585
|
+
/** Default: `null` */
|
|
1586
|
+
body?: string | Buffer | Uint8Array | Readable | null | FormData;
|
|
1587
|
+
/** Default: `null` */
|
|
1588
|
+
headers?: UndiciHeaders;
|
|
1589
|
+
/** Query string params to be embedded in the request URL. Default: `null` */
|
|
1590
|
+
query?: Record<string, any>;
|
|
1591
|
+
/** Whether the requests can be safely retried or not. If `false` the request won't be sent until all preceding requests in the pipeline have completed. Default: `true` if `method` is `HEAD` or `GET`. */
|
|
1592
|
+
idempotent?: boolean;
|
|
1593
|
+
/** Whether the response is expected to take a long time and would end up blocking the pipeline. When this is set to `true` further pipelining will be avoided on the same connection until headers have been received. Defaults to `method !== 'HEAD'`. */
|
|
1594
|
+
blocking?: boolean;
|
|
1595
|
+
/** The IP Type of Service (ToS) value for the request socket. Must be an integer between 0 and 255. Default: `0` */
|
|
1596
|
+
typeOfService?: number | null;
|
|
1597
|
+
/** Upgrade the request. Should be used to specify the kind of upgrade i.e. `'Websocket'`. Default: `method === 'CONNECT' || null`. */
|
|
1598
|
+
upgrade?: boolean | string | null;
|
|
1599
|
+
/** The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers. Defaults to 300 seconds. */
|
|
1600
|
+
headersTimeout?: number | null;
|
|
1601
|
+
/** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use 0 to disable it entirely. Defaults to 300 seconds. */
|
|
1602
|
+
bodyTimeout?: number | null;
|
|
1603
|
+
/** Whether the request should stablish a keep-alive or not. Default `false` */
|
|
1604
|
+
reset?: boolean;
|
|
1605
|
+
/** For H2, it appends the expect: 100-continue header, and halts the request body until a 100-continue is received from the remote server */
|
|
1606
|
+
expectContinue?: boolean;
|
|
1607
|
+
}
|
|
1608
|
+
export interface ConnectOptions<TOpaque = null> {
|
|
1609
|
+
origin: string | URL;
|
|
1610
|
+
path: string;
|
|
1611
|
+
/** Default: `null` */
|
|
1612
|
+
headers?: UndiciHeaders;
|
|
1613
|
+
/** Default: `null` */
|
|
1614
|
+
signal?: AbortSignal | EventEmitter | null;
|
|
1615
|
+
/** This argument parameter is passed through to `ConnectData` */
|
|
1616
|
+
opaque?: TOpaque;
|
|
1617
|
+
/** Default: `null` */
|
|
1618
|
+
responseHeaders?: 'raw' | null;
|
|
1619
|
+
}
|
|
1620
|
+
export interface RequestOptions<TOpaque = null> extends DispatchOptions {
|
|
1621
|
+
/** Default: `null` */
|
|
1622
|
+
opaque?: TOpaque;
|
|
1623
|
+
/** Default: `null` */
|
|
1624
|
+
signal?: AbortSignal | EventEmitter | null;
|
|
1625
|
+
/** Default: `null` */
|
|
1626
|
+
onInfo?: (info: {
|
|
1627
|
+
statusCode: number;
|
|
1628
|
+
headers: Record<string, string | string[]>;
|
|
1629
|
+
}) => void;
|
|
1630
|
+
/** Default: `null` */
|
|
1631
|
+
responseHeaders?: 'raw' | null;
|
|
1632
|
+
/** Default: `64 KiB` */
|
|
1633
|
+
highWaterMark?: number;
|
|
1634
|
+
}
|
|
1635
|
+
export interface PipelineOptions<TOpaque = null> extends RequestOptions<TOpaque> {
|
|
1636
|
+
/** `true` if the `handler` will return an object stream. Default: `false` */
|
|
1637
|
+
objectMode?: boolean;
|
|
1638
|
+
}
|
|
1639
|
+
export interface UpgradeOptions {
|
|
1640
|
+
path: string;
|
|
1641
|
+
/** Default: `'GET'` */
|
|
1642
|
+
method?: string;
|
|
1643
|
+
/** Default: `null` */
|
|
1644
|
+
headers?: UndiciHeaders;
|
|
1645
|
+
/** A string of comma separated protocols, in descending preference order. Default: `'Websocket'` */
|
|
1646
|
+
protocol?: string;
|
|
1647
|
+
/** Default: `null` */
|
|
1648
|
+
signal?: AbortSignal | EventEmitter | null;
|
|
1649
|
+
/** Default: `null` */
|
|
1650
|
+
responseHeaders?: 'raw' | null;
|
|
1651
|
+
}
|
|
1652
|
+
export interface ConnectData<TOpaque = null> {
|
|
1653
|
+
statusCode: number;
|
|
1654
|
+
headers: IncomingHttpHeaders;
|
|
1655
|
+
socket: Duplex;
|
|
1656
|
+
opaque: TOpaque;
|
|
1657
|
+
}
|
|
1658
|
+
export interface ResponseData<TOpaque = null> {
|
|
1659
|
+
statusCode: number;
|
|
1660
|
+
statusText: string;
|
|
1661
|
+
headers: IncomingHttpHeaders;
|
|
1662
|
+
body: BodyReadable & BodyMixin;
|
|
1663
|
+
trailers: Record<string, string>;
|
|
1664
|
+
opaque: TOpaque;
|
|
1665
|
+
context: object;
|
|
1666
|
+
}
|
|
1667
|
+
export interface PipelineHandlerData<TOpaque = null> {
|
|
1668
|
+
statusCode: number;
|
|
1669
|
+
headers: IncomingHttpHeaders;
|
|
1670
|
+
opaque: TOpaque;
|
|
1671
|
+
body: BodyReadable;
|
|
1672
|
+
context: object;
|
|
1673
|
+
}
|
|
1674
|
+
export interface StreamData<TOpaque = null> {
|
|
1675
|
+
opaque: TOpaque;
|
|
1676
|
+
trailers: Record<string, string>;
|
|
1677
|
+
}
|
|
1678
|
+
export interface UpgradeData<TOpaque = null> {
|
|
1679
|
+
headers: IncomingHttpHeaders;
|
|
1680
|
+
socket: Duplex;
|
|
1681
|
+
opaque: TOpaque;
|
|
1682
|
+
}
|
|
1683
|
+
export interface StreamFactoryData<TOpaque = null> {
|
|
1684
|
+
statusCode: number;
|
|
1685
|
+
headers: IncomingHttpHeaders;
|
|
1686
|
+
opaque: TOpaque;
|
|
1687
|
+
context: object;
|
|
1688
|
+
}
|
|
1689
|
+
export type StreamFactory<TOpaque = null> = (data: StreamFactoryData<TOpaque>) => Writable;
|
|
1690
|
+
export interface DispatchController {
|
|
1691
|
+
get aborted(): boolean;
|
|
1692
|
+
get paused(): boolean;
|
|
1693
|
+
get reason(): Error | null;
|
|
1694
|
+
rawHeaders?: Buffer[] | string[] | IncomingHttpHeaders | null;
|
|
1695
|
+
rawTrailers?: Buffer[] | string[] | IncomingHttpHeaders | null;
|
|
1696
|
+
abort(reason: Error): void;
|
|
1697
|
+
pause(): void;
|
|
1698
|
+
resume(): void;
|
|
1699
|
+
}
|
|
1700
|
+
export interface DispatchHandler {
|
|
1701
|
+
onRequestStart?(controller: DispatchController, context: any): void;
|
|
1702
|
+
onRequestUpgrade?(controller: DispatchController, statusCode: number, headers: IncomingHttpHeaders, socket: Duplex): void;
|
|
1703
|
+
onResponseStart?(controller: DispatchController, statusCode: number, headers: IncomingHttpHeaders, statusMessage?: string): void;
|
|
1704
|
+
onResponseData?(controller: DispatchController, chunk: Buffer): void;
|
|
1705
|
+
onResponseEnd?(controller: DispatchController, trailers: IncomingHttpHeaders): void;
|
|
1706
|
+
onResponseError?(controller: DispatchController, error: Error): void;
|
|
1707
|
+
/** Invoked when response is received, before headers have been read. **/
|
|
1708
|
+
onResponseStarted?(): void;
|
|
1709
|
+
/** Invoked when a body chunk is sent to the server. May be invoked multiple times for chunked requests */
|
|
1710
|
+
onBodySent?(chunk: Buffer): void;
|
|
1711
|
+
/** Invoked after the request body is fully sent. */
|
|
1712
|
+
onRequestSent?(): void;
|
|
1713
|
+
}
|
|
1714
|
+
export type PipelineHandler<TOpaque = null> = (data: PipelineHandlerData<TOpaque>) => Readable;
|
|
1715
|
+
export type HttpMethod = Autocomplete<'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE' | 'PATCH'>;
|
|
1716
|
+
/**
|
|
1717
|
+
* @link https://fetch.spec.whatwg.org/#body-mixin
|
|
1718
|
+
*/
|
|
1719
|
+
interface BodyMixin {
|
|
1720
|
+
readonly body?: never;
|
|
1721
|
+
readonly bodyUsed: boolean;
|
|
1722
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
1723
|
+
blob(): Promise<Blob>;
|
|
1724
|
+
bytes(): Promise<Uint8Array>;
|
|
1725
|
+
formData(): Promise<never>;
|
|
1726
|
+
json(): Promise<unknown>;
|
|
1727
|
+
text(): Promise<string>;
|
|
1728
|
+
}
|
|
1729
|
+
export interface DispatchInterceptor {
|
|
1730
|
+
(dispatch: Dispatch): Dispatch;
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
//#endregion
|
|
1734
|
+
//#region ../../node_modules/.pnpm/undici@8.7.0/node_modules/undici/types/mock-interceptor.d.ts
|
|
1735
|
+
/** The scope associated with a mock dispatch. */
|
|
1736
|
+
declare class MockScope<TData extends object = object> {
|
|
1737
|
+
constructor(mockDispatch: MockInterceptor.MockDispatch<TData>);
|
|
1738
|
+
/** Delay a reply by a set amount of time in ms. */
|
|
1739
|
+
delay(waitInMs: number): MockScope<TData>;
|
|
1740
|
+
/** Persist the defined mock data for the associated reply. It will return the defined mock data indefinitely. */
|
|
1741
|
+
persist(): MockScope<TData>;
|
|
1742
|
+
/** Define a reply for a set amount of matching requests. */
|
|
1743
|
+
times(repeatTimes: number): MockScope<TData>;
|
|
1744
|
+
}
|
|
1745
|
+
/** The interceptor for a Mock. */
|
|
1746
|
+
declare class MockInterceptor {
|
|
1747
|
+
constructor(options: MockInterceptor.Options, mockDispatches: MockInterceptor.MockDispatch[]);
|
|
1748
|
+
/** Mock an undici request with the defined reply. */
|
|
1749
|
+
reply<TData extends object = object>(replyOptionsCallback: MockInterceptor.MockReplyOptionsCallback<TData>): MockScope<TData>;
|
|
1750
|
+
reply<TData extends object = object>(statusCode: number, data?: TData | Buffer | string | MockInterceptor.MockResponseDataHandler<TData>, responseOptions?: MockInterceptor.MockResponseOptions): MockScope<TData>;
|
|
1751
|
+
/** Mock an undici request by throwing the defined reply error. */
|
|
1752
|
+
replyWithError<TError extends Error = Error>(error: TError): MockScope;
|
|
1753
|
+
/** Set default reply headers on the interceptor for subsequent mocked replies. */
|
|
1754
|
+
defaultReplyHeaders(headers: IncomingHttpHeaders): MockInterceptor;
|
|
1755
|
+
/** Set default reply trailers on the interceptor for subsequent mocked replies. */
|
|
1756
|
+
defaultReplyTrailers(trailers: Record<string, string>): MockInterceptor;
|
|
1757
|
+
/** Set automatically calculated content-length header on subsequent mocked replies. */
|
|
1758
|
+
replyContentLength(): MockInterceptor;
|
|
1759
|
+
}
|
|
1760
|
+
declare namespace MockInterceptor {
|
|
1761
|
+
/** MockInterceptor options. */
|
|
1762
|
+
export interface Options {
|
|
1763
|
+
/** Path to intercept on. */
|
|
1764
|
+
path: string | RegExp | ((path: string) => boolean);
|
|
1765
|
+
/** Method to intercept on. Defaults to GET. */
|
|
1766
|
+
method?: string | RegExp | ((method: string) => boolean);
|
|
1767
|
+
/** Body to intercept on. */
|
|
1768
|
+
body?: string | RegExp | ((body: string) => boolean);
|
|
1769
|
+
/** Headers to intercept on. */
|
|
1770
|
+
headers?: Record<string, string | RegExp | ((body: string) => boolean)> | ((headers: Record<string, string>) => boolean);
|
|
1771
|
+
/** Query params to intercept on */
|
|
1772
|
+
query?: Record<string, any>;
|
|
1773
|
+
}
|
|
1774
|
+
export interface MockDispatch<TData extends object = object, TError extends Error = Error> extends Options {
|
|
1775
|
+
times: number | null;
|
|
1776
|
+
persist: boolean;
|
|
1777
|
+
consumed: boolean;
|
|
1778
|
+
data: MockDispatchData<TData, TError>;
|
|
1779
|
+
}
|
|
1780
|
+
export interface MockDispatchData<TData extends object = object, TError extends Error = Error> extends MockResponseOptions {
|
|
1781
|
+
error: TError | null;
|
|
1782
|
+
statusCode?: number;
|
|
1783
|
+
data?: TData | string;
|
|
1784
|
+
}
|
|
1785
|
+
export interface MockResponseOptions {
|
|
1786
|
+
headers?: IncomingHttpHeaders;
|
|
1787
|
+
trailers?: Record<string, string>;
|
|
1788
|
+
}
|
|
1789
|
+
export interface MockResponseCallbackOptions {
|
|
1790
|
+
path: string;
|
|
1791
|
+
method: string;
|
|
1792
|
+
headers?: Headers$1 | Record<string, string>;
|
|
1793
|
+
origin?: string;
|
|
1794
|
+
body?: BodyInit | Dispatcher.DispatchOptions['body'] | null;
|
|
1795
|
+
}
|
|
1796
|
+
export type MockResponseDataHandler<TData extends object = object> = (opts: MockResponseCallbackOptions) => TData | Buffer | string;
|
|
1797
|
+
export type MockReplyOptionsCallback<TData extends object = object> = (opts: MockResponseCallbackOptions) => {
|
|
1798
|
+
statusCode: number;
|
|
1799
|
+
data?: TData | Buffer | string;
|
|
1800
|
+
responseOptions?: MockResponseOptions;
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1803
|
+
//#endregion
|
|
1804
|
+
//#region ../shared/dist/index.d.ts
|
|
1805
|
+
//#endregion
|
|
1806
|
+
//#region src/oauth/pkce.d.ts
|
|
1807
|
+
interface PkcePair {
|
|
1808
|
+
/** code_verifier:token 交换时回传,向 server 证明授权码的持有者。 */
|
|
1809
|
+
verifier: string;
|
|
1810
|
+
/** code_challenge:S256(verifier),随 authorize 请求发出。 */
|
|
1811
|
+
challenge: string;
|
|
1812
|
+
/** challenge 方法,固定 'S256'。 */
|
|
1813
|
+
method: 'S256';
|
|
1814
|
+
}
|
|
1815
|
+
/**
|
|
1816
|
+
* 生成 code_verifier:32 字节随机熵 → base64url(43 字符,
|
|
1817
|
+
* 落在 RFC 7636 要求的 43–128 字符区间内)。
|
|
1818
|
+
*/
|
|
1819
|
+
declare function generateVerifier(): string;
|
|
1820
|
+
declare function generateChallenge(verifier: string): string;
|
|
1821
|
+
declare function createPkcePair(): PkcePair;
|
|
1822
|
+
declare function generateState(): string; //#endregion
|
|
1823
|
+
//#region src/oauth/loopback-server.d.ts
|
|
1824
|
+
interface LoopbackServerOptions {
|
|
1825
|
+
ports?: number[];
|
|
1826
|
+
callbackPath?: string;
|
|
1827
|
+
expectedState?: string;
|
|
1828
|
+
host?: string;
|
|
1829
|
+
signal?: AbortSignal;
|
|
1830
|
+
}
|
|
1831
|
+
interface LoopbackCallback {
|
|
1832
|
+
code: string;
|
|
1833
|
+
state?: string;
|
|
1834
|
+
}
|
|
1835
|
+
interface LoopbackServer {
|
|
1836
|
+
readonly port: number;
|
|
1837
|
+
readonly redirectUri: string;
|
|
1838
|
+
waitForCallback(): Promise<LoopbackCallback>;
|
|
1839
|
+
close(): Promise<void>;
|
|
1840
|
+
}
|
|
1841
|
+
declare function startLoopbackServer(options?: LoopbackServerOptions): Promise<LoopbackServer>; //#endregion
|
|
1842
|
+
//#region src/oauth/browser.d.ts
|
|
1843
|
+
/**
|
|
1844
|
+
* 用操作系统默认浏览器打开 URL。
|
|
1845
|
+
* 跨平台:macOS→`open`、Windows→`start`、Linux→`xdg-open`。
|
|
1846
|
+
* 失败静默吞错(不抛),返回 boolean 表示是否成功启动。
|
|
1847
|
+
*/
|
|
1848
|
+
//#endregion
|
|
1849
|
+
//#region src/oauth/jwt.d.ts
|
|
1850
|
+
/**
|
|
1851
|
+
* JWT claim 提取:独立于 PKCE/device-flow/loopback 的通用编码原语。
|
|
1852
|
+
*/
|
|
1853
|
+
/**
|
|
1854
|
+
* 从多个 JWT token 中提取某个字符串 claim。
|
|
1855
|
+
*
|
|
1856
|
+
* 提取规则:
|
|
1857
|
+
* - 先查命名空间 `claims[namespace]?.[claim]`,未命中回退顶层 `claims[claim]`
|
|
1858
|
+
* - 按 `tokenSources` 数组顺序逐个 token 尝试,任一命中即返回
|
|
1859
|
+
* - 解析失败(非 JWT 格式/不透明 token)静默返回 `undefined`
|
|
1860
|
+
*
|
|
1861
|
+
* @param tokens - 待扫描的 JWT token 数组(如 `[idToken, accessToken]`)
|
|
1862
|
+
* @param claim - 目标 claim key
|
|
1863
|
+
* @param namespace - 可选命名空间前缀(如 `https://api.openai.com/auth`)
|
|
1864
|
+
* @returns 提取到的 claim 值,或 `undefined`
|
|
1865
|
+
*/
|
|
1866
|
+
declare function extractJwtClaim(tokens: Array<string | undefined>, claim: string, namespace?: string): string | undefined;
|
|
1867
|
+
//#endregion
|
|
1868
|
+
//#region src/oauth/templates.d.ts
|
|
1869
|
+
interface PKCEOAuthTemplateParams {
|
|
1870
|
+
/** OAuth provider id(同 `OAuthProvider.id`)。 */
|
|
1871
|
+
id: string;
|
|
1872
|
+
/** 显示名(同 `OAuthProvider.name`)。 */
|
|
1873
|
+
name: string;
|
|
1874
|
+
clientId: string;
|
|
1875
|
+
authorizeUrl: string;
|
|
1876
|
+
tokenUrl: string;
|
|
1877
|
+
redirectUri: string;
|
|
1878
|
+
scope: string;
|
|
1879
|
+
/**
|
|
1880
|
+
* loopback 自动回填端口列表(按序回退);缺省/空 → 纯手动粘贴。
|
|
1881
|
+
* 对齐 Anthropic 的 54545 白名单端口机制与 Codex 的 [1455,1457] 多端口。
|
|
1882
|
+
*/
|
|
1883
|
+
loopbackPorts?: number[];
|
|
1884
|
+
/**
|
|
1885
|
+
* loopback 是否假定始终可用、不提供手动粘贴兜底。
|
|
1886
|
+
* `false`(缺省,对齐 Anthropic)= 端口被占时降级手动粘贴框;
|
|
1887
|
+
* `true`(对齐 Codex)= 假设 loopback 始终可用,要求 `loopbackPorts` 非空。
|
|
1888
|
+
*/
|
|
1889
|
+
assumesLoopbackAlways?: boolean;
|
|
1890
|
+
/** authorize URL 额外的 query 参数(如 Codex 的 `id_token_add_organizations`)。 */
|
|
1891
|
+
extraAuthParams?: Record<string, string>;
|
|
1892
|
+
/** token 端点请求体编码:'json'(对齐 Anthropic)| 'form'(对齐 Codex,缺省)。 */
|
|
1893
|
+
tokenExchangeEncoding?: 'json' | 'form';
|
|
1894
|
+
/** 该 OAuth token 是否绑定产品订阅。 */
|
|
1895
|
+
subscriptionScoped?: boolean;
|
|
1896
|
+
/** 以 OAuth token 调用 API 时附带的 beta 头。 */
|
|
1897
|
+
oauthBeta?: string;
|
|
1898
|
+
}
|
|
1899
|
+
interface DeviceFlowOAuthTemplateParams {
|
|
1900
|
+
/** OAuth provider id。 */
|
|
1901
|
+
id: string;
|
|
1902
|
+
/** 显示名。 */
|
|
1903
|
+
name: string;
|
|
1904
|
+
clientId: string;
|
|
1905
|
+
/**
|
|
1906
|
+
* 设备授权码端点 URL 模板,`{domain}` 占位符在运行时替换为用户输入的域名。
|
|
1907
|
+
* 示例:`https://{domain}/login/device/code`
|
|
1908
|
+
*/
|
|
1909
|
+
deviceCodeUrlTemplate: string;
|
|
1910
|
+
/**
|
|
1911
|
+
* 轮询 access token 端点 URL 模板,`{domain}` 替换规则同上。
|
|
1912
|
+
* 示例:`https://{domain}/login/oauth/access_token`
|
|
1913
|
+
*/
|
|
1914
|
+
tokenUrlTemplate: string;
|
|
1915
|
+
/**
|
|
1916
|
+
* refresh token 端点 URL 模板(可选:不存在时使用内置默认推导)。
|
|
1917
|
+
* 示例:`https://api.{domain}/copilot_internal/v2/token`
|
|
1918
|
+
*/
|
|
1919
|
+
refreshUrlTemplate?: string;
|
|
1920
|
+
scope: string;
|
|
1921
|
+
/** 是否提示用户输入自定义域名(对齐 Copilot 企业域覆盖)。 */
|
|
1922
|
+
allowCustomDomain?: boolean;
|
|
1923
|
+
/** 请求头 User-Agent(部分厂商强制校验)。 */
|
|
1924
|
+
userAgent?: string;
|
|
1925
|
+
}
|
|
1926
|
+
/**
|
|
1927
|
+
* `PKCEOAuthTemplate(params)` 返回一个 PKCE S256 OAuth 实例。
|
|
1928
|
+
*
|
|
1929
|
+
* 行为与终态参数由 `PKCEOAuthTemplateParams` 完全控制:
|
|
1930
|
+
* - loopback 端口按列表顺序回退(`assumesLoopbackAlways:true` 时不提供手动粘贴兜底)
|
|
1931
|
+
* - authorize URL 上拼装额外 query 参数(`extraAuthParams`)
|
|
1932
|
+
* - token 端点请求体编码由 `tokenExchangeEncoding` 决定(`json` vs `form`)
|
|
1933
|
+
*
|
|
1934
|
+
* 插件声明式 OAuth(`kind: 'pkce'`,如 anthropic/openai-codex)与内置 provider 均委托本模板。
|
|
1935
|
+
*/
|
|
1936
|
+
declare function PKCEOAuthTemplate(params: PKCEOAuthTemplateParams): OAuthProvider;
|
|
1937
|
+
/**
|
|
1938
|
+
* `DeviceFlowOAuthTemplate(params)` 返回一个 Device Flow OAuth 实例。
|
|
1939
|
+
*
|
|
1940
|
+
* 行为由 `DeviceFlowOAuthTemplateParams` 控制:
|
|
1941
|
+
* - `allowCustomDomain:true` 时登录流程提示用户输入域名(企业域覆盖)
|
|
1942
|
+
* - 三处端点模板各自独立 `{domain}` 插值(device code / access token / refresh)
|
|
1943
|
+
* - 可选 `userAgent` 头(部分厂商校验)
|
|
1944
|
+
*
|
|
1945
|
+
* 插件声明式 OAuth(`kind: 'device-flow'`,如 GitHub Copilot)委托本模板。
|
|
1946
|
+
*/
|
|
1947
|
+
declare function DeviceFlowOAuthTemplate(params: DeviceFlowOAuthTemplateParams): OAuthProvider;
|
|
1948
|
+
//#endregion
|
|
1949
|
+
//#region src/openai-usage.d.ts
|
|
1950
|
+
/**
|
|
1951
|
+
* 从标准 `x-ratelimit-*` 响应头中解析 usage 快照——**厂商无关**(终局架构 review
|
|
1952
|
+
* 2026-07-21:函数名历史上带 "OpenAi" 后缀,但实现只解析 RFC 标准头族,对任何
|
|
1953
|
+
* OpenAI 兼容 provider(DeepSeek/groq/openrouter 等)同样适用,无厂商专属逻辑)。
|
|
1954
|
+
*
|
|
1955
|
+
* 可靠部分(有官方文档):
|
|
1956
|
+
* - standardLimits:x-ratelimit-* 标准 API 限流头(任何认证方式都返回)
|
|
1957
|
+
*
|
|
1958
|
+
* 不可靠(无 HTTP 头对应):
|
|
1959
|
+
* - 订阅池 status/resetsAt/usedPercent/limitType — 全设为 undefined / 'unknown'
|
|
1960
|
+
* - overage — OpenAI 无此概念,undefined
|
|
1961
|
+
*
|
|
1962
|
+
* Header dump:debug 级别输出全部响应头 key+value,供实证分析。
|
|
1963
|
+
*/
|
|
1964
|
+
declare function extractStandardRateLimitHeaders(headers: Headers | undefined): ProviderUsageSnapshot | null;
|
|
1965
|
+
/**
|
|
1966
|
+
* @deprecated 改名为 {@link extractStandardRateLimitHeaders}(终局架构 review
|
|
1967
|
+
* 2026-07-21:函数只解析厂商无关的标准 x-ratelimit-* 头族,"OpenAi" 后缀具有误导性)。
|
|
1968
|
+
* 保留别名过渡,下个大版本移除。
|
|
1969
|
+
*/
|
|
1970
|
+
declare const extractProviderUsageFromOpenAiHeaders: typeof extractStandardRateLimitHeaders;
|
|
1971
|
+
//#endregion
|
|
1972
|
+
//#region src/stream-errors.d.ts
|
|
1973
|
+
/**
|
|
1974
|
+
* 上下文溢出(413 / "prompt too long" 类)——本轮请求因上下文超限被服务端拒绝。
|
|
1975
|
+
* 与一般可重试错误(429/5xx/断连)不同:重发同样请求仍会失败,必须先压缩上下文。
|
|
1976
|
+
*/
|
|
1977
|
+
declare function isContextOverflowError(error: unknown): boolean;
|
|
1978
|
+
type StreamErrorClass = 'context-overflow' | 'image-constraint' | 'retryable' | 'fatal';
|
|
1979
|
+
/**
|
|
1980
|
+
* Anthropic unified rate limit 头族解析。
|
|
1981
|
+
* 从 429 响应的 anthropic-ratelimit-unified-* 头族判定是否硬额度耗尽(rejected)。
|
|
1982
|
+
* 瞬时 429(无 unified 头)返回 null——仍可退避重试。
|
|
1983
|
+
*
|
|
1984
|
+
* RFC-148 M4 已知边界(原计划迁出 extensions/plugin-otto-wire-protocols,执行时发现不可行):
|
|
1985
|
+
* `packages/agent/src/work-loop-stream-error.ts` 与本文件的 `classifyStreamError` 均
|
|
1986
|
+
* 直接调用本函数——`packages/agent` 是引擎最核心包,不可依赖 `extensions/` 插件目录
|
|
1987
|
+
* (会破坏"引擎核心零外部插件依赖"的分层边界,比厂商知识残留更严重的架构违例)。
|
|
1988
|
+
* 保留在协议中立层的依据:本函数是纯 HTTP 头名解析(零 SDK 依赖、零网络调用),符合
|
|
1989
|
+
* "多方可复用的协议中立原语"判据的弱形式——即便目前只有 Anthropic 一家使用这个
|
|
1990
|
+
* `anthropic-ratelimit-unified-*` 头族约定,它不携带任何 SDK 调用或厂商专属业务逻辑,
|
|
1991
|
+
* 与已随协议实现迁出的 `anthropic-usage.ts`(`extractProviderUsageFromHeaders`,
|
|
1992
|
+
* 同头族的成功路径解析)不同——那个只被单一协议实现消费,此函数被引擎核心跨包直接消费。
|
|
1993
|
+
*/
|
|
1994
|
+
declare function extractAnthropicRateLimit(error: unknown): {
|
|
1995
|
+
status: 'rejected' | 'allowed_warning';
|
|
1996
|
+
type?: 'five_hour' | 'seven_day' | 'seven_day_opus' | 'seven_day_sonnet' | 'seven_day_overage_included';
|
|
1997
|
+
resetsAt?: number;
|
|
1998
|
+
} | null;
|
|
1999
|
+
/**
|
|
2000
|
+
* 流错误分类,决定 work-loop 的恢复策略。
|
|
2001
|
+
* - `image-constraint`:400 + 图片维度/数量/大小超限(D7)——图片降级后重试。
|
|
2002
|
+
* - `context-overflow`:先压缩再重试(见 isContextOverflowError / H3)。
|
|
2003
|
+
* - `retryable`:429 / 5xx / 网络断连——丢弃 partial、退避后**重发整请求**。
|
|
2004
|
+
* - `fatal`:其它 4xx(鉴权/无效参数等)——重发无益,直接上抛。
|
|
2005
|
+
*
|
|
2006
|
+
* 顺序:先判 image-constraint(400+文案)→ overflow(413 / 400+文案)→ retryable → fatal。
|
|
2007
|
+
* image-constraint 必须在 isContextOverflowError 之前检查,防未来 Anthropic 文案改成
|
|
2008
|
+
* "exceeds the maximum..." 被 overflow 正则抢分类。
|
|
2009
|
+
*/
|
|
2010
|
+
/**
|
|
2011
|
+
* 是否为「网络断连」子类的可重试错误(ECONNRESET/socket hang up/terminated 等,或
|
|
2012
|
+
* PROVIDER_INCOMPLETE_STREAM/PROVIDER_STREAM_ERROR 传输层代码)——不含 429/5xx 状态码类。
|
|
2013
|
+
* 用于 work-loop-stream-error.ts 按错误子类选择重试节奏:网络断连走固定间隔(给对端/代理
|
|
2014
|
+
* 恢复时间),429/5xx 保留指数退避 + Retry-After 头(限流场景需要快速恢复,不应被拖慢)。
|
|
2015
|
+
* 仅在 classifyStreamError(error) === 'retryable' 时调用才有意义。
|
|
2016
|
+
*
|
|
2017
|
+
* 范围说明(终局 review 澄清):本判定复用整个 TRANSIENT_NETWORK_PATTERNS(不止新增的
|
|
2018
|
+
* terminated/other side closed)——econnreset/socket hang up/fetch failed/premature close/
|
|
2019
|
+
* connection closed 等均属于同一「连接被动中断」语义类别,一并归入固定 30s 节奏是有意的架构
|
|
2020
|
+
* 决策(而非本次改动的范围蔓延),回归测试见 stream-errors.test.ts 对多个既有模式的覆盖。
|
|
2021
|
+
* 有明确 4xx/5xx 状态码的错误(含 overloaded 类,多数 provider 会带 529/503)永远不会走到这里
|
|
2022
|
+
* ——上方 status 门控优先短路返回 false,继续用调用方的指数退避 retryCfg。
|
|
2023
|
+
*
|
|
2024
|
+
* 例外(review 发现的 bug 修复):流内(mid-stream SSE `event: error`)限流/过载帧 status 为
|
|
2025
|
+
* undefined,若不特殊处理会被 TRANSIENT_NETWORK_PATTERNS 的 `/overloaded/i` 误收编成"网络断连",
|
|
2026
|
+
* 错误地走 30s 固定节奏——这类错误语义上是「服务端限流信号」,应沿用调用方传入的指数退避
|
|
2027
|
+
* retryCfg(classifyStreamError 已将其分类为 retryable)。故此处优先检查
|
|
2028
|
+
* IN_STREAM_RATE_LIMIT_PATTERNS,命中则直接返回 false(非网络断连)。
|
|
2029
|
+
*/
|
|
2030
|
+
declare function isNetworkDisconnectError(error: unknown): boolean;
|
|
2031
|
+
/**
|
|
2032
|
+
* 是否为鉴权失败类错误(本地无凭据 / 服务端 401 拒绝 / OAuth 刷新失败)——`fatal` 分类下的
|
|
2033
|
+
* 一个子类,供上层(work-loop-stream-error.ts)区分"认证失效"与其他不可重试错误,记录专门的
|
|
2034
|
+
* 结构化事件(供用户事后追溯"什么时候、哪个 provider、失效了几次",此前完全零记录)。
|
|
2035
|
+
*
|
|
2036
|
+
* 三种触发源:
|
|
2037
|
+
* - `code === 'PROVIDER_AUTH_MISSING'`:本地压根没有可用凭据(resolveKey/resolveAuthCredential
|
|
2038
|
+
* 在请求发起前就抛出,具体 resolveKey 实现见各协议插件——RFC-148 M2 后 anthropic-messages/
|
|
2039
|
+
* openai-responses/openai-completions 已迁至 extensions/plugin-otto-wire-protocols/src/,
|
|
2040
|
+
* github-copilot 在 extensions/plugin-github-copilot/src/provider.ts)。
|
|
2041
|
+
* - `code === 'PROVIDER_AUTH_REFRESH_FAILED'`(RFC-137 D5):本地**确实持有** oauth 类型
|
|
2042
|
+
* 凭据,但 OAuth token 刷新流程本身失败(含跨进程锁等待超时后的失败,见
|
|
2043
|
+
* `auth-store.ts` 的 `refreshOAuthWithCrossProcessLock`)——与"从未配置凭据"是完全不同
|
|
2044
|
+
* 的语义,但同样需要走 auth 错误的记录+自动重试路径(RFC-137 D4,`work-loop-stream-error.ts`
|
|
2045
|
+
* 据此对"首次遇到"的这类错误自动重试一次)。**遗漏这一行会让 D4 的自动重试逻辑永远不会
|
|
2046
|
+
* 被触发**——`classifyStreamError` 会把未识别的错误码归为普通 `'fatal'`,直接 rethrow,
|
|
2047
|
+
* 跳过下面的记录与重试分支(RFC-137 独立评审 C1 finding)。
|
|
2048
|
+
* - `status === 401`:服务端拒绝了已提供的凭据(token 过期/被吊销/权限不足),这是真实的
|
|
2049
|
+
* "登录态失效"场景——请求已经发出,服务端明确回了 401。
|
|
2050
|
+
*/
|
|
2051
|
+
declare function isAuthError(error: unknown): boolean;
|
|
2052
|
+
/**
|
|
2053
|
+
* RFC-139 D3:鉴权失效根因分类(供 `stream.auth-failed` trace 事件记录机器可读细分)。
|
|
2054
|
+
* 与 `isAuthError` 同源判别(同一 code/status 提取),避免两处分类漂移。
|
|
2055
|
+
*
|
|
2056
|
+
* - `credential-missing`:本地无可用凭据(PROVIDER_AUTH_MISSING)——包括"凭据条目被
|
|
2057
|
+
* 外部删除后经 fs.watch 传播"的场景(RFC-139 事故根因正是此类,65/65 条 trace)。
|
|
2058
|
+
* - `refresh-failed`:本地持有 oauth 凭据但刷新失败(PROVIDER_AUTH_REFRESH_FAILED,RFC-137)。
|
|
2059
|
+
* - `server-rejected`:服务端拒绝已提供的凭据(401);**无 code 的 raw 401**(如
|
|
2060
|
+
* Anthropic SDK 直抛的 AuthenticationError,不经 ProviderError 包装)也归此类
|
|
2061
|
+
* (RFC-139 对抗评审 P1:extractCode 返回 undefined 时的回退分支)。
|
|
2062
|
+
*
|
|
2063
|
+
* 前置约定:调用方已用 `isAuthError` 判真后才调用本函数;对非 auth 错误返回
|
|
2064
|
+
* `server-rejected` 兜底(不抛错,分类器不承担守卫职责)。
|
|
2065
|
+
*/
|
|
2066
|
+
type AuthErrorType = 'credential-missing' | 'refresh-failed' | 'server-rejected';
|
|
2067
|
+
declare function classifyAuthErrorType(error: unknown): AuthErrorType;
|
|
2068
|
+
declare function classifyStreamError(error: unknown): StreamErrorClass;
|
|
2069
|
+
/**
|
|
2070
|
+
* 从错误链上取 `Retry-After`(秒)或 `retry-after-ms`(毫秒)头,返回毫秒。
|
|
2071
|
+
* 仅处理数值形式(最常见);HTTP-date 形式返回 undefined 交由退避计算。
|
|
2072
|
+
*/
|
|
2073
|
+
declare function extractRetryAfterMs(error: unknown): number | undefined;
|
|
2074
|
+
//#endregion
|
|
2075
|
+
//#region src/recording/stream-recording.d.ts
|
|
2076
|
+
interface RecordingHeader {
|
|
2077
|
+
version: 1;
|
|
2078
|
+
modelId: string;
|
|
2079
|
+
api: string;
|
|
2080
|
+
recordedAt: string;
|
|
2081
|
+
contextWindow: number;
|
|
2082
|
+
}
|
|
2083
|
+
interface RecordingLine {
|
|
2084
|
+
/** 相对首事件的毫秒偏移。 */
|
|
2085
|
+
t: number;
|
|
2086
|
+
e: StreamEvent;
|
|
2087
|
+
}
|
|
2088
|
+
interface Recording {
|
|
2089
|
+
header: RecordingHeader;
|
|
2090
|
+
events: RecordingLine[];
|
|
2091
|
+
}
|
|
2092
|
+
/** 录制目录(OTTO_HOME/recordings;权限 0o700——含对话内容的敏感数据)。 */
|
|
2093
|
+
declare function recordingsDir(ottoHome: string): string;
|
|
2094
|
+
/**
|
|
2095
|
+
* 包装一个 StreamEvent 异步迭代器,把事件透传的同时 append 到 JSONL 录制文件。
|
|
2096
|
+
* 透传零延迟——写盘是 fire-and-forget(WriteStream 内部缓冲),不阻塞流消费。
|
|
2097
|
+
*/
|
|
2098
|
+
declare function recordStream(source: AsyncIterable<StreamEvent>, model: Model, filePath: string): AsyncIterable<StreamEvent>;
|
|
2099
|
+
/** 读取并解析录制文件(header + 事件序列)。 */
|
|
2100
|
+
declare function loadRecording(filePath: string): Promise<Recording>;
|
|
2101
|
+
interface ReplayOptions {
|
|
2102
|
+
/**
|
|
2103
|
+
* true = 零间隔快放(测引擎开销的正确模式——原相对间隔含录制时 LLM 推理延迟的幽灵,
|
|
2104
|
+
* 只适合端到端对照,不适合引擎开销基准;RFC-200 评审修订 7)。
|
|
2105
|
+
*/
|
|
2106
|
+
fast?: boolean;
|
|
2107
|
+
}
|
|
2108
|
+
/** 按录制内容重放 StreamEvent 序列(默认按原相对间隔;fast 模式零间隔)。 */
|
|
2109
|
+
declare function replayStream(recording: Recording, options?: ReplayOptions, signal?: AbortSignal): AsyncIterable<StreamEvent>;
|
|
2110
|
+
//#endregion
|
|
2111
|
+
//#region src/recording/replay-provider.d.ts
|
|
2112
|
+
declare const REPLAY_API = "replay";
|
|
2113
|
+
/** 从录制 header 派生重放 Model 条目(与 factory 成对注册进 registry)。 */
|
|
2114
|
+
declare function buildReplayModel(recording: Recording): Model;
|
|
2115
|
+
declare class ReplayProviderStream implements ProviderStream {
|
|
2116
|
+
private readonly filePath;
|
|
2117
|
+
private readonly options;
|
|
2118
|
+
readonly id = "replay";
|
|
2119
|
+
readonly displayName = "Replay Provider (RFC-200)";
|
|
2120
|
+
private recording;
|
|
2121
|
+
constructor(filePath: string, options?: ReplayOptions);
|
|
2122
|
+
/** 预载录制(可选——converse 首次调用也会惰性加载;bench 场景预载可把 IO 摘出计时窗)。 */
|
|
2123
|
+
preload(): Promise<Recording>;
|
|
2124
|
+
converse(_model: Model, _context: StreamContext, options: StreamOptions, signal: AbortSignal): AsyncIterable<StreamEvent>;
|
|
2125
|
+
}
|
|
2126
|
+
declare function createReplayProviderFactory(filePath: string, options?: ReplayOptions): () => ProviderStream;
|
|
2127
|
+
//#endregion
|
|
2128
|
+
export { type Api, type AssistantContent, type AssistantMessage, type AssistantMessageMeta, type AuthErrorType, type AuthMode, type CacheRetention, type ChatCompletionsStreamParams, type ContentPart, DeviceFlowOAuthTemplate, type DeviceFlowOAuthTemplateParams, type FlatStreamState, type FlatToolCallAcc, type ImageContent, type LoopbackCallback, type LoopbackServer, type LoopbackServerOptions, type Message, type Model, type OAuthCredentials, type OAuthInfo, type OAuthLoginOptions, type OAuthPrompt, type OAuthProvider, type OAuthProviderFactory, type OAuthProviderId, type OAuthRefreshTokenOptions, PKCEOAuthTemplate, type PKCEOAuthTemplateParams, type PkcePair, type Provider, type ProviderFactory, type ProviderStream, REPLAY_API, type Recording, type RecordingHeader, type RecordingLine, type ReplayOptions, ReplayProviderStream, type RequestHeaderSources, type ResolvedAuth, type StopReason, type StreamBlock, type StreamContext, type StreamErrorClass, type StreamEvent, type StreamFunction, type StreamOptions, type StreamUsage, type SystemPromptSegment, type TextContent, type ThinkingContent, type TokenDerivedHeader, type ToolCall, type ToolDefinition, type ToolResultMessage, type UserMessage, type WireProtocolFactoryInput, type WireProtocolLogger, type WireProtocolMeta, type WireProtocolRegistration, type WireRequestCustomization, type WireRequestCustomizeInput, type WireSystemTextBlock, assembleAssistantMessage, assertSystemNotificationPlacement, blocksContent, buildChatCompletionsBody, buildChatCompletionsMessages, buildReplayModel, buildRequestHeaders, clampThinkingLevel, classifyAuthErrorType, classifyStreamError, createPkcePair, createReplayProviderFactory, degradedSystemNotificationText, extractAnthropicRateLimit, extractJwtClaim, extractProviderUsageFromOpenAiHeaders, extractRetryAfterMs, extractStandardRateLimitHeaders, flatContent, generateChallenge, generateState, generateVerifier, hasTrailingInvokeXml, initFlatStreamState, initStreamUsage, isAuthError, isContextOverflowError, isNetworkDisconnectError, loadRecording, mapChatFinishReason, mergeConsecutiveSystemNotifications, parseToolArguments, parseToolArgumentsWithStatus, recordStream, recordingsDir, recoverLiteralInvokeToolCalls, registeredToolNames, replayStream, sanitizeSurrogates, sanitizeToolRoundtrips, startLoopbackServer, streamChatCompletions, toJsonSchema, toolCallFromParsed };
|
|
2129
|
+
//# sourceMappingURL=index.d.ts.map
|