open-agents-ai 0.103.83 → 0.103.85

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 +169 -52
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4713,6 +4713,24 @@ Process error: ${err.message}`;
4713
4713
  entry.finishedAt = Date.now();
4714
4714
  return true;
4715
4715
  }
4716
+ /** Kill ALL running tasks immediately (for /stop and /quit authority) */
4717
+ stopAll() {
4718
+ let killed = 0;
4719
+ for (const [, entry] of this.tasks) {
4720
+ if (entry.status !== "running")
4721
+ continue;
4722
+ if (entry.child) {
4723
+ try {
4724
+ entry.child.kill("SIGKILL");
4725
+ } catch {
4726
+ }
4727
+ }
4728
+ entry.status = "stopped";
4729
+ entry.finishedAt = Date.now();
4730
+ killed++;
4731
+ }
4732
+ return killed;
4733
+ }
4716
4734
  list() {
4717
4735
  return Array.from(this.tasks.values()).map(toInfo);
4718
4736
  }
@@ -12442,8 +12460,8 @@ async function handleCmd(cmd) {
12442
12460
  // succeeds in <1s. Racing them eliminates the wait.
12443
12461
  dlog('remote_infer: invoking ' + riCapName + ' on peer ' + riTargetPeer.slice(0, 20) + ' (libp2p' + (_natsConn ? ' + NATS parallel' : '') + ')');
12444
12462
  try {
12445
- var RI_TIMEOUT = 300000;
12446
- var riInvokeP = nexus.invokeCapability(riTargetPeer, riCapName, riData, { stream: false, maxDurationMs: 240000 });
12463
+ var RI_TIMEOUT = 60000; // 60s outer timeout \u2014 fail fast for interactive use
12464
+ var riInvokeP = nexus.invokeCapability(riTargetPeer, riCapName, riData, { stream: false, maxDurationMs: 45000 });
12447
12465
  var riTimeoutP = new Promise(function(_, reject) { setTimeout(function() { reject(new Error('remote_infer timed out after ' + (RI_TIMEOUT / 1000) + 's')); }, RI_TIMEOUT); });
12448
12466
 
12449
12467
  // Build race candidates \u2014 libp2p + timeout always present
@@ -12454,7 +12472,7 @@ async function handleCmd(cmd) {
12454
12472
  var _riNatsRaceP = (async function() {
12455
12473
  var _rSubject = 'nexus.invoke.' + riTargetPeer;
12456
12474
  var _rPayload = JSON.stringify({ capability: riCapName, input: riData, from: nexus.peerId || '' });
12457
- var _rResp = await _natsConn.request(_rSubject, _natsCodec.encode(_rPayload), { timeout: 240000 });
12475
+ var _rResp = await _natsConn.request(_rSubject, _natsCodec.encode(_rPayload), { timeout: 45000 });
12458
12476
  var _rResult = JSON.parse(_natsCodec.decode(_rResp.data));
12459
12477
  if (_rResult && _rResult.error) throw new Error('NATS: ' + _rResult.error);
12460
12478
  dlog('remote_infer: NATS won the race');
@@ -12493,8 +12511,8 @@ async function handleCmd(cmd) {
12493
12511
  var rPid = riCandidates[ri];
12494
12512
  dlog('remote_infer: trying peer ' + rPid.slice(0, 20) + '...');
12495
12513
  try {
12496
- var PEER_INVOKE_TIMEOUT = 180000; // 3 min per peer \u2014 remote API inference can be slow
12497
- var specInvoke = nexus.invokeCapability(rPid, riCapName, riData, { stream: false, maxDurationMs: 150000 });
12514
+ var PEER_INVOKE_TIMEOUT = 30000; // 30s per peer in discovery \u2014 fail fast, try next
12515
+ var specInvoke = nexus.invokeCapability(rPid, riCapName, riData, { stream: false, maxDurationMs: 25000 });
12498
12516
  var specTimeout = new Promise(function(_, reject) {
12499
12517
  setTimeout(function() { reject(new Error('peer invoke timeout')); }, PEER_INVOKE_TIMEOUT);
12500
12518
  });
@@ -12523,7 +12541,7 @@ async function handleCmd(cmd) {
12523
12541
  try {
12524
12542
  var _dpSubject = 'nexus.invoke.' + _dpPid;
12525
12543
  var _dpPayload = JSON.stringify({ capability: riCapName, input: riData, from: nexus.peerId || '' });
12526
- var _dpResp = await _natsConn.request(_dpSubject, _natsCodec.encode(_dpPayload), { timeout: 180000 });
12544
+ var _dpResp = await _natsConn.request(_dpSubject, _natsCodec.encode(_dpPayload), { timeout: 30000 });
12527
12545
  var _dpResult = JSON.parse(_natsCodec.decode(_dpResp.data));
12528
12546
  if (_dpResult && !_dpResult.error) {
12529
12547
  riResult = _dpResult;
@@ -18848,6 +18866,13 @@ ${this.options.dynamicContext}`,
18848
18866
  injectUserMessage(content) {
18849
18867
  this.pendingUserMessages.push(content);
18850
18868
  }
