open-agents-ai 0.138.47 → 0.138.49

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 +156 -22
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14273,6 +14273,8 @@ const nexus = new NexusClient(nexusOpts);
14273
14273
  const rooms = new Map();
14274
14274
  let connected = false;
14275
14275
  const blockedPeers = [];
14276
+ let cohereActive = false;
14277
+ const cohereDedup = new Map(); // queryId -> timestamp (60s TTL dedup)
14276
14278
 
14277
14279
  // NATS invoke relay \u2014 for cross-NAT fallback when direct libp2p dial fails.
14278
14280
  // Both peers connect to wss://demo.nats.io:8443, so NATS request/reply bridges the gap.
@@ -14997,6 +14999,20 @@ async function handleCmd(cmd) {
14997
14999
  break;
14998
15000
  }
14999
15001
 
15002
+ // \u2500\u2500 COHERE distributed inference toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
15003
+ case 'cohere_enable': {
15004
+ cohereActive = true;
15005
+ dlog('COHERE query handler enabled \u2014 listening on nexus.cohere.query');
15006
+ writeResp(id, { ok: true, output: 'COHERE inference handler enabled' });
15007
+ break;
15008
+ }
15009
+ case 'cohere_disable': {
15010
+ cohereActive = false;
15011
+ dlog('COHERE query handler disabled');
15012
+ writeResp(id, { ok: true, output: 'COHERE inference handler disabled' });
15013
+ break;
15014
+ }
15015
+
15000
15016
  // \u2500\u2500 Metered Inference Exposure \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
