open-agents-ai 0.187.578 → 0.187.579

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.
package/dist/index.js CHANGED
@@ -65,7 +65,7 @@ function parseBackendType(value2) {
65
65
  return VALID_BACKEND_TYPES.has(value2) ? value2 : void 0;
66
66
  }
67
67
  function loadConfigFile() {
68
- const configPath2 = join(homedir(), ".open-agents", "config.json");
68
+ const configPath2 = join(openAgentsConfigDir(), "config.json");
69
69
  if (!existsSync(configPath2)) return {};
70
70
  try {
71
71
  const raw = readFileSync(configPath2, "utf8");
@@ -110,13 +110,16 @@ function mergeConfig(base3, overrides) {
110
110
  return { ...base3, ...overrides };
111
111
  }
112
112
  function setConfigValue(key, value2) {
113
- const dir = join(homedir(), ".open-agents");
113
+ const dir = openAgentsConfigDir();
114
114
  mkdirSync(dir, { recursive: true });
115
115
  const configPath2 = join(dir, "config.json");
116
116
  const existing = loadConfigFile();
117
117
  existing[key] = coerceConfigValue(key, value2);
118
118
  writeFileSync(configPath2, JSON.stringify(existing, null, 2) + "\n", { encoding: "utf8", mode: 384 });
119
119
  }
120
+ function openAgentsConfigDir() {
121
+ return join(process.env["OPEN_AGENTS_CONFIG_HOME"] ?? homedir(), ".open-agents");
122
+ }
120
123
  function coerceConfigValue(key, value2) {
121
124
  const intKeys = /* @__PURE__ */ new Set(["maxRetries", "timeoutMs"]);
122
125
  const boolKeys = /* @__PURE__ */ new Set(["dryRun", "verbose"]);
@@ -594439,6 +594442,18 @@ async function runCommand(input, opts) {
594439
594442
  const argsStr = rest.join(" ");
594440
594443
  const release = await acquireLock2();
594441
594444
  try {
594445
+ const quick2 = buildNonInteractiveSummary(cmdName, argsStr, opts?.config);
594446
+ if (quick2) {
594447
+ return {
594448
+ ok: true,
594449
+ command: cmdName,
594450
+ args: argsStr,
594451
+ kind: "handled",
594452
+ output: quick2,
594453
+ ansi: quick2,
594454
+ durationMs: Date.now() - start2
594455
+ };
594456
+ }
594442
594457
  const buf = [];
594443
594458
  setContentWriteHook({
594444
594459
  begin: () => {
@@ -594489,6 +594504,43 @@ async function runCommand(input, opts) {
594489
594504
  release();
594490
594505
  }
594491
594506
  }
594507
+ function buildNonInteractiveSummary(cmdName, _args, config) {
594508
+ const cfg = config ?? loadConfig();
594509
+ if (cmdName === "setup" || cmdName === "wizard") {
594510
+ return [
594511
+ "open-agents setup",
594512
+ "",
594513
+ "The setup wizard is an interactive terminal flow. In the GUI command bridge it is summarized instead of opening prompts, installing software, starting Ollama, or pulling models.",
594514
+ "",
594515
+ `Current backend: ${cfg.backendType ?? "ollama"}`,
594516
+ `Current endpoint: ${cfg.backendUrl ?? "http://127.0.0.1:11434"}`,
594517
+ `Current model: ${cfg.model ?? "qwen3.5:latest"}`,
594518
+ "",
594519
+ "Available non-interactive setup actions:",
594520
+ " /endpoint <url> Set or inspect the inference endpoint.",
594521
+ " /model <name> Set the active model directly.",
594522
+ " /models Show model-selection guidance.",
594523
+ " /config Inspect persisted configuration.",
594524
+ " /doctor Run diagnostics from the terminal if deeper repair is needed.",
594525
+ "",
594526
+ "Open a terminal and run `oa`, then use /setup for the full guided wizard."
594527
+ ].join("\n");
594528
+ }
594529
+ if (cmdName === "models") {
594530
+ return [
594531
+ "open-agents models",
594532
+ "",
594533
+ "The model picker is interactive in the TUI. The GUI bridge does not probe remote model endpoints here, so it cannot hang on a stale backend.",
594534
+ "",
594535
+ `Active model: ${cfg.model ?? "qwen3.5:latest"}`,
594536
+ `Endpoint: ${cfg.backendUrl ?? "http://127.0.0.1:11434"}`,
594537
+ `Backend: ${cfg.backendType ?? "ollama"}`,
594538
+ "",
594539
+ "Use /model <name> to set a model directly, /endpoint to switch providers, or open the TUI for the searchable model picker."
594540
+ ].join("\n");
594541
+ }
594542
+ return null;
594543
+ }
594492
594544
  function acquireLock2() {
594493
594545
  let release;
594494
594546
  const next = new Promise((res) => {
@@ -607320,6 +607372,7 @@ async function refreshEndpointRegistry() {
607320
607372
  type: config.backendType || "ollama",
607321
607373
  authKey: config.apiKey
607322
607374
  });
607375
+ if (process.env["OA_SKIP_SPONSOR_DISCOVERY"] === "1") return;
607323
607376
  try {
607324
607377
  const resp = await fetch("https://openagents.nexus/api/v1/sponsors", {
607325
607378
  signal: AbortSignal.timeout(5e3)
@@ -607440,6 +607493,16 @@ function getBackendTimeoutMs(perRequestSeconds) {
607440
607493
  }
607441
607494
  return BACKEND_TIMEOUT_DEFAULT_MS;
607442
607495
  }
607496
+ function getModelListTimeoutMs() {
607497
+ const envS = process.env["OA_MODEL_LIST_TIMEOUT_S"];
607498
+ if (envS) {
607499
+ const n2 = parseFloat(envS);
607500
+ if (Number.isFinite(n2) && n2 > 0) {
607501
+ return Math.min(Math.floor(n2 * 1e3), 3e4);
607502
+ }
607503
+ }
607504
+ return MODEL_LIST_TIMEOUT_DEFAULT_MS;
607505
+ }
607443
607506
  function recordMetric(method, path11, status) {
607444
607507
  const key = `${method}|${path11}|${status}`;
607445
607508
  const existing = metrics.requests.get(key);
@@ -607879,10 +607942,12 @@ function ollamaRequest(ollamaUrl, path11, method, body, timeoutMs) {
607879
607942
  }
607880
607943
  };
607881
607944
  const transport = isHttps ? https3 : http5;
607945
+ const _to = getBackendTimeoutMs(timeoutMs ? timeoutMs / 1e3 : void 0);
607882
607946
  const proxyReq = transport.request(options2, (proxyRes) => {
607883
607947
  const chunks = [];
607884
607948
  proxyRes.on("data", (chunk) => chunks.push(chunk));
607885
607949
  proxyRes.on("end", () => {
607950
+ clearTimeout(hardTimeout);
607886
607951
  resolve43({
607887
607952
  status: proxyRes.statusCode ?? 500,
607888
607953
  headers: proxyRes.headers,
@@ -607890,11 +607955,17 @@ function ollamaRequest(ollamaUrl, path11, method, body, timeoutMs) {
607890
607955
  });
607891
607956
  });
607892
607957
  });
607893
- const _to = getBackendTimeoutMs(timeoutMs ? timeoutMs / 1e3 : void 0);
607958
+ const hardTimeout = setTimeout(() => {
607959
+ proxyReq.destroy(new Error(`Backend request timeout (${Math.round(_to / 1e3)}s)`));
607960
+ }, _to);
607961
+ hardTimeout.unref();
607894
607962
  proxyReq.setTimeout(_to, () => {
607895
607963
  proxyReq.destroy(new Error(`Backend request timeout (${Math.round(_to / 1e3)}s)`));
607896
607964
  });
607897
- proxyReq.on("error", reject);
607965
+ proxyReq.on("error", (err) => {
607966
+ clearTimeout(hardTimeout);
607967
+ reject(err);
607968
+ });
607898
607969
  if (body) proxyReq.write(body);
607899
607970
  proxyReq.end();
607900
607971
  });
@@ -608670,7 +608741,7 @@ async function fetchAggregatedOllamaTags() {
608670
608741
  try {
608671
608742
  const isOllama = ep.type === "ollama";
608672
608743
  const path11 = isOllama ? "/api/tags" : "/v1/models";
608673
- const result = await ollamaRequest(ep.url, path11, "GET");
608744
+ const result = await ollamaRequest(ep.url, path11, "GET", void 0, getModelListTimeoutMs());
608674
608745
  if (result.status !== 200) return;
608675
608746
  const body = JSON.parse(result.body);
608676
608747
  if (isOllama) {
@@ -608727,6 +608798,10 @@ async function fetchAggregatedOllamaTags() {
608727
608798
  return out.sort((a2, b) => a2.name.localeCompare(b.name));
608728
608799
  }
608729
608800
  async function handleApiTags(res) {
608801
+ if (process.env["OA_API_TEST_MODE"] === "1") {
608802
+ jsonResponse(res, 200, { models: [] });
608803
+ return;
608804
+ }
608730
608805
  try {
608731
608806
  const models = await fetchAggregatedOllamaTags();
608732
608807
  jsonResponse(res, 200, { models });
@@ -611272,8 +611347,16 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
611272
611347
  jsonResponse(res, 400, { error: "missing_text" });
611273
611348
  return;
611274
611349
  }
611350
+ const voiceStatus = getRuntimeStatus();
611351
+ if (!voiceStatus.voiceReady) {
611352
+ jsonResponse(res, 501, {
611353
+ error: "tts_not_ready",
611354
+ message: "Voice synthesis is not ready in the daemon. Warm the voice runtime with POST /v1/voice/start before requesting audio.",
611355
+ state: voiceStatus
611356
+ });
611357
+ return;
611358
+ }
611275
611359
  try {
611276
- await ensureRuntime();
611277
611360
  const ve = getVoiceEngine();
611278
611361
  let prevModel = null;
611279
611362
  if (requestedModel && ve.modelId !== requestedModel) {
@@ -613510,6 +613593,7 @@ function startApiServer(options2 = {}) {
613510
613593
  if (options2.host) host = options2.host;
613511
613594
  if (options2.port) port = options2.port;
613512
613595
  const verbose = options2.verbose ?? false;
613596
+ const apiTestMode = process.env["OA_API_TEST_MODE"] === "1";
613513
613597
  const config = loadConfig();
613514
613598
  const ollamaUrl = options2.ollamaUrl ?? config.backendUrl;
613515
613599
  const cwd4 = process.cwd();
@@ -613529,31 +613613,37 @@ function startApiServer(options2 = {}) {
613529
613613
  taskMgr.onEviction((taskId) => {
613530
613614
  deleteAgentTaskSidecar(taskId);
613531
613615
  });
613532
- restoreAgentTasks(taskMgr).then((report2) => {
613533
- if (report2.restored > 0) {
613534
- log22(` task recovery: restored=${report2.restored} re-attached=${report2.reAttached} marked-failed=${report2.markedFailed}
613616
+ if (!apiTestMode) {
613617
+ restoreAgentTasks(taskMgr).then((report2) => {
613618
+ if (report2.restored > 0) {
613619
+ log22(` task recovery: restored=${report2.restored} re-attached=${report2.reAttached} marked-failed=${report2.markedFailed}
613535
613620
  `);
613536
- }
613537
- }).catch(() => {
613538
- });
613539
- setTimeout(() => {
613540
- try {
613541
- purgeOldSidecars(24);
613542
- } catch {
613543
- }
613544
- }, 5e3).unref();
613621
+ }
613622
+ }).catch(() => {
613623
+ });
613624
+ }
613625
+ if (!apiTestMode) {
613626
+ setTimeout(() => {
613627
+ try {
613628
+ purgeOldSidecars(24);
613629
+ } catch {
613630
+ }
613631
+ }, 5e3).unref();
613632
+ }
613545
613633
  } catch {
613546
613634
  }
613547
- try {
613548
- const report2 = loadPersistedSessions();
613549
- if (report2.restored > 0 || report2.staleInFlight > 0) {
613550
- log22(` chat sessions: restored=${report2.restored} stale-in-flight=${report2.staleInFlight}
613635
+ if (!apiTestMode) {
613636
+ try {
613637
+ const report2 = loadPersistedSessions();
613638
+ if (report2.restored > 0 || report2.staleInFlight > 0) {
613639
+ log22(` chat sessions: restored=${report2.restored} stale-in-flight=${report2.staleInFlight}
613551
613640
  `);
613641
+ }
613642
+ } catch {
613552
613643
  }
613553
- } catch {
613554
613644
  }
613555
613645
  setTodoEventPublisher(null);
613556
- try {
613646
+ if (!apiTestMode) try {
613557
613647
  const dir = todoDir();
613558
613648
  try {
613559
613649
  mkdirSync69(dir, { recursive: true });
@@ -613630,7 +613720,7 @@ function startApiServer(options2 = {}) {
613630
613720
  `);
613631
613721
  }
613632
613722
  const retentionDays = parseInt(process.env["OA_JOB_RETENTION_DAYS"] ?? "30", 10);
613633
- if (retentionDays > 0) {
613723
+ if (!apiTestMode && retentionDays > 0) {
613634
613724
  try {
613635
613725
  const jobsDir3 = join129(cwd4, ".oa", "jobs");
613636
613726
  if (existsSync113(jobsDir3)) {
@@ -613681,9 +613771,12 @@ function startApiServer(options2 = {}) {
613681
613771
  }
613682
613772
  let _accessRejected = 0;
613683
613773
  const handler = (req2, res) => {
613774
+ const requestId = req2.headers["x-request-id"] || randomUUID16();
613775
+ res.setHeader("X-Request-ID", requestId);
613776
+ res.setHeader("X-API-Version", API_VERSION);
613684
613777
  const rawIp = req2.socket?.remoteAddress ?? "";
613685
613778
  const hasBearer = typeof req2.headers["authorization"] === "string" && req2.headers["authorization"].startsWith("Bearer ");
613686
- const anyKeyConfigured = Boolean(
613779
+ const anyKeyConfigured = hasBearer && Boolean(
613687
613780
  process.env["OA_API_KEY"] || process.env["OA_API_KEYS"] || runtimeKeysExist()
613688
613781
  );
613689
613782
  if (!isAllowedIP(rawIp, runtimeAccessMode) && !(hasBearer && anyKeyConfigured)) {
@@ -613770,10 +613863,6 @@ function startApiServer(options2 = {}) {
613770
613863
  handleEntitiesList(req2, res);
613771
613864
  return;
613772
613865
  }
613773
- if (req2.method === "POST" && url.pathname === "/v1/memory/search") {
613774
- handleMemorySearch2(req2, res);
613775
- return;
613776
- }
613777
613866
  } catch {
613778
613867
  }
613779
613868
  handleRequest(req2, res, ollamaUrl, verbose).catch((err) => {
@@ -614024,6 +614113,10 @@ function startApiServer(options2 = {}) {
614024
614113
  `);
614025
614114
  log22(` Primary: ${config.backendUrl} (${config.backendType || "ollama"})
614026
614115
  `);
614116
+ if (apiTestMode) {
614117
+ void refreshEndpointRegistry();
614118
+ return;
614119
+ }
614027
614120
  try {
614028
614121
  const { writeFileSync: writeFileSync67, mkdirSync: mkdirSync74, existsSync: _exists, readFileSync: _rfs } = require3("node:fs");
614029
614122
  const { join: _join } = require3("node:path");
@@ -614451,28 +614544,6 @@ async function handleEntitiesList(req2, res) {
614451
614544
  jsonResponse(res, 500, { error: "server_error", message: err instanceof Error ? err.message : String(err) });
614452
614545
  }
614453
614546
  }
614454
- async function handleMemorySearch2(req2, res) {
614455
- try {
614456
- const body = await parseJsonBody(req2);
614457
- if (!body || typeof body !== "object") {
614458
- jsonResponse(res, 400, { error: "bad_request" });
614459
- return;
614460
- }
614461
- const b = body;
614462
- const query = String(b.query || "");
614463
- const modality = b.modality ? String(b.modality) : void 0;
614464
- const limit = b.limit ? Math.max(1, Math.min(200, parseInt(String(b.limit), 10))) : 20;
614465
- const qEmb = Array.isArray(b.query_embedding) ? new Float32Array(b.query_embedding) : null;
614466
- const wLex = typeof b.lexical_weight === "number" ? b.lexical_weight : 1;
614467
- const wEmb = typeof b.embedding_weight === "number" ? b.embedding_weight : 1;
614468
- const { EpisodeStore: EpisodeStore3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
614469
- const epStore = new EpisodeStore3(join129(process.cwd(), ".oa", "memory.db"));
614470
- const results = epStore.search({ query, modality, limit }, { queryEmbedding: qEmb, lexicalWeight: wLex, embeddingWeight: wEmb });
614471
- jsonResponse(res, 200, { object: "list", data: results.map((e2) => ({ id: e2.id, modality: e2.modality, content: e2.content, timestamp: e2.timestamp })) });
614472
- } catch (err) {
614473
- jsonResponse(res, 500, { error: "server_error", message: err instanceof Error ? err.message : String(err) });
614474
- }
614475
- }
614476
614547
  async function apiServeCommand(opts, config) {
614477
614548
  const server2 = startApiServer({
614478
614549
  port: opts.port,
@@ -614533,7 +614604,7 @@ function setTimerEnabled(name10, enabled2) {
614533
614604
  return false;
614534
614605
  }
614535
614606
  }
614536
- var require3, endpointRegistry, modelRouteMap, endpointUsage, _lastEndpointDiagnostics, BACKEND_TIMEOUT_DEFAULT_MS, BACKEND_TIMEOUT_MAX_MS, metrics, startedAt, runningProcesses, perKeyUsage, CRON_MARKER2;
614607
+ var require3, endpointRegistry, modelRouteMap, endpointUsage, _lastEndpointDiagnostics, BACKEND_TIMEOUT_DEFAULT_MS, BACKEND_TIMEOUT_MAX_MS, MODEL_LIST_TIMEOUT_DEFAULT_MS, metrics, startedAt, runningProcesses, perKeyUsage, CRON_MARKER2;
614537
614608
  var init_serve = __esm({
614538
614609
  "packages/cli/src/api/serve.ts"() {
614539
614610
  "use strict";
@@ -614569,6 +614640,7 @@ var init_serve = __esm({
614569
614640
  _lastEndpointDiagnostics = [];
614570
614641
  BACKEND_TIMEOUT_DEFAULT_MS = 12e4;
614571
614642
  BACKEND_TIMEOUT_MAX_MS = 36e5;
614643
+ MODEL_LIST_TIMEOUT_DEFAULT_MS = 1500;
614572
614644
  metrics = {
614573
614645
  requests: /* @__PURE__ */ new Map(),
614574
614646
  totalTokensIn: 0,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.578",
3
+ "version": "0.187.579",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "open-agents-ai",
9
- "version": "0.187.578",
9
+ "version": "0.187.579",
10
10
  "hasInstallScript": true,
11
11
  "license": "CC-BY-NC-4.0",
12
12
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.578",
3
+ "version": "0.187.579",
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",