@mindstudio-ai/remy 0.1.245 → 0.1.246

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.
@@ -19,7 +19,10 @@
19
19
  * page size (default 500, hard cap 2000). Response: {event:"history",
20
20
  * messages, startIndex, endIndex, totalMessageCount, ...}. Walk backward by
21
21
  * passing the previous response's `startIndex` as the next `before`. When
22
- * `startIndex === 0`, no older messages remain.
22
+ * `startIndex === 0`, no older messages remain. Indices are GLOBAL — they span
23
+ * the sealed session archives followed by the live tail (see getHistoryPage in
24
+ * session.ts), so scrollback continues past a rotation to the conversation
25
+ * start, not just to the start of the live (post-rotation) array.
23
26
  */
24
27
  interface HeadlessOptions {
25
28
  apiKey?: string;
package/dist/headless.js CHANGED
@@ -6309,6 +6309,14 @@ var ARCHIVE_DIR = ".logs/sessions";
6309
6309
  var ROTATE_THRESHOLD_BYTES = 32 * 1024 * 1024;
6310
6310
  var RETAIN_TAIL_BYTES = 16 * 1024 * 1024;
6311
6311
  var ARCHIVE_RETENTION_BYTES = 64 * 1024 * 1024;
6312
+ var ARCHIVE_NAME_RE = /^(cleared|rotated)-.*\.json$/;
6313
+ var archiveSortKey = (name) => name.replace(/^(cleared|rotated)-/, "");
6314
+ var ARCHIVE_COUNT_RE = /\.c(\d+)\.json$/;
6315
+ var HISTORY_DEFAULT_LIMIT = 500;
6316
+ var HISTORY_MAX_LIMIT = 2e3;
6317
+ var archiveCountCache = /* @__PURE__ */ new Map();
6318
+ var archiveMsgCache = /* @__PURE__ */ new Map();
6319
+ var ARCHIVE_MSG_CACHE_MAX = 3;
6312
6320
  function loadSession(state) {
6313
6321
  pruneArchives();
6314
6322
  try {
@@ -6387,31 +6395,34 @@ function buildPayload(state) {
6387
6395
  function archiveMessages(messages, label, models) {
6388
6396
  fs21.mkdirSync(ARCHIVE_DIR, { recursive: true });
6389
6397
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
6390
- let dest = path11.join(ARCHIVE_DIR, `${label}-${ts}.json`);
6398
+ const count = messages.length;
6399
+ let dest = path11.join(ARCHIVE_DIR, `${label}-${ts}.c${count}.json`);
6391
6400
  let n = 1;
6392
6401
  while (fs21.existsSync(dest)) {
6393
- dest = path11.join(ARCHIVE_DIR, `${label}-${ts}-${n++}.json`);
6402
+ dest = path11.join(ARCHIVE_DIR, `${label}-${ts}-${n++}.c${count}.json`);
6394
6403
  }
6395
6404
  const payload = { messages };
6396
6405
  if (models && Object.keys(models).length > 0) {
6397
6406
  payload.models = models;
6398
6407
  }
6399
6408
  fs21.writeFileSync(dest, JSON.stringify(payload), "utf-8");
6400
- log9.info("Session archived", { label, dest, messageCount: messages.length });
6409
+ archiveCountCache.set(path11.basename(dest), count);
6410
+ log9.info("Session archived", { label, dest, messageCount: count });
6401
6411
  pruneArchives();
6402
6412
  return dest;
6403
6413
  }
6404
6414
  function pruneArchives() {
6405
6415
  try {
6406
- const entries = fs21.readdirSync(ARCHIVE_DIR).filter((name) => /^(cleared|rotated)-.*\.json$/.test(name));
6416
+ const entries = fs21.readdirSync(ARCHIVE_DIR).filter((name) => ARCHIVE_NAME_RE.test(name));
6407
6417
  if (entries.length <= 1) {
6408
6418
  return;
6409
6419
  }
6410
- const sortKey = (name) => name.replace(/^(cleared|rotated)-/, "");
6411
6420
  const archives = entries.map((name) => ({
6412
6421
  name,
6413
6422
  size: fs21.statSync(path11.join(ARCHIVE_DIR, name)).size
6414
- })).sort((a, b) => sortKey(b.name).localeCompare(sortKey(a.name)));
6423
+ })).sort(
6424
+ (a, b) => archiveSortKey(b.name).localeCompare(archiveSortKey(a.name))
6425
+ );
6415
6426
  let kept = 0;
6416
6427
  let cut = archives.length;
6417
6428
  for (let i = 0; i < archives.length; i++) {
@@ -6442,6 +6453,129 @@ function pruneArchives() {
6442
6453
  } catch {
6443
6454
  }
6444
6455
  }
6456
+ function parseArchive(name) {
6457
+ const cached3 = archiveMsgCache.get(name);
6458
+ if (cached3) {
6459
+ archiveMsgCache.delete(name);
6460
+ archiveMsgCache.set(name, cached3);
6461
+ return cached3;
6462
+ }
6463
+ try {
6464
+ const raw = fs21.readFileSync(path11.join(ARCHIVE_DIR, name), "utf-8");
6465
+ const data = JSON.parse(raw);
6466
+ const messages = Array.isArray(data?.messages) ? data.messages : [];
6467
+ archiveCountCache.set(name, messages.length);
6468
+ archiveMsgCache.set(name, messages);
6469
+ while (archiveMsgCache.size > ARCHIVE_MSG_CACHE_MAX) {
6470
+ const oldest = archiveMsgCache.keys().next().value;
6471
+ if (oldest === void 0) {
6472
+ break;
6473
+ }
6474
+ archiveMsgCache.delete(oldest);
6475
+ }
6476
+ return messages;
6477
+ } catch (err) {
6478
+ log9.warn("Session archive unreadable", { name, error: err?.message });
6479
+ return null;
6480
+ }
6481
+ }
6482
+ function archiveCount(name) {
6483
+ const cached3 = archiveCountCache.get(name);
6484
+ if (cached3 !== void 0) {
6485
+ return cached3;
6486
+ }
6487
+ const m = ARCHIVE_COUNT_RE.exec(name);
6488
+ if (m) {
6489
+ const n = Number(m[1]);
6490
+ archiveCountCache.set(name, n);
6491
+ return n;
6492
+ }
6493
+ const msgs = parseArchive(name);
6494
+ return msgs ? msgs.length : null;
6495
+ }
6496
+ function readArchiveMessages(name) {
6497
+ return parseArchive(name) ?? [];
6498
+ }
6499
+ function listConversationArchives() {
6500
+ let names;
6501
+ try {
6502
+ names = fs21.readdirSync(ARCHIVE_DIR).filter((n) => ARCHIVE_NAME_RE.test(n));
6503
+ } catch {
6504
+ return { slots: [], archivedCount: 0 };
6505
+ }
6506
+ let maxClearedKey = null;
6507
+ for (const name of names) {
6508
+ if (name.startsWith("cleared-")) {
6509
+ const key = archiveSortKey(name);
6510
+ if (maxClearedKey === null || key > maxClearedKey) {
6511
+ maxClearedKey = key;
6512
+ }
6513
+ }
6514
+ }
6515
+ const rotated = names.filter((n) => n.startsWith("rotated-")).filter((n) => maxClearedKey === null || archiveSortKey(n) > maxClearedKey).sort((a, b) => archiveSortKey(a).localeCompare(archiveSortKey(b)));
6516
+ const slots = [];
6517
+ let offset = 0;
6518
+ for (const name of rotated) {
6519
+ const count = archiveCount(name);
6520
+ if (count === null || count <= 0) {
6521
+ continue;
6522
+ }
6523
+ slots.push({ name, count, offset });
6524
+ offset += count;
6525
+ }
6526
+ return { slots, archivedCount: offset };
6527
+ }
6528
+ function getHistoryPage(state, opts) {
6529
+ const { slots, archivedCount } = listConversationArchives();
6530
+ const liveLen = state.messages.length;
6531
+ const total = archivedCount + liveLen;
6532
+ const rawLimit = opts?.limit;
6533
+ const limit = typeof rawLimit === "number" && Number.isFinite(rawLimit) ? Math.min(Math.max(1, rawLimit | 0), HISTORY_MAX_LIMIT) : HISTORY_DEFAULT_LIMIT;
6534
+ const rawBefore = opts?.before;
6535
+ const before = typeof rawBefore === "number" && Number.isFinite(rawBefore) ? Math.max(0, Math.min(rawBefore | 0, total)) : total;
6536
+ const peekGlobal = (i) => {
6537
+ if (i >= archivedCount) {
6538
+ return state.messages[i - archivedCount];
6539
+ }
6540
+ for (const slot of slots) {
6541
+ if (i < slot.offset + slot.count) {
6542
+ return readArchiveMessages(slot.name)[i - slot.offset];
6543
+ }
6544
+ }
6545
+ return void 0;
6546
+ };
6547
+ let startIndex = Math.max(0, before - limit);
6548
+ while (startIndex > 0) {
6549
+ const msg = peekGlobal(startIndex);
6550
+ if (msg && msg.role === "user" && msg.toolCallId) {
6551
+ startIndex--;
6552
+ } else {
6553
+ break;
6554
+ }
6555
+ }
6556
+ const endIndex = before;
6557
+ const messages = [];
6558
+ for (const slot of slots) {
6559
+ const slotEnd = slot.offset + slot.count;
6560
+ if (slotEnd <= startIndex || slot.offset >= endIndex) {
6561
+ continue;
6562
+ }
6563
+ const from = Math.max(startIndex, slot.offset) - slot.offset;
6564
+ const to = Math.min(endIndex, slotEnd) - slot.offset;
6565
+ const msgs = readArchiveMessages(slot.name);
6566
+ for (let i = from; i < to; i++) {
6567
+ messages.push(msgs[i]);
6568
+ }
6569
+ }
6570
+ if (endIndex > archivedCount) {
6571
+ const from = Math.max(startIndex, archivedCount) - archivedCount;
6572
+ const to = endIndex - archivedCount;
6573
+ for (let i = from; i < to; i++) {
6574
+ messages.push(state.messages[i]);
6575
+ }
6576
+ }
6577
+ return { messages, startIndex, endIndex, totalMessageCount: total };
6578
+ }
6445
6579
  function rotate(state) {
6446
6580
  const messages = state.messages;
6447
6581
  if (messages.length === 0) {
@@ -7979,8 +8113,6 @@ var USER_FACING_TOOLS = /* @__PURE__ */ new Set([
7979
8113
  "presentPublishPlan"
7980
8114
  ]);
7981
8115
  var FORCED_COMPACTION_THRESHOLD_TOKENS = 85e4;
7982
- var HISTORY_DEFAULT_LIMIT = 500;
7983
- var HISTORY_MAX_LIMIT = 2e3;
7984
8116
  var HeadlessSession = class {
7985
8117
  // Configuration
7986
8118
  opts;
@@ -8726,30 +8858,24 @@ var HeadlessSession = class {
8726
8858
  }
8727
8859
  if (action === "get_history") {
8728
8860
  this.applyPendingBlockUpdates();
8729
- const total = this.state.messages.length;
8730
- const rawLimit = parsed.limit;
8731
- const limit = typeof rawLimit === "number" && Number.isFinite(rawLimit) ? Math.min(Math.max(1, rawLimit | 0), HISTORY_MAX_LIMIT) : HISTORY_DEFAULT_LIMIT;
8732
- const rawBefore = parsed.before;
8733
- const before = typeof rawBefore === "number" && Number.isFinite(rawBefore) ? Math.max(0, Math.min(rawBefore | 0, total)) : total;
8734
- let startIndex = Math.max(0, before - limit);
8735
- while (startIndex > 0 && this.state.messages[startIndex].role === "user" && this.state.messages[startIndex].toolCallId) {
8736
- startIndex--;
8737
- }
8738
- const endIndex = before;
8861
+ const page = getHistoryPage(this.state, {
8862
+ ...typeof parsed.before === "number" ? { before: parsed.before } : {},
8863
+ ...typeof parsed.limit === "number" ? { limit: parsed.limit } : {}
8864
+ });
8739
8865
  log15.info("History response", {
8740
8866
  requestId,
8741
- startIndex,
8742
- endIndex,
8743
- count: endIndex - startIndex,
8744
- totalMessageCount: total,
8745
- beforeParam: rawBefore,
8746
- limitParam: rawLimit
8867
+ startIndex: page.startIndex,
8868
+ endIndex: page.endIndex,
8869
+ count: page.endIndex - page.startIndex,
8870
+ totalMessageCount: page.totalMessageCount,
8871
+ beforeParam: parsed.before,
8872
+ limitParam: parsed.limit
8747
8873
  });
8748
8874
  this.dispatchSimple(requestId, "history", () => ({
8749
- messages: this.state.messages.slice(startIndex, endIndex),
8750
- startIndex,
8751
- endIndex,
8752
- totalMessageCount: total,
8875
+ messages: page.messages,
8876
+ startIndex: page.startIndex,
8877
+ endIndex: page.endIndex,
8878
+ totalMessageCount: page.totalMessageCount,
8753
8879
  running: this.running,
8754
8880
  ...this.running && this.currentRequestId ? { currentRequestId: this.currentRequestId } : {},
8755
8881
  ...this.state.models && { models: this.state.models },
package/dist/index.js CHANGED
@@ -2314,31 +2314,34 @@ function buildPayload(state) {
2314
2314
  function archiveMessages(messages, label, models) {
2315
2315
  fs10.mkdirSync(ARCHIVE_DIR, { recursive: true });
2316
2316
  const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
2317
- let dest = path4.join(ARCHIVE_DIR, `${label}-${ts}.json`);
2317
+ const count = messages.length;
2318
+ let dest = path4.join(ARCHIVE_DIR, `${label}-${ts}.c${count}.json`);
2318
2319
  let n = 1;
2319
2320
  while (fs10.existsSync(dest)) {
2320
- dest = path4.join(ARCHIVE_DIR, `${label}-${ts}-${n++}.json`);
2321
+ dest = path4.join(ARCHIVE_DIR, `${label}-${ts}-${n++}.c${count}.json`);
2321
2322
  }
2322
2323
  const payload = { messages };
2323
2324
  if (models && Object.keys(models).length > 0) {
2324
2325
  payload.models = models;
2325
2326
  }
2326
2327
  fs10.writeFileSync(dest, JSON.stringify(payload), "utf-8");
2327
- log3.info("Session archived", { label, dest, messageCount: messages.length });
2328
+ archiveCountCache.set(path4.basename(dest), count);
2329
+ log3.info("Session archived", { label, dest, messageCount: count });
2328
2330
  pruneArchives();
2329
2331
  return dest;
2330
2332
  }
2331
2333
  function pruneArchives() {
2332
2334
  try {
2333
- const entries = fs10.readdirSync(ARCHIVE_DIR).filter((name) => /^(cleared|rotated)-.*\.json$/.test(name));
2335
+ const entries = fs10.readdirSync(ARCHIVE_DIR).filter((name) => ARCHIVE_NAME_RE.test(name));
2334
2336
  if (entries.length <= 1) {
2335
2337
  return;
2336
2338
  }
2337
- const sortKey = (name) => name.replace(/^(cleared|rotated)-/, "");
2338
2339
  const archives = entries.map((name) => ({
2339
2340
  name,
2340
2341
  size: fs10.statSync(path4.join(ARCHIVE_DIR, name)).size
2341
- })).sort((a, b) => sortKey(b.name).localeCompare(sortKey(a.name)));
2342
+ })).sort(
2343
+ (a, b) => archiveSortKey(b.name).localeCompare(archiveSortKey(a.name))
2344
+ );
2342
2345
  let kept = 0;
2343
2346
  let cut = archives.length;
2344
2347
  for (let i = 0; i < archives.length; i++) {
@@ -2369,6 +2372,129 @@ function pruneArchives() {
2369
2372
  } catch {
2370
2373
  }
2371
2374
  }
2375
+ function parseArchive(name) {
2376
+ const cached3 = archiveMsgCache.get(name);
2377
+ if (cached3) {
2378
+ archiveMsgCache.delete(name);
2379
+ archiveMsgCache.set(name, cached3);
2380
+ return cached3;
2381
+ }
2382
+ try {
2383
+ const raw = fs10.readFileSync(path4.join(ARCHIVE_DIR, name), "utf-8");
2384
+ const data = JSON.parse(raw);
2385
+ const messages = Array.isArray(data?.messages) ? data.messages : [];
2386
+ archiveCountCache.set(name, messages.length);
2387
+ archiveMsgCache.set(name, messages);
2388
+ while (archiveMsgCache.size > ARCHIVE_MSG_CACHE_MAX) {
2389
+ const oldest = archiveMsgCache.keys().next().value;
2390
+ if (oldest === void 0) {
2391
+ break;
2392
+ }
2393
+ archiveMsgCache.delete(oldest);
2394
+ }
2395
+ return messages;
2396
+ } catch (err) {
2397
+ log3.warn("Session archive unreadable", { name, error: err?.message });
2398
+ return null;
2399
+ }
2400
+ }
2401
+ function archiveCount(name) {
2402
+ const cached3 = archiveCountCache.get(name);
2403
+ if (cached3 !== void 0) {
2404
+ return cached3;
2405
+ }
2406
+ const m = ARCHIVE_COUNT_RE.exec(name);
2407
+ if (m) {
2408
+ const n = Number(m[1]);
2409
+ archiveCountCache.set(name, n);
2410
+ return n;
2411
+ }
2412
+ const msgs = parseArchive(name);
2413
+ return msgs ? msgs.length : null;
2414
+ }
2415
+ function readArchiveMessages(name) {
2416
+ return parseArchive(name) ?? [];
2417
+ }
2418
+ function listConversationArchives() {
2419
+ let names;
2420
+ try {
2421
+ names = fs10.readdirSync(ARCHIVE_DIR).filter((n) => ARCHIVE_NAME_RE.test(n));
2422
+ } catch {
2423
+ return { slots: [], archivedCount: 0 };
2424
+ }
2425
+ let maxClearedKey = null;
2426
+ for (const name of names) {
2427
+ if (name.startsWith("cleared-")) {
2428
+ const key = archiveSortKey(name);
2429
+ if (maxClearedKey === null || key > maxClearedKey) {
2430
+ maxClearedKey = key;
2431
+ }
2432
+ }
2433
+ }
2434
+ const rotated = names.filter((n) => n.startsWith("rotated-")).filter((n) => maxClearedKey === null || archiveSortKey(n) > maxClearedKey).sort((a, b) => archiveSortKey(a).localeCompare(archiveSortKey(b)));
2435
+ const slots = [];
2436
+ let offset = 0;
2437
+ for (const name of rotated) {
2438
+ const count = archiveCount(name);
2439
+ if (count === null || count <= 0) {
2440
+ continue;
2441
+ }
2442
+ slots.push({ name, count, offset });
2443
+ offset += count;
2444
+ }
2445
+ return { slots, archivedCount: offset };
2446
+ }
2447
+ function getHistoryPage(state, opts) {
2448
+ const { slots, archivedCount } = listConversationArchives();
2449
+ const liveLen = state.messages.length;
2450
+ const total = archivedCount + liveLen;
2451
+ const rawLimit = opts?.limit;
2452
+ const limit = typeof rawLimit === "number" && Number.isFinite(rawLimit) ? Math.min(Math.max(1, rawLimit | 0), HISTORY_MAX_LIMIT) : HISTORY_DEFAULT_LIMIT;
2453
+ const rawBefore = opts?.before;
2454
+ const before = typeof rawBefore === "number" && Number.isFinite(rawBefore) ? Math.max(0, Math.min(rawBefore | 0, total)) : total;
2455
+ const peekGlobal = (i) => {
2456
+ if (i >= archivedCount) {
2457
+ return state.messages[i - archivedCount];
2458
+ }
2459
+ for (const slot of slots) {
2460
+ if (i < slot.offset + slot.count) {
2461
+ return readArchiveMessages(slot.name)[i - slot.offset];
2462
+ }
2463
+ }
2464
+ return void 0;
2465
+ };
2466
+ let startIndex = Math.max(0, before - limit);
2467
+ while (startIndex > 0) {
2468
+ const msg = peekGlobal(startIndex);
2469
+ if (msg && msg.role === "user" && msg.toolCallId) {
2470
+ startIndex--;
2471
+ } else {
2472
+ break;
2473
+ }
2474
+ }
2475
+ const endIndex = before;
2476
+ const messages = [];
2477
+ for (const slot of slots) {
2478
+ const slotEnd = slot.offset + slot.count;
2479
+ if (slotEnd <= startIndex || slot.offset >= endIndex) {
2480
+ continue;
2481
+ }
2482
+ const from = Math.max(startIndex, slot.offset) - slot.offset;
2483
+ const to = Math.min(endIndex, slotEnd) - slot.offset;
2484
+ const msgs = readArchiveMessages(slot.name);
2485
+ for (let i = from; i < to; i++) {
2486
+ messages.push(msgs[i]);
2487
+ }
2488
+ }
2489
+ if (endIndex > archivedCount) {
2490
+ const from = Math.max(startIndex, archivedCount) - archivedCount;
2491
+ const to = endIndex - archivedCount;
2492
+ for (let i = from; i < to; i++) {
2493
+ messages.push(state.messages[i]);
2494
+ }
2495
+ }
2496
+ return { messages, startIndex, endIndex, totalMessageCount: total };
2497
+ }
2372
2498
  function rotate(state) {
2373
2499
  const messages = state.messages;
2374
2500
  if (messages.length === 0) {
@@ -2428,7 +2554,7 @@ function clearSession(state) {
2428
2554
  });
2429
2555
  }
2430
2556
  }
2431
- var log3, SESSION_FILE, ARCHIVE_DIR, ROTATE_THRESHOLD_BYTES, RETAIN_TAIL_BYTES, ARCHIVE_RETENTION_BYTES;
2557
+ var log3, SESSION_FILE, ARCHIVE_DIR, ROTATE_THRESHOLD_BYTES, RETAIN_TAIL_BYTES, ARCHIVE_RETENTION_BYTES, ARCHIVE_NAME_RE, archiveSortKey, ARCHIVE_COUNT_RE, HISTORY_DEFAULT_LIMIT, HISTORY_MAX_LIMIT, archiveCountCache, archiveMsgCache, ARCHIVE_MSG_CACHE_MAX;
2432
2558
  var init_session = __esm({
2433
2559
  "src/session.ts"() {
2434
2560
  "use strict";
@@ -2442,6 +2568,14 @@ var init_session = __esm({
2442
2568
  ROTATE_THRESHOLD_BYTES = 32 * 1024 * 1024;
2443
2569
  RETAIN_TAIL_BYTES = 16 * 1024 * 1024;
2444
2570
  ARCHIVE_RETENTION_BYTES = 64 * 1024 * 1024;
2571
+ ARCHIVE_NAME_RE = /^(cleared|rotated)-.*\.json$/;
2572
+ archiveSortKey = (name) => name.replace(/^(cleared|rotated)-/, "");
2573
+ ARCHIVE_COUNT_RE = /\.c(\d+)\.json$/;
2574
+ HISTORY_DEFAULT_LIMIT = 500;
2575
+ HISTORY_MAX_LIMIT = 2e3;
2576
+ archiveCountCache = /* @__PURE__ */ new Map();
2577
+ archiveMsgCache = /* @__PURE__ */ new Map();
2578
+ ARCHIVE_MSG_CACHE_MAX = 3;
2445
2579
  }
2446
2580
  });
2447
2581
 
@@ -8839,7 +8973,7 @@ var headless_exports = {};
8839
8973
  __export(headless_exports, {
8840
8974
  HeadlessSession: () => HeadlessSession
8841
8975
  });
8842
- var log15, EXTERNAL_TOOL_TIMEOUT_MS, USER_FACING_TOOLS, FORCED_COMPACTION_THRESHOLD_TOKENS, HISTORY_DEFAULT_LIMIT, HISTORY_MAX_LIMIT, HeadlessSession;
8976
+ var log15, EXTERNAL_TOOL_TIMEOUT_MS, USER_FACING_TOOLS, FORCED_COMPACTION_THRESHOLD_TOKENS, HeadlessSession;
8843
8977
  var init_headless = __esm({
8844
8978
  "src/headless/index.ts"() {
8845
8979
  "use strict";
@@ -8868,8 +9002,6 @@ var init_headless = __esm({
8868
9002
  "presentPublishPlan"
8869
9003
  ]);
8870
9004
  FORCED_COMPACTION_THRESHOLD_TOKENS = 85e4;
8871
- HISTORY_DEFAULT_LIMIT = 500;
8872
- HISTORY_MAX_LIMIT = 2e3;
8873
9005
  HeadlessSession = class {
8874
9006
  // Configuration
8875
9007
  opts;
@@ -9615,30 +9747,24 @@ var init_headless = __esm({
9615
9747
  }
9616
9748
  if (action === "get_history") {
9617
9749
  this.applyPendingBlockUpdates();
9618
- const total = this.state.messages.length;
9619
- const rawLimit = parsed.limit;
9620
- const limit = typeof rawLimit === "number" && Number.isFinite(rawLimit) ? Math.min(Math.max(1, rawLimit | 0), HISTORY_MAX_LIMIT) : HISTORY_DEFAULT_LIMIT;
9621
- const rawBefore = parsed.before;
9622
- const before = typeof rawBefore === "number" && Number.isFinite(rawBefore) ? Math.max(0, Math.min(rawBefore | 0, total)) : total;
9623
- let startIndex = Math.max(0, before - limit);
9624
- while (startIndex > 0 && this.state.messages[startIndex].role === "user" && this.state.messages[startIndex].toolCallId) {
9625
- startIndex--;
9626
- }
9627
- const endIndex = before;
9750
+ const page = getHistoryPage(this.state, {
9751
+ ...typeof parsed.before === "number" ? { before: parsed.before } : {},
9752
+ ...typeof parsed.limit === "number" ? { limit: parsed.limit } : {}
9753
+ });
9628
9754
  log15.info("History response", {
9629
9755
  requestId,
9630
- startIndex,
9631
- endIndex,
9632
- count: endIndex - startIndex,
9633
- totalMessageCount: total,
9634
- beforeParam: rawBefore,
9635
- limitParam: rawLimit
9756
+ startIndex: page.startIndex,
9757
+ endIndex: page.endIndex,
9758
+ count: page.endIndex - page.startIndex,
9759
+ totalMessageCount: page.totalMessageCount,
9760
+ beforeParam: parsed.before,
9761
+ limitParam: parsed.limit
9636
9762
  });
9637
9763
  this.dispatchSimple(requestId, "history", () => ({
9638
- messages: this.state.messages.slice(startIndex, endIndex),
9639
- startIndex,
9640
- endIndex,
9641
- totalMessageCount: total,
9764
+ messages: page.messages,
9765
+ startIndex: page.startIndex,
9766
+ endIndex: page.endIndex,
9767
+ totalMessageCount: page.totalMessageCount,
9642
9768
  running: this.running,
9643
9769
  ...this.running && this.currentRequestId ? { currentRequestId: this.currentRequestId } : {},
9644
9770
  ...this.state.models && { models: this.state.models },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.245",
3
+ "version": "0.1.246",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",