@kodelyth/codex 2026.5.42 → 2026.6.1

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 (138) hide show
  1. package/package.json +16 -1
  2. package/doctor-contract-api.test.ts +0 -44
  3. package/doctor-contract-api.ts +0 -68
  4. package/harness.ts +0 -72
  5. package/index.test.ts +0 -230
  6. package/index.ts +0 -66
  7. package/media-understanding-provider.test.ts +0 -486
  8. package/media-understanding-provider.ts +0 -521
  9. package/prompt-overlay-runtime-contract.test.ts +0 -48
  10. package/prompt-overlay.ts +0 -21
  11. package/provider-catalog.ts +0 -83
  12. package/provider-discovery.ts +0 -45
  13. package/provider.test.ts +0 -384
  14. package/provider.ts +0 -243
  15. package/src/app-server/app-inventory-cache.test.ts +0 -176
  16. package/src/app-server/app-inventory-cache.ts +0 -324
  17. package/src/app-server/approval-bridge.test.ts +0 -1471
  18. package/src/app-server/approval-bridge.ts +0 -1211
  19. package/src/app-server/auth-bridge.test.ts +0 -1449
  20. package/src/app-server/auth-bridge.ts +0 -614
  21. package/src/app-server/auth-profile-runtime-contract.test.ts +0 -239
  22. package/src/app-server/capabilities.ts +0 -27
  23. package/src/app-server/client-factory.ts +0 -24
  24. package/src/app-server/client.test.ts +0 -563
  25. package/src/app-server/client.ts +0 -715
  26. package/src/app-server/compact.test.ts +0 -710
  27. package/src/app-server/compact.ts +0 -500
  28. package/src/app-server/computer-use.test.ts +0 -788
  29. package/src/app-server/computer-use.ts +0 -683
  30. package/src/app-server/config.test.ts +0 -879
  31. package/src/app-server/config.ts +0 -1038
  32. package/src/app-server/context-engine-projection.test.ts +0 -252
  33. package/src/app-server/context-engine-projection.ts +0 -403
  34. package/src/app-server/delivery-no-reply-runtime-contract.test.ts +0 -80
  35. package/src/app-server/dynamic-tool-diagnostics.ts +0 -73
  36. package/src/app-server/dynamic-tool-profile.ts +0 -69
  37. package/src/app-server/dynamic-tools.test.ts +0 -1302
  38. package/src/app-server/dynamic-tools.ts +0 -623
  39. package/src/app-server/elicitation-bridge.test.ts +0 -1056
  40. package/src/app-server/elicitation-bridge.ts +0 -783
  41. package/src/app-server/event-projector.test.ts +0 -2668
  42. package/src/app-server/event-projector.ts +0 -2057
  43. package/src/app-server/image-payload-sanitizer.test.ts +0 -49
  44. package/src/app-server/image-payload-sanitizer.ts +0 -167
  45. package/src/app-server/klaw-owned-tool-runtime-contract.test.ts +0 -456
  46. package/src/app-server/local-runtime-attribution.ts +0 -39
  47. package/src/app-server/managed-binary.test.ts +0 -139
  48. package/src/app-server/managed-binary.ts +0 -193
  49. package/src/app-server/models.test.ts +0 -246
  50. package/src/app-server/models.ts +0 -172
  51. package/src/app-server/native-hook-relay.test.ts +0 -271
  52. package/src/app-server/native-hook-relay.ts +0 -150
  53. package/src/app-server/native-subagent-task-mirror.test.ts +0 -573
  54. package/src/app-server/native-subagent-task-mirror.ts +0 -497
  55. package/src/app-server/outcome-fallback-runtime-contract.test.ts +0 -404
  56. package/src/app-server/plugin-activation.test.ts +0 -336
  57. package/src/app-server/plugin-activation.ts +0 -283
  58. package/src/app-server/plugin-app-cache-key.ts +0 -74
  59. package/src/app-server/plugin-approval-roundtrip.ts +0 -122
  60. package/src/app-server/plugin-inventory.test.ts +0 -355
  61. package/src/app-server/plugin-inventory.ts +0 -357
  62. package/src/app-server/plugin-thread-config.test.ts +0 -865
  63. package/src/app-server/plugin-thread-config.ts +0 -455
  64. package/src/app-server/protocol-generated/json/DynamicToolCallParams.json +0 -33
  65. package/src/app-server/protocol-generated/json/v2/ErrorNotification.json +0 -199
  66. package/src/app-server/protocol-generated/json/v2/GetAccountResponse.json +0 -102
  67. package/src/app-server/protocol-generated/json/v2/ModelListResponse.json +0 -227
  68. package/src/app-server/protocol-generated/json/v2/ThreadResumeResponse.json +0 -2630
  69. package/src/app-server/protocol-generated/json/v2/ThreadStartResponse.json +0 -2630
  70. package/src/app-server/protocol-generated/json/v2/TurnCompletedNotification.json +0 -1659
  71. package/src/app-server/protocol-generated/json/v2/TurnStartResponse.json +0 -1655
  72. package/src/app-server/protocol-validators.test.ts +0 -75
  73. package/src/app-server/protocol-validators.ts +0 -203
  74. package/src/app-server/protocol.ts +0 -520
  75. package/src/app-server/rate-limit-cache.ts +0 -48
  76. package/src/app-server/rate-limits.test.ts +0 -202
  77. package/src/app-server/rate-limits.ts +0 -583
  78. package/src/app-server/request.ts +0 -73
  79. package/src/app-server/run-attempt.context-engine.test.ts +0 -1004
  80. package/src/app-server/run-attempt.test.ts +0 -9477
  81. package/src/app-server/run-attempt.ts +0 -4683
  82. package/src/app-server/run-attempt.vision-tools.test.ts +0 -35
  83. package/src/app-server/schema-normalization-runtime-contract.test.ts +0 -206
  84. package/src/app-server/session-binding.test.ts +0 -303
  85. package/src/app-server/session-binding.ts +0 -398
  86. package/src/app-server/session-history.ts +0 -44
  87. package/src/app-server/shared-client.test.ts +0 -589
  88. package/src/app-server/shared-client.ts +0 -289
  89. package/src/app-server/side-question.test.ts +0 -1175
  90. package/src/app-server/side-question.ts +0 -1007
  91. package/src/app-server/test-support.ts +0 -48
  92. package/src/app-server/thread-lifecycle.test.ts +0 -447
  93. package/src/app-server/thread-lifecycle.ts +0 -939
  94. package/src/app-server/thread-lifecycle.user-mcp-servers.test.ts +0 -442
  95. package/src/app-server/timeout.ts +0 -9
  96. package/src/app-server/tool-progress-normalization.ts +0 -77
  97. package/src/app-server/trajectory.test.ts +0 -205
  98. package/src/app-server/trajectory.ts +0 -365
  99. package/src/app-server/transcript-mirror.test.ts +0 -524
  100. package/src/app-server/transcript-mirror.ts +0 -208
  101. package/src/app-server/transcript-repair-runtime-contract.test.ts +0 -44
  102. package/src/app-server/transport-stdio.test.ts +0 -171
  103. package/src/app-server/transport-stdio.ts +0 -107
  104. package/src/app-server/transport-websocket.test.ts +0 -69
  105. package/src/app-server/transport-websocket.ts +0 -90
  106. package/src/app-server/transport.ts +0 -117
  107. package/src/app-server/user-input-bridge.test.ts +0 -249
  108. package/src/app-server/user-input-bridge.ts +0 -316
  109. package/src/app-server/version.ts +0 -4
  110. package/src/app-server/vision-tools.ts +0 -12
  111. package/src/command-account.ts +0 -544
  112. package/src/command-formatters.ts +0 -425
  113. package/src/command-handlers.ts +0 -2004
  114. package/src/command-rpc.test.ts +0 -16
  115. package/src/command-rpc.ts +0 -142
  116. package/src/commands.test.ts +0 -3312
  117. package/src/commands.ts +0 -65
  118. package/src/conversation-binding-data.ts +0 -124
  119. package/src/conversation-binding.test.ts +0 -599
  120. package/src/conversation-binding.ts +0 -561
  121. package/src/conversation-control.test.ts +0 -126
  122. package/src/conversation-control.ts +0 -303
  123. package/src/conversation-turn-collector.test.ts +0 -191
  124. package/src/conversation-turn-collector.ts +0 -186
  125. package/src/conversation-turn-input.test.ts +0 -141
  126. package/src/conversation-turn-input.ts +0 -106
  127. package/src/manifest.test.ts +0 -20
  128. package/src/migration/apply.ts +0 -501
  129. package/src/migration/helpers.ts +0 -55
  130. package/src/migration/plan.ts +0 -461
  131. package/src/migration/provider.test.ts +0 -1741
  132. package/src/migration/provider.ts +0 -41
  133. package/src/migration/source.ts +0 -643
  134. package/src/migration/targets.ts +0 -25
  135. package/src/node-cli-sessions.test.ts +0 -180
  136. package/src/node-cli-sessions.ts +0 -711
  137. package/test-api.ts +0 -82
  138. package/tsconfig.json +0 -16