15001
15017
  case 'expose': {
15002
15018
  // Clear old inference capabilities before registering new ones
@@ -16000,6 +16016,86 @@ process.on('unhandledRejection', (reason) => {
16000
16016
  dlog('NATS invoke relay setup failed: ' + (_nSetupErr.message || _nSetupErr));
16001
16017
  }
16002
16018
 
16019
+ // \u2500\u2500 COHERE distributed inference handler \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
16020
+ // Subscribe to nexus.cohere.query, process through local Ollama,
16021
+ // publish response to nexus.cohere.response.
16022
+ // Privacy: handler constructs ISOLATED messages \u2014 no history, no system prompt.
16023
+ if (_natsConn && _natsCodec) {
16024
+ const _cohereSub = _natsConn.subscribe('nexus.cohere.query');
16025
+ (async function() {
16026
+ for await (const _cMsg of _cohereSub) {
16027
+ if (!cohereActive) continue;
16028
+ try {
16029
+ const _cData = JSON.parse(_natsCodec.decode(_cMsg.data));
16030
+ if (!_cData.queryId || !_cData.query) continue;
16031
+ // Dedup: skip if we already processed this queryId
16032
+ if (cohereDedup.has(_cData.queryId)) continue;
16033
+ cohereDedup.set(_cData.queryId, Date.now());
16034
+ // Prune dedup map (60s TTL)
16035
+ const _cNow = Date.now();
16036
+ for (const [_cK, _cV] of cohereDedup) { if (_cNow - _cV > 60000) cohereDedup.delete(_cK); }
16037
+ // Random jitter 0-2s to prevent all nodes racing
16038
+ await new Promise(function(r) { setTimeout(r, Math.random() * 2000); });
16039
+ // Skip if another node already responded (check dedup again after jitter)
16040
+ if (!cohereActive) continue;
16041
+ dlog('COHERE query: ' + _cData.queryId + ' \u2014 ' + (_cData.query || '').slice(0, 80));
16042
+ const _cStart = Date.now();
16043
+ // Query local Ollama \u2014 ISOLATED context (no history, no system prompt)
16044
+ const _cOllamaUrl = process.env.OLLAMA_HOST || 'http://localhost:11434';
16045
+ let _cModel = '';
16046
+ try {
16047
+ const _cTags = await fetch(_cOllamaUrl + '/api/tags').then(function(r) { return r.json(); });
16048
+ const _cModels = (_cTags.models || []).filter(function(m) { return !/embed|nomic/i.test(m.name); });
16049
+ _cModels.sort(function(a, b) { return (b.size || 0) - (a.size || 0); });
16050
+ _cModel = _cModels.length > 0 ? _cModels[0].name : '';
16051
+ } catch {}
16052
+ if (!_cModel) { dlog('COHERE: no Ollama models available'); continue; }
16053
+ try {
16054
+ const _cResp = await fetch(_cOllamaUrl + '/api/chat', {
16055
+ method: 'POST',
16056
+ headers: { 'Content-Type': 'application/json' },
16057
+ body: JSON.stringify({
16058
+ model: _cModel,
16059
+ messages: [{ role: 'user', content: _cData.query }],
16060
+ stream: false,
16061
+ }),
16062
+ signal: AbortSignal.timeout(120000),
16063
+ });
16064
+ const _cResult = await _cResp.json();
16065
+ const _cContent = _cResult.message ? _cResult.message.content : '';
16066
+ const _cLatency = Date.now() - _cStart;
16067
+ // Sign response for accountability (HMAC-SHA256 with peerId)
16068
+ const _cSigData = _cData.queryId + ':' + _cContent.slice(0, 200) + ':' + _cModel + ':' + _cLatency;
16069
+ const _cSig = require('crypto').createHmac('sha256', nexus.peerId).update(_cSigData).digest('hex').slice(0, 32);
16070
+ // Scan inbound query for leaked secrets (defense-in-depth)
16071
+ const _cSecretPatterns = [/sk-[a-zA-Z0-9]{20,}/g, /ghp_[a-zA-Z0-9]{36,}/g, /AKIA[0-9A-Z]{16}/g];
16072
+ for (const _cPat of _cSecretPatterns) {
16073
+ if (_cPat.test(_cData.query)) { dlog('COHERE WARNING: inbound query contains potential secret!'); break; }
16074
+ }
16075
+ // Publish response
16076
+ _natsConn.publish('nexus.cohere.response', _natsCodec.encode(JSON.stringify({
16077
+ type: 'cohere.response',
16078
+ queryId: _cData.queryId,
16079
+ content: _cContent,
16080
+ model: _cModel,
16081
+ provider: nexus.peerId,
16082
+ agentName: nexus.agentName || ('oa-' + require('os').hostname().slice(0, 12)),
16083
+ latencyMs: _cLatency,
16084
+ usage: _cResult.eval_count ? { inputTokens: _cResult.prompt_eval_count || 0, outputTokens: _cResult.eval_count || 0 } : undefined,
16085
+ signature: _cSig,
16086
+ })));
16087
+ dlog('COHERE response: ' + _cData.queryId + ' model=' + _cModel + ' ' + _cLatency + 'ms');
16088
+ } catch (_cErr) {
16089
+ dlog('COHERE inference error: ' + (_cErr.message || _cErr));
16090
+ }
16091
+ } catch (_cParseErr) {
16092
+ // Malformed message \u2014 skip
16093
+ }
16094
+ }
16095
+ })().catch(function(e) { dlog('COHERE query handler loop error: ' + (e.message || e)); });
16096
+ dlog('COHERE query handler subscribed to nexus.cohere.query');
16097
+ }
16098
+
16003
16099
  writeStatus();
16004
16100
  console.log('Nexus daemon connected as ' + nexus.peerId);
16005
16101
  } catch (err) {
@@ -16065,9 +16161,11 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
16065
16161
  "budget_set",
16066
16162
  "spend",
16067
16163
  "remote_infer",
16068
- "cohere_status"
16164
+ "cohere_status",
16165
+ "cohere_enable",
16166
+ "cohere_disable"
16069
16167
  ],
16070
- description: "The nexus action. MUST call 'connect' first (spawns daemon). Then: join_room, send_message, discover_peers, expose, status, cohere_status, etc."
16168
+ description: "The nexus action. MUST call 'connect' first (spawns daemon). Then: join_room, send_message, discover_peers, expose, status, cohere_status, cohere_enable, cohere_disable, etc."
16071
16169
  },
