@eddyskywalker/dsh-chatgpt-subscription 0.20.0 → 0.22.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +51 -1
  3. package/lib/client.js +2674 -528
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +7712 -2590
  6. package/lib/types/client/glm-coding-plan/GlmCodingPlanSection.d.ts.map +1 -1
  7. package/lib/types/client/glm-coding-plan/locales.d.ts +11 -17
  8. package/lib/types/client/glm-coding-plan/locales.d.ts.map +1 -1
  9. package/lib/types/client/glm-coding-plan/styles.d.ts +2 -2
  10. package/lib/types/client/glm-coding-plan/styles.d.ts.map +1 -1
  11. package/lib/types/client/hub/brand-icons.d.ts +2 -2
  12. package/lib/types/client/hub/brand-icons.d.ts.map +1 -1
  13. package/lib/types/client/hub/providers.d.ts.map +1 -1
  14. package/lib/types/client/index.d.ts +2 -0
  15. package/lib/types/client/index.d.ts.map +1 -1
  16. package/lib/types/client/ollama/OllamaSection.d.ts.map +1 -1
  17. package/lib/types/client/ollama/api.d.ts +2 -2
  18. package/lib/types/client/ollama/api.d.ts.map +1 -1
  19. package/lib/types/client/step-code/StepCodeComposerQuota.d.ts +52 -0
  20. package/lib/types/client/step-code/StepCodeComposerQuota.d.ts.map +1 -0
  21. package/lib/types/client/step-code/StepCodeSection.d.ts +28 -0
  22. package/lib/types/client/step-code/StepCodeSection.d.ts.map +1 -0
  23. package/lib/types/client/step-code/api.d.ts +4 -0
  24. package/lib/types/client/step-code/api.d.ts.map +1 -0
  25. package/lib/types/client/step-code/locales.d.ts +648 -0
  26. package/lib/types/client/step-code/locales.d.ts.map +1 -0
  27. package/lib/types/client/step-code/styles.d.ts +28 -0
  28. package/lib/types/client/step-code/styles.d.ts.map +1 -0
  29. package/lib/types/client/step-code/useStepCodeSection.d.ts +122 -0
  30. package/lib/types/client/step-code/useStepCodeSection.d.ts.map +1 -0
  31. package/lib/types/host/antigravity/account-pool.d.ts.map +1 -1
  32. package/lib/types/host/common/account-pool.d.ts +38 -3
  33. package/lib/types/host/common/account-pool.d.ts.map +1 -1
  34. package/lib/types/host/common/model-request-control.d.ts +1 -1
  35. package/lib/types/host/common/model-request-control.d.ts.map +1 -1
  36. package/lib/types/host/common/request-diagnostics.d.ts +1 -1
  37. package/lib/types/host/common/request-diagnostics.d.ts.map +1 -1
  38. package/lib/types/host/glm-coding-plan/account-pool.d.ts.map +1 -1
  39. package/lib/types/host/ollama/adapter.d.ts.map +1 -1
  40. package/lib/types/host/ollama/routes.d.ts.map +1 -1
  41. package/lib/types/host/ollama/token-store.d.ts +8 -3
  42. package/lib/types/host/ollama/token-store.d.ts.map +1 -1
  43. package/lib/types/host/step-code/account-pool.d.ts +187 -0
  44. package/lib/types/host/step-code/account-pool.d.ts.map +1 -0
  45. package/lib/types/host/step-code/adapter.d.ts +142 -0
  46. package/lib/types/host/step-code/adapter.d.ts.map +1 -0
  47. package/lib/types/host/step-code/adopt.d.ts +201 -0
  48. package/lib/types/host/step-code/adopt.d.ts.map +1 -0
  49. package/lib/types/host/step-code/cache-stats.d.ts +181 -0
  50. package/lib/types/host/step-code/cache-stats.d.ts.map +1 -0
  51. package/lib/types/host/step-code/client.d.ts +331 -0
  52. package/lib/types/host/step-code/client.d.ts.map +1 -0
  53. package/lib/types/host/step-code/mapper.d.ts +301 -0
  54. package/lib/types/host/step-code/mapper.d.ts.map +1 -0
  55. package/lib/types/host/step-code/model-catalog.d.ts +230 -0
  56. package/lib/types/host/step-code/model-catalog.d.ts.map +1 -0
  57. package/lib/types/host/step-code/oauth.d.ts +265 -0
  58. package/lib/types/host/step-code/oauth.d.ts.map +1 -0
  59. package/lib/types/host/step-code/routes.d.ts +126 -0
  60. package/lib/types/host/step-code/routes.d.ts.map +1 -0
  61. package/lib/types/host/step-code/token-store.d.ts +325 -0
  62. package/lib/types/host/step-code/token-store.d.ts.map +1 -0
  63. package/lib/types/host/step-code/types.d.ts +488 -0
  64. package/lib/types/host/step-code/types.d.ts.map +1 -0
  65. package/lib/types/host/workbuddy/adapter.d.ts.map +1 -1
  66. package/lib/types/index.d.ts +5 -0
  67. package/lib/types/index.d.ts.map +1 -1
  68. package/lib/types/shared/ollama-contracts.d.ts +8 -1
  69. package/lib/types/shared/ollama-contracts.d.ts.map +1 -1
  70. package/lib/types/shared/step-code-contracts.d.ts +438 -0
  71. package/lib/types/shared/step-code-contracts.d.ts.map +1 -0
  72. package/package.json +1 -1
