open-agents-ai 0.186.17 → 0.186.19

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 +136 -30
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -38028,6 +38028,7 @@ Type /expose tunnel to retry manually, or /expose libp2p as alternative.`);
38028
38028
  this.emitStats();
38029
38029
  this.options.onInfo?.(`Tunnel restarted with new URL \u2014 share with consumers:
38030
38030
  ${this.formatConnectionInfo()}`);
38031
+ this.options.onTunnelRestart?.(this._tunnelUrl);
38031
38032
  if (this._stateDir) {
38032
38033
  writeExposeState(this._stateDir, {
38033
38034
  pid: this._cloudflaredPid,
@@ -46489,11 +46490,25 @@ async function runSponsorWizard(ctx) {
46489
46490
  }
46490
46491
  config.status = "active";
46491
46492
  saveSponsorConfig(ctx.projectDir, config);
46493
+ let goLiveSuccess = true;
46492
46494
  if (ctx.onGoLive) {
46493
- await ctx.onGoLive(config);
46495
+ try {
46496
+ const result = await ctx.onGoLive(config);
46497
+ if (result === false || result === "failed")
46498
+ goLiveSuccess = false;
46499
+ } catch {
46500
+ goLiveSuccess = false;
46501
+ }
46502
+ }
46503
+ if (goLiveSuccess) {
46504
+ renderInfo("\u2726 Sponsorship active!");
46505
+ renderInfo("Toggle: /sponsor status | Pause: /sponsor pause | Remove: /sponsor remove");
46506
+ } else {
46507
+ config.status = "inactive";
46508
+ saveSponsorConfig(ctx.projectDir, config);
46509
+ renderWarning("Sponsorship could not go live \u2014 no public endpoint available.");
46510
+ renderInfo("Fix the tunnel/P2P issue and run /sponsor again.");
46494
46511
  }
46495
- renderInfo("\u2726 Sponsorship active!");
46496
- renderInfo("Toggle: /sponsor status | Pause: /sponsor pause | Remove: /sponsor remove");
46497
46512
  return config;
46498
46513
  }
46499
46514
  var COLOR_PRESETS, GRADIENT_PRESETS, ANIM_PRESETS2;
@@ -49310,21 +49325,53 @@ import * as nodeOs from "node:os";
49310
49325
  import { execSync as nodeExecSync } from "node:child_process";
49311
49326
  import { existsSync as existsSync44, readFileSync as readFileSync33, writeFileSync as writeFileSync21, mkdirSync as mkdirSync20, readdirSync as readdirSync13, statSync as statSync15, rmSync } from "node:fs";
49312
49327
  import { join as join60 } from "node:path";
49328
+ async function _immediateReregister(newUrl) {
49329
+ if (!_lastRegisteredSponsorPayload)
49330
+ return;
49331
+ _lastRegisteredSponsorPayload.tunnelUrl = newUrl;
49332
+ _lastRegisteredSponsorPayload.status = "active";
49333
+ try {
49334
+ await fetch("https://openagents.nexus/api/v1/sponsors", {
49335
+ method: "POST",
49336
+ headers: { "Content-Type": "application/json" },
49337
+ body: JSON.stringify(_lastRegisteredSponsorPayload),
49338
+ signal: AbortSignal.timeout(1e4)
49339
+ });
49340
+ } catch {
49341
+ }
49342
+ }
49313
49343
  function startSponsorHeartbeat(payload, getExposeGateway) {
49314
49344
  stopSponsorHeartbeat();
49315
49345
  _lastRegisteredSponsorPayload = { ...payload };
49346
+ const _stableGetGateway = getExposeGateway;
49347
+ try {
49348
+ const gw = _stableGetGateway?.();
49349
+ if (gw && !gw._sponsorRestartWired) {
49350
+ gw._sponsorRestartWired = true;
49351
+ if (gw.options)
49352
+ gw.options.onTunnelRestart = _immediateReregister;
49353
+ }
49354
+ } catch {
49355
+ }
49316
49356
  const HEARTBEAT_MS = 5 * 60 * 1e3;
49317
49357
  _sponsorHeartbeatTimer = setInterval(async () => {
49318
49358
  if (!_lastRegisteredSponsorPayload)
49319
49359
  return;
49320
49360
  try {
49321
- const gw = getExposeGateway?.();
49322
- if (gw && gw.tunnelUrl && gw.tunnelUrl !== _lastRegisteredSponsorPayload.tunnelUrl) {
49323
- _lastRegisteredSponsorPayload.tunnelUrl = gw.tunnelUrl;
49361
+ const gw = _stableGetGateway?.();
49362
+ if (gw) {
49363
+ if (gw.tunnelUrl && gw.tunnelUrl !== _lastRegisteredSponsorPayload.tunnelUrl) {
49364
+ _lastRegisteredSponsorPayload.tunnelUrl = gw.tunnelUrl;
49365
+ }
49366
+ if (gw.models && Array.isArray(gw.models)) {
49367
+ _lastRegisteredSponsorPayload.models = gw.models;
49368
+ }
49324
49369
  _lastRegisteredSponsorPayload.status = "active";
49325
49370
  }
49326
49371
  } catch {
49327
49372
  }
49373
+ if (!_lastRegisteredSponsorPayload.tunnelUrl)
49374
+ return;
49328
49375
  try {
49329
49376
  await fetch("https://openagents.nexus/api/v1/sponsors", {
49330
49377
  method: "POST",
@@ -51110,6 +51157,15 @@ Clone a new voice: /voice clone <wav-file> [name]`);
51110
51157
  if (pauseGw && "setSponsorLimits" in pauseGw) {
51111
51158
  pauseGw.setSponsorLimits({ maxRequestsPerMinute: 0, maxTokensPerDay: 0, maxConcurrent: 0, allowedModels: [] });
51112
51159
  }
