open-agents-ai 0.103.42 → 0.103.44

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 +85 -19
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12297,9 +12297,9 @@ async function handleCmd(cmd) {
12297
12297
  if (!peerId) { writeResp(id, { ok: false, output: 'target_peer is required' }); return; }
12298
12298
  dlog('invoke_capability: peer=' + peerId.slice(0, 20) + ' cap=' + capability);
12299
12299
  try {
12300
- // Wrap in a 90s timeout to prevent hangs from nexus library issues
12301
- const INVOKE_TIMEOUT = 90_000;
12302
- const invokePromise = nexus.invokeCapability(peerId, capability, typeof input === 'string' ? { prompt: input } : input, { stream: false, maxDurationMs: 60000 });
12300
+ // Wrap in a 300s timeout \u2014 remote API inference (Chutes, etc.) can take 60-180s for large models
12301
+ const INVOKE_TIMEOUT = 300_000;
12302
+ const invokePromise = nexus.invokeCapability(peerId, capability, typeof input === 'string' ? { prompt: input } : input, { stream: false, maxDurationMs: 240000 });
12303
12303
  const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('invoke_capability timed out after ' + (INVOKE_TIMEOUT / 1000) + 's (client-side timeout)')), INVOKE_TIMEOUT));
12304
12304
  const result = await Promise.race([invokePromise, timeoutPromise]);
12305
12305
  dlog('invoke_capability: SUCCESS');
@@ -12349,8 +12349,8 @@ async function handleCmd(cmd) {
12349
12349
  // Direct invoke on specified peer
12350
12350
  dlog('remote_infer: invoking ' + riCapName + ' on explicit peer ' + riTargetPeer.slice(0, 20));
12351
12351
  try {
12352
- var RI_TIMEOUT = 120000;
12353
- var riInvokeP = nexus.invokeCapability(riTargetPeer, riCapName, riData, { stream: false, maxDurationMs: 90000 });
12352
+ var RI_TIMEOUT = 300000; // 5 min \u2014 remote APIs (Chutes, etc.) can be slow for large models
12353
+ var riInvokeP = nexus.invokeCapability(riTargetPeer, riCapName, riData, { stream: false, maxDurationMs: 240000 });
12354
12354
  var riTimeoutP = new Promise(function(_, reject) { setTimeout(function() { reject(new Error('remote_infer timed out after ' + (RI_TIMEOUT / 1000) + 's')); }, RI_TIMEOUT); });
12355
12355
  var riResult = await Promise.race([riInvokeP, riTimeoutP]);
12356
12356
  dlog('remote_infer: SUCCESS (explicit peer)');
@@ -12378,8 +12378,8 @@ async function handleCmd(cmd) {
12378
12378
  var rPid = riCandidates[ri];
12379
12379
  dlog('remote_infer: trying peer ' + rPid.slice(0, 20) + '...');
12380
12380
  try {
12381
- var PEER_INVOKE_TIMEOUT = 30000; // 30s per peer attempt
12382
- var specInvoke = nexus.invokeCapability(rPid, riCapName, riData, { stream: false, maxDurationMs: 25000 });
12381
+ var PEER_INVOKE_TIMEOUT = 180000; // 3 min per peer \u2014 remote API inference can be slow
12382
+ var specInvoke = nexus.invokeCapability(rPid, riCapName, riData, { stream: false, maxDurationMs: 150000 });
12383
12383
  var specTimeout = new Promise(function(_, reject) {
12384
12384
  setTimeout(function() { reject(new Error('peer invoke timeout')); }, PEER_INVOKE_TIMEOUT);
12385
12385
  });
@@ -12698,7 +12698,7 @@ async function handleCmd(cmd) {
12698
12698
  } catch { /* offline \u2014 use zero rates */ }
12699
12699
 
12700
12700
  // Build pricing menu \u2014 match local models to market rates
12701
- const margin = parseFloat(args.margin || '0.5'); // default 50% of market rate
12701
+ const margin = parseFloat(args.margin || '0'); // default free \u2014 set margin > 0 to enable x402 pricing
12702
12702
  const pricingMenu = [];
12703
12703
 
12704
12704
  for (const model of models) {
@@ -12754,6 +12754,16 @@ async function handleCmd(cmd) {
12754
12754
  const logFile = join(invocationsDir, Date.now() + '-' + capName + '.json');
12755
12755
  try { writeFileSync(logFile, JSON.stringify(logEntry, null, 2)); } catch {}
12756
12756
 
12757
+ // Safe stream write \u2014 consumer may have timed out and closed the stream
12758
+ var streamClosed = false;
12759
+ async function swrite(msg) {
12760
+ if (streamClosed) return;
12761
+ try { await stream.write(msg); } catch (swErr) {
12762
+ dlog('stream.write failed (consumer likely timed out): ' + (swErr.message || swErr));
12763
+ streamClosed = true;
12764
+ }
12765
+ }
12766
+
12757
12767
  // Collect input via stream data events
12758
12768
  // NOTE: auth_key arrives in invoke.chunk data, NOT in invoke.open (request).
12759
12769
  // We must accept + read data FIRST, then validate auth.
@@ -12771,7 +12781,7 @@ async function handleCmd(cmd) {
12771
12781
  });
12772
12782
 
12773
12783
  // Accept the invocation so the consumer sends data
12774
- await stream.write({
12784
+ await swrite({
12775
12785
  type: 'invoke.accept', version: 1,
12776
12786
  requestId: request.requestId, accepted: true,
12777
12787
  });
@@ -12802,9 +12812,9 @@ async function handleCmd(cmd) {
12802
12812
  }
12803
12813
  if (reqAuthKey !== exposeAuthKey) {
12804
12814
  dlog('expose: auth REJECTED for ' + capName + ' from ' + (request.from || 'unknown'));
12805
- await stream.write({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: 0, event: 'error', data: 'Unauthorized \u2014 invalid or missing auth key' });
12806
- await stream.write({ type: 'invoke.done', version: 1, requestId: request.requestId, usage: { inputBytes: 0, outputBytes: 0 } });
12807
- stream.close();
12815
+ await swrite({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: 0, event: 'error', data: 'Unauthorized \u2014 invalid or missing auth key' });
12816
+ await swrite({ type: 'invoke.done', version: 1, requestId: request.requestId, usage: { inputBytes: 0, outputBytes: 0 } });
12817
+ try { stream.close(); } catch {}
12808
12818
  return;
12809
12819
  }
12810
12820
  dlog('expose: auth OK for ' + capName);
@@ -12837,6 +12847,7 @@ async function handleCmd(cmd) {
12837
12847
  method: 'POST',
12838
12848
  headers: chatHeaders,
12839
12849
  body: JSON.stringify(chatBody),
12850
+ signal: AbortSignal.timeout(210000), // 3.5 min \u2014 upstream API may be slow
12840
12851
  });
12841
12852
  genData = await genResp.json();
12842
12853
  dlog('expose: ollama response keys=' + Object.keys(genData).join(',') + ' choices=' + (genData.choices ? genData.choices.length : 0));
@@ -12879,6 +12890,7 @@ async function handleCmd(cmd) {
12879
12890
  messages: [{ role: 'user', content: flatPrompt }],
12880
12891
  stream: false,
12881
12892
  }),
12893
+ signal: AbortSignal.timeout(210000), // 3.5 min
12882
12894
  });
12883
12895
  genData = await genResp.json();
12884
12896
  var ptChoices = genData.choices || [];
@@ -12905,6 +12917,7 @@ async function handleCmd(cmd) {
12905
12917
  prompt: flatPrompt,
12906
12918
  stream: false,
12907
12919
  }),
12920
+ signal: AbortSignal.timeout(210000), // 3.5 min
12908
12921
  });
