@mindstudio-ai/remy 0.1.216 → 0.1.218

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/headless.js CHANGED
@@ -3632,7 +3632,8 @@ var ALLOWED_MODELS_BY_TYPE = {
3632
3632
  "gemini-3-flash",
3633
3633
  "gemini-3.5-flash",
3634
3634
  "grok-build-0.1",
3635
- "grok-4.5"
3635
+ "grok-4.5",
3636
+ "muse-spark-1.1"
3636
3637
  ]
3637
3638
  // vision: undefined — unconstrained
3638
3639
  // image_generation: undefined — unconstrained
@@ -5723,8 +5724,8 @@ async function compactConversation(messages, apiConfig, system, tools2, model) {
5723
5724
  log8.info("Compaction complete", { summaries: summaries.length });
5724
5725
  return checkpointMessages;
5725
5726
  }
5726
- function findSafeInsertionPoint(messages) {
5727
- let idx = messages.length;
5727
+ function findSafeInsertionPoint(messages, fromIndex = messages.length) {
5728
+ let idx = fromIndex;
5728
5729
  while (idx > 0) {
5729
5730
  const msg = messages[idx - 1];
5730
5731
  if (msg.role === "user" && msg.toolCallId) {
@@ -5733,7 +5734,7 @@ function findSafeInsertionPoint(messages) {
5733
5734
  break;
5734
5735
  }
5735
5736
  }
5736
- if (idx < messages.length && idx > 0) {
5737
+ if (idx < fromIndex && idx > 0) {
5737
5738
  const msg = messages[idx - 1];
5738
5739
  if (msg.role === "assistant" && Array.isArray(msg.content)) {
5739
5740
  const hasToolUse = msg.content.some(
@@ -6279,6 +6280,8 @@ import path11 from "path";
6279
6280
  var log12 = createLogger("session");
6280
6281
  var SESSION_FILE = ".remy-session.json";
6281
6282
  var ARCHIVE_DIR = ".logs/sessions";
6283
+ var ROTATE_THRESHOLD_BYTES = 32 * 1024 * 1024;
6284
+ var RETAIN_TAIL_BYTES = 16 * 1024 * 1024;
6282
6285
  function loadSession(state) {
6283
6286
  try {
6284
6287
  const raw = fs22.readFileSync(SESSION_FILE, "utf-8");
@@ -6334,36 +6337,86 @@ function sanitizeMessages(messages) {
6334
6337
  }
6335
6338
  return result;
6336
6339
  }
6340
+ function buildPayload(state) {
6341
+ const payload = { messages: state.messages };
6342
+ if (state.models && Object.keys(state.models).length > 0) {
6343
+ payload.models = state.models;
6344
+ }
6345
+ return payload;
6346
+ }
6347
+ function archiveMessages(messages, label, models) {
6348
+ fs22.mkdirSync(ARCHIVE_DIR, { recursive: true });
6349
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
6350
+ let dest = path11.join(ARCHIVE_DIR, `${label}-${ts}.json`);
6351
+ let n = 1;
6352
+ while (fs22.existsSync(dest)) {
6353
+ dest = path11.join(ARCHIVE_DIR, `${label}-${ts}-${n++}.json`);
6354
+ }
6355
+ const payload = { messages };
6356
+ if (models && Object.keys(models).length > 0) {
6357
+ payload.models = models;
6358
+ }
6359
+ fs22.writeFileSync(dest, JSON.stringify(payload), "utf-8");
6360
+ log12.info("Session archived", { label, dest, messageCount: messages.length });
6361
+ return dest;
6362
+ }
6363
+ function rotate(state) {
6364
+ const messages = state.messages;
6365
+ if (messages.length === 0) {
6366
+ return false;
6367
+ }
6368
+ let tailBytes = 0;
6369
+ let scrollbackStart = 0;
6370
+ for (let i = messages.length - 1; i >= 0; i--) {
6371
+ tailBytes += Buffer.byteLength(JSON.stringify(messages[i]), "utf-8") + 1;
6372
+ if (tailBytes >= RETAIN_TAIL_BYTES) {
6373
+ scrollbackStart = i;
6374
+ break;
6375
+ }
6376
+ }
6377
+ const checkpointIdx = findLastSummaryCheckpoint(messages, "conversation");
6378
+ let cut = checkpointIdx === -1 ? scrollbackStart : Math.min(scrollbackStart, checkpointIdx);
6379
+ cut = findSafeInsertionPoint(messages, cut);
6380
+ if (cut <= 0) {
6381
+ return false;
6382
+ }
6383
+ archiveMessages(messages.slice(0, cut), "rotated", state.models);
6384
+ state.messages = messages.slice(cut);
6385
+ log12.info("Session rotated", {
6386
+ archived: cut,
6387
+ retained: state.messages.length
6388
+ });
6389
+ return true;
6390
+ }
6337
6391
  function saveSession(state) {
6338
6392
  try {
6339
- const payload = { messages: state.messages };
6340
- if (state.models && Object.keys(state.models).length > 0) {
6341
- payload.models = state.models;
6393
+ let serialized = JSON.stringify(buildPayload(state));
6394
+ if (Buffer.byteLength(serialized, "utf-8") > ROTATE_THRESHOLD_BYTES && rotate(state)) {
6395
+ serialized = JSON.stringify(buildPayload(state));
6342
6396
  }
6343
- fs22.writeFileSync(SESSION_FILE, JSON.stringify(payload, null, 2), "utf-8");
6397
+ fs22.writeFileSync(SESSION_FILE, serialized, "utf-8");
6344
6398
  log12.info("Session saved", { messageCount: state.messages.length });
6345
6399
  } catch (err) {
6346
6400
  log12.warn("Session save failed", { error: err.message });
6347
6401
  }
6348
6402
  }
6349
6403
  function clearSession(state) {
6404
+ try {
6405
+ if (state.messages.length > 0) {
6406
+ archiveMessages(state.messages, "cleared", state.models);
6407
+ }
6408
+ } catch (err) {
6409
+ log12.warn("Session archive on clear failed", { error: err.message });
6410
+ }
6350
6411
  state.messages = [];
6351
6412
  try {
6352
6413
  if (fs22.existsSync(SESSION_FILE)) {
6353
- fs22.mkdirSync(ARCHIVE_DIR, { recursive: true });
6354
- const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
6355
- const dest = path11.join(ARCHIVE_DIR, `cleared-${ts}.json`);
6356
- fs22.renameSync(SESSION_FILE, dest);
6357
- log12.info("Session archived on clear", { dest });
6414
+ fs22.unlinkSync(SESSION_FILE);
6358
6415
  }
6359
6416
  } catch (err) {
6360
- log12.warn("Session archive on clear failed, deleting instead", {
6417
+ log12.warn("Session clear: could not remove live file", {
6361
6418
  error: err.message
6362
6419
  });
6363
- try {
6364
- fs22.unlinkSync(SESSION_FILE);
6365
- } catch {
6366
- }
6367
6420
  }
6368
6421
  }
6369
6422
 
package/dist/index.js CHANGED
@@ -1584,8 +1584,8 @@ async function compactConversation(messages, apiConfig, system, tools2, model) {
1584
1584
  log2.info("Compaction complete", { summaries: summaries.length });
1585
1585
  return checkpointMessages;
1586
1586
  }
1587
- function findSafeInsertionPoint(messages) {
1588
- let idx = messages.length;
1587
+ function findSafeInsertionPoint(messages, fromIndex = messages.length) {
1588
+ let idx = fromIndex;
1589
1589
  while (idx > 0) {
1590
1590
  const msg = messages[idx - 1];
1591
1591
  if (msg.role === "user" && msg.toolCallId) {
@@ -1594,7 +1594,7 @@ function findSafeInsertionPoint(messages) {
1594
1594
  break;
1595
1595
  }
1596
1596
  }
1597
- if (idx < messages.length && idx > 0) {
1597
+ if (idx < fromIndex && idx > 0) {
1598
1598
  const msg = messages[idx - 1];
1599
1599
  if (msg.role === "assistant" && Array.isArray(msg.content)) {
1600
1600
  const hasToolUse = msg.content.some(
@@ -2251,7 +2251,8 @@ var init_surfaces = __esm({
2251
2251
  "gemini-3-flash",
2252
2252
  "gemini-3.5-flash",
2253
2253
  "grok-build-0.1",
2254
- "grok-4.5"
2254
+ "grok-4.5",
2255
+ "muse-spark-1.1"
2255
2256
  ]
2256
2257
  // vision: undefined — unconstrained
2257
2258
  // image_generation: undefined — unconstrained
@@ -6706,46 +6707,100 @@ function sanitizeMessages(messages) {
6706
6707
  }
6707
6708
  return result;
6708
6709
  }
6710
+ function buildPayload(state) {
6711
+ const payload = { messages: state.messages };
6712
+ if (state.models && Object.keys(state.models).length > 0) {
6713
+ payload.models = state.models;
6714
+ }
6715
+ return payload;
6716
+ }
6717
+ function archiveMessages(messages, label, models) {
6718
+ fs20.mkdirSync(ARCHIVE_DIR, { recursive: true });
6719
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
6720
+ let dest = path9.join(ARCHIVE_DIR, `${label}-${ts}.json`);
6721
+ let n = 1;
6722
+ while (fs20.existsSync(dest)) {
6723
+ dest = path9.join(ARCHIVE_DIR, `${label}-${ts}-${n++}.json`);
6724
+ }
6725
+ const payload = { messages };
6726
+ if (models && Object.keys(models).length > 0) {
6727
+ payload.models = models;
6728
+ }
6729
+ fs20.writeFileSync(dest, JSON.stringify(payload), "utf-8");
6730
+ log9.info("Session archived", { label, dest, messageCount: messages.length });
6731
+ return dest;
6732
+ }
6733
+ function rotate(state) {
6734
+ const messages = state.messages;
6735
+ if (messages.length === 0) {
6736
+ return false;
6737
+ }
6738
+ let tailBytes = 0;
6739
+ let scrollbackStart = 0;
6740
+ for (let i = messages.length - 1; i >= 0; i--) {
6741
+ tailBytes += Buffer.byteLength(JSON.stringify(messages[i]), "utf-8") + 1;
6742
+ if (tailBytes >= RETAIN_TAIL_BYTES) {
6743
+ scrollbackStart = i;
6744
+ break;
6745
+ }
6746
+ }
6747
+ const checkpointIdx = findLastSummaryCheckpoint(messages, "conversation");
6748
+ let cut = checkpointIdx === -1 ? scrollbackStart : Math.min(scrollbackStart, checkpointIdx);
6749
+ cut = findSafeInsertionPoint(messages, cut);
6750
+ if (cut <= 0) {
6751
+ return false;
6752
+ }
6753
+ archiveMessages(messages.slice(0, cut), "rotated", state.models);
6754
+ state.messages = messages.slice(cut);
6755
+ log9.info("Session rotated", {
6756
+ archived: cut,
6757
+ retained: state.messages.length
6758
+ });
6759
+ return true;
6760
+ }
6709
6761
  function saveSession(state) {
6710
6762
  try {
6711
- const payload = { messages: state.messages };
6712
- if (state.models && Object.keys(state.models).length > 0) {
6713
- payload.models = state.models;
6763
+ let serialized = JSON.stringify(buildPayload(state));
6764
+ if (Buffer.byteLength(serialized, "utf-8") > ROTATE_THRESHOLD_BYTES && rotate(state)) {
6765
+ serialized = JSON.stringify(buildPayload(state));
6714
6766
  }
6715
- fs20.writeFileSync(SESSION_FILE, JSON.stringify(payload, null, 2), "utf-8");
6767
+ fs20.writeFileSync(SESSION_FILE, serialized, "utf-8");
6716
6768
  log9.info("Session saved", { messageCount: state.messages.length });
6717
6769
  } catch (err) {
6718
6770
  log9.warn("Session save failed", { error: err.message });
6719
6771
  }
6720
6772
  }
6721
6773
  function clearSession(state) {
6774
+ try {
6775
+ if (state.messages.length > 0) {
6776
+ archiveMessages(state.messages, "cleared", state.models);
6777
+ }
6778
+ } catch (err) {
6779
+ log9.warn("Session archive on clear failed", { error: err.message });
6780
+ }
6722
6781
  state.messages = [];
6723
6782
  try {
6724
6783
  if (fs20.existsSync(SESSION_FILE)) {
6725
- fs20.mkdirSync(ARCHIVE_DIR, { recursive: true });
6726
- const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
6727
- const dest = path9.join(ARCHIVE_DIR, `cleared-${ts}.json`);
6728
- fs20.renameSync(SESSION_FILE, dest);
6729
- log9.info("Session archived on clear", { dest });
6784
+ fs20.unlinkSync(SESSION_FILE);
6730
6785
  }
6731
6786
  } catch (err) {
6732
- log9.warn("Session archive on clear failed, deleting instead", {
6787
+ log9.warn("Session clear: could not remove live file", {
6733
6788
  error: err.message
6734
6789
  });
6735
- try {
6736
- fs20.unlinkSync(SESSION_FILE);
6737
- } catch {
6738
- }
6739
6790
  }
6740
6791
  }
6741
- var log9, SESSION_FILE, ARCHIVE_DIR;
6792
+ var log9, SESSION_FILE, ARCHIVE_DIR, ROTATE_THRESHOLD_BYTES, RETAIN_TAIL_BYTES;
6742
6793
  var init_session = __esm({
6743
6794
  "src/session.ts"() {
6744
6795
  "use strict";
6745
6796
  init_logger();
6797
+ init_compaction();
6798
+ init_cleanMessages();
6746
6799
  log9 = createLogger("session");
6747
6800
  SESSION_FILE = ".remy-session.json";
6748
6801
  ARCHIVE_DIR = ".logs/sessions";
6802
+ ROTATE_THRESHOLD_BYTES = 32 * 1024 * 1024;
6803
+ RETAIN_TAIL_BYTES = 16 * 1024 * 1024;
6749
6804
  }
6750
6805
  });
6751
6806
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.216",
3
+ "version": "0.1.218",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",