@wudao-org/providers 0.0.0-stage → 0.4.21
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/LICENSE +21 -0
- package/README.md +8 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/anthropic.d.ts +19 -0
- package/dist/anthropic.d.ts.map +1 -0
- package/dist/anthropic.js +621 -0
- package/dist/anthropic.js.map +1 -0
- package/dist/balance.d.ts +28 -0
- package/dist/balance.d.ts.map +1 -0
- package/dist/balance.js +105 -0
- package/dist/balance.js.map +1 -0
- package/dist/config.d.ts +328 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +623 -0
- package/dist/config.js.map +1 -0
- package/dist/dispatcher.d.ts +5 -0
- package/dist/dispatcher.d.ts.map +1 -0
- package/dist/dispatcher.js +21 -0
- package/dist/dispatcher.js.map +1 -0
- package/dist/effort-catalog.d.ts +17 -0
- package/dist/effort-catalog.d.ts.map +1 -0
- package/dist/effort-catalog.js +73 -0
- package/dist/effort-catalog.js.map +1 -0
- package/dist/error-body.d.ts +32 -0
- package/dist/error-body.d.ts.map +1 -0
- package/dist/error-body.js +74 -0
- package/dist/error-body.js.map +1 -0
- package/dist/header-validation.d.ts +57 -0
- package/dist/header-validation.d.ts.map +1 -0
- package/dist/header-validation.js +130 -0
- package/dist/header-validation.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +110 -0
- package/dist/index.js.map +1 -0
- package/dist/json-arguments.d.ts +17 -0
- package/dist/json-arguments.d.ts.map +1 -0
- package/dist/json-arguments.js +227 -0
- package/dist/json-arguments.js.map +1 -0
- package/dist/key-pool.d.ts +66 -0
- package/dist/key-pool.d.ts.map +1 -0
- package/dist/key-pool.js +207 -0
- package/dist/key-pool.js.map +1 -0
- package/dist/missing-reasoning-circuit.d.ts +17 -0
- package/dist/missing-reasoning-circuit.d.ts.map +1 -0
- package/dist/missing-reasoning-circuit.js +38 -0
- package/dist/missing-reasoning-circuit.js.map +1 -0
- package/dist/model-failure.d.ts +156 -0
- package/dist/model-failure.d.ts.map +1 -0
- package/dist/model-failure.js +253 -0
- package/dist/model-failure.js.map +1 -0
- package/dist/model-fallback.d.ts +18 -0
- package/dist/model-fallback.d.ts.map +1 -0
- package/dist/model-fallback.js +87 -0
- package/dist/model-fallback.js.map +1 -0
- package/dist/models.d.ts +20 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +55 -0
- package/dist/models.js.map +1 -0
- package/dist/openai-compatible.d.ts +87 -0
- package/dist/openai-compatible.d.ts.map +1 -0
- package/dist/openai-compatible.js +368 -0
- package/dist/openai-compatible.js.map +1 -0
- package/dist/openai-engine.d.ts +18 -0
- package/dist/openai-engine.d.ts.map +1 -0
- package/dist/openai-engine.js +515 -0
- package/dist/openai-engine.js.map +1 -0
- package/dist/openai-images.d.ts +38 -0
- package/dist/openai-images.d.ts.map +1 -0
- package/dist/openai-images.js +301 -0
- package/dist/openai-images.js.map +1 -0
- package/dist/openai-messages.d.ts +40 -0
- package/dist/openai-messages.d.ts.map +1 -0
- package/dist/openai-messages.js +135 -0
- package/dist/openai-messages.js.map +1 -0
- package/dist/openai-wire.d.ts +93 -0
- package/dist/openai-wire.d.ts.map +1 -0
- package/dist/openai-wire.js +151 -0
- package/dist/openai-wire.js.map +1 -0
- package/dist/persona/apply.d.ts +19 -0
- package/dist/persona/apply.d.ts.map +1 -0
- package/dist/persona/apply.js +98 -0
- package/dist/persona/apply.js.map +1 -0
- package/dist/persona/builtins.d.ts +3 -0
- package/dist/persona/builtins.d.ts.map +1 -0
- package/dist/persona/builtins.js +180 -0
- package/dist/persona/builtins.js.map +1 -0
- package/dist/persona/decorator.d.ts +4 -0
- package/dist/persona/decorator.d.ts.map +1 -0
- package/dist/persona/decorator.js +112 -0
- package/dist/persona/decorator.js.map +1 -0
- package/dist/persona/files.d.ts +20 -0
- package/dist/persona/files.d.ts.map +1 -0
- package/dist/persona/files.js +84 -0
- package/dist/persona/files.js.map +1 -0
- package/dist/persona/ids.d.ts +9 -0
- package/dist/persona/ids.d.ts.map +1 -0
- package/dist/persona/ids.js +11 -0
- package/dist/persona/ids.js.map +1 -0
- package/dist/persona/registry.d.ts +12 -0
- package/dist/persona/registry.d.ts.map +1 -0
- package/dist/persona/registry.js +54 -0
- package/dist/persona/registry.js.map +1 -0
- package/dist/persona/runtime.d.ts +23 -0
- package/dist/persona/runtime.d.ts.map +1 -0
- package/dist/persona/runtime.js +32 -0
- package/dist/persona/runtime.js.map +1 -0
- package/dist/persona/schema.d.ts +27 -0
- package/dist/persona/schema.d.ts.map +1 -0
- package/dist/persona/schema.js +165 -0
- package/dist/persona/schema.js.map +1 -0
- package/dist/persona/types.d.ts +38 -0
- package/dist/persona/types.d.ts.map +1 -0
- package/dist/persona/types.js +2 -0
- package/dist/persona/types.js.map +1 -0
- package/dist/pricing.d.ts +40 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +70 -0
- package/dist/pricing.js.map +1 -0
- package/dist/quota-park.d.ts +53 -0
- package/dist/quota-park.d.ts.map +1 -0
- package/dist/quota-park.js +135 -0
- package/dist/quota-park.js.map +1 -0
- package/dist/rate-pause.d.ts +28 -0
- package/dist/rate-pause.d.ts.map +1 -0
- package/dist/rate-pause.js +72 -0
- package/dist/rate-pause.js.map +1 -0
- package/dist/registry.d.ts +142 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +471 -0
- package/dist/registry.js.map +1 -0
- package/dist/responses.d.ts +5 -0
- package/dist/responses.d.ts.map +1 -0
- package/dist/responses.js +290 -0
- package/dist/responses.js.map +1 -0
- package/dist/retry-after.d.ts +13 -0
- package/dist/retry-after.d.ts.map +1 -0
- package/dist/retry-after.js +64 -0
- package/dist/retry-after.js.map +1 -0
- package/dist/retry-ladder.d.ts +176 -0
- package/dist/retry-ladder.d.ts.map +1 -0
- package/dist/retry-ladder.js +664 -0
- package/dist/retry-ladder.js.map +1 -0
- package/dist/split-inband-thinking.d.ts +35 -0
- package/dist/split-inband-thinking.d.ts.map +1 -0
- package/dist/split-inband-thinking.js +117 -0
- package/dist/split-inband-thinking.js.map +1 -0
- package/dist/stream-idle.d.ts +97 -0
- package/dist/stream-idle.d.ts.map +1 -0
- package/dist/stream-idle.js +127 -0
- package/dist/stream-idle.js.map +1 -0
- package/dist/tool-call-ids.d.ts +16 -0
- package/dist/tool-call-ids.d.ts.map +1 -0
- package/dist/tool-call-ids.js +36 -0
- package/dist/tool-call-ids.js.map +1 -0
- package/package.json +32 -3
package/dist/pricing.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// 借鉴弧 B1(SoL-Pi C1)— providers 的价目面:模型价格目录 schema + 缓存
|
|
2
|
+
// 经济学 ratio 的自动推导。
|
|
3
|
+
//
|
|
4
|
+
// 立场(对 SoL-Pi 的 N7 负裁决的正面侧):cacheWriteReadRatio 不做用户配置
|
|
5
|
+
// 项、不手填常量(他们的 12.5 抄 GPT-5.6 定价)。推导链:
|
|
6
|
+
// catalog pin(registry 行的 models[].prices——用户 overlay,builtin 只有
|
|
7
|
+
// 文档核实的数字才钉)> WUDAO_PRICE_<MODEL> env(CLI /cost 的既有约定,
|
|
8
|
+
// "in,out,cacheRead,cacheWrite" per-M-USD)> 保守缺省(core 的
|
|
9
|
+
// DEFAULT_CACHE_WRITE_READ_RATIO,ratioSource:"default" 类型化标注)。
|
|
10
|
+
//
|
|
11
|
+
// ratio 语义:重读每 token 价格 ÷ 缓存命中每 token 价格。重读价取
|
|
12
|
+
// max(input, cacheWrite):OpenAI/Anthropic 语义下 cacheWrite ≥ input(压缩后
|
|
13
|
+
// 重建前缀按 write 计价);DeepSeek 语义下无独立 write 价、重建按 miss=input
|
|
14
|
+
// 计价(usageCostUsd 的 write=0 形)。cacheRead ≤ 0(免费缓存或坏行)推不出
|
|
15
|
+
// 比值——回落下一档,绝不除零。
|
|
16
|
+
import { DEFAULT_CACHE_WRITE_READ_RATIO } from "@wudao-org/core";
|
|
17
|
+
/** registry/目录行的 fail-closed 形状校验:必需面在场且 finite ≥ 0,可选面
|
|
18
|
+
* 在场时同样。坏行拒收(fail-visible),绝不猜成 rate。 */
|
|
19
|
+
export function isModelPrices(v) {
|
|
20
|
+
if (typeof v !== "object" || v === null || Array.isArray(v))
|
|
21
|
+
return false;
|
|
22
|
+
const r = v;
|
|
23
|
+
const nonNeg = (x) => typeof x === "number" && Number.isFinite(x) && x >= 0;
|
|
24
|
+
if (!nonNeg(r.inputPerM) || !nonNeg(r.cacheReadPerM))
|
|
25
|
+
return false;
|
|
26
|
+
if (r.outputPerM !== undefined && !nonNeg(r.outputPerM))
|
|
27
|
+
return false;
|
|
28
|
+
if (r.cacheWritePerM !== undefined && !nonNeg(r.cacheWritePerM))
|
|
29
|
+
return false;
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
/** 从一档价格推导 ratio。cacheRead > 0 时 = prefill/cacheRead;cacheRead = 0
|
|
33
|
+
* 且 prefill > 0(免费缓存——DeepSeek 2024 真实存在过)时幸存前缀每请求
|
|
34
|
+
* $0:归档节省为 0 而重建仍付费 → 永不经济(Infinity,窗口保护兜底)。
|
|
35
|
+
* 两档推不出(全 0 / NaN)→ undefined(回落下一档)。 */
|
|
36
|
+
function ratioFrom(source) {
|
|
37
|
+
if (source.cacheReadPerM > 0) {
|
|
38
|
+
const r = Math.max(source.inputPerM, source.cacheWritePerM ?? 0) / source.cacheReadPerM;
|
|
39
|
+
return Number.isFinite(r) ? r : undefined;
|
|
40
|
+
}
|
|
41
|
+
const prefill = Math.max(source.inputPerM, source.cacheWritePerM ?? 0);
|
|
42
|
+
return prefill > 0 ? Number.POSITIVE_INFINITY : undefined;
|
|
43
|
+
}
|
|
44
|
+
/** ratio 可用 = 有限非负,或显式 +Infinity(免费缓存的永不经济档)。 */
|
|
45
|
+
const usableRatio = (r) => r !== undefined && (Number.isFinite(r) || r === Number.POSITIVE_INFINITY) && r >= 0;
|
|
46
|
+
/**
|
|
47
|
+
* 推导压缩经济学的定价事实。优先级 catalog > env > 保守缺省;每一档的来源
|
|
48
|
+
* 都类型化在 ratioSource 上("default" = 价目未知,决策面板可见)。
|
|
49
|
+
* 纯函数。
|
|
50
|
+
*/
|
|
51
|
+
export function deriveCachePricing(input) {
|
|
52
|
+
const fromCatalog = ratioFrom(input.catalog ?? { inputPerM: 0, cacheReadPerM: 0 });
|
|
53
|
+
if (usableRatio(fromCatalog)) {
|
|
54
|
+
return { cacheWriteReadRatio: fromCatalog, ratioSource: "catalog" };
|
|
55
|
+
}
|
|
56
|
+
const fromEnv = ratioFrom(input.env ?? { inputPerM: 0, cacheReadPerM: 0 });
|
|
57
|
+
if (usableRatio(fromEnv)) {
|
|
58
|
+
return { cacheWriteReadRatio: fromEnv, ratioSource: "env" };
|
|
59
|
+
}
|
|
60
|
+
return { cacheWriteReadRatio: DEFAULT_CACHE_WRITE_READ_RATIO, ratioSource: "default" };
|
|
61
|
+
}
|
|
62
|
+
/** 在一个 effective profile 的目录里按模型名找价格 pin(精确名;目录缺该
|
|
63
|
+
* 模型 = undefined)。纯。 */
|
|
64
|
+
export function catalogPricesFor(models, model) {
|
|
65
|
+
if (models === undefined)
|
|
66
|
+
return undefined;
|
|
67
|
+
const entry = models.find((m) => m.name === model);
|
|
68
|
+
return entry?.prices;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=pricing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** The account/window-level usage-cap body vocabulary. Deliberately does NOT
|
|
2
|
+
* include bare "limit" — the context-length family ("maximum context
|
|
3
|
+
* length", "context_limit") shares the word, and those classify one branch
|
|
4
|
+
* earlier at the HTTP boundary (isContextLengthFailure) with disjoint
|
|
5
|
+
* statuses (413/400/500 vs this module's 429); pinning the vocabulary tight
|
|
6
|
+
* keeps the two families disjoint even if the ordering ever moves. */
|
|
7
|
+
export declare const QUOTA_BODY_SIGNATURES: readonly RegExp[];
|
|
8
|
+
/** True when a 429 body carries a known account-quota signature. */
|
|
9
|
+
export declare function sniffQuotaBody(body: string): boolean;
|
|
10
|
+
/** Parse the provider's reset moment out of a 429 body (and, as the last
|
|
11
|
+
* resort, the already-parsed Retry-After header wait). Sources, first match
|
|
12
|
+
* wins: the Chinese absolute wording, the English absolute wording, a body
|
|
13
|
+
* `reset-after` seconds figure, the Retry-After header. Fail-closed:
|
|
14
|
+
* unparseable/past instants and non-positive header waits yield undefined
|
|
15
|
+
* (a past instant is the server's "already reset" — not park material; the
|
|
16
|
+
* ordinary ladder path owns it). */
|
|
17
|
+
export declare function parseQuotaResetAt(body: string, retryAfterMs?: number, now?: number): Date | undefined;
|
|
18
|
+
/** True iff the (status, body, deadline) triple is an account-level quota
|
|
19
|
+
* window past the 60s fail cap — the park candidate. All four gates must
|
|
20
|
+
* hold: HTTP 429, the quota vocabulary, a parseable reset moment, and a wait
|
|
21
|
+
* strictly beyond RETRY_AFTER_FAIL_CAP_MS (exactly-at-cap stays with the
|
|
22
|
+
* ladder — the existing `>` comparison). Everything else keeps today's
|
|
23
|
+
* semantics byte-for-byte. */
|
|
24
|
+
export declare function isQuotaParkFailure(status: number, body: string, retryAfterMs?: number, now?: number): boolean;
|
|
25
|
+
/** The typed account-quota failure (113-B3). Carries the parsed reset moment
|
|
26
|
+
* and the failing leg's provider identity — the CLI driver parks the run
|
|
27
|
+
* until resetAt (+margin) and schedules a one-shot wake. Message keeps a
|
|
28
|
+
* NON-transport prefix (`provider quota reached:` — deliberately not
|
|
29
|
+
* `provider (request|stream) failed: <status>`, so no message-regex consumer
|
|
30
|
+
* can misread it as a retryable status), and the name check in
|
|
31
|
+
* isRetryableProviderError makes the ladder's skip explicit regardless. */
|
|
32
|
+
export declare class QuotaParkError extends Error {
|
|
33
|
+
readonly status: number;
|
|
34
|
+
readonly body: string;
|
|
35
|
+
/** The parsed reset instant (see parseQuotaResetAt). */
|
|
36
|
+
readonly resetAt: Date;
|
|
37
|
+
/** v7 γ4 family: the failing leg's provider identity (registry id, or the
|
|
38
|
+
* baseURL host when the config carries no registry identity). */
|
|
39
|
+
readonly provider: string;
|
|
40
|
+
/** The failing leg's model id (the fallback chain swaps it — identity names
|
|
41
|
+
* the LEG). Omitted when unknown (omit-never-null). */
|
|
42
|
+
readonly model?: string;
|
|
43
|
+
constructor(which: "request" | "stream", status: number, body: string, resetAt: Date, provider: string, model?: string);
|
|
44
|
+
}
|
|
45
|
+
/** Classify at the HTTP boundary: build the typed QuotaParkError when the
|
|
46
|
+
* (status, body, deadline) triple is a park candidate, undefined otherwise
|
|
47
|
+
* (the caller falls through to the generic ProviderHttpError — today's
|
|
48
|
+
* semantics). */
|
|
49
|
+
export declare function tryQuotaParkError(which: "request" | "stream", status: number, body: string, retryAfterMs: number | undefined, identity: {
|
|
50
|
+
readonly provider?: string;
|
|
51
|
+
readonly model?: string;
|
|
52
|
+
}, now?: number): QuotaParkError | undefined;
|
|
53
|
+
//# sourceMappingURL=quota-park.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quota-park.d.ts","sourceRoot":"","sources":["../src/quota-park.ts"],"names":[],"mappings":"AAqBA;;;;;uEAKuE;AACvE,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EASlD,CAAC;AAEF,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAoBD;;;;;;qCAMqC;AACrC,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,IAAI,GAAG,SAAS,CAkBjH;AAED;;;;;+BAK+B;AAC/B,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,YAAY,CAAC,EAAE,MAAM,EACrB,GAAG,GAAE,MAAmB,GACvB,OAAO,CAKT;AAED;;;;;;4EAM4E;AAC5E,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB;sEACkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;4DACwD;IACxD,SAAiB,KAAK,CAAC,EAAE,MAAM,CAAC;gBAG9B,KAAK,EAAE,SAAS,GAAG,QAAQ,EAC3B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,IAAI,EACb,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE,MAAM;CAajB;AAED;;;kBAGkB;AAClB,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,GAAG,QAAQ,EAC3B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,QAAQ,EAAE;IAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EACjE,GAAG,GAAE,MAAmB,GACvB,cAAc,GAAG,SAAS,CAW5B"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// 113-B3(prime-agent #2375 形 + 超越点)— 账户级配额 429 的识别与类型化
|
|
2
|
+
// 停摆错误。
|
|
3
|
+
//
|
|
4
|
+
// 马拉松三次实证的问题形态:glm-5.3 账户级配额 429,错误体自带重置时刻——
|
|
5
|
+
// 429 [1308][已达到 5 小时的使用上限。您的限额将在 2026-09-24 05:30:32 重置。]
|
|
6
|
+
// 在位者(r1a Task 4)的裁决:Retry-After/等待 >60s 帽=硬停直接抛错。小时级
|
|
7
|
+
// 配额窗下这个"硬停"就是"整 run 报废"——基准马拉松里烧穿了两批任务。本模块
|
|
8
|
+
// 只把这一类错从"匿名硬停"升级为带 resetAt 的类型化 QuotaParkError:识别在
|
|
9
|
+
// HTTP 边界(与 ContextLengthError/MandatoryReasoning 同位、在通用
|
|
10
|
+
// ProviderHttpError 之前),梯子不重试它(isRetryableProviderError 的 name
|
|
11
|
+
// 判)、fallback 链不换腿(账户级配额是 provider 域,换模型烧的还是同一账
|
|
12
|
+
// 户),上层的 CLI 驱动据 resetAt 停摆 run 并排一次性唤醒。
|
|
13
|
+
//
|
|
14
|
+
// 语义红线:不改 60s 帽语义。≤60s 的配额等待(Retry-After 短、或重置时刻
|
|
15
|
+
// 30s 后就到)不分类——仍走既有梯子路径(Retry-After 精确等待,429 可重
|
|
16
|
+
// 试);无重置信息的普通 429 不误判——仍是 ProviderHttpError。只有"429 +
|
|
17
|
+
// 配额词表 + 可解析的重置时刻 + 距今 >60s"四条全中才升级。纯函数模块(只
|
|
18
|
+
// 依赖 retry-after 的帽常量,无环),永不触碰请求序列化(前缀缓存字节稳定)。
|
|
19
|
+
import { RETRY_AFTER_FAIL_CAP_MS } from "./retry-after.js";
|
|
20
|
+
/** The account/window-level usage-cap body vocabulary. Deliberately does NOT
|
|
21
|
+
* include bare "limit" — the context-length family ("maximum context
|
|
22
|
+
* length", "context_limit") shares the word, and those classify one branch
|
|
23
|
+
* earlier at the HTTP boundary (isContextLengthFailure) with disjoint
|
|
24
|
+
* statuses (413/400/500 vs this module's 429); pinning the vocabulary tight
|
|
25
|
+
* keeps the two families disjoint even if the ordering ever moves. */
|
|
26
|
+
export const QUOTA_BODY_SIGNATURES = [
|
|
27
|
+
/使用上限/, // glm/bigmodel 1308:已达到 5 小时的使用上限
|
|
28
|
+
/用量上限/,
|
|
29
|
+
/已达到.{0,12}上限/,
|
|
30
|
+
/限额将在/, // …您的限额将在 <时刻> 重置
|
|
31
|
+
/配额/,
|
|
32
|
+
/\bquota\b/i,
|
|
33
|
+
/usage\s+limit/i,
|
|
34
|
+
/rate\s*limit/i,
|
|
35
|
+
];
|
|
36
|
+
/** True when a 429 body carries a known account-quota signature. */
|
|
37
|
+
export function sniffQuotaBody(body) {
|
|
38
|
+
return QUOTA_BODY_SIGNATURES.some((re) => re.test(body));
|
|
39
|
+
}
|
|
40
|
+
/** The Chinese absolute reset wording: `将在 2026-09-24 05:30:32 重置`(本
|
|
41
|
+
* 地墙钟——服务中文错误体的网关按用户所在时区报时;`new Date("…T…")` 无
|
|
42
|
+
* 时区标记即按本地解析,正是这个语义)。秒可省。 */
|
|
43
|
+
const CN_RESET_RE = /(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}(?::\d{2})?)\s*重置/;
|
|
44
|
+
/** The English absolute wording: `resets at 2026-09-24T05:30:32Z` / `will
|
|
45
|
+
* reset on 2026-09-24 05:30:32`(带时区标记则尊重,缺省同中文款按本地)。 */
|
|
46
|
+
const EN_RESET_RE = /reset(?:s|ting)?\s+(?:at|on)\s+(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}(?::\d{2})?)\s*(Z|UTC|[+-]\d{2}:?\d{2})?/i;
|
|
47
|
+
/** Body-relative reset seconds: `Reset-After: 3600` / `"reset_after": 3600`
|
|
48
|
+
* (JSON 或散文形,纯秒数——分/时单位的散文不猜,trusted-parse-only)。 */
|
|
49
|
+
const RESET_AFTER_BODY_RE = /reset[-_ ]?after["']?\s*[:=]\s*"?(\d{1,8})"?/i;
|
|
50
|
+
function parseWallClock(date, time, zone) {
|
|
51
|
+
const at = Date.parse(zone !== undefined ? `${date}T${time}${zone === "UTC" ? "Z" : zone}` : `${date}T${time}`);
|
|
52
|
+
return Number.isFinite(at) ? new Date(at) : undefined;
|
|
53
|
+
}
|
|
54
|
+
/** Parse the provider's reset moment out of a 429 body (and, as the last
|
|
55
|
+
* resort, the already-parsed Retry-After header wait). Sources, first match
|
|
56
|
+
* wins: the Chinese absolute wording, the English absolute wording, a body
|
|
57
|
+
* `reset-after` seconds figure, the Retry-After header. Fail-closed:
|
|
58
|
+
* unparseable/past instants and non-positive header waits yield undefined
|
|
59
|
+
* (a past instant is the server's "already reset" — not park material; the
|
|
60
|
+
* ordinary ladder path owns it). */
|
|
61
|
+
export function parseQuotaResetAt(body, retryAfterMs, now = Date.now()) {
|
|
62
|
+
const cn = CN_RESET_RE.exec(body);
|
|
63
|
+
if (cn !== null) {
|
|
64
|
+
const at = parseWallClock(cn[1], cn[2], undefined);
|
|
65
|
+
if (at !== undefined && at.getTime() > now)
|
|
66
|
+
return at;
|
|
67
|
+
}
|
|
68
|
+
const en = EN_RESET_RE.exec(body);
|
|
69
|
+
if (en !== null) {
|
|
70
|
+
const at = parseWallClock(en[1], en[2], en[3]);
|
|
71
|
+
if (at !== undefined && at.getTime() > now)
|
|
72
|
+
return at;
|
|
73
|
+
}
|
|
74
|
+
const rel = RESET_AFTER_BODY_RE.exec(body);
|
|
75
|
+
if (rel !== null) {
|
|
76
|
+
const seconds = Number(rel[1]);
|
|
77
|
+
if (Number.isFinite(seconds) && seconds > 0)
|
|
78
|
+
return new Date(now + seconds * 1000);
|
|
79
|
+
}
|
|
80
|
+
if (retryAfterMs !== undefined && retryAfterMs > 0)
|
|
81
|
+
return new Date(now + retryAfterMs);
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
/** True iff the (status, body, deadline) triple is an account-level quota
|
|
85
|
+
* window past the 60s fail cap — the park candidate. All four gates must
|
|
86
|
+
* hold: HTTP 429, the quota vocabulary, a parseable reset moment, and a wait
|
|
87
|
+
* strictly beyond RETRY_AFTER_FAIL_CAP_MS (exactly-at-cap stays with the
|
|
88
|
+
* ladder — the existing `>` comparison). Everything else keeps today's
|
|
89
|
+
* semantics byte-for-byte. */
|
|
90
|
+
export function isQuotaParkFailure(status, body, retryAfterMs, now = Date.now()) {
|
|
91
|
+
if (status !== 429)
|
|
92
|
+
return false;
|
|
93
|
+
if (!sniffQuotaBody(body))
|
|
94
|
+
return false;
|
|
95
|
+
const resetAt = parseQuotaResetAt(body, retryAfterMs, now);
|
|
96
|
+
return resetAt !== undefined && resetAt.getTime() - now > RETRY_AFTER_FAIL_CAP_MS;
|
|
97
|
+
}
|
|
98
|
+
/** The typed account-quota failure (113-B3). Carries the parsed reset moment
|
|
99
|
+
* and the failing leg's provider identity — the CLI driver parks the run
|
|
100
|
+
* until resetAt (+margin) and schedules a one-shot wake. Message keeps a
|
|
101
|
+
* NON-transport prefix (`provider quota reached:` — deliberately not
|
|
102
|
+
* `provider (request|stream) failed: <status>`, so no message-regex consumer
|
|
103
|
+
* can misread it as a retryable status), and the name check in
|
|
104
|
+
* isRetryableProviderError makes the ladder's skip explicit regardless. */
|
|
105
|
+
export class QuotaParkError extends Error {
|
|
106
|
+
status;
|
|
107
|
+
body;
|
|
108
|
+
/** The parsed reset instant (see parseQuotaResetAt). */
|
|
109
|
+
resetAt;
|
|
110
|
+
/** v7 γ4 family: the failing leg's provider identity (registry id, or the
|
|
111
|
+
* baseURL host when the config carries no registry identity). */
|
|
112
|
+
provider;
|
|
113
|
+
constructor(which, status, body, resetAt, provider, model) {
|
|
114
|
+
const tail = model !== undefined && model !== "" ? `/${model}` : "";
|
|
115
|
+
super(`provider quota reached: ${status} ${body} — account usage cap, window resets at ${resetAt.toISOString()} (provider ${provider}${tail}); run parked until reset`);
|
|
116
|
+
this.name = "QuotaParkError";
|
|
117
|
+
this.status = status;
|
|
118
|
+
this.body = body;
|
|
119
|
+
this.resetAt = resetAt;
|
|
120
|
+
this.provider = provider;
|
|
121
|
+
if (model !== undefined && model !== "")
|
|
122
|
+
this.model = model;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/** Classify at the HTTP boundary: build the typed QuotaParkError when the
|
|
126
|
+
* (status, body, deadline) triple is a park candidate, undefined otherwise
|
|
127
|
+
* (the caller falls through to the generic ProviderHttpError — today's
|
|
128
|
+
* semantics). */
|
|
129
|
+
export function tryQuotaParkError(which, status, body, retryAfterMs, identity, now = Date.now()) {
|
|
130
|
+
if (!isQuotaParkFailure(status, body, retryAfterMs, now))
|
|
131
|
+
return undefined;
|
|
132
|
+
const resetAt = parseQuotaResetAt(body, retryAfterMs, now);
|
|
133
|
+
return new QuotaParkError(which, status, body, resetAt, identity.provider !== undefined && identity.provider !== "" ? identity.provider : "unknown", identity.model);
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=quota-park.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quota-park.js","sourceRoot":"","sources":["../src/quota-park.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Slice ceiling for the sliced re-check loop (CodeWhale C1's 250ms). */
|
|
2
|
+
export declare const RATE_PAUSE_SLICE_MS = 250;
|
|
3
|
+
/** Default pause when a 429 carries no Retry-After — the key pool's rate
|
|
4
|
+
* class cooldown (60s), so the provider dimension and the key dimension
|
|
5
|
+
* agree on how long a rate signal lasts. */
|
|
6
|
+
export declare const DEFAULT_RATE_PAUSE_MS = 60000;
|
|
7
|
+
export interface RatePauseWindow {
|
|
8
|
+
/** Wait out any active pause in ≤250ms slices; an abort signal breaks the
|
|
9
|
+
* loop with AbortError (the ladder never retries aborts — the caller's
|
|
10
|
+
* cancel survives the pause). No-op when idle. */
|
|
11
|
+
wait(signal?: AbortSignal): Promise<void>;
|
|
12
|
+
/** Extend the pause deadline (never shorten; clamped to the trust cap). */
|
|
13
|
+
trip(pauseMs: number): void;
|
|
14
|
+
/** A successful response proves the pause stale — reset to idle. */
|
|
15
|
+
clear(): void;
|
|
16
|
+
/** Current deadline in epoch ms; 0 when idle (assertions/observability). */
|
|
17
|
+
until(): number;
|
|
18
|
+
}
|
|
19
|
+
export interface RatePauseOptions {
|
|
20
|
+
/** Injectable clock (tests); default Date.now. */
|
|
21
|
+
readonly now?: () => number;
|
|
22
|
+
/** Injectable sleep (tests); default setTimeout-based. */
|
|
23
|
+
readonly sleep?: (ms: number) => Promise<void>;
|
|
24
|
+
/** Slice ceiling for wait(); default RATE_PAUSE_SLICE_MS. */
|
|
25
|
+
readonly sliceMs?: number;
|
|
26
|
+
}
|
|
27
|
+
export declare function createRatePauseWindow(options?: RatePauseOptions): RatePauseWindow;
|
|
28
|
+
//# sourceMappingURL=rate-pause.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-pause.d.ts","sourceRoot":"","sources":["../src/rate-pause.ts"],"names":[],"mappings":"AAgCA,yEAAyE;AACzE,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC;;6CAE6C;AAC7C,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC9B;;uDAEmD;IACnD,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,2EAA2E;IAC3E,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oEAAoE;IACpE,KAAK,IAAI,IAAI,CAAC;IACd,4EAA4E;IAC5E,KAAK,IAAI,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAMD,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,gBAAqB,GAAG,eAAe,CA+BrF"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// 波次 7 #37 (CodeWhale C1): the provider-level 429 pause window.
|
|
2
|
+
//
|
|
3
|
+
// The M56 key pool already handles the KEY dimension of a 429 — the limited
|
|
4
|
+
// key cools for every request through the shared pool. What it cannot handle
|
|
5
|
+
// is the PROVIDER dimension under concurrency: with a single key (or every
|
|
6
|
+
// key cooling), each concurrent request still enters its OWN retry ladder and
|
|
7
|
+
// hammers a provider that just said "stop" — under subagent fanout, N
|
|
8
|
+
// requests burn N ladders against the same rate limit (the self-harm CodeWhale
|
|
9
|
+
//'s C1 exists for). The window closes that gap:
|
|
10
|
+
//
|
|
11
|
+
// trip() — called at the HTTP boundary the moment a 429 arrives while the
|
|
12
|
+
// key pool has no healthy spare to rotate to (single-key, or all
|
|
13
|
+
// cooling). Deadline = the response's Retry-After when present,
|
|
14
|
+
// else the 60s rate-class default; never above the ladder's
|
|
15
|
+
// Retry-After trust cap, and never SHORTER than an existing
|
|
16
|
+
// deadline.
|
|
17
|
+
// wait() — the leg entry gate, before every generate/stream call. While a
|
|
18
|
+
// pause is active the caller re-checks the clock in ≤250ms
|
|
19
|
+
// slices (CodeWhale's sliced re-check) and fires its first HTTP
|
|
20
|
+
// attempt only after the window lapses. The originator's own
|
|
21
|
+
// ladder retries are NOT gated (they sit INSIDE one leg call): a
|
|
22
|
+
// transient 429 still recovers on its normal backoff — today's
|
|
23
|
+
// behavior, byte-for-byte.
|
|
24
|
+
// clear() — any 2xx proves the pause stale (the blip recovered); the next
|
|
25
|
+
// concurrent request enters immediately.
|
|
26
|
+
//
|
|
27
|
+
// The window is created once per provider factory closure (keyPool topology)
|
|
28
|
+
// and injectable whole through ProviderOptions.ratePauseWindow — tests drive
|
|
29
|
+
// it with a fake clock/sleep pair, embedders can share one window across
|
|
30
|
+
// protocol factories behind a single endpoint.
|
|
31
|
+
import { RETRY_AFTER_FAIL_CAP_MS } from "./retry-after.js";
|
|
32
|
+
/** Slice ceiling for the sliced re-check loop (CodeWhale C1's 250ms). */
|
|
33
|
+
export const RATE_PAUSE_SLICE_MS = 250;
|
|
34
|
+
/** Default pause when a 429 carries no Retry-After — the key pool's rate
|
|
35
|
+
* class cooldown (60s), so the provider dimension and the key dimension
|
|
36
|
+
* agree on how long a rate signal lasts. */
|
|
37
|
+
export const DEFAULT_RATE_PAUSE_MS = 60_000;
|
|
38
|
+
function defaultSleep(ms) {
|
|
39
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
40
|
+
}
|
|
41
|
+
export function createRatePauseWindow(options = {}) {
|
|
42
|
+
const now = options.now ?? Date.now;
|
|
43
|
+
const sleep = options.sleep ?? defaultSleep;
|
|
44
|
+
const sliceMs = options.sliceMs ?? RATE_PAUSE_SLICE_MS;
|
|
45
|
+
let deadline = 0;
|
|
46
|
+
const aborted = (signal) => {
|
|
47
|
+
const err = new Error("aborted while waiting out the provider rate pause");
|
|
48
|
+
err.name = "AbortError";
|
|
49
|
+
return err;
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
async wait(signal) {
|
|
53
|
+
while (deadline > now()) {
|
|
54
|
+
if (signal?.aborted === true)
|
|
55
|
+
throw aborted(signal);
|
|
56
|
+
const remaining = deadline - now();
|
|
57
|
+
await sleep(Math.min(sliceMs, remaining));
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
trip(pauseMs) {
|
|
61
|
+
const clamped = Math.max(0, Math.min(pauseMs, RETRY_AFTER_FAIL_CAP_MS));
|
|
62
|
+
deadline = Math.max(deadline, now() + clamped);
|
|
63
|
+
},
|
|
64
|
+
clear() {
|
|
65
|
+
deadline = 0;
|
|
66
|
+
},
|
|
67
|
+
until() {
|
|
68
|
+
return deadline;
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=rate-pause.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-pause.js","sourceRoot":"","sources":["../src/rate-pause.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,2EAA2E;AAC3E,8EAA8E;AAC9E,sEAAsE;AACtE,+EAA+E;AAC/E,gDAAgD;AAChD,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,6EAA6E;AAC7E,yEAAyE;AACzE,yEAAyE;AACzE,yBAAyB;AACzB,8EAA8E;AAC9E,wEAAwE;AACxE,6EAA6E;AAC7E,0EAA0E;AAC1E,8EAA8E;AAC9E,4EAA4E;AAC5E,wCAAwC;AACxC,6EAA6E;AAC7E,sDAAsD;AACtD,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,yEAAyE;AACzE,+CAA+C;AAC/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,yEAAyE;AACzE,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEvC;;6CAE6C;AAC7C,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAwB5C,SAAS,YAAY,CAAC,EAAU;IAC9B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,UAA4B,EAAE;IAClE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,YAAY,CAAC;IAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,mBAAmB,CAAC;IACvD,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,MAAM,OAAO,GAAG,CAAC,MAAmB,EAAS,EAAE;QAC7C,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QAC3E,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC;QACxB,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,IAAI,CAAC,MAAoB;YAC7B,OAAO,QAAQ,GAAG,GAAG,EAAE,EAAE,CAAC;gBACxB,IAAI,MAAM,EAAE,OAAO,KAAK,IAAI;oBAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;gBACpD,MAAM,SAAS,GAAG,QAAQ,GAAG,GAAG,EAAE,CAAC;gBACnC,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QACD,IAAI,CAAC,OAAe;YAClB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC;YACxE,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC;QACjD,CAAC;QACD,KAAK;YACH,QAAQ,GAAG,CAAC,CAAC;QACf,CAAC;QACD,KAAK;YACH,OAAO,QAAQ,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type { ProviderProfile, ReasoningEffort, ReasoningFormat, WindowMode } from "./config.js";
|
|
2
|
+
import type { ProtocolId } from "./persona/types.js";
|
|
3
|
+
import { type ModelPrices } from "./pricing.js";
|
|
4
|
+
/** One catalog entry: a model name plus its optional context window and
|
|
5
|
+
* (借鉴弧 B1) its optional doc-verified prices — the catalog face the cache
|
|
6
|
+
* economics ratio derives from. A pin exists ONLY where the number comes
|
|
7
|
+
* from the provider's own docs (same policy as contextLength). */
|
|
8
|
+
export interface ProviderModelEntry {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly contextLength?: number;
|
|
11
|
+
readonly prices?: ModelPrices;
|
|
12
|
+
}
|
|
13
|
+
/** The user-facing slice of a profile (registry file shape). Every field is
|
|
14
|
+
* optional; unknown fields are ignored for forward compatibility. */
|
|
15
|
+
export interface UserProviderConfig {
|
|
16
|
+
readonly label?: string;
|
|
17
|
+
readonly baseUrl?: string;
|
|
18
|
+
readonly defaultModel?: string;
|
|
19
|
+
readonly reasoningFormat?: ReasoningFormat;
|
|
20
|
+
readonly windowMode?: WindowMode;
|
|
21
|
+
readonly defaultContextLength?: number;
|
|
22
|
+
readonly models?: readonly ProviderModelEntry[];
|
|
23
|
+
readonly thinkingLevelMap?: ProviderProfile["thinkingLevelMap"];
|
|
24
|
+
readonly supportsReasoningEffort?: boolean;
|
|
25
|
+
readonly acceptsReasoningOnlyFinish?: boolean;
|
|
26
|
+
readonly requiresBaseUrl?: boolean;
|
|
27
|
+
/** SDD 2026-08-23 persona Task 4 — the per-provider persona binding, a
|
|
28
|
+
* THREE-STATE column (spec §2): key absent = follow the global default;
|
|
29
|
+
* a non-empty string = bound persona id; explicit null = forced none.
|
|
30
|
+
* Deliberately NOT part of EffectiveProfile — it is binding-chain data
|
|
31
|
+
* (read by the CLI's readProviderPersonaBinding), never a profile fact,
|
|
32
|
+
* so the effectiveProfiles merge never touches it. */
|
|
33
|
+
readonly persona?: string | null;
|
|
34
|
+
/** SDD 2026-08-24 reg-headers Task 1 (92 §3.4-1); ω99-64 on the wire —
|
|
35
|
+
* per-provider extra request headers (the enterprise-gateway baseline).
|
|
36
|
+
* CONTROLLER RULING (ω99-64): the old "deliberately never an
|
|
37
|
+
* EffectiveProfile fact" stance is REVERSED. Unlike `persona` (binding-
|
|
38
|
+
* chain data with its own lifecycle, still profile-external), headers are
|
|
39
|
+
* a TRANSPORT-LAYER fact of the endpoint — the same class as baseUrl /
|
|
40
|
+
* wire / balanceUrl (gateway-fronting facts). They fold through the
|
|
41
|
+
* effectiveProfiles overlay merge (overlay-beats-builtin for free) and
|
|
42
|
+
* ride to request construction as ProviderConfig.extraHeaders, spread
|
|
43
|
+
* behind adapter auth and ahead of persona wire.headers. FORBIDDEN keys
|
|
44
|
+
* (auth/transport-control, single source persona/schema) refuse the row
|
|
45
|
+
* at save AND load — a registry row can structurally never override the
|
|
46
|
+
* adapter's credentials or transport headers. */
|
|
47
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
48
|
+
/** 0.3.13 (#215, user trial feedback): the PROTOCOL this row speaks —
|
|
49
|
+
* "openai-chat" | "anthropic" | "responses". Absent = the dispatch
|
|
50
|
+
* default (openai-chat), byte-identical to the historical shape. Unlike
|
|
51
|
+
* persona/headers this IS a profile fact: the effectiveProfiles merge
|
|
52
|
+
* folds it into EffectiveProfile.wire, where resolveProviderConfigResult
|
|
53
|
+
* already consults it (selection.wire > env > profile.wire) — so a
|
|
54
|
+
* custom Anthropic-protocol provider needs NO WUDAO_WIRE once saved. */
|
|
55
|
+
readonly wire?: ProtocolId;
|
|
56
|
+
/** P0-4 (96 队列): the row's wallet-balance endpoint. A profile fact like
|
|
57
|
+
* wire: an explicit overlay value beats the builtin's compiled-in pin,
|
|
58
|
+
* and a custom's own value rides through — the /cost all wallet face
|
|
59
|
+
* resolves it from the effective profile view. */
|
|
60
|
+
readonly balanceUrl?: string;
|
|
61
|
+
/** 2026-08-28 推理档三级配置 S1 — the per-provider reasoning-effort
|
|
62
|
+
* binding, a THREE-STATE column mirroring `persona`: key absent = follow
|
|
63
|
+
* the global default (model.defaultEffort); a string = bound level (a
|
|
64
|
+
* REASONING_EFFORTS member); explicit null = don't send the param at all
|
|
65
|
+
* (distinct from the literal "none" level, which IS a wire value). Like
|
|
66
|
+
* persona, deliberately never an EffectiveProfile fact — the CLI's
|
|
67
|
+
* effort resolution chain reads it (readProviderEffortBinding). */
|
|
68
|
+
readonly effort?: string | null;
|
|
69
|
+
/** ω99-245: #5 — the capability-catalog OVERRIDE column: what THIS
|
|
70
|
+
* endpoint accepts, wholesale-replacing the compiled-in family set (and
|
|
71
|
+
* its model pins) in supportedEfforts. The user's escape hatch for a new
|
|
72
|
+
* model or an outdated catalog pin — fail-closed but never bricked. A
|
|
73
|
+
* non-empty array of REASONING_EFFORTS members (validated fail-visibly:
|
|
74
|
+
* junk must never silently widen the gate). Unlike `effort` above this IS
|
|
75
|
+
* an EffectiveProfile fact (like headers/wire), read through the
|
|
76
|
+
* effective view. */
|
|
77
|
+
readonly efforts?: readonly ReasoningEffort[];
|
|
78
|
+
}
|
|
79
|
+
/** The registry file: version-gated from v1, malformed files load as empty. */
|
|
80
|
+
export interface ProviderRegistryFile {
|
|
81
|
+
readonly version: 1;
|
|
82
|
+
readonly providers: Record<string, UserProviderConfig>;
|
|
83
|
+
}
|
|
84
|
+
/** A load outcome: the entries that validated, plus one row per entry that
|
|
85
|
+
* did not (fail-visible — the UI lists them; boot never blocks on them). */
|
|
86
|
+
export interface RegistryLoadResult {
|
|
87
|
+
readonly entries: ReadonlyMap<string, UserProviderConfig>;
|
|
88
|
+
readonly invalid: readonly {
|
|
89
|
+
id: string;
|
|
90
|
+
reason: string;
|
|
91
|
+
}[];
|
|
92
|
+
}
|
|
93
|
+
/** A ProviderProfile extended with the registry-only facts: the per-model
|
|
94
|
+
* catalog (empty for builtins unless an overlay supplies one — the builtin
|
|
95
|
+
* defaultModel never joins it), the provider-level context-window default,
|
|
96
|
+
* whether the id is user-registered (custom) or compiled in, and (ω99-245)
|
|
97
|
+
* the optional capability-catalog override the effort preflight reads. */
|
|
98
|
+
export type EffectiveProfile = ProviderProfile & {
|
|
99
|
+
readonly models: readonly ProviderModelEntry[];
|
|
100
|
+
readonly defaultContextLength?: number;
|
|
101
|
+
readonly custom: boolean;
|
|
102
|
+
/** The supported-efforts override (see UserProviderConfig.efforts).
|
|
103
|
+
* Absent on every builtin; present exactly when a registry row declares it. */
|
|
104
|
+
readonly efforts?: readonly ReasoningEffort[];
|
|
105
|
+
};
|
|
106
|
+
/** Where the registry lives. Mirrors the CLI's global-home resolution so
|
|
107
|
+
* tests/CI isolate the whole ~/.wudao tier with one env var. */
|
|
108
|
+
export declare function defaultProviderRegistryPath(env?: NodeJS.ProcessEnv): string;
|
|
109
|
+
/** Validate one registry entry. Returns the SANITIZED config (unknown fields
|
|
110
|
+
* dropped) or the reason it was refused. A builtin id may overlay without a
|
|
111
|
+
* baseUrl; a custom id must carry one — it IS the provider. */
|
|
112
|
+
export declare function validateUserProviderEntry(id: string, cfg: unknown): {
|
|
113
|
+
ok: true;
|
|
114
|
+
value: UserProviderConfig;
|
|
115
|
+
} | {
|
|
116
|
+
ok: false;
|
|
117
|
+
reason: string;
|
|
118
|
+
};
|
|
119
|
+
/** Read + validate the registry. Fault-tolerant by contract: a missing file
|
|
120
|
+
* is an empty registry; a malformed file (bad JSON, wrong version, wrong
|
|
121
|
+
* shape) demotes to empty entries with ONE file-level invalid row; a bad
|
|
122
|
+
* ENTRY costs only that entry. Never throws. */
|
|
123
|
+
export declare function readProviderRegistrySync(path?: string): RegistryLoadResult;
|
|
124
|
+
/** Atomically write the registry (tmp + rename, 0600 — same shape as the
|
|
125
|
+
* global settings writer). Creates the parent directory when missing. */
|
|
126
|
+
export declare function writeProviderRegistrySync(path: string, file: ProviderRegistryFile): void;
|
|
127
|
+
/** Merge validated user entries onto the compiled-in profiles:
|
|
128
|
+
* - builtin ids always present; an entry for one overlays field-by-field
|
|
129
|
+
* (`overlay ?? base`, the FULL profile surface — reasoning fields included);
|
|
130
|
+
* - other ids become customs (requiresBaseUrl pinned true; the entry's
|
|
131
|
+
* baseUrl becomes defaultBaseUrl; reasoningFormat defaults to "none").
|
|
132
|
+
* `models` on an overlay REPLACES the builtin catalog wholesale (the
|
|
133
|
+
* builtins' own doc-verified context pins included); the builtin
|
|
134
|
+
* defaultModel never joins it. A custom entry without a baseUrl
|
|
135
|
+
* is defensively skipped — read-time validation is what reports it. */
|
|
136
|
+
export declare function effectiveProfiles(userEntries: ReadonlyMap<string, UserProviderConfig>): ReadonlyMap<string, EffectiveProfile>;
|
|
137
|
+
/** The context-window resolution chain (§7): the model's registered
|
|
138
|
+
* contextLength, else the provider's default, else the caller-supplied env
|
|
139
|
+
* value (already resolved: WUDAO_CONTEXT_WINDOW ?? 200_000). Pure — no fs, no
|
|
140
|
+
* env reads of its own. */
|
|
141
|
+
export declare function resolveContextWindowTokens(profiles: ReadonlyMap<string, EffectiveProfile>, providerId: string, model: string, envValue: number): number;
|
|
142
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|