open-agents-ai 0.54.0 → 0.55.0

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 +67 -9
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -17692,6 +17692,7 @@ var init_render = __esm({
17692
17692
  // packages/cli/dist/tui/voice-session.js
17693
17693
  import { createServer } from "node:http";
17694
17694
  import { spawn as spawn10, execSync as execSync19 } from "node:child_process";
17695
+ import { createHash } from "node:crypto";
17695
17696
  import { EventEmitter as EventEmitter2 } from "node:events";
17696
17697
  function parseWebSocketFrame(buf) {
17697
17698
  if (buf.length < 2)
@@ -17846,20 +17847,31 @@ let scriptProcessor = null;
17846
17847
  let micActive = false;
17847
17848
  let playbackQueue = [];
17848
17849
  let isPlaying = false;
17850
+ let reconnectDelay = 1000;
17851
+ let reconnectTimer = null;
17849
17852
 
17850
17853
  // Connect WebSocket
17851
17854
  function connect() {
17855
+ if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
17852
17856
  const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
17853
17857
  ws = new WebSocket(proto + '//' + location.host + '/ws');
17854
17858
  ws.binaryType = 'arraybuffer';
17855
17859
 
17856
17860
  ws.onopen = () => {
17857
17861
  statusEl.innerHTML = '<span class="connected">Connected</span>';
17862
+ reconnectDelay = 1000; // Reset backoff on successful connection
17863
+ };
17864
+
17865
+ ws.onerror = () => {
17866
+ // Error fires before close \u2014 just update status, close handler does reconnect
17867
+ statusEl.innerHTML = '<span class="disconnected">Connection error</span>';
17858
17868
  };
17859
17869
 
17860
17870
  ws.onclose = () => {
17861
17871
  statusEl.innerHTML = '<span class="disconnected">Disconnected \u2014 reconnecting...</span>';
17862
- setTimeout(connect, 2000);
17872
+ // Exponential backoff: 1s, 2s, 4s, max 10s
17873
+ reconnectTimer = setTimeout(connect, reconnectDelay);
17874
+ reconnectDelay = Math.min(reconnectDelay * 2, 10000);
17863
17875
  };
17864
17876
 
17865
17877
  ws.onmessage = (evt) => {
@@ -18184,9 +18196,10 @@ var init_voice_session = __esm({
18184
18196
  socket.destroy();
18185
18197
  return;
18186
18198
  }
18187
- const crypto2 = __require("node:crypto");
18188
18199
  const magic = "258EAFA5-E914-47DA-95CA-5AB9DC085B62";
18189
- const accept = crypto2.createHash("sha1").update(key + magic).digest("base64");
18200
+ const accept = createHash("sha1").update(key + magic).digest("base64");
18201
+ socket.setNoDelay(true);
18202
+ socket.setKeepAlive(true, 3e4);
18190
18203
  socket.write(`HTTP/1.1 101 Switching Protocols\r
18191
18204
  Upgrade: websocket\r
18192
18205
  Connection: Upgrade\r
@@ -18197,6 +18210,21 @@ Sec-WebSocket-Accept: ${accept}\r
18197
18210
  this.wsClients.set(clientId, socket);
18198
18211
  this.state.connectedUsers.set(clientId, { username: "web-user", connectedAt: Date.now() });
18199
18212
  this.emit("userConnected", clientId, "web-user");
18213
+ try {
18214
+ socket.write(createWebSocketFrame(9, Buffer.from("keepalive")));
18215
+ } catch {
18216
+ }
18217
+ const pingInterval = setInterval(() => {
18218
+ if (socket.destroyed) {
18219
+ clearInterval(pingInterval);
18220
+ return;
18221
+ }
18222
+ try {
18223
+ socket.write(createWebSocketFrame(9, Buffer.from("keepalive")));
18224
+ } catch {
18225
+ clearInterval(pingInterval);
18226
+ }
18227
+ }, 25e3);
18200
18228
  let frameBuffer = Buffer.alloc(0);
18201
18229
  socket.on("data", (data) => {
18202
18230
  frameBuffer = Buffer.concat([frameBuffer, data]);
@@ -18218,10 +18246,15 @@ Sec-WebSocket-Accept: ${accept}\r
18218
18246
  const consumed = headerLen + (masked ? 4 : 0) + payloadLen;
18219
18247
  frameBuffer = frameBuffer.subarray(consumed);
18220
18248
  if (frame.opcode === 8) {
18249
+ try {
18250
+ socket.write(createWebSocketFrame(8, Buffer.alloc(0)));
18251
+ } catch {
18252
+ }
18221
18253
  socket.end();
18222
18254
  return;
18223
18255
  } else if (frame.opcode === 9) {
18224
18256
  socket.write(createWebSocketFrame(10, frame.payload));
18257
+ } else if (frame.opcode === 10) {
18225
18258
  } else if (frame.opcode === 1) {
18226
18259
  try {
18227
18260
  const msg = JSON.parse(frame.payload.toString());
@@ -18229,7 +18262,6 @@ Sec-WebSocket-Accept: ${accept}\r
18229
18262
  const entry = this.state.connectedUsers.get(clientId);
18230
18263
  if (entry)
18231
18264
  entry.username = msg.username;
18232
- this.emit("userConnected", clientId, msg.username);
18233
18265
  }
18234
18266
  } catch {
18235
18267
  }
@@ -18241,12 +18273,13 @@ Sec-WebSocket-Accept: ${accept}\r
18241
18273
  }
18242
18274
  });
18243
18275
  socket.on("close", () => {
18276
+ clearInterval(pingInterval);
18244
18277
  this.wsClients.delete(clientId);
18245
- const user = this.state.connectedUsers.get(clientId);
18246
18278
  this.state.connectedUsers.delete(clientId);
18247
18279
  this.emit("userDisconnected", clientId);
18248
18280
  });
18249
18281
  socket.on("error", () => {
18282
+ clearInterval(pingInterval);
18250
18283
  this.wsClients.delete(clientId);
18251
18284
  this.state.connectedUsers.delete(clientId);
18252
18285
  });
@@ -27257,6 +27290,10 @@ function convertMarkdownToTelegramHTML(md) {
27257
27290
  return html;
27258
27291
  }
27259
27292
  function formatIntermediateState(event) {
27293
+ if (event.type === "tool_call" && event.toolName === "task_complete")
27294
+ return null;
27295
+ if (event.type === "tool_result" && event.toolName === "task_complete")
27296
+ return null;
27260
27297
  if (event.type === "tool_call") {
27261
27298
  const argsPreview = event.toolArgs ? JSON.stringify(event.toolArgs).slice(0, 60) : "";
27262
27299
  return `\u{1F527} <code>${event.toolName || "tool"}</code>(${argsPreview.length > 57 ? argsPreview.slice(0, 57) + "..." : argsPreview})`;
@@ -27456,6 +27493,8 @@ with summary "no_reply" to silently skip without responding.
27456
27493
  commandHandler = null;
27457
27494
  /** Callback to get active call session URL (wired from interactive.ts) */
27458
27495
  callUrlGetter = null;
27496
+ /** Callback to start a call session and return the URL (wired from interactive.ts) */
27497
+ callStarter = null;
27459
27498
  /** Callback to write content into the scrollable TUI waterfall area (wired from interactive.ts) */
27460
27499
  writeContent = null;
27461
27500
  /** Media cache — fileUniqueId → cache entry */
@@ -27495,6 +27534,10 @@ with summary "no_reply" to silently skip without responding.
27495
27534
  setCallUrlGetter(getter) {
27496
27535
  this.callUrlGetter = getter;
27497
27536
  }
27537
+ /** Register callback to start a call session (returns URL or null) */
27538
+ setCallStarter(starter) {
27539
+ this.callStarter = starter;
27540
+ }
27498
27541
  /** Register callback to write content into the scrollable TUI area (status bar guard) */
27499
27542
  setWriteContent(fn) {
27500
27543
  this.writeContent = fn;
@@ -27665,6 +27708,20 @@ with summary "no_reply" to silently skip without responding.
27665
27708
  await this.sendMessage(msg.chatId, "No active call session. Ask the admin to start one with /call.");
27666
27709
  return;
27667
27710
  }
27711
+ if (this.callStarter) {
27712
+ try {
27713
+ const newUrl = await this.callStarter();
27714
+ if (newUrl) {
27715
+ await this.sendCallButton(msg.chatId, newUrl);
27716
+ } else {
27717
+ await this.sendMessage(msg.chatId, "Failed to start call session.");
27718
+ }
27719
+ } catch (err) {
27720
+ await this.sendMessage(msg.chatId, `Call error: ${err instanceof Error ? err.message : String(err)}`).catch(() => {
27721
+ });
27722
+ }
27723
+ return;
27724
+ }
27668
27725
  }
27669
27726
  if (isAdminDM && msg.text.startsWith("/") && this.commandHandler) {
27670
27727
  const cmdName = msg.text.split(/\s+/)[0].slice(1).toLowerCase();
@@ -30796,6 +30853,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
30796
30853
  telegramBridge.voiceEnabled = true;
30797
30854
  }
30798
30855
  telegramBridge.setCallUrlGetter(() => voiceSession?.tunnelUrl ?? null);
30856
+ telegramBridge.setCallStarter(async () => commandCtx.callStart());
30799
30857
  telegramBridge.setCommandHandler(async (input) => {
30800
30858
  const captured = [];
30801
30859
  const origWrite = process.stdout.write;
@@ -31472,13 +31530,13 @@ NEW TASK: ${fullInput}`;
31472
31530
  writeContent(() => renderError(errMsg));
31473
31531
  if (failureStore) {
31474
31532
  try {
31475
- const { createHash: createHash2 } = await import("node:crypto");
31533
+ const { createHash: createHash3 } = await import("node:crypto");
31476
31534
  failureStore.insert({
31477
31535
  taskId: "",
31478
31536
  sessionId: `${Date.now()}`,
31479
31537
  repoRoot,
31480
31538
  failureType: "runtime-error",
31481
- fingerprint: createHash2("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
31539
+ fingerprint: createHash3("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
31482
31540
  filePath: null,
31483
31541
  errorMessage: errMsg.slice(0, 500),
31484
31542
  context: null,
@@ -31739,7 +31797,7 @@ var init_run = __esm({
31739
31797
  import { glob } from "glob";
31740
31798
  import ignore from "ignore";
31741
31799
  import { readFile as readFile14, stat as stat4 } from "node:fs/promises";
31742
- import { createHash } from "node:crypto";
31800
+ import { createHash as createHash2 } from "node:crypto";
31743
31801
  import { join as join41, relative as relative3, extname as extname10, basename as basename15 } from "node:path";
31744
31802
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
31745
31803
  var init_codebase_indexer = __esm({
@@ -31805,7 +31863,7 @@ var init_codebase_indexer = __esm({
31805
31863
  if (fileStat.size > this.config.maxFileSize)
31806
31864
  continue;
31807
31865
  const content = await readFile14(fullPath);
31808
- const hash = createHash("sha256").update(content).digest("hex");
31866
+ const hash = createHash2("sha256").update(content).digest("hex");
31809
31867
  const ext = extname10(relativePath);
31810
31868
  indexed.push({
31811
31869
  path: fullPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.54.0",
3
+ "version": "0.55.0",
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",