@eddyskywalker/dsh-chatgpt-subscription 0.21.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.
- package/CHANGELOG.md +27 -0
- package/README.md +51 -1
- package/lib/client.js +2661 -516
- package/lib/client.js.map +1 -1
- package/lib/index.js +7657 -2573
- package/lib/types/client/glm-coding-plan/GlmCodingPlanSection.d.ts.map +1 -1
- package/lib/types/client/glm-coding-plan/locales.d.ts +11 -17
- package/lib/types/client/glm-coding-plan/locales.d.ts.map +1 -1
- package/lib/types/client/glm-coding-plan/styles.d.ts +2 -2
- package/lib/types/client/glm-coding-plan/styles.d.ts.map +1 -1
- package/lib/types/client/hub/brand-icons.d.ts +2 -2
- package/lib/types/client/hub/brand-icons.d.ts.map +1 -1
- package/lib/types/client/hub/providers.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +2 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/step-code/StepCodeComposerQuota.d.ts +52 -0
- package/lib/types/client/step-code/StepCodeComposerQuota.d.ts.map +1 -0
- package/lib/types/client/step-code/StepCodeSection.d.ts +28 -0
- package/lib/types/client/step-code/StepCodeSection.d.ts.map +1 -0
- package/lib/types/client/step-code/api.d.ts +4 -0
- package/lib/types/client/step-code/api.d.ts.map +1 -0
- package/lib/types/client/step-code/locales.d.ts +648 -0
- package/lib/types/client/step-code/locales.d.ts.map +1 -0
- package/lib/types/client/step-code/styles.d.ts +28 -0
- package/lib/types/client/step-code/styles.d.ts.map +1 -0
- package/lib/types/client/step-code/useStepCodeSection.d.ts +122 -0
- package/lib/types/client/step-code/useStepCodeSection.d.ts.map +1 -0
- package/lib/types/host/antigravity/account-pool.d.ts.map +1 -1
- package/lib/types/host/common/account-pool.d.ts +38 -3
- package/lib/types/host/common/account-pool.d.ts.map +1 -1
- package/lib/types/host/common/model-request-control.d.ts +1 -1
- package/lib/types/host/common/model-request-control.d.ts.map +1 -1
- package/lib/types/host/common/request-diagnostics.d.ts +1 -1
- package/lib/types/host/common/request-diagnostics.d.ts.map +1 -1
- package/lib/types/host/glm-coding-plan/account-pool.d.ts.map +1 -1
- package/lib/types/host/step-code/account-pool.d.ts +187 -0
- package/lib/types/host/step-code/account-pool.d.ts.map +1 -0
- package/lib/types/host/step-code/adapter.d.ts +142 -0
- package/lib/types/host/step-code/adapter.d.ts.map +1 -0
- package/lib/types/host/step-code/adopt.d.ts +201 -0
- package/lib/types/host/step-code/adopt.d.ts.map +1 -0
- package/lib/types/host/step-code/cache-stats.d.ts +181 -0
- package/lib/types/host/step-code/cache-stats.d.ts.map +1 -0
- package/lib/types/host/step-code/client.d.ts +331 -0
- package/lib/types/host/step-code/client.d.ts.map +1 -0
- package/lib/types/host/step-code/mapper.d.ts +301 -0
- package/lib/types/host/step-code/mapper.d.ts.map +1 -0
- package/lib/types/host/step-code/model-catalog.d.ts +230 -0
- package/lib/types/host/step-code/model-catalog.d.ts.map +1 -0
- package/lib/types/host/step-code/oauth.d.ts +265 -0
- package/lib/types/host/step-code/oauth.d.ts.map +1 -0
- package/lib/types/host/step-code/routes.d.ts +126 -0
- package/lib/types/host/step-code/routes.d.ts.map +1 -0
- package/lib/types/host/step-code/token-store.d.ts +325 -0
- package/lib/types/host/step-code/token-store.d.ts.map +1 -0
- package/lib/types/host/step-code/types.d.ts +488 -0
- package/lib/types/host/step-code/types.d.ts.map +1 -0
- package/lib/types/host/workbuddy/adapter.d.ts.map +1 -1
- package/lib/types/index.d.ts +5 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/step-code-contracts.d.ts +438 -0
- package/lib/types/shared/step-code-contracts.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Step Code(Step Plan 订阅)线路的 DSH 适配器。
|
|
3
|
+
*
|
|
4
|
+
* 形状与 GLM / WorkBuddy 同构(`extends LlmAdapter`:`listModels` / `resolveModel` /
|
|
5
|
+
* `prepareCall` / `stream` / `catalog` / `credentialFor`),但它**不碰任何协议细节**:
|
|
6
|
+
*
|
|
7
|
+
* - 请求体、流解析、用量与错误分类全部来自 `./mapper.ts`;
|
|
8
|
+
* - URL 全部来自 `./client.ts`(`stepChatCompletionsUrl` / `stepModelCatalogUrl`);
|
|
9
|
+
* - 目录的归一化全部来自 `./model-catalog.ts`。
|
|
10
|
+
*
|
|
11
|
+
* 也就是说本文件只回答三件事:**这一行请求用哪个目录行**、**用哪把凭据**、
|
|
12
|
+
* **失败之后换不换账号**。任何一份 URL 拼接或 JSON 解析在这里出现第二遍,
|
|
13
|
+
* 就等于给线路造了第二条会漂移的真相。
|
|
14
|
+
*
|
|
15
|
+
* 三处刻意如此:
|
|
16
|
+
*
|
|
17
|
+
* 1. **凭据只在 `credentialFor()` 一处取。** 有号池时轮转,没有池时读单凭据存储
|
|
18
|
+
* (无头 host 与测试的形态)。两条路径都**不刷新**:Step 的 api_key 永不过期,
|
|
19
|
+
* 号池的 refresh 钩子恒抛 `StepCodeCredentialRefreshError`,所以这里没有「捕获后重登」
|
|
20
|
+
* 这种分支——上游撤销一把 Key 的唯一诚实的处置是 401 时的 `markAuthFailed`。
|
|
21
|
+
* 2. **请求路径不联网。** 目录只读 `client.ts` 的进程内缓存,随包目录兜底;
|
|
22
|
+
* 实时目录是 `/catalog/refresh` 与登录/adopt 的产物。
|
|
23
|
+
* 3. **缓存用量在本进程累计。** 累计器住在本文件(流的末端是唯一知道用量帧的地方),
|
|
24
|
+
* `/status` 由 `readStepCodeCacheStats()` 读它;路由不另算第二套口径。
|
|
25
|
+
*/
|
|
26
|
+
import { LlmAdapter, type GenerateOptions, type LlmModelInfo, type LlmProviderInfo, type LlmResolvedModelInfo, type PreparedAdapterCall, type ResolvedRetryPolicy, type StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
27
|
+
import type { AttachmentImageReader } from '../common/request-images.ts';
|
|
28
|
+
import { type StepCodeCacheUsage } from './cache-stats.ts';
|
|
29
|
+
import { type StepCodeCatalogEntry, type StepCodeUpstreamCredential } from './client.ts';
|
|
30
|
+
import { type StepCodeModelEntry } from './model-catalog.ts';
|
|
31
|
+
import { StepCodeCredentialStore, StepCodeModelSettingsStore, type StepCodePreferenceStore } from './token-store.ts';
|
|
32
|
+
import type { StepCodeAccountPool } from './account-pool.ts';
|
|
33
|
+
import { PROVIDER_ID, PROVIDER_NAME } from './types.ts';
|
|
34
|
+
import type { StepCodeCacheStatsDto, StepCodeProfile } from '../../shared/step-code-contracts.ts';
|
|
35
|
+
/**
|
|
36
|
+
* 这条路由的瞬时故障重试策略,与兄弟线路逐字一致。
|
|
37
|
+
*
|
|
38
|
+
* 刻意不在集合里:AUTH(被拒的 Key 每次都一样,而它只能重新授权)、
|
|
39
|
+
* PROVIDER_ERROR(400 或套餐拒绝)、ABORTED(调用方自己取消)。
|
|
40
|
+
*/
|
|
41
|
+
export declare const STEP_CODE_RETRY_POLICY_CONFIG: {
|
|
42
|
+
mode: 'normal';
|
|
43
|
+
maxRetries: number;
|
|
44
|
+
retryableCodes: string[];
|
|
45
|
+
backoff: {
|
|
46
|
+
initialDelayMs: number;
|
|
47
|
+
maxDelayMs: number;
|
|
48
|
+
jitterRatio: number;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
/** 上游没有给 `Retry-After` 时,一次 429 按 5 分钟冷却。 */
|
|
52
|
+
export declare const STEP_CODE_POOL_COOLDOWN_MS: number;
|
|
53
|
+
/**
|
|
54
|
+
* 目录缓存 → 能力行。
|
|
55
|
+
*
|
|
56
|
+
* `client.ts` 的缓存装的是 `StepCodeCatalogEntry`(**只含端点真的报了的字段**),
|
|
57
|
+
* 而请求面与设置面要的是 `model-catalog.ts` 的 `StepCodeModelEntry`。
|
|
58
|
+
* 这里把前者还原成上游载荷再交给 {@link parseStepCodeModelListing},而不是自己映射一遍:
|
|
59
|
+
* 档位表、`model_type` 过滤、上下文窗口兜底与 hint 生成都因此只有**一份**实现。
|
|
60
|
+
*
|
|
61
|
+
* 还原是等价的:缓存条目里每个字段都对应上游记录里的同名键,
|
|
62
|
+
* 而 `model_type` 的过滤在 `client.ts` 已经按同一条规则做过一次,
|
|
63
|
+
* 再跑一遍得到同一份集合(缓存里要么全带 `model_type` 要么全不带)。
|
|
64
|
+
*/
|
|
65
|
+
export declare function stepCodeModelCatalogFrom(entries: readonly StepCodeCatalogEntry[]): StepCodeModelEntry[];
|
|
66
|
+
/**
|
|
67
|
+
* 这个部署能调的模型:**进程内缓存优先、随包目录兜底,请求路径上绝不联网**。
|
|
68
|
+
*
|
|
69
|
+
* 实时目录只由 `/catalog/refresh` 与登录/adopt 产生(见 `routes.ts`),
|
|
70
|
+
* 卡片打开时就能把它同步好;让每一次模型解析都去打上游只会把设置页变成一条压测。
|
|
71
|
+
*/
|
|
72
|
+
export declare function cachedStepCodeModelCatalog(profile?: StepCodeProfile): readonly StepCodeModelEntry[];
|
|
73
|
+
/** 设置卡片渲染的模型总数(hub 概览与状态共用同一份读数)。 */
|
|
74
|
+
export declare function stepCodeCatalogSize(): number;
|
|
75
|
+
/**
|
|
76
|
+
* 记下一次请求的用量(流读到终止帧之后调用)。
|
|
77
|
+
*
|
|
78
|
+
* 口径全部借自 `cache-stats.ts` 的 {@link promptTokensOf}——它是本线路对
|
|
79
|
+
* 「聚合 prompt = 未命中 + 缓存读入 + 缓存写入」的唯一写法,这里不再复述一遍。
|
|
80
|
+
*/
|
|
81
|
+
export declare function rememberStepCodeCacheUsage(usage: StepCodeCacheUsage): void;
|
|
82
|
+
/**
|
|
83
|
+
* 卡片要的那份切片;**尚无样本时返回 undefined**。
|
|
84
|
+
*
|
|
85
|
+
* 「还没有样本」与「样本全都没命中」必须能被区分:契约里 `cacheStats` 是可选的,
|
|
86
|
+
* 客户端把缺失渲染成占位符、把 0 渲染成真实的 0%,所以这里绝不下发一个全 0 的对象。
|
|
87
|
+
*/
|
|
88
|
+
export declare function readStepCodeCacheStats(): StepCodeCacheStatsDto | undefined;
|
|
89
|
+
/** 一行请求要用的凭据:发请求只需要 `client.ts` 认得的那三件事。 */
|
|
90
|
+
export interface StepCodePickedCredential {
|
|
91
|
+
/** 号池里的账号 id;无池(单凭据路径)时为 null。 */
|
|
92
|
+
accountId: string | null;
|
|
93
|
+
credentials: StepCodeUpstreamCredential;
|
|
94
|
+
}
|
|
95
|
+
export interface StepCodeAdapterOptions {
|
|
96
|
+
fetchFn?: typeof fetch;
|
|
97
|
+
attachments?: AttachmentImageReader;
|
|
98
|
+
/** 多账号号池;缺省走单凭据路径(无头 host 与测试)。 */
|
|
99
|
+
accountPool?: StepCodeAccountPool;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Step Code(Step Plan 订阅)线路的 LlmAdapter 实现。
|
|
103
|
+
*
|
|
104
|
+
* 请求面只有一个:四条 profile 全部走 OpenAI Chat Completions(官方
|
|
105
|
+
* `STEP_MODEL_API = "openai-completions"` 对所有模型一视同仁),所以本文件里
|
|
106
|
+
* **没有**协议面判定——而 region 也不在这里拼,URL 由 `client.ts` 从凭据的 profile 得出。
|
|
107
|
+
*/
|
|
108
|
+
export declare class StepCodeAdapter extends LlmAdapter {
|
|
109
|
+
private readonly store;
|
|
110
|
+
private readonly modelSettings;
|
|
111
|
+
private readonly preferences;
|
|
112
|
+
private readonly accountPool;
|
|
113
|
+
private readonly options;
|
|
114
|
+
constructor(store?: StepCodeCredentialStore, modelSettings?: StepCodeModelSettingsStore, preferences?: StepCodePreferenceStore, options?: StepCodeAdapterOptions);
|
|
115
|
+
providerInfo(provider: string): LlmProviderInfo;
|
|
116
|
+
providerRetryPolicy(): ResolvedRetryPolicy;
|
|
117
|
+
imageRequestPricing(): undefined;
|
|
118
|
+
private settings;
|
|
119
|
+
/** 这个部署的目录行(缓存优先,请求路径不联网)。 */
|
|
120
|
+
private catalog;
|
|
121
|
+
/**
|
|
122
|
+
* 这一行请求用哪份凭据。
|
|
123
|
+
*
|
|
124
|
+
* 有池时轮转;没有池时读单凭据存储(无头 host 与测试的形态)。
|
|
125
|
+
* 两条路径都**不刷新**:Step 的 api_key 永不过期,号池的 refresh 钩子恒抛
|
|
126
|
+
* `StepCodeCredentialRefreshError`,所以这里不存在「刷新失败后再试一次」的分支。
|
|
127
|
+
*/
|
|
128
|
+
private credentialFor;
|
|
129
|
+
listModels(provider?: string): Promise<readonly LlmModelInfo[]>;
|
|
130
|
+
resolveModel(provider: string, model: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
|
|
131
|
+
prepareCall(provider: string, model: string, signal?: AbortSignal): Promise<PreparedAdapterCall>;
|
|
132
|
+
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
133
|
+
/**
|
|
134
|
+
* 一次请求的完整往返:选账号 → 定目录行 → 发 → 解析流。
|
|
135
|
+
*
|
|
136
|
+
* 账号轮转的循环只有一处:一次 429 或一次 AUTH 会把那个账号移出本次请求,
|
|
137
|
+
* 由另一个账号来发**同一份**请求体。没有池时这个循环只跑一次。
|
|
138
|
+
*/
|
|
139
|
+
private requestStream;
|
|
140
|
+
}
|
|
141
|
+
export { PROVIDER_ID, PROVIDER_NAME };
|
|
142
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../src/host/step-code/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adopt:只读导入本机已登录的 stepcode 客户端登录态。
|
|
3
|
+
*
|
|
4
|
+
* 上游落盘事实全部来自官方源码:`step/auth.ts`(路径、两代形状、占位符)、
|
|
5
|
+
* `step/environment.ts`(home / 配置根目录的解析),路径清单的骨架来自 `types.ts` 的
|
|
6
|
+
* STEPCODE_ADOPT_PATHS 与 STEPCODE_ADOPT_SHAPES。
|
|
7
|
+
*
|
|
8
|
+
* ---------------------------------------------------------------------------
|
|
9
|
+
* 规则 1 —— 本模块永不写入。它是 reader,而且只是 reader。
|
|
10
|
+
* ---------------------------------------------------------------------------
|
|
11
|
+
* 不得创建、修改、移动或删除任何属于 stepcode 客户端的文件:不以写方式打开任何文件、
|
|
12
|
+
* 不建目录、不改名、不 unlink。保证是**结构性**的而不是散文里的承诺——本模块从
|
|
13
|
+
* node:fs/promises **按名**只导入 readFile 与 stat 两个函数,不导入整个命名空间,
|
|
14
|
+
* 于是引入任何写操作都必须改动 import 列表,而那正是复审者第一行会看的地方。
|
|
15
|
+
*
|
|
16
|
+
* 官方自己的做法是**就地归一化**(`migrateLegacyStepCredential` 会改写 auth.json,
|
|
17
|
+
* `writeCanonicalCredentialFile` 还会 chmod 0600)。本插件明确不做那一步:
|
|
18
|
+
* 改写别人的文件是一次没有授权的写操作。
|
|
19
|
+
*
|
|
20
|
+
* ---------------------------------------------------------------------------
|
|
21
|
+
* 规则 2 —— 存在性与内容分成两个函数。
|
|
22
|
+
* ---------------------------------------------------------------------------
|
|
23
|
+
* `stepCodeAdoptPresence()` 便宜到可以在插件启动时调用,只 stat、从不 open:
|
|
24
|
+
* 没 opt in 的用户,他的令牌内容根本不会被读过。`adoptStepCodeSignIn()` 才是完整读取,
|
|
25
|
+
* 且只在用户显式选择之后才被调用。分开是全部意义所在:一个「顺手先读一下以防万一」
|
|
26
|
+
* 的启动路径会让 opt in 变成装饰。
|
|
27
|
+
*
|
|
28
|
+
* ---------------------------------------------------------------------------
|
|
29
|
+
* 规则 3 —— 认不出来的形状永远给一个**值**,永远不给异常。
|
|
30
|
+
* ---------------------------------------------------------------------------
|
|
31
|
+
* 没有文件、读不了、不是 JSON、形状不认识、解不出 profile、里面根本没有 Step 的条目——
|
|
32
|
+
* 全部落在 StepCodeAdoptResultDto 的 reason 枚举里。一个异常逃进设置路由只会变成 500,
|
|
33
|
+
* 而「没找到本机登录态」不是错误,是正常状态。
|
|
34
|
+
*
|
|
35
|
+
* ---------------------------------------------------------------------------
|
|
36
|
+
* 规则 4 —— **profile 缺失时不猜区域**。
|
|
37
|
+
* ---------------------------------------------------------------------------
|
|
38
|
+
* 区域是凭据的属性,而凭据里唯一说出区域的地方就是 profile(计划 §1、§10 风险 6)。
|
|
39
|
+
* 猜错的代价落在调用方身上:国区凭据打国际区端点会被拒,而国际区凭据打国区端点同样会,
|
|
40
|
+
* 且两次都是「鉴权失败」而不是「串区了」。所以缺 profile 的文件被判为 unsupported-shape,
|
|
41
|
+
* 让用户自己说这条登录态属于哪一区,而不是替他决定。
|
|
42
|
+
*
|
|
43
|
+
* ---------------------------------------------------------------------------
|
|
44
|
+
* 规则 5 —— 快照,不是活凭据。
|
|
45
|
+
* ---------------------------------------------------------------------------
|
|
46
|
+
* adopt 进来的是一份**快照**:用户在 Step 侧撤销之后它立刻失效,而本插件既不能刷新它
|
|
47
|
+
* (Step 的凭据没有刷新链)也不该改它。
|
|
48
|
+
*/
|
|
49
|
+
import { type StepCodeAdoptResultDto } from '../../shared/step-code-contracts.ts';
|
|
50
|
+
import { type StepCodeStoredCredential } from './oauth.ts';
|
|
51
|
+
/** stepcode 客户端改名前用的配置目录(逐字 LEGACY_RENAMED_CONFIG_DIR,environment.ts:9)。 */
|
|
52
|
+
export declare const LEGACY_RENAMED_CONFIG_DIR = ".step-harness";
|
|
53
|
+
/**
|
|
54
|
+
* 显式指定 auth.json 路径的环境变量(逐字 `getStepAuthPath`,auth.ts:18-20)。
|
|
55
|
+
*
|
|
56
|
+
* 有了它,本模块(以及测试)不必碰开发者的真实 profile 就能被驱动;
|
|
57
|
+
* 它也是官方自己给「嵌入式宿主」留的口子。
|
|
58
|
+
*/
|
|
59
|
+
export declare const STEPCODE_AUTH_PATH_ENV = "STEPCODE_AUTH_PATH";
|
|
60
|
+
/** 显式指定旧登录态路径的环境变量(逐字 getLegacyStepAuthPaths,auth.ts:29-32)。 */
|
|
61
|
+
export declare const STEPCODE_LEGACY_AUTH_PATH_ENV = "STEPCODE_LEGACY_AUTH_PATH";
|
|
62
|
+
/** 配置目录名的环境覆盖(逐字 resolveStepConfigDir,environment.ts:30-32)。 */
|
|
63
|
+
export declare const STEPCODE_CONFIG_DIR_ENV = "STEPCODE_CONFIG_DIR";
|
|
64
|
+
/** agent 目录名的环境覆盖(逐字 resolveStepConfigRoot,environment.ts:48-57)。 */
|
|
65
|
+
export declare const STEP_CODING_AGENT_DIR_ENV = "STEP_CODING_AGENT_DIR";
|
|
66
|
+
/**
|
|
67
|
+
* stepcode 客户端的家目录(逐字 resolveStepHomeDir,environment.ts:25-27)。
|
|
68
|
+
*
|
|
69
|
+
* 读的是 HOME / USERPROFILE 再退到 os.homedir()——与官方同一口径,所以 Windows 上
|
|
70
|
+
* 拿到的是 %USERPROFILE%、POSIX 上是 ~。
|
|
71
|
+
*/
|
|
72
|
+
export declare function stepCodeHomeDir(env?: NodeJS.ProcessEnv): string;
|
|
73
|
+
/**
|
|
74
|
+
* stepcode 配置根目录(auth.json 与它同级放着,逐字 resolveStepConfigRoot)。
|
|
75
|
+
*
|
|
76
|
+
* 环境覆盖优先:官方把 `STEP_CODING_AGENT_DIR` 解析成绝对路径再取父目录,
|
|
77
|
+
* 因为「textual 的 ..」会落到进程工作目录旁边。本文件照抄那个顺序。
|
|
78
|
+
*/
|
|
79
|
+
export declare function stepCodeConfigRoot(env?: NodeJS.ProcessEnv): string;
|
|
80
|
+
/**
|
|
81
|
+
* adopt 会读的每一个路径,按优先级排列。
|
|
82
|
+
*
|
|
83
|
+
* 顺序逐字照抄官方 `getLegacyStepAuthPaths`(auth.ts:29-44)给的理由:canonical root
|
|
84
|
+
* 那个文件排在最前,因为它是「需要就地归一化的旧形状」;剩下的覆盖上一个版本写下的文件。
|
|
85
|
+
*
|
|
86
|
+
* 前三条来自 `types.ts` 的 STEPCODE_ADOPT_PATHS(相对配置根目录的片段);后两条是
|
|
87
|
+
* 改名前的 `.step-harness` 根,官方仍在扫,本插件也扫——多看一个只读文件没有代价。
|
|
88
|
+
*
|
|
89
|
+
* 纯函数、不碰文件系统:只为渲染卡片调它也是安全的,优先级因此可以脱离磁盘被测试。
|
|
90
|
+
*/
|
|
91
|
+
export declare function stepCodeAdoptPaths(env?: NodeJS.ProcessEnv): readonly string[];
|
|
92
|
+
/**
|
|
93
|
+
* 客户端模板文件里的占位符(逐字 auth.ts:203,220)。
|
|
94
|
+
*
|
|
95
|
+
* 它是一个**看起来像凭据**的字符串:不排除它,`{ "apiKey": "<your_api_key>" }`
|
|
96
|
+
* 会被当成一次成功的 adopt,然后把一个 401 发到上游。
|
|
97
|
+
*/
|
|
98
|
+
export declare const STEPCODE_PLACEHOLDER_KEY = "<your_api_key>";
|
|
99
|
+
/** adopt 成功时带走的凭据:凭据 + 它是从哪儿、哪个文件捡来的。 */
|
|
100
|
+
export interface StepCodeAdoptedCredential {
|
|
101
|
+
/**
|
|
102
|
+
* 池里的判别式,恒为 true。
|
|
103
|
+
*
|
|
104
|
+
* 一个可被测试的布尔,好过一句需要人去读的注释:adopt 快照永不可刷新、且它的删除
|
|
105
|
+
* 语义与本插件自己登出来的账号不同(后者只删本插件自己的文件)。
|
|
106
|
+
*/
|
|
107
|
+
readonly adopted: true;
|
|
108
|
+
/** 来源标识,供卡片与池记录。 */
|
|
109
|
+
readonly source: typeof STEPCODE_ADOPT_SOURCE;
|
|
110
|
+
/** 读到的确切路径,卡片可以把它显示给用户。 */
|
|
111
|
+
readonly sourcePath: string;
|
|
112
|
+
/** 本线路的凭据形态(oauth + 静态哨兵 + MAX_SAFE_INTEGER)。 */
|
|
113
|
+
readonly credentials: StepCodeStoredCredential;
|
|
114
|
+
}
|
|
115
|
+
/** adopt 快照的来源标识。 */
|
|
116
|
+
export declare const STEPCODE_ADOPT_SOURCE = "stepcode-client";
|
|
117
|
+
/** adopt 失败原因,直接取自冻结契约的 StepCodeAdoptResultDto['reason'],不另立一套。 */
|
|
118
|
+
export type StepCodeAdoptReason = NonNullable<StepCodeAdoptResultDto['reason']>;
|
|
119
|
+
/**
|
|
120
|
+
* 每个失败原因对应的一句可照做的下一步(给路由层与设置卡片用)。
|
|
121
|
+
*
|
|
122
|
+
* 四个取值各自的下一步不同,所以分开写而不是拼一句「导入失败」:
|
|
123
|
+
* 前两个是「本机没有 / 读不懂」,第三个是「这份登录态没有说自己是哪一区」,
|
|
124
|
+
* 第四个是「这个文件里根本没有 Step 的条目」。
|
|
125
|
+
*/
|
|
126
|
+
export declare const ADOPT_REASON_HINTS: Readonly<Record<StepCodeAdoptReason, string>>;
|
|
127
|
+
/** 解析一份已读入的 JSON 的结论:要么带凭据,要么带一个 reason。 */
|
|
128
|
+
export type StepCodeAdoptParse = {
|
|
129
|
+
readonly ok: true;
|
|
130
|
+
readonly adopted: StepCodeAdoptedCredential;
|
|
131
|
+
} | {
|
|
132
|
+
readonly ok: false;
|
|
133
|
+
readonly reason: StepCodeAdoptReason;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* 把一份已读入的登录态文档解析成本线路的 adopt 结果。
|
|
137
|
+
*
|
|
138
|
+
* 纯函数、导出:两代形状的规则可以脱离文件系统被测试(测试用夹具驱动它)。
|
|
139
|
+
*
|
|
140
|
+
* 顺序照抄官方 `readLegacyStepCredential`(auth.ts:193-235):
|
|
141
|
+
*
|
|
142
|
+
* 1. 顶层 `{ apiKey, profile?, uid? }`(StepCode 自己写的老文件);
|
|
143
|
+
* 2. `{ step: { type:'oauth', access|refresh|expires|profile|uid } }`(pi 形状;
|
|
144
|
+
* 官方在那里也认 `key`,auth.ts:214-220);
|
|
145
|
+
* 3. 都不匹配时:有别的 provider 条目 → `not-a-stepcode-login`(契约给的那个例子),
|
|
146
|
+
* 否则 → `invalid-credentials`。
|
|
147
|
+
*
|
|
148
|
+
* 认出形状但**没有 profile** 时是 `unsupported-shape`:见模块头的规则 4。
|
|
149
|
+
* uid 不合格只丢弃 uid,不丢掉整份登录态(uid 只影响账号显示与去重)。
|
|
150
|
+
*/
|
|
151
|
+
export declare function parseAdoptedStepCodeCredential(value: unknown, sourcePath: string): StepCodeAdoptParse;
|
|
152
|
+
/**
|
|
153
|
+
* 本机有没有可导入的 stepcode 登录态文件。
|
|
154
|
+
*
|
|
155
|
+
* 启动路径安全:它**从不**打开候选文件去读,所以没 opt in 的用户,令牌内容根本没被碰过——
|
|
156
|
+
* 既不被它读,也不被渲染卡片的路由读。只 stat,透露的是存在与时间戳,没有别的。
|
|
157
|
+
*
|
|
158
|
+
* 刻意**不**在这里回答「有效 / 过期 / 是不是 JSON」:那需要它存在的目的就是避免的那次读。
|
|
159
|
+
*/
|
|
160
|
+
export declare function stepCodeAdoptPresence(paths?: readonly string[]): Promise<boolean>;
|
|
161
|
+
/**
|
|
162
|
+
* 一次 adopt 的结论:给卡片的切片 + (成功时)真正要落盘的凭据。
|
|
163
|
+
*
|
|
164
|
+
* 两者**刻意分开**:凭据只在这里,绝不进 StepCodeAdoptResultDto(那个类型要下发到客户端,
|
|
165
|
+
* 契约里的一切都是公开信息)。
|
|
166
|
+
*/
|
|
167
|
+
export interface StepCodeAdoptOutcome {
|
|
168
|
+
/** 卡片渲染用;不含任何凭据。 */
|
|
169
|
+
readonly result: StepCodeAdoptResultDto;
|
|
170
|
+
/** 成功时才有:带来源标记的凭据,交给号池或凭据存储落盘。 */
|
|
171
|
+
readonly adopted?: StepCodeAdoptedCredential;
|
|
172
|
+
/** 实际读到的文件(设置卡片要把它显示出来)。 */
|
|
173
|
+
readonly sourcePath?: string;
|
|
174
|
+
}
|
|
175
|
+
export interface StepCodeAdoptOptions {
|
|
176
|
+
/** 候选路径;缺省 stepCodeAdoptPaths()(测试注入夹具路径)。 */
|
|
177
|
+
paths?: readonly string[];
|
|
178
|
+
/** 环境变量读取处;缺省 process.env,且**调用时**读取。 */
|
|
179
|
+
env?: NodeJS.ProcessEnv;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* 只读导入本机 stepcode 登录态;第一个可用候选获胜。
|
|
183
|
+
*
|
|
184
|
+
* **只在用户显式 opt in 之后调用**(见模块头规则 2)。
|
|
185
|
+
*
|
|
186
|
+
* 永不抛出、永不拒绝:文件不存在、读不了、不是 JSON、形状不认识、解不出 profile——
|
|
187
|
+
* 全部是一个带 reason 的值。设置路由不能因为用户文件正在被写就整个失败。
|
|
188
|
+
*
|
|
189
|
+
* 两个候选路径的失败被区分开:一个文件读不出来(invalid-credentials)会继续看下一个,
|
|
190
|
+
* 而**全部**候选都失败时,返回的是第一个真实失败的原因——「有文件但读不出来」
|
|
191
|
+
* 与「根本没有文件」给用户的下一步不同。
|
|
192
|
+
*/
|
|
193
|
+
export declare function adoptStepCodeSignIn(options?: StepCodeAdoptOptions): Promise<StepCodeAdoptOutcome>;
|
|
194
|
+
/**
|
|
195
|
+
* 只要那张给卡片的切片(不带走凭据)。
|
|
196
|
+
*
|
|
197
|
+
* 渲染「本机有没有可导入的东西」时用这个:它仍要读文件(所以仍要显式 opt in),
|
|
198
|
+
* 但把凭据留在本模块的返回值之外。
|
|
199
|
+
*/
|
|
200
|
+
export declare function readStepCodeAdoptResult(options?: StepCodeAdoptOptions): Promise<StepCodeAdoptResultDto>;
|
|
201
|
+
//# sourceMappingURL=adopt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adopt.d.ts","sourceRoot":"","sources":["../../../../src/host/step-code/adopt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache-waste diagnosis for the Step Code route: how many prompt tokens should
|
|
3
|
+
* have been cache reads and were billed fresh anyway.
|
|
4
|
+
*
|
|
5
|
+
* Ported from the official Step-Code client
|
|
6
|
+
* (`_ref-stepcode/packages/coding-agent/src/core/cache-stats.ts`, 164 lines).
|
|
7
|
+
* The arithmetic and the counting rules are kept as they are; only the data
|
|
8
|
+
* sources change, because this repository has no `SessionEntry` type and this
|
|
9
|
+
* route must not depend on one:
|
|
10
|
+
*
|
|
11
|
+
* - the official scan walks persisted session entries; here the caller hands in
|
|
12
|
+
* an already-ordered list of {@link StepCodeCacheEntry} values,
|
|
13
|
+
* - the official message carries `usage.cost`; on this route every price is
|
|
14
|
+
* zero, so {@link StepCodeCacheMiss.missedCost} is 0 and the card is told not
|
|
15
|
+
* to render money at all.
|
|
16
|
+
*
|
|
17
|
+
* WHY the diagnosis is worth porting here rather than into the shared cache
|
|
18
|
+
* layer: Step's cache is automatic and invisible. The client gets no marker when
|
|
19
|
+
* a prefix stopped being reused, so the only evidence is the read number on the
|
|
20
|
+
* next turn — and the question "did we throw the prefix away, or did the server?"
|
|
21
|
+
* is answered by comparing against the previous request.
|
|
22
|
+
*
|
|
23
|
+
* Pure functions only: no state is retained here, so the caller owns the history
|
|
24
|
+
* and the lifetime of it.
|
|
25
|
+
*
|
|
26
|
+
* @module dsh-chatgpt-subscription/step-code-cache-stats
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Prompt-cache time-to-live.
|
|
30
|
+
*
|
|
31
|
+
* An idle gap longer than this is the likeliest explanation for a miss, and it
|
|
32
|
+
* is the only cheap hint this diagnosis can give: the upstream offers no
|
|
33
|
+
* "your entry expired" signal, so the idle period is the whole evidence.
|
|
34
|
+
* Five minutes is the TTL the official client uses for the same notice.
|
|
35
|
+
*/
|
|
36
|
+
export declare const CACHE_TTL_MS: number;
|
|
37
|
+
/**
|
|
38
|
+
* Misses at or below this are cache-breakpoint granularity, not waste.
|
|
39
|
+
*
|
|
40
|
+
* A prefix cache breaks at block boundaries, so a few hundred tokens of drift
|
|
41
|
+
* between two turns is normal re-shuffling. Reporting it teaches the user to
|
|
42
|
+
* ignore the notice, which costs the one notice that mattered.
|
|
43
|
+
*/
|
|
44
|
+
export declare const NOISE_FLOOR_TOKENS = 1024;
|
|
45
|
+
/**
|
|
46
|
+
* Whether this route can put money on a cache number.
|
|
47
|
+
*
|
|
48
|
+
* Always false: the official model table hardwires every price to 0
|
|
49
|
+
* (`STEP_MODEL_DEFAULTS.cost`, `step-provider/index.ts:102`), and Step Plan is a
|
|
50
|
+
* subscription rather than a metered SKU. A caller that renders
|
|
51
|
+
* `missedCost` from a zero price shows a correct, useless "you saved $0"; the
|
|
52
|
+
* alternative — inventing a rate — would show a plausible, false number. So the
|
|
53
|
+
* card shows the token dimension alone.
|
|
54
|
+
*/
|
|
55
|
+
export declare function isCacheWasteCostPriced(): boolean;
|
|
56
|
+
/** Disjoint token counts for one assistant turn, as this route reports them. */
|
|
57
|
+
export interface StepCodeCacheUsage {
|
|
58
|
+
/** Uncached prompt tokens. */
|
|
59
|
+
inputTokens: number;
|
|
60
|
+
/** Output tokens, which reasoning is billed against. */
|
|
61
|
+
outputTokens?: number;
|
|
62
|
+
/** Prompt tokens served from the automatic prefix cache. */
|
|
63
|
+
cacheReadTokens?: number;
|
|
64
|
+
/**
|
|
65
|
+
* Always 0 on this route — the cache is automatic, so there is no client-side
|
|
66
|
+
* write to count. Kept in the shape because the arithmetic below reads it.
|
|
67
|
+
*/
|
|
68
|
+
cacheWriteTokens?: number;
|
|
69
|
+
}
|
|
70
|
+
/** One assistant turn: what it spent, when, and on which model. */
|
|
71
|
+
export interface StepCodeCacheTurn {
|
|
72
|
+
readonly usage: StepCodeCacheUsage;
|
|
73
|
+
/** Epoch milliseconds the request completed. */
|
|
74
|
+
readonly timestamp: number;
|
|
75
|
+
/**
|
|
76
|
+
* Identity of the model route, `{provider}/{model}`.
|
|
77
|
+
*
|
|
78
|
+
* Compared as a string rather than as two fields so a caller can extend it
|
|
79
|
+
* (region, profile, wire) without this file needing to know what a "route" is.
|
|
80
|
+
*/
|
|
81
|
+
readonly modelKey: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* What the previous request in this segment left behind.
|
|
85
|
+
*
|
|
86
|
+
* Everything in its prompt should be a cache read on the next turn; that is the
|
|
87
|
+
* premise the whole diagnosis rests on.
|
|
88
|
+
*/
|
|
89
|
+
export interface StepCodePreviousRequest {
|
|
90
|
+
/** Its aggregate prompt count. */
|
|
91
|
+
promptTokens: number;
|
|
92
|
+
readonly modelKey: string;
|
|
93
|
+
readonly timestamp: number;
|
|
94
|
+
/**
|
|
95
|
+
* Sticky: some earlier request in this segment reported cache activity.
|
|
96
|
+
*
|
|
97
|
+
* This is what separates two cases that look identical from the outside — a
|
|
98
|
+
* total miss on a read-reporting endpoint versus an endpoint that reports no
|
|
99
|
+
* caching at all. Without it, the second would be reported as a total miss on
|
|
100
|
+
* every single turn.
|
|
101
|
+
*/
|
|
102
|
+
readonly reportedCache: boolean;
|
|
103
|
+
}
|
|
104
|
+
/** A counted cache miss on one assistant turn. */
|
|
105
|
+
export interface StepCodeCacheMiss {
|
|
106
|
+
/** Tokens that were in the previous prompt and were NOT read from cache. */
|
|
107
|
+
missedTokens: number;
|
|
108
|
+
/** Always 0 on this route; see {@link isCacheWasteCostPriced}. */
|
|
109
|
+
missedCost: number;
|
|
110
|
+
/** Milliseconds since the previous request, which last refreshed the cache. */
|
|
111
|
+
idleMs: number;
|
|
112
|
+
/** True when the model changed relative to the previous request. */
|
|
113
|
+
modelChanged: boolean;
|
|
114
|
+
}
|
|
115
|
+
/** Cumulative waste across a segment. */
|
|
116
|
+
export interface StepCodeCacheWasteTotals {
|
|
117
|
+
missedTokens: number;
|
|
118
|
+
missedCost: number;
|
|
119
|
+
/** Counted misses — turns above {@link NOISE_FLOOR_TOKENS}. */
|
|
120
|
+
missCount: number;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* One entry of the ordered history this diagnosis scans.
|
|
124
|
+
*
|
|
125
|
+
* The two context-change kinds exist because compaction and branch summaries
|
|
126
|
+
* legitimately REPLACE the prompt: the next turn's context is new content, not
|
|
127
|
+
* re-billed content, so counting it as waste would be wrong.
|
|
128
|
+
*/
|
|
129
|
+
export type StepCodeCacheEntry = {
|
|
130
|
+
readonly kind: 'turn';
|
|
131
|
+
readonly turn: StepCodeCacheTurn;
|
|
132
|
+
} | {
|
|
133
|
+
readonly kind: 'compaction';
|
|
134
|
+
} | {
|
|
135
|
+
readonly kind: 'branch-summary';
|
|
136
|
+
};
|
|
137
|
+
/** Aggregate prompt count of one turn: uncached input plus both cache buckets. */
|
|
138
|
+
export declare function promptTokensOf(usage: StepCodeCacheUsage): number;
|
|
139
|
+
/**
|
|
140
|
+
* The segment state one turn leaves behind, or undefined when it carries no
|
|
141
|
+
* prompt and therefore cannot be a baseline.
|
|
142
|
+
*/
|
|
143
|
+
export declare function asPreviousRequest(turn: StepCodeCacheTurn, reportedCache: boolean): StepCodePreviousRequest | undefined;
|
|
144
|
+
/**
|
|
145
|
+
* Cache miss for one turn relative to the previous request, or undefined when
|
|
146
|
+
* nothing is counted.
|
|
147
|
+
*
|
|
148
|
+
* Not counted: the first turn (no baseline), a turn with no prompt, a turn whose
|
|
149
|
+
* segment reported no cache activity at all (see
|
|
150
|
+
* {@link StepCodePreviousRequest.reportedCache}), and a miss at or below
|
|
151
|
+
* {@link NOISE_FLOOR_TOKENS}.
|
|
152
|
+
*/
|
|
153
|
+
export declare function detectCacheMiss(prev: StepCodePreviousRequest | undefined, turn: StepCodeCacheTurn): StepCodeCacheMiss | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* Whether an idle period is long enough to suspect the cache entry expired.
|
|
156
|
+
*
|
|
157
|
+
* Strictly greater: an entry alive exactly to its TTL has not expired, and
|
|
158
|
+
* rounding must not turn that into a warning.
|
|
159
|
+
*/
|
|
160
|
+
export declare function cacheLikelyExpired(idleMs: number): boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Cumulative cache waste across a segment: prompt tokens that should have been
|
|
163
|
+
* cache reads because they were in the previous turn's prompt, and were not.
|
|
164
|
+
*/
|
|
165
|
+
export declare function computeCacheWaste(entries: readonly StepCodeCacheEntry[]): StepCodeCacheWasteTotals;
|
|
166
|
+
/**
|
|
167
|
+
* Every counted miss, keyed by the turn that paid for it (by reference).
|
|
168
|
+
*
|
|
169
|
+
* The key is the turn object, so a caller re-deriving notices while rebuilding a
|
|
170
|
+
* transcript can look a turn up without inventing a second identity for it.
|
|
171
|
+
*/
|
|
172
|
+
export declare function collectCacheMisses(entries: readonly StepCodeCacheEntry[]): ReadonlyMap<StepCodeCacheTurn, StepCodeCacheMiss>;
|
|
173
|
+
/**
|
|
174
|
+
* The miss for a turn that has just completed.
|
|
175
|
+
*
|
|
176
|
+
* `entries` must NOT already contain `turn`: the caller passes the history as
|
|
177
|
+
* of before the turn. A turn that is present twice would be compared against
|
|
178
|
+
* itself, which always reads as a total miss.
|
|
179
|
+
*/
|
|
180
|
+
export declare function detectCacheMissForTurn(entries: readonly StepCodeCacheEntry[], turn: StepCodeCacheTurn): StepCodeCacheMiss | undefined;
|
|
181
|
+
//# sourceMappingURL=cache-stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-stats.d.ts","sourceRoot":"","sources":["../../../../src/host/step-code/cache-stats.ts"],"names":[],"mappings":"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"}
|