16072
16170
  room_id: {
16073
16171
  type: "string",
@@ -16280,6 +16378,12 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
16280
16378
  case "cohere_status":
16281
16379
  result = await this.doCohereSummary();
16282
16380
  break;
16381
+ case "cohere_enable":
16382
+ result = await this.sendDaemonCmd("cohere_enable", {});
16383
+ break;
16384
+ case "cohere_disable":
16385
+ result = await this.sendDaemonCmd("cohere_disable", {});
16386
+ break;
16283
16387
  default:
16284
16388
  return { success: false, output: "", error: `Unknown nexus action: ${action}`, durationMs: Date.now() - start };
16285
16389
  }
@@ -44638,6 +44742,9 @@ var init_banner = __esm({
44638
44742
  const row = frame.grid[r];
44639
44743
  if (!row)
44640
44744
  continue;
44745
+ if (r === 1 && this.currentDesign?.type === "default") {
44746
+ buf += `\x1B]8;;file://${process.cwd()}\x07`;
44747
+ }
44641
44748
  let prevFg = -1, prevBg = -1, prevBold = false;
44642
44749
  for (let c3 = 0; c3 < Math.min(this.width, row.length); c3++) {
44643
44750
  const cell = row[c3];
@@ -44657,6 +44764,9 @@ var init_banner = __esm({
44657
44764
  buf += seq + cell.char;
44658
44765
  }
44659
44766
  buf += "\x1B[0m";
44767
+ if (r === 1 && this.currentDesign?.type === "default") {
44768
+ buf += "\x1B]8;;\x07";
44769
+ }
44660
44770
  }
44661
44771
  buf += "\x1B8";
44662
44772
  process.stdout.write(buf);
@@ -52215,7 +52325,7 @@ ${CONTENT_BG_SEQ}`);
52215
52325
  * before readline splits them into garbage text. Scroll wheel support
52216
52326
  * is keyboard-only (Page Up/Down, Shift+Up/Down).
52217
52327
  */
52218
- hookReadlineScroll(rl, onEscape) {
52328
+ hookReadlineScroll(rl, onEscape, onCtrlO) {
52219
52329
  if (!rl || !rl._ttyWrite)
52220
52330
  return;
52221
52331
  const self = this;
@@ -52233,6 +52343,10 @@ ${CONTENT_BG_SEQ}`);
52233
52343
  if (cursor <= 0)
52234
52344
  return;
52235
52345
  }
52346
+ if (key?.ctrl && key?.name === "o" && onCtrlO) {
52347
+ onCtrlO();
52348
+ return;
52349
+ }
52236
52350
  if (s && (/\x1B\[</.test(s) || /^\d+;\d+;\d*[Mm]/.test(s) || /^;\d+[Mm]/.test(s) || /\[<\d/.test(s))) {
52237
52351
  return;
52238
52352
  }
@@ -54083,6 +54197,12 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
54083
54197
  let _escapeHandler = null;
54084
54198
  statusBar.hookReadlineScroll(rl, () => {
54085
54199
  _escapeHandler?.();
54200
+ }, () => {
54201
+ if (sudoPromptPending) {
54202
+ passwordShowPlain = !passwordShowPlain;
54203
+ if (statusBar.isActive)
54204
+ statusBar.handleResize();
54205
+ }
54086
54206
  });
54087
54207
  rl.output = null;
54088
54208
  if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
@@ -54337,6 +54457,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
54337
54457
  }
54338
54458
  })().catch(() => {
54339
54459
  });
54460
+ let passwordShowPlain = false;
54340
54461
  function handleSudoRequest(_command) {
54341
54462
  if (sudoPromptPending)
54342
54463
  return;
@@ -54345,12 +54466,20 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
54345
54466
  return;
54346
54467
  }
54347
54468
  sudoPromptPending = true;
