open-agents-ai 0.138.79 → 0.138.81

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 +160 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5653,6 +5653,35 @@ async function handleCmd(cmd) {
5653
5653
  var _cpiConfidence = parseFloat(args.confidence || '0.7');
5654
5654
  if (!_cpiInsight) { writeResp(id, { ok: false, output: 'insight text required' }); break; }
5655
5655
  try {
5656
+ // Detect local model tier from warm model
5657
+ var _cpiTier = 'unknown';
5658
+ try {
5659
+ var _cpiOllamaUrl = process.env.OLLAMA_HOST || 'http://localhost:11434';
5660
+ if (_cLastModel) {
5661
+ var _cpiTagsResp = await fetch(_cpiOllamaUrl + '/api/tags');
5662
+ var _cpiTags = await _cpiTagsResp.json();
5663
+ var _cpiModel = (_cpiTags.models || []).find(function(m) { return m.name === _cLastModel; });
5664
+ if (_cpiModel) {
5665
+ var _cpiSizeGB = (_cpiModel.size || 0) / (1024*1024*1024);
5666
+ _cpiTier = _cpiSizeGB >= 20 ? 'large' : _cpiSizeGB >= 5 ? 'medium' : 'small';
5667
+ }
5668
+ }
5669
+ } catch {}
5670
+ // WO-DL4: IPFS pin the insight content for persistence + cross-node retrieval
5671
+ var _cpiCid = null;
5672
+ try {
5673
+ var _cpiHeliaReady = await _ensureHelia();
5674
+ if (_cpiHeliaReady && _heliaFs) {
5675
+ var _cpiBytes = new TextEncoder().encode(JSON.stringify({ insight: _cpiInsight, category: _cpiCategory, confidence: _cpiConfidence, tier: _cpiTier, agent: agentName, ts: Date.now() }));
5676
+ var _cpiCidObj = await _heliaFs.addBytes(_cpiBytes);
5677
+ for await (var _cpiPin of _heliaNode.pins.add(_cpiCidObj)) {}
5678
+ _cpiCid = _cpiCidObj.toString();
5679
+ dlog('IPFS pinned insight: ' + _cpiCid);
5680
+ }
5681
+ } catch (_cpiIpfsErr) {
5682
+ dlog('IPFS pin failed (graceful): ' + (_cpiIpfsErr.message || _cpiIpfsErr));
5683
+ }
5684
+
5656
5685
  var _cpiDelta = {
5657
5686
  type: 'cohere.learning',
5658
5687
  delta_id: 'insight-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 6),
@@ -5661,7 +5690,8 @@ async function handleCmd(cmd) {
5661
5690
  insight: String(_cpiInsight).slice(0, 500),
5662
5691
  category: _cpiCategory,
5663
5692
  confidence: _cpiConfidence,
5664
- model_tier: 'unknown',
5693
+ model_tier: _cpiTier,
5694
+ cid: _cpiCid, // null if IPFS unavailable, CID string if pinned
5665
5695
  timestamp: Date.now(),
5666
5696
  };
5667
5697
  _natsConn.publish('nexus.cohere.learning', _natsCodec.encode(JSON.stringify(_cpiDelta)));
@@ -6887,6 +6917,47 @@ process.on('unhandledRejection', (reason) => {
6887
6917
  if (!_lData.insight || !_lData.source_peer) continue;
6888
6918
  // Skip our own insights
6889
6919
  if (_lData.source_peer === nexus.peerId) continue;
6920
+
6921
+ // WO-DL2: Model-tier-aware ingestion filtering
6922
+ // Determine local model tier from warm model size
6923
+ var _lLocalTier = 'unknown';
6924
+ try {
6925
+ var _lOllamaUrl = process.env.OLLAMA_HOST || 'http://localhost:11434';
6926
+ if (_cLastModel) {
6927
+ var _lTagsResp = await fetch(_lOllamaUrl + '/api/tags');
6928
+ var _lTags = await _lTagsResp.json();
6929
+ var _lModel = (_lTags.models || []).find(function(m) { return m.name === _cLastModel; });
6930
+ if (_lModel) {
6931
+ var _lSizeGB = (_lModel.size || 0) / (1024*1024*1024);
6932
+ _lLocalTier = _lSizeGB >= 20 ? 'large' : _lSizeGB >= 5 ? 'medium' : 'small';
6933
+ }
6934
+ }
6935
+ } catch {}
6936
+
6937
+ var _lSourceTier = _lData.model_tier || 'unknown';
6938
+ var _lCategory = _lData.category || 'strategy';
6939
+ var _lConfidence = _lData.confidence || 0.5;
6940
+
6941
+ // Tier filtering rules:
6942
+ // - Same or lower tier \u2192 always ingest
6943
+ // - Higher tier \u2192 only if confidence > 0.8 AND category is recovery (model-agnostic)
6944
+ // - Never ingest complex strategies from much larger models to tiny models
6945
+ var _lTierOrder = { 'small': 0, 'medium': 1, 'large': 2, 'unknown': 1 };
6946
+ var _lLocalLevel = _lTierOrder[_lLocalTier] || 1;
6947
+ var _lSourceLevel = _lTierOrder[_lSourceTier] || 1;
6948
+
6949
+ if (_lSourceLevel > _lLocalLevel) {
6950
+ // Insight from a LARGER model \u2014 apply strict filtering
6951
+ if (_lConfidence < 0.8) {
6952
+ dlog('COHERE learning SKIPPED (low confidence from higher tier): ' + _lCategory + ' conf=' + _lConfidence);
6953
+ continue;
6954
+ }
6955
+ if (_lCategory !== 'recovery' && _lCategory !== 'debug_heuristic') {
6956
+ dlog('COHERE learning SKIPPED (non-recovery from higher tier): ' + _lCategory);
6957
+ continue;
6958
+ }
6959
+ }
6960
+
6890
6961
  // Ingest: write to local metabolism store
6891
6962
  var _lStoreDir = join(nexusDir, '..', 'memory', 'metabolism');
6892
6963
  var _lStoreFile = join(_lStoreDir, 'store.json');
@@ -6916,6 +6987,31 @@ process.on('unhandledRejection', (reason) => {
6916
6987
  mkdirSync(_lStoreDir, { recursive: true });
6917
6988
  writeFileSync(_lStoreFile, JSON.stringify(_lStore, null, 2));
6918
6989
  dlog('COHERE learning ingested from ' + (_lData.source_agent || 'unknown') + ': ' + String(_lData.insight).slice(0, 60));
6990
+
6991
+ // WO-DL4: Cross-pin the CID locally if provided (content persistence)
6992
+ if (_lData.cid && _lData.cid.startsWith('bafy')) {
6993
+ try {
6994
+ var _lCidDir = join(nexusDir, 'ipfs', 'cid-registry');
6995
+ mkdirSync(_lCidDir, { recursive: true });
6996
+ var _lCidFile = join(_lCidDir, 'learning-cids.json');
6997
+ var _lCids = {};
6998
+ try { if (existsSync(_lCidFile)) _lCids = JSON.parse(readFileSync(_lCidFile, 'utf8')); } catch {}
6999
+ _lCids[_lData.delta_id] = { cid: _lData.cid, source: _lData.source_agent, pinned: false, timestamp: Date.now() };
7000
+ writeFileSync(_lCidFile, JSON.stringify(_lCids, null, 2));
7001
+ dlog('CID registered: ' + _lData.cid.slice(0, 20) + '... from ' + _lData.source_agent);
7002
+ // Attempt cross-pin if Helia is ready
7003
+ try {
7004
+ if (_heliaReady && _heliaNode) {
7005
+ var { CID: CIDClass } = await import('multiformats/cid');
7006
+ var _lCidObj = CIDClass.parse(_lData.cid);
7007
+ for await (var _lPin of _heliaNode.pins.add(_lCidObj)) {}
7008
+ _lCids[_lData.delta_id].pinned = true;
7009
+ writeFileSync(_lCidFile, JSON.stringify(_lCids, null, 2));
7010
+ dlog('Cross-pinned CID: ' + _lData.cid.slice(0, 20));
7011
+ }
7012
+ } catch {}
7013
+ } catch {}
7014
+ }
6919
7015
  } catch {}
6920
7016
  }
6921
7017
  })().catch(function(e) { dlog('COHERE learning listener error: ' + (e.message || e)); });
@@ -6977,6 +7073,69 @@ process.on('unhandledRejection', (reason) => {
6977
7073
  if (cohereActive) _publishCapacityAnnouncement();
6978
7074
  }, 60000);
6979
7075
 
7076
+ // \u2500\u2500 WO-DL3: Epoch sync \u2014 hash-based state comparison every 5 min \u2500\u2500
7077
+ // Each node publishes a lightweight fingerprint of its memory state.
7078
+ // If hashes differ between same-tier nodes, the lagging node can
7079
+ // request missing insights via nexus.cohere.learning.request.
7080
+ var _epochCounter = 0;
7081
+ function _publishEpochSync() {
7082
+ if (!cohereActive || !_natsConn || !_natsCodec) return;
7083
+ try {
7084
+ // Read local memory store for fingerprinting
7085
+ var _esStoreFile = join(nexusDir, '..', 'memory', 'metabolism', 'store.json');
7086
+ var _esStore = [];
7087
+ try { if (existsSync(_esStoreFile)) _esStore = JSON.parse(readFileSync(_esStoreFile, 'utf8')); } catch {}
7088
+
7089
+ // Compute top-10 memory IDs sorted by utility*confidence (deterministic)
7090
+ var _esFiltered = _esStore
7091
+ .filter(function(m) { return m.type !== 'quarantine' && m.scores && m.scores.confidence > 0.15; })
7092
+ .sort(function(a, b) { return (b.scores.utility * b.scores.confidence) - (a.scores.utility * a.scores.confidence); })
7093
+ .slice(0, 10);
7094
+ var _esTopIds = _esFiltered.map(function(m) { return m.id; }).sort().join(',');
7095
+
7096
+ // SHA-256 hash of top-10 IDs for compact comparison
7097
+ var _esHash = require('crypto').createHash('sha256').update(_esTopIds).digest('hex').slice(0, 16);
7098
+
7099
+ _epochCounter++;
7100
+ var _esAnnouncement = {
7101
+ type: 'cohere.epoch',
7102
+ peer: nexus.peerId,
7103
+ agentName: agentName,
7104
+ epoch: _epochCounter,
7105
+ memoryCount: _esStore.length,
7106
+ topHash: _esHash,
7107
+ insightsAvailable: _esFiltered.length,
7108
+ timestamp: Date.now(),
7109
+ };
7110
+ _natsConn.publish('nexus.cohere.learning.epoch', _natsCodec.encode(JSON.stringify(_esAnnouncement)));
7111
+ dlog('Epoch sync published: epoch=' + _epochCounter + ' memories=' + _esStore.length + ' hash=' + _esHash);
7112
+ } catch (e) {
7113
+ dlog('Epoch sync error: ' + (e.message || e));
7114
+ }
7115
+ }
7116
+
7117
+ // Epoch sync every 5 minutes
7118
+ setInterval(function() {
7119
+ if (cohereActive) _publishEpochSync();
7120
+ }, 300000);
7121
+ // Also publish on startup after a brief delay
7122
+ setTimeout(function() { if (cohereActive) _publishEpochSync(); }, 10000);
7123
+
7124
+ // Listen for epoch announcements from other nodes
7125
+ var _epochSub = _natsConn.subscribe('nexus.cohere.learning.epoch');
7126
+ (async function() {
7127
+ for await (var _eMsg of _epochSub) {
7128
+ try {
7129
+ var _eData = JSON.parse(_natsCodec.decode(_eMsg.data));
7130
+ if (!_eData.peer || _eData.peer === nexus.peerId) continue;
7131
+ // Log peer epoch state for dashboard visibility
7132
+ dlog('Epoch from ' + (_eData.agentName || 'peer') + ': epoch=' + _eData.epoch + ' memories=' + _eData.memoryCount + ' hash=' + _eData.topHash);
7133
+ // Future: if our hash differs and they have more insights, request sync
7134
+ } catch {}
7135
+ }
7136
+ })().catch(function(e) { dlog('Epoch listener error: ' + (e.message || e)); });
7137
+ dlog('Epoch sync listener active on nexus.cohere.learning.epoch');
7138
+
6980
7139
  // Lazy-init IPFS in background (non-blocking)
6981
7140
  _ensureHelia().catch(function() {});
6982
7141
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.138.79",
3
+ "version": "0.138.81",
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",