mio-agent-runtime 0.5.15 → 0.5.16

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.
@@ -0,0 +1,111 @@
1
+ 'use strict'
2
+
3
+ const fs = require('fs')
4
+ const path = require('path')
5
+
6
+ const RUNTIME_NAME = 'mio-agent-runtime'
7
+
8
+ const evolutionModules = [
9
+ {
10
+ name: '@akemi-mio/runtime-contracts',
11
+ packageDir: 'runtime-contracts',
12
+ health: (module) => typeof module.createRuntimeEvent === 'function',
13
+ },
14
+ {
15
+ name: '@akemi-mio/runtime-foundation',
16
+ packageDir: 'runtime-foundation',
17
+ health: (module) => typeof module.JsonlStore === 'function' && typeof module.EventBus === 'function',
18
+ },
19
+ {
20
+ name: '@akemi-mio/experience-memory',
21
+ packageDir: 'experience-memory',
22
+ health: (module) => typeof module.ExperienceMemory === 'function',
23
+ },
24
+ {
25
+ name: '@akemi-mio/evolution-learning',
26
+ packageDir: 'evolution-learning',
27
+ health: (module) => typeof module.createLearningModule === 'function' && typeof module.evaluateAnalysis === 'function',
28
+ },
29
+ {
30
+ name: '@akemi-mio/evolution-strategy',
31
+ packageDir: 'evolution-strategy',
32
+ health: (module) => typeof module.createStrategyModule === 'function' && typeof module.buildProposal === 'function',
33
+ },
34
+ {
35
+ name: '@akemi-mio/evolution-safety',
36
+ packageDir: 'evolution-safety',
37
+ health: (module) => typeof module.createSafetyModule === 'function' && typeof module.validateProposal === 'function',
38
+ },
39
+ {
40
+ name: '@akemi-mio/evolution-scheduler',
41
+ packageDir: 'evolution-scheduler',
42
+ health: (module) => typeof module.createSchedulerModule === 'function' && typeof module.createSchedulePlan === 'function',
43
+ },
44
+ ]
45
+
46
+ function fallbackPackagePath(entry) {
47
+ return path.resolve(__dirname, '..', '..', entry.packageDir)
48
+ }
49
+
50
+ function loadEvolutionModule(entry) {
51
+ try {
52
+ return require(entry.name)
53
+ } catch (_) {
54
+ return require(fallbackPackagePath(entry))
55
+ }
56
+ }
57
+
58
+ function readPackageVersion(entry) {
59
+ try {
60
+ const packagePath = require.resolve(`${entry.name}/package.json`)
61
+ return JSON.parse(fs.readFileSync(packagePath, 'utf8')).version
62
+ } catch (_) {
63
+ try {
64
+ return JSON.parse(fs.readFileSync(path.join(fallbackPackagePath(entry), 'package.json'), 'utf8')).version
65
+ } catch (_) {
66
+ return null
67
+ }
68
+ }
69
+ }
70
+
71
+ function runtimeVersion() {
72
+ try {
73
+ return JSON.parse(fs.readFileSync(path.resolve(__dirname, '..', 'package.json'), 'utf8')).version
74
+ } catch (_) {
75
+ return null
76
+ }
77
+ }
78
+
79
+ function getEvolutionStatus() {
80
+ const modules = evolutionModules.map((entry) => {
81
+ let loaded = false
82
+ let healthy = false
83
+ try {
84
+ const module = loadEvolutionModule(entry)
85
+ loaded = true
86
+ healthy = Boolean(entry.health(module))
87
+ } catch (_) {}
88
+ return {
89
+ name: entry.name,
90
+ version: readPackageVersion(entry),
91
+ loaded,
92
+ healthy,
93
+ }
94
+ })
95
+ return { runtime: RUNTIME_NAME, version: runtimeVersion(), modules }
96
+ }
97
+
98
+ function formatEvolutionStatusText(status) {
99
+ const lines = [`${status.runtime} ${status.version || 'unknown'}`]
100
+ for (const module of status.modules) {
101
+ lines.push(`${module.name}@${module.version || 'unknown'}: ${module.healthy ? 'healthy' : 'unavailable'}`)
102
+ }
103
+ return lines.join('\n')
104
+ }
105
+
106
+ module.exports = {
107
+ RUNTIME_NAME,
108
+ evolutionModules,
109
+ getEvolutionStatus,
110
+ formatEvolutionStatusText,
111
+ }
@@ -1,171 +0,0 @@
1
- const fs = require('fs')
2
- const path = require('path')
3
- const http = require('http')
4
- const os = require('os')
5
- const { spawn } = require('child_process')
6
-
7
- function dataDir() {
8
- return process.env.MIO_DATA_DIR || path.join(os.homedir(), '.mio-intelligence')
9
- }
10
-
11
- function readJsonl(file) {
12
- const full = path.join(dataDir(), file)
13
- if (!fs.existsSync(full)) return []
14
- try {
15
- return fs.readFileSync(full, 'utf8')
16
- .split('\n')
17
- .map(function (l) { return l.trim() })
18
- .filter(function (l) { return l.length })
19
- .map(function (l) {
20
- try { return JSON.parse(l) } catch (_) { return null }
21
- })
22
- .filter(Boolean)
23
- } catch (_) {
24
- return []
25
- }
26
- }
27
-
28
- function tally(rows, keyFn) {
29
- const out = {}
30
- for (const r of rows) {
31
- const k = keyFn(r)
32
- if (k == null || k === '') continue
33
- out[k] = (out[k] || 0) + 1
34
- }
35
- return out
36
- }
37
-
38
- function topN(obj, n) {
39
- return Object.keys(obj)
40
- .sort(function (a, b) { return obj[b] - obj[a] })
41
- .slice(0, n)
42
- .map(function (k) { return { key: k, count: obj[k] } })
43
- }
44
-
45
- function aggregate() {
46
- const memory = readJsonl('memory.jsonl')
47
- const traces = readJsonl('traces.jsonl')
48
- const experience = readJsonl('experience_reuse.jsonl')
49
- const ideas = readJsonl('ideas.jsonl')
50
- const suggestions = readJsonl('suggestions.jsonl')
51
- const agents = readJsonl('agents.jsonl')
52
-
53
- const memoryByKind = tally(memory, function (r) { return r.kind })
54
- const memoryBySource = tally(memory, function (r) { return r.source })
55
- const memoryByProject = tally(memory, function (r) { return r.project })
56
-
57
- const tracesByHost = tally(traces, function (r) { return r.host || 'unknown' })
58
- const tracesByOutcome = tally(traces, function (r) { return r.outcome || 'unknown' })
59
- const tracesByEventType = tally(traces, function (r) { return r.event_type || 'unknown' })
60
-
61
- const taskOutcomes = traces.filter(function (t) { return t.event_type === 'task_outcome' })
62
- const successCount = taskOutcomes.filter(function (t) { return t.outcome === 'success' }).length
63
- const taskTotal = taskOutcomes.length
64
- const successRate = taskTotal ? (successCount / taskTotal * 100).toFixed(1) : '0.0'
65
-
66
- const verified = experience.filter(function (e) {
67
- return e.reuse && e.behaviorChanged && e.outcomeImproved
68
- }).length
69
- const reuseCount = experience.filter(function (e) { return e.reuse }).length
70
- const crossAgent = experience.filter(function (e) {
71
- return e.sourceAgent && e.targetAgent && e.sourceAgent !== e.targetAgent
72
- }).length
73
-
74
- const hosts = Object.keys(tracesByHost).filter(function (h) { return h && h !== 'mcp' })
75
- const phase0 = {
76
- hosts: hosts.length,
77
- tasks: taskTotal,
78
- verifiedReuse: verified,
79
- successRate: successRate,
80
- thresholds: { hosts: 2, tasks: 20, verifiedReuse: 5 },
81
- passed: hosts.length >= 2 && taskTotal >= 20 && verified >= 5,
82
- }
83
-
84
- function recent(rows, n) {
85
- return rows.slice(-n).map(function (r) {
86
- return {
87
- id: r.id,
88
- timestamp: r.timestamp,
89
- kind: r.kind || r.event_type || null,
90
- source: r.source || r.host || null,
91
- text: (r.content || r.notes || r.trace_id || '').toString().slice(0, 160),
92
- }
93
- })
94
- }
95
-
96
- return {
97
- generatedAt: new Date().toISOString(),
98
- dataDir: dataDir(),
99
- summary: {
100
- memory: memory.length,
101
- traces: traces.length,
102
- experience: experience.length,
103
- ideas: ideas.length,
104
- suggestions: suggestions.length,
105
- agents: agents.length,
106
- },
107
- memoryByKind: topN(memoryByKind, 10),
108
- memoryBySource: topN(memoryBySource, 10),
109
- memoryByProject: topN(memoryByProject, 10),
110
- tracesByHost: topN(tracesByHost, 10),
111
- tracesByOutcome: topN(tracesByOutcome, 10),
112
- tracesByEventType: topN(tracesByEventType, 10),
113
- experience: {
114
- total: experience.length,
115
- reuse: reuseCount,
116
- verified: verified,
117
- crossAgent: crossAgent,
118
- reuseRate: experience.length ? (reuseCount / experience.length * 100).toFixed(1) : '0.0',
119
- },
120
- agents: agents.slice(-10),
121
- phase0: phase0,
122
- ideas: ideas.slice(-10).map(function (i) {
123
- return { id: i.id, title: i.title, goal: i.goal, strategy: i.provenance && i.provenance.strategy }
124
- }),
125
- suggestions: suggestions.slice(-10).map(function (s) {
126
- return { id: s.id, title: s.title, nextAction: s.nextAction, impact: s.impact }
127
- }),
128
- recentMemory: recent(memory, 10).reverse(),
129
- recentTraces: recent(traces, 10).reverse(),
130
- }
131
- }
132
-
133
- function startServer(port, htmlPath) {
134
- const server = http.createServer(function (req, res) {
135
- const url = (req.url || '/').split('?')[0]
136
- if (url === '/api/data' || url === '/api/health') {
137
- res.setHeader('Content-Type', 'application/json; charset=utf-8')
138
- res.setHeader('Access-Control-Allow-Origin', '*')
139
- if (url === '/api/health') {
140
- res.end(JSON.stringify({ ok: true }))
141
- return
142
- }
143
- res.end(JSON.stringify(aggregate(), null, 2))
144
- return
145
- }
146
- if (url === '/' || url === '/index.html' || url === '/dashboard') {
147
- res.setHeader('Content-Type', 'text/html; charset=utf-8')
148
- if (htmlPath && fs.existsSync(htmlPath)) {
149
- res.end(fs.readFileSync(htmlPath, 'utf8'))
150
- } else {
151
- res.end('<h1>Mio Dashboard</h1><p>HTML not found at ' + htmlPath + '</p>')
152
- }
153
- return
154
- }
155
- res.statusCode = 404
156
- res.end('Not found')
157
- })
158
- server.listen(port, function () {
159
- console.log('Mio dashboard running at http://localhost:' + port)
160
- })
161
- return server
162
- }
163
-
164
- // When run directly: `node dashboard-server.js [port]`
165
- if (require.main === module) {
166
- const port = parseInt(process.argv[2] || process.env.MIO_DASHBOARD_PORT || '8787', 10)
167
- const htmlPath = path.join(__dirname, '..', '..', 'mio-dashboard.html')
168
- startServer(port, htmlPath)
169
- }
170
-
171
- module.exports = { startServer, aggregate, dataDir }