18869
+ /** Retract the last pending user message (Esc cancel).
18870
+ * Returns the retracted text, or null if queue is empty or already consumed. */
18871
+ retractLastPendingMessage() {
18872
+ if (this.pendingUserMessages.length === 0)
18873
+ return null;
18874
+ return this.pendingUserMessages.pop();
18875
+ }
18851
18876
  /** Abort the current task run — cancels in-flight requests and kills child processes */
18852
18877
  abort() {
18853
18878
  this.aborted = true;
@@ -19126,6 +19151,10 @@ If you're stuck, try a completely different approach. Do NOT repeat what failed
19126
19151
  try {
19127
19152
  response = this.options.streamEnabled && this.hasStreamingSupport() ? await this.streamingRequest(chatRequest, turn) : await this.backend.chatCompletion(chatRequest);
19128
19153
  } catch (reqErr) {
19154
+ if (reqErr instanceof Error && reqErr.fatal) {
19155
+ this.emit({ type: "error", content: `Backend error: ${reqErr.message}`, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
19156
+ break;
19157
+ }
19129
19158
  const recovered = await this.retryOnTransient(reqErr, chatRequest, turn);
19130
19159
  if (!recovered) {
19131
19160
  const errMsg = reqErr instanceof Error ? reqErr.message : String(reqErr);
@@ -20886,6 +20915,8 @@ ${transcript}`
20886
20915
  // -------------------------------------------------------------------------
20887
20916
  /** Detect whether an error is transient (worth retrying) */
20888
20917
  isTransientError(err) {
20918
+ if (err instanceof Error && err.fatal)
20919
+ return false;
20889
20920
  const msg = err instanceof Error ? err.message : String(err);
20890
20921
  if (/Backend HTTP (502|503|504)/i.test(msg))
20891
20922
  return true;
@@ -20895,6 +20926,10 @@ ${transcript}`
20895
20926
  return true;
20896
20927
  if (/model is loading|server busy|overloaded/i.test(msg))
20897
20928
  return true;
20929
+ if (/multiaddrs failed|all multiaddrs failed|dial to peer failed|stream was reset|Cannot reach peer/i.test(msg))
20930
+ return true;
20931
+ if (/NATS.*timeout|relay.*timeout|invoke.*timeout/i.test(msg))
20932
+ return true;
20898
20933
  return false;
20899
20934
  }
20900
20935
  /**
@@ -21222,6 +21257,15 @@ var init_nexusBackend = __esm({
21222
21257
  this.authKey = authKey || "";
21223
21258
  this.thinking = thinking ?? true;
21224
21259
  }
21260
+ /** Reset the consecutive failure counter (called on endpoint switch / reconnect) */
21261
+ resetFailures() {
21262
+ this.consecutiveFailures = 0;
21263
+ }
21264
+ /** Update target peer (allows switching peers without recreating the backend) */
21265
+ setTargetPeer(peerId) {
21266
+ this.targetPeer = peerId;
21267
+ this.consecutiveFailures = 0;
21268
+ }
21225
21269
  async chatCompletion(request) {
21226
21270
  if (this.consecutiveFailures >= _NexusAgenticBackend.MAX_CONSECUTIVE_FAILURES) {
21227
21271
  const err = new Error(`Remote peer unreachable after ${this.consecutiveFailures} attempts. Use /endpoint to switch to a local model or reconnect.`);
@@ -21258,7 +21302,10 @@ var init_nexusBackend = __esm({
21258
21302
  }
21259
21303
  if (parsed.success === false) {
21260
21304
  this.consecutiveFailures++;
21261
- throw new Error(`Remote inference failed: ${parsed.output || rawResult}`);
21305
+ const output = String(parsed.output || rawResult);
21306
+ const isDialErr = /multiaddrs failed|Cannot reach peer|dial to peer|timeout|ECONNREFUSED/i.test(output);
21307
+ const hint = isDialErr ? ` (${this.consecutiveFailures}/${_NexusAgenticBackend.MAX_CONSECUTIVE_FAILURES} failures \u2014 will stop after ${_NexusAgenticBackend.MAX_CONSECUTIVE_FAILURES})` : "";
21308
+ throw new Error(`Remote inference failed: ${output}${hint}`);
21262
21309
  }
21263
21310
  this.consecutiveFailures = 0;
21264
21311
  const invokeResult = parsed.result;
@@ -45592,8 +45639,11 @@ var init_status_bar = __esm({
45592
45639
  active = false;
45593
45640
  scrollRegionTop = 1;
45594
45641
  stdinHooked = false;
45595
- /** Track previous terminal rows to clear ghost separators on resize */
45642
+ /** Track previous terminal dimensions to clear ghost separators on resize */
45596
45643
  _prevTermRows = 0;
45644
+ _prevTermCols = 0;
45645
+ /** Debounce timer for resize events — prevents separator stacking during drag */
45646
+ _resizeTimer = null;
45597
45647
  /**
45598
45648
  * Depth-counted content write guard. Incremented by beginContentWrite(),
45599
45649
  * decremented by endContentWrite(). Footer is only redrawn and cursor
@@ -46040,6 +46090,7 @@ var init_status_bar = __esm({
46040
46090
  this.scrollRegionTop = scrollRegionTop ?? 1;
46041
46091
  this.active = true;
46042
46092
  this._prevTermRows = process.stdout.rows ?? 24;
46093
+ this._prevTermCols = process.stdout.columns ?? 80;
46043
46094
  this.applyScrollRegion();
46044
46095
  this.renderFooterAndPositionInput();
46045
46096
  this.hookStdin();
@@ -46077,24 +46128,42 @@ var init_status_bar = __esm({
46077
46128
  get reservedRows() {
46078
46129
  return this._currentFooterHeight;
46079
46130
  }
46080
- /** Handle terminal resize — reapply scroll region and redraw footer */
46131
+ /** Handle terminal resize — debounced to prevent separator stacking during drag */
46081
46132
  handleResize() {
46082
46133
  if (!this.active)
46083
46134
  return;
46135
+ if (this._resizeTimer)
46136
+ clearTimeout(this._resizeTimer);
46137
+ this._resizeTimer = setTimeout(() => {
46138
+ this._resizeTimer = null;
46139
+ this._handleResizeImmediate();
46140
+ }, 50);
46141
+ }
46142
+ /** Actual resize handler — called after debounce settles */
46143
+ _handleResizeImmediate() {
46144
+ if (!this.active)
46145
+ return;
46146
+ const prevRows = this._prevTermRows;
46147
+ const prevCols = this._prevTermCols;
46084
46148
  this.updateFooterHeight();
46085
46149
  const rows = process.stdout.rows ?? 24;
46086
- const prevRows = this._prevTermRows;
46150
+ const cols = process.stdout.columns ?? 80;
46087
46151
  this._prevTermRows = rows;
46152
+ this._prevTermCols = cols;
46088
46153
  const pos = this.rowPositions(rows);
46089
46154
  const w = getTermWidth();
46090
46155
  const sep = c2.dim("\u2500".repeat(w));
46091
- let clearGhosts = "";
46092
- if (prevRows > 0 && rows < prevRows) {
46093
- clearGhosts = "\x1B[1;" + rows + `r\x1B[${pos.bufferRow};1H\x1B[J`;
46156
+ let clearBuf = "";
46157
+ if (prevRows > 0 && (rows !== prevRows || cols !== prevCols)) {
46158
+ const wrapFactor = cols > 0 ? Math.ceil(prevCols / cols) : 1;
46159
+ const extraWrappedRows = Math.max(0, (wrapFactor - 1) * 3);
46160
+ const safetyMargin = extraWrappedRows + 2;
46161
+ const clearFrom = Math.max(1, pos.bufferRow - safetyMargin);
46162
+ clearBuf = "\x1B[1;" + rows + `r\x1B[${clearFrom};1H\x1B[J`;
46094
46163
  }
46095
46164
  if (this.writeDepth > 0) {
46096
46165
  const inputWrap = this.wrapInput(w);
46097
- let buf = clearGhosts + `\x1B[${this.scrollRegionTop};${pos.scrollEnd}r\x1B[?25l\x1B[?7l\x1B[${pos.bufferRow};1H\x1B[2K${this.buildBufferContent(w)}\x1B[${pos.topSepRow};1H\x1B[2K${sep}`;
46166
+ let buf = clearBuf + `\x1B[${this.scrollRegionTop};${pos.scrollEnd}r\x1B[?25l\x1B[?7l\x1B[${pos.bufferRow};1H\x1B[2K${this.buildBufferContent(w)}\x1B[${pos.topSepRow};1H\x1B[2K${sep}`;
46098
46167
  for (let i = 0; i < inputWrap.lines.length; i++) {
46099
46168
  const row = pos.inputStartRow + i;
46100
46169
  const prefix = i === 0 ? this.promptText : " ".repeat(this.promptWidth);
@@ -46103,8 +46172,8 @@ var init_status_bar = __esm({
46103
46172
  buf += `\x1B[${pos.bottomSepRow};1H\x1B[2K${sep}\x1B[${pos.metricsRow};1H\x1B[2K${this.buildMetricsLine()}\x1B[?7h\x1B[${pos.scrollEnd};1H`;
46104
46173
  process.stdout.write(buf);
46105
46174
  } else {
46106
- if (clearGhosts)
46107
- process.stdout.write(clearGhosts);
46175
+ if (clearBuf)
46176
+ process.stdout.write(clearBuf);
46108
46177
  this.applyScrollRegion();
46109
46178
  this.renderFooterAndPositionInput();
46110
46179
  }
@@ -47956,8 +48025,9 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
47956
48025
  let currentTaskType;
47957
48026
  let sessionFilesTouched = [];
47958
48027
  let sessionToolCallCount = 0;
48028
+ let lastSteeringInput = "";
48029
+ let lastSteeringRetracted = false;
47959
48030
  let restoredSessionContext = null;
47960
- let pendingSessionRestore = false;
47961
48031
  let sessionSudoPassword = null;
47962
48032
  let sudoPromptPending = false;
47963
48033
  const idlePrompt = `${c2.bold(c2.white("\u276F "))}`;
@@ -49217,7 +49287,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
49217
49287
  if (!activeTask)
49218
49288
  return false;
49219
49289
  activeTask.runner.abort();
49220
- writeContent(() => renderInfo("Task aborted."));
49290
+ const bgKilled = taskManager.stopAll();
49291
+ writeContent(() => renderInfo(`Task aborted.${bgKilled > 0 ? ` ${bgKilled} background task(s) killed.` : ""}`));
49221
49292
  return true;
49222
49293
  },
49223
49294
  pauseTask() {
@@ -49309,28 +49380,40 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
49309
49380
  const lastTime = lastEntry.savedAt ? new Date(lastEntry.savedAt) : null;
49310
49381
  const timeAgo = lastTime ? formatTimeAgo(lastTime) : "unknown";
49311
49382
  const lastTask = lastEntry.task?.slice(0, 80) || "unknown";
49312
- setTimeout(() => {
49383
+ setTimeout(async () => {
49313
49384
  writeContent(() => {
49314
49385
  renderInfo(`Previous session found (${savedCtx.entries.length} entries, last active ${timeAgo})`);
49315
49386
  renderInfo(`Last task: ${lastTask}${lastEntry.task && lastEntry.task.length > 80 ? "..." : ""}`);
49316
- renderInfo(`Restore previous context? (y/n) [auto-restores in 15s]`);
49317
49387
  });
49318
- showPrompt();
49319
- pendingSessionRestore = true;
49320
- setTimeout(() => {
49321
- if (pendingSessionRestore) {
49322
- pendingSessionRestore = false;
49323
- const prompt = buildContextRestorePrompt(repoRoot);
49324
- if (prompt) {
49325
- restoredSessionContext = prompt;
49326
- const info = loadSessionContext(repoRoot);
49327
- writeContent(() => renderInfo(`Context auto-restored from ${info?.entries.length ?? 0} session(s).`));
49328
- } else {
49329
- writeContent(() => renderInfo("No context to restore. Starting fresh."));
49330
- }
49331
- showPrompt();
49332
- }
49388
+ let autoRestoreTimer = setTimeout(() => {
49389
+ autoRestoreTimer = null;
49333
49390
  }, 15e3);
49391
+ const result = await tuiSelect({
49392
+ items: [
49393
+ { key: "restore", label: "Restore previous context" },
49394
+ { key: "fresh", label: "Start fresh" }
49395
+ ],
49396
+ activeKey: "restore",
49397
+ title: "Restore previous session context?",
49398
+ rl
49399
+ });
49400
+ if (autoRestoreTimer)
49401
+ clearTimeout(autoRestoreTimer);
49402
+ if (result.confirmed && result.key === "restore" || !result.confirmed && !autoRestoreTimer) {
49403
+ const prompt = buildContextRestorePrompt(repoRoot);
49404
+ if (prompt) {
49405
+ restoredSessionContext = prompt;
49406
+ const info = loadSessionContext(repoRoot);
49407
+ writeContent(() => renderInfo(`Context restored from ${info?.entries.length ?? 0} session(s).`));
49408
+ } else {
49409
+ writeContent(() => renderInfo("No context to restore. Starting fresh."));
49410
+ }
49411
+ } else if (result.confirmed && result.key === "fresh") {
49412
+ writeContent(() => renderInfo("Starting fresh."));
49413
+ } else {
49414
+ writeContent(() => renderInfo("Starting fresh."));
49415
+ }
49416
+ showPrompt();
49334
49417
  }, 150);
49335
49418
  }
49336
49419
  }
@@ -49453,22 +49536,6 @@ ${result.content.slice(0, 2e3)}${result.content.length > 2e3 ? "\n[truncated]" :
49453
49536
  rl.on("line", (line) => {
49454
49537
  persistHistoryLine(line);
49455
49538
  const input = line.trim();
49456
- if (pendingSessionRestore) {
49457
- pendingSessionRestore = false;
49458
- const answer = input.toLowerCase();
49459
- if (answer === "y" || answer === "yes") {
49460
- const prompt = buildContextRestorePrompt(repoRoot);
49461
- if (prompt) {
49462
- restoredSessionContext = prompt;
49463
- const info = loadSessionContext(repoRoot);
49464
- writeContent(() => renderInfo(`Context restored from ${info?.entries.length ?? 0} session(s). Will be injected into your next task.`));
49465
- }
49466
- } else {
49467
- writeContent(() => renderInfo("Starting fresh."));
49468
- }
49469
- showPrompt();
49470
- return;
49471
- }
49472
49539
  if (!input) {
49473
49540
  if (pasteBuffer.length > 0) {
49474
49541
  flushPasteBuffer();
@@ -49523,6 +49590,7 @@ ${result.content.slice(0, 2e3)}${result.content.length > 2e3 ? "\n[truncated]" :
49523
49590
  if (activeTask) {
49524
49591
  activeTask.runner.abort();
49525
49592
  }
49593
+ taskManager.stopAll();
49526
49594
  if (blessEngine?.isActive)
49527
49595
  blessEngine.stop();
49528
49596
  if (telegramBridge?.isActive)
@@ -49592,6 +49660,10 @@ Execute this skill now. Follow the behavioral guidance above.`;
49592
49660
  const isImage = isImagePath(cleanPath) && existsSync40(resolve28(repoRoot, cleanPath));
49593
49661
  const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync40(resolve28(repoRoot, cleanPath));
49594
49662
  if (activeTask) {
49663
+ if (activeTask.runner.isPaused) {
49664
+ activeTask.runner.resume();
49665
+ statusBar.setProcessing(true);
49666
+ }
49595
49667
  if (isImage) {
49596
49668
  try {
49597
49669
  const imgPath = resolve28(repoRoot, cleanPath);
@@ -49619,8 +49691,16 @@ ${result.text}`;
49619
49691
  writeContent(() => renderUserInterrupt(`[Media: ${cleanPath}]`));
49620
49692
  }
49621
49693
  } else {
49694
+ const isReplacement = lastSteeringRetracted;
49695
+ lastSteeringInput = input;
49696
+ lastSteeringRetracted = false;
49622
49697
  const lineCount = input.split("\n").length;
49623
- if (lineCount > 1) {
49698
+ if (isReplacement) {
49699
+ const displayText2 = lineCount > 1 ? `[pasted ${lineCount} lines]` : input;
49700
+ writeContent(() => process.stdout.write(`
49701
+ ${c2.green("\u21BB")} ${c2.bold("Context replaced:")} ${displayText2}
49702
+ `));
49703
+ } else if (lineCount > 1) {
49624
49704
  writeContent(() => renderUserInterrupt(`[pasted ${lineCount} lines]`));
49625
49705
  } else {
49626
49706
  writeContent(() => renderUserInterrupt(input));
@@ -49991,6 +50071,7 @@ ${c2.dim("(paste cancelled)")}
49991
50071
  }
49992
50072
  if (activeTask) {
49993
50073
  activeTask.runner.abort();
50074
+ taskManager.stopAll();
49994
50075
  writeContent(() => renderTaskAborted());
49995
50076
  } else {
49996
50077
  writeContent(() => process.stdout.write(`
@@ -49999,6 +50080,42 @@ ${c2.dim("(Use /quit to exit)")}
49999
50080
  }
50000
50081
  showPrompt();
50001
50082
  });
50083
+ if (process.stdin.isTTY) {
50084
+ readline2.emitKeypressEvents(process.stdin, rl);
50085
+ process.stdin.on("keypress", (_str, key) => {
50086
+ if (!key)
50087
+ return;
50088
+ if (key.name === "escape" && activeTask) {
50089
+ if (!activeTask.runner.isPaused) {
50090
+ activeTask.runner.pause();
50091
+ statusBar.setProcessing(false);
50092
+ }
50093
+ const retracted = activeTask.runner.retractLastPendingMessage();
50094
+ if (retracted) {
50095
+ lastSteeringInput = retracted;
50096
+ lastSteeringRetracted = true;
50097
+ writeContent(() => process.stdout.write(` ${c2.yellow("\u23F8")} ${c2.dim("\x1B[9m" + retracted.slice(0, 120) + "\x1B[29m")} ${c2.dim("\u2190 retracted, edit below and press Enter")}
50098
+ `));
50099
+ rl.line = retracted;
50100
+ rl.cursor = retracted.length;
50101
+ if (statusBar.isActive)
50102
+ statusBar.renderFooterPreserveCursor?.();
50103
+ } else if (lastSteeringInput) {
50104
+ lastSteeringRetracted = true;
50105
+ writeContent(() => process.stdout.write(` ${c2.yellow("\u23F8")} ${c2.dim("\x1B[9m" + lastSteeringInput.slice(0, 120) + "\x1B[29m")} ${c2.dim("\u2190 already sent, re-type below to override")}
50106
+ `));
50107
+ rl.line = lastSteeringInput;
50108
+ rl.cursor = lastSteeringInput.length;
50109
+ if (statusBar.isActive)
50110
+ statusBar.renderFooterPreserveCursor?.();
50111
+ } else {
50112
+ writeContent(() => process.stdout.write(` ${c2.yellow("\u23F8")} ${c2.dim("Paused. /resume to continue, /stop to kill.")}
50113
+ `));
50114
+ }
50115
+ showPrompt();
50116
+ }
50117
+ });
50118
+ }
50002
50119
  }
50003
50120
  async function runWithTUI(task, config, repoPath) {
50004
50121
  const repoRoot = resolve28(repoPath ?? cwd());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.103.83",
3
+ "version": "0.103.85",
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",