micro-models-agent 0.13.1 → 0.13.2

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.
@@ -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("0.4.0")
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
- process.stdout.write("\n" + pc.green(t("repl.agent")));
696
- const renderer = new Renderer({ spinner: this.config.ui?.spinner ?? true });
697
- const result = await this.agent.run(input, (c) => renderer.text(c), (m) => renderer.meta(m), (ev) => {
698
- if (ev.type === "start") {
699
- renderer.toolStart(ev.tool, ev.args);
700
- }
701
- else {
702
- renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error);
703
- }
704
- }, (phase) => {
705
- if (phase === "thinking") {
706
- renderer.thinkingStart();
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
- else {
709
- renderer.thinkingEnd();
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);
@@ -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 {
@@ -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: "ctx7sk-f3dd1f44-bc3a-4f6b-94c0-87cacb6c084b",
79
+ CONTEXT7_API_KEY: process.env.CONTEXT7_API_KEY || "",
80
80
  },
81
81
  enabled: true,
82
82
  timeout: 30000,
@@ -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
+ }
@@ -1,11 +1,9 @@
1
1
  import { t } from "../i18n/index";
2
2
  import { pc } from "../ui/colors";
3
3
  import { PromptBuilder } from "./prompt-builder";
4
- import { OrchestratorClient } from "../llm/orchestrator";
5
- import { validatePlan, applyAutoFixes, } from "../modules/execution/plan-validator";
6
- import { MoEExecutor } from "../modules/execution/moe-executor";
7
- import { StepVerifier } from "../modules/execution/verifier";
8
4
  import { processRegistry } from "../modules/processes";
5
+ import { SessionLogger } from "./session-logger";
6
+ import { runWithMoE } from "./agent-moe";
9
7
  const TOOL_RESULT_MAX_TOKENS_RATIO = 0.3;
10
8
  const TOOL_RESULT_ABSOLUTE_MAX_CHARS = 15000;
11
9
  export class Agent {
@@ -15,9 +13,8 @@ export class Agent {
15
13
  this.deps = deps;
16
14
  }
17
15
  setScope() {
18
- const executor = this.deps.toolExecutor;
19
- if (executor && executor.ctx && this.deps.scope) {
20
- executor.ctx.scope = this.deps.scope;
16
+ if (this.deps.scope) {
17
+ this.deps.toolExecutor.setScope(this.deps.scope);
21
18
  }
22
19
  }
23
20
  buildSystemPrompt() {
@@ -42,7 +39,6 @@ export class Agent {
42
39
  }
43
40
  return builder.build();
44
41
  }
45
- /** Refresh the system prompt in context if dynamic blocks changed. */
46
42
  refreshSystemPrompt() {
47
43
  const { prompt } = this.buildSystemPrompt();
48
44
  const current = this.deps.contextManager
@@ -70,7 +66,8 @@ export class Agent {
70
66
  }
71
67
  async run(input, onChunk, onMeta, onTool, onPhase) {
72
68
  this.setScope();
73
- const { config, llmProvider, toolExecutor, pluginManager, contextManager, hallucinationDetector, logger, sessionManager, } = this.deps;
69
+ const { config, llmProvider, toolExecutor, pluginManager, contextManager, logger, sessionManager, } = this.deps;
70
+ const slog = new SessionLogger(sessionManager);
74
71
  if (sessionManager && !sessionManager.getActive()) {
75
72
  sessionManager.create();
76
73
  logger.debug(`Session started: ${sessionManager.getActive()}`);
@@ -80,19 +77,9 @@ export class Agent {
80
77
  const { prompt: systemPrompt, excluded } = this.buildSystemPrompt();
81
78
  contextManager.addMessage({ role: "system", content: systemPrompt });
82
79
  this.systemPromptAdded = true;
83
- if (sessionManager) {
84
- sessionManager.appendLog({
85
- ts: new Date().toISOString(),
86
- type: "system",
87
- content: systemPrompt.slice(0, 2000),
88
- });
89
- if (excluded.length > 0) {
90
- sessionManager.appendLog({
91
- ts: new Date().toISOString(),
92
- type: "system",
93
- content: `[Excluded prompt blocks: ${excluded.length}]`,
94
- });
95
- }
80
+ slog.logSystem(systemPrompt.slice(0, 2000));
81
+ if (excluded.length > 0) {
82
+ slog.logSystem(`[Excluded prompt blocks: ${excluded.length}]`);
96
83
  }
97
84
  pluginManager.runOnSessionStart({
98
85
  logger,
@@ -100,25 +87,21 @@ export class Agent {
100
87
  });
101
88
  }
102
89
  contextManager.addMessage({ role: "user", content: input });
103
- if (sessionManager) {
104
- sessionManager.appendMessage({
105
- role: "user",
106
- content: input,
107
- timestamp: new Date().toISOString(),
108
- });
109
- sessionManager.appendLog({
110
- ts: new Date().toISOString(),
111
- type: "user",
112
- content: input,
113
- });
114
- }
90
+ slog.logUser(input);
115
91
  if (config.moe?.enabled) {
116
- return this.runWithMoE(input, onChunk, onMeta, onTool, onPhase);
92
+ return runWithMoE({
93
+ config,
94
+ llmProvider,
95
+ toolExecutor,
96
+ logger,
97
+ baseDir: this.deps.baseDir,
98
+ }, input, () => this.executeSingleAgentLoop(input, onChunk, onMeta, onTool, onPhase), { onMeta, onTool, onPhase });
117
99
  }
118
100
  return this.executeSingleAgentLoop(input, onChunk, onMeta, onTool, onPhase);
119
101
  }
120
102
  async executeSingleAgentLoop(input, onChunk, onMeta, onTool, onPhase) {
121
103
  const { config, llmProvider, toolExecutor, pluginManager, contextManager, hallucinationDetector, logger, sessionManager, } = this.deps;
104
+ const slog = new SessionLogger(sessionManager);
122
105
  let iteration = 0;
123
106
  let lastText = "";
124
107
  let hallucinationRetries = 0;
@@ -136,43 +119,19 @@ export class Agent {
136
119
  if (contextManager.needsCompaction()) {
137
120
  contextManager.compact();
138
121
  logger.debug("Context compacted");
139
- if (sessionManager) {
140
- sessionManager.appendLog({
141
- ts: new Date().toISOString(),
142
- type: "compaction",
143
- content: `regular compaction, iteration ${iteration}`,
144
- iteration,
145
- });
146
- }
122
+ slog.logCompaction(`regular compaction, iteration ${iteration}`, iteration);
147
123
  }
148
124
  const currentTokens = contextManager.getEstimatedTokens();
149
125
  const budget = contextManager.getBudget();
150
126
  if (currentTokens > budget.history) {
151
127
  contextManager.compact();
152
128
  logger.warn(`Context overflow (${currentTokens} > ${budget.history}), forced compaction`);
153
- if (sessionManager) {
154
- sessionManager.appendLog({
155
- ts: new Date().toISOString(),
156
- type: "compaction",
157
- content: `forced compaction (${currentTokens} > ${budget.history}), iteration ${iteration}`,
158
- iteration,
159
- contextTokens: currentTokens,
160
- contextLimit: budget.history,
161
- });
162
- }
129
+ slog.logCompaction(`forced compaction (${currentTokens} > ${budget.history}), iteration ${iteration}`, iteration, currentTokens, budget.history);
163
130
  }
164
131
  this.refreshSystemPrompt();
165
132
  const history = contextManager.getActiveHistory();
166
133
  const allTools = toolExecutor.getToolDefinitions(this.deps.toolTags);
167
- if (sessionManager) {
168
- sessionManager.appendLog({
169
- ts: new Date().toISOString(),
170
- type: "tool_defs",
171
- toolCount: allTools.length,
172
- toolNames: allTools.map((t) => t.name),
173
- iteration,
174
- });
175
- }
134
+ slog.logToolDefs(allTools.length, allTools.map((t) => t.name), iteration);
176
135
  let textContent = "";
177
136
  let reasoningContent = "";
178
137
  const toolCalls = [];
@@ -218,13 +177,7 @@ export class Agent {
218
177
  }
219
178
  catch (err) {
220
179
  logger.error(`LLM call failed: ${err.message}`);
221
- if (sessionManager) {
222
- sessionManager.appendLog({
223
- ts: new Date().toISOString(),
224
- type: "error",
225
- content: err.message,
226
- });
227
- }
180
+ slog.logError(err.message);
228
181
  pluginManager.runOnError({ iteration, logger }, err);
229
182
  return {
230
183
  success: false,
@@ -257,28 +210,8 @@ export class Agent {
257
210
  }
258
211
  lastToolSignature = signature;
259
212
  }
260
- if (sessionManager) {
261
- if (reasoningContent) {
262
- sessionManager.appendLog({
263
- ts: new Date().toISOString(),
264
- type: "reasoning",
265
- content: reasoningContent,
266
- iteration,
267
- });
268
- }
269
- if (sawToolCall) {
270
- sessionManager.appendLog({
271
- ts: new Date().toISOString(),
272
- type: "assistant",
273
- content: textContent || "",
274
- tool_calls: toolCalls.map((tc) => ({
275
- id: tc.id,
276
- name: tc.name,
277
- arguments: tc.arguments,
278
- })),
279
- iteration,
280
- });
281
- }
213
+ if (sawToolCall) {
214
+ slog.logAssistant(textContent || "", reasoningContent, toolCalls, iteration);
282
215
  }
283
216
  if (sawToolCall) {
284
217
  contextManager.addMessage({
@@ -303,16 +236,7 @@ export class Agent {
303
236
  });
304
237
  pluginManager.runOnToolStart({ iteration, logger }, { id: call.id, name: call.name, arguments: call.arguments });
305
238
  onTool?.({ type: "start", tool: call.name, args: call.arguments });
306
- if (sessionManager) {
307
- sessionManager.appendLog({
308
- ts: new Date().toISOString(),
309
- type: "tool_call",
310
- tool: call.name,
311
- tool_call_id: call.id,
312
- args: call.arguments,
313
- iteration,
314
- });
315
- }
239
+ slog.logToolCall(call, iteration);
316
240
  const result = await toolExecutor.execute(call);
317
241
  const duration = Date.now() - startTime;
318
242
  pluginManager.runOnToolEnd({ iteration, logger }, { id: call.id, name: call.name, arguments: call.arguments }, result, duration);
@@ -341,24 +265,8 @@ export class Agent {
341
265
  tool_call_id: call.id,
342
266
  });
343
267
  summaries.push(`[Tool: ${call.name} (${JSON.stringify(call.arguments)}) → ${truncatedOutput.slice(0, 200)}]`);
344
- if (sessionManager && config.session.autoSave) {
345
- sessionManager.appendMessage({
346
- role: "tool",
347
- content: truncatedOutput.slice(0, 500),
348
- name: call.name,
349
- timestamp: new Date().toISOString(),
350
- });
351
- sessionManager.appendLog({
352
- ts: new Date().toISOString(),
353
- type: "tool_result",
354
- tool: call.name,
355
- tool_call_id: call.id,
356
- success: result.success,
357
- content: result.output.slice(0, 1000),
358
- diff: result.diff,
359
- duration,
360
- iteration,
361
- });
268
+ if (config.session.autoSave) {
269
+ slog.logToolResult(call, result, duration, iteration);
362
270
  }
363
271
  if (contextManager.needsCompaction()) {
364
272
  contextManager.compact();
@@ -423,39 +331,8 @@ export class Agent {
423
331
  }
424
332
  if (textContent) {
425
333
  contextManager.addMessage({ role: "assistant", content: textContent });
426
- if (sessionManager && config.session.autoSave) {
427
- sessionManager.appendMessage({
428
- role: "assistant",
429
- content: textContent.slice(0, 500),
430
- timestamp: new Date().toISOString(),
431
- });
432
- }
433
- }
434
- if (sessionManager) {
435
- if (reasoningContent) {
436
- sessionManager.appendLog({
437
- ts: new Date().toISOString(),
438
- type: "reasoning",
439
- content: reasoningContent,
440
- iteration,
441
- });
442
- }
443
- if (textContent) {
444
- sessionManager.appendLog({
445
- ts: new Date().toISOString(),
446
- type: "assistant",
447
- content: textContent,
448
- iteration,
449
- });
450
- }
451
- else if (reasoningContent) {
452
- sessionManager.appendLog({
453
- ts: new Date().toISOString(),
454
- type: "assistant",
455
- content: reasoningContent,
456
- iteration,
457
- });
458
- }
334
+ slog.saveAssistantMessage(textContent);
335
+ slog.logAssistant(textContent, reasoningContent, undefined, iteration);
459
336
  }
460
337
  lastText = textContent;
461
338
  if (!sawToolCall) {
@@ -471,14 +348,7 @@ export class Agent {
471
348
  steps,
472
349
  })}</system-summary>`,
473
350
  });
474
- if (sessionManager) {
475
- sessionManager.appendLog({
476
- ts: new Date().toISOString(),
477
- type: "audit",
478
- content: audit.summary,
479
- iteration,
480
- });
481
- }
351
+ slog.logAudit(audit.summary, iteration);
482
352
  if (iteration >= config.maxToolIterations - 1) {
483
353
  break;
484
354
  }
@@ -508,94 +378,6 @@ export class Agent {
508
378
  contextLimit: budget.history,
509
379
  };
510
380
  }
511
- async runWithMoE(input, _onChunk, onMeta, onTool, onPhase) {
512
- const { config, llmProvider, logger } = this.deps;
513
- const orchestrator = new OrchestratorClient({
514
- model: config.orchestrator.model,
515
- provider: config.orchestrator.provider,
516
- }, llmProvider);
517
- if (!orchestrator.isEnabled()) {
518
- logger.debug("MoE enabled but no orchestrator model configured — falling back to single-agent");
519
- return this.executeSingleAgentLoop(input, _onChunk, onMeta, onTool, onPhase);
520
- }
521
- onMeta?.("🤖 Planning with MoE mode...\n");
522
- this.emitPhase(0, "thinking", onPhase);
523
- const planResult = await orchestrator.plan(input);
524
- this.emitPhase(0, "done", onPhase);
525
- if ("error" in planResult) {
526
- logger.warn(`MoE plan failed: ${planResult.error} — falling back to single-agent`);
527
- return this.executeSingleAgentLoop(input, _onChunk, onMeta, onTool);
528
- }
529
- const { plan } = planResult;
530
- onMeta?.(`📋 Plan created: "${plan.title}" (${plan.subtasks.length} subtasks)\n`);
531
- const validation = validatePlan(plan, config);
532
- if (!validation.valid) {
533
- const applied = applyAutoFixes(plan, validation.autoFixes);
534
- const retry = validatePlan(applied, config);
535
- if (!retry.valid) {
536
- logger.warn(`MoE plan validation failed: ${retry.errors.join("; ")} — falling back to single-agent`);
537
- onMeta?.(`⚠️ Plan validation failed. Falling back to single-agent mode.\n`);
538
- return this.executeSingleAgentLoop(input, _onChunk, onMeta, onTool);
539
- }
540
- Object.assign(plan, applied);
541
- onMeta?.(`🔧 Auto-fixed ${validation.autoFixes.length} plan issues.\n`);
542
- }
543
- const moeDeps = {
544
- config,
545
- toolRegistry: this.deps.toolExecutor.registry,
546
- toolExecutor: this.deps.toolExecutor,
547
- llmProvider,
548
- logger,
549
- baseDir: this.deps.baseDir,
550
- };
551
- const executor = new MoEExecutor(moeDeps);
552
- onMeta?.(`⚙️ Executing ${plan.subtasks.length} subtasks...\n`);
553
- const planResults = await executor.executePlan(plan);
554
- onMeta?.(`✅ Execution complete: ${planResults.results.filter((r) => r.success).length}/${planResults.results.length} succeeded\n`);
555
- const verifier = new StepVerifier(this.deps.baseDir);
556
- const knownTags = [
557
- "file",
558
- "code",
559
- "shell",
560
- "research",
561
- "browser",
562
- "vision",
563
- "core",
564
- ];
565
- const verification = await verifier.verifyMoEManifest(plan, config, knownTags);
566
- this.emitPhase(0, "thinking", onPhase);
567
- const verifyResult = await orchestrator.verifyAndMerge({
568
- plan,
569
- results: planResults.results.map((r) => ({
570
- subtaskId: r.subtaskId,
571
- success: r.success,
572
- summary: r.summary,
573
- result: r.result,
574
- error: r.error,
575
- })),
576
- verifierErrors: verification.errors,
577
- verifierWarnings: verification.warnings,
578
- });
579
- this.emitPhase(0, "done", onPhase);
580
- const outputLines = [`## MoE Execution Results\n`];
581
- for (const r of planResults.results) {
582
- const icon = r.success ? "✅" : "❌";
583
- outputLines.push(`${icon} **${r.subtaskId}**: ${r.summary} (${r.durationMs}ms)`);
584
- }
585
- outputLines.push("");
586
- if (verifyResult.type === "final") {
587
- outputLines.push(`**Result:** ${verifyResult.finalAnswer || "Complete"}`);
588
- }
589
- else {
590
- outputLines.push(`**Re-plan requested:** ${verifyResult.explanation || ""}`);
591
- }
592
- const failedCount = planResults.results.filter((r) => !r.success).length;
593
- return {
594
- success: failedCount === 0 && verification.success,
595
- text: outputLines.join("\n"),
596
- iterationCount: planResults.results.length,
597
- };
598
- }
599
381
  clearContext() {
600
382
  this.deps.contextManager.clear();
601
383
  this.systemPromptAdded = false;