@eddyskywalker/dsh-chatgpt-subscription 0.21.0 → 0.23.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 (85) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +56 -3
  3. package/lib/client.js +2719 -491
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +8041 -3092
  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 +17 -26
  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 +13 -0
  18. package/lib/types/client/ollama/api.d.ts.map +1 -1
  19. package/lib/types/client/ollama/locales.d.ts +24 -0
  20. package/lib/types/client/ollama/locales.d.ts.map +1 -1
  21. package/lib/types/client/step-code/StepCodeComposerQuota.d.ts +52 -0
  22. package/lib/types/client/step-code/StepCodeComposerQuota.d.ts.map +1 -0
  23. package/lib/types/client/step-code/StepCodeSection.d.ts +28 -0
  24. package/lib/types/client/step-code/StepCodeSection.d.ts.map +1 -0
  25. package/lib/types/client/step-code/api.d.ts +4 -0
  26. package/lib/types/client/step-code/api.d.ts.map +1 -0
  27. package/lib/types/client/step-code/locales.d.ts +648 -0
  28. package/lib/types/client/step-code/locales.d.ts.map +1 -0
  29. package/lib/types/client/step-code/styles.d.ts +28 -0
  30. package/lib/types/client/step-code/styles.d.ts.map +1 -0
  31. package/lib/types/client/step-code/useStepCodeSection.d.ts +122 -0
  32. package/lib/types/client/step-code/useStepCodeSection.d.ts.map +1 -0
  33. package/lib/types/host/antigravity/account-pool.d.ts.map +1 -1
  34. package/lib/types/host/common/account-pool.d.ts +38 -3
  35. package/lib/types/host/common/account-pool.d.ts.map +1 -1
  36. package/lib/types/host/common/model-request-control.d.ts +1 -1
  37. package/lib/types/host/common/model-request-control.d.ts.map +1 -1
  38. package/lib/types/host/common/request-diagnostics.d.ts +1 -1
  39. package/lib/types/host/common/request-diagnostics.d.ts.map +1 -1
  40. package/lib/types/host/glm-coding-plan/account-pool.d.ts.map +1 -1
  41. package/lib/types/host/glm-coding-plan/adapter.d.ts +1 -14
  42. package/lib/types/host/glm-coding-plan/adapter.d.ts.map +1 -1
  43. package/lib/types/host/glm-coding-plan/client.d.ts.map +1 -1
  44. package/lib/types/host/glm-coding-plan/types.d.ts +0 -10
  45. package/lib/types/host/glm-coding-plan/types.d.ts.map +1 -1
  46. package/lib/types/host/ollama/adapter.d.ts +26 -2
  47. package/lib/types/host/ollama/adapter.d.ts.map +1 -1
  48. package/lib/types/host/ollama/client.d.ts +16 -1
  49. package/lib/types/host/ollama/client.d.ts.map +1 -1
  50. package/lib/types/host/ollama/routes.d.ts +1 -1
  51. package/lib/types/host/ollama/routes.d.ts.map +1 -1
  52. package/lib/types/host/ollama/types.d.ts +74 -8
  53. package/lib/types/host/ollama/types.d.ts.map +1 -1
  54. package/lib/types/host/step-code/account-pool.d.ts +187 -0
  55. package/lib/types/host/step-code/account-pool.d.ts.map +1 -0
  56. package/lib/types/host/step-code/adapter.d.ts +142 -0
  57. package/lib/types/host/step-code/adapter.d.ts.map +1 -0
  58. package/lib/types/host/step-code/adopt.d.ts +201 -0
  59. package/lib/types/host/step-code/adopt.d.ts.map +1 -0
  60. package/lib/types/host/step-code/cache-stats.d.ts +181 -0
  61. package/lib/types/host/step-code/cache-stats.d.ts.map +1 -0
  62. package/lib/types/host/step-code/client.d.ts +331 -0
  63. package/lib/types/host/step-code/client.d.ts.map +1 -0
  64. package/lib/types/host/step-code/mapper.d.ts +301 -0
  65. package/lib/types/host/step-code/mapper.d.ts.map +1 -0
  66. package/lib/types/host/step-code/model-catalog.d.ts +230 -0
  67. package/lib/types/host/step-code/model-catalog.d.ts.map +1 -0
  68. package/lib/types/host/step-code/oauth.d.ts +265 -0
  69. package/lib/types/host/step-code/oauth.d.ts.map +1 -0
  70. package/lib/types/host/step-code/routes.d.ts +126 -0
  71. package/lib/types/host/step-code/routes.d.ts.map +1 -0
  72. package/lib/types/host/step-code/token-store.d.ts +325 -0
  73. package/lib/types/host/step-code/token-store.d.ts.map +1 -0
  74. package/lib/types/host/step-code/types.d.ts +488 -0
  75. package/lib/types/host/step-code/types.d.ts.map +1 -0
  76. package/lib/types/host/workbuddy/adapter.d.ts.map +1 -1
  77. package/lib/types/index.d.ts +5 -1
  78. package/lib/types/index.d.ts.map +1 -1
  79. package/lib/types/shared/ollama-contracts.d.ts +30 -0
  80. package/lib/types/shared/ollama-contracts.d.ts.map +1 -1
  81. package/lib/types/shared/step-code-contracts.d.ts +438 -0
  82. package/lib/types/shared/step-code-contracts.d.ts.map +1 -0
  83. package/package.json +1 -1
  84. package/lib/types/host/glm-coding-plan/signing.d.ts +0 -323
  85. package/lib/types/host/glm-coding-plan/signing.d.ts.map +0 -1
@@ -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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"}