54348
- const sudoPromptStr = ` ${c2.bold(c2.yellow("\u{1F511} Password:"))} `;
54349
- if (isNeovimActive()) {
54350
- writeToNeovimOutput(sudoPromptStr);
54351
- } else {
54352
- process.stdout.write(sudoPromptStr);
54469
+ writeContent(() => renderInfo("Password required for sudo. Type below, Enter to submit. Ctrl+O to show/hide."));
54470
+ const pwPrompt = `\x1B[38;5;178m\u{1F511}\x1B[0m `;
54471
+ rl.setPrompt(pwPrompt);
54472
+ if (statusBar.isActive) {
54473
+ const origProvider = statusBar.inputStateProvider;
54474
+ statusBar.inputStateProvider = () => {
54475
+ const state = origProvider?.() ?? { line: "", cursor: 0 };
54476
+ if (passwordShowPlain)
54477
+ return state;
54478
+ return { line: "\u25CF".repeat(state.line.length), cursor: state.cursor };
54479
+ };
54480
+ statusBar.setPromptText(pwPrompt, 3);
54353
54481
  }
54482
+ showPrompt();
54354
54483
  }
54355
54484
  async function handleAskUser(question, options, allowMultiple) {
54356
54485
  if (statusBar?.isActive)
@@ -54586,6 +54715,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
54586
54715
  statusBar.setCohereActive(cohereEnabled);
54587
54716
  saveProjectSettings(repoRoot, { cohere: cohereEnabled });
54588
54717
  saveGlobalSettings({ cohere: cohereEnabled });
54718
+ try {
54719
+ const { NexusTool: NexusTool2 } = __require("../../execution/dist/tools/nexus.js");
54720
+ const nexusTool = new NexusTool2(repoRoot);
54721
+ nexusTool.execute({ action: cohereEnabled ? "cohere_enable" : "cohere_disable" }).catch(() => {
54722
+ });
54723
+ } catch {
54724
+ }
54589
54725
  return cohereEnabled;
54590
54726
  },
54591
54727
  isCohere() {
@@ -55686,28 +55822,26 @@ ${result.content.slice(0, 2e3)}${result.content.length > 2e3 ? "\n[truncated]" :
55686
55822
  async function processLine(input) {
55687
55823
  if (depSudoPromptPending && depSudoResolver) {
55688
55824
  const pw = input.trim();
55689
- const pwRecvMsg = `\r\x1B[K ${c2.dim("\u{1F511} Password received")}
55690
- `;
55691
- if (isNeovimActive()) {
55692
- writeToNeovimOutput(pwRecvMsg);
55693
- } else {
55694
- process.stdout.write(pwRecvMsg);
55695
- }
55825
+ passwordShowPlain = false;
55826
+ statusBar.setInputStateProvider(() => ({
55827
+ line: rl.line ?? "",
55828
+ cursor: rl.cursor ?? 0
55829
+ }));
55830
+ writeContent(() => renderInfo("\u{1F511} Password received"));
55696
55831
  depSudoResolver(pw || null);
55697
55832
  showPrompt();
55698
55833
  return;
55699
55834
  }
55700
55835
  if (sudoPromptPending && activeTask) {
55701
55836
  sudoPromptPending = false;
55837
+ passwordShowPlain = false;
55702
55838
  sessionSudoPassword = input;
55703
55839
  activeTask.runner.setSudoPassword(input);
55704
- const pwRecvMsg2 = `\r\x1B[K ${c2.dim("\u{1F511} Password received")}
55705
- `;
55706
- if (isNeovimActive()) {
55707
- writeToNeovimOutput(pwRecvMsg2);
55708
- } else {
55709
- process.stdout.write(pwRecvMsg2);
55710
- }
55840
+ statusBar.setInputStateProvider(() => ({
55841
+ line: rl.line ?? "",
55842
+ cursor: rl.cursor ?? 0
55843
+ }));
55844
+ writeContent(() => renderInfo("\u{1F511} Password received"));
55711
55845
  showPrompt();
55712
55846
  return;
55713
55847
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.138.47",
3
+ "version": "0.138.49",
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",