@@ -0,0 +1,331 @@
1
+ /**
2
+ * Step Code 线路的上游 I/O:模型目录 + 开发者中心额度。
3
+ *
4
+ * 本文件只做两件事:**把请求发到上游**,以及**把上游的载荷翻译成本线路的形状**。
5
+ * 传输(发送模型请求、拆流)不在这里——那是 mapper.ts / adapter.ts 的活。
6
+ *
7
+ * ---------------------------------------------------------------------------
8
+ * 三条必须记住的上游事实(逐字证据在每处注释里)
9
+ * ---------------------------------------------------------------------------
10
+ *
11
+ * 1. **base 归一化是幂等循环,不是 endsWith 判断。**
12
+ * 官方 normalizeStepApiBaseUrl(step-provider/index.ts:378-400)反复剥掉尾部的
13
+ * /v1/messages、/messages、/v1,因为历史配置里出现过**重复后缀**(/v1/v1/messages):
14
+ * 一次 endsWith 只能修好一层,两层就还剩一层。本文件照抄那个循环。
15
+ *
16
+ * 2. **逐模型详情在域名根的 /v1,不在 /step_plan/v1。**
17
+ * index.ts:420-426:the subpath variant 404s。所以 stepModelDetailUrl 走
18
+ * {origin}/v1/models/{id},而列表走 {归一化 base}/v1/models。
19
+ * 这两条**故意不一样**,合并它们就是那个 404。
20
+ *
21
+ * 3. **额度失败绝不影响模型请求。**
22
+ * 额度面是**非公开接口**(计划 §5、§10 风险 1),上游改一次路径或字段就全失效。
23
+ * 所以额度的一切都返回**值**(StepCodeQuotaRead),没有一条路径把错误抛给调用方
24
+ * 之外的边界:调用方不需要 try/catch 就能安全地把额度塞进状态面。
25
+ *
26
+ * ---------------------------------------------------------------------------
27
+ * 注入缝
28
+ * ---------------------------------------------------------------------------
29
+ * 每个网络函数都接受 fetchFn(默认 fetch)与 env(默认 process.env),
30
+ * 且 env **在调用时**读取(不是模块加载时),这样单测不碰真实网络也不碰真实凭据。
31
+ */
32
+ import { type StepCodeProfile, type StepCodeQuotaSnapshotDto, type StepCodeRegion } from '../../shared/step-code-contracts.ts';
33
+ export interface StepCodeRequestOptions {
34
+ /** 测试缝。默认 fetch。 */
35
+ fetchFn?: typeof fetch;
36
+ signal?: AbortSignal;
37
+ /** 环境变量读取处。默认 process.env,且**调用时**读取。 */
38
+ env?: NodeJS.ProcessEnv;
39
+ }
40
+ /** 错误详情去控制字符并截断到 MAX_ERROR_DETAIL_LENGTH(逐字 login-client.ts:39)。 */
41
+ export declare function stepCodeErrorDetail(text: string, limit?: number): string;
42
+ /**
43
+ * 本线路发上游请求只需要的三件事:一个 key、它属于哪条 profile、(可选)账号标识。
44
+ *
45
+ * 这是**号池凭据的结构化超集**:account-pool.ts 的 StepCodeCredentials 就是它加一个
46
+ * 来源标记,所以本文件的每个函数都能直接吃号池交出来的凭据,而不必认识池。
47
+ */
48
+ export interface StepCodeUpstreamCredential {
49
+ readonly apiKey: string;
50
+ readonly profile: StepCodeProfile;
51
+ readonly uid?: string;
52
+ }
53
+ /**
54
+ * 模型面请求的头(逐字 index.ts:453-456:只有 accept 与 authorization)。
55
+ *
56
+ * 刻意**不加** user-agent:官方目录请求就这两个头,凭空多一个头不会让目录多返回
57
+ * 一个字段,却会让「我们发的与官方一致」这句话变成假的。
58
+ */
59
+ export declare function stepCodeModelHeaders(credentials: StepCodeUpstreamCredential): Record<string, string>;
60
+ /**
61
+ * 把任意写法的 Step base 归一化成**路由前缀**(不带尾部斜杠、不带版本段)。
62
+ *
63
+ * 逐字照抄官方 normalizeStepApiBaseUrl(index.ts:378-400),包括它的理由:
64
+ * /v1/messages、/messages、/v1 三种尾部**反复**剥,直到剥不动为止。官方的原话是
65
+ * Be tolerant of files produced by an intermediate release that already contained
66
+ * one duplicated suffix——所以用循环而不是 if。
67
+ *
68
+ * 非法 URL 原样返回(与官方一致):校验是 provider resolver 的职责,而这个导出函数
69
+ * 也会被拿去修复已有配置,坏条目应当留给正常的校验去报错。
70
+ */
71
+ export declare function normalizeStepApiBaseUrl(value: string): string;
72
+ /**
73
+ * 一条 profile 的模型面 base(**已归一化**的路由前缀)。
74
+ *
75
+ * 取值来自 apiBaseForProfile(含环境变量覆盖),归一化在这里做掉,于是所有调用点
76
+ * 拼路径时不会把版本段发两次。
77
+ */
78
+ export declare function stepApiRoutePrefix(profile: StepCodeProfile, env?: NodeJS.ProcessEnv): string;
79
+ /**
80
+ * OpenAI 风格 base(.../v1),逐字照抄官方 stepOpenAiBaseUrl(index.ts:410-412)。
81
+ *
82
+ * step_plan → https://api.stepfun.com/step_plan/v1;platform_cn → .../v1。
83
+ */
84
+ export declare function stepOpenAiBaseUrl(profile: StepCodeProfile, env?: NodeJS.ProcessEnv): string;
85
+ /** 对话请求 URL:{归一化 base}/v1/chat/completions。 */
86
+ export declare function stepChatCompletionsUrl(profile: StepCodeProfile, env?: NodeJS.ProcessEnv): string;
87
+ /** 目录请求 URL:{归一化 base}/v1/models。 */
88
+ export declare function stepModelCatalogUrl(profile: StepCodeProfile, env?: NodeJS.ProcessEnv): string;
89
+ /**
90
+ * 逐模型详情的 base:**域名根的 /v1**(逐字 index.ts:414-426)。
91
+ *
92
+ * 反直觉但是必须:/step_plan/v1/models/{id} 会 404。解析不出域名时退回归一化 base,
93
+ * 与官方一致(官方那句 Falls back to the input if it is not a valid URL)。
94
+ */
95
+ export declare function stepModelDetailBaseUrl(profile: StepCodeProfile, env?: NodeJS.ProcessEnv): string;
96
+ /** 逐模型详情 URL:{域名根}/v1/models/{encodeURIComponent(id)}。 */
97
+ export declare function stepModelDetailUrl(profile: StepCodeProfile, modelId: string, env?: NodeJS.ProcessEnv): string;
98
+ /**
99
+ * 目录里的一条模型,**只含端点真的报了的字段**。
100
+ *
101
+ * modelType / maxInputTokens / description 允许缺失是刻意的:计划 §10 风险 2 明说这些
102
+ * 字段都不在官方文档里,**一律按可能缺失处理**。能力**不从模型名推断**(计划 §3)。
103
+ */
104
+ export interface StepCodeCatalogEntry {
105
+ readonly id: string;
106
+ readonly name: string;
107
+ readonly modelType?: string;
108
+ readonly maxInputTokens?: number;
109
+ readonly reasoning: boolean;
110
+ readonly vision: boolean;
111
+ /** reasoning_effort_support_list;空数组表示端点没声明或一个都不支持。 */
112
+ readonly efforts: readonly string[];
113
+ readonly description: string | null;
114
+ }
115
+ /**
116
+ * 解析 GET {base}/v1/models 的载荷。
117
+ *
118
+ * 逐字照抄官方 fetchStepModels 的读法(index.ts:462-494),三条规则各有理由:
119
+ *
120
+ * - **id 必填,缺失就跳过**(index.ts:470):没有 id 的条目既无法被请求也无法被选中。
121
+ * - **model_type 的过滤是二元的**(index.ts:481-486):只保留**存在该字段**的条目里
122
+ * USABLE_MODEL_TYPES 的两个字面量;**全部条目都不带该字段时整表不过滤**——
123
+ * 那是更老的/别的端点,向后兼容比过滤更重要。
124
+ * - **按 id 去重**(index.ts:487-491):同一 id 出现两次时取第一次。
125
+ *
126
+ * 纯函数、导出:格式规则可以脱离文件系统与网络被测试。
127
+ */
128
+ export declare function parseStepModelCatalog(payload: unknown): StepCodeCatalogEntry[];
129
+ /** 无凭据 / 失败 / 离线时目录为空:调用方回落随包表,而不是抛错。 */
130
+ export declare function fetchStepModelCatalog(credentials: StepCodeUpstreamCredential, options?: StepCodeRequestOptions): Promise<StepCodeCatalogEntry[]>;
131
+ /** 本进程当前记住的目录(纯内存读,不触发任何网络请求)。 */
132
+ export declare function getCachedStepModelCatalog(profile?: StepCodeProfile): readonly StepCodeCatalogEntry[];
133
+ /** 清掉内存目录、快照 scope 与在飞的去重。 */
134
+ export declare function clearCachedStepModelCatalog(): void;
135
+ /**
136
+ * TTL 缓存 + in-flight 去重 + 磁盘快照的目录读取。
137
+ *
138
+ * 三层各解决一件事,照抄 workbuddy/client.ts:397-491:
139
+ *
140
+ * - **TTL**:目录不是快变数据,半小时的陈旧比一次网络往返划算。
141
+ * - **in-flight 去重**:同一个 profile 上并发的两个调用共用一次请求。
142
+ * - **磁盘快照**(catalog-snapshot.ts):冷启动不等网络。快照按 profile 分文件,
143
+ * 所以国际区的列表不会把国区调用方喂成空。
144
+ *
145
+ * force: true 跳过缓存与快照直接重取(设置卡片的「刷新」按钮用)。
146
+ */
147
+ export declare function loadStepModelCatalog(credentials: StepCodeUpstreamCredential, options?: StepCodeRequestOptions & {
148
+ force?: boolean;
149
+ }): Promise<StepCodeCatalogEntry[]>;
150
+ /**
151
+ * 逐模型档位:GET {域名根}/v1/models/{id} 的顶层 reasoning_effort_support_list。
152
+ *
153
+ * 逐字照抄官方 fetchStepModelEfforts(index.ts:532-552):**任何**失败都返回
154
+ * undefined 而不是抛错或返回空数组——「没取到」与「这个模型一个档位都不支持」是两句
155
+ * 话,前者不能被后者冒充。
156
+ *
157
+ * 注意它读的是**顶层**字段,不是 data 里的一份列表(官方就这么读)。
158
+ */
159
+ export declare function fetchStepModelEfforts(credentials: StepCodeUpstreamCredential, modelId: string, options?: StepCodeRequestOptions): Promise<string[] | undefined>;
160
+ /**
161
+ * 老式载荷的 reset 时间字段名(逐字:计划 §5 的「+ *_reset_time」)。
162
+ *
163
+ * types.ts 的 QUOTA_LEGACY_FIELDS 只收了两个 left_rate,没收它们的 reset 字段名,
164
+ * 所以这两个常量暂住本文件;**待上提到 types.ts**(避免下个波次再抄一遍)。
165
+ */
166
+ export declare const STEP_QUOTA_LEGACY_RESET_FIELDS: {
167
+ readonly fiveHour: "five_hour_reset_time";
168
+ readonly weekly: "weekly_reset_time";
169
+ };
170
+ /**
171
+ * 套餐状态里的套餐名 / 续费时刻候选字段。
172
+ *
173
+ * ⚠ **未验证**:GetStepPlanStatus 的响应形状没有任何公开文档,本表按常见写法列了几种,
174
+ * 取到第一个非空值就用,取不到就是 null(卡片少一个字段,而不是显示一个编的值)。
175
+ * 待上提到 types.ts。
176
+ */
177
+ export declare const STEP_QUOTA_STATUS_FIELDS: {
178
+ readonly planName: readonly ["plan_name", "package_name", "product_name", "name"];
179
+ readonly renewAt: readonly ["renew_time", "renew_at", "expire_time", "expires_at"];
180
+ };
181
+ /** OASIS 匿名设备 Cookie 名(逐字:计划 §5 的 GET {auth} 取 INGRESSCOOKIE)。 */
182
+ export declare const OASIS_INGRESS_COOKIE = "INGRESSCOOKIE";
183
+ /** 额度凭据的来源,与冻结契约的 StepCodeQuotaCredentialStatusDto['source'] 同一组取值。 */
184
+ export type StepCodeQuotaCredentialSource = 'auto' | 'manual';
185
+ /**
186
+ * 开发者中心的额度凭据:Oasis-Token + 与它成对的 Oasis-Webid。
187
+ *
188
+ * **两个字段必须一起流动**:服务端要求 Oasis-Webid 等于该 token 的 device_id claim,
189
+ * 否则报「token is embezzled」(计划 §10 风险 5)。所以它不是「一个 token 加一个可以
190
+ * 随便填的头」,而是一对凭据。
191
+ *
192
+ * ⚠ 它等价于一次账号登录,**永远不过 host → client 的边界**;下发的是
193
+ * StepCodeQuotaCredentialStatusDto 那张「有没有、从哪来」的切片。
194
+ */
195
+ export interface StepCodeQuotaCredential {
196
+ readonly token: string;
197
+ readonly deviceId: string;
198
+ readonly source: StepCodeQuotaCredentialSource;
199
+ /** 非机密:登录用到的账号,仅供卡片显示是哪一路凭据在服务。 */
200
+ readonly account?: string;
201
+ /** 过期时刻(Unix 毫秒);上游未给出时为 null。 */
202
+ readonly expiresAt?: number | null;
203
+ }
204
+ /**
205
+ * 从 token 的 JWT 载荷里取 device_id claim;取不出(不是 JWT / 没有这个 claim)时
206
+ * 返回 undefined。**在本地解码**,token 绝不发给任何地方去解析(照 codex-adopt.ts)。
207
+ *
208
+ * 找不到签名密钥,也就不验证签名——这里只是把服务端已经签过的那句话读出来用。
209
+ */
210
+ export declare function oasisDeviceIdFromToken(token: string): string | undefined;
211
+ /**
212
+ * 手动粘贴兜底:用户在浏览器开发者工具里复制 Oasis-Token,deviceId 顺带从 token 里解。
213
+ *
214
+ * 解不出 device_id 时**直接失败**,而不是让用户随便填一个:填错的上游会报
215
+ * 「token is embezzled」,那比这里一句「这个 token 里没有 device_id」难查得多。
216
+ */
217
+ export declare function manualStepCodeQuotaCredential(token: string, options?: {
218
+ account?: string;
219
+ }): StepCodeQuotaCredential;
220
+ /** 自动登录失败时给卡片的一句话:降级到手动粘贴,而不是让用户反复重试密码。 */
221
+ export declare const OASIS_MANUAL_PASTE_HINT = "\u81EA\u52A8\u767B\u5F55\u5931\u8D25\u3002\u8BF7\u6253\u5F00 Step \u5F00\u53D1\u8005\u4E2D\u5FC3\uFF0C\u5728\u6D4F\u89C8\u5668\u5F00\u53D1\u8005\u5DE5\u5177\u91CC\u590D\u5236 Oasis-Token \u5E76\u7C98\u8D34\u5230\u8BBE\u7F6E\u9875\u3002";
222
+ /**
223
+ * 自动登录失败时抛出的错误:带一句「下一步做什么」,而不是把上游原文丢给用户。
224
+ */
225
+ export declare class OasisSignInError extends Error {
226
+ /** 面向用户的下一步(手动粘贴兜底)。 */
227
+ readonly hint: string;
228
+ constructor(message: string);
229
+ }
230
+ export interface StepCodeOasisSignInInput {
231
+ /** 走哪个区域的开发者中心(profile 唯一决定)。 */
232
+ readonly profile: StepCodeProfile;
233
+ /** 账号(手机号 / 邮箱,按 Step 的登录口径)。 */
234
+ readonly account: string;
235
+ readonly password: string;
236
+ readonly fetchFn?: typeof fetch;
237
+ readonly signal?: AbortSignal;
238
+ readonly env?: NodeJS.ProcessEnv;
239
+ }
240
+ /**
241
+ * 账号密码换 Oasis-Token,三步(逐字:计划 §5)。
242
+ *
243
+ * 1. `GET {authBase}` 取 `Set-Cookie: INGRESSCOOKIE=…`(网关的匿名 cookie)。
244
+ * 2. `POST …/PassportService/RegisterDevice` 注册设备,换匿名 token。
245
+ * 3. `POST …/PassportService/SignInByPassword` 用账号密码换 Oasis-Token。
246
+ *
247
+ * 失败一律抛 {@link OasisSignInError}:调用方据此降级到「手动粘贴」(计划 §5)。
248
+ * 账号密码**只出现在这一步的请求体里**,不写日志、不落盘、不进任何返回值。
249
+ *
250
+ * ⚠ 请求体字段名**未验证**(这两个接口不属于任何公开契约),按常见写法给最小集合。
251
+ */
252
+ export declare function signInOasisQuotaCredential(input: StepCodeOasisSignInInput): Promise<StepCodeQuotaCredential>;
253
+ /**
254
+ * 把多次应答合成一份载荷(浅合并,后者覆盖前者)。
255
+ *
256
+ * 两个接口是分开打的,而套餐名/续费时刻只在一个里、额度窗口只在另一个里;
257
+ * 合成之后再判定,才不会因为「先打的那个不认识」就把一代套餐判成 unknown。
258
+ */
259
+ export declare function mergeStepQuotaPayloads(...payloads: readonly unknown[]): Record<string, unknown>;
260
+ export interface StepCodeQuotaParseContext {
261
+ /** 读到的开发者中心属于哪个区域(由 profile 唯一决定)。 */
262
+ readonly region: StepCodeRegion;
263
+ /** 实际应答过的端点路径,供设置卡片诊断(计划 §5:sources 记实际打过的路径)。 */
264
+ readonly sources: readonly string[];
265
+ /** 本次读取时刻;缺省用现在。 */
266
+ readonly fetchedAt?: number;
267
+ }
268
+ /**
269
+ * 把 devcenter 载荷翻译成 StepCodeQuotaSnapshotDto。
270
+ *
271
+ * **按载荷形状判定两代套餐,不单信 plan_family**(计划 §5 的加粗句):
272
+ *
273
+ * - 老式:顶层 five_hour_usage_left_rate / weekly_usage_left_rate + *_reset_time。
274
+ * - 新式:plan_credit_rate_limit.{subscription_credit_left_rate, topup_credit_left_rate,
275
+ * credit_buckets[]},桶的每项是 {credit_total, credit_residual, expire_at, next_reset_at}。
276
+ *
277
+ * 两代都认不出来时 kind = 'unknown',**不发明**第三条形状。
278
+ * 数字字段三种写法(int / float / 数字字符串)、时间戳两种形态(数字 / 字符串)都收,
279
+ * 见本文件顶部的 asNumber / asTimestampMs。
280
+ *
281
+ * 纯函数、导出:形状规则可以脱离网络被测试。
282
+ */
283
+ export declare function parseStepQuotaSnapshot(payload: unknown, context: StepCodeQuotaParseContext): StepCodeQuotaSnapshotDto;
284
+ /**
285
+ * 一次额度读取的结果。
286
+ *
287
+ * 刻意**不**是 throw:额度面是非公开接口,而它的失败绝不能影响模型请求
288
+ *(计划 §5、§10 风险 1)。调用方拿到 {ok:false, error} 就能把失败写进状态面,
289
+ * 不必把 try/catch 铺到每个调用点。
290
+ */
291
+ export type StepCodeQuotaRead = {
292
+ readonly ok: true;
293
+ readonly snapshot: StepCodeQuotaSnapshotDto;
294
+ } | {
295
+ readonly ok: false;
296
+ readonly error: string;
297
+ };
298
+ /**
299
+ * 读一次额度;两个接口都失败时返回 {ok:false},**不抛**。
300
+ *
301
+ * 先打 QueryStepPlanRateLimit(额度窗口 / Credit 池),再打 GetStepPlanStatus
302
+ *(套餐名与续费时刻)。第二个打不通不影响第一个的结果:它只补展示字段。
303
+ * sources 记的是**实际应答过**的路径,而不是打算要打的路径。
304
+ */
305
+ export declare function readStepQuota(quotaCredential: StepCodeQuotaCredential, profile: StepCodeProfile, options?: StepCodeRequestOptions): Promise<StepCodeQuotaRead>;
306
+ /**
307
+ * 额度快照的缓存键。
308
+ *
309
+ * **额度跟着账号走**(共享号池契约的原话):一次轮转决定哪个账号花下一次请求,
310
+ * 线路级的一份读数描述的是「恰好轮到的那个账号」。所以键里带账号标识;
311
+ * 账号标识缺失时退回 profile —— 代价是两个都没有 uid 的账号共用一份读数,
312
+ * 那仍然是「我们只知道这么多」,不是编的数字。
313
+ */
314
+ export declare function stepCodeQuotaCacheKey(profile: StepCodeProfile, accountId?: string | null): string;
315
+ /** 本进程为某个账号记住的最新额度快照(纯内存读,从不发请求)。 */
316
+ export declare function getCachedStepQuotaFor(accountId?: string | null): StepCodeQuotaSnapshotDto | undefined;
317
+ /** 一次成功读取之后由调用方登记(键与 stepCodeQuotaCacheKey 一致)。 */
318
+ export declare function rememberStepQuotaSnapshot(accountId: string, snapshot: StepCodeQuotaSnapshotDto): void;
319
+ /** 清掉额度缓存与在飞去重(登录/切号时调用)。 */
320
+ export declare function clearCachedStepQuota(): void;
321
+ /**
322
+ * 带 TTL 与 in-flight 去重的额度读取。
323
+ *
324
+ * TTL = QUOTA_CACHE_TTL_MS;force: true 跳过缓存(设置卡片的「刷新」)。
325
+ * 失败**不缓存**:非公开接口改版后恢复得很快,缓存住一个失败只会让用户多等一个 TTL。
326
+ */
327
+ export declare function loadStepQuota(quotaCredential: StepCodeQuotaCredential, profile: StepCodeProfile, options?: StepCodeRequestOptions & {
328
+ force?: boolean;
329
+ cacheKey?: string;
330
+ }): Promise<StepCodeQuotaRead>;
331
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/host/step-code/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Wire mapping for the Step Code (Step Plan subscription) chat endpoint.
3
+ *
4
+ * The endpoint is OpenAI Chat Completions shaped — every Step profile
5
+ * (`step_plan`, `step_plan_oversea`, `platform_cn`, `platform_oversea`)
6
+ * answers `{base}/v1/chat/completions` with the standard SSE frames (official
7
+ * `step-provider/index.ts:88` pins one dialect, `STEP_MODEL_API =
8
+ * "openai-completions"`, for every model). This module therefore looks like its
9
+ * WorkBuddy / GLM siblings and exists to absorb the places where Step is not
10
+ * OpenAI:
11
+ *
12
+ * 1. **The output cap is `max_tokens`, never `max_completion_tokens`.**
13
+ * Step's Chat Completions documentation defines only `max_tokens`. The
14
+ * official client picks the field from a detected `compat.maxTokensField`
15
+ * (`openai-completions.ts:816-819`); this route hardwires the documented one
16
+ * instead of running detection per request.
17
+ * 2. **Cache reads are reported at the TOP LEVEL as `usage.cached_tokens`.**
18
+ * That is the field Step's own documentation names as the hit criterion
19
+ * (`cached_tokens > 0`), and it is NOT in this repository's shared diagnostic
20
+ * parse chain (`common/request-diagnostics.ts:406-409` reads
21
+ * `prompt_tokens_details.cached_tokens` → `cache_read_input_tokens` →
22
+ * `cache_read_tokens`). So this route carries its own chain, driven by the
23
+ * frozen `STEP_CODE_CACHE_READ_FIELD_ORDER`; see {@link parseStepCodeUsage}.
24
+ * 3. **Caching is automatic and parameterless.** The server keeps an automatic
25
+ * prefix cache (a prefix of at least 256 tokens hits, LRU eviction, no request
26
+ * field). The official client sends nothing at all to a Step endpoint:
27
+ * `prompt_cache_key` is gated on `baseUrl.includes("api.openai.com")`
28
+ * (`openai-completions.ts:799-801`), session-affinity headers are off for Step,
29
+ * and `cache_control` only exists on the Anthropic wire. This module follows
30
+ * that default exactly and adds `prompt_cache_key` only behind an explicit
31
+ * caller flag; see {@link stepCodePromptCacheKey}.
32
+ * 4. **There is no cache write to report, and no price to report.** Automatic
33
+ * prefix caching has no client-visible write step, so `cacheWriteTokens` is 0
34
+ * on this route and the route says so out loud
35
+ * (`STEP_CODE_CACHE_WRITE_NOTE`). Every Step model lists all-zero prices
36
+ * (`MODEL_DEFAULTS.cost`, `step-provider/index.ts:102`), so money is derived
37
+ * from that table instead of a guessed rate — see
38
+ * {@link STEP_CODE_PRICE_PER_MILLION_TOKENS}.
39
+ *
40
+ * ## Why the constants are imported, not restated
41
+ *
42
+ * Every ladder, ceiling and default below comes from `./types.ts`,
43
+ * `./model-catalog.ts` or `../../shared/step-code-contracts.ts`. Writing a
44
+ * second copy of a value is how a route starts lying: upstream moves one step of
45
+ * a ladder and this file keeps sending the old one, with no test and no compile
46
+ * error pointing at it. `STEP_CODE_CACHE_READ_FIELD_ORDER` is even walked at
47
+ * runtime rather than transcribed, so adding a rung upstream changes the parse
48
+ * here without a second edit.
49
+ *
50
+ * ## Division of labour
51
+ *
52
+ * The request URL is NOT assembled here: the caller owns the base URL because the
53
+ * region profile decides it, and this file performs no network I/O at all (fetch,
54
+ * SSE reading and byte decoding belong to the transport layer). Like the sibling
55
+ * routes the adapter owns the transport: it builds the body with
56
+ * {@link buildChatRequest}, feeds SSE lines to {@link processStreamLine}, flushes
57
+ * with {@link closeStream}, checks {@link assertStreamComplete}, and turns a
58
+ * non-2xx response into an `LlmError` with {@link classifyStepCodeFailure}.
59
+ *
60
+ * @module dsh-chatgpt-subscription/step-code-mapper
61
+ */
62
+ import { CHAT_COMPLETIONS_PATH, STEP_CODE_EFFORTS } from './types.ts';
63
+ import type { StepCodeModelEntry } from './model-catalog.ts';
64
+ import { STEP_CODE_CACHE_READ_FIELD_ORDER, STEP_CODE_CACHE_WRITE_NOTE, STEP_CODE_PROMPT_CACHE_KEY_MAX_LENGTH, type StepCodeReasoningEffort } from '../../shared/step-code-contracts.ts';
65
+ import { LlmError, type GenerateOptions, type OutboundContentBlock, type StreamChunk, type TokenUsage } from '../common/llm-compat.ts';
66
+ import { resolveRequestImages, type AttachmentImageReader, type ResolvedRequestImage, type ResolvedRequestImages } from '../common/request-images.ts';
67
+ export { CHAT_COMPLETIONS_PATH, STEP_CODE_EFFORTS, STEP_CODE_CACHE_WRITE_NOTE };
68
+ export { STEP_CODE_CACHE_READ_FIELD_ORDER, STEP_CODE_PROMPT_CACHE_KEY_MAX_LENGTH };
69
+ export { resolveRequestImages };
70
+ export type { AttachmentImageReader, ResolvedRequestImage, ResolvedRequestImages, StepCodeReasoningEffort };
71
+ /** One selectable thinking level on the Step endpoint. */
72
+ export type { StepCodeReasoningEffort as StepCodeEffort };
73
+ /**
74
+ * Price of one million tokens on every Step model: zero, read from the catalog.
75
+ *
76
+ * `MODEL_DEFAULTS.cost` hardwires `{ input: 0, output: 0, cacheRead: 0,
77
+ * cacheWrite: 0 }` — the upstream table was never filled in, and Step Plan is a
78
+ * subscription rather than a metered SKU. Deriving the number from that table
79
+ * keeps this value honest if the table is ever completed: a route that
80
+ * multiplied tokens by an invented rate would show a plausible, wrong number,
81
+ * while zero is the only defensible one. The card shows the token dimension
82
+ * alone (see `STEP_CODE_PRICING_STATUS` in the shared contracts).
83
+ */
84
+ export declare const STEP_CODE_PRICE_PER_MILLION_TOKENS: 0;
85
+ /**
86
+ * Base64 image payload one request may carry on this route.
87
+ *
88
+ * Step publishes no per-request image ceiling, so this is a defensive budget
89
+ * rather than a documented limit: it mirrors the sibling OpenAI-shaped WorkBuddy
90
+ * route (12 MB) and exists so a runaway conversation degrades to placeholders
91
+ * instead of growing a body the transport has to carry. Lower it once a real
92
+ * Step ceiling has been measured — the offload mechanism itself is shared.
93
+ */
94
+ export declare const STEP_CODE_MAX_REQUEST_IMAGE_BYTES: number;
95
+ /**
96
+ * The shared image budget, for a caller that prefers the plugin's conservative
97
+ * ceiling to {@link STEP_CODE_MAX_REQUEST_IMAGE_BYTES}.
98
+ */
99
+ export declare const STEP_CODE_SHARED_IMAGE_BUDGET = 1500000;
100
+ /**
101
+ * Replace the oldest inline images with a visible placeholder once one request
102
+ * would exceed {@link STEP_CODE_MAX_REQUEST_IMAGE_BYTES}.
103
+ *
104
+ * Durable history is untouched; only the request about to be sent changes, and
105
+ * the budget is passed in rather than inherited so this route's ceiling and the
106
+ * shared default stay two separate decisions.
107
+ */
108
+ export declare function offloadOldestStepCodeRequestImages(options: GenerateOptions, images?: ResolvedRequestImages): GenerateOptions;
109
+ /**
110
+ * Reasoning effort to put on the wire, or undefined to omit the field.
111
+ *
112
+ * Delegates to the line's own {@link convergeStepCodeEffort}, which snaps the
113
+ * caller's effort onto the ladder THIS model declared in
114
+ * `reasoning_effort_support_list` and answers null for an empty ladder. Two
115
+ * outcomes matter here and both mean "do not send": an absent/blank request, and
116
+ * a model that declares no effort field at all. Nothing outside the declared
117
+ * ladder ever reaches the body — an effort the endpoint does not list is a
118
+ * rejected request, not a rounded-down preference.
119
+ */
120
+ export declare function resolveStepCodeReasoningEffort(requested: unknown, ladder: readonly string[]): StepCodeReasoningEffort | undefined;
121
+ /**
122
+ * `prompt_cache_key` for this request, or undefined to send no cache field.
123
+ *
124
+ * THE default is undefined. Step's server-side cache is automatic and takes no
125
+ * parameter, and the official client sends no cache parameter to a Step endpoint
126
+ * at all — `prompt_cache_key` is gated on
127
+ * `baseUrl.includes("api.openai.com")` (`openai-completions.ts:799-801`),
128
+ * session-affinity headers are disabled for Step, and `prompt_cache_retention`
129
+ * (24h) is an undocumented field this route never sends either. The key is
130
+ * therefore behind the caller's explicit `cacheRequestParams` flag, so a
131
+ * deployment that measured the endpoint's acceptance can turn it on and one that
132
+ * did not sends exactly what the official client sends.
133
+ */
134
+ export declare function stepCodePromptCacheKey(options: GenerateOptions, request: StepCodeRequestOptions): string | undefined;
135
+ /**
136
+ * Clamp a session id to {@link STEP_CODE_PROMPT_CACHE_KEY_MAX_LENGTH} code
137
+ * points, or undefined when there is nothing to key on.
138
+ */
139
+ export declare function clampStepCodePromptCacheKey(sessionId: string | undefined): string | undefined;
140
+ /** Per-request knobs the wire needs but the conversation does not carry. */
141
+ export interface StepCodeRequestOptions {
142
+ /** Whether the selected model declares image input (`enable_vision_input`). */
143
+ supportsImages?: boolean;
144
+ /**
145
+ * Output ceiling to use when the caller stated none; normally the catalog
146
+ * entry's `defaultMaxTokens`. Falls back to the line's own rule ("no reported
147
+ * output cap, so equal to the input window").
148
+ */
149
+ defaultMaxTokens?: number;
150
+ /**
151
+ * Efforts this model declared (`reasoning_effort_support_list`). Empty — the
152
+ * undeclared-model row — means no effort field is sent at all.
153
+ */
154
+ reasoningEfforts?: readonly string[];
155
+ /**
156
+ * Whether to send the optional `prompt_cache_key`. Off by default, exactly
157
+ * like the official client on a Step endpoint; see
158
+ * {@link stepCodePromptCacheKey}. This is a per-settings capability bit, not a
159
+ * model property, which is why {@link stepCodeRequestOptionsFor} leaves it to
160
+ * the caller.
161
+ */
162
+ cacheRequestParams?: boolean;
163
+ }
164
+ /** Factory defaults: images gated off, no cache parameter, no ladder. */
165
+ export declare const DEFAULT_STEP_CODE_REQUEST_OPTIONS: StepCodeRequestOptions;
166
+ /**
167
+ * The wire knobs for one catalog row.
168
+ *
169
+ * Exists so the field-by-field copy from a catalog entry lives in exactly one
170
+ * place: the adapter resolves the entry and only has to add the two things that
171
+ * are not model properties — the cache capability bit and a caller override of
172
+ * the output ceiling. An unknown model yields the undeclared row's facts (no
173
+ * ladder, no images), which is what makes "never send a field the endpoint does
174
+ * not declare" the default path rather than a special case.
175
+ */
176
+ export declare function stepCodeRequestOptionsFor(entry: StepCodeModelEntry | undefined, overrides?: {
177
+ cacheRequestParams?: boolean;
178
+ defaultMaxTokens?: number;
179
+ }): StepCodeRequestOptions;
180
+ /**
181
+ * Build one `{base}/v1/chat/completions` body.
182
+ *
183
+ * Always `stream: true` with `stream_options: { include_usage: true }`: the
184
+ * cache numbers this line exists to report arrive on the terminal frame, and
185
+ * there is no non-streaming path to keep in sync. The output cap is
186
+ * `max_tokens`, the field Step documents (see the module note).
187
+ *
188
+ * Session-folded tool history has no field on this wire, so the complete tool
189
+ * declarations are sent every request — the documented behaviour of omitting
190
+ * `toolHistory`, not a silent drop of it.
191
+ */
192
+ export declare function buildChatRequest(options: GenerateOptions, images?: ResolvedRequestImages, request?: StepCodeRequestOptions): Record<string, unknown>;
193
+ /** One usage frame read off the wire, already normalized. */
194
+ export interface StepCodeParsedUsage {
195
+ /** The endpoint's aggregate prompt count, before the cache split. */
196
+ promptTokens: number;
197
+ /** Uncached input, disjoint from the two cache buckets. */
198
+ inputTokens: number;
199
+ outputTokens: number;
200
+ cacheReadTokens: number;
201
+ cacheWriteTokens: number;
202
+ reasoningTokens: number;
203
+ }
204
+ /**
205
+ * Cache reads for one usage frame, walking the frozen
206
+ * `STEP_CODE_CACHE_READ_FIELD_ORDER`.
207
+ *
208
+ * The order is NOT restated here — it is the shared contract's array, walked in
209
+ * order — for two reasons. The third rung is the one this route lives or dies by:
210
+ * top-level `usage.cached_tokens` is the field Step's documentation shows and
211
+ * the one its hit criterion (`> 0`) is written against, while the repository's
212
+ * shared diagnostic chain (`common/request-diagnostics.ts:406-409`) has no rung
213
+ * for it. And a second hand-written list of the same four names is exactly the
214
+ * shape that rots the first time upstream reorders or extends it.
215
+ *
216
+ * The fifth rung is `0`, meaning "the endpoint reported nothing" rather than
217
+ * "nothing hit"; hit or miss is judged against the prefix length upstream.
218
+ */
219
+ export declare function readCacheReadTokens(usage: Record<string, unknown>): number;
220
+ /**
221
+ * Normalize one `usage` object into DSH's disjoint counters.
222
+ *
223
+ * Cache writes are read only from `prompt_tokens_details.cache_write_tokens`,
224
+ * which this endpoint never reports (automatic prefix cache), so the value is 0
225
+ * here — see {@link STEP_CODE_CACHE_WRITE_NOTE}. It still takes part in the
226
+ * subtraction so an endpoint that does report one is accounted correctly.
227
+ * Reasoning tokens are OpenAI's own detail field; completion_tokens already
228
+ * includes them, so nothing is subtracted there.
229
+ */
230
+ export declare function parseStepCodeUsage(raw: unknown): StepCodeParsedUsage | undefined;
231
+ interface PendingToolCall {
232
+ blockIndex: number;
233
+ id: string;
234
+ name: string;
235
+ arguments: string;
236
+ started: boolean;
237
+ }
238
+ /** Accumulated state of one Step streaming response. */
239
+ export interface StepCodeStreamState {
240
+ blocks: OutboundContentBlock[];
241
+ current: OpenTextBlock | null;
242
+ /** wire tool index -> accumulating call. */
243
+ toolCalls: Map<number, PendingToolCall>;
244
+ hasContent: boolean;
245
+ hasToolCall: boolean;
246
+ finishReason: string | null;
247
+ /** The `[DONE]` sentinel arrived. */
248
+ done: boolean;
249
+ /** Terminal chunks were already emitted. */
250
+ finished: boolean;
251
+ inputTokens: number;
252
+ outputTokens: number;
253
+ cacheReadTokens: number;
254
+ cacheWriteTokens: number;
255
+ reasoningTokens: number;
256
+ sawUsage: boolean;
257
+ }
258
+ interface OpenTextBlock {
259
+ index: number;
260
+ type: 'text' | 'reasoning';
261
+ text: string;
262
+ }
263
+ export declare function createStreamState(): StepCodeStreamState;
264
+ /**
265
+ * Feed one SSE line from `{base}/v1/chat/completions`.
266
+ *
267
+ * Heartbeats and comment frames (": ping") carry no `data:` prefix and produce
268
+ * nothing here. The caller pulses its idle watchdog on bytes and on complete
269
+ * frames, so a keep-alive neither becomes content nor stalls the stream: an empty
270
+ * payload and a frame with no choices both fall through to an empty chunk list,
271
+ * which is a no-op rather than an end-of-stream.
272
+ */
273
+ export declare function processStreamLine(line: string, state: StepCodeStreamState): StreamChunk[];
274
+ /** The DSH accounting for one response, with cache fields omitted when zero. */
275
+ export declare function streamTokenUsage(state: StepCodeStreamState): TokenUsage;
276
+ /**
277
+ * Flush every open block, then emit usage and the terminal finish.
278
+ *
279
+ * Order is a hard requirement: DSH settles a call on `finish`, so usage that
280
+ * arrives after it is never booked.
281
+ */
282
+ export declare function closeStream(state: StepCodeStreamState): StreamChunk[];
283
+ /**
284
+ * A stream that ends without a terminal event is truncated, not complete.
285
+ *
286
+ * Chat Completions always terminates with `finish_reason` or `[DONE]`, so their
287
+ * absence means the connection dropped mid-answer and the partial text must not
288
+ * be presented as a finished reply.
289
+ */
290
+ export declare function assertStreamComplete(state: StepCodeStreamState): void;
291
+ /**
292
+ * Classify one non-2xx response into a DSH failure.
293
+ *
294
+ * The codes are the harness's shared vocabulary rather than this line's own, so
295
+ * the account pool recognises `AUTH` ("this account must sign in again") and no
296
+ * retry set picks up an exhausted-plan verdict. Context overflow is reclassified
297
+ * through `isHttpContextOverflow` so the harness can compact and retry instead
298
+ * of showing the user a raw window error.
299
+ */
300
+ export declare function classifyStepCodeFailure(status: number, detail: string): LlmError;
301
+ //# sourceMappingURL=mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["../../../../src/host/step-code/mapper.ts"],"names":[],"mappings":"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"}