mio-agent-runtime 0.5.14 → 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.
- package/README.md +144 -236
- package/adapters/codex.js +122 -134
- package/adapters/hermes.js +122 -140
- package/adapters/host-utils.js +61 -61
- package/adapters/opencode.js +176 -215
- package/adapters/workbuddy.js +196 -242
- package/bin/mio.js +423 -424
- package/observe/observer.js +1326 -1335
- package/package.json +24 -13
- package/scripts/verify-packed-runtime.js +371 -0
- package/server/evolution-cutover.js +119 -0
- package/server/host-capabilities.js +50 -0
- package/server/mio-intelligence-mcp/README.md +184 -173
- package/server/mio-intelligence-mcp/index.js +123 -284
- package/server/mio-intelligence-mcp/package.json +17 -17
- package/server/mio-intelligence-mcp/phase0.js +381 -381
- package/server/runtime-modules.js +111 -0
- package/server/mio-intelligence-mcp/dashboard-server.js +0 -171
|
@@ -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 }
|