mio-agent-runtime 0.15.0 → 0.16.1
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/bin/mio.js +168 -118
- package/package.json +2 -2
- package/server/mechanism-registry.js +99 -0
- package/server/mio-intelligence-mcp/index.js +298 -199
- package/server/observer-store.js +19 -22
package/bin/mio.js
CHANGED
|
@@ -24,6 +24,7 @@ const { createMemoryStore } = require('../server/memory-store.js')
|
|
|
24
24
|
const { createExperienceStore } = require('../server/experience-store.js')
|
|
25
25
|
const { createPolicyStore } = require('../server/policy-store.js')
|
|
26
26
|
const { CreativityEngine, sourcesFromInsights, adoptHypothesis } = require('../server/creativity-engine.js')
|
|
27
|
+
const { mechanismRegistry, mechanismPromote, mechanismRollback } = require('../server/mechanism-registry.js')
|
|
27
28
|
const { buildAutoSources, topUpSources } = require('../server/creativity-sources.js')
|
|
28
29
|
const { runIdeaGenerate, groundingFrom } = require('../server/idea-generate.js')
|
|
29
30
|
const { createAgentStore } = require('../server/agent-store.js')
|
|
@@ -71,15 +72,11 @@ function readJsonl(file) {
|
|
|
71
72
|
|
|
72
73
|
function projectName() {
|
|
73
74
|
try {
|
|
74
|
-
const commonDir = execFileSync(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
encoding: 'utf8',
|
|
80
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
81
|
-
}
|
|
82
|
-
).trim()
|
|
75
|
+
const commonDir = execFileSync('git', ['rev-parse', '--path-format=absolute', '--git-common-dir'], {
|
|
76
|
+
cwd: process.cwd(),
|
|
77
|
+
encoding: 'utf8',
|
|
78
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
79
|
+
}).trim()
|
|
83
80
|
if (commonDir) return path.basename(path.dirname(commonDir))
|
|
84
81
|
} catch (_) {}
|
|
85
82
|
return path.basename(process.cwd())
|
|
@@ -193,7 +190,7 @@ function printMigrationPlan(plan, useJson) {
|
|
|
193
190
|
if (useJson) return jsonOrText(plan, true)
|
|
194
191
|
console.log(`Migration plan: ${plan.ready ? 'ready' : 'conflicts'}`)
|
|
195
192
|
console.log(
|
|
196
|
-
`legacy=${plan.summary.legacy} modular=${plan.summary.modular} toCreate=${plan.summary.toCreate} conflicts=${plan.summary.conflicts}
|
|
193
|
+
`legacy=${plan.summary.legacy} modular=${plan.summary.modular} toCreate=${plan.summary.toCreate} conflicts=${plan.summary.conflicts}`,
|
|
197
194
|
)
|
|
198
195
|
}
|
|
199
196
|
|
|
@@ -457,7 +454,9 @@ function splitTagsOption(args, name) {
|
|
|
457
454
|
function recallCommand(args, useJson) {
|
|
458
455
|
const query = args[1]
|
|
459
456
|
if (!query) {
|
|
460
|
-
console.error(
|
|
457
|
+
console.error(
|
|
458
|
+
'Usage: mio recall "<query>" [--project name] [--scope project|global|all] [--kind kind] [--tags a,b] [--limit n] [--json]',
|
|
459
|
+
)
|
|
461
460
|
process.exitCode = 1
|
|
462
461
|
return
|
|
463
462
|
}
|
|
@@ -479,9 +478,7 @@ function recallCommand(args, useJson) {
|
|
|
479
478
|
return
|
|
480
479
|
}
|
|
481
480
|
if (useJson) return jsonOrText(result, true)
|
|
482
|
-
console.log(
|
|
483
|
-
`Mio memory: ${result.count} result(s) for "${result.query}" (project=${result.project}, scope=${result.scope})`
|
|
484
|
-
)
|
|
481
|
+
console.log(`Mio memory: ${result.count} result(s) for "${result.query}" (project=${result.project}, scope=${result.scope})`)
|
|
485
482
|
result.results.forEach((record, index) => {
|
|
486
483
|
const date = (record.timestamp || '').slice(0, 10)
|
|
487
484
|
console.log(`${index + 1}. [${record.kind || 'note'}] ${record.content}`)
|
|
@@ -523,9 +520,7 @@ function tracesCommand(args, useJson) {
|
|
|
523
520
|
.filter(([, value]) => value !== null && value !== undefined)
|
|
524
521
|
.map(([key, value]) => `${key}=${value}`)
|
|
525
522
|
.join(', ')
|
|
526
|
-
console.log(
|
|
527
|
-
`Mio traces: ${result.matched} matched / ${result.total} total${filters ? ' (' + filters + ')' : ''}`
|
|
528
|
-
)
|
|
523
|
+
console.log(`Mio traces: ${result.matched} matched / ${result.total} total${filters ? ' (' + filters + ')' : ''}`)
|
|
529
524
|
const summary = Object.entries(result.summary.byOutcome)
|
|
530
525
|
.map(([key, value]) => `${key}=${value}`)
|
|
531
526
|
.join(' ')
|
|
@@ -534,7 +529,7 @@ function tracesCommand(args, useJson) {
|
|
|
534
529
|
const time = (trace.timestamp || '').replace('T', ' ').slice(0, 19)
|
|
535
530
|
const brief = trace.payload && trace.payload.summary ? ' | ' + String(trace.payload.summary).slice(0, 100) : ''
|
|
536
531
|
console.log(
|
|
537
|
-
`${index + 1}. ${time} [${trace.event_type || '?'}${trace.outcome ? '/' + trace.outcome : ''}] ${trace.agent || '?'} @ ${trace.project || '?'}${brief}
|
|
532
|
+
`${index + 1}. ${time} [${trace.event_type || '?'}${trace.outcome ? '/' + trace.outcome : ''}] ${trace.agent || '?'} @ ${trace.project || '?'}${brief}`,
|
|
538
533
|
)
|
|
539
534
|
console.log(` ${trace.id} trace_id=${trace.trace_id || '-'}`)
|
|
540
535
|
})
|
|
@@ -587,15 +582,11 @@ function digestCommand(args, useJson) {
|
|
|
587
582
|
targetCwds = [explicitCwd]
|
|
588
583
|
} else if (explicitProject) {
|
|
589
584
|
const wanted = String(explicitProject).toLowerCase()
|
|
590
|
-
targetCwds = Object.keys(state.contexts).filter(
|
|
591
|
-
(cwd) => path.basename(cwd).toLowerCase() === wanted,
|
|
592
|
-
)
|
|
585
|
+
targetCwds = Object.keys(state.contexts).filter((cwd) => path.basename(cwd).toLowerCase() === wanted)
|
|
593
586
|
} else {
|
|
594
587
|
// No explicit target: only write to workspaces this digest has data for.
|
|
595
588
|
// A workspace with no matching project gets nothing.
|
|
596
|
-
targetCwds = Object.keys(state.contexts).filter((cwd) =>
|
|
597
|
-
projectLine.has(path.basename(cwd).toLowerCase()),
|
|
598
|
-
)
|
|
589
|
+
targetCwds = Object.keys(state.contexts).filter((cwd) => projectLine.has(path.basename(cwd).toLowerCase()))
|
|
599
590
|
}
|
|
600
591
|
|
|
601
592
|
let written = 0
|
|
@@ -633,9 +624,7 @@ function digestCommand(args, useJson) {
|
|
|
633
624
|
console.log(report.markdown)
|
|
634
625
|
console.log(`Report saved: ${reportFile}`)
|
|
635
626
|
if (report.writeBack) {
|
|
636
|
-
console.log(
|
|
637
|
-
`Write-back: ${report.writeBack.workspaces} workspace(s), ${report.writeBack.skipped} skipped (no digest data)`,
|
|
638
|
-
)
|
|
627
|
+
console.log(`Write-back: ${report.writeBack.workspaces} workspace(s), ${report.writeBack.skipped} skipped (no digest data)`)
|
|
639
628
|
if (report.writeBack.failures && report.writeBack.failures.length > 0) {
|
|
640
629
|
console.error(` ${report.writeBack.failures.length} write-back failure(s):`)
|
|
641
630
|
for (const f of report.writeBack.failures) console.error(` - ${f.workspace}: ${f.error}`)
|
|
@@ -665,7 +654,7 @@ function pruneCommand(args, useJson) {
|
|
|
665
654
|
}
|
|
666
655
|
if (useJson) return jsonOrText(result, true)
|
|
667
656
|
console.log(
|
|
668
|
-
`Prune ${dryRun ? 'plan (dry-run)' : 'result'}: cutoff ${result.cutoff}, days=${days}${includeMemory ? ', memory included' : ''}
|
|
657
|
+
`Prune ${dryRun ? 'plan (dry-run)' : 'result'}: cutoff ${result.cutoff}, days=${days}${includeMemory ? ', memory included' : ''}`,
|
|
669
658
|
)
|
|
670
659
|
for (const file of result.files) {
|
|
671
660
|
console.log(`- ${file.file}: ${file.total} total -> keep ${file.kept}, remove ${file.removed}`)
|
|
@@ -678,7 +667,9 @@ function pruneCommand(args, useJson) {
|
|
|
678
667
|
function rememberCommand(args, useJson) {
|
|
679
668
|
const content = args[1]
|
|
680
669
|
if (!content) {
|
|
681
|
-
console.error(
|
|
670
|
+
console.error(
|
|
671
|
+
'Usage: mio remember "<content>" [--kind decision|context|problem|note] [--tags a,b] [--hypothesis-id id] [--scope project|global] [--project name] [--json]',
|
|
672
|
+
)
|
|
682
673
|
process.exitCode = 1
|
|
683
674
|
return
|
|
684
675
|
}
|
|
@@ -710,8 +701,18 @@ function rememberCommand(args, useJson) {
|
|
|
710
701
|
// Every flag that consumes the next token. A positional directly after one of
|
|
711
702
|
// these is that flag's value, not an id.
|
|
712
703
|
const VALUE_FLAGS = new Set([
|
|
713
|
-
'--ids',
|
|
714
|
-
'--
|
|
704
|
+
'--ids',
|
|
705
|
+
'--reason',
|
|
706
|
+
'--project',
|
|
707
|
+
'--limit',
|
|
708
|
+
'--scope',
|
|
709
|
+
'--keep',
|
|
710
|
+
'--by',
|
|
711
|
+
'--notes',
|
|
712
|
+
'--source-agent',
|
|
713
|
+
'--target-agent',
|
|
714
|
+
'--experience-id',
|
|
715
|
+
'--status',
|
|
715
716
|
])
|
|
716
717
|
|
|
717
718
|
// Accept ids both as `--ids a,b,c` and as bare positionals
|
|
@@ -741,9 +742,7 @@ function collectIds(flags) {
|
|
|
741
742
|
|
|
742
743
|
function printMemoryAnalyze(result) {
|
|
743
744
|
const project = result.project || 'all'
|
|
744
|
-
console.log(
|
|
745
|
-
`Memory analyze: ${result.total} active, ${result.archived} archived (project=${project})`,
|
|
746
|
-
)
|
|
745
|
+
console.log(`Memory analyze: ${result.total} active, ${result.archived} archived (project=${project})`)
|
|
747
746
|
console.log(`layers: project=${result.layers.project} global=${result.layers.global}`)
|
|
748
747
|
const kinds = Object.entries(result.byKind)
|
|
749
748
|
if (kinds.length > 0) {
|
|
@@ -813,9 +812,7 @@ function printMemoryMerge(result) {
|
|
|
813
812
|
return
|
|
814
813
|
}
|
|
815
814
|
|
|
816
|
-
console.log(
|
|
817
|
-
`Merged ${result.archivedCount} record(s) into ${result.survivor.id} (project=${result.project || 'current'})`,
|
|
818
|
-
)
|
|
815
|
+
console.log(`Merged ${result.archivedCount} record(s) into ${result.survivor.id} (project=${result.project || 'current'})`)
|
|
819
816
|
console.log(`survivor: ${result.survivor.contentLength} chars, ${result.survivor.timestamp || 'no timestamp'}`)
|
|
820
817
|
if (result.divergentContent) console.log('note: content differed across members; the survivor body was chosen explicitly')
|
|
821
818
|
console.log(`supersedes: ${result.survivor.supersedes.join(', ')}`)
|
|
@@ -921,7 +918,11 @@ function memoryCommand(args, useJson) {
|
|
|
921
918
|
const matched = all.filter((r) => idSet.has(r.id))
|
|
922
919
|
console.log(`Forget preview: ${ids.length} id(s) (project=${previewProject})`)
|
|
923
920
|
for (const record of matched) {
|
|
924
|
-
console.log(
|
|
921
|
+
console.log(
|
|
922
|
+
` ${record.id} ${String(record.content || '')
|
|
923
|
+
.replace(/\s+/g, ' ')
|
|
924
|
+
.slice(0, 80)}`,
|
|
925
|
+
)
|
|
925
926
|
}
|
|
926
927
|
for (const id of ids) {
|
|
927
928
|
if (!matched.some((r) => r.id === id)) console.log(` ${id} (not found)`)
|
|
@@ -1075,9 +1076,7 @@ Options:
|
|
|
1075
1076
|
}
|
|
1076
1077
|
|
|
1077
1078
|
function printExperienceList(result) {
|
|
1078
|
-
console.log(
|
|
1079
|
-
`Experience reuse: ${result.count} shown of ${result.total} (project=${result.project || 'all'}, status=${result.status})`,
|
|
1080
|
-
)
|
|
1079
|
+
console.log(`Experience reuse: ${result.count} shown of ${result.total} (project=${result.project || 'all'}, status=${result.status})`)
|
|
1081
1080
|
if (result.count === 0) {
|
|
1082
1081
|
console.log('No reuse records match.')
|
|
1083
1082
|
return
|
|
@@ -1086,23 +1085,15 @@ function printExperienceList(result) {
|
|
|
1086
1085
|
const state = record.confirmed ? 'confirmed' : 'pending'
|
|
1087
1086
|
const badge = record.reuse && record.behaviorChanged && record.outcomeImproved ? 'verified' : state
|
|
1088
1087
|
const arrow = `${record.sourceAgent || '?'} -> ${record.targetAgent || '?'}`
|
|
1089
|
-
const flags = [
|
|
1090
|
-
record.reuse ? 'reused' : null,
|
|
1091
|
-
record.behaviorChanged ? 'changed' : null,
|
|
1092
|
-
record.outcomeImproved ? 'improved' : null,
|
|
1093
|
-
]
|
|
1088
|
+
const flags = [record.reuse ? 'reused' : null, record.behaviorChanged ? 'changed' : null, record.outcomeImproved ? 'improved' : null]
|
|
1094
1089
|
.filter(Boolean)
|
|
1095
1090
|
.join(',')
|
|
1096
1091
|
console.log(`${index + 1}. [${badge}] ${record.experienceId} ${arrow}`)
|
|
1097
|
-
console.log(
|
|
1098
|
-
` ${flags || 'no effect flags'} | ${(record.timestamp || '').slice(0, 19)} | ${record.id}`,
|
|
1099
|
-
)
|
|
1092
|
+
console.log(` ${flags || 'no effect flags'} | ${(record.timestamp || '').slice(0, 19)} | ${record.id}`)
|
|
1100
1093
|
if (record.notes) console.log(` note: ${record.notes}`)
|
|
1101
1094
|
})
|
|
1102
1095
|
// Only auto_claims are confirmable — experience.confirm rejects anything else.
|
|
1103
|
-
const pending = result.records
|
|
1104
|
-
.filter((record) => record.source === 'auto_claim' && !record.confirmed)
|
|
1105
|
-
.map((record) => record.id)
|
|
1096
|
+
const pending = result.records.filter((record) => record.source === 'auto_claim' && !record.confirmed).map((record) => record.id)
|
|
1106
1097
|
if (pending.length > 0) {
|
|
1107
1098
|
console.log('')
|
|
1108
1099
|
console.log(
|
|
@@ -1158,11 +1149,7 @@ function experienceCommand(args, useJson) {
|
|
|
1158
1149
|
return
|
|
1159
1150
|
}
|
|
1160
1151
|
// Absent = keep whatever the auto-claim recorded; --no-improved rejects it.
|
|
1161
|
-
const improved = flagPresent(flags, '--no-improved')
|
|
1162
|
-
? false
|
|
1163
|
-
: flagPresent(flags, '--outcome-improved')
|
|
1164
|
-
? true
|
|
1165
|
-
: undefined
|
|
1152
|
+
const improved = flagPresent(flags, '--no-improved') ? false : flagPresent(flags, '--outcome-improved') ? true : undefined
|
|
1166
1153
|
result = store.confirmReuse({
|
|
1167
1154
|
ids,
|
|
1168
1155
|
outcomeImproved: improved,
|
|
@@ -1260,9 +1247,7 @@ function printPolicyCheck(result) {
|
|
|
1260
1247
|
console.log('Try a more specific action, e.g. mio policy check "npm publish".')
|
|
1261
1248
|
} else if (diag && diag.lowSample) {
|
|
1262
1249
|
console.log('')
|
|
1263
|
-
console.log(
|
|
1264
|
-
`NOTE: only ${diag.sampleSize} matching trace(s); treat the level above as a weak signal.`,
|
|
1265
|
-
)
|
|
1250
|
+
console.log(`NOTE: only ${diag.sampleSize} matching trace(s); treat the level above as a weak signal.`)
|
|
1266
1251
|
}
|
|
1267
1252
|
|
|
1268
1253
|
console.log(`\n${result.suggestion}`)
|
|
@@ -1500,9 +1485,7 @@ function insightGenerateCommand(args, useJson) {
|
|
|
1500
1485
|
return Promise.resolve(result).then((resolved) => {
|
|
1501
1486
|
if (useJson) return jsonOrText(resolved, true)
|
|
1502
1487
|
if (!resolved || resolved.generated === 0) {
|
|
1503
|
-
console.log(
|
|
1504
|
-
`No insights generated: ${(resolved && resolved.reason) || 'nothing notable in the given context'}`
|
|
1505
|
-
)
|
|
1488
|
+
console.log(`No insights generated: ${(resolved && resolved.reason) || 'nothing notable in the given context'}`)
|
|
1506
1489
|
return
|
|
1507
1490
|
}
|
|
1508
1491
|
console.log(`Generated ${resolved.generated} insight(s)`)
|
|
@@ -1623,7 +1606,10 @@ function printObserverEssays(essays) {
|
|
|
1623
1606
|
}
|
|
1624
1607
|
for (const essay of essays) {
|
|
1625
1608
|
console.log(`- ${essay.file} (${essay.type}, ${String(essay.created).slice(0, 10)})`)
|
|
1626
|
-
const firstLine =
|
|
1609
|
+
const firstLine =
|
|
1610
|
+
String(essay.content || '')
|
|
1611
|
+
.split('\n')
|
|
1612
|
+
.find((l) => l.trim()) || ''
|
|
1627
1613
|
if (firstLine) console.log(` ${firstLine.replace(/\s+/g, ' ').slice(0, 120)}`)
|
|
1628
1614
|
}
|
|
1629
1615
|
console.log(`\n${essays.length} essay(s)`)
|
|
@@ -1960,7 +1946,9 @@ function printObserverServe(result) {
|
|
|
1960
1946
|
}
|
|
1961
1947
|
console.log(`Observer research scheduler running (base-dir=${result.baseDir})`)
|
|
1962
1948
|
console.log(` ${result.schedule ? result.schedule.collectors : 'collectors started'}`)
|
|
1963
|
-
console.log(
|
|
1949
|
+
console.log(
|
|
1950
|
+
` pipeline: first tick ${result.schedule ? result.schedule.pipelineFirstTickMs : 5000}ms, then every ${result.schedule ? result.schedule.pipelineTickMs : 60000}ms`,
|
|
1951
|
+
)
|
|
1964
1952
|
console.log(' Stops with Ctrl+C (or `mio observe --stop` when started that way).')
|
|
1965
1953
|
}
|
|
1966
1954
|
|
|
@@ -2104,7 +2092,9 @@ function printCreativityStatus(result) {
|
|
|
2104
2092
|
console.log(` hypotheses: ${result.hypotheses} combos: ${result.combos} experiments: ${result.experiments}`)
|
|
2105
2093
|
console.log(` active: ${result.active} validated: ${result.validated} rejected: ${result.rejected} draft: ${result.draft}`)
|
|
2106
2094
|
const adoption = result.adoption || { adopted: 0, claimed: 0, evidenced: 0 }
|
|
2107
|
-
console.log(
|
|
2095
|
+
console.log(
|
|
2096
|
+
` adoption: ${adoption.adopted} adopted (events=${adoption.claimed} tags=${adoption.evidenced}) — derived join, not a metric`,
|
|
2097
|
+
)
|
|
2108
2098
|
if (result.recentIdeas.length === 0) {
|
|
2109
2099
|
console.log('No hypotheses yet.')
|
|
2110
2100
|
return
|
|
@@ -2125,7 +2115,9 @@ function printCreativityList(items) {
|
|
|
2125
2115
|
items.forEach((h, index) => {
|
|
2126
2116
|
const when = h.createdAt ? new Date(h.createdAt).toISOString().slice(0, 19).replace('T', ' ') : ''
|
|
2127
2117
|
const labels = Array.isArray(h.sourceLabels) && h.sourceLabels.length > 0 ? h.sourceLabels.join(' + ') : '—'
|
|
2128
|
-
console.log(
|
|
2118
|
+
console.log(
|
|
2119
|
+
`${index + 1}. [${h.status}]${h.adopted ? ' [adopted]' : ''} ${h.title} (N=${h.novelty} F=${h.feasibility} I=${h.impact} score=${h.score}${h.noveltyScore !== undefined ? ` noveltyScore=${h.noveltyScore}` : ''})`,
|
|
2120
|
+
)
|
|
2129
2121
|
console.log(` ${labels} | ${when} | ${h.id}`)
|
|
2130
2122
|
if (h.fermentCount) console.log(` fermented ${h.fermentCount}x`)
|
|
2131
2123
|
})
|
|
@@ -2168,7 +2160,7 @@ function printCreativityErrors(errors, label) {
|
|
|
2168
2160
|
if (!Array.isArray(errors) || errors.length === 0) return
|
|
2169
2161
|
console.log(`\n${errors.length} ${label}(s) failed:`)
|
|
2170
2162
|
for (const err of errors) {
|
|
2171
|
-
const who = err.pair ? err.pair.join(' + ') :
|
|
2163
|
+
const who = err.pair ? err.pair.join(' + ') : err.title || err.id
|
|
2172
2164
|
console.log(`- ${who}: ${err.error}`)
|
|
2173
2165
|
}
|
|
2174
2166
|
}
|
|
@@ -2327,7 +2319,7 @@ function creativityAdoptCommand(args, useJson) {
|
|
|
2327
2319
|
note: optionValue(flags, '--note'),
|
|
2328
2320
|
},
|
|
2329
2321
|
cliTaskStore().ingestObservation,
|
|
2330
|
-
MIO_HOME
|
|
2322
|
+
MIO_HOME,
|
|
2331
2323
|
)
|
|
2332
2324
|
} catch (error) {
|
|
2333
2325
|
console.error(error.message || error)
|
|
@@ -2408,7 +2400,9 @@ async function ideaGenerateCommand(args, useJson) {
|
|
|
2408
2400
|
console.log(`Generated ${result.ideas.length} idea(s) (grounded with ${result.groundedWith} memories)`)
|
|
2409
2401
|
result.ideas.forEach((idea) => {
|
|
2410
2402
|
console.log(`- [${idea.hypothesis.status}] ${idea.title}`)
|
|
2411
|
-
console.log(
|
|
2403
|
+
console.log(
|
|
2404
|
+
` novelty=${idea.hypothesis.novelty} feasibility=${idea.hypothesis.feasibility} impact=${idea.hypothesis.impact} | ${idea.hypothesis.id}`,
|
|
2405
|
+
)
|
|
2412
2406
|
if (idea.provenance && idea.provenance.technique) console.log(` technique=${idea.provenance.technique}`)
|
|
2413
2407
|
if (idea.hypothesis.rejectionReason) console.log(` rejected: ${idea.hypothesis.rejectionReason}`)
|
|
2414
2408
|
})
|
|
@@ -2472,6 +2466,86 @@ function creativityCommand(args, useJson) {
|
|
|
2472
2466
|
else printCreativityList(result)
|
|
2473
2467
|
}
|
|
2474
2468
|
|
|
2469
|
+
function mechanismUsage(write = console.log) {
|
|
2470
|
+
write(`mio mechanism <subcommand> — mechanism registry (promotion/rollback)
|
|
2471
|
+
|
|
2472
|
+
Subcommands:
|
|
2473
|
+
mio mechanism registry List versions and promotion requests (--mechanism-id, --status)
|
|
2474
|
+
mio mechanism promote submit ... Submit a PromotionRequest (gate-checked)
|
|
2475
|
+
mio mechanism promote approve ... Approve a request (approver must differ from submitter)
|
|
2476
|
+
mio mechanism promote reject ... Reject a request
|
|
2477
|
+
mio mechanism rollback <mechanismId> Roll back the active version to its rollbackTo target
|
|
2478
|
+
|
|
2479
|
+
Options:
|
|
2480
|
+
--json Machine-readable output
|
|
2481
|
+
|
|
2482
|
+
Examples:
|
|
2483
|
+
mio mechanism registry
|
|
2484
|
+
mio mechanism promote submit --mechanism-id m-1 --version 1 --submitted-by codex
|
|
2485
|
+
mio mechanism promote approve --request-id pr-1 --approved-by other-agent
|
|
2486
|
+
mio mechanism rollback m-1`)
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
function mechanismCommand(args, useJson) {
|
|
2490
|
+
const sub = args[1]
|
|
2491
|
+
|
|
2492
|
+
if (!sub || sub === 'help' || sub === '--help' || sub === '-h') {
|
|
2493
|
+
mechanismUsage()
|
|
2494
|
+
if (!sub) process.exitCode = 1
|
|
2495
|
+
return
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
const flags = args.slice(2)
|
|
2499
|
+
|
|
2500
|
+
try {
|
|
2501
|
+
if (sub === 'registry') {
|
|
2502
|
+
const result = mechanismRegistry(
|
|
2503
|
+
{ mechanismId: optionValue(flags, '--mechanism-id'), status: optionValue(flags, '--status') },
|
|
2504
|
+
MIO_HOME,
|
|
2505
|
+
)
|
|
2506
|
+
return jsonOrText(result, useJson)
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
if (sub === 'promote') {
|
|
2510
|
+
const action = flags[0]
|
|
2511
|
+
const result = mechanismPromote(
|
|
2512
|
+
{
|
|
2513
|
+
action,
|
|
2514
|
+
mechanismId: optionValue(flags, '--mechanism-id'),
|
|
2515
|
+
version: parseNumberOption(flags, '--version'),
|
|
2516
|
+
hypothesisId: optionValue(flags, '--hypothesis-id'),
|
|
2517
|
+
experimentRunIds: optionValues(flags, '--experiment-run-ids'),
|
|
2518
|
+
submittedBy: optionValue(flags, '--submitted-by'),
|
|
2519
|
+
requestId: optionValue(flags, '--request-id'),
|
|
2520
|
+
approvedBy: optionValue(flags, '--approved-by'),
|
|
2521
|
+
reason: optionValue(flags, '--reason'),
|
|
2522
|
+
},
|
|
2523
|
+
MIO_HOME,
|
|
2524
|
+
)
|
|
2525
|
+
return jsonOrText(result, useJson)
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
if (sub === 'rollback') {
|
|
2529
|
+
const mechanismId = args[2]
|
|
2530
|
+
if (!mechanismId) {
|
|
2531
|
+
console.error('mio mechanism rollback requires <mechanismId>')
|
|
2532
|
+
console.error('Usage: mio mechanism rollback <mechanismId> [--json]')
|
|
2533
|
+
process.exitCode = 1
|
|
2534
|
+
return
|
|
2535
|
+
}
|
|
2536
|
+
const result = mechanismRollback({ mechanismId }, MIO_HOME)
|
|
2537
|
+
return jsonOrText(result, useJson)
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
console.error(`Unknown mechanism subcommand: ${sub}`)
|
|
2541
|
+
mechanismUsage(console.error)
|
|
2542
|
+
process.exitCode = 1
|
|
2543
|
+
} catch (error) {
|
|
2544
|
+
console.error(error.message || error)
|
|
2545
|
+
process.exitCode = 1
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2475
2549
|
function readConfig() {
|
|
2476
2550
|
const fallback = { version: 1, home: MIO_HOME, agents: {} }
|
|
2477
2551
|
if (!fs.existsSync(CONFIG_FILE)) return fallback
|
|
@@ -2538,7 +2612,7 @@ function configShowCommand(useJson) {
|
|
|
2538
2612
|
configured: isLlmConfigured(),
|
|
2539
2613
|
},
|
|
2540
2614
|
},
|
|
2541
|
-
true
|
|
2615
|
+
true,
|
|
2542
2616
|
)
|
|
2543
2617
|
}
|
|
2544
2618
|
|
|
@@ -2548,7 +2622,7 @@ function configShowCommand(useJson) {
|
|
|
2548
2622
|
console.log('LLM (effective):')
|
|
2549
2623
|
console.log(` apiUrl: ${effective.apiUrl} [${LLM_SOURCE_LABELS[sources.apiUrl]}]`)
|
|
2550
2624
|
console.log(
|
|
2551
|
-
` apiKey: ${effective.apiKey ? `${maskSecret(effective.apiKey)} [${LLM_SOURCE_LABELS[sources.apiKey]}]` : '(none / unauthenticated)'}
|
|
2625
|
+
` apiKey: ${effective.apiKey ? `${maskSecret(effective.apiKey)} [${LLM_SOURCE_LABELS[sources.apiKey]}]` : '(none / unauthenticated)'}`,
|
|
2552
2626
|
)
|
|
2553
2627
|
console.log(` model: ${effective.model} [${LLM_SOURCE_LABELS[sources.model]}]`)
|
|
2554
2628
|
console.log('')
|
|
@@ -2632,7 +2706,7 @@ function configLlmCommand(flags, useJson) {
|
|
|
2632
2706
|
},
|
|
2633
2707
|
configFile: CONFIG_FILE,
|
|
2634
2708
|
},
|
|
2635
|
-
true
|
|
2709
|
+
true,
|
|
2636
2710
|
)
|
|
2637
2711
|
}
|
|
2638
2712
|
|
|
@@ -2738,11 +2812,8 @@ function statusCommand(useJson) {
|
|
|
2738
2812
|
dataDir: MIO_HOME,
|
|
2739
2813
|
projectName: () => null,
|
|
2740
2814
|
}).listReuse({ status: 'pending', limit: 100 }).records
|
|
2741
|
-
return records.filter(
|
|
2742
|
-
|
|
2743
|
-
String(record.sourceAgent || '').toLowerCase() !==
|
|
2744
|
-
String(record.targetAgent || '').toLowerCase()
|
|
2745
|
-
).length
|
|
2815
|
+
return records.filter((record) => String(record.sourceAgent || '').toLowerCase() !== String(record.targetAgent || '').toLowerCase())
|
|
2816
|
+
.length
|
|
2746
2817
|
} catch {
|
|
2747
2818
|
return 0
|
|
2748
2819
|
}
|
|
@@ -2789,11 +2860,9 @@ function statusCommand(useJson) {
|
|
|
2789
2860
|
console.log(`Observer: ${observer.isRunning(MIO_HOME) ? 'running (pid ' + observer.readPid(MIO_HOME) + ')' : 'not running'}`)
|
|
2790
2861
|
if (pendingAutoClaims > 0) {
|
|
2791
2862
|
console.log(
|
|
2792
|
-
`Pending auto-claims: ${pendingAutoClaims} (${pendingCrossAgent} cross-agent) -- only cross-agent claims whose target output actually cites the source memory may be confirmed; same-agent / weak / self-reported must NOT be (ADR-017)
|
|
2793
|
-
)
|
|
2794
|
-
console.log(
|
|
2795
|
-
` review: \`mio experience list --status pending\` then \`mio experience confirm --ids <id,...>\``
|
|
2863
|
+
`Pending auto-claims: ${pendingAutoClaims} (${pendingCrossAgent} cross-agent) -- only cross-agent claims whose target output actually cites the source memory may be confirmed; same-agent / weak / self-reported must NOT be (ADR-017).`,
|
|
2796
2864
|
)
|
|
2865
|
+
console.log(` review: \`mio experience list --status pending\` then \`mio experience confirm --ids <id,...>\``)
|
|
2797
2866
|
}
|
|
2798
2867
|
}
|
|
2799
2868
|
|
|
@@ -2928,9 +2997,7 @@ function agentsCommand(args, useJson) {
|
|
|
2928
2997
|
}
|
|
2929
2998
|
if (useJson) return jsonOrText(result, true)
|
|
2930
2999
|
console.log(`Registered ${result.agentId} (project=${project})`)
|
|
2931
|
-
console.log(
|
|
2932
|
-
` ${result.registered ? 'created' : `updated (session ${result.sessionCount})`} | host=${result.hostType}`,
|
|
2933
|
-
)
|
|
3000
|
+
console.log(` ${result.registered ? 'created' : `updated (session ${result.sessionCount})`} | host=${result.hostType}`)
|
|
2934
3001
|
if (result.capabilities && result.capabilities.length > 0) {
|
|
2935
3002
|
console.log(` capabilities: ${result.capabilities.join(', ')}`)
|
|
2936
3003
|
}
|
|
@@ -2951,9 +3018,7 @@ function printAgentList(result) {
|
|
|
2951
3018
|
for (const a of result.agents) {
|
|
2952
3019
|
const caps = Array.isArray(a.capabilities) && a.capabilities.length > 0 ? ` [${a.capabilities.join(', ')}]` : ''
|
|
2953
3020
|
console.log(`${a.agentId} (${a.hostType})${caps} project=${a.project || '-'}`)
|
|
2954
|
-
console.log(
|
|
2955
|
-
` sessions=${a.sessionCount || 0} tasks=${a.taskCount} success=${a.successCount} failure=${a.failureCount} | ${a.id}`,
|
|
2956
|
-
)
|
|
3021
|
+
console.log(` sessions=${a.sessionCount || 0} tasks=${a.taskCount} success=${a.successCount} failure=${a.failureCount} | ${a.id}`)
|
|
2957
3022
|
}
|
|
2958
3023
|
}
|
|
2959
3024
|
|
|
@@ -2967,9 +3032,7 @@ function printAgentReport(result) {
|
|
|
2967
3032
|
const o = r.taskOutcomes
|
|
2968
3033
|
const when = r.lastSeenAt ? r.lastSeenAt.slice(0, 19).replace('T', ' ') : 'unknown'
|
|
2969
3034
|
console.log(`${r.agentId} (${r.hostType}) ${r.active ? 'active' : 'idle'}`)
|
|
2970
|
-
console.log(
|
|
2971
|
-
` tasks: ${o.total} total, ${o.success} success, ${o.failure} failure (${o.successRate}% success)`,
|
|
2972
|
-
)
|
|
3035
|
+
console.log(` tasks: ${o.total} total, ${o.success} success, ${o.failure} failure (${o.successRate}% success)`)
|
|
2973
3036
|
console.log(` memories: ${r.memories} experience reuses: ${r.experienceReuses.total} (verified ${r.experienceReuses.verified})`)
|
|
2974
3037
|
console.log(` last seen: ${when} | sessions=${r.sessionCount}`)
|
|
2975
3038
|
}
|
|
@@ -2993,12 +3056,8 @@ function printRate(label, metric, numeratorKey, denominatorKey, unit, rateKey =
|
|
|
2993
3056
|
|
|
2994
3057
|
function printEvaluation(result) {
|
|
2995
3058
|
const s = result.sample
|
|
2996
|
-
console.log(
|
|
2997
|
-
|
|
2998
|
-
)
|
|
2999
|
-
console.log(
|
|
3000
|
-
` sample: queries=${s.queries} routeHits=${s.routeHits} reuses=${s.reuses} traces=${s.traces} agents=${s.agents}`,
|
|
3001
|
-
)
|
|
3059
|
+
console.log(`ADR-017 evaluation${result.project ? ` (project=${result.project})` : ''}${result.since ? ` since ${result.since}` : ''}`)
|
|
3060
|
+
console.log(` sample: queries=${s.queries} routeHits=${s.routeHits} reuses=${s.reuses} traces=${s.traces} agents=${s.agents}`)
|
|
3002
3061
|
console.log(' 1. route adoption rate (hit and acted on / hits)')
|
|
3003
3062
|
printRate('adoption', result.routeAdoption, 'adopted', 'routeHits', 'experience hits')
|
|
3004
3063
|
console.log(' 2. behaviour change rate (confirmed behaviorChanged / reuses)')
|
|
@@ -3012,9 +3071,7 @@ function printEvaluation(result) {
|
|
|
3012
3071
|
if (base) {
|
|
3013
3072
|
const now = result.behaviorChange.verified
|
|
3014
3073
|
const verdict = now >= base.observed ? 'at or above' : now >= base.required ? 'above threshold, below baseline' : 'BELOW BASELINE'
|
|
3015
|
-
console.log(
|
|
3016
|
-
` baseline ${result.baseline.date}: ${base.observed} (required ${base.required}) -- now ${now}, ${verdict}`,
|
|
3017
|
-
)
|
|
3074
|
+
console.log(` baseline ${result.baseline.date}: ${base.observed} (required ${base.required}) -- now ${now}, ${verdict}`)
|
|
3018
3075
|
}
|
|
3019
3076
|
console.log(' 3. recall quality (queries with results that led to a reuse)')
|
|
3020
3077
|
printRate('yield', result.recallQuality, 'queriesLinkedToReuse', 'queriesWithResults', 'queries', 'yield')
|
|
@@ -3393,11 +3450,7 @@ function installCommand(host, useJson) {
|
|
|
3393
3450
|
if (!observerCycleOk) {
|
|
3394
3451
|
console.error('Warning: observer cycle failed during install; run `mio observe --once` manually.')
|
|
3395
3452
|
}
|
|
3396
|
-
console.log(
|
|
3397
|
-
observer.isRunning(MIO_HOME)
|
|
3398
|
-
? 'Observer daemon running.'
|
|
3399
|
-
: 'Observer daemon not running. Run `mio observe --start`.'
|
|
3400
|
-
)
|
|
3453
|
+
console.log(observer.isRunning(MIO_HOME) ? 'Observer daemon running.' : 'Observer daemon not running. Run `mio observe --start`.')
|
|
3401
3454
|
}
|
|
3402
3455
|
|
|
3403
3456
|
function mcpCommand() {
|
|
@@ -3438,7 +3491,8 @@ function observeCommand(args, jsonFlag = false) {
|
|
|
3438
3491
|
console.log(result.started ? 'Observer started.' : 'Observer already running.')
|
|
3439
3492
|
if (researchResult) {
|
|
3440
3493
|
if (researchResult.skipped) console.log('Research scheduler skipped: ' + researchResult.skipped)
|
|
3441
|
-
else if (researchResult.started)
|
|
3494
|
+
else if (researchResult.started)
|
|
3495
|
+
console.log('Research scheduler started (pid ' + researchResult.pid + ', base-dir ' + researchResult.baseDir + ')')
|
|
3442
3496
|
else console.log('Research scheduler already running (pid ' + researchResult.pid + ')')
|
|
3443
3497
|
}
|
|
3444
3498
|
return
|
|
@@ -3447,10 +3501,7 @@ function observeCommand(args, jsonFlag = false) {
|
|
|
3447
3501
|
const result = observer.stopBackground(MIO_HOME)
|
|
3448
3502
|
const researchResult = observer.stopResearchBackground(MIO_HOME)
|
|
3449
3503
|
if (useJson) {
|
|
3450
|
-
return jsonOrText(
|
|
3451
|
-
{ ...result, research: { running: false, stopped: researchResult.stopped, pid: researchResult.pid } },
|
|
3452
|
-
true
|
|
3453
|
-
)
|
|
3504
|
+
return jsonOrText({ ...result, research: { running: false, stopped: researchResult.stopped, pid: researchResult.pid } }, true)
|
|
3454
3505
|
}
|
|
3455
3506
|
console.log(result.stopped ? 'Observer stopped.' : 'Observer was not running.')
|
|
3456
3507
|
console.log(researchResult.stopped ? 'Research scheduler stopped.' : 'Research scheduler was not running.')
|
|
@@ -3464,9 +3515,7 @@ function observeCommand(args, jsonFlag = false) {
|
|
|
3464
3515
|
const researchInfo = { running: researchRunning, pid: researchPid, logFile: observer.researchLogFile(MIO_HOME) }
|
|
3465
3516
|
if (useJson) return jsonOrText({ running, pid, research: researchInfo }, true)
|
|
3466
3517
|
console.log(running ? 'Observer: running (pid ' + pid + ')' : 'Observer: not running')
|
|
3467
|
-
console.log(
|
|
3468
|
-
researchRunning ? 'Research scheduler: running (pid ' + researchPid + ')' : 'Research scheduler: not running'
|
|
3469
|
-
)
|
|
3518
|
+
console.log(researchRunning ? 'Research scheduler: running (pid ' + researchPid + ')' : 'Research scheduler: not running')
|
|
3470
3519
|
return
|
|
3471
3520
|
}
|
|
3472
3521
|
if (flags.includes('--research') && !flags.includes('--start')) {
|
|
@@ -3475,11 +3524,7 @@ function observeCommand(args, jsonFlag = false) {
|
|
|
3475
3524
|
return
|
|
3476
3525
|
}
|
|
3477
3526
|
if (flags.includes('--once')) {
|
|
3478
|
-
const res = observer.runCycle(
|
|
3479
|
-
MIO_HOME,
|
|
3480
|
-
observer.loadState(MIO_HOME),
|
|
3481
|
-
observer.createSinks(MIO_HOME)
|
|
3482
|
-
)
|
|
3527
|
+
const res = observer.runCycle(MIO_HOME, observer.loadState(MIO_HOME), observer.createSinks(MIO_HOME))
|
|
3483
3528
|
if (useJson) return jsonOrText(res, true)
|
|
3484
3529
|
console.log('Observed files=' + res.files + ' lines=' + res.lines + ' outcomes=' + res.outcomes)
|
|
3485
3530
|
return
|
|
@@ -3540,6 +3585,9 @@ Usage:
|
|
|
3540
3585
|
mio creativity generate Generate hypotheses from 2+ --source "name|content" (or --from-insights; calls an LLM)
|
|
3541
3586
|
mio creativity ferment Review and refine active hypotheses (calls an LLM)
|
|
3542
3587
|
mio creativity adopt Record an adoption event for a stored hypothesis (writes traces only)
|
|
3588
|
+
mio mechanism registry List mechanism versions and promotion requests
|
|
3589
|
+
mio mechanism promote Submit/approve/reject a PromotionRequest (approver must differ from submitter)
|
|
3590
|
+
mio mechanism rollback Roll back the active version of a mechanism
|
|
3543
3591
|
mio idea generate --goal "..." Grounded idea pipeline: auto sources, novelty gate, persisted (calls an LLM)
|
|
3544
3592
|
mio insight status Insight counts: total, reported, unreported, high-value
|
|
3545
3593
|
mio insight list List insights (--unreported, --min-score N, --detector X, --limit N)
|
|
@@ -3604,6 +3652,8 @@ async function main() {
|
|
|
3604
3652
|
return policyCommand(args, useJson)
|
|
3605
3653
|
case 'creativity':
|
|
3606
3654
|
return creativityCommand(args, useJson)
|
|
3655
|
+
case 'mechanism':
|
|
3656
|
+
return mechanismCommand(args, useJson)
|
|
3607
3657
|
case 'idea':
|
|
3608
3658
|
return ideaCommand(args, useJson)
|
|
3609
3659
|
case 'insight':
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mio-agent-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"description": "Mio Agent Runtime installer and MCP intelligence layer",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@akemi-mio/evolution-scheduler": "^0.1.0",
|
|
37
37
|
"@akemi-mio/observer": "^0.1.5",
|
|
38
38
|
"@akemi-mio/insight": "^0.1.1",
|
|
39
|
-
"@akemi-mio/creativity": "^0.1.
|
|
39
|
+
"@akemi-mio/creativity": "^0.1.1"
|
|
40
40
|
},
|
|
41
41
|
"main": "index.js",
|
|
42
42
|
"directories": {
|