51160
+ try {
51161
+ await fetch("https://openagents.nexus/api/v1/sponsors", {
51162
+ method: "POST",
51163
+ headers: { "Content-Type": "application/json" },
51164
+ body: JSON.stringify({ name: existingConfig.header?.message || "unknown", status: "inactive", tunnelUrl: pauseGw?.tunnelUrl || "" }),
51165
+ signal: AbortSignal.timeout(5e3)
51166
+ });
51167
+ } catch {
51168
+ }
51113
51169
  renderInfo("Sponsorship paused. Tunnel still alive for quick resume.");
51114
51170
  renderInfo("/sponsor to resume, /sponsor remove to fully stop.");
51115
51171
  return "handled";
@@ -51165,13 +51221,44 @@ Clone a new voice: /voice clone <wav-file> [name]`);
51165
51221
  case "pause":
51166
51222
  existingConfig.status = "paused";
51167
51223
  saveSponsorConfig2(projectDir, existingConfig);
51224
+ stopSponsorHeartbeat();
51225
+ try {
51226
+ await fetch("https://openagents.nexus/api/v1/sponsors", {
51227
+ method: "POST",
51228
+ headers: { "Content-Type": "application/json" },
51229
+ body: JSON.stringify({ name: existingConfig.header?.message || "unknown", status: "inactive" }),
51230
+ signal: AbortSignal.timeout(5e3)
51231
+ });
51232
+ } catch {
51233
+ }
51168
51234
  renderInfo("Sponsorship paused. /sponsor to resume.");
51169
51235
  return "handled";
51170
- case "resume":
51236
+ case "resume": {
51171
51237
  existingConfig.status = "active";
51172
51238
  saveSponsorConfig2(projectDir, existingConfig);
51173
- renderInfo("Sponsorship resumed.");
51239
+ const resumeGw = ctx.getExposeGateway?.();
51240
+ if (resumeGw?.tunnelUrl) {
51241
+ const resumePayload = {
51242
+ name: existingConfig.header?.message || "OA Sponsor",
51243
+ tunnelUrl: resumeGw.tunnelUrl,
51244
+ authKey: resumeGw.authKey || "",
51245
+ models: [],
51246
+ status: "active"
51247
+ };
51248
+ startSponsorHeartbeat(resumePayload, ctx.getExposeGateway);
51249
+ try {
51250
+ await fetch("https://openagents.nexus/api/v1/sponsors", {
51251
+ method: "POST",
51252
+ headers: { "Content-Type": "application/json" },
51253
+ body: JSON.stringify(resumePayload),
51254
+ signal: AbortSignal.timeout(5e3)
51255
+ });
51256
+ } catch {
51257
+ }
51258
+ }
51259
+ renderInfo("Sponsorship resumed. Heartbeat restarted.");
51174
51260
  return "handled";
51261
+ }
51175
51262
  case "remove":
51176
51263
  existingConfig.status = "inactive";
51177
51264
  saveSponsorConfig2(projectDir, existingConfig);
@@ -51233,27 +51320,42 @@ Clone a new voice: /voice clone <wav-file> [name]`);
51233
51320
  let daemonReady = false;