12909
12922
  genData = await genResp.json();
12910
12923
  output = genData.response || '';
@@ -12920,14 +12933,14 @@ async function handleCmd(cmd) {
12920
12933
  }
12921
12934
 
12922
12935
  // Stream result back
12923
- await stream.write({
12936
+ await swrite({
12924
12937
  type: 'invoke.event', version: 1,
12925
12938
  requestId: request.requestId, seq: 0,
12926
12939
  event: 'result',
12927
12940
  data: JSON.stringify(responsePayload),
12928
12941
  });
12929
12942
 
12930
- await stream.write({
12943
+ await swrite({
12931
12944
  type: 'invoke.done', version: 1,
12932
12945
  requestId: request.requestId,
12933
12946
  usage: {
@@ -12937,18 +12950,19 @@ async function handleCmd(cmd) {
12937
12950
  },
12938
12951
  });
12939
12952
  } catch (e) {
12940
- await stream.write({
12953
+ dlog('expose: inference error: ' + (e.message || e));
12954
+ await swrite({
12941
12955
  type: 'invoke.event', version: 1,
12942
12956
  requestId: request.requestId, seq: 0,
12943
12957
  event: 'error', data: 'Inference failed: ' + e.message,
12944
12958
  });
12945
- await stream.write({
12959
+ await swrite({
12946
12960
  type: 'invoke.done', version: 1,
12947
12961
  requestId: request.requestId,
12948
12962
  usage: { inputBytes: 0, outputBytes: 0 },
12949
12963
  });
12950
12964
  }
12951
- stream.close();
12965
+ try { stream.close(); } catch {}
12952
12966
  }, capOpts);
12953
12967
  }
12954
12968
  }
@@ -13347,7 +13361,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
13347
13361
  },
13348
13362
  margin: {
13349
13363
  type: "string",
13350
- description: "Price margin multiplier for expose (0.5 = 50% of market rate, 0 = free). Default: 0.5"
13364
+ description: "Price margin multiplier for expose (0.5 = 50% of market rate, 0 = free). Default: 0 (free)"
13351
13365
  },
13352
13366
  daily_limit: {
13353
13367
  type: "string",
@@ -13700,6 +13714,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
13700
13714
  }
13701
13715
  }
13702
13716
  }
13717
+ await this.ensureWallet();
13703
13718
  const daemonPath = join30(this.nexusDir, "nexus-daemon.mjs");
13704
13719
  await writeFile12(daemonPath, DAEMON_SCRIPT);
13705
13720
  const agentName = args.agent_name || "open-agents-node";
@@ -14016,6 +14031,57 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14016
14031
  `Free inference (margin=0) works without funding.`
14017
14032
  ].join("\n");
