open-agents-ai 0.12.8 → 0.12.10

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.
Files changed (2) hide show
  1. package/dist/index.js +75 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7666,8 +7666,10 @@ You have used ${totalTurns} turns and ${toolCallCount} tool calls without comple
7666
7666
  You have ${this.options.maxTurns} more turns. Be creative and investigative. If a file is confusing, re-read it. If a test fails, read the FULL error. Call task_complete when done.`
7667
7667
  });
7668
7668
  const compacted = this.compactMessages(messages);
7669
- messages.length = 0;
7670
- messages.push(...compacted);
7669
+ if (compacted !== messages) {
7670
+ messages.length = 0;
7671
+ messages.push(...compacted);
7672
+ }
7671
7673
  for (let turn = 0; turn < this.options.maxTurns; turn++) {
7672
7674
  if (this.aborted) {
7673
7675
  this.emit({ type: "error", content: "Task aborted by user", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
@@ -12646,8 +12648,16 @@ var init_status_bar = __esm({
12646
12648
  active = false;
12647
12649
  scrollRegionTop = 1;
12648
12650
  stdinHooked = false;
12649
- /** True while content is being written to the scroll region (between begin/end) */
12650
- writingContent = false;
12651
+ /**
12652
+ * Depth-counted content write guard. Incremented by beginContentWrite(),
12653
+ * decremented by endContentWrite(). Footer is only redrawn and cursor
12654
+ * parked on the input row when depth reaches 0. This prevents nested
12655
+ * content writes (e.g. a slash command executed mid-stream) from
12656
+ * prematurely ending the outer streaming session's scroll-region lock.
12657
+ */
12658
+ writeDepth = 0;
12659
+ /** Optional callback invoked when writeDepth drops to 0 (content write fully ended) */
12660
+ _onEndContentWrite;
12651
12661
  /** Context window size to display. Can be updated if model changes. */
12652
12662
  setContextWindowSize(size) {
12653
12663
  this.metrics.contextWindowSize = size;
@@ -12692,6 +12702,18 @@ var init_status_bar = __esm({
12692
12702
  get isActive() {
12693
12703
  return this.active;
12694
12704
  }
12705
+ /** Whether content is currently being written to the scroll region */
12706
+ get isWritingContent() {
12707
+ return this.writeDepth > 0;
12708
+ }
12709
+ /**
12710
+ * Register a callback invoked when the outermost content write ends
12711
+ * (writeDepth drops to 0). Used by the REPL to refresh readline's prompt
12712
+ * so the cursor lands after the prompt text, not at column 1.
12713
+ */
12714
+ onEndContentWrite(fn) {
12715
+ this._onEndContentWrite = fn;
12716
+ }
12695
12717
  /** Number of rows reserved at the bottom */
12696
12718
  get reservedRows() {
12697
12719
  return FOOTER_ROWS;
@@ -12703,31 +12725,47 @@ var init_status_bar = __esm({
12703
12725
  this.applyScrollRegion();
12704
12726
  this.renderFooterAndPositionInput();
12705
12727
  }
12728
+ /**
12729
+ * Update the top boundary of the scroll region (e.g. after carousel retirement).
12730
+ * When the scroll region starts at row 1, most terminals preserve scrollback.
12731
+ */
12732
+ setScrollRegionTop(top) {
12733
+ this.scrollRegionTop = top;
12734
+ if (this.active) {
12735
+ this.applyScrollRegion();
12736
+ this.renderFooterAndPositionInput();
12737
+ }
12738
+ }
12706
12739
  /**
12707
12740
  * Call BEFORE writing content to the scrollable area above the footer.
12708
- * Re-enforces the DECSTBM scroll region (guards against corruption from
12709
- * carousel.stop(), resize, or any other reset) then positions the cursor
12710
- * at the bottom of the scroll region so content output scrolls properly.
12741
+ * Increments writeDepth and re-enforces the DECSTBM scroll region so
12742
+ * content output scrolls properly. Safe to nest: a slash command or
12743
+ * tool event executed mid-stream will push depth to 2; its paired
12744
+ * endContentWrite() drops it back to 1 without touching the footer.
12711
12745
  */
12712
12746
  beginContentWrite() {
12713
12747
  if (!this.active)
12714
12748
  return;
12715
- this.writingContent = true;
12749
+ this.writeDepth++;
12716
12750
  const rows = process.stdout.rows ?? 24;
12717
12751
  const scrollEnd = Math.max(rows - FOOTER_ROWS, this.scrollRegionTop + 1);
12718
12752
  process.stdout.write(`\x1B[${this.scrollRegionTop};${scrollEnd}r\x1B[${scrollEnd};1H`);
12719
12753
  }
12720
12754
  /**
12721
12755
  * Call AFTER writing content to the scrollable area.
12722
- * Clears the writing guard, redraws footer, and parks cursor on the input row.
12723
- * Does NOT try to restore to a previous cursor position uses explicit
12724
- * absolute positioning instead (avoids SCP/RCP alias issues on some terminals).
12756
+ * Decrements writeDepth. Only when depth reaches 0 (outermost write
12757
+ * finished) does it redraw the footer and park the cursor on the input row.
12758
+ * This prevents a nested endContentWrite (e.g. from a slash command during
12759
+ * streaming) from prematurely moving the cursor out of the scroll region.
12725
12760
  */
12726
12761
  endContentWrite() {
12727
12762
  if (!this.active)
12728
12763
  return;
12729
- this.writingContent = false;
12730
- this.renderFooterAndPositionInput();
12764
+ this.writeDepth = Math.max(0, this.writeDepth - 1);
12765
+ if (this.writeDepth === 0) {
12766
+ this.renderFooterAndPositionInput();
12767
+ this._onEndContentWrite?.();
12768
+ }
12731
12769
  }
12732
12770
  /**
12733
12771
  * Clear the input row and position cursor there at column 1.
@@ -12767,8 +12805,9 @@ var init_status_bar = __esm({
12767
12805
  /**
12768
12806
  * Draw the footer (separators + metrics) and leave cursor on the input row.
12769
12807
  * All ANSI sequences are batched into a SINGLE write to prevent interleaving.
12770
- * Re-enforces the DECSTBM scroll region after drawing to ensure the content
12771
- * area boundary is always correct.
12808
+ * Does NOT set DECSTBM — the scroll region is maintained by applyScrollRegion()
12809
+ * (on activate/resize) and beginContentWrite(). Setting DECSTBM here can move
12810
+ * the cursor to unexpected positions on some terminals.
12772
12811
  * Does NOT touch the input row content — readline manages that.
12773
12812
  */
12774
12813
  renderFooterAndPositionInput() {
@@ -12778,8 +12817,7 @@ var init_status_bar = __esm({
12778
12817
  const w = getTermWidth();
12779
12818
  const sep = c2.dim("\u2500".repeat(w));
12780
12819
  const inputRow = rows - 2;
12781
- const scrollEnd = Math.max(rows - FOOTER_ROWS, this.scrollRegionTop + 1);
12782
- const buf = `\x1B[?7l\x1B[${rows - 4};1H\x1B[2K\x1B[${rows - 3};1H\x1B[2K${sep}\x1B[${rows - 1};1H\x1B[2K${sep}\x1B[${rows};1H\x1B[2K${this.buildMetricsLine()}\x1B[?7h\x1B[${this.scrollRegionTop};${scrollEnd}r\x1B[${inputRow};1H`;
12820
+ const buf = `\x1B[?7l\x1B[${rows - 4};1H\x1B[2K\x1B[${rows - 3};1H\x1B[2K${sep}\x1B[${rows - 1};1H\x1B[2K${sep}\x1B[${rows};1H\x1B[2K${this.buildMetricsLine()}\x1B[?7h\x1B[${inputRow};1H`;
12783
12821
  process.stdout.write(buf);
12784
12822
  }
12785
12823
  /**
@@ -12787,7 +12825,10 @@ var init_status_bar = __esm({
12787
12825
  * Used by keystroke protection and metrics updates — these must not
12788
12826
  * move the cursor away from where readline left it.
12789
12827
  * Uses DEC DECSC/DECRC (\x1B7/\x1B8) for save/restore in a single write.
12790
- * Re-enforces the DECSTBM scroll region after drawing.
12828
+ *
12829
+ * IMPORTANT: Does NOT set DECSTBM here — setting the scroll region between
12830
+ * cursor save/restore corrupts the restore position on many terminals.
12831
+ * The scroll region is enforced by beginContentWrite() and renderFooterAndPositionInput().
12791
12832
  */
12792
12833
  renderFooterPreserveCursor() {
12793
12834
  if (!this.active)
@@ -12795,8 +12836,7 @@ var init_status_bar = __esm({
12795
12836
  const rows = process.stdout.rows ?? 24;
12796
12837
  const w = getTermWidth();
12797
12838
  const sep = c2.dim("\u2500".repeat(w));
12798
- const scrollEnd = Math.max(rows - FOOTER_ROWS, this.scrollRegionTop + 1);
12799
- const buf = `\x1B7\x1B[?7l\x1B[${rows - 4};1H\x1B[2K\x1B[${rows - 3};1H\x1B[2K${sep}\x1B[${rows - 1};1H\x1B[2K${sep}\x1B[${rows};1H\x1B[2K${this.buildMetricsLine()}\x1B[?7h\x1B[${this.scrollRegionTop};${scrollEnd}r\x1B8`;
12839
+ const buf = `\x1B7\x1B[?7l\x1B[${rows - 4};1H\x1B[2K\x1B[${rows - 3};1H\x1B[2K${sep}\x1B[${rows - 1};1H\x1B[2K${sep}\x1B[${rows};1H\x1B[2K${this.buildMetricsLine()}\x1B[?7h\x1B8`;
12800
12840
  process.stdout.write(buf);
12801
12841
  }
12802
12842
  /**
@@ -12809,10 +12849,10 @@ var init_status_bar = __esm({
12809
12849
  return;
12810
12850
  this.stdinHooked = true;
12811
12851
  process.stdin.on("data", () => {
12812
- if (!this.active || this.writingContent)
12852
+ if (!this.active || this.writeDepth > 0)
12813
12853
  return;
12814
12854
  setImmediate(() => {
12815
- if (this.writingContent)
12855
+ if (this.writeDepth > 0)
12816
12856
  return;
12817
12857
  this.renderFooterPreserveCursor();
12818
12858
  });
@@ -13282,6 +13322,11 @@ async function startInteractive(config, repoPath) {
13282
13322
  terminal: true,
13283
13323
  historySize: 100
13284
13324
  });
13325
+ statusBar.onEndContentWrite(() => {
13326
+ rl.setPrompt(activeTask ? activePrompt : idlePrompt);
13327
+ statusBar.positionAtInput();
13328
+ rl.prompt();
13329
+ });
13285
13330
  process.stdout.on("resize", () => {
13286
13331
  statusBar.handleResize();
13287
13332
  if (!carouselRetired) {
@@ -13300,6 +13345,8 @@ async function startInteractive(config, repoPath) {
13300
13345
  }
13301
13346
  });
13302
13347
  function showPrompt() {
13348
+ if (statusBar.isActive && statusBar.isWritingContent)
13349
+ return;
13303
13350
  rl.setPrompt(activeTask ? activePrompt : idlePrompt);
13304
13351
  if (statusBar.isActive) {
13305
13352
  statusBar.positionAtInput();
@@ -13449,11 +13496,16 @@ async function startInteractive(config, repoPath) {
13449
13496
  return;
13450
13497
  }
13451
13498
  if (input.startsWith("/")) {
13499
+ if (statusBar.isActive)
13500
+ statusBar.beginContentWrite();
13452
13501
  const cmdResult = await handleSlashCommand(input, commandCtx);
13502
+ if (statusBar.isActive)
13503
+ statusBar.endContentWrite();
13453
13504
  if (cmdResult === "exit") {
13454
13505
  if (activeTask) {
13455
13506
  activeTask.runner.abort();
13456
13507
  }
13508
+ statusBar.deactivate();
13457
13509
  process.stdout.write(`
13458
13510
  ${c2.dim("Goodbye!")}
13459
13511
 
@@ -13501,7 +13553,7 @@ ${c2.dim("Goodbye!")}
13501
13553
  carousel.stop();
13502
13554
  carouselRetired = true;
13503
13555
  if (statusBar.isActive)
13504
- statusBar.handleResize();
13556
+ statusBar.setScrollRegionTop(1);
13505
13557
  }
13506
13558
  writeContent(() => renderUserMessage(isImage ? `[Image: ${cleanPath}]` : fullInput));
13507
13559
  lastSubmittedPrompt = fullInput;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.12.8",
3
+ "version": "0.12.10",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",