ocuclaw 1.2.4 → 1.3.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.
- package/README.md +21 -6
- package/dist/config/runtime-config.js +84 -3
- package/dist/domain/activity-status-adapter.js +138 -605
- package/dist/domain/activity-status-arbiter.js +109 -0
- package/dist/domain/activity-status-labels.js +906 -0
- package/dist/domain/code-span-regions.js +103 -0
- package/dist/domain/conversation-state.js +14 -1
- package/dist/domain/debug-store.js +56 -182
- package/dist/domain/glasses-ui-content-summary.js +62 -0
- package/dist/domain/glasses-ui-system-prompt.js +28 -0
- package/dist/domain/message-emoji-allowlist.js +16 -0
- package/dist/domain/message-emoji-filter.js +33 -55
- package/dist/domain/neural-emoji-reactor-system-prompt.js +43 -0
- package/dist/domain/neural-emoji-reactor-tag-config.js +56 -0
- package/dist/domain/neural-pace-modulator-system-prompt.js +32 -0
- package/dist/domain/neural-pace-modulator-tag-config.js +51 -0
- package/dist/domain/tagged-span-parser.js +121 -0
- package/dist/domain/tagged-span-strip.js +38 -0
- package/dist/even-ai/even-ai-endpoint.js +91 -0
- package/dist/even-ai/even-ai-run-waiter.js +14 -0
- package/dist/even-ai/even-ai-settings-store.js +14 -0
- package/dist/gateway/gateway-bridge.js +14 -2
- package/dist/gateway/gateway-timing-ledger.js +457 -0
- package/dist/gateway/openclaw-client.js +462 -38
- package/dist/index.js +28 -1
- package/dist/runtime/downstream-handler.js +754 -83
- package/dist/runtime/ocuclaw-settings-store.js +74 -31
- package/dist/runtime/plugin-version-service.js +23 -0
- package/dist/runtime/protocol-adapter.js +9 -0
- package/dist/runtime/provider-usage-select.js +168 -0
- package/dist/runtime/relay-client-nudge-controller.js +553 -0
- package/dist/runtime/relay-core.js +1293 -225
- package/dist/runtime/relay-health-monitor.js +172 -0
- package/dist/runtime/relay-operation-registry.js +263 -0
- package/dist/runtime/relay-service.js +201 -1
- package/dist/runtime/relay-worker-approval-replay-cache.js +68 -0
- package/dist/runtime/relay-worker-entry.js +32 -0
- package/dist/runtime/relay-worker-health.js +272 -0
- package/dist/runtime/relay-worker-protocol.js +281 -0
- package/dist/runtime/relay-worker-queue.js +202 -0
- package/dist/runtime/relay-worker-supervisor.js +1004 -0
- package/dist/runtime/relay-worker-transport.js +1051 -0
- package/dist/runtime/session-context-service.js +189 -0
- package/dist/runtime/session-service.js +638 -27
- package/dist/runtime/upstream-runtime.js +1167 -60
- package/dist/tools/device-info-tool.js +242 -0
- package/dist/tools/glasses-ui-cron.js +427 -0
- package/dist/tools/glasses-ui-descriptors.js +261 -0
- package/dist/tools/glasses-ui-limits.js +21 -0
- package/dist/tools/glasses-ui-paint-floor.js +99 -0
- package/dist/tools/glasses-ui-recipes.js +581 -0
- package/dist/tools/glasses-ui-surfaces.js +278 -0
- package/dist/tools/glasses-ui-template.js +182 -0
- package/dist/tools/glasses-ui-tool.js +1111 -0
- package/dist/tools/session-title-tool.js +209 -0
- package/dist/version.js +2 -0
- package/openclaw.plugin.json +163 -15
- package/package.json +14 -5
- package/skills/glasses-ui/SKILL.md +156 -0
- package/dist/runtime/downstream-server.js +0 -1891
|
@@ -3,6 +3,7 @@ import * as path from "node:path";
|
|
|
3
3
|
|
|
4
4
|
const STORE_VERSION = 1;
|
|
5
5
|
const STORE_FILENAME = "ocuclaw-settings.json";
|
|
6
|
+
const PERSIST_DEBOUNCE_MS = 250;
|
|
6
7
|
|
|
7
8
|
function normalizeLogger(logger) {
|
|
8
9
|
if (!logger || typeof logger !== "object") {
|
|
@@ -48,6 +49,10 @@ export function normalizeOcuClawDefaultThinking(value) {
|
|
|
48
49
|
return "";
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
export function normalizeOcuClawDefaultFastMode(value) {
|
|
53
|
+
return value === true;
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
function isStoredSnapshotCanonical(value, snapshot) {
|
|
52
57
|
if (!value || typeof value !== "object") {
|
|
53
58
|
return false;
|
|
@@ -55,7 +60,8 @@ function isStoredSnapshotCanonical(value, snapshot) {
|
|
|
55
60
|
return (
|
|
56
61
|
normalizeTrimmedString(value.systemPrompt) === snapshot.systemPrompt &&
|
|
57
62
|
normalizeTrimmedString(value.defaultModel) === snapshot.defaultModel &&
|
|
58
|
-
normalizeOcuClawDefaultThinking(value.defaultThinking) === snapshot.defaultThinking
|
|
63
|
+
normalizeOcuClawDefaultThinking(value.defaultThinking) === snapshot.defaultThinking &&
|
|
64
|
+
normalizeOcuClawDefaultFastMode(value.defaultFastMode) === snapshot.defaultFastMode
|
|
59
65
|
);
|
|
60
66
|
}
|
|
61
67
|
|
|
@@ -64,6 +70,7 @@ export function normalizeOcuClawSettingsSnapshot(value = {}) {
|
|
|
64
70
|
systemPrompt: normalizeOcuClawSystemPrompt(value.systemPrompt),
|
|
65
71
|
defaultModel: normalizeOcuClawDefaultModel(value.defaultModel),
|
|
66
72
|
defaultThinking: normalizeOcuClawDefaultThinking(value.defaultThinking),
|
|
73
|
+
defaultFastMode: normalizeOcuClawDefaultFastMode(value.defaultFastMode),
|
|
67
74
|
};
|
|
68
75
|
}
|
|
69
76
|
|
|
@@ -83,37 +90,26 @@ export function createOcuClawSettingsStore(opts = {}) {
|
|
|
83
90
|
? path.join(opts.stateDir.trim(), STORE_FILENAME)
|
|
84
91
|
: null;
|
|
85
92
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
"settings.loadsave",
|
|
90
|
-
"ocuclaw_settings_persist_skipped",
|
|
91
|
-
"debug",
|
|
92
|
-
null,
|
|
93
|
-
() => ({
|
|
94
|
-
reason,
|
|
95
|
-
systemPromptChars: snapshot.systemPrompt.length,
|
|
96
|
-
defaultModel: snapshot.defaultModel,
|
|
97
|
-
defaultThinking: snapshot.defaultThinking,
|
|
98
|
-
}),
|
|
99
|
-
);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
93
|
+
let pendingWrite = null;
|
|
94
|
+
let pendingWriteTimer = null;
|
|
95
|
+
let writeInFlight = false;
|
|
102
96
|
|
|
97
|
+
async function writeSnapshotToDisk(snapshot, reason) {
|
|
98
|
+
const payload =
|
|
99
|
+
JSON.stringify(
|
|
100
|
+
{
|
|
101
|
+
version: STORE_VERSION,
|
|
102
|
+
updatedAtMs: now(),
|
|
103
|
+
settings: snapshot,
|
|
104
|
+
},
|
|
105
|
+
null,
|
|
106
|
+
2,
|
|
107
|
+
) + "\n";
|
|
108
|
+
const tmpPath = `${statePath}.tmp`;
|
|
103
109
|
try {
|
|
104
|
-
fs.
|
|
105
|
-
fs.
|
|
106
|
-
|
|
107
|
-
JSON.stringify(
|
|
108
|
-
{
|
|
109
|
-
version: STORE_VERSION,
|
|
110
|
-
updatedAtMs: now(),
|
|
111
|
-
settings: snapshot,
|
|
112
|
-
},
|
|
113
|
-
null,
|
|
114
|
-
2,
|
|
115
|
-
) + "\n",
|
|
116
|
-
);
|
|
110
|
+
await fs.promises.mkdir(path.dirname(statePath), { recursive: true });
|
|
111
|
+
await fs.promises.writeFile(tmpPath, payload);
|
|
112
|
+
await fs.promises.rename(tmpPath, statePath);
|
|
117
113
|
emitDebug(
|
|
118
114
|
"settings.loadsave",
|
|
119
115
|
"ocuclaw_settings_persisted",
|
|
@@ -125,6 +121,7 @@ export function createOcuClawSettingsStore(opts = {}) {
|
|
|
125
121
|
systemPromptChars: snapshot.systemPrompt.length,
|
|
126
122
|
defaultModel: snapshot.defaultModel,
|
|
127
123
|
defaultThinking: snapshot.defaultThinking,
|
|
124
|
+
defaultFastMode: snapshot.defaultFastMode,
|
|
128
125
|
}),
|
|
129
126
|
);
|
|
130
127
|
} catch (err) {
|
|
@@ -142,10 +139,52 @@ export function createOcuClawSettingsStore(opts = {}) {
|
|
|
142
139
|
message: err && err.message ? err.message : String(err),
|
|
143
140
|
}),
|
|
144
141
|
);
|
|
145
|
-
throw err;
|
|
146
142
|
}
|
|
147
143
|
}
|
|
148
144
|
|
|
145
|
+
function flushPendingWrite() {
|
|
146
|
+
if (writeInFlight || !pendingWrite) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const { snapshot, reason } = pendingWrite;
|
|
150
|
+
pendingWrite = null;
|
|
151
|
+
writeInFlight = true;
|
|
152
|
+
writeSnapshotToDisk(snapshot, reason).finally(() => {
|
|
153
|
+
writeInFlight = false;
|
|
154
|
+
if (pendingWrite) {
|
|
155
|
+
flushPendingWrite();
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function persistSnapshot(snapshot, reason) {
|
|
161
|
+
if (!statePath) {
|
|
162
|
+
emitDebug(
|
|
163
|
+
"settings.loadsave",
|
|
164
|
+
"ocuclaw_settings_persist_skipped",
|
|
165
|
+
"debug",
|
|
166
|
+
null,
|
|
167
|
+
() => ({
|
|
168
|
+
reason,
|
|
169
|
+
systemPromptChars: snapshot.systemPrompt.length,
|
|
170
|
+
defaultModel: snapshot.defaultModel,
|
|
171
|
+
defaultThinking: snapshot.defaultThinking,
|
|
172
|
+
defaultFastMode: snapshot.defaultFastMode,
|
|
173
|
+
}),
|
|
174
|
+
);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
pendingWrite = { snapshot, reason };
|
|
179
|
+
if (pendingWriteTimer) {
|
|
180
|
+
clearTimeout(pendingWriteTimer);
|
|
181
|
+
}
|
|
182
|
+
pendingWriteTimer = setTimeout(() => {
|
|
183
|
+
pendingWriteTimer = null;
|
|
184
|
+
flushPendingWrite();
|
|
185
|
+
}, PERSIST_DEBOUNCE_MS);
|
|
186
|
+
}
|
|
187
|
+
|
|
149
188
|
function loadInitialSnapshot() {
|
|
150
189
|
if (!statePath || !fs.existsSync(statePath)) {
|
|
151
190
|
persistSnapshot(defaults, "seed_defaults");
|
|
@@ -173,6 +212,7 @@ export function createOcuClawSettingsStore(opts = {}) {
|
|
|
173
212
|
systemPromptChars: loaded.systemPrompt.length,
|
|
174
213
|
defaultModel: loaded.defaultModel,
|
|
175
214
|
defaultThinking: loaded.defaultThinking,
|
|
215
|
+
defaultFastMode: loaded.defaultFastMode,
|
|
176
216
|
}),
|
|
177
217
|
);
|
|
178
218
|
if (
|
|
@@ -223,6 +263,9 @@ export function createOcuClawSettingsStore(opts = {}) {
|
|
|
223
263
|
defaultThinking: hasOwn(patch, "defaultThinking")
|
|
224
264
|
? normalizeOcuClawDefaultThinking(patch.defaultThinking)
|
|
225
265
|
: snapshot.defaultThinking,
|
|
266
|
+
defaultFastMode: hasOwn(patch, "defaultFastMode")
|
|
267
|
+
? normalizeOcuClawDefaultFastMode(patch.defaultFastMode)
|
|
268
|
+
: snapshot.defaultFastMode,
|
|
226
269
|
};
|
|
227
270
|
snapshot = next;
|
|
228
271
|
persistSnapshot(snapshot, "set_settings");
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { PLUGIN_VERSION, REQUIRES_CLIENT_VERSION } from "../version.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Plugin version provider. Exposes the build-time version constants used by the
|
|
5
|
+
* relay handshake. No process execution.
|
|
6
|
+
*/
|
|
7
|
+
function createPluginVersionService() {
|
|
8
|
+
function getPluginVersion() {
|
|
9
|
+
return typeof PLUGIN_VERSION === "string" && PLUGIN_VERSION.length > 0
|
|
10
|
+
? PLUGIN_VERSION
|
|
11
|
+
: null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function getRequiresClientVersion() {
|
|
15
|
+
return typeof REQUIRES_CLIENT_VERSION === "string" && REQUIRES_CLIENT_VERSION.length > 0
|
|
16
|
+
? REQUIRES_CLIENT_VERSION
|
|
17
|
+
: null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return { getPluginVersion, getRequiresClientVersion };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { createPluginVersionService };
|
|
@@ -4,8 +4,11 @@ const V1_TO_INTERNAL = {
|
|
|
4
4
|
switchSession: "ocuclaw.session.switch",
|
|
5
5
|
newChat: "ocuclaw.session.reset",
|
|
6
6
|
getSessions: "ocuclaw.session.list",
|
|
7
|
+
deleteSessions: "ocuclaw.session.delete",
|
|
8
|
+
setSessionPinned: "ocuclaw.session.pinned.set",
|
|
7
9
|
getStatus: "ocuclaw.runtime.status.get",
|
|
8
10
|
getModelsCatalog: "ocuclaw.model.catalog.get",
|
|
11
|
+
getProviderUsageSnapshot: "ocuclaw.provider.usage.get",
|
|
9
12
|
getSkills: "ocuclaw.skills.catalog.get",
|
|
10
13
|
getSonioxModels: "ocuclaw.voice.soniox.models.get",
|
|
11
14
|
getSessionModelConfig: "ocuclaw.session.config.get",
|
|
@@ -22,6 +25,7 @@ const V1_TO_INTERNAL = {
|
|
|
22
25
|
"debug-set": "ocuclaw.debug.config.set",
|
|
23
26
|
"debug-dump": "ocuclaw.debug.events.query",
|
|
24
27
|
resume: "ocuclaw.sync.resume",
|
|
28
|
+
compactSession: "ocuclaw.session.compact",
|
|
25
29
|
};
|
|
26
30
|
|
|
27
31
|
const RESULT_TO_V1 = {
|
|
@@ -36,15 +40,18 @@ const RESULT_TO_V1 = {
|
|
|
36
40
|
"ocuclaw.settings.snapshot": "ocuClawSettings",
|
|
37
41
|
"ocuclaw.settings.set.ack": "ocuClawSettingsAck",
|
|
38
42
|
"ocuclaw.model.catalog.snapshot": "modelsCatalog",
|
|
43
|
+
"ocuclaw.provider.usage.snapshot": "providerUsageSnapshot",
|
|
39
44
|
"ocuclaw.skills.catalog.snapshot": "skillsCatalog",
|
|
40
45
|
"ocuclaw.voice.soniox.models.snapshot": "sonioxModels",
|
|
41
46
|
"ocuclaw.approval.resolve.ack": "approvalResponseAck",
|
|
47
|
+
"ocuclaw.session.compact.ack": "compactSessionAck",
|
|
42
48
|
};
|
|
43
49
|
|
|
44
50
|
const EVENT_TO_V1 = {
|
|
45
51
|
"ocuclaw.view.pages.snapshot": "pages",
|
|
46
52
|
"ocuclaw.runtime.status": "status",
|
|
47
53
|
"ocuclaw.activity.update": "activity",
|
|
54
|
+
"ocuclaw.typing.update": "typing",
|
|
48
55
|
"ocuclaw.message.stream.delta": "streaming",
|
|
49
56
|
"ocuclaw.session.switch.applied": "sessionSwitched",
|
|
50
57
|
"ocuclaw.sync.resume.ack": "resume-ack",
|
|
@@ -52,6 +59,8 @@ const EVENT_TO_V1 = {
|
|
|
52
59
|
"ocuclaw.approval.resolved": "approvalResolved",
|
|
53
60
|
"ocuclaw.remote.control": "remote-control",
|
|
54
61
|
"ocuclaw.protocol.tap.frame": "protocol",
|
|
62
|
+
"ocuclaw.provider.usage.snapshot": "providerUsageSnapshot",
|
|
63
|
+
"ocuclaw.session.context.snapshot": "sessionContextSnapshot",
|
|
55
64
|
};
|
|
56
65
|
|
|
57
66
|
const INTERNAL_TO_V1 = Object.fromEntries(
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
function normalizeWindowKey(label, index) {
|
|
2
|
+
const normalized = typeof label === "string" ? label.trim().toLowerCase() : "";
|
|
3
|
+
|
|
4
|
+
if (normalized === "week" || normalized === "weekly") {
|
|
5
|
+
return { key: "week", sortOrder: 20 };
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (/^5\s*(h|hr|hrs|hour|hours)?$/.test(normalized)) {
|
|
9
|
+
return { key: "5h", sortOrder: 10 };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const key = normalized.replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
13
|
+
return {
|
|
14
|
+
key: key || `window_${index}`,
|
|
15
|
+
sortOrder: 100 + index,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function toFiniteNumber(value, fallback) {
|
|
20
|
+
if (value === null || value === undefined || value === "") {
|
|
21
|
+
return fallback;
|
|
22
|
+
}
|
|
23
|
+
const number = Number(value);
|
|
24
|
+
return Number.isFinite(number) ? number : fallback;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function normalizeWindow(window, index) {
|
|
28
|
+
const normalizedKey = normalizeWindowKey(window && window.label, index);
|
|
29
|
+
const label =
|
|
30
|
+
typeof window?.label === "string" && window.label.trim()
|
|
31
|
+
? window.label.trim()
|
|
32
|
+
: normalizedKey.key;
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
key: normalizedKey.key,
|
|
36
|
+
label,
|
|
37
|
+
usedPercent: toFiniteNumber(window && window.usedPercent, 0),
|
|
38
|
+
resetAtMs: toFiniteNumber(window && window.resetAt, null),
|
|
39
|
+
sortOrder: normalizedKey.sortOrder,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isStrongerWindow(candidate, current) {
|
|
44
|
+
if (candidate.usedPercent !== current.usedPercent) {
|
|
45
|
+
return candidate.usedPercent > current.usedPercent;
|
|
46
|
+
}
|
|
47
|
+
return candidate.sortOrder > current.sortOrder;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function selectLimitingWindow(windows) {
|
|
51
|
+
if (!Array.isArray(windows) || windows.length === 0) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return windows.slice().sort((left, right) => {
|
|
56
|
+
const leftExhausted = left.usedPercent >= 100;
|
|
57
|
+
const rightExhausted = right.usedPercent >= 100;
|
|
58
|
+
|
|
59
|
+
if (leftExhausted !== rightExhausted) {
|
|
60
|
+
return leftExhausted ? -1 : 1;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (left.usedPercent !== right.usedPercent) {
|
|
64
|
+
return right.usedPercent - left.usedPercent;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return right.sortOrder - left.sortOrder;
|
|
68
|
+
})[0];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function selectProviderUsageSnapshot(summary, opts = {}) {
|
|
72
|
+
const providers = Array.isArray(summary && summary.providers) ? summary.providers : [];
|
|
73
|
+
const activeProvider =
|
|
74
|
+
typeof opts.provider === "string" ? opts.provider.trim().toLowerCase() : "";
|
|
75
|
+
|
|
76
|
+
if (!activeProvider) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const namedEntries = providers.filter(
|
|
81
|
+
(entry) => typeof entry?.provider === "string",
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
let match = namedEntries.find(
|
|
85
|
+
(entry) => entry.provider.trim().toLowerCase() === activeProvider,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// Family fallback: the session model config reports the base provider id
|
|
89
|
+
// (e.g. "openai") while the usage summary keys the same usage by its
|
|
90
|
+
// sub-provider source (e.g. "openai-codex"). When there is no exact match
|
|
91
|
+
// but exactly ONE summary entry belongs to the active provider's family
|
|
92
|
+
// ("${activeProvider}-…"), resolve it. Restricted to a single family member
|
|
93
|
+
// to avoid ambiguous attribution when multiple sub-providers exist.
|
|
94
|
+
if (!match) {
|
|
95
|
+
const familyMatches = namedEntries.filter((entry) =>
|
|
96
|
+
entry.provider.trim().toLowerCase().startsWith(`${activeProvider}-`),
|
|
97
|
+
);
|
|
98
|
+
if (familyMatches.length === 1) {
|
|
99
|
+
match = familyMatches[0];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!match) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const windows = (Array.isArray(match.windows) ? match.windows : []).map(normalizeWindow);
|
|
108
|
+
const limitingWindow = selectLimitingWindow(windows);
|
|
109
|
+
const dedupedWindows = [];
|
|
110
|
+
const keyToIndex = new Map();
|
|
111
|
+
|
|
112
|
+
for (const window of windows) {
|
|
113
|
+
if (!keyToIndex.has(window.key)) {
|
|
114
|
+
keyToIndex.set(window.key, dedupedWindows.length);
|
|
115
|
+
dedupedWindows.push(window);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const existingIndex = keyToIndex.get(window.key);
|
|
120
|
+
const existingWindow = dedupedWindows[existingIndex];
|
|
121
|
+
if (isStrongerWindow(window, existingWindow)) {
|
|
122
|
+
dedupedWindows[existingIndex] = window;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const provider = typeof match.provider === "string" ? match.provider.trim() : match.provider;
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
sessionKey: typeof opts.sessionKey === "string" ? opts.sessionKey : null,
|
|
130
|
+
provider,
|
|
131
|
+
displayName:
|
|
132
|
+
typeof match.displayName === "string" && match.displayName.trim()
|
|
133
|
+
? match.displayName.trim()
|
|
134
|
+
: provider,
|
|
135
|
+
fetchedAtMs: toFiniteNumber(summary && summary.updatedAt, null),
|
|
136
|
+
stale: opts.stale === true,
|
|
137
|
+
limitingWindowKey: limitingWindow ? limitingWindow.key : null,
|
|
138
|
+
windows: dedupedWindows,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function buildRateLimitInfoFromSnapshot(snapshot) {
|
|
143
|
+
if (!snapshot || snapshot.stale === true || !snapshot.limitingWindowKey) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
if (snapshot.poolStatus === "ready") {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const limitingWindow = Array.isArray(snapshot.windows)
|
|
151
|
+
? snapshot.windows.find((window) => window.key === snapshot.limitingWindowKey) || null
|
|
152
|
+
: null;
|
|
153
|
+
|
|
154
|
+
if (!limitingWindow) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
sessionKey: snapshot.sessionKey || null,
|
|
160
|
+
provider: snapshot.provider || null,
|
|
161
|
+
windowKey: limitingWindow.key,
|
|
162
|
+
windowLabel: limitingWindow.label,
|
|
163
|
+
usedPercent: limitingWindow.usedPercent,
|
|
164
|
+
resetAtMs: limitingWindow.resetAtMs,
|
|
165
|
+
fetchedAtMs: snapshot.fetchedAtMs,
|
|
166
|
+
stale: false,
|
|
167
|
+
};
|
|
168
|
+
}
|