14018
14033
  }
14034
+ /**
14035
+ * Auto-create wallet + x402-wallet.key if none exists.
14036
+ * Called from doConnect() before daemon spawn so the daemon starts x402-ready.
14037
+ * Silent — no user output, just ensures the files exist.
14038
+ */
14039
+ async ensureWallet() {
14040
+ const walletPath = join30(this.nexusDir, "wallet.enc");
14041
+ if (existsSync23(walletPath))
14042
+ return;
14043
+ let address;
14044
+ let privKeyHex;
14045
+ try {
14046
+ const { privateKeyToAccount } = await import("viem/accounts");
14047
+ const privKey = randomBytes6(32);
14048
+ privKeyHex = privKey.toString("hex");
14049
+ const account = privateKeyToAccount(`0x${privKeyHex}`);
14050
+ address = account.address;
14051
+ privKey.fill(0);
14052
+ } catch {
14053
+ const privKey = randomBytes6(32);
14054
+ privKeyHex = privKey.toString("hex");
14055
+ address = "0x" + createHash("sha256").update(privKey).digest("hex").slice(0, 40);
14056
+ privKey.fill(0);
14057
+ }
14058
+ const salt = randomBytes6(32);
14059
+ const key = scryptSync(`${hostname()}:${userInfo().username}:nexus-wallet`, salt, 32, { N: 16384, r: 8, p: 1 });
14060
+ const iv = randomBytes6(16);
14061
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
14062
+ let enc = cipher.update(privKeyHex, "utf8", "hex");
14063
+ enc += cipher.final("hex");
14064
+ const x402KeyPath = join30(this.nexusDir, "x402-wallet.key");
14065
+ const x402Fh = await fsOpen(x402KeyPath, "w", 384);
14066
+ await x402Fh.writeFile("0x" + privKeyHex);
14067
+ await x402Fh.close();
14068
+ privKeyHex = "0".repeat(64);
14069
+ const w = {
14070
+ version: 2,
14071
+ address,
14072
+ encryptedKey: enc,
14073
+ iv: iv.toString("hex"),
14074
+ authTag: cipher.getAuthTag().toString("hex"),
14075
+ salt: salt.toString("hex"),
14076
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
14077
+ network: "base",
14078
+ chainId: 8453
14079
+ };
14080
+ const walletFh = await fsOpen(walletPath, "w", 384);
14081
+ await walletFh.writeFile(JSON.stringify(w, null, 2));
14082
+ await walletFh.close();
14083
+ await this.ensureDefaultBudget();
14084
+ }
14019
14085
  // ---------------------------------------------------------------------------
14020
14086
  // Step 2: USDC Balance Query via Base RPC
14021
14087
  // ---------------------------------------------------------------------------
@@ -28484,7 +28550,7 @@ ${this.formatConnectionInfo()}`);
28484
28550
  }
28485
28551
  this._targetUrl = options.targetUrl ?? DEFAULT_TARGETS[options.kind];
28486
28552
  this._stateDir = options.stateDir ?? null;
28487
- this._margin = options.margin ?? 0.5;
28553
+ this._margin = options.margin ?? 0;
28488
28554
  this._passthrough = options.passthrough ?? false;
28489
28555
  this._loadbalance = options.loadbalance ?? false;
28490
28556
  this._endpointAuth = options.endpointAuth;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.103.42",
3
+ "version": "0.103.44",
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",