alvin-bot 5.7.0 → 5.8.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/CHANGELOG.md +25 -0
- package/README.md +25 -31
- package/dist/claude.js +1 -102
- package/dist/config.js +1 -96
- package/dist/engine.js +1 -90
- package/dist/find-claude-binary.js +1 -98
- package/dist/handlers/async-agent-chunk-handler.js +1 -50
- package/dist/handlers/background-bypass.js +1 -75
- package/dist/handlers/commands.js +1 -2336
- package/dist/handlers/cron-progress.js +1 -52
- package/dist/handlers/document.js +1 -194
- package/dist/handlers/message.js +1 -959
- package/dist/handlers/photo.js +1 -154
- package/dist/handlers/platform-message.js +1 -360
- package/dist/handlers/stuck-timer.js +1 -54
- package/dist/handlers/video.js +1 -237
- package/dist/handlers/voice.js +1 -148
- package/dist/i18n.js +1 -805
- package/dist/index.js +1 -697
- package/dist/init-data-dir.js +1 -98
- package/dist/middleware/auth.js +1 -233
- package/dist/migrate.js +1 -162
- package/dist/paths.js +1 -146
- package/dist/platforms/discord.js +1 -175
- package/dist/platforms/index.js +1 -130
- package/dist/platforms/signal.js +1 -205
- package/dist/platforms/slack-slash-parser.js +1 -32
- package/dist/platforms/slack.js +1 -501
- package/dist/platforms/telegram.js +1 -111
- package/dist/platforms/types.js +1 -8
- package/dist/platforms/whatsapp-auth-helpers.js +1 -53
- package/dist/platforms/whatsapp.js +1 -707
- package/dist/providers/claude-sdk-provider.js +1 -565
- package/dist/providers/codex-cli-provider.js +1 -134
- package/dist/providers/index.js +1 -7
- package/dist/providers/ollama-provider.js +1 -32
- package/dist/providers/openai-compatible.js +1 -406
- package/dist/providers/registry.js +1 -352
- package/dist/providers/runtime-header.js +1 -45
- package/dist/providers/tool-executor.js +1 -475
- package/dist/providers/types.js +1 -227
- package/dist/services/access.js +1 -144
- package/dist/services/allowed-users-gate.js +1 -56
- package/dist/services/alvin-dispatch.js +1 -174
- package/dist/services/alvin-mcp-tools.js +1 -104
- package/dist/services/asset-index.js +1 -224
- package/dist/services/async-agent-parser.js +1 -418
- package/dist/services/async-agent-watcher.js +1 -583
- package/dist/services/auto-diagnostic.js +1 -228
- package/dist/services/broadcast.js +1 -52
- package/dist/services/browser-manager.js +1 -562
- package/dist/services/browser-webfetch.js +1 -127
- package/dist/services/browser.js +1 -121
- package/dist/services/cdp-bootstrap.js +1 -357
- package/dist/services/compaction.js +1 -144
- package/dist/services/critical-notify.js +1 -203
- package/dist/services/cron-resolver.js +1 -58
- package/dist/services/cron-scheduling.js +1 -310
- package/dist/services/cron.js +1 -861
- package/dist/services/custom-tools.js +1 -317
- package/dist/services/delivery-queue.js +1 -173
- package/dist/services/delivery-registry.js +1 -21
- package/dist/services/disk-cleanup.js +1 -203
- package/dist/services/elevenlabs.js +1 -58
- package/dist/services/embeddings/auto-detect.js +1 -74
- package/dist/services/embeddings/fts5.js +1 -108
- package/dist/services/embeddings/gemini.js +1 -65
- package/dist/services/embeddings/index.js +1 -496
- package/dist/services/embeddings/ollama.js +1 -78
- package/dist/services/embeddings/openai.js +1 -49
- package/dist/services/embeddings/provider.js +1 -22
- package/dist/services/embeddings/vector-base.js +1 -113
- package/dist/services/embeddings-migration.js +1 -193
- package/dist/services/embeddings.js +1 -9
- package/dist/services/env-file.js +1 -50
- package/dist/services/exec-guard.js +1 -71
- package/dist/services/fallback-order.js +1 -154
- package/dist/services/file-permissions.js +1 -93
- package/dist/services/heartbeat-file.js +1 -65
- package/dist/services/heartbeat.js +1 -313
- package/dist/services/hooks.js +1 -44
- package/dist/services/imagegen.js +1 -72
- package/dist/services/language-detect.js +1 -154
- package/dist/services/markdown.js +1 -63
- package/dist/services/mcp.js +1 -263
- package/dist/services/memory-extractor.js +1 -178
- package/dist/services/memory-inject-mode.js +1 -43
- package/dist/services/memory-layers.js +1 -156
- package/dist/services/memory.js +1 -146
- package/dist/services/ollama-manager.js +1 -339
- package/dist/services/permissions-wizard.js +1 -291
- package/dist/services/personality.js +1 -376
- package/dist/services/plugins.js +1 -171
- package/dist/services/preflight.js +1 -292
- package/dist/services/process-manager.js +1 -291
- package/dist/services/release-highlights.js +1 -79
- package/dist/services/reminders.js +1 -97
- package/dist/services/restart.js +1 -48
- package/dist/services/security-audit.js +1 -74
- package/dist/services/self-diagnosis.js +1 -272
- package/dist/services/self-search.js +1 -129
- package/dist/services/session-persistence.js +1 -237
- package/dist/services/session.js +1 -282
- package/dist/services/skills.js +1 -290
- package/dist/services/ssrf-guard.js +1 -162
- package/dist/services/standing-orders.js +1 -29
- package/dist/services/steer-channel.js +1 -46
- package/dist/services/stop-controller.js +1 -52
- package/dist/services/subagent-dedup.js +1 -86
- package/dist/services/subagent-delivery.js +1 -452
- package/dist/services/subagent-stats.js +1 -123
- package/dist/services/subagents.js +1 -814
- package/dist/services/sudo.js +1 -329
- package/dist/services/telegram.js +1 -158
- package/dist/services/timing-safe-bearer.js +1 -51
- package/dist/services/tool-discovery.js +1 -214
- package/dist/services/trends.js +1 -580
- package/dist/services/updater.js +1 -291
- package/dist/services/usage-tracker.js +1 -144
- package/dist/services/users.js +1 -271
- package/dist/services/voice.js +1 -104
- package/dist/services/watchdog-brake.js +1 -154
- package/dist/services/watchdog.js +1 -311
- package/dist/services/workspaces.js +1 -276
- package/dist/tui/index.js +1 -667
- package/dist/util/console-formatter.js +1 -109
- package/dist/util/debounce.js +1 -24
- package/dist/util/telegram-error-filter.js +1 -62
- package/dist/version.js +1 -24
- package/dist/web/bind-strategy.js +1 -42
- package/dist/web/canvas.js +1 -30
- package/dist/web/doctor-api.js +1 -604
- package/dist/web/openai-compat.js +1 -252
- package/dist/web/server.js +1 -1902
- package/dist/web/setup-api.js +1 -1101
- package/package.json +5 -2
- package/dist/.metadata_never_index +0 -0
|
@@ -1,237 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session Persistence Service (v4.11.0)
|
|
3
|
-
*
|
|
4
|
-
* The sessions Map in src/services/session.ts is in-memory only. When the bot
|
|
5
|
-
* restarts (launchctl, watchdog brake, npm install, crash), every user's
|
|
6
|
-
* Claude SDK session_id, conversation history, language preference, and
|
|
7
|
-
* tracking counters are wiped. Claude SDK then starts a fresh conversation
|
|
8
|
-
* on the next user message, behaving like a goldfish.
|
|
9
|
-
*
|
|
10
|
-
* This service:
|
|
11
|
-
* 1. Flushes a sanitized snapshot of getAllSessions() to disk (atomic write).
|
|
12
|
-
* 2. Loads that snapshot at bot startup and rehydrates the Map.
|
|
13
|
-
* 3. Coalesces rapid mutations via a debounced timer.
|
|
14
|
-
*
|
|
15
|
-
* Persisted fields are intentionally a SUBSET of UserSession — runtime-only
|
|
16
|
-
* fields like abortController, isProcessing, and messageQueue are excluded.
|
|
17
|
-
*
|
|
18
|
-
* History is capped at MAX_PERSISTED_HISTORY (50 entries) per session so the
|
|
19
|
-
* state file stays small even after months of conversation.
|
|
20
|
-
*/
|
|
21
|
-
import fs from "fs";
|
|
22
|
-
import { dirname } from "path";
|
|
23
|
-
import { SESSIONS_STATE_FILE } from "../paths.js";
|
|
24
|
-
import { SECURE_MODE } from "./file-permissions.js";
|
|
25
|
-
import { getAllSessions, getTelegramWorkspacesMap, } from "./session.js";
|
|
26
|
-
/** History entries to keep in the persisted snapshot (per session). */
|
|
27
|
-
const MAX_PERSISTED_HISTORY = 50;
|
|
28
|
-
/** Debounce window for grouped mutations. */
|
|
29
|
-
const DEBOUNCE_MS = 1500;
|
|
30
|
-
let debounceTimer = null;
|
|
31
|
-
/** Strip runtime-only fields and clip history. */
|
|
32
|
-
function snapshot(session) {
|
|
33
|
-
return {
|
|
34
|
-
sessionId: session.sessionId,
|
|
35
|
-
workingDir: session.workingDir,
|
|
36
|
-
workspaceName: session.workspaceName,
|
|
37
|
-
language: session.language,
|
|
38
|
-
effort: session.effort,
|
|
39
|
-
voiceReply: session.voiceReply,
|
|
40
|
-
lastActivity: session.lastActivity,
|
|
41
|
-
startedAt: session.startedAt,
|
|
42
|
-
totalCost: session.totalCost,
|
|
43
|
-
messageCount: session.messageCount,
|
|
44
|
-
toolUseCount: session.toolUseCount,
|
|
45
|
-
totalInputTokens: session.totalInputTokens,
|
|
46
|
-
totalOutputTokens: session.totalOutputTokens,
|
|
47
|
-
lastSdkHistoryIndex: session.lastSdkHistoryIndex,
|
|
48
|
-
history: session.history.slice(-MAX_PERSISTED_HISTORY),
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
/** Skip sessions that have never accumulated meaningful state. */
|
|
52
|
-
function isWorthPersisting(session) {
|
|
53
|
-
return !!(session.sessionId ||
|
|
54
|
-
session.history.length > 0 ||
|
|
55
|
-
session.messageCount > 0 ||
|
|
56
|
-
session.totalCost > 0);
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Atomic flush of all worth-persisting sessions to SESSIONS_STATE_FILE.
|
|
60
|
-
* Cancels any pending debounced flush — this is the immediate path.
|
|
61
|
-
*/
|
|
62
|
-
export async function flushSessions() {
|
|
63
|
-
if (debounceTimer) {
|
|
64
|
-
clearTimeout(debounceTimer);
|
|
65
|
-
debounceTimer = null;
|
|
66
|
-
}
|
|
67
|
-
try {
|
|
68
|
-
const all = getAllSessions();
|
|
69
|
-
const out = {};
|
|
70
|
-
for (const [key, session] of all) {
|
|
71
|
-
if (isWorthPersisting(session)) {
|
|
72
|
-
out[key] = snapshot(session);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
// Ensure the state directory exists
|
|
76
|
-
fs.mkdirSync(dirname(SESSIONS_STATE_FILE), { recursive: true });
|
|
77
|
-
// v4.12.0 — Persist Telegram active-workspace map alongside sessions.
|
|
78
|
-
// Wrapped in a versioned envelope so we can add more state later without
|
|
79
|
-
// breaking loadPersistedSessions' backwards-compat path for older files.
|
|
80
|
-
const tgWorkspaces = {};
|
|
81
|
-
for (const [userId, ws] of getTelegramWorkspacesMap()) {
|
|
82
|
-
tgWorkspaces[userId] = ws;
|
|
83
|
-
}
|
|
84
|
-
const envelope = {
|
|
85
|
-
version: 2,
|
|
86
|
-
sessions: out,
|
|
87
|
-
telegramWorkspaces: tgWorkspaces,
|
|
88
|
-
};
|
|
89
|
-
// Atomic write: tmp + rename. v4.12.2 — mode 0o600 enforced so other
|
|
90
|
-
// users on the same machine can't read conversation history or tokens.
|
|
91
|
-
const tmpFile = `${SESSIONS_STATE_FILE}.tmp`;
|
|
92
|
-
fs.writeFileSync(tmpFile, JSON.stringify(envelope, null, 2), {
|
|
93
|
-
encoding: "utf-8",
|
|
94
|
-
mode: SECURE_MODE,
|
|
95
|
-
});
|
|
96
|
-
// Belt-and-suspenders: chmod in case the tmp file already existed with
|
|
97
|
-
// looser permissions (writeFileSync's mode option is only applied on
|
|
98
|
-
// initial create).
|
|
99
|
-
try {
|
|
100
|
-
fs.chmodSync(tmpFile, SECURE_MODE);
|
|
101
|
-
}
|
|
102
|
-
catch { /* fs may not support */ }
|
|
103
|
-
fs.renameSync(tmpFile, SESSIONS_STATE_FILE);
|
|
104
|
-
}
|
|
105
|
-
catch (err) {
|
|
106
|
-
console.warn("⚠️ session-persistence: flush failed —", err instanceof Error ? err.message : String(err));
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Schedule a debounced flush. Multiple rapid calls collapse into one.
|
|
111
|
-
* Use this from any session-mutating code path; the immediate flushSessions()
|
|
112
|
-
* is reserved for graceful shutdown.
|
|
113
|
-
*/
|
|
114
|
-
export function schedulePersist() {
|
|
115
|
-
if (debounceTimer)
|
|
116
|
-
clearTimeout(debounceTimer);
|
|
117
|
-
debounceTimer = setTimeout(() => {
|
|
118
|
-
debounceTimer = null;
|
|
119
|
-
void flushSessions();
|
|
120
|
-
}, DEBOUNCE_MS);
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Load the persisted sessions snapshot from disk and rehydrate the Map.
|
|
124
|
-
* Called once at bot startup. Returns the number of sessions restored.
|
|
125
|
-
*/
|
|
126
|
-
export function loadPersistedSessions() {
|
|
127
|
-
let raw;
|
|
128
|
-
try {
|
|
129
|
-
raw = fs.readFileSync(SESSIONS_STATE_FILE, "utf-8");
|
|
130
|
-
}
|
|
131
|
-
catch {
|
|
132
|
-
return 0; // no file = nothing to do
|
|
133
|
-
}
|
|
134
|
-
let raw_parsed;
|
|
135
|
-
try {
|
|
136
|
-
raw_parsed = JSON.parse(raw);
|
|
137
|
-
}
|
|
138
|
-
catch (err) {
|
|
139
|
-
console.warn("⚠️ session-persistence: corrupt sessions.json, starting fresh —", err instanceof Error ? err.message : String(err));
|
|
140
|
-
return 0;
|
|
141
|
-
}
|
|
142
|
-
if (!raw_parsed || typeof raw_parsed !== "object")
|
|
143
|
-
return 0;
|
|
144
|
-
// v4.12.0 — Detect envelope format vs legacy v4.11.0 flat format
|
|
145
|
-
// M4: Validate the top-level shape before trusting any field.
|
|
146
|
-
if (Array.isArray(raw_parsed)) {
|
|
147
|
-
// An array at root is not a valid sessions file
|
|
148
|
-
console.warn("⚠️ session-persistence: sessions file contains an array at root, starting fresh");
|
|
149
|
-
return 0;
|
|
150
|
-
}
|
|
151
|
-
let parsed;
|
|
152
|
-
let tgWorkspaces = {};
|
|
153
|
-
if (raw_parsed &&
|
|
154
|
-
typeof raw_parsed === "object" &&
|
|
155
|
-
"version" in raw_parsed &&
|
|
156
|
-
"sessions" in raw_parsed) {
|
|
157
|
-
const env = raw_parsed;
|
|
158
|
-
// M4: sessions field must be a non-null object; degrade gracefully if tampered
|
|
159
|
-
if (!env.sessions || typeof env.sessions !== "object" || Array.isArray(env.sessions)) {
|
|
160
|
-
console.warn("⚠️ session-persistence: 'sessions' field is not an object, starting fresh");
|
|
161
|
-
return 0;
|
|
162
|
-
}
|
|
163
|
-
parsed = env.sessions;
|
|
164
|
-
tgWorkspaces = (env.telegramWorkspaces && typeof env.telegramWorkspaces === "object" && !Array.isArray(env.telegramWorkspaces))
|
|
165
|
-
? env.telegramWorkspaces
|
|
166
|
-
: {};
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
// Legacy flat format (v4.11.0) — must also be an object
|
|
170
|
-
if (!raw_parsed || typeof raw_parsed !== "object") {
|
|
171
|
-
console.warn("⚠️ session-persistence: sessions file is not a valid object, starting fresh");
|
|
172
|
-
return 0;
|
|
173
|
-
}
|
|
174
|
-
parsed = raw_parsed;
|
|
175
|
-
}
|
|
176
|
-
// Rehydrate Telegram workspace map
|
|
177
|
-
const tgMap = getTelegramWorkspacesMap();
|
|
178
|
-
for (const [userId, name] of Object.entries(tgWorkspaces)) {
|
|
179
|
-
if (typeof name === "string")
|
|
180
|
-
tgMap.set(userId, name);
|
|
181
|
-
}
|
|
182
|
-
// Use the same getAllSessions Map that session.ts exports
|
|
183
|
-
const all = getAllSessions();
|
|
184
|
-
let count = 0;
|
|
185
|
-
for (const [key, persisted] of Object.entries(parsed)) {
|
|
186
|
-
if (!persisted || typeof persisted !== "object")
|
|
187
|
-
continue;
|
|
188
|
-
// Build a UserSession from the persisted shape, filling defaults for any
|
|
189
|
-
// fields added in newer schema versions.
|
|
190
|
-
const restored = {
|
|
191
|
-
// v5.1.x — Canonical registry key stamped so stop-controller and watcher
|
|
192
|
-
// helpers can read session.sessionKey regardless of how the session was
|
|
193
|
-
// created (direct access or rehydrated from disk).
|
|
194
|
-
sessionKey: key,
|
|
195
|
-
sessionId: persisted.sessionId ?? null,
|
|
196
|
-
workingDir: persisted.workingDir ?? process.cwd(),
|
|
197
|
-
workspaceName: persisted.workspaceName ?? null,
|
|
198
|
-
isProcessing: false,
|
|
199
|
-
abortController: null,
|
|
200
|
-
_stopRequested: null,
|
|
201
|
-
_qHandle: null,
|
|
202
|
-
_steerChannel: null,
|
|
203
|
-
_steerAckSentThisTurn: false,
|
|
204
|
-
_turnId: null,
|
|
205
|
-
lastActivity: persisted.lastActivity ?? Date.now(),
|
|
206
|
-
startedAt: persisted.startedAt ?? Date.now(),
|
|
207
|
-
totalCost: persisted.totalCost ?? 0,
|
|
208
|
-
costByProvider: {},
|
|
209
|
-
queriesByProvider: {},
|
|
210
|
-
effort: persisted.effort ?? "medium",
|
|
211
|
-
voiceReply: persisted.voiceReply ?? false,
|
|
212
|
-
messageCount: persisted.messageCount ?? 0,
|
|
213
|
-
toolUseCount: persisted.toolUseCount ?? 0,
|
|
214
|
-
totalInputTokens: persisted.totalInputTokens ?? 0,
|
|
215
|
-
totalOutputTokens: persisted.totalOutputTokens ?? 0,
|
|
216
|
-
lastTurnInputTokens: 0,
|
|
217
|
-
compactionCount: 0,
|
|
218
|
-
checkpointHintsInjected: 0,
|
|
219
|
-
sdkSubTaskCount: 0,
|
|
220
|
-
// v4.12.3 — Don't persist pendingBackgroundCount. On restart, the
|
|
221
|
-
// async-agent-watcher re-hydrates its own state file and polls each
|
|
222
|
-
// pending agent's outputFile, which handles delivery independently.
|
|
223
|
-
// Starting at 0 avoids stale counters surviving a crash.
|
|
224
|
-
pendingBackgroundCount: 0,
|
|
225
|
-
history: Array.isArray(persisted.history) ? persisted.history : [],
|
|
226
|
-
language: persisted.language ?? "en",
|
|
227
|
-
messageQueue: [],
|
|
228
|
-
lastSdkHistoryIndex: persisted.lastSdkHistoryIndex ?? -1,
|
|
229
|
-
};
|
|
230
|
-
all.set(key, restored);
|
|
231
|
-
count++;
|
|
232
|
-
}
|
|
233
|
-
if (count > 0) {
|
|
234
|
-
console.log(`🧠 session-persistence: restored ${count} session(s) from disk`);
|
|
235
|
-
}
|
|
236
|
-
return count;
|
|
237
|
-
}
|
|
1
|
+
(function(_0x224624,_0x38df0d){const _0x2f3d49=_0x9392,_0x1f63a6=_0x9392,_0x24a2fc=_0x224624();while(!![]){try{const _0x89b33f=parseInt(_0x2f3d49(0x18b))/(-0x178+0x1*0x1b6f+0x19f6*-0x1)+-parseInt(_0x2f3d49(0x15f))/(0xc3*-0xf+0x7*-0x509+0x2eae)+parseInt(_0x2f3d49(0x190))/(0x188+-0x185+0x0)*(parseInt(_0x1f63a6(0x16f))/(0x16f6*-0x1+0x3*-0x901+0x31fd))+-parseInt(_0x1f63a6(0x194))/(-0xcfb+-0x6f1+-0x5*-0x3fd)+-parseInt(_0x2f3d49(0x17b))/(-0xef8+0x1a46+0x1*-0xb48)*(parseInt(_0x2f3d49(0x193))/(0x1*0x796+0xa*-0x18e+0x199*0x5))+parseInt(_0x1f63a6(0x18d))/(0x1856+-0x9a9*-0x1+0x1*-0x21f7)*(parseInt(_0x1f63a6(0x174))/(-0x1c*-0xf5+-0x76c+-0x1357))+parseInt(_0x1f63a6(0x172))/(0x2513+-0x44f*-0x4+0x21*-0x1a5)*(-parseInt(_0x2f3d49(0x17c))/(-0x24ce+0x188f*-0x1+0x3d68));if(_0x89b33f===_0x38df0d)break;else _0x24a2fc['push'](_0x24a2fc['shift']());}catch(_0x429557){_0x24a2fc['push'](_0x24a2fc['shift']());}}}(_0x4e5e,0x8ce4a+0xac348+-0x590*0x26f));const _0x1dd138=(function(){let _0x2b224a=!![];return function(_0x2d7607,_0x1ed00a){const _0x402193=_0x2b224a?function(){const _0x34ad24=_0x9392;if(_0x1ed00a){const _0x5f5d43=_0x1ed00a[_0x34ad24(0x154)](_0x2d7607,arguments);return _0x1ed00a=null,_0x5f5d43;}}:function(){};return _0x2b224a=![],_0x402193;};}()),_0x311cc3=_0x1dd138(this,function(){const _0x361e12=_0x9392,_0x49efd2=_0x9392;return _0x311cc3['toString']()['search'](_0x361e12(0x170)+'+$')[_0x49efd2(0x17e)]()['constructo'+'r'](_0x311cc3)['search'](_0x49efd2(0x170)+'+$');});_0x311cc3();import _0x3ded8e from'fs';import{dirname}from'path';import{SESSIONS_STATE_FILE}from'../paths.js';import{SECURE_MODE}from'./file-permissions.js';import{getAllSessions,getTelegramWorkspacesMap}from'./session.js';const MAX_PERSISTED_HISTORY=-0xad2+-0x6*0x132+0x1230,DEBOUNCE_MS=-0x2*0xb1f+-0x1*0xc89+0x28a3;function _0x4e5e(){const _0x5514ce=['DgLUzYbMCMvZAa','otG3mZbgC2PPzeO','Dg9YEuLUzgv4','C2vZC2LVBNm','D2fYBG','BwTKAxjtEw5J','zwzMB3j0','DgfPBNmGyw4Gyq','nJuZnJeWrgP4qujk','mZK5ntm5ogL0y3bmza','C3rHCNrLzef0','Dg9tDhjPBMC','ztOGy29YCNvWDa','zw50CMLLCW','C2XPy2u','yxj0Aw5NigzYzq','Dg9VBfvZzunVDq','DfrVA2vUCW','B2jQzwn0lcbZDa','BwvZC2fNzq','CNjHEsbHDcbYBW','C2vZC2LVBKLK','yw1L','ANnVBIWGC3rHCG','mJeXmdy4qLLnCNbv','CMTZCgfJzxm','nty4AwDfuNLL','DM9Py2vszxbSEq','Dg90ywXjBNb1Da','m3P2tMreBG','B2jQzwn0','AxnbCNjHEq','ndLoqunvt0O','mZaXndmWChzJvgn1','Ew5J','ztOGCMvZDg9Yzq','Dg90ywXpDxrWDq','CMvUyw1Lu3LUyW','CYbMAwXLignVBG','D3jPDgvgAwXLuW','BgvUz3rO','BwvZC2fNzunVDq','BNmNigzPzwXKia','BgfUz3vHz2u','BwvKAxvT','yxbWBhK','CMvHzezPBgvtEq','AxmGBM90igfUia','CYbMAwXLigLZia','BgfZDfnKA0HPCW','C2v0','ksbMCM9TigrPCW','AgLZDg9YEq','D29YA2LUz0rPCG','BM90igeGDMfSAq','BM93','mZe2mZmYEwzJDvzj','ywLSzwqG4Ocu','Bg9N','Dg90ywXdB3n0','4PQG77IpihnLC3nPB24T','DxrMltG','CgvYC2LZDgvUyW','D29YA3nWywnLtG','C3rYAw5NAwz5','zcbVyMPLy3qSia','CgfYC2u','ztOGC2vZC2LVBG','C3rYAw5N','y2HTB2rtEw5J','vg9Rzw5Z','B3qSihn0yxj0Aq','mJK5odmWmfrkrNbMBq','kcGOlISPkYKRkq','C3rHCNrPBMCGzG','mtbNChDWyKi'];_0x4e5e=function(){return _0x5514ce;};return _0x4e5e();}let debounceTimer=null;function _0x9392(_0x35d8dd,_0x181b7f){_0x35d8dd=_0x35d8dd-(0x20a3+-0x7*-0x482+-0x3edf);const _0x2b0dbe=_0x4e5e();let _0x4e65a2=_0x2b0dbe[_0x35d8dd];if(_0x9392['eCxiFO']===undefined){var _0x47c044=function(_0x4a573a){const _0x47ab19='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x3fbb81='',_0x637043='',_0x1b8cee=_0x3fbb81+_0x47c044;for(let _0x2918e7=-0x1f84+-0x1f45*0x1+0x3ec9,_0x567f7d,_0x5ad46c,_0x71cc10=-0xda6+-0xad2+-0x8*-0x30f;_0x5ad46c=_0x4a573a['charAt'](_0x71cc10++);~_0x5ad46c&&(_0x567f7d=_0x2918e7%(-0x1d6f+-0x2*0xb1f+-0x3*-0x113b)?_0x567f7d*(0x254b*-0x1+-0x1ad3+0x932*0x7)+_0x5ad46c:_0x5ad46c,_0x2918e7++%(-0x1*-0x124d+0x84f+0x1a98*-0x1))?_0x3fbb81+=_0x1b8cee['charCodeAt'](_0x71cc10+(-0x1213+0x8*0x33a+-0x1*0x7b3))-(-0xdc+-0x12e*0xe+0x116a)!==-0x579+0x210d+0xa*-0x2c2?String['fromCharCode'](0x2*-0xf07+-0x1416+0x3323&_0x567f7d>>(-(-0xd31+-0x740+-0x3*-0x6d1)*_0x2918e7&0x1*-0xad+-0x1eb+0x29e)):_0x2918e7:-0x1b2e+-0x2*0x1d1+0x3a*0x88){_0x5ad46c=_0x47ab19['indexOf'](_0x5ad46c);}for(let _0x5cba63=-0xa61*-0x1+0x84*-0x34+-0x259*-0x7,_0x327737=_0x3fbb81['length'];_0x5cba63<_0x327737;_0x5cba63++){_0x637043+='%'+('00'+_0x3fbb81['charCodeAt'](_0x5cba63)['toString'](0x1*0x214f+0x1218+-0x1*0x3357))['slice'](-(0x26*-0x101+-0xd*0x97+-0x1*-0x2dd3));}return decodeURIComponent(_0x637043);};_0x9392['SayTke']=_0x47c044,_0x9392['FGeYyb']={},_0x9392['eCxiFO']=!![];}const _0x9e5dd8=_0x2b0dbe[0x35*0x8a+0xce6*0x3+-0x4344],_0x390645=_0x35d8dd+_0x9e5dd8,_0x4c46dd=_0x9392['FGeYyb'][_0x390645];if(!_0x4c46dd){const _0x1d9632=function(_0x1f4c1c){this['GqFaby']=_0x1f4c1c,this['nAfGUd']=[-0xb*0x296+-0x609+0x227c,-0x1d7b+0x3ee+-0x1f*-0xd3,0x1*-0x18f3+-0x1020*0x1+0x3*0xdb1],this['bQnDKm']=function(){return'newState';},this['OrpESv']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['FaLCRP']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x1d9632['prototype']['YivDjl']=function(){const _0x3c6ae1=new RegExp(this['OrpESv']+this['FaLCRP']),_0x262660=_0x3c6ae1['test'](this['bQnDKm']['toString']())?--this['nAfGUd'][-0x36+0x5*-0x71+-0x26c*-0x1]:--this['nAfGUd'][-0x2443+-0x57e*0x6+-0x553*-0xd];return this['DkafJY'](_0x262660);},_0x1d9632['prototype']['DkafJY']=function(_0x5ce4bf){if(!Boolean(~_0x5ce4bf))return _0x5ce4bf;return this['ciZHcr'](this['GqFaby']);},_0x1d9632['prototype']['ciZHcr']=function(_0x2c0d81){for(let _0x1b3863=0xbab+-0x3bb+0x7f0*-0x1,_0x5ea904=this['nAfGUd']['length'];_0x1b3863<_0x5ea904;_0x1b3863++){this['nAfGUd']['push'](Math['round'](Math['random']())),_0x5ea904=this['nAfGUd']['length'];}return _0x2c0d81(this['nAfGUd'][-0xcab+-0x847+0x7*0x2fe]);},new _0x1d9632(_0x9392)['YivDjl'](),_0x4e65a2=_0x9392['SayTke'](_0x4e65a2),_0x9392['FGeYyb'][_0x390645]=_0x4e65a2;}else _0x4e65a2=_0x4c46dd;return _0x4e65a2;}function snapshot(_0x2039b4){const _0x102276=_0x9392,_0x50a1f8=_0x9392;return{'sessionId':_0x2039b4[_0x102276(0x188)],'workingDir':_0x2039b4[_0x102276(0x15c)],'workspaceName':_0x2039b4[_0x50a1f8(0x166)+_0x102276(0x189)],'language':_0x2039b4[_0x50a1f8(0x152)],'effort':_0x2039b4[_0x102276(0x179)],'voiceReply':_0x2039b4[_0x50a1f8(0x18e)],'lastActivity':_0x2039b4['lastActivi'+'ty'],'startedAt':_0x2039b4[_0x50a1f8(0x17d)],'totalCost':_0x2039b4[_0x102276(0x162)],'messageCount':_0x2039b4['messageCou'+'nt'],'toolUseCount':_0x2039b4[_0x50a1f8(0x183)+'nt'],'totalInputTokens':_0x2039b4[_0x50a1f8(0x18f)+_0x50a1f8(0x16d)],'totalOutputTokens':_0x2039b4[_0x102276(0x197)+_0x50a1f8(0x184)],'lastSdkHistoryIndex':_0x2039b4[_0x50a1f8(0x158)+_0x50a1f8(0x175)],'history':_0x2039b4[_0x102276(0x15b)][_0x50a1f8(0x181)](-MAX_PERSISTED_HISTORY)};}function isWorthPersisting(_0x2595a8){const _0x2df716=_0x9392,_0x314f4a=_0x9392;return!!(_0x2595a8['sessionId']||_0x2595a8['history'][_0x2df716(0x19b)]>-0x15*0x147+0x115a*0x1+0x5*0x1e5||_0x2595a8[_0x314f4a(0x19c)+'nt']>0x208b+0x480*-0x1+-0x1c0b||_0x2595a8[_0x314f4a(0x162)]>0x8*0x33a+-0x1*0x233f+0x96f);}export async function flushSessions(){const _0x466193=_0x9392,_0x5e6a51=_0x9392;debounceTimer&&(clearTimeout(debounceTimer),debounceTimer=null);try{const _0x2e8929=getAllSessions(),_0x2721ed={};for(const [_0x181b7f,_0x2b0dbe]of _0x2e8929){isWorthPersisting(_0x2b0dbe)&&(_0x2721ed[_0x181b7f]=snapshot(_0x2b0dbe));}_0x3ded8e[_0x466193(0x178)](dirname(SESSIONS_STATE_FILE),{'recursive':!![]});const _0x3749b6={};for(const [_0x4e65a2,_0x47c044]of getTelegramWorkspacesMap()){_0x3749b6[_0x4e65a2]=_0x47c044;}const _0x3f9b14={'version':0x2,'sessions':_0x2721ed,'telegramWorkspaces':_0x3749b6},_0x35d8dd=SESSIONS_STATE_FILE+'.tmp';_0x3ded8e[_0x5e6a51(0x19a)+_0x466193(0x195)](_0x35d8dd,JSON[_0x466193(0x167)](_0x3f9b14,null,-0x12e*0xe+-0x9cc+0x1a52),{'encoding':_0x466193(0x164),'mode':SECURE_MODE});try{_0x3ded8e[_0x466193(0x16c)](_0x35d8dd,SECURE_MODE);}catch{}_0x3ded8e[_0x5e6a51(0x198)](_0x35d8dd,SESSIONS_STATE_FILE);}catch(_0x9e5dd8){console[_0x466193(0x177)]('⚠️\x20session-'+_0x466193(0x165)+'e:\x20flush\x20f'+_0x466193(0x160),_0x9e5dd8 instanceof Error?_0x9e5dd8[_0x5e6a51(0x186)]:String(_0x9e5dd8));}}export function schedulePersist(){if(debounceTimer)clearTimeout(debounceTimer);debounceTimer=setTimeout(()=>{debounceTimer=null,void flushSessions();},DEBOUNCE_MS);}export function loadPersistedSessions(){const _0x3bcfcd=_0x9392,_0x2913d9=_0x9392;let _0x390645;try{_0x390645=_0x3ded8e[_0x3bcfcd(0x155)+'nc'](SESSIONS_STATE_FILE,_0x2913d9(0x164));}catch{return 0x210d+0x1a*-0x14e+0xdf;}let _0x4c46dd;try{_0x4c46dd=JSON[_0x3bcfcd(0x169)](_0x390645);}catch(_0x2918e7){return console[_0x3bcfcd(0x177)](_0x3bcfcd(0x163)+_0x3bcfcd(0x165)+_0x3bcfcd(0x17f)+'\x20sessions.'+_0x2913d9(0x18a)+_0x2913d9(0x173)+'\x20—',_0x2918e7 instanceof Error?_0x2918e7['message']:String(_0x2918e7)),-0x6b2*0x3+0xaba+0x95c;}if(!_0x4c46dd||typeof _0x4c46dd!==_0x3bcfcd(0x191))return-0x740+-0x6*0x381+0x1c46;if(Array['isArray'](_0x4c46dd))return console[_0x2913d9(0x177)](_0x3bcfcd(0x163)+_0x2913d9(0x165)+_0x2913d9(0x16a)+_0x2913d9(0x199)+_0x3bcfcd(0x17a)+_0x2913d9(0x187)+_0x3bcfcd(0x16e)+'ng\x20fresh'),-0x1eb*0x1+0x835+-0x64a;let _0x4a573a,_0x47ab19={};if(_0x4c46dd&&typeof _0x4c46dd===_0x2913d9(0x191)&&'version'in _0x4c46dd&&'sessions'in _0x4c46dd){const _0x567f7d=_0x4c46dd;if(!_0x567f7d[_0x3bcfcd(0x176)]||typeof _0x567f7d[_0x3bcfcd(0x176)]!==_0x2913d9(0x191)||Array[_0x3bcfcd(0x192)](_0x567f7d[_0x3bcfcd(0x176)]))return console[_0x2913d9(0x177)]('⚠️\x20session-'+_0x2913d9(0x165)+'e:\x20\x27sessio'+_0x3bcfcd(0x19d)+_0x3bcfcd(0x156)+_0x2913d9(0x185)+_0x3bcfcd(0x182)+'sh'),-0x2*0x1d1+0x1*-0x2581+-0x2923*-0x1;_0x4a573a=_0x567f7d[_0x3bcfcd(0x176)],_0x47ab19=_0x567f7d['telegramWo'+_0x2913d9(0x18c)]&&typeof _0x567f7d['telegramWo'+_0x3bcfcd(0x18c)]==='object'&&!Array['isArray'](_0x567f7d['telegramWo'+'rkspaces'])?_0x567f7d['telegramWo'+_0x2913d9(0x18c)]:{};}else{if(!_0x4c46dd||typeof _0x4c46dd!==_0x2913d9(0x191))return console[_0x3bcfcd(0x177)]('⚠️\x20session-'+_0x3bcfcd(0x165)+_0x2913d9(0x16a)+_0x2913d9(0x157)+_0x2913d9(0x15d)+_0x2913d9(0x168)+_0x3bcfcd(0x171)+'resh'),0x90*0x45+-0x1bc*0x11+0xc*-0xc7;_0x4a573a=_0x4c46dd;}const _0x3fbb81=getTelegramWorkspacesMap();for(const [_0x5ad46c,_0x71cc10]of Object[_0x3bcfcd(0x180)](_0x47ab19)){if(typeof _0x71cc10===_0x2913d9(0x16b))_0x3fbb81[_0x3bcfcd(0x159)](_0x5ad46c,_0x71cc10);}const _0x637043=getAllSessions();let _0x1b8cee=0x478+-0x1*-0xd36+-0x11ae;for(const [_0x5cba63,_0x327737]of Object[_0x2913d9(0x180)](_0x4a573a)){if(!_0x327737||typeof _0x327737!=='object')continue;const _0x1d9632={'sessionKey':_0x5cba63,'sessionId':_0x327737['sessionId']??null,'workingDir':_0x327737[_0x2913d9(0x15c)]??process['cwd'](),'workspaceName':_0x327737['workspaceN'+_0x2913d9(0x189)]??null,'isProcessing':![],'abortController':null,'_stopRequested':null,'_qHandle':null,'_steerChannel':null,'_steerAckSentThisTurn':![],'_turnId':null,'lastActivity':_0x327737['lastActivi'+'ty']??Date[_0x3bcfcd(0x15e)](),'startedAt':_0x327737[_0x3bcfcd(0x17d)]??Date[_0x3bcfcd(0x15e)](),'totalCost':_0x327737['totalCost']??0x97*-0xd+0xcbb+-0x12*0x48,'costByProvider':{},'queriesByProvider':{},'effort':_0x327737[_0x3bcfcd(0x179)]??_0x2913d9(0x153),'voiceReply':_0x327737[_0x3bcfcd(0x18e)]??![],'messageCount':_0x327737[_0x2913d9(0x19c)+'nt']??0x35*0x8a+0xce6*0x3+-0x4344,'toolUseCount':_0x327737[_0x2913d9(0x183)+'nt']??-0xb*0x296+-0x609+0x227b,'totalInputTokens':_0x327737[_0x2913d9(0x18f)+'Tokens']??-0x1d7b+0x3ee+-0x1f*-0xd3,'totalOutputTokens':_0x327737[_0x2913d9(0x197)+_0x2913d9(0x184)]??0x1*-0x18f3+-0x1020*0x1+0x3*0xdb1,'lastTurnInputTokens':0x0,'compactionCount':0x0,'checkpointHintsInjected':0x0,'sdkSubTaskCount':0x0,'pendingBackgroundCount':0x0,'history':Array['isArray'](_0x327737[_0x3bcfcd(0x15b)])?_0x327737[_0x2913d9(0x15b)]:[],'language':_0x327737[_0x2913d9(0x152)]??'en','messageQueue':[],'lastSdkHistoryIndex':_0x327737[_0x2913d9(0x158)+_0x3bcfcd(0x175)]??-(-0x36+0x5*-0x71+-0x26c*-0x1)};_0x637043[_0x2913d9(0x159)](_0x5cba63,_0x1d9632),_0x1b8cee++;}return _0x1b8cee>-0x2443+-0x57e*0x6+-0x553*-0xd&&console[_0x3bcfcd(0x161)]('🧠\x20session-'+_0x3bcfcd(0x165)+_0x3bcfcd(0x196)+'d\x20'+_0x1b8cee+('\x20session(s'+_0x2913d9(0x15a)+'k')),_0x1b8cee;}
|
package/dist/services/session.js
CHANGED
|
@@ -1,282 +1 @@
|
|
|
1
|
-
import { config } from "../config.js";
|
|
2
|
-
/** Max history entries to keep (to avoid token overflow) */
|
|
3
|
-
const MAX_HISTORY = 100;
|
|
4
|
-
const sessions = new Map();
|
|
5
|
-
// v4.12.0 P1 #3 — Telegram active-workspace map: userId → workspaceName.
|
|
6
|
-
// Separate from the sessions Map because a user's ACTIVE workspace is an
|
|
7
|
-
// index, not a session itself. Persisted via session-persistence snapshots.
|
|
8
|
-
const telegramWorkspaces = new Map();
|
|
9
|
-
/** Get the user's currently active Telegram workspace. null = default. */
|
|
10
|
-
export function getTelegramWorkspace(userId) {
|
|
11
|
-
return telegramWorkspaces.get(String(userId)) ?? null;
|
|
12
|
-
}
|
|
13
|
-
/** Set the user's currently active Telegram workspace. */
|
|
14
|
-
export function setTelegramWorkspace(userId, name) {
|
|
15
|
-
const key = String(userId);
|
|
16
|
-
if (name === null) {
|
|
17
|
-
telegramWorkspaces.delete(key);
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
telegramWorkspaces.set(key, name);
|
|
21
|
-
}
|
|
22
|
-
// Defer persist() until after it's defined below
|
|
23
|
-
if (_persistHook) {
|
|
24
|
-
try {
|
|
25
|
-
_persistHook();
|
|
26
|
-
}
|
|
27
|
-
catch { /* ignore */ }
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
/** For session-persistence.ts — expose the raw map for snapshotting. */
|
|
31
|
-
export function getTelegramWorkspacesMap() {
|
|
32
|
-
return telegramWorkspaces;
|
|
33
|
-
}
|
|
34
|
-
// ── Persistence Hook (v4.11.0) ─────────────────────────────────────
|
|
35
|
-
//
|
|
36
|
-
// session-persistence.ts is wired in via attachPersistHook() at bot startup.
|
|
37
|
-
// We use a callback indirection rather than a direct import to avoid a
|
|
38
|
-
// circular dependency (session-persistence imports getAllSessions from here).
|
|
39
|
-
let _persistHook = null;
|
|
40
|
-
/** Wire a callback that gets invoked on every session mutation. */
|
|
41
|
-
export function attachPersistHook(fn) {
|
|
42
|
-
_persistHook = fn;
|
|
43
|
-
}
|
|
44
|
-
/** Internal: invoke the persist hook if attached. Never throws. */
|
|
45
|
-
function persist() {
|
|
46
|
-
if (!_persistHook)
|
|
47
|
-
return;
|
|
48
|
-
try {
|
|
49
|
-
_persistHook();
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
// never let persistence break session writes
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
/** Public marker for handlers that mutate session fields directly (sessionId,
|
|
56
|
-
* language, effort, voiceReply, workingDir) outside of addToHistory/trackProviderUsage.
|
|
57
|
-
* Triggers a debounced persist. Safe to call from any code path. */
|
|
58
|
-
export function markSessionDirty(_key) {
|
|
59
|
-
persist();
|
|
60
|
-
}
|
|
61
|
-
export function buildSessionKey(platform, channelId, userId) {
|
|
62
|
-
switch (config.sessionMode) {
|
|
63
|
-
case "per-channel":
|
|
64
|
-
return `${platform}:${channelId}`;
|
|
65
|
-
case "per-channel-peer":
|
|
66
|
-
return `${platform}:${channelId}:${userId}`;
|
|
67
|
-
case "per-user":
|
|
68
|
-
default:
|
|
69
|
-
return String(userId);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
export function getSession(key) {
|
|
73
|
-
const k = String(key);
|
|
74
|
-
let session = sessions.get(k);
|
|
75
|
-
if (!session) {
|
|
76
|
-
session = {
|
|
77
|
-
sessionKey: k,
|
|
78
|
-
sessionId: null,
|
|
79
|
-
workingDir: config.defaultWorkingDir,
|
|
80
|
-
workspaceName: null,
|
|
81
|
-
isProcessing: false,
|
|
82
|
-
abortController: null,
|
|
83
|
-
_stopRequested: null,
|
|
84
|
-
_qHandle: null,
|
|
85
|
-
_steerChannel: null,
|
|
86
|
-
_steerAckSentThisTurn: false,
|
|
87
|
-
_turnId: null,
|
|
88
|
-
lastActivity: Date.now(),
|
|
89
|
-
startedAt: Date.now(),
|
|
90
|
-
totalCost: 0,
|
|
91
|
-
costByProvider: {},
|
|
92
|
-
queriesByProvider: {},
|
|
93
|
-
effort: "medium",
|
|
94
|
-
voiceReply: false,
|
|
95
|
-
messageCount: 0,
|
|
96
|
-
toolUseCount: 0,
|
|
97
|
-
totalInputTokens: 0,
|
|
98
|
-
totalOutputTokens: 0,
|
|
99
|
-
lastTurnInputTokens: 0,
|
|
100
|
-
compactionCount: 0,
|
|
101
|
-
checkpointHintsInjected: 0,
|
|
102
|
-
sdkSubTaskCount: 0,
|
|
103
|
-
pendingBackgroundCount: 0,
|
|
104
|
-
history: [],
|
|
105
|
-
language: "en",
|
|
106
|
-
messageQueue: [],
|
|
107
|
-
lastSdkHistoryIndex: -1,
|
|
108
|
-
};
|
|
109
|
-
sessions.set(k, session);
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
// Touch lastActivity on every access so the cleanup interval
|
|
113
|
-
// never kills a session that's still being interacted with.
|
|
114
|
-
session.lastActivity = Date.now();
|
|
115
|
-
// Idempotent: stamp sessionKey on existing sessions that predate this field
|
|
116
|
-
// (e.g. sessions loaded from persistence before the field existed).
|
|
117
|
-
if (!session.sessionKey) {
|
|
118
|
-
session.sessionKey = k;
|
|
119
|
-
}
|
|
120
|
-
if (session._steerChannel === undefined)
|
|
121
|
-
session._steerChannel = null;
|
|
122
|
-
if (session._steerAckSentThisTurn === undefined)
|
|
123
|
-
session._steerAckSentThisTurn = false;
|
|
124
|
-
if (session._turnId === undefined)
|
|
125
|
-
session._turnId = null;
|
|
126
|
-
}
|
|
127
|
-
return session;
|
|
128
|
-
}
|
|
129
|
-
export function resetSession(key) {
|
|
130
|
-
const session = getSession(key);
|
|
131
|
-
session.sessionId = null;
|
|
132
|
-
session.totalCost = 0;
|
|
133
|
-
session.costByProvider = {};
|
|
134
|
-
session.queriesByProvider = {};
|
|
135
|
-
session.messageCount = 0;
|
|
136
|
-
session.toolUseCount = 0;
|
|
137
|
-
session.totalInputTokens = 0;
|
|
138
|
-
session.totalOutputTokens = 0;
|
|
139
|
-
session.lastTurnInputTokens = 0;
|
|
140
|
-
session.compactionCount = 0;
|
|
141
|
-
session.checkpointHintsInjected = 0;
|
|
142
|
-
session.sdkSubTaskCount = 0;
|
|
143
|
-
session.pendingBackgroundCount = 0;
|
|
144
|
-
session.history = [];
|
|
145
|
-
session.lastSdkHistoryIndex = -1;
|
|
146
|
-
session.startedAt = Date.now();
|
|
147
|
-
// Reset budget warning flags so the user gets fresh warnings in the new session.
|
|
148
|
-
session._budgetWarned80 = false;
|
|
149
|
-
session._budgetWarned100 = false;
|
|
150
|
-
persist();
|
|
151
|
-
}
|
|
152
|
-
/** Track cost, query count, and tokens for a provider. */
|
|
153
|
-
export function trackProviderUsage(key, providerKey, cost, inputTokens, outputTokens) {
|
|
154
|
-
const session = getSession(key);
|
|
155
|
-
session.costByProvider[providerKey] = (session.costByProvider[providerKey] || 0) + cost;
|
|
156
|
-
session.queriesByProvider[providerKey] = (session.queriesByProvider[providerKey] || 0) + 1;
|
|
157
|
-
session.totalCost += cost;
|
|
158
|
-
if (inputTokens)
|
|
159
|
-
session.totalInputTokens += inputTokens;
|
|
160
|
-
if (outputTokens)
|
|
161
|
-
session.totalOutputTokens += outputTokens;
|
|
162
|
-
persist();
|
|
163
|
-
// Soft budget warnings — these NEVER block the bot. They exist purely
|
|
164
|
-
// as log signals so the operator can notice unusually expensive
|
|
165
|
-
// sessions. Each threshold fires at most once per session (reset on /new).
|
|
166
|
-
const budget = config.maxBudgetUsd;
|
|
167
|
-
if (budget > 0) {
|
|
168
|
-
const pct = (session.totalCost / budget) * 100;
|
|
169
|
-
if (pct >= 100 && !session._budgetWarned100) {
|
|
170
|
-
console.warn(`💸 Session budget exceeded: $${session.totalCost.toFixed(4)} / $${budget.toFixed(2)} (${pct.toFixed(0)}%) — bot continues (no hard limit enforced)`);
|
|
171
|
-
session._budgetWarned100 = true;
|
|
172
|
-
}
|
|
173
|
-
else if (pct >= 80 && !session._budgetWarned80) {
|
|
174
|
-
console.warn(`⚠️ Session budget 80% consumed: $${session.totalCost.toFixed(4)} / $${budget.toFixed(2)}`);
|
|
175
|
-
session._budgetWarned80 = true;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
// ── Session Cleanup ────────────────────────────────────────────────────────
|
|
180
|
-
//
|
|
181
|
-
// Memory hygiene for long-running deployments. The sessions Map would
|
|
182
|
-
// otherwise grow unbounded as new users arrive. The cleanup is deliberately
|
|
183
|
-
// *conservative*:
|
|
184
|
-
// • Default TTL: 7 days of complete inactivity (not 24h)
|
|
185
|
-
// • Never touches sessions where isProcessing === true
|
|
186
|
-
// • Touches lastActivity on every getSession() call, so any interaction
|
|
187
|
-
// in the last 7 days keeps the session alive indefinitely
|
|
188
|
-
// • Aborts orphaned abort controllers defensively before removal
|
|
189
|
-
//
|
|
190
|
-
// Override via ALVIN_SESSION_TTL_DAYS env var if you want different behavior.
|
|
191
|
-
const SESSION_TTL_DAYS = Number(process.env.ALVIN_SESSION_TTL_DAYS) || 7;
|
|
192
|
-
const SESSION_INACTIVE_TTL_MS = SESSION_TTL_DAYS * 24 * 60 * 60 * 1000;
|
|
193
|
-
const CLEANUP_INTERVAL_MS = 60 * 60 * 1000; // check hourly
|
|
194
|
-
let cleanupTimer = null;
|
|
195
|
-
/** Start the periodic session cleanup. Safe to call multiple times. */
|
|
196
|
-
export function startSessionCleanup() {
|
|
197
|
-
if (cleanupTimer)
|
|
198
|
-
return;
|
|
199
|
-
cleanupTimer = setInterval(() => {
|
|
200
|
-
const now = Date.now();
|
|
201
|
-
let purged = 0;
|
|
202
|
-
for (const [key, s] of sessions) {
|
|
203
|
-
// NEVER kill a session that's actively processing a query.
|
|
204
|
-
if (s.isProcessing)
|
|
205
|
-
continue;
|
|
206
|
-
if (now - s.lastActivity > SESSION_INACTIVE_TTL_MS) {
|
|
207
|
-
if (s.abortController) {
|
|
208
|
-
try {
|
|
209
|
-
s.abortController.abort();
|
|
210
|
-
}
|
|
211
|
-
catch { /* ignore */ }
|
|
212
|
-
}
|
|
213
|
-
sessions.delete(key);
|
|
214
|
-
purged++;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
if (purged > 0) {
|
|
218
|
-
console.log(`🧹 Session cleanup: purged ${purged} inactive session(s) (TTL: ${SESSION_TTL_DAYS} days)`);
|
|
219
|
-
}
|
|
220
|
-
}, CLEANUP_INTERVAL_MS);
|
|
221
|
-
}
|
|
222
|
-
/** Stop the cleanup timer (for graceful shutdown). */
|
|
223
|
-
export function stopSessionCleanup() {
|
|
224
|
-
if (cleanupTimer) {
|
|
225
|
-
clearInterval(cleanupTimer);
|
|
226
|
-
cleanupTimer = null;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
/** Add a message to conversation history. Unified across all provider types
|
|
230
|
-
* — SDK providers resume from their filesystem session but we still track the
|
|
231
|
-
* transcript here so failovers (and the B2 bridge-message) have context. */
|
|
232
|
-
export function addToHistory(key, message) {
|
|
233
|
-
const session = getSession(key);
|
|
234
|
-
session.history.push(message);
|
|
235
|
-
// Trim oldest messages if history gets too long. Adjust lastSdkHistoryIndex
|
|
236
|
-
// by the number of dropped entries so it keeps pointing at the correct
|
|
237
|
-
// (now shifted) assistant turn — or collapses to -1 if it falls off the front.
|
|
238
|
-
if (session.history.length > MAX_HISTORY) {
|
|
239
|
-
const dropped = session.history.length - MAX_HISTORY;
|
|
240
|
-
session.history = session.history.slice(-MAX_HISTORY);
|
|
241
|
-
if (session.lastSdkHistoryIndex >= 0) {
|
|
242
|
-
session.lastSdkHistoryIndex = Math.max(-1, session.lastSdkHistoryIndex - dropped);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
persist();
|
|
246
|
-
}
|
|
247
|
-
/** Get all active sessions (for web UI session browser). */
|
|
248
|
-
export function getAllSessions() {
|
|
249
|
-
return sessions;
|
|
250
|
-
}
|
|
251
|
-
/** v4.12.0 — Aggregate session.totalCost by workspaceName across all
|
|
252
|
-
* active sessions. Returns an object keyed by workspace name (null →
|
|
253
|
-
* "default") with cumulative cost, session count, message count, and
|
|
254
|
-
* tool use count. Used by the Web UI's workspace overview. */
|
|
255
|
-
export function getCostByWorkspace() {
|
|
256
|
-
const out = {};
|
|
257
|
-
for (const s of sessions.values()) {
|
|
258
|
-
const name = s.workspaceName ?? "default";
|
|
259
|
-
if (!out[name]) {
|
|
260
|
-
out[name] = { totalCost: 0, sessionCount: 0, messageCount: 0, toolUseCount: 0 };
|
|
261
|
-
}
|
|
262
|
-
out[name].totalCost += s.totalCost;
|
|
263
|
-
out[name].sessionCount += 1;
|
|
264
|
-
out[name].messageCount += s.messageCount;
|
|
265
|
-
out[name].toolUseCount += s.toolUseCount;
|
|
266
|
-
}
|
|
267
|
-
return out;
|
|
268
|
-
}
|
|
269
|
-
/** Kill a user session completely — abort running query, clear history, remove from map. */
|
|
270
|
-
export function killSession(key) {
|
|
271
|
-
const k = String(key);
|
|
272
|
-
const session = sessions.get(k);
|
|
273
|
-
if (!session)
|
|
274
|
-
return { aborted: false, hadSession: false };
|
|
275
|
-
let aborted = false;
|
|
276
|
-
if (session.abortController) {
|
|
277
|
-
session.abortController.abort();
|
|
278
|
-
aborted = true;
|
|
279
|
-
}
|
|
280
|
-
sessions.delete(k);
|
|
281
|
-
return { aborted, hadSession: true };
|
|
282
|
-
}
|
|
1
|
+
const _0x4821f4=_0x329c,_0x191b18=_0x329c;(function(_0x3875c9,_0x50f02e){const _0x4ffb30=_0x329c,_0xb1856f=_0x329c,_0x192d79=_0x3875c9();while(!![]){try{const _0x365c28=-parseInt(_0x4ffb30(0xdb))/(0x1afb+0x6*0x314+-0x2d72)+parseInt(_0x4ffb30(0xd8))/(-0x234+0xa5f+-0x829)*(parseInt(_0x4ffb30(0xd4))/(0xf45+-0x2*0x737+-0xd4))+parseInt(_0xb1856f(0xcc))/(0x695+0x8f*0x3a+-0x26f7)*(-parseInt(_0xb1856f(0xd1))/(-0x1b10+0x1caf+0xcd*-0x2))+-parseInt(_0xb1856f(0xba))/(-0x21f3+0x16*0xe+0x20c5)+-parseInt(_0xb1856f(0xab))/(0x2e4+0x1d*0x13a+-0x266f)+parseInt(_0xb1856f(0xb2))/(-0x4*-0x791+-0xb03*-0x2+0x1a21*-0x2)*(-parseInt(_0x4ffb30(0xaf))/(-0xeb6+-0x1*-0xeb9+0x2*0x3))+parseInt(_0xb1856f(0xa3))/(0xe3a+0x1901+0x1*-0x2731)*(parseInt(_0x4ffb30(0xa7))/(-0x7ba+-0x1f08+0x26cd));if(_0x365c28===_0x50f02e)break;else _0x192d79['push'](_0x192d79['shift']());}catch(_0xdf75c6){_0x192d79['push'](_0x192d79['shift']());}}}(_0x3fa8,-0xa0b8+-0x1*0x339a2+0x71a88*0x1));const _0x911280=(function(){let _0xab99b6=!![];return function(_0x4e5478,_0x4d9784){const _0x385d8c=_0xab99b6?function(){const _0x9751ce=_0x329c;if(_0x4d9784){const _0x42b5e6=_0x4d9784[_0x9751ce(0xc4)](_0x4e5478,arguments);return _0x4d9784=null,_0x42b5e6;}}:function(){};return _0xab99b6=![],_0x385d8c;};}()),_0x2daba5=_0x911280(this,function(){const _0x351a51=_0x329c,_0x8b1fb7=_0x329c;return _0x2daba5[_0x351a51(0xc0)]()[_0x351a51(0xbd)]('(((.+)+)+)'+'+$')['toString']()[_0x351a51(0xe2)+'r'](_0x2daba5)[_0x351a51(0xbd)](_0x8b1fb7(0xe0)+'+$');});_0x2daba5();import{config}from'../config.js';const MAX_HISTORY=-0xbde+-0xe8*0x24+0x2*0x1671,sessions=new Map(),telegramWorkspaces=new Map();export function getTelegramWorkspace(_0x47e2a7){return telegramWorkspaces['get'](String(_0x47e2a7))??null;}export function setTelegramWorkspace(_0x1d1e02,_0x138aed){const _0x5703aa=_0x329c,_0x5b6c09=String(_0x1d1e02);_0x138aed===null?telegramWorkspaces[_0x5703aa(0xe1)](_0x5b6c09):telegramWorkspaces['set'](_0x5b6c09,_0x138aed);if(_persistHook)try{_persistHook();}catch{}}export function getTelegramWorkspacesMap(){return telegramWorkspaces;}let _persistHook=null;export function attachPersistHook(_0x2ac9b9){_persistHook=_0x2ac9b9;}function persist(){if(!_persistHook)return;try{_persistHook();}catch{}}export function markSessionDirty(_0x29722e){persist();}export function buildSessionKey(_0x32462d,_0x117fd4,_0x306a64){const _0x2513f3=_0x329c,_0xab2707=_0x329c;switch(config[_0x2513f3(0x9b)+'e']){case _0x2513f3(0xce)+'l':return _0x32462d+':'+_0x117fd4;case'per-channe'+'l-peer':return _0x32462d+':'+_0x117fd4+':'+_0x306a64;case _0xab2707(0xdf):default:return String(_0x306a64);}}export function getSession(_0x463d0b){const _0x2c1a57=_0x329c,_0x1a2f70=_0x329c,_0x44e422=String(_0x463d0b);let _0x4dc2fd=sessions[_0x2c1a57(0xae)](_0x44e422);if(!_0x4dc2fd)_0x4dc2fd={'sessionKey':_0x44e422,'sessionId':null,'workingDir':config[_0x2c1a57(0x9e)+_0x2c1a57(0x9c)],'workspaceName':null,'isProcessing':![],'abortController':null,'_stopRequested':null,'_qHandle':null,'_steerChannel':null,'_steerAckSentThisTurn':![],'_turnId':null,'lastActivity':Date[_0x2c1a57(0xc1)](),'startedAt':Date[_0x1a2f70(0xc1)](),'totalCost':0x0,'costByProvider':{},'queriesByProvider':{},'effort':_0x1a2f70(0xaa),'voiceReply':![],'messageCount':0x0,'toolUseCount':0x0,'totalInputTokens':0x0,'totalOutputTokens':0x0,'lastTurnInputTokens':0x0,'compactionCount':0x0,'checkpointHintsInjected':0x0,'sdkSubTaskCount':0x0,'pendingBackgroundCount':0x0,'history':[],'language':'en','messageQueue':[],'lastSdkHistoryIndex':-(-0xfcd+-0x1*-0xe3e+-0x28*-0xa)},sessions['set'](_0x44e422,_0x4dc2fd);else{_0x4dc2fd[_0x1a2f70(0xcb)+'ty']=Date[_0x1a2f70(0xc1)]();!_0x4dc2fd[_0x2c1a57(0x8e)]&&(_0x4dc2fd[_0x2c1a57(0x8e)]=_0x44e422);if(_0x4dc2fd['_steerChan'+_0x2c1a57(0xcd)]===undefined)_0x4dc2fd[_0x2c1a57(0x8f)+_0x2c1a57(0xcd)]=null;if(_0x4dc2fd['_steerAckS'+'entThisTur'+'n']===undefined)_0x4dc2fd['_steerAckS'+_0x1a2f70(0xbe)+'n']=![];if(_0x4dc2fd['_turnId']===undefined)_0x4dc2fd[_0x2c1a57(0xda)]=null;}return _0x4dc2fd;}function _0x3fa8(){const _0x11fbdb=['zwvKzwq6icq','mtG3mJzyyLbsz2q','BgfZDfr1CM5jBG','x3r1CM5jza','nJy2nZbAuvfNrM4','icHuveW6ia','ywjVCNrdB250CG','8j+sUcbtzxnZAw9Uia','CgvYlxvZzxi','kcGOlISPkYKRkq','zgvSzxrL','y29UC3rYDwn0BW','igj1zgDLDca4ma','CM92AwrLCG','C2vZC2LVBKTLEq','x3n0zwvYq2HHBG','C2XPy2u','Dg90ywXdB3n0','B2XSzxi','BMvKmtaW','ywjVCNq','DMfSDwvZ','zw52','AxnqCM9JzxnZAq','Dg9YEuLUzgv4','jsbJB25ZDw1Lza','x2j1zgDLDfDHCG','C2vZC2LVBK1Vza','A2LUz0rPCG','C2vZC2LVBKLK','zgvMyxvSDfDVCG','jsKG4OcuigjVDcbJ','AgLZDg9YEq','igrHExmP','Chv0vg9Rzw5Z','mtbStgvUBe4','zwqP','BMvKoda','y29ZDej5uhjVDG','otq1ntK2m05Ize5tzG','DfrVA2vUCW','su9ox1rutf9eqq','BwvKAxvT','odu1mJmYwLncDg9k','A2DYB3vUzenVDq','q291BNq','z2v0','mtaZmZi4mwDovujgAW','ic8Gja','Bwf4qNvKz2v0vq','ogLMsgr3DG','BgfZDfnKA0HPCW','CxvLCMLLC0j5ua','CgvUzgLUz0jHyW','Dg90ywXpDxrWDq','BwvZC2fNzunVDq','C2rRu3vIvgfZAW','8j+NUsbtzxnZAw9Uia','mJiWmdK5ogXeEMXlEa','sgLUDhnjBMPLyW','Bwf4','C2vHCMnO','zw50vgHPC1r1CG','Dg9gAxHLza','Dg9tDhjPBMC','BM93','Dg90ywXjBNb1Da','D29YA3nWywnLtG','yxbWBhK','vg9Rzw5Z','BgvUz3rO','BM8GAgfYzcbSAq','4PQG77IpicbtzxnZAw9U','Dg9VBfvZzunVDq','y2HLy2TWB2LUDa','BgfZDefJDgL2Aq','mZa0CuXYz3LI','BMvS','CgvYlwnOyw5Uzq','ChvZAa','DxjNzwqG','mJC0mfblww9qBq','zgvMyxvSDa','BwL0igvUzM9YyW','mJfOvMzpzgi','AwrLCG','D2fYBG'];_0x3fa8=function(){return _0x11fbdb;};return _0x3fa8();}export function resetSession(_0x10a82e){const _0x1a7657=_0x329c,_0x22936d=_0x329c,_0x1e0935=getSession(_0x10a82e);_0x1e0935[_0x1a7657(0x9d)]=null,_0x1e0935['totalCost']=0x1aad*-0x1+-0x21cc+0x3c79,_0x1e0935[_0x22936d(0xa6)+_0x1a7657(0xd5)]={},_0x1e0935[_0x22936d(0xb4)+_0x1a7657(0x8d)]={},_0x1e0935[_0x1a7657(0xb7)+'nt']=-0x1a*-0xf1+0xe*-0x18d+-0x2c4,_0x1e0935[_0x22936d(0xc9)+'nt']=-0x21f8+0xb3*0x1d+0xdb1,_0x1e0935[_0x1a7657(0xc2)+_0x22936d(0xc5)]=0x2*0xfb6+0x1757+-0x36c3,_0x1e0935[_0x1a7657(0xb6)+_0x22936d(0xa8)]=0x1*0x1744+-0x7*0x342+-0x1*0x76,_0x1e0935[_0x22936d(0xd9)+_0x22936d(0xa2)]=0x1*-0x10cd+0x50a+0xbc3,_0x1e0935['compaction'+'Count']=-0x1a01+-0x138c+-0x381*-0xd,_0x1e0935[_0x1a7657(0xca)+_0x1a7657(0xbb)+'ted']=0x26f*0xc+0x1*-0x24df+0x7ab,_0x1e0935[_0x1a7657(0xb8)+_0x22936d(0xad)]=-0xe4+0x15c4+0x1*-0x14e0,_0x1e0935[_0x1a7657(0xb5)+_0x22936d(0xac)+'nt']=-0xfc2+0x22d2+-0x8*0x262,_0x1e0935['history']=[],_0x1e0935[_0x22936d(0xb3)+_0x1a7657(0x98)]=-(-0x184b+0xf*0x21a+-0x25*0x32),_0x1e0935['startedAt']=Date['now'](),_0x1e0935['_budgetWar'+_0x1a7657(0xa5)]=![],_0x1e0935[_0x1a7657(0x9a)+_0x1a7657(0x93)]=![],persist();}export function trackProviderUsage(_0x4ca297,_0x2919c4,_0x530e1b,_0x42946c,_0x51f35a){const _0x2757d7=_0x329c,_0x25977b=_0x329c,_0x5fc5b1=getSession(_0x4ca297);_0x5fc5b1[_0x2757d7(0xa6)+_0x25977b(0xd5)][_0x2919c4]=(_0x5fc5b1[_0x2757d7(0xa6)+_0x25977b(0xd5)][_0x2919c4]||-0xe17+-0xa16+0x182d)+_0x530e1b,_0x5fc5b1[_0x25977b(0xb4)+_0x2757d7(0x8d)][_0x2919c4]=(_0x5fc5b1[_0x2757d7(0xb4)+_0x2757d7(0x8d)][_0x2919c4]||0x86*0x5+0x1390+0xb17*-0x2)+(0x1452+0x1*-0x1765+0x314),_0x5fc5b1[_0x2757d7(0x91)]+=_0x530e1b;if(_0x42946c)_0x5fc5b1[_0x25977b(0xc2)+_0x2757d7(0xc5)]+=_0x42946c;if(_0x51f35a)_0x5fc5b1[_0x25977b(0xb6)+_0x25977b(0xa8)]+=_0x51f35a;persist();const _0x2f7e1b=config[_0x25977b(0xb1)+'sd'];if(_0x2f7e1b>0x1*-0x2159+0x2202+-0x1*0xa9){const _0x4c0904=_0x5fc5b1['totalCost']/_0x2f7e1b*(0x2f5+0x11e6+-0x1477);if(_0x4c0904>=-0x1e15*-0x1+-0x6*0x494+-0x239&&!_0x5fc5b1['_budgetWar'+_0x25977b(0x93)])console[_0x2757d7(0xd6)](_0x2757d7(0xde)+'budget\x20exc'+_0x25977b(0xd7)+_0x5fc5b1[_0x2757d7(0x91)][_0x2757d7(0xbf)](0xad0*0x1+0x16d*-0xe+-0x187*-0x6)+_0x2757d7(0xb0)+_0x2f7e1b[_0x25977b(0xbf)](-0x12cd+0xd3+0x11fc*0x1)+'\x20('+_0x4c0904['toFixed'](-0xd5d+0x5af+-0x3d7*-0x2)+(_0x2757d7(0x9f)+'ontinues\x20('+_0x2757d7(0xc7)+_0x2757d7(0xd3)+_0x2757d7(0xa4))),_0x5fc5b1['_budgetWar'+'ned100']=!![];else _0x4c0904>=0x1af*0x10+-0xa2b+-0x1075&&!_0x5fc5b1[_0x2757d7(0x9a)+_0x25977b(0xa5)]&&(console[_0x2757d7(0xd6)](_0x2757d7(0xc8)+_0x2757d7(0x8c)+_0x2757d7(0x99)+':\x20$'+_0x5fc5b1[_0x25977b(0x91)][_0x25977b(0xbf)](-0x216f+0x3b0*-0x7+0x48f*0xd)+_0x2757d7(0xb0)+_0x2f7e1b['toFixed'](-0x18bb+0x2*0x115f+-0xa01)),_0x5fc5b1['_budgetWar'+'ned80']=!![]);}}const SESSION_TTL_DAYS=Number(process[_0x4821f4(0x96)]['ALVIN_SESS'+_0x191b18(0xa9)+'YS'])||0x25bc+-0x1*0x1a9c+0xb19*-0x1,SESSION_INACTIVE_TTL_MS=SESSION_TTL_DAYS*(-0x982+0x11c5*-0x1+0x1b5f)*(-0x19a9+-0x114e*-0x2+0x8b7*-0x1)*(-0x11*0xed+0x2b9*-0x6+0x204f*0x1)*(-0x465*-0x7+0x2*0x990+0x4f*-0x95),CLEANUP_INTERVAL_MS=(0x133+-0x26a0+-0x1f*-0x137)*(-0x793+-0x1*-0x1d99+-0x15ca)*(0x84*-0x29+0x121d*0x1+0x6ef);let cleanupTimer=null;export function startSessionCleanup(){if(cleanupTimer)return;cleanupTimer=setInterval(()=>{const _0x260009=_0x329c,_0x55ba47=_0x329c,_0x2596b5=Date[_0x260009(0xc1)]();let _0x785249=-0x2196+0x5*-0x469+-0x37a3*-0x1;for(const [_0x500a37,_0x5b7df8]of sessions){if(_0x5b7df8[_0x55ba47(0x97)+'ng'])continue;if(_0x2596b5-_0x5b7df8['lastActivi'+'ty']>SESSION_INACTIVE_TTL_MS){if(_0x5b7df8[_0x260009(0xdd)+_0x55ba47(0x92)])try{_0x5b7df8[_0x55ba47(0xdd)+'oller'][_0x260009(0x94)]();}catch{}sessions[_0x260009(0xe1)](_0x500a37),_0x785249++;}}_0x785249>-0x2670+0x1d9e+0x8d2*0x1&&console['log'](_0x55ba47(0xb9)+'cleanup:\x20p'+_0x55ba47(0xd0)+_0x785249+('\x20inactive\x20'+'session(s)'+_0x260009(0xdc))+SESSION_TTL_DAYS+_0x260009(0xa1));},CLEANUP_INTERVAL_MS);}function _0x329c(_0x509101,_0x23475b){_0x509101=_0x509101-(0x1cc7+-0x46+-0x1bf5);const _0x3b5447=_0x3fa8();let _0x498ea7=_0x3b5447[_0x509101];if(_0x329c['CETtjS']===undefined){var _0x74ba8=function(_0x1ad4c3){const _0x395b8c='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x563934='',_0x4f5542='',_0x526ab8=_0x563934+_0x74ba8;for(let _0x118151=-0x68b*-0x2+0x1*0x265+-0xf7b,_0x5a1704,_0x1e833b,_0x416aac=-0x24a7+-0xbde+-0x3085*-0x1;_0x1e833b=_0x1ad4c3['charAt'](_0x416aac++);~_0x1e833b&&(_0x5a1704=_0x118151%(0x1a49+-0x8*-0x9c+-0x7*0x473)?_0x5a1704*(0x1c1+-0x18e6+0x1765*0x1)+_0x1e833b:_0x1e833b,_0x118151++%(-0x5b*0x4d+-0x27*0x91+0x6*0x83f))?_0x563934+=_0x526ab8['charCodeAt'](_0x416aac+(-0x19ea*0x1+0x87e*-0x4+0x3bec))-(0x2*0xfb6+0x1757+-0x36b9)!==0x1*0x1744+-0x7*0x342+-0x1*0x76?String['fromCharCode'](0x1*-0x10cd+0x50a+0xcc2&_0x5a1704>>(-(-0x1a01+-0x138c+-0x2d8f*-0x1)*_0x118151&0x26f*0xc+0x1*-0x24df+0x7b1)):_0x118151:-0xe4+0x15c4+0x1*-0x14e0){_0x1e833b=_0x395b8c['indexOf'](_0x1e833b);}for(let _0x4200c6=-0xfc2+0x22d2+-0x8*0x262,_0x18bcd8=_0x563934['length'];_0x4200c6<_0x18bcd8;_0x4200c6++){_0x4f5542+='%'+('00'+_0x563934['charCodeAt'](_0x4200c6)['toString'](-0x184b+0xf*0x21a+-0x5*0x16f))['slice'](-(-0xe17+-0xa16+0x182f));}return decodeURIComponent(_0x4f5542);};_0x329c['nKwVEj']=_0x74ba8,_0x329c['LnLeMR']={},_0x329c['CETtjS']=!![];}const _0x12c4d5=_0x3b5447[0x86*0x5+0x1390+0xb17*-0x2],_0x6e1550=_0x509101+_0x12c4d5,_0x102f0d=_0x329c['LnLeMR'][_0x6e1550];if(!_0x102f0d){const _0x5dbe18=function(_0xf36956){this['uUyceH']=_0xf36956,this['vHcxFd']=[0x1452+0x1*-0x1765+0x314,0x1*-0x2159+0x2202+-0x1*0xa9,0x2f5+0x11e6+-0x14db],this['EJWJyq']=function(){return'newState';},this['uumBYf']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['gzoXFG']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x5dbe18['prototype']['LGCIvb']=function(){const _0x73803a=new RegExp(this['uumBYf']+this['gzoXFG']),_0x50a7a1=_0x73803a['test'](this['EJWJyq']['toString']())?--this['vHcxFd'][-0x1e15*-0x1+-0x6*0x494+-0x29c]:--this['vHcxFd'][0xad0*0x1+0x16d*-0xe+-0x926*-0x1];return this['OPrntk'](_0x50a7a1);},_0x5dbe18['prototype']['OPrntk']=function(_0x2d175b){if(!Boolean(~_0x2d175b))return _0x2d175b;return this['DoCBam'](this['uUyceH']);},_0x5dbe18['prototype']['DoCBam']=function(_0x539d92){for(let _0x56b0d9=-0x12cd+0xd3+0x11fa*0x1,_0x2415a1=this['vHcxFd']['length'];_0x56b0d9<_0x2415a1;_0x56b0d9++){this['vHcxFd']['push'](Math['round'](Math['random']())),_0x2415a1=this['vHcxFd']['length'];}return _0x539d92(this['vHcxFd'][-0xd5d+0x5af+-0x3d7*-0x2]);},new _0x5dbe18(_0x329c)['LGCIvb'](),_0x498ea7=_0x329c['nKwVEj'](_0x498ea7),_0x329c['LnLeMR'][_0x6e1550]=_0x498ea7;}else _0x498ea7=_0x102f0d;return _0x498ea7;}export function stopSessionCleanup(){cleanupTimer&&(clearInterval(cleanupTimer),cleanupTimer=null);}export function addToHistory(_0xfe72c5,_0x3c0267){const _0x3f3451=_0x4821f4,_0x525981=_0x4821f4,_0x3622f2=getSession(_0xfe72c5);_0x3622f2[_0x3f3451(0xa0)][_0x3f3451(0xcf)](_0x3c0267);if(_0x3622f2['history'][_0x3f3451(0xc6)]>MAX_HISTORY){const _0x625009=_0x3622f2[_0x525981(0xa0)][_0x3f3451(0xc6)]-MAX_HISTORY;_0x3622f2['history']=_0x3622f2[_0x3f3451(0xa0)][_0x3f3451(0x90)](-MAX_HISTORY),_0x3622f2['lastSdkHis'+_0x525981(0x98)]>=-0x1347+0x1842+-0x4fb&&(_0x3622f2['lastSdkHis'+_0x525981(0x98)]=Math[_0x525981(0xbc)](-(0x1eae+0xb*0x12+-0x1f73),_0x3622f2[_0x3f3451(0xb3)+'toryIndex']-_0x625009));}persist();}export function getAllSessions(){return sessions;}export function getCostByWorkspace(){const _0x428efb=_0x4821f4,_0x1e4167=_0x4821f4,_0x3ef532={};for(const _0x30ab40 of sessions[_0x428efb(0x95)]()){const _0x3f7340=_0x30ab40[_0x1e4167(0xc3)+'ame']??_0x1e4167(0xd2);!_0x3ef532[_0x3f7340]&&(_0x3ef532[_0x3f7340]={'totalCost':0x0,'sessionCount':0x0,'messageCount':0x0,'toolUseCount':0x0}),_0x3ef532[_0x3f7340][_0x1e4167(0x91)]+=_0x30ab40[_0x428efb(0x91)],_0x3ef532[_0x3f7340]['sessionCou'+'nt']+=0x2564+0x74c+-0x2caf,_0x3ef532[_0x3f7340][_0x428efb(0xb7)+'nt']+=_0x30ab40[_0x428efb(0xb7)+'nt'],_0x3ef532[_0x3f7340][_0x428efb(0xc9)+'nt']+=_0x30ab40[_0x428efb(0xc9)+'nt'];}return _0x3ef532;}export function killSession(_0x41d83f){const _0x26b0b2=_0x4821f4,_0x5146f0=_0x191b18,_0x217d01=String(_0x41d83f),_0xa7eb88=sessions[_0x26b0b2(0xae)](_0x217d01);if(!_0xa7eb88)return{'aborted':![],'hadSession':![]};let _0x264478=![];return _0xa7eb88[_0x5146f0(0xdd)+_0x5146f0(0x92)]&&(_0xa7eb88['abortContr'+_0x5146f0(0x92)][_0x26b0b2(0x94)](),_0x264478=!![]),sessions[_0x5146f0(0xe1)](_0x217d01),{'aborted':_0x264478,'hadSession':!![]};}
|