open-agents-ai 0.30.3 → 0.30.4

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 +110 -3
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10343,6 +10343,8 @@ Rules:
10343
10343
  handlers = [];
10344
10344
  pendingUserMessages = [];
10345
10345
  aborted = false;
10346
+ _paused = false;
10347
+ _pauseResolve = null;
10346
10348
  _sudoPassword = null;
10347
10349
  _sudoResolve = null;
10348
10350
  constructor(backend, options) {
@@ -10388,6 +10390,50 @@ Rules:
10388
10390
  /** Abort the current task run */
10389
10391
  abort() {
10390
10392
  this.aborted = true;
10393
+ if (this._pauseResolve) {
10394
+ this._pauseResolve();
10395
+ this._pauseResolve = null;
10396
+ }
10397
+ }
10398
+ /**
10399
+ * Pause the current task gracefully. The run loop will suspend at the next
10400
+ * turn boundary (between tool calls / model requests) without destroying state.
10401
+ * Call resume() to continue.
10402
+ */
10403
+ pause() {
10404
+ if (!this._paused) {
10405
+ this._paused = true;
10406
+ this.emit({ type: "compaction", content: "Task paused by user.", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
10407
+ }
10408
+ }
10409
+ /**
10410
+ * Resume a paused task. The run loop continues from where it left off.
10411
+ */
10412
+ resume() {
10413
+ if (this._paused) {
10414
+ this._paused = false;
10415
+ this.emit({ type: "compaction", content: "Task resumed by user.", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
10416
+ if (this._pauseResolve) {
10417
+ this._pauseResolve();
10418
+ this._pauseResolve = null;
10419
+ }
10420
+ }
10421
+ }
10422
+ /** Whether the runner is currently paused */
10423
+ get isPaused() {
10424
+ return this._paused;
10425
+ }
10426
+ /**
10427
+ * If paused, block until resume() or abort() is called.
10428
+ * Returns true if the loop should continue, false if aborted while paused.
10429
+ */
10430
+ async waitIfPaused() {
10431
+ if (!this._paused)
10432
+ return true;
10433
+ await new Promise((resolve19) => {
10434
+ this._pauseResolve = resolve19;
10435
+ });
10436
+ return !this.aborted;
10391
10437
  }
10392
10438
  emit(event) {
10393
10439
  for (const handler of this.handlers) {
@@ -10440,6 +10486,8 @@ Respond with your assessment, then take action.`;
10440
10486
  let selfEvalCount = 0;
10441
10487
  const toolCallLog = [];
10442
10488
  this.aborted = false;
10489
+ this._paused = false;
10490
+ this._pauseResolve = null;
10443
10491
  this.pendingUserMessages.length = 0;
10444
10492
  const basePrompt = getSystemPromptForTier(this.options.modelTier);
10445
10493
  const systemPrompt = this.options.dynamicContext ? `${basePrompt}
@@ -10461,6 +10509,13 @@ TASK: ${task}` : task }
10461
10509
  let summary = "";
10462
10510
  let bruteForceCycle = 0;
10463
10511
  for (let turn = 0; turn < this.options.maxTurns; turn++) {
10512
+ if (this._paused) {
10513
+ const shouldContinue = await this.waitIfPaused();
10514
+ if (!shouldContinue) {
10515
+ this.emit({ type: "error", content: "Task aborted by user", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
10516
+ break;
10517
+ }
10518
+ }
10464
10519
  if (this.aborted) {
10465
10520
  this.emit({ type: "error", content: "Task aborted by user", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
10466
10521
  break;
@@ -10717,6 +10772,13 @@ You have ${this.options.maxTurns} more turns. Continue making progress. Call tas
10717
10772
  messages.push(...compacted);
10718
10773
  }
10719
10774
  for (let turn = 0; turn < this.options.maxTurns; turn++) {
10775
+ if (this._paused) {
10776
+ const shouldContinue = await this.waitIfPaused();
10777
+ if (!shouldContinue) {
10778
+ this.emit({ type: "error", content: "Task aborted by user", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
10779
+ break;
10780
+ }
10781
+ }
10720
10782
  if (this.aborted) {
10721
10783
  this.emit({ type: "error", content: "Task aborted by user", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
10722
10784
  break;
@@ -15489,8 +15551,24 @@ async function handleSlashCommand(input, ctx) {
15489
15551
  renderInfo(`Colors ${next ? "enabled" : "disabled"}.`);
15490
15552
  return "handled";
15491
15553
  }
15492
- case "stop":
15493
15554
  case "pause": {
15555
+ if (!ctx.hasActiveTask?.()) {
15556
+ renderWarning("No active task to pause.");
15557
+ return "handled";
15558
+ }
15559
+ if (ctx.isTaskPaused?.()) {
15560
+ renderWarning("Task is already paused. Use /resume to continue.");
15561
+ return "handled";
15562
+ }
15563
+ const paused = ctx.pauseTask?.() ?? false;
15564
+ if (paused) {
15565
+ renderInfo("Task paused. Use /resume to continue or /stop to abort.");
15566
+ } else {
15567
+ renderWarning("Could not pause the task.");
15568
+ }
15569
+ return "handled";
15570
+ }
15571
+ case "stop": {
15494
15572
  if (!ctx.hasActiveTask?.()) {
15495
15573
  renderWarning("No active task to stop.");
15496
15574
  return "handled";
@@ -15507,8 +15585,17 @@ async function handleSlashCommand(input, ctx) {
15507
15585
  return "handled";
15508
15586
  }
15509
15587
  case "resume": {
15588
+ if (ctx.isTaskPaused?.()) {
15589
+ const resumed2 = ctx.resumeInSessionTask?.() ?? false;
15590
+ if (resumed2) {
15591
+ renderInfo("Task resumed.");
15592
+ } else {
15593
+ renderWarning("Could not resume the paused task.");
15594
+ }
15595
+ return "handled";
15596
+ }
15510
15597
  if (ctx.hasActiveTask?.()) {
15511
- renderWarning("A task is already running. Stop it first with /stop.");
15598
+ renderWarning("A task is already running. Pause it first with /pause or stop with /stop.");
15512
15599
  return "handled";
15513
15600
  }
15514
15601
  const resumed = ctx.resumeTask?.() ?? false;
@@ -20474,6 +20561,7 @@ async function startInteractive(config, repoPath) {
20474
20561
  let sudoPromptPending = false;
20475
20562
  const idlePrompt = `${c2.bold(c2.white("\u276F "))}`;
20476
20563
  const activePrompt = `${c2.bold(c2.white("+ "))}`;
20564
+ const pausedPrompt = `${c2.bold(c2.yellow("| "))}`;
20477
20565
  const rl = readline2.createInterface({
20478
20566
  input: process.stdin,
20479
20567
  output: process.stdout,
@@ -20507,7 +20595,7 @@ async function startInteractive(config, repoPath) {
20507
20595
  }
20508
20596
  });
20509
20597
  function showPrompt() {
20510
- const prompt = activeTask ? activePrompt : idlePrompt;
20598
+ const prompt = activeTask ? activeTask.runner.isPaused ? pausedPrompt : activePrompt : idlePrompt;
20511
20599
  rl.setPrompt(prompt);
20512
20600
  if (statusBar.isActive) {
20513
20601
  statusBar.setPromptText(prompt, 2);
@@ -20759,6 +20847,25 @@ async function startInteractive(config, repoPath) {
20759
20847
  writeContent(() => renderInfo("Task aborted."));
20760
20848
  return true;
20761
20849
  },
20850
+ pauseTask() {
20851
+ if (!activeTask)
20852
+ return false;
20853
+ activeTask.runner.pause();
20854
+ statusBar.setProcessing(false);
20855
+ showPrompt();
20856
+ return true;
20857
+ },
20858
+ resumeInSessionTask() {
20859
+ if (!activeTask || !activeTask.runner.isPaused)
20860
+ return false;
20861
+ activeTask.runner.resume();
20862
+ statusBar.setProcessing(true);
20863
+ showPrompt();
20864
+ return true;
20865
+ },
20866
+ isTaskPaused() {
20867
+ return activeTask !== null && activeTask.runner.isPaused;
20868
+ },
20762
20869
  resumeTask() {
20763
20870
  const pendingTask = loadPendingTask(repoRoot);
20764
20871
  if (!pendingTask)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.30.3",
3
+ "version": "0.30.4",
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",