51234
51321
  try {
51235
51322
  const nexus = new NexusTool(projectDir);
51236
- try {
51237
- await nexus.execute({ action: "disconnect" });
51238
- await new Promise((r) => setTimeout(r, 500));
51239
- } catch {
51240
- }
51241
- renderInfo("Starting nexus daemon...");
51242
- await nexus.execute({ action: "connect" });
51243
- for (let wait = 0; wait < 15; wait++) {
51244
- await new Promise((r) => setTimeout(r, 1e3));
51245
- try {
51246
- const status = await nexus.execute({ action: "status" });
51247
- if (typeof status === "string" && status.includes("connected")) {
51323
+ const curStatus = String(await nexus.execute({ action: "status" }) ?? "");
51324
+ if (/Connected:\s*true/i.test(curStatus)) {
51325
+ daemonReady = true;
51326
+ renderInfo("Using existing nexus daemon connection.");
51327
+ } else if (curStatus.includes("not running")) {
51328
+ renderInfo("Starting nexus daemon...");
51329
+ await nexus.execute({ action: "connect" });
51330
+ for (let wait = 0; wait < 25; wait++) {
51331
+ await new Promise((r) => setTimeout(r, 1e3));
51332
+ try {
51333
+ const status = String(await nexus.execute({ action: "status" }) ?? "");
51334
+ if (/Connected:\s*true/i.test(status)) {
51335
+ daemonReady = true;
51336
+ renderInfo("Nexus daemon ready.");
51337
+ break;
51338
+ }
51339
+ } catch {
51340
+ }
51341
+ }
51342
+ if (!daemonReady)
51343
+ renderWarning("Nexus daemon did not become ready in 25s. P2P may fail.");
51344
+ } else {
51345
+ renderInfo("Waiting for nexus daemon to finish connecting...");
51346
+ for (let wait = 0; wait < 15; wait++) {
51347
+ await new Promise((r) => setTimeout(r, 1e3));
51348
+ const s = String(await nexus.execute({ action: "status" }) ?? "");
51349
+ if (/Connected:\s*true/i.test(s)) {
51248
51350
  daemonReady = true;
51249
- renderInfo("Nexus daemon ready.");
51250
51351
  break;
51251
51352
  }
51252
- } catch {
51253
51353
  }
51354
+ if (daemonReady)
51355
+ renderInfo("Nexus daemon ready.");
51356
+ else
51357
+ renderWarning("Nexus daemon still connecting \u2014 P2P may be delayed.");
51254
51358
  }
51255
- if (!daemonReady)
51256
- renderWarning("Nexus daemon did not become ready in 15s. P2P may fail.");
51257
51359
  } catch (err) {
51258
51360
  renderWarning(`Nexus connect: ${err instanceof Error ? err.message : String(err)}`);
51259
51361
  }
@@ -51279,8 +51381,7 @@ Clone a new voice: /voice clone <wav-file> [name]`);
51279
51381
  const sponsorUrl = tunnelGw?.tunnelUrl || "";
51280
51382
  if (!sponsorUrl) {
51281
51383
  renderWarning("No tunnel URL available \u2014 sponsor not registered in directory. Start with cloudflared or libp2p first.");
51282
- renderInfo("Sponsor wizard completed (offline mode \u2014 no public endpoint).");
51283
- return;
51384
+ return false;
51284
51385
  }
51285
51386
  let sponsorName = (config.header.message || "").replace(/^\/+/, "").trim();
51286
51387
  if (!sponsorName || sponsorName.length < 2) {
@@ -53352,9 +53453,14 @@ async function handleSponsoredEndpoint(ctx, local) {
53352
53453
  if (sp.authKey)
53353
53454
  headers["Authorization"] = `Bearer ${sp.authKey}`;
53354
53455
  const resp = await fetch(`${base}/v1/models`, { headers, signal: AbortSignal.timeout(15e3) });
53456
+ if (resp.status === 429 || resp.status === 503)
53457
+ return true;
53355
53458
  if (!resp.ok && sp.authKey) {
53356
- const noAuth = await fetch(`${base}/v1/models`, { signal: AbortSignal.timeout(1e4) });
53357
- return noAuth.ok;
53459
+ if (resp.status === 401) {
53460
+ const noAuth = await fetch(`${base}/v1/models`, { signal: AbortSignal.timeout(1e4) });
53461
+ return noAuth.ok || noAuth.status === 429 || noAuth.status === 503;
53462
+ }
53463
+ return false;
53358
53464
  }
53359
53465
  return resp.ok;
53360
53466
  } catch {
@@ -71800,13 +71906,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
71800
71906
  if (sponsor.authKey)
71801
71907
  headers["Authorization"] = `Bearer ${sponsor.authKey}`;
71802
71908
  const probe = await fetch(testUrl, { headers, signal: AbortSignal.timeout(15e3) });
71803
- if (probe.ok) {
71909
+ if (probe.ok || probe.status === 429 || probe.status === 503) {
71804
71910
  best = sponsor;
71805
71911
  break;
71806
71912
  }
71807
71913
  if (probe.status === 401 && sponsor.authKey) {
71808
71914
  const noAuthProbe = await fetch(testUrl, { signal: AbortSignal.timeout(1e4) });
71809
- if (noAuthProbe.ok) {
71915
+ if (noAuthProbe.ok || noAuthProbe.status === 429 || noAuthProbe.status === 503) {
71810
71916
  best = sponsor;
71811
71917
  bestNoAuth = true;
71812
71918
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.186.17",
3
+ "version": "0.186.19",
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",