open-agents-ai 0.53.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 +77 -15
  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,20 +30853,21 @@ 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;
30802
- process.stdout.write = function(chunk, ...args) {
30860
+ process.stdout.write = function(chunk, ..._args) {
30803
30861
  if (typeof chunk === "string") {
30804
- const clean = chunk.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "").trim();
30805
- if (clean)
30806
- captured.push(clean);
30862
+ captured.push(chunk);
30807
30863
  }
30808
- return origWrite.call(process.stdout, chunk, ...args);
30864
+ return true;
30809
30865
  };
30810
30866
  try {
30811
30867
  const result = await handleSlashCommand(input, commandCtx);
30812
30868
  process.stdout.write = origWrite;
30869
+ if (statusBar.isActive)
30870
+ statusBar.handleResize();
30813
30871
  if (result === "exit") {
30814
30872
  return "Exit command received (ignored via Telegram).";
30815
30873
  }
@@ -30820,7 +30878,11 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
30820
30878
  rl.emit("line", input);
30821
30879
  return `Skill invoked: ${result.name}`;
30822
30880
  }
30823
- return captured.length > 0 ? captured.join("\n") : `Done: ${input}`;
30881
+ const raw = captured.join("");
30882
+ const clean = raw.replace(/\x1B\[[0-9;]*[A-Za-z]/g, "").replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B[()][A-Z0-9]/g, "").replace(/\x1B\[?\??[0-9;]*[a-zA-Z]/g, "").replace(/\x1B/g, "").replace(/[─━│┃┌┐└┘├┤┬┴┼╔╗╚╝╠╣╦╩╬⎿⎾▕▏⏐]/g, "").replace(/\n{3,}/g, "\n\n").trim();
30883
+ if (!clean)
30884
+ return `Done: ${input}`;
30885
+ return clean.length > 3900 ? clean.slice(0, 3900) + "\n..." : clean;
30824
30886
  } catch (err) {
30825
30887
  process.stdout.write = origWrite;
30826
30888
  throw err;
@@ -31468,13 +31530,13 @@ NEW TASK: ${fullInput}`;
31468
31530
  writeContent(() => renderError(errMsg));
31469
31531
  if (failureStore) {
31470
31532
  try {
31471
- const { createHash: createHash2 } = await import("node:crypto");
31533
+ const { createHash: createHash3 } = await import("node:crypto");
31472
31534
  failureStore.insert({
31473
31535
  taskId: "",
31474
31536
  sessionId: `${Date.now()}`,
31475
31537
  repoRoot,
31476
31538
  failureType: "runtime-error",
31477
- 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),
31478
31540
  filePath: null,
31479
31541
  errorMessage: errMsg.slice(0, 500),
31480
31542
  context: null,
@@ -31735,7 +31797,7 @@ var init_run = __esm({
31735
31797
  import { glob } from "glob";
31736
31798
  import ignore from "ignore";
31737
31799
  import { readFile as readFile14, stat as stat4 } from "node:fs/promises";
31738
- import { createHash } from "node:crypto";
31800
+ import { createHash as createHash2 } from "node:crypto";
31739
31801
  import { join as join41, relative as relative3, extname as extname10, basename as basename15 } from "node:path";
31740
31802
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
31741
31803
  var init_codebase_indexer = __esm({
@@ -31801,7 +31863,7 @@ var init_codebase_indexer = __esm({
31801
31863
  if (fileStat.size > this.config.maxFileSize)
31802
31864
  continue;
31803
31865
  const content = await readFile14(fullPath);
31804
- const hash = createHash("sha256").update(content).digest("hex");
31866
+ const hash = createHash2("sha256").update(content).digest("hex");
31805
31867
  const ext = extname10(relativePath);
31806
31868
  indexed.push({
31807
31869
  path: fullPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.53.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",