@@ -1,425 +0,0 @@
1
- import type { CodexComputerUseStatus } from "./app-server/computer-use.js";
2
- import type { CodexAppServerModelListResult } from "./app-server/models.js";
3
- import { isJsonObject, type JsonObject, type JsonValue } from "./app-server/protocol.js";
4
- import {
5
- hasCodexRateLimitSnapshots,
6
- summarizeCodexAccountRateLimits,
7
- summarizeCodexRateLimits,
8
- } from "./app-server/rate-limits.js";
9
- import type { CodexAccountAuthOverview } from "./command-account.js";
10
- import type { SafeValue } from "./command-rpc.js";
11
-
12
- type CodexStatusProbes = {
13
- models: SafeValue<CodexAppServerModelListResult>;
14
- account: SafeValue<JsonValue | undefined>;
15
- limits: SafeValue<JsonValue | undefined>;
16
- mcps: SafeValue<JsonValue | undefined>;
17
- skills: SafeValue<JsonValue | undefined>;
18
- };
19
-
20
- export function formatCodexStatus(probes: CodexStatusProbes): string {
21
- const connected =
22
- probes.models.ok || probes.account.ok || probes.limits.ok || probes.mcps.ok || probes.skills.ok;
23
- const lines = [`Codex app-server: ${connected ? "connected" : "unavailable"}`];
24
- if (probes.models.ok) {
25
- lines.push(
26
- `Models: ${
27
- probes.models.value.models
28
- .map((model) => formatCodexDisplayText(model.id))
29
- .slice(0, 8)
30
- .join(", ") || "none"
31
- }`,
32
- );
33
- } else {
34
- lines.push(`Models: ${formatCodexDisplayText(probes.models.error)}`);
35
- }
36
- lines.push(
37
- `Account: ${
38
- probes.account.ok
39
- ? formatCodexAccountSummary(probes.account.value)
40
- : formatCodexDisplayText(probes.account.error)
41
- }`,
42
- );
43
- lines.push(
44
- `Rate limits: ${
45
- probes.limits.ok
46
- ? formatCodexRateLimitSummary(probes.limits.value)
47
- : formatCodexDisplayText(probes.limits.error)
48
- }`,
49
- );
50
- lines.push(
51
- `MCP servers: ${
52
- probes.mcps.ok
53
- ? summarizeArrayLike(probes.mcps.value)
54
- : formatCodexDisplayText(probes.mcps.error)
55
- }`,
56
- );
57
- lines.push(
58
- `Skills: ${
59
- probes.skills.ok
60
- ? summarizeArrayLike(probes.skills.value)
61
- : formatCodexDisplayText(probes.skills.error)
62
- }`,
63
- );
64
- return lines.join("\n");
65
- }
66
-
67
- export function formatModels(result: CodexAppServerModelListResult): string {
68
- if (result.models.length === 0) {
69
- return "No Codex app-server models returned.";
70
- }
71
- const lines = [
72
- "Codex models:",
73
- ...result.models.map(
74
- (model) => `- ${formatCodexDisplayText(model.id)}${model.isDefault ? " (default)" : ""}`,
75
- ),
76
- ];
77
- if (result.truncated) {
78
- lines.push("- More models available; output truncated.");
79
- }
80
- return lines.join("\n");
81
- }
82
-
83
- export function formatThreads(response: JsonValue | undefined): string {
84
- const threads = extractArray(response);
85
- if (threads.length === 0) {
86
- return "No Codex threads returned.";
87
- }
88
- return [
89
- "Codex threads:",
90
- ...threads.slice(0, 10).map((thread) => {
91
- const record = isJsonObject(thread) ? thread : {};
92
- const id = readString(record, "threadId") ?? readString(record, "id") ?? "<unknown>";
93
- const title =
94
- readString(record, "title") ?? readString(record, "name") ?? readString(record, "summary");
95
- const details = [
96
- readString(record, "model"),
97
- readString(record, "cwd"),
98
- readString(record, "updatedAt") ?? readString(record, "lastUpdatedAt"),
99
- ].filter((value): value is string => Boolean(value));
100
- return `- ${formatCodexDisplayText(id)}${title ? ` - ${formatCodexDisplayText(title)}` : ""}${
101
- details.length > 0 ? ` (${details.map(formatCodexDisplayText).join(", ")})` : ""
102
- }\n Resume: ${formatCodexResumeHint(id)}`;
103
- }),
104
- ].join("\n");
105
- }
106
-
107
- export function formatAccount(
108
- account: SafeValue<JsonValue | undefined>,
109
- limits: SafeValue<JsonValue | undefined>,
110
- authOverview?: CodexAccountAuthOverview,
111
- ): string {
112
- if (authOverview) {
113
- return formatAccountAuthOverview(authOverview);
114
- }
115
- const formattedLimits = limits.ok
116
- ? formatCodexRateLimitDetails(limits.value)
117
- : formatCodexDisplayText(limits.error);
118
- const rateLimitBlock = formattedLimits.startsWith("Codex is ")
119
- ? formattedLimits
120
- : formattedLimits.includes("\n")
121
- ? `Rate limits:\n${formattedLimits}`
122
- : `Rate limits: ${formattedLimits}`;
123
- return [
124
- `Account: ${account.ok ? formatCodexAccountSummary(account.value) : formatCodexDisplayText(account.error)}`,
125
- rateLimitBlock,
126
- ].join("\n\n");
127
- }
128
-
129
- function formatAccountAuthOverview(overview: CodexAccountAuthOverview): string {
130
- const lines: string[] = [];
131
- if (overview.currentLine) {
132
- lines.push(overview.currentLine, "");
133
- }
134
- if (overview.subscriptionLabel) {
135
- lines.push(`Subscription ${overview.subscriptionLabel}`);
136
- if (overview.subscriptionUsage) {
137
- lines.push(` ${overview.subscriptionUsage}`);
138
- }
139
- lines.push("");
140
- }
141
- if (overview.rows.length > 0) {
142
- lines.push(overview.orderTitle);
143
- for (const [index, row] of overview.rows.entries()) {
144
- lines.push(` ${index + 1}. ${row.label} ${row.kind} — ${formatAuthRowStatus(row)}`);
145
- }
146
- }
147
- while (lines.at(-1) === "") {
148
- lines.pop();
149
- }
150
- return lines.map(formatCodexAccountLine).join("\n");
151
- }
152
-
153
- function formatAuthRowStatus(row: CodexAccountAuthOverview["rows"][number]): string {
154
- return row.billingNote ? `${row.status} · ${row.billingNote}` : row.status;
155
- }
156
-
157
- export function formatComputerUseStatus(status: CodexComputerUseStatus): string {
158
- const lines = [
159
- `Computer Use: ${status.ready ? "ready" : status.enabled ? "not ready" : "disabled"}`,
160
- ];
161
- lines.push(
162
- `Plugin: ${formatCodexDisplayText(status.pluginName)} (${computerUsePluginState(status)})`,
163
- );
164
- lines.push(
165
- `MCP server: ${formatCodexDisplayText(status.mcpServerName)}${
166
- status.mcpServerAvailable ? ` (${status.tools.length} tools)` : " (unavailable)"
167
- }`,
168
- );
169
- if (status.marketplaceName) {
170
- lines.push(`Marketplace: ${formatCodexDisplayText(status.marketplaceName)}`);
171
- }
172
- if (status.tools.length > 0) {
173
- lines.push(`Tools: ${status.tools.slice(0, 8).map(formatCodexDisplayText).join(", ")}`);
174
- }
175
- lines.push(formatCodexDisplayText(status.message));
176
- return lines.join("\n");
177
- }
178
-
179
- function computerUsePluginState(status: CodexComputerUseStatus): string {
180
- if (!status.installed) {
181
- return "not installed";
182
- }
183
- return status.pluginEnabled ? "installed" : "installed, disabled";
184
- }
185
-
186
- export function formatList(response: JsonValue | undefined, label: string): string {
187
- const entries = extractArray(response);
188
- if (entries.length === 0) {
189
- return `${label}: none returned.`;
190
- }
191
- return [
192
- `${label}:`,
193
- ...entries.slice(0, 25).map((entry) => {
194
- const record = isJsonObject(entry) ? entry : {};
195
- return `- ${formatCodexDisplayText(
196
- readString(record, "name") ?? readString(record, "id") ?? JSON.stringify(entry),
197
- )}`;
198
- }),
199
- ].join("\n");
200
- }
201
-
202
- const CODEX_RESUME_SAFE_THREAD_ID_PATTERN = /^[A-Za-z0-9._:-]+$/;
203
-
204
- function formatCodexResumeHint(threadId: string): string {
205
- const safe = formatCodexTextForDisplay(threadId);
206
- if (!CODEX_RESUME_SAFE_THREAD_ID_PATTERN.test(safe)) {
207
- return "copy the thread id above and run /codex resume <thread-id>";
208
- }
209
- return `/codex resume ${safe}`;
210
- }
211
-
212
- export function formatCodexDisplayText(value: string): string {
213
- return escapeCodexChatText(formatCodexTextForDisplay(value));
214
- }
215
-
216
- function formatCodexAccountSummary(value: JsonValue | undefined): string {
217
- const safe = formatCodexTextForDisplay(summarizeAccount(value));
218
- return isLikelyEmailAddress(safe)
219
- ? escapeCodexChatTextPreservingAt(safe)
220
- : escapeCodexChatText(safe);
221
- }
222
-
223
- function formatCodexTextForDisplay(value: string): string {
224
- const safe = sanitizeCodexTextForDisplay(value).trim();
225
- return safe || "<unknown>";
226
- }
227
-
228
- function sanitizeCodexTextForDisplay(value: string): string {
229
- let safe = "";
230
- for (const character of value) {
231
- const codePoint = character.codePointAt(0);
232
- safe += codePoint != null && isUnsafeDisplayCodePoint(codePoint) ? "?" : character;
233
- }
234
- return safe;
235
- }
236
-
237
- function escapeCodexChatText(value: string): string {
238
- return value
239
- .replaceAll("&", "&amp;")
240
- .replaceAll("<", "&lt;")
241
- .replaceAll(">", "&gt;")
242
- .replaceAll("@", "\uff20")
243
- .replaceAll("`", "\uff40")
244
- .replaceAll("[", "\uff3b")
245
- .replaceAll("]", "\uff3d")
246
- .replaceAll("(", "\uff08")
247
- .replaceAll(")", "\uff09")
248
- .replaceAll("*", "\u2217")
249
- .replaceAll("_", "\uff3f")
250
- .replaceAll("~", "\uff5e")
251
- .replaceAll("|", "\uff5c");
252
- }
253
-
254
- function escapeCodexChatTextPreservingAt(value: string): string {
255
- return escapeCodexChatText(value).replaceAll("\uff20", "@");
256
- }
257
-
258
- function formatCodexAccountLine(value: string): string {
259
- if (value === "") {
260
- return "";
261
- }
262
- const safe = sanitizeCodexTextForDisplay(value).trimEnd();
263
- if (!safe.trim()) {
264
- return "";
265
- }
266
- const emailPattern = /[^\s@<>()[\]`]+@[^\s@<>()[\]`]+\.[^\s@<>()[\]`]+/gu;
267
- let formatted = "";
268
- let lastIndex = 0;
269
- for (const match of safe.matchAll(emailPattern)) {
270
- const index = match.index ?? 0;
271
- formatted += escapeCodexChatText(safe.slice(lastIndex, index));
272
- formatted += escapeCodexChatTextPreservingAt(match[0]);
273
- lastIndex = index + match[0].length;
274
- }
275
- formatted += escapeCodexChatText(safe.slice(lastIndex));
276
- return formatted;
277
- }
278
-
279
- function isLikelyEmailAddress(value: string): boolean {
280
- return /^[^\s@<>()[\]`]+@[^\s@<>()[\]`]+\.[^\s@<>()[\]`]+$/.test(value);
281
- }
282
-
283
- function isUnsafeDisplayCodePoint(codePoint: number): boolean {
284
- return (
285
- codePoint <= 0x001f ||
286
- (codePoint >= 0x007f && codePoint <= 0x009f) ||
287
- codePoint === 0x00ad ||
288
- codePoint === 0x061c ||
289
- codePoint === 0x180e ||
290
- (codePoint >= 0x200b && codePoint <= 0x200f) ||
291
- (codePoint >= 0x202a && codePoint <= 0x202e) ||
292
- (codePoint >= 0x2060 && codePoint <= 0x206f) ||
293
- codePoint === 0xfeff ||
294
- (codePoint >= 0xfff9 && codePoint <= 0xfffb) ||
295
- (codePoint >= 0xe0000 && codePoint <= 0xe007f)
296
- );
297
- }
298
-
299
- export function buildHelp(): string {
300
- return [
301
- "Codex commands:",
302
- "- /codex status",
303
- "- /codex models",
304
- "- /codex threads [filter]",
305
- "- /codex sessions --host <node> [filter]",
306
- "- /codex resume <thread-id>",
307
- "- /codex resume <session-id> --host <node> --bind here",
308
- "- /codex bind [thread-id] [--cwd <path>] [--model <model>] [--provider <provider>]",
309
- "- /codex binding",
310
- "- /codex stop",
311
- "- /codex steer <message>",
312
- "- /codex model [model]",
313
- "- /codex fast [on|off|status]",
314
- "- /codex permissions [default|yolo|status]",
315
- "- /codex detach",
316
- "- /codex compact",
317
- "- /codex review",
318
- "- /codex diagnostics [note]",
319
- "- /codex computer-use [status|install]",
320
- "- /codex account",
321
- "- /codex mcp",
322
- "- /codex skills",
323
- ].join("\n");
324
- }
325
-
326
- function summarizeAccount(value: JsonValue | undefined): string {
327
- if (!isJsonObject(value)) {
328
- return "unavailable";
329
- }
330
- const account = isJsonObject(value.account) ? value.account : value;
331
- const accountType = readString(account, "type");
332
- if (accountType === "amazonBedrock") {
333
- return "Amazon Bedrock";
334
- }
335
- return (
336
- readString(account, "email") ??
337
- readString(account, "accountEmail") ??
338
- readString(account, "planType") ??
339
- readString(account, "id") ??
340
- "available"
341
- );
342
- }
343
-
344
- function summarizeArrayLike(value: JsonValue | undefined): string {
345
- const entries = extractArray(value);
346
- if (entries.length === 0) {
347
- return "none returned";
348
- }
349
- return `${entries.length}`;
350
- }
351
-
352
- function formatCodexRateLimitSummary(value: JsonValue | undefined): string {
353
- const summary = summarizeCodexRateLimits(value);
354
- if (summary) {
355
- return formatCodexDisplayText(summary);
356
- }
357
- return formatCodexDisplayText(
358
- hasCodexRateLimitSnapshots(value) ? "none returned" : summarizeRateLimits(value),
359
- );
360
- }
361
-
362
- function formatCodexRateLimitDetails(value: JsonValue | undefined): string {
363
- const lines = summarizeCodexAccountRateLimits(value);
364
- if (!lines) {
365
- return formatCodexDisplayText(
366
- hasCodexRateLimitSnapshots(value) ? "none returned" : summarizeRateLimits(value),
367
- );
368
- }
369
- return lines.map(formatCodexDisplayText).join("\n");
370
- }
371
-
372
- function summarizeRateLimits(value: JsonValue | undefined): string {
373
- const entries = extractArray(value);
374
- if (entries.length > 0) {
375
- const count = entries.filter(isMeaningfulRateLimitSnapshot).length;
376
- return count > 0 ? `${count}` : "none returned";
377
- }
378
- if (!isJsonObject(value)) {
379
- return "none returned";
380
- }
381
- const keyed = value.rateLimitsByLimitId;
382
- if (isJsonObject(keyed)) {
383
- const count = Object.values(keyed).filter(isMeaningfulRateLimitSnapshot).length;
384
- if (count > 0) {
385
- return `${count}`;
386
- }
387
- }
388
- return isMeaningfulRateLimitSnapshot(value.rateLimits) ? "1" : "none returned";
389
- }
390
-
391
- function isMeaningfulRateLimitSnapshot(value: JsonValue | undefined): boolean {
392
- if (!isJsonObject(value)) {
393
- return false;
394
- }
395
- const reachedType =
396
- readString(value, "rateLimitReachedType") ?? readString(value, "rate_limit_reached_type");
397
- if (reachedType) {
398
- return true;
399
- }
400
- return ["primary", "secondary"].some((key) => {
401
- const window = value[key];
402
- return isJsonObject(window) && Object.values(window).some((entry) => entry != null);
403
- });
404
- }
405
-
406
- function extractArray(value: JsonValue | undefined): JsonValue[] {
407
- if (Array.isArray(value)) {
408
- return value;
409
- }
410
- if (!isJsonObject(value)) {
411
- return [];
412
- }
413
- for (const key of ["data", "items", "threads", "models", "skills", "servers", "rateLimits"]) {
414
- const child = value[key];
415
- if (Array.isArray(child)) {
416
- return child;
417
- }
418
- }
419
- return [];
420
- }
421
-
422
- export function readString(record: JsonObject, key: string): string | undefined {
423
- const value = record[key];
424
- return typeof value === "string" && value.trim() ? value.trim() : undefined;
425
- }