@nomad-e/bluma-cli 0.23.0 → 0.24.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/dist/main.js +341 -101
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2242,25 +2242,14 @@ var init_ListMailboxMessagesTool = __esm({
|
|
|
2242
2242
|
|
|
2243
2243
|
// src/app/agent/core/context-api/token_counter.ts
|
|
2244
2244
|
import { getEncoding } from "js-tiktoken";
|
|
2245
|
-
import { createHash as createHash2 } from "crypto";
|
|
2246
2245
|
function getO200kEncoding() {
|
|
2247
2246
|
if (!cachedEncoding) {
|
|
2248
2247
|
cachedEncoding = getEncoding("o200k_base");
|
|
2249
2248
|
}
|
|
2250
2249
|
return cachedEncoding;
|
|
2251
2250
|
}
|
|
2252
|
-
function
|
|
2253
|
-
|
|
2254
|
-
hash.update(`len:${messages.length}:`);
|
|
2255
|
-
for (const msg of messages) {
|
|
2256
|
-
const m = msg;
|
|
2257
|
-
hash.update(`role:${m.role ?? ""}:`);
|
|
2258
|
-
hash.update(`content:${JSON.stringify(m.content ?? "")}:`);
|
|
2259
|
-
hash.update(`tool_calls:${JSON.stringify(m.tool_calls ?? "")}:`);
|
|
2260
|
-
hash.update(`tool_call_id:${m.tool_call_id ?? ""}:`);
|
|
2261
|
-
hash.update(`name:${m.name ?? ""}:`);
|
|
2262
|
-
}
|
|
2263
|
-
return hash.digest("hex");
|
|
2251
|
+
function invalidateTokenCache() {
|
|
2252
|
+
cacheVersion++;
|
|
2264
2253
|
}
|
|
2265
2254
|
function messageBodyForTokens(msg) {
|
|
2266
2255
|
const c = msg.content;
|
|
@@ -2286,41 +2275,40 @@ function messageExtraForTokens(msg) {
|
|
|
2286
2275
|
}
|
|
2287
2276
|
return parts.join("\0");
|
|
2288
2277
|
}
|
|
2278
|
+
function tokensForString(s) {
|
|
2279
|
+
if (s.length === 0) return 0;
|
|
2280
|
+
let cached = tokenStringCache.get(s);
|
|
2281
|
+
if (cached !== void 0) return cached;
|
|
2282
|
+
cached = getO200kEncoding().encode(s).length;
|
|
2283
|
+
if (tokenStringCache.size >= TOKEN_STRING_CACHE_MAX) {
|
|
2284
|
+
const first = tokenStringCache.keys().next().value;
|
|
2285
|
+
if (first !== void 0) tokenStringCache.delete(first);
|
|
2286
|
+
}
|
|
2287
|
+
tokenStringCache.set(s, cached);
|
|
2288
|
+
return cached;
|
|
2289
|
+
}
|
|
2290
|
+
function tokensForMessage(msg) {
|
|
2291
|
+
const body = messageBodyForTokens(msg);
|
|
2292
|
+
const extra = messageExtraForTokens(msg);
|
|
2293
|
+
return tokensForString(body) + tokensForString(extra) + MESSAGE_OVERHEAD_TOKENS;
|
|
2294
|
+
}
|
|
2289
2295
|
function countTokens(messages, useCache = true) {
|
|
2290
2296
|
if (messages.length === 0) {
|
|
2291
2297
|
return CONVERSATION_BASE_OVERHEAD;
|
|
2292
2298
|
}
|
|
2293
|
-
if (useCache) {
|
|
2294
|
-
|
|
2295
|
-
if (tokenCountCache && tokenCountCache.hash === currentHash) {
|
|
2296
|
-
return tokenCountCache.count;
|
|
2297
|
-
}
|
|
2298
|
-
const enc2 = getO200kEncoding();
|
|
2299
|
-
let total2 = CONVERSATION_BASE_OVERHEAD;
|
|
2300
|
-
for (const msg of messages) {
|
|
2301
|
-
const body = messageBodyForTokens(msg);
|
|
2302
|
-
const extra = messageExtraForTokens(msg);
|
|
2303
|
-
const nBody = body ? enc2.encode(body).length : 0;
|
|
2304
|
-
const nExtra = extra ? enc2.encode(extra).length : 0;
|
|
2305
|
-
total2 += nBody + nExtra + MESSAGE_OVERHEAD_TOKENS;
|
|
2306
|
-
}
|
|
2307
|
-
tokenCountCache = { hash: currentHash, count: total2 };
|
|
2308
|
-
return total2;
|
|
2299
|
+
if (useCache && cacheVersion === cachedVersion) {
|
|
2300
|
+
return cachedCount;
|
|
2309
2301
|
}
|
|
2310
|
-
const enc = getO200kEncoding();
|
|
2311
2302
|
let total = CONVERSATION_BASE_OVERHEAD;
|
|
2312
2303
|
for (const msg of messages) {
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2304
|
+
total += tokensForMessage(msg);
|
|
2305
|
+
}
|
|
2306
|
+
if (useCache) {
|
|
2307
|
+
cachedVersion = cacheVersion;
|
|
2308
|
+
cachedCount = total;
|
|
2318
2309
|
}
|
|
2319
2310
|
return total;
|
|
2320
2311
|
}
|
|
2321
|
-
function clearTokenCountCache() {
|
|
2322
|
-
tokenCountCache = null;
|
|
2323
|
-
}
|
|
2324
2312
|
function countToolDefinitionsTokens(tools) {
|
|
2325
2313
|
if (!tools || tools.length === 0) {
|
|
2326
2314
|
return 0;
|
|
@@ -2345,14 +2333,18 @@ function computeEffectiveInputBudget(rawBudget, toolDefinitions = [], options) {
|
|
|
2345
2333
|
effectiveBudget
|
|
2346
2334
|
};
|
|
2347
2335
|
}
|
|
2348
|
-
var MESSAGE_OVERHEAD_TOKENS, CONVERSATION_BASE_OVERHEAD, cachedEncoding,
|
|
2336
|
+
var MESSAGE_OVERHEAD_TOKENS, CONVERSATION_BASE_OVERHEAD, cachedEncoding, cacheVersion, cachedVersion, cachedCount, tokenStringCache, TOKEN_STRING_CACHE_MAX, DEFAULT_OUTPUT_TOKEN_RESERVE, DEFAULT_PROTOCOL_OVERHEAD_TOKENS;
|
|
2349
2337
|
var init_token_counter = __esm({
|
|
2350
2338
|
"src/app/agent/core/context-api/token_counter.ts"() {
|
|
2351
2339
|
"use strict";
|
|
2352
2340
|
MESSAGE_OVERHEAD_TOKENS = 4;
|
|
2353
2341
|
CONVERSATION_BASE_OVERHEAD = 3;
|
|
2354
2342
|
cachedEncoding = null;
|
|
2355
|
-
|
|
2343
|
+
cacheVersion = 0;
|
|
2344
|
+
cachedVersion = -1;
|
|
2345
|
+
cachedCount = 0;
|
|
2346
|
+
tokenStringCache = /* @__PURE__ */ new Map();
|
|
2347
|
+
TOKEN_STRING_CACHE_MAX = 4096;
|
|
2356
2348
|
DEFAULT_OUTPUT_TOKEN_RESERVE = 8192;
|
|
2357
2349
|
DEFAULT_PROTOCOL_OVERHEAD_TOKENS = 512;
|
|
2358
2350
|
}
|
|
@@ -14315,7 +14307,7 @@ import { v4 as uuidv412 } from "uuid";
|
|
|
14315
14307
|
import chalk3 from "chalk";
|
|
14316
14308
|
|
|
14317
14309
|
// src/app/ui/BlumaSession.tsx
|
|
14318
|
-
import
|
|
14310
|
+
import { useState as useState25, useEffect as useEffect22, useRef as useRef13, useCallback as useCallback11, memo as memo25, useMemo as useMemo8 } from "react";
|
|
14319
14311
|
|
|
14320
14312
|
// src/app/ui/layout.tsx
|
|
14321
14313
|
import { memo as memo2 } from "react";
|
|
@@ -25084,8 +25076,13 @@ var HistoryCompressor = class {
|
|
|
25084
25076
|
const tokenBudget = budgetBreakdown.effectiveBudget;
|
|
25085
25077
|
const compressThreshold = options?.compressThreshold ?? COMPRESS_THRESHOLD;
|
|
25086
25078
|
const keepRecentTurns = options?.keepRecentTurns ?? KEEP_RECENT_TURNS;
|
|
25087
|
-
|
|
25088
|
-
|
|
25079
|
+
let safeHistory;
|
|
25080
|
+
if (options?.skipSanitize) {
|
|
25081
|
+
safeHistory = fullHistory;
|
|
25082
|
+
} else {
|
|
25083
|
+
const sanitized = sanitizeConversationForProvider(fullHistory);
|
|
25084
|
+
safeHistory = sanitized.messages;
|
|
25085
|
+
}
|
|
25089
25086
|
const systemMessages = [];
|
|
25090
25087
|
let historyStartIndex = 0;
|
|
25091
25088
|
while (historyStartIndex < safeHistory.length && safeHistory[historyStartIndex].role === "system") {
|
|
@@ -25102,7 +25099,6 @@ var HistoryCompressor = class {
|
|
|
25102
25099
|
const thresholdTokens = tokenBudget * compressThreshold;
|
|
25103
25100
|
let pendingSlices = turnSlices.slice(sliceCount, recentStart);
|
|
25104
25101
|
let pendingFlat = pendingSlices.flat();
|
|
25105
|
-
clearTokenCountCache();
|
|
25106
25102
|
let messages = this.assembleMessages(systemMessages, pendingFlat, recentFlat);
|
|
25107
25103
|
let tokens = countTokens(messages, true);
|
|
25108
25104
|
contextEventBus.emit("context:compression_start", {
|
|
@@ -25149,12 +25145,12 @@ var HistoryCompressor = class {
|
|
|
25149
25145
|
reason: compressError?.message || "timeout"
|
|
25150
25146
|
});
|
|
25151
25147
|
}
|
|
25152
|
-
|
|
25148
|
+
invalidateTokenCache();
|
|
25153
25149
|
messages = this.assembleMessages(systemMessages, pendingFlat, recentFlat);
|
|
25154
25150
|
tokens = countTokens(messages, true);
|
|
25155
25151
|
}
|
|
25156
25152
|
if (tokens > tokenBudget) {
|
|
25157
|
-
|
|
25153
|
+
invalidateTokenCache();
|
|
25158
25154
|
const { capped, slices: cappedSlices } = this.enforceHardCap(
|
|
25159
25155
|
systemMessages,
|
|
25160
25156
|
recentSlices,
|
|
@@ -26432,7 +26428,14 @@ function cleanupOldEntries() {
|
|
|
26432
26428
|
}
|
|
26433
26429
|
function setToolResultStatus(toolCallId, status, result) {
|
|
26434
26430
|
if (!toolCallId) return;
|
|
26435
|
-
|
|
26431
|
+
let parsedResult = result;
|
|
26432
|
+
if (typeof result === "string") {
|
|
26433
|
+
try {
|
|
26434
|
+
parsedResult = JSON.parse(result);
|
|
26435
|
+
} catch {
|
|
26436
|
+
parsedResult = result;
|
|
26437
|
+
}
|
|
26438
|
+
}
|
|
26436
26439
|
store.set(toolCallId, { status, timestamp: Date.now(), result: parsedResult });
|
|
26437
26440
|
cleanupOldEntries();
|
|
26438
26441
|
changed.emit();
|
|
@@ -27246,7 +27249,9 @@ var BluMaTurnCoordinator = class {
|
|
|
27246
27249
|
this.deps.getLlmUserContext(),
|
|
27247
27250
|
{
|
|
27248
27251
|
tokenBudget,
|
|
27249
|
-
toolDefinitions: this.deps.mcpClient.getAvailableTools()
|
|
27252
|
+
toolDefinitions: this.deps.mcpClient.getAvailableTools(),
|
|
27253
|
+
skipSanitize: true
|
|
27254
|
+
// already sanitized above
|
|
27250
27255
|
}
|
|
27251
27256
|
);
|
|
27252
27257
|
this.turnLog.debug("Context window prepared", {
|
|
@@ -28137,11 +28142,15 @@ function hasMetUpdateThreshold(currentTokens) {
|
|
|
28137
28142
|
// src/app/agent/memory/session_memory_update.ts
|
|
28138
28143
|
init_logger();
|
|
28139
28144
|
var log2 = logger.child("session_memory");
|
|
28145
|
+
var MIN_COOLDOWN_MS = 6e4;
|
|
28146
|
+
var lastUpdateTime = 0;
|
|
28140
28147
|
function isSessionMemoryEnabled() {
|
|
28141
28148
|
if (process.env.BLUMA_DISABLE_SESSION_MEMORY === "1") return false;
|
|
28142
28149
|
return true;
|
|
28143
28150
|
}
|
|
28144
28151
|
function shouldUpdateSessionMemory(history) {
|
|
28152
|
+
const now2 = Date.now();
|
|
28153
|
+
if (now2 - lastUpdateTime < MIN_COOLDOWN_MS) return false;
|
|
28145
28154
|
const tokens = estimateHistoryTokens(history);
|
|
28146
28155
|
if (!isSessionMemoryInitialized()) {
|
|
28147
28156
|
if (!hasMetInitializationThreshold(tokens)) return false;
|
|
@@ -28191,6 +28200,7 @@ async function runSessionMemoryUpdate(deps) {
|
|
|
28191
28200
|
});
|
|
28192
28201
|
recordExtractionTokenCount(estimateHistoryTokens(history));
|
|
28193
28202
|
setLastCursorIndex(history.length);
|
|
28203
|
+
lastUpdateTime = Date.now();
|
|
28194
28204
|
log2.debug("finished");
|
|
28195
28205
|
} catch (err) {
|
|
28196
28206
|
log2.warn("failed", { error: err instanceof Error ? err.message : String(err) });
|
|
@@ -28205,8 +28215,10 @@ function scheduleSessionMemoryUpdate(deps) {
|
|
|
28205
28215
|
|
|
28206
28216
|
// src/app/agent/memory/background_memory.ts
|
|
28207
28217
|
function runBackgroundMemoryAfterTurn(params) {
|
|
28218
|
+
const MAX_SNAPSHOT = 80;
|
|
28219
|
+
const snapshot = params.history.length > MAX_SNAPSHOT ? params.history.slice(-MAX_SNAPSHOT) : params.history;
|
|
28208
28220
|
const deps = {
|
|
28209
|
-
history:
|
|
28221
|
+
history: snapshot,
|
|
28210
28222
|
sessionId: params.sessionId,
|
|
28211
28223
|
llm: params.llm,
|
|
28212
28224
|
mcpClient: params.mcpClient,
|
|
@@ -31761,8 +31773,37 @@ function ToolUseLoader({ state: state2 }) {
|
|
|
31761
31773
|
}
|
|
31762
31774
|
|
|
31763
31775
|
// src/app/agent/tools/shared/toolResultUtils.ts
|
|
31776
|
+
function sanitizeJsonString(s) {
|
|
31777
|
+
return s.replace(/[\x00-\x1f]/g, (ch) => {
|
|
31778
|
+
switch (ch) {
|
|
31779
|
+
case "\n":
|
|
31780
|
+
return "\\n";
|
|
31781
|
+
case "\r":
|
|
31782
|
+
return "\\r";
|
|
31783
|
+
case " ":
|
|
31784
|
+
return "\\t";
|
|
31785
|
+
case "\b":
|
|
31786
|
+
return "\\b";
|
|
31787
|
+
case "\f":
|
|
31788
|
+
return "\\f";
|
|
31789
|
+
default:
|
|
31790
|
+
return `\\u${ch.charCodeAt(0).toString(16).padStart(4, "0")}`;
|
|
31791
|
+
}
|
|
31792
|
+
});
|
|
31793
|
+
}
|
|
31764
31794
|
function resolveToolPayload(result) {
|
|
31765
|
-
|
|
31795
|
+
let raw = result;
|
|
31796
|
+
if (typeof result === "string") {
|
|
31797
|
+
try {
|
|
31798
|
+
raw = JSON.parse(result);
|
|
31799
|
+
} catch {
|
|
31800
|
+
try {
|
|
31801
|
+
raw = JSON.parse(sanitizeJsonString(result));
|
|
31802
|
+
} catch {
|
|
31803
|
+
return result;
|
|
31804
|
+
}
|
|
31805
|
+
}
|
|
31806
|
+
}
|
|
31766
31807
|
if (!raw) return null;
|
|
31767
31808
|
if (raw?.status === "error") return { error: raw.error };
|
|
31768
31809
|
if (raw?.status === "success" && "data" in raw) {
|
|
@@ -45377,6 +45418,177 @@ function ScrollBox({
|
|
|
45377
45418
|
}
|
|
45378
45419
|
var ScrollBox_default = ScrollBox;
|
|
45379
45420
|
|
|
45421
|
+
// src/app/ui/hooks/useVirtualScroll.ts
|
|
45422
|
+
import {
|
|
45423
|
+
useCallback as useCallback10,
|
|
45424
|
+
useLayoutEffect as useLayoutEffect3,
|
|
45425
|
+
useMemo as useMemo7,
|
|
45426
|
+
useRef as useRef12,
|
|
45427
|
+
useState as useState24
|
|
45428
|
+
} from "react";
|
|
45429
|
+
var DEFAULT_ESTIMATE = 3;
|
|
45430
|
+
var OVERSCAN_ROWS = 40;
|
|
45431
|
+
var COLD_START_COUNT = 20;
|
|
45432
|
+
var MAX_MOUNTED_ITEMS = 200;
|
|
45433
|
+
var PESSIMISTIC_HEIGHT = 1;
|
|
45434
|
+
function useVirtualScroll(scrollRef, itemKeys, columns) {
|
|
45435
|
+
const heightCache = useRef12(/* @__PURE__ */ new Map());
|
|
45436
|
+
const offsetVersionRef = useRef12(0);
|
|
45437
|
+
const lastScrollTopRef = useRef12(0);
|
|
45438
|
+
const offsetsRef = useRef12({
|
|
45439
|
+
arr: new Float64Array(0),
|
|
45440
|
+
version: -1,
|
|
45441
|
+
n: -1
|
|
45442
|
+
});
|
|
45443
|
+
const itemRefs = useRef12(/* @__PURE__ */ new Map());
|
|
45444
|
+
const refCache = useRef12(/* @__PURE__ */ new Map());
|
|
45445
|
+
const prevColumns = useRef12(columns);
|
|
45446
|
+
const skipMeasurementRef = useRef12(false);
|
|
45447
|
+
if (prevColumns.current !== columns) {
|
|
45448
|
+
const ratio = prevColumns.current / columns;
|
|
45449
|
+
prevColumns.current = columns;
|
|
45450
|
+
for (const [k, h] of heightCache.current) {
|
|
45451
|
+
heightCache.current.set(k, Math.max(1, Math.round(h * ratio)));
|
|
45452
|
+
}
|
|
45453
|
+
offsetVersionRef.current++;
|
|
45454
|
+
skipMeasurementRef.current = true;
|
|
45455
|
+
}
|
|
45456
|
+
const SCROLL_QUANTUM = OVERSCAN_ROWS >> 1;
|
|
45457
|
+
const subscribe = useCallback10(
|
|
45458
|
+
(cb) => scrollRef.current?.subscribe(cb) ?? (() => {
|
|
45459
|
+
}),
|
|
45460
|
+
[scrollRef]
|
|
45461
|
+
);
|
|
45462
|
+
const getSnapshot = useCallback10(() => {
|
|
45463
|
+
const sb = scrollRef.current;
|
|
45464
|
+
if (!sb) return NaN;
|
|
45465
|
+
const raw = sb.getScrollTop();
|
|
45466
|
+
const sticky = sb.isSticky();
|
|
45467
|
+
const quantized = Math.floor(raw / SCROLL_QUANTUM) * SCROLL_QUANTUM;
|
|
45468
|
+
return sticky ? -(quantized | 1) : quantized;
|
|
45469
|
+
}, [scrollRef, SCROLL_QUANTUM]);
|
|
45470
|
+
const getServerSnapshot = useCallback10(() => NaN, []);
|
|
45471
|
+
const scrollTop = useSyncExternalStore5(subscribe, getSnapshot, getServerSnapshot);
|
|
45472
|
+
const [viewportHeight, setViewportHeight] = useState24(
|
|
45473
|
+
() => scrollRef.current?.getViewportHeight() ?? 0
|
|
45474
|
+
);
|
|
45475
|
+
const prevVpRef = useRef12(viewportHeight);
|
|
45476
|
+
useLayoutEffect3(() => {
|
|
45477
|
+
const next = scrollRef.current?.getViewportHeight() ?? 0;
|
|
45478
|
+
if (next !== prevVpRef.current) {
|
|
45479
|
+
prevVpRef.current = next;
|
|
45480
|
+
setViewportHeight(next);
|
|
45481
|
+
}
|
|
45482
|
+
});
|
|
45483
|
+
const isSticky = scrollRef.current?.isSticky() ?? true;
|
|
45484
|
+
const n = itemKeys.length;
|
|
45485
|
+
const computeOffsets = useCallback10(() => {
|
|
45486
|
+
const cached = offsetsRef.current;
|
|
45487
|
+
if (cached.n === n && cached.version === offsetVersionRef.current && cached.arr.length === n + 1) {
|
|
45488
|
+
return cached.arr;
|
|
45489
|
+
}
|
|
45490
|
+
const offsets2 = new Float64Array(n + 1);
|
|
45491
|
+
for (let i = 0; i < n; i++) {
|
|
45492
|
+
const h = heightCache.current.get(itemKeys[i]) ?? DEFAULT_ESTIMATE;
|
|
45493
|
+
offsets2[i + 1] = offsets2[i] + h;
|
|
45494
|
+
}
|
|
45495
|
+
offsetsRef.current = { arr: offsets2, version: offsetVersionRef.current, n };
|
|
45496
|
+
return offsets2;
|
|
45497
|
+
}, [n, itemKeys, offsetVersionRef.current]);
|
|
45498
|
+
const offsets = computeOffsets();
|
|
45499
|
+
const totalHeight = offsets[n] ?? 0;
|
|
45500
|
+
const range = useMemo7(() => {
|
|
45501
|
+
if (n === 0) return [0, 0];
|
|
45502
|
+
if (viewportHeight <= 0) {
|
|
45503
|
+
return [0, Math.min(n, COLD_START_COUNT)];
|
|
45504
|
+
}
|
|
45505
|
+
const absScrollTop = Math.abs(scrollTop);
|
|
45506
|
+
if (isSticky) {
|
|
45507
|
+
let hi3 = n;
|
|
45508
|
+
let remaining = viewportHeight + OVERSCAN_ROWS;
|
|
45509
|
+
while (hi3 > 0 && remaining > 0) {
|
|
45510
|
+
const h = heightCache.current.get(itemKeys[hi3 - 1]) ?? DEFAULT_ESTIMATE;
|
|
45511
|
+
remaining -= h;
|
|
45512
|
+
hi3--;
|
|
45513
|
+
}
|
|
45514
|
+
const lo3 = Math.max(0, hi3 - OVERSCAN_ROWS);
|
|
45515
|
+
return [lo3, n];
|
|
45516
|
+
}
|
|
45517
|
+
let lo2 = 0;
|
|
45518
|
+
{
|
|
45519
|
+
const target = Math.max(0, absScrollTop - OVERSCAN_ROWS);
|
|
45520
|
+
let lo_ = 0;
|
|
45521
|
+
let hi_ = n;
|
|
45522
|
+
while (lo_ < hi_) {
|
|
45523
|
+
const mid = lo_ + hi_ >>> 1;
|
|
45524
|
+
if (offsets[mid] < target) lo_ = mid + 1;
|
|
45525
|
+
else hi_ = mid;
|
|
45526
|
+
}
|
|
45527
|
+
lo2 = lo_;
|
|
45528
|
+
}
|
|
45529
|
+
let hi2 = lo2;
|
|
45530
|
+
let accumulated = 0;
|
|
45531
|
+
const needed = viewportHeight + 2 * OVERSCAN_ROWS;
|
|
45532
|
+
while (hi2 < n && accumulated < needed) {
|
|
45533
|
+
const h = heightCache.current.get(itemKeys[hi2]) ?? PESSIMISTIC_HEIGHT;
|
|
45534
|
+
accumulated += h;
|
|
45535
|
+
hi2++;
|
|
45536
|
+
}
|
|
45537
|
+
return [lo2, Math.min(hi2, lo2 + MAX_MOUNTED_ITEMS)];
|
|
45538
|
+
}, [scrollTop, viewportHeight, isSticky, n, offsets, itemKeys]);
|
|
45539
|
+
const measureRef = useCallback10((key) => {
|
|
45540
|
+
if (refCache.current.has(key)) return refCache.current.get(key);
|
|
45541
|
+
const refFn = (el) => {
|
|
45542
|
+
if (skipMeasurementRef.current) return;
|
|
45543
|
+
if (el) {
|
|
45544
|
+
itemRefs.current.set(key, el);
|
|
45545
|
+
const h = el.yogaNode?.getComputedHeight();
|
|
45546
|
+
if (h != null && h > 0) {
|
|
45547
|
+
const prev = heightCache.current.get(key);
|
|
45548
|
+
if (prev !== h) {
|
|
45549
|
+
heightCache.current.set(key, h);
|
|
45550
|
+
offsetVersionRef.current++;
|
|
45551
|
+
}
|
|
45552
|
+
}
|
|
45553
|
+
}
|
|
45554
|
+
};
|
|
45555
|
+
refCache.current.set(key, refFn);
|
|
45556
|
+
return refFn;
|
|
45557
|
+
}, []);
|
|
45558
|
+
const [lo, hi] = range;
|
|
45559
|
+
const topSpacer = offsets[lo] ?? 0;
|
|
45560
|
+
const bottomSpacer = totalHeight - (offsets[hi] ?? totalHeight);
|
|
45561
|
+
return {
|
|
45562
|
+
range,
|
|
45563
|
+
topSpacer,
|
|
45564
|
+
bottomSpacer,
|
|
45565
|
+
offsets,
|
|
45566
|
+
measureRef
|
|
45567
|
+
};
|
|
45568
|
+
}
|
|
45569
|
+
function useSyncExternalStore5(subscribe, getSnapshot, getServerSnapshot) {
|
|
45570
|
+
const [value, setValue] = useState24(getSnapshot);
|
|
45571
|
+
const getSnapshotRef = useRef12(getSnapshot);
|
|
45572
|
+
getSnapshotRef.current = getSnapshot;
|
|
45573
|
+
useLayoutEffect3(() => {
|
|
45574
|
+
let didSubscribe = false;
|
|
45575
|
+
const checkForUpdates2 = () => {
|
|
45576
|
+
if (didSubscribe) {
|
|
45577
|
+
const newValue = getSnapshotRef.current();
|
|
45578
|
+
setValue(newValue);
|
|
45579
|
+
}
|
|
45580
|
+
};
|
|
45581
|
+
didSubscribe = true;
|
|
45582
|
+
checkForUpdates2();
|
|
45583
|
+
const unsubscribe = subscribe(checkForUpdates2);
|
|
45584
|
+
return () => {
|
|
45585
|
+
didSubscribe = false;
|
|
45586
|
+
unsubscribe();
|
|
45587
|
+
};
|
|
45588
|
+
}, [subscribe]);
|
|
45589
|
+
return value;
|
|
45590
|
+
}
|
|
45591
|
+
|
|
45380
45592
|
// src/app/ui/BlumaSession.tsx
|
|
45381
45593
|
import { Fragment as Fragment19, jsx as jsx104, jsxs as jsxs85 } from "react/jsx-runtime";
|
|
45382
45594
|
var blumaUpdateRegistryCheckStarted = false;
|
|
@@ -45442,23 +45654,23 @@ function UserMessageWithOptionalImages({
|
|
|
45442
45654
|
) : /* @__PURE__ */ jsx104(Text, { color: BLUMA_TERMINAL.m3OnSurface, wrap: "wrap", children: displayRaw }) });
|
|
45443
45655
|
}
|
|
45444
45656
|
var BlumaSessionComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
45445
|
-
const agentInstance =
|
|
45446
|
-
const [history, setHistory] =
|
|
45447
|
-
const [statusMessage, setStatusMessage] =
|
|
45657
|
+
const agentInstance = useRef13(null);
|
|
45658
|
+
const [history, setHistory] = useState25([]);
|
|
45659
|
+
const [statusMessage, setStatusMessage] = useState25(
|
|
45448
45660
|
"Initializing agent..."
|
|
45449
45661
|
);
|
|
45450
|
-
const [toolsCount, setToolsCount] =
|
|
45451
|
-
const [mcpStatus, setMcpStatus] =
|
|
45662
|
+
const [toolsCount, setToolsCount] = useState25(null);
|
|
45663
|
+
const [mcpStatus, setMcpStatus] = useState25(
|
|
45452
45664
|
"connecting"
|
|
45453
45665
|
);
|
|
45454
|
-
const [isProcessing, setIsProcessing] =
|
|
45455
|
-
const [pendingConfirmation, setPendingConfirmation] =
|
|
45666
|
+
const [isProcessing, setIsProcessing] = useState25(true);
|
|
45667
|
+
const [pendingConfirmation, setPendingConfirmation] = useState25(
|
|
45456
45668
|
null
|
|
45457
45669
|
);
|
|
45458
|
-
const [confirmationPreview, setConfirmationPreview] =
|
|
45670
|
+
const [confirmationPreview, setConfirmationPreview] = useState25(
|
|
45459
45671
|
null
|
|
45460
45672
|
);
|
|
45461
|
-
const [pendingAskUserQuestions, setPendingAskUserQuestions] =
|
|
45673
|
+
const [pendingAskUserQuestions, setPendingAskUserQuestions] = useState25(null);
|
|
45462
45674
|
const {
|
|
45463
45675
|
tokenCount,
|
|
45464
45676
|
tokenBudget,
|
|
@@ -45471,7 +45683,7 @@ var BlumaSessionComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
45471
45683
|
const { currentPlan, isPlanMode, parseMessage, resetPlan } = usePlanMode();
|
|
45472
45684
|
const { agentMode } = useAgentMode();
|
|
45473
45685
|
const workdir = getSandboxPolicy().workspaceRoot;
|
|
45474
|
-
const lastUpdateRef =
|
|
45686
|
+
const lastUpdateRef = useRef13(0);
|
|
45475
45687
|
useEffect22(() => {
|
|
45476
45688
|
const now2 = Date.now();
|
|
45477
45689
|
if (now2 - lastUpdateRef.current < 250) {
|
|
@@ -45490,29 +45702,29 @@ var BlumaSessionComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
45490
45702
|
activeProjects
|
|
45491
45703
|
});
|
|
45492
45704
|
}, [tokenCount, tokenBudget, isCompressing, compressionProgress, agentMode, isPlanMode, workdir, activeProjects]);
|
|
45493
|
-
const [isInitAgentActive, setIsInitAgentActive] =
|
|
45494
|
-
const [liveToolName, setLiveToolName] =
|
|
45495
|
-
const [liveToolArgs, setLiveToolArgs] =
|
|
45496
|
-
const [isReasoning, setIsReasoning] =
|
|
45497
|
-
const alwaysAcceptList =
|
|
45498
|
-
const turnStartedAtRef =
|
|
45499
|
-
const [processingStartMs, setProcessingStartMs] =
|
|
45500
|
-
const [lastTurnDurationLabel, setLastTurnDurationLabel] =
|
|
45501
|
-
const markTurnStarted =
|
|
45705
|
+
const [isInitAgentActive, setIsInitAgentActive] = useState25(false);
|
|
45706
|
+
const [liveToolName, setLiveToolName] = useState25(null);
|
|
45707
|
+
const [liveToolArgs, setLiveToolArgs] = useState25(void 0);
|
|
45708
|
+
const [isReasoning, setIsReasoning] = useState25(false);
|
|
45709
|
+
const alwaysAcceptList = useRef13([]);
|
|
45710
|
+
const turnStartedAtRef = useRef13(null);
|
|
45711
|
+
const [processingStartMs, setProcessingStartMs] = useState25(null);
|
|
45712
|
+
const [lastTurnDurationLabel, setLastTurnDurationLabel] = useState25(null);
|
|
45713
|
+
const markTurnStarted = useCallback11(() => {
|
|
45502
45714
|
const t = Date.now();
|
|
45503
45715
|
turnStartedAtRef.current = t;
|
|
45504
45716
|
setProcessingStartMs(t);
|
|
45505
45717
|
setLastTurnDurationLabel(null);
|
|
45506
45718
|
}, []);
|
|
45507
|
-
const handleWorkComplete =
|
|
45719
|
+
const handleWorkComplete = useCallback11((elapsedMs) => {
|
|
45508
45720
|
const label = formatTurnDurationMs(elapsedMs);
|
|
45509
45721
|
setLastTurnDurationLabel(label);
|
|
45510
45722
|
}, []);
|
|
45511
|
-
const lastReasoningTextRef =
|
|
45512
|
-
const streamedReasoningTextRef =
|
|
45513
|
-
const activeReasoningHistoryIdRef =
|
|
45514
|
-
const lastStreamAssistantKeyRef =
|
|
45515
|
-
const appendExpandPreviewToHistory =
|
|
45723
|
+
const lastReasoningTextRef = useRef13(null);
|
|
45724
|
+
const streamedReasoningTextRef = useRef13("");
|
|
45725
|
+
const activeReasoningHistoryIdRef = useRef13(null);
|
|
45726
|
+
const lastStreamAssistantKeyRef = useRef13(null);
|
|
45727
|
+
const appendExpandPreviewToHistory = useCallback11(() => {
|
|
45516
45728
|
const p = peekLatestExpandable();
|
|
45517
45729
|
setHistory((prev) => {
|
|
45518
45730
|
const id = nextHistoryId(prev);
|
|
@@ -45557,7 +45769,7 @@ var BlumaSessionComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
45557
45769
|
});
|
|
45558
45770
|
});
|
|
45559
45771
|
}, []);
|
|
45560
|
-
const handleInterrupt =
|
|
45772
|
+
const handleInterrupt = useCallback11(() => {
|
|
45561
45773
|
if (!isProcessing) return;
|
|
45562
45774
|
eventBus.emit("user_interrupt");
|
|
45563
45775
|
turnStartedAtRef.current = null;
|
|
@@ -45574,7 +45786,7 @@ var BlumaSessionComponent = ({ eventBus, sessionId, cliVersion }) => {
|
|
|
45574
45786
|
];
|
|
45575
45787
|
});
|
|
45576
45788
|
}, [isProcessing]);
|
|
45577
|
-
const handleSubmit =
|
|
45789
|
+
const handleSubmit = useCallback11(
|
|
45578
45790
|
(text) => {
|
|
45579
45791
|
if (!text || !agentInstance.current) return;
|
|
45580
45792
|
const trimmedForSlash = text.trim();
|
|
@@ -45823,7 +46035,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
45823
46035
|
[isProcessing, markTurnStarted]
|
|
45824
46036
|
);
|
|
45825
46037
|
const { snapshot: queuedMessages, clear: clearQueue } = useMessageQueue_default();
|
|
45826
|
-
const isAgentIdle =
|
|
46038
|
+
const isAgentIdle = useMemo8(
|
|
45827
46039
|
() => !isProcessing && !pendingConfirmation && !pendingAskUserQuestions?.length && !isInitAgentActive,
|
|
45828
46040
|
[isProcessing, pendingConfirmation, pendingAskUserQuestions, isInitAgentActive]
|
|
45829
46041
|
);
|
|
@@ -45855,7 +46067,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
45855
46067
|
subscription.off("clear_queue", handleClearQueue);
|
|
45856
46068
|
};
|
|
45857
46069
|
}, [queuedMessages.length, clearQueue]);
|
|
45858
|
-
const handleConfirmation =
|
|
46070
|
+
const handleConfirmation = useCallback11(
|
|
45859
46071
|
async (decision, toolCalls, opts) => {
|
|
45860
46072
|
if (!agentInstance.current) return;
|
|
45861
46073
|
setPendingConfirmation(null);
|
|
@@ -45878,7 +46090,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
45878
46090
|
},
|
|
45879
46091
|
[]
|
|
45880
46092
|
);
|
|
45881
|
-
const appendStreamedReasoning =
|
|
46093
|
+
const appendStreamedReasoning = useCallback11((reasoning) => {
|
|
45882
46094
|
const r = String(reasoning ?? "").trim();
|
|
45883
46095
|
if (!r) return;
|
|
45884
46096
|
setHistory((prev) => {
|
|
@@ -45896,7 +46108,7 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
45896
46108
|
return [...prev, { id, component }];
|
|
45897
46109
|
});
|
|
45898
46110
|
}, []);
|
|
45899
|
-
const appendStreamedAssistant =
|
|
46111
|
+
const appendStreamedAssistant = useCallback11((content) => {
|
|
45900
46112
|
const t = String(content ?? "").trim();
|
|
45901
46113
|
if (!t) return;
|
|
45902
46114
|
const key = reasoningDedupeKey(t);
|
|
@@ -45922,9 +46134,9 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
45922
46134
|
return [...prev, { id, component: nextComponent }];
|
|
45923
46135
|
});
|
|
45924
46136
|
}, []);
|
|
45925
|
-
const handleConfirmationRef =
|
|
46137
|
+
const handleConfirmationRef = useRef13(handleConfirmation);
|
|
45926
46138
|
handleConfirmationRef.current = handleConfirmation;
|
|
45927
|
-
const sessionIdRef =
|
|
46139
|
+
const sessionIdRef = useRef13(sessionId);
|
|
45928
46140
|
sessionIdRef.current = sessionId;
|
|
45929
46141
|
useEffect22(() => {
|
|
45930
46142
|
const initializeAgent = async () => {
|
|
@@ -46217,17 +46429,17 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
46217
46429
|
eventBus.off("backend_message", handleBackendMessage);
|
|
46218
46430
|
};
|
|
46219
46431
|
}, [eventBus, handleConfirmation]);
|
|
46220
|
-
const handleAnswerQuestion =
|
|
46432
|
+
const handleAnswerQuestion = useCallback11((answerJson) => {
|
|
46221
46433
|
setPendingAskUserQuestions(null);
|
|
46222
46434
|
eventBus.emit("ask_user_question_answer", { answer: answerJson });
|
|
46223
46435
|
}, [eventBus]);
|
|
46224
|
-
const handleCancelQuestion =
|
|
46436
|
+
const handleCancelQuestion = useCallback11(() => {
|
|
46225
46437
|
setPendingAskUserQuestions(null);
|
|
46226
46438
|
eventBus.emit("ask_user_question_answer", {
|
|
46227
46439
|
answer: JSON.stringify({ success: false, cancelled: true })
|
|
46228
46440
|
});
|
|
46229
46441
|
}, [eventBus]);
|
|
46230
|
-
const handleDecision =
|
|
46442
|
+
const handleDecision = useCallback11(async (decision) => {
|
|
46231
46443
|
if (!pendingConfirmation || pendingConfirmation.length === 0) return;
|
|
46232
46444
|
const [currentToolCall, ...remainingToolCalls] = pendingConfirmation;
|
|
46233
46445
|
if (!currentToolCall) return;
|
|
@@ -46244,8 +46456,33 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
46244
46456
|
setIsProcessing(false);
|
|
46245
46457
|
}
|
|
46246
46458
|
}, [handleConfirmation, pendingConfirmation]);
|
|
46247
|
-
const
|
|
46248
|
-
|
|
46459
|
+
const scrollBoxRef = useRef13(null);
|
|
46460
|
+
const { columns } = useTerminalSize();
|
|
46461
|
+
const historyKeys = useMemo8(
|
|
46462
|
+
() => history.map((item) => String(item.id)),
|
|
46463
|
+
[history.length, history.length > 0 ? history[history.length - 1].id : 0]
|
|
46464
|
+
);
|
|
46465
|
+
const { range, topSpacer, bottomSpacer, measureRef } = useVirtualScroll(
|
|
46466
|
+
scrollBoxRef,
|
|
46467
|
+
historyKeys,
|
|
46468
|
+
columns
|
|
46469
|
+
);
|
|
46470
|
+
const [lo, hi] = range;
|
|
46471
|
+
const mountedItems = useMemo8(() => {
|
|
46472
|
+
return history.slice(lo, hi);
|
|
46473
|
+
}, [history, lo, hi]);
|
|
46474
|
+
const transcript = useMemo8(() => /* @__PURE__ */ jsx104(Fragment19, { children: /* @__PURE__ */ jsx104(ScrollBox_default, { ref: scrollBoxRef, stickyScroll: true, flexDirection: "column", flexGrow: 1, minHeight: 0, width: "100%", children: /* @__PURE__ */ jsxs85(Box_default, { flexDirection: "column", minHeight: 0, width: "100%", children: [
|
|
46475
|
+
topSpacer > 0 && /* @__PURE__ */ jsx104(Box_default, { height: topSpacer }),
|
|
46476
|
+
mountedItems.map((item) => /* @__PURE__ */ jsx104(
|
|
46477
|
+
Box_default,
|
|
46478
|
+
{
|
|
46479
|
+
flexDirection: "column",
|
|
46480
|
+
ref: measureRef(String(item.id)),
|
|
46481
|
+
children: item.component
|
|
46482
|
+
},
|
|
46483
|
+
item.id
|
|
46484
|
+
)),
|
|
46485
|
+
bottomSpacer > 0 && /* @__PURE__ */ jsx104(Box_default, { height: bottomSpacer }),
|
|
46249
46486
|
/* @__PURE__ */ jsx104(
|
|
46250
46487
|
StreamingText,
|
|
46251
46488
|
{
|
|
@@ -46258,10 +46495,13 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
46258
46495
|
appendStreamedAssistant,
|
|
46259
46496
|
appendStreamedReasoning,
|
|
46260
46497
|
eventBus,
|
|
46261
|
-
|
|
46498
|
+
mountedItems,
|
|
46499
|
+
topSpacer,
|
|
46500
|
+
bottomSpacer,
|
|
46501
|
+
measureRef,
|
|
46262
46502
|
liveToolName
|
|
46263
46503
|
]);
|
|
46264
|
-
const bottomDock =
|
|
46504
|
+
const bottomDock = useMemo8(() => /* @__PURE__ */ jsx104(
|
|
46265
46505
|
BlumaBottomDock,
|
|
46266
46506
|
{
|
|
46267
46507
|
eventBus,
|
|
@@ -46311,9 +46551,9 @@ Please use command_status to check the result and report back to the user.`;
|
|
|
46311
46551
|
statusMessage,
|
|
46312
46552
|
workdir
|
|
46313
46553
|
]);
|
|
46314
|
-
const header =
|
|
46315
|
-
const overlay =
|
|
46316
|
-
const floating =
|
|
46554
|
+
const header = useMemo8(() => /* @__PURE__ */ jsx104(Header, { sessionId, workdir, cliVersion }), [cliVersion, sessionId, workdir]);
|
|
46555
|
+
const overlay = useMemo8(() => /* @__PURE__ */ jsx104(BlumaWorkersOverlay, { sessionId }), [sessionId]);
|
|
46556
|
+
const floating = useMemo8(() => /* @__PURE__ */ jsx104(CoordinatorTaskPanel, {}), []);
|
|
46317
46557
|
return /* @__PURE__ */ jsx104(
|
|
46318
46558
|
BlumaViewport,
|
|
46319
46559
|
{
|
|
@@ -46497,7 +46737,7 @@ import React39 from "react";
|
|
|
46497
46737
|
init_agent_session_paths();
|
|
46498
46738
|
|
|
46499
46739
|
// src/app/ui/components/SessionResumePicker.tsx
|
|
46500
|
-
import { memo as memo26, useCallback as
|
|
46740
|
+
import { memo as memo26, useCallback as useCallback12, useEffect as useEffect23, useMemo as useMemo9, useState as useState26 } from "react";
|
|
46501
46741
|
|
|
46502
46742
|
// src/app/agent/session_manager/session_resume_browser.ts
|
|
46503
46743
|
init_bluma_app_dir();
|
|
@@ -46644,12 +46884,12 @@ var SessionResumePickerComponent = ({
|
|
|
46644
46884
|
4,
|
|
46645
46885
|
Math.min(VISIBLE_DEFAULT, (stdout?.rows ?? 24) - 14)
|
|
46646
46886
|
);
|
|
46647
|
-
const [cwd2, setCwd] =
|
|
46648
|
-
const [entries, setEntries] =
|
|
46649
|
-
const [loading, setLoading] =
|
|
46650
|
-
const [selectedIndex, setSelectedIndex] =
|
|
46651
|
-
const [scrollTop, setScrollTop] =
|
|
46652
|
-
const reload =
|
|
46887
|
+
const [cwd2, setCwd] = useState26("");
|
|
46888
|
+
const [entries, setEntries] = useState26([]);
|
|
46889
|
+
const [loading, setLoading] = useState26(true);
|
|
46890
|
+
const [selectedIndex, setSelectedIndex] = useState26(0);
|
|
46891
|
+
const [scrollTop, setScrollTop] = useState26(0);
|
|
46892
|
+
const reload = useCallback12(async (rel) => {
|
|
46653
46893
|
setLoading(true);
|
|
46654
46894
|
try {
|
|
46655
46895
|
const list = await listSessionBrowserEntries(rel);
|
|
@@ -46675,7 +46915,7 @@ var SessionResumePickerComponent = ({
|
|
|
46675
46915
|
setScrollTop(selectedIndex - visibleCount + 1);
|
|
46676
46916
|
}
|
|
46677
46917
|
}, [selectedIndex, scrollTop, visibleCount]);
|
|
46678
|
-
const windowItems =
|
|
46918
|
+
const windowItems = useMemo9(
|
|
46679
46919
|
() => entries.slice(scrollTop, scrollTop + visibleCount),
|
|
46680
46920
|
[entries, scrollTop, visibleCount]
|
|
46681
46921
|
);
|