micro-models-agent 0.13.1 → 0.13.3
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/dist/cli/commands.js +2 -1
- package/dist/cli/repl.js +42 -20
- package/dist/config/config.js +42 -0
- package/dist/config/defaults.js +1 -1
- package/dist/config/security.js +1 -1
- package/dist/core/agent-moe.js +98 -0
- package/dist/core/agent.js +41 -250
- package/dist/core/bootstrap.js +4 -3
- package/dist/core/session-logger.js +122 -0
- package/dist/i18n/en.json +1 -0
- package/dist/i18n/ru.json +1 -0
- package/dist/llm/openai-compat.js +6 -9
- package/dist/modules/execution/moe-executor.js +13 -0
- package/dist/modules/hallucination/confidence.js +22 -15
- package/dist/modules/hallucination/consistency.js +29 -1
- package/dist/modules/hallucination/factual.js +49 -7
- package/dist/modules/processes/registry.js +6 -0
- package/dist/modules/security/command-validator.js +57 -14
- package/dist/modules/security/encryption.js +8 -6
- package/dist/modules/session/module.js +0 -4
- package/dist/tools/bash.js +27 -0
- package/dist/tools/create-dir.js +3 -4
- package/dist/tools/delete-file.js +3 -4
- package/dist/tools/edit-file.js +3 -4
- package/dist/tools/executor.js +6 -0
- package/dist/tools/file-info.js +3 -4
- package/dist/tools/list-dir.js +4 -4
- package/dist/tools/path-utils.js +51 -0
- package/dist/tools/read-file.js +6 -3
- package/dist/tools/write-file.js +5 -5
- package/dist/ui/renderer.js +1 -1
- package/package.json +1 -1
package/dist/cli/commands.js
CHANGED
|
@@ -6,11 +6,12 @@ import { t } from "../i18n/index";
|
|
|
6
6
|
import { join } from "path";
|
|
7
7
|
import { homedir } from "os";
|
|
8
8
|
import { createSecurityCommand } from "./security-commands";
|
|
9
|
+
import { version } from "../../package.json";
|
|
9
10
|
export function createProgram() {
|
|
10
11
|
const program = new Command()
|
|
11
12
|
.name("mma")
|
|
12
13
|
.description(t("cli.description"))
|
|
13
|
-
.version(
|
|
14
|
+
.version(version)
|
|
14
15
|
.option("--no-agents-md", t("cli.no_agents_md"))
|
|
15
16
|
.option("-d, --dir <path>", t("cli.dir"))
|
|
16
17
|
.option("-e, --exit-on-complete", t("cli.exit_on_complete"))
|
package/dist/cli/repl.js
CHANGED
|
@@ -43,6 +43,7 @@ export class Repl {
|
|
|
43
43
|
commands = new Map();
|
|
44
44
|
completer = new Completer();
|
|
45
45
|
running = false;
|
|
46
|
+
agentRunning = false;
|
|
46
47
|
agent;
|
|
47
48
|
config;
|
|
48
49
|
sessionManager;
|
|
@@ -609,6 +610,15 @@ export class Repl {
|
|
|
609
610
|
let inMultiLine = false;
|
|
610
611
|
this.rl.on("line", async (line) => {
|
|
611
612
|
const trimmed = line.trim();
|
|
613
|
+
if (this.agentRunning) {
|
|
614
|
+
if (trimmed) {
|
|
615
|
+
this.history.push(trimmed);
|
|
616
|
+
if (this.history.length > this.maxHistory) {
|
|
617
|
+
this.history = this.history.slice(-this.maxHistory);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
612
622
|
if (trimmed) {
|
|
613
623
|
this.history.push(trimmed);
|
|
614
624
|
if (this.history.length > this.maxHistory) {
|
|
@@ -692,29 +702,41 @@ export class Repl {
|
|
|
692
702
|
return false;
|
|
693
703
|
}
|
|
694
704
|
async runAgent(input) {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
705
|
+
if (this.agentRunning)
|
|
706
|
+
return;
|
|
707
|
+
this.agentRunning = true;
|
|
708
|
+
this.rl.pause();
|
|
709
|
+
try {
|
|
710
|
+
process.stdout.write("\n" + pc.green(t("repl.agent")));
|
|
711
|
+
const renderer = new Renderer({ spinner: this.config.ui?.spinner ?? true });
|
|
712
|
+
const result = await this.agent.run(input, (c) => renderer.text(c), (m) => renderer.meta(m), (ev) => {
|
|
713
|
+
if (ev.type === "start") {
|
|
714
|
+
renderer.toolStart(ev.tool, ev.args);
|
|
715
|
+
}
|
|
716
|
+
else {
|
|
717
|
+
renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error);
|
|
718
|
+
}
|
|
719
|
+
}, (phase) => {
|
|
720
|
+
if (phase === "thinking") {
|
|
721
|
+
renderer.thinkingStart();
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
renderer.thinkingEnd();
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
renderer.flush();
|
|
728
|
+
process.stdout.write("\n");
|
|
729
|
+
if (!result.success) {
|
|
730
|
+
console.error(pc.red(`${t("error.prefix")}${result.error}`));
|
|
707
731
|
}
|
|
708
|
-
|
|
709
|
-
|
|
732
|
+
this.showContextBar(result);
|
|
733
|
+
}
|
|
734
|
+
finally {
|
|
735
|
+
this.agentRunning = false;
|
|
736
|
+
if (this.running) {
|
|
737
|
+
this.rl.resume();
|
|
710
738
|
}
|
|
711
|
-
});
|
|
712
|
-
renderer.flush();
|
|
713
|
-
process.stdout.write("\n");
|
|
714
|
-
if (!result.success) {
|
|
715
|
-
console.error(pc.red(`${t("error.prefix")}${result.error}`));
|
|
716
739
|
}
|
|
717
|
-
this.showContextBar(result);
|
|
718
740
|
}
|
|
719
741
|
registerCommand(cmd) {
|
|
720
742
|
this.commands.set(cmd.name, cmd);
|
package/dist/config/config.js
CHANGED
|
@@ -7,6 +7,13 @@ import { MigrationDetector } from '../migration/detect';
|
|
|
7
7
|
import { BackupManager } from '../migration/backup';
|
|
8
8
|
import { validateExpertConfig } from './experts';
|
|
9
9
|
import { ConfigEncryptor } from '../modules/security/encryption';
|
|
10
|
+
/**
|
|
11
|
+
* When the user's config version is older than this, force-overwrite
|
|
12
|
+
* the security bash settings with the current defaults.
|
|
13
|
+
* This ensures critical security changes (like operator allowlists)
|
|
14
|
+
* are applied even if the user has a saved config.
|
|
15
|
+
*/
|
|
16
|
+
const FORCE_SECURITY_UPDATE_VERSION = '2.1.0';
|
|
10
17
|
/**
|
|
11
18
|
* Restore RegExp instances in dangerousPatterns that were serialized as {}
|
|
12
19
|
* (pre-0.8.0 configs) or as {__regex, source, flags} (new format).
|
|
@@ -115,6 +122,39 @@ function applyEnvVars(config) {
|
|
|
115
122
|
result.moe = { ...result.moe, enabled: env.MMA_MOE_ENABLED === 'true' };
|
|
116
123
|
return result;
|
|
117
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Force-update security settings when upgrading from an older version.
|
|
127
|
+
* This overrides user config for critical security fields that must
|
|
128
|
+
* match the current code defaults (e.g. dangerousOperators).
|
|
129
|
+
*/
|
|
130
|
+
function forceSecurityUpdate(config) {
|
|
131
|
+
const userVersion = config.version || '0.0.0';
|
|
132
|
+
if (userVersion >= FORCE_SECURITY_UPDATE_VERSION)
|
|
133
|
+
return config;
|
|
134
|
+
// Force-overwrite bash security with current defaults
|
|
135
|
+
const security = config.security || {};
|
|
136
|
+
const userBash = security.bash || {};
|
|
137
|
+
security.bash = {
|
|
138
|
+
...DEFAULT_SECURITY_CONFIG.bash,
|
|
139
|
+
// Keep user's custom blacklist additions, but ensure defaults are present
|
|
140
|
+
blacklist: [...new Set([
|
|
141
|
+
...DEFAULT_SECURITY_CONFIG.bash.blacklist,
|
|
142
|
+
...(userBash.blacklist || []),
|
|
143
|
+
])],
|
|
144
|
+
whitelist: userBash.whitelist || DEFAULT_SECURITY_CONFIG.bash.whitelist,
|
|
145
|
+
dangerousFlags: [...new Set([
|
|
146
|
+
...DEFAULT_SECURITY_CONFIG.bash.dangerousFlags,
|
|
147
|
+
...(userBash.dangerousFlags || []),
|
|
148
|
+
])],
|
|
149
|
+
// dangerousOperators: ALWAYS use defaults — user overrides are dangerous
|
|
150
|
+
dangerousOperators: [...DEFAULT_SECURITY_CONFIG.bash.dangerousOperators],
|
|
151
|
+
blockDangerousFlags: DEFAULT_SECURITY_CONFIG.bash.blockDangerousFlags,
|
|
152
|
+
logCommands: DEFAULT_SECURITY_CONFIG.bash.logCommands,
|
|
153
|
+
};
|
|
154
|
+
config.security = security;
|
|
155
|
+
console.log(t('migration.security_updated', { from: userVersion, to: FORCE_SECURITY_UPDATE_VERSION }));
|
|
156
|
+
return config;
|
|
157
|
+
}
|
|
118
158
|
export function loadConfig(options) {
|
|
119
159
|
const globalPath = join(options.configDir, 'config.json');
|
|
120
160
|
mkdirSync(options.configDir, { recursive: true });
|
|
@@ -146,6 +186,8 @@ export function loadConfig(options) {
|
|
|
146
186
|
if (config.security?.contentScan?.dangerousPatterns) {
|
|
147
187
|
config.security.contentScan.dangerousPatterns = restoreDangerousPatterns(config.security.contentScan.dangerousPatterns, DEFAULT_SECURITY_CONFIG.contentScan.dangerousPatterns);
|
|
148
188
|
}
|
|
189
|
+
// Force-update security settings when upgrading from older version
|
|
190
|
+
config = forceSecurityUpdate(config);
|
|
149
191
|
config = applyEnvVars(config);
|
|
150
192
|
// Decrypt sensitive fields in the loaded config
|
|
151
193
|
try {
|
package/dist/config/defaults.js
CHANGED
|
@@ -76,7 +76,7 @@ export const DEFAULTS = {
|
|
|
76
76
|
transport: "http",
|
|
77
77
|
url: "https://mcp.context7.com/mcp",
|
|
78
78
|
headers: {
|
|
79
|
-
CONTEXT7_API_KEY: "
|
|
79
|
+
CONTEXT7_API_KEY: process.env.CONTEXT7_API_KEY || "",
|
|
80
80
|
},
|
|
81
81
|
enabled: true,
|
|
82
82
|
timeout: 30000,
|
package/dist/config/security.js
CHANGED
|
@@ -65,7 +65,7 @@ export const DEFAULT_SECURITY_CONFIG = {
|
|
|
65
65
|
"--no-confirm",
|
|
66
66
|
],
|
|
67
67
|
// Dangerous operators that are always blocked
|
|
68
|
-
dangerousOperators: [">", ">>", "2>", "2>>", "
|
|
68
|
+
dangerousOperators: [">", ">>", "2>", "2>>", "&", "`"],
|
|
69
69
|
},
|
|
70
70
|
paths: {
|
|
71
71
|
// Glob patterns for paths that are always denied
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { OrchestratorClient } from "../llm/orchestrator";
|
|
2
|
+
import { validatePlan, applyAutoFixes, } from "../modules/execution/plan-validator";
|
|
3
|
+
import { MoEExecutor } from "../modules/execution/moe-executor";
|
|
4
|
+
import { StepVerifier } from "../modules/execution/verifier";
|
|
5
|
+
/**
|
|
6
|
+
* Execute the MoE (Mixture of Experts) path: plan → validate → execute → verify.
|
|
7
|
+
* Returns a fallback signal when MoE cannot proceed so the caller can fall
|
|
8
|
+
* back to the single-agent loop.
|
|
9
|
+
*/
|
|
10
|
+
export async function runWithMoE(deps, input, fallback, opts = {}) {
|
|
11
|
+
const { config, llmProvider, logger, toolExecutor, baseDir } = deps;
|
|
12
|
+
const { onMeta, onPhase } = opts;
|
|
13
|
+
const orchestrator = new OrchestratorClient({
|
|
14
|
+
model: config.orchestrator.model,
|
|
15
|
+
provider: config.orchestrator.provider,
|
|
16
|
+
}, llmProvider);
|
|
17
|
+
if (!orchestrator.isEnabled()) {
|
|
18
|
+
logger.debug("MoE enabled but no orchestrator model configured — falling back to single-agent");
|
|
19
|
+
return fallback();
|
|
20
|
+
}
|
|
21
|
+
onMeta?.("🤖 Planning with MoE mode...\n");
|
|
22
|
+
onPhase?.("thinking");
|
|
23
|
+
const planResult = await orchestrator.plan(input);
|
|
24
|
+
onPhase?.("done");
|
|
25
|
+
if ("error" in planResult) {
|
|
26
|
+
logger.warn(`MoE plan failed: ${planResult.error} — falling back to single-agent`);
|
|
27
|
+
return fallback();
|
|
28
|
+
}
|
|
29
|
+
const { plan } = planResult;
|
|
30
|
+
onMeta?.(`📋 Plan created: "${plan.title}" (${plan.subtasks.length} subtasks)\n`);
|
|
31
|
+
const validation = validatePlan(plan, config);
|
|
32
|
+
if (!validation.valid) {
|
|
33
|
+
const applied = applyAutoFixes(plan, validation.autoFixes);
|
|
34
|
+
const retry = validatePlan(applied, config);
|
|
35
|
+
if (!retry.valid) {
|
|
36
|
+
logger.warn(`MoE plan validation failed: ${retry.errors.join("; ")} — falling back to single-agent`);
|
|
37
|
+
onMeta?.(`⚠️ Plan validation failed. Falling back to single-agent mode.\n`);
|
|
38
|
+
return fallback();
|
|
39
|
+
}
|
|
40
|
+
Object.assign(plan, applied);
|
|
41
|
+
onMeta?.(`🔧 Auto-fixed ${validation.autoFixes.length} plan issues.\n`);
|
|
42
|
+
}
|
|
43
|
+
const moeDeps = {
|
|
44
|
+
config,
|
|
45
|
+
toolRegistry: toolExecutor.getRegistry(),
|
|
46
|
+
toolExecutor,
|
|
47
|
+
llmProvider,
|
|
48
|
+
logger,
|
|
49
|
+
baseDir,
|
|
50
|
+
};
|
|
51
|
+
const executor = new MoEExecutor(moeDeps);
|
|
52
|
+
onMeta?.(`⚙️ Executing ${plan.subtasks.length} subtasks...\n`);
|
|
53
|
+
const planResults = await executor.executePlan(plan);
|
|
54
|
+
onMeta?.(`✅ Execution complete: ${planResults.results.filter((r) => r.success).length}/${planResults.results.length} succeeded\n`);
|
|
55
|
+
const verifier = new StepVerifier(baseDir);
|
|
56
|
+
const knownTags = [
|
|
57
|
+
"file",
|
|
58
|
+
"code",
|
|
59
|
+
"shell",
|
|
60
|
+
"research",
|
|
61
|
+
"browser",
|
|
62
|
+
"vision",
|
|
63
|
+
"core",
|
|
64
|
+
];
|
|
65
|
+
const verification = await verifier.verifyMoEManifest(plan, config, knownTags);
|
|
66
|
+
onPhase?.("thinking");
|
|
67
|
+
const verifyResult = await orchestrator.verifyAndMerge({
|
|
68
|
+
plan,
|
|
69
|
+
results: planResults.results.map((r) => ({
|
|
70
|
+
subtaskId: r.subtaskId,
|
|
71
|
+
success: r.success,
|
|
72
|
+
summary: r.summary,
|
|
73
|
+
result: r.result,
|
|
74
|
+
error: r.error,
|
|
75
|
+
})),
|
|
76
|
+
verifierErrors: verification.errors,
|
|
77
|
+
verifierWarnings: verification.warnings,
|
|
78
|
+
});
|
|
79
|
+
onPhase?.("done");
|
|
80
|
+
const outputLines = [`## MoE Execution Results\n`];
|
|
81
|
+
for (const r of planResults.results) {
|
|
82
|
+
const icon = r.success ? "✅" : "❌";
|
|
83
|
+
outputLines.push(`${icon} **${r.subtaskId}**: ${r.summary} (${r.durationMs}ms)`);
|
|
84
|
+
}
|
|
85
|
+
outputLines.push("");
|
|
86
|
+
if (verifyResult.type === "final") {
|
|
87
|
+
outputLines.push(`**Result:** ${verifyResult.finalAnswer || "Complete"}`);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
outputLines.push(`**Re-plan requested:** ${verifyResult.explanation || ""}`);
|
|
91
|
+
}
|
|
92
|
+
const failedCount = planResults.results.filter((r) => !r.success).length;
|
|
93
|
+
return {
|
|
94
|
+
success: failedCount === 0 && verification.success,
|
|
95
|
+
text: outputLines.join("\n"),
|
|
96
|
+
iterationCount: planResults.results.length,
|
|
97
|
+
};
|
|
98
|
+
}
|