micro-models-agent 0.28.9 → 0.29.0
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 +220 -0
- package/dist/cli/completer.js +168 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/main.js +113 -0
- package/dist/cli/repl.js +987 -0
- package/dist/cli/security-commands.js +166 -0
- package/dist/cli/setup.js +229 -0
- package/dist/config/config.js +186 -0
- package/dist/config/defaults.js +91 -0
- package/dist/config/experts.js +15 -0
- package/dist/config/index.js +3 -0
- package/dist/config/security.js +193 -0
- package/dist/config/types.js +1 -0
- package/dist/core/agent-moe.js +98 -0
- package/dist/core/agent.js +461 -0
- package/dist/core/bootstrap.js +321 -0
- package/dist/core/index.js +2 -0
- package/dist/core/prompt-builder.js +55 -0
- package/dist/core/session-logger.js +122 -0
- package/dist/core/types.js +1 -0
- package/dist/i18n/en.json +461 -0
- package/dist/i18n/index.js +43 -0
- package/dist/i18n/ru.json +461 -0
- package/dist/index.js +22 -0
- package/dist/llm/image-utils.js +144 -0
- package/dist/llm/index.js +4 -0
- package/dist/llm/model-loader.js +78 -0
- package/dist/llm/openai-compat.js +324 -0
- package/dist/llm/orchestrator.js +194 -0
- package/dist/llm/provider.js +10 -0
- package/dist/llm/response.js +39 -0
- package/dist/llm/token-counter.js +39 -0
- package/dist/llm/types.js +1 -0
- package/dist/logger/app-logger.js +76 -0
- package/dist/logger/index.js +1 -0
- package/dist/main.js +2251 -724
- package/dist/migration/backup.js +45 -0
- package/dist/migration/detect.js +50 -0
- package/dist/migration/index.js +2 -0
- package/dist/modules/browser/actions.js +46 -0
- package/dist/modules/browser/cookie-store.js +24 -0
- package/dist/modules/browser/index.js +5 -0
- package/dist/modules/browser/module.js +28 -0
- package/dist/modules/browser/session.js +287 -0
- package/dist/modules/browser/snapshot.js +114 -0
- package/dist/modules/browser/types.js +9 -0
- package/dist/modules/context/history.js +15 -0
- package/dist/modules/context/index.js +1 -0
- package/dist/modules/context/manager.js +240 -0
- package/dist/modules/execution/auditor.js +72 -0
- package/dist/modules/execution/index.js +6 -0
- package/dist/modules/execution/module.js +337 -0
- package/dist/modules/execution/moe-executor.js +209 -0
- package/dist/modules/execution/plan-validator.js +153 -0
- package/dist/modules/execution/planner.js +35 -0
- package/dist/modules/execution/stuck-detector.js +134 -0
- package/dist/modules/execution/tracker.js +53 -0
- package/dist/modules/execution/types.js +1 -0
- package/dist/modules/execution/verifier.js +149 -0
- package/dist/modules/hallucination/confidence.js +54 -0
- package/dist/modules/hallucination/consistency.js +60 -0
- package/dist/modules/hallucination/detector.js +41 -0
- package/dist/modules/hallucination/factual.js +170 -0
- package/dist/modules/hallucination/index.js +4 -0
- package/dist/modules/index.js +5 -0
- package/dist/modules/indexer/cache.js +38 -0
- package/dist/modules/indexer/index.js +3 -0
- package/dist/modules/indexer/module.js +192 -0
- package/dist/modules/indexer/walker.js +101 -0
- package/dist/modules/mcp/client.js +393 -0
- package/dist/modules/mcp/index.js +3 -0
- package/dist/modules/mcp/module.js +146 -0
- package/dist/modules/mcp/registry.js +15 -0
- package/dist/modules/memory/index.js +1 -0
- package/dist/modules/memory/module.js +48 -0
- package/dist/modules/memory/search.js +40 -0
- package/dist/modules/memory/store.js +65 -0
- package/dist/modules/pipelines/engine.js +60 -0
- package/dist/modules/pipelines/index.js +3 -0
- package/dist/modules/pipelines/parser.js +53 -0
- package/dist/modules/pipelines/template.js +14 -0
- package/dist/modules/plugins/builtin/lint-on-write.js +121 -0
- package/dist/modules/plugins/builtin/notify.js +8 -0
- package/dist/modules/plugins/index.js +1 -0
- package/dist/modules/plugins/loader.js +28 -0
- package/dist/modules/plugins/manager.js +161 -0
- package/dist/modules/plugins/types.js +1 -0
- package/dist/modules/processes/detect.js +34 -0
- package/dist/modules/processes/index.js +3 -0
- package/dist/modules/processes/registry.js +148 -0
- package/dist/modules/processes/runner.js +124 -0
- package/dist/modules/registry.js +45 -0
- package/dist/modules/security/audit-log.js +116 -0
- package/dist/modules/security/audit-notifier.js +292 -0
- package/dist/modules/security/command-validator.js +185 -0
- package/dist/modules/security/content-scanner.js +52 -0
- package/dist/modules/security/data-sanitizer.js +97 -0
- package/dist/modules/security/encryption.js +240 -0
- package/dist/modules/security/index.js +14 -0
- package/dist/modules/security/network-validator.js +79 -0
- package/dist/modules/security/path-validator.js +155 -0
- package/dist/modules/security/rate-limiter.js +119 -0
- package/dist/modules/security/security-policies.js +393 -0
- package/dist/modules/security/session-encryption.js +193 -0
- package/dist/modules/security/session-isolation.js +95 -0
- package/dist/modules/session/index.js +3 -0
- package/dist/modules/session/manager.js +167 -0
- package/dist/modules/session/module.js +24 -0
- package/dist/modules/session/store.js +174 -0
- package/dist/modules/session/types.js +1 -0
- package/dist/modules/skills/index.js +3 -0
- package/dist/modules/skills/loader.js +72 -0
- package/dist/modules/skills/matcher.js +27 -0
- package/dist/modules/skills/module.js +143 -0
- package/dist/modules/types.js +1 -0
- package/dist/modules/updater/checker.js +32 -0
- package/dist/modules/updater/index.js +1 -0
- package/dist/modules/user-profile/compressor.js +16 -0
- package/dist/modules/user-profile/index.js +1 -0
- package/dist/modules/user-profile/profile.js +68 -0
- package/dist/tools/approve.js +32 -0
- package/dist/tools/attach-image.js +89 -0
- package/dist/tools/bash.js +140 -0
- package/dist/tools/browser.js +97 -0
- package/dist/tools/create-dir.js +56 -0
- package/dist/tools/delete-file.js +63 -0
- package/dist/tools/edit-file.js +77 -0
- package/dist/tools/executor.js +95 -0
- package/dist/tools/file-info.js +45 -0
- package/dist/tools/filter-tools.js +10 -0
- package/dist/tools/glob-tool.js +26 -0
- package/dist/tools/grep-tool.js +64 -0
- package/dist/tools/index.js +52 -0
- package/dist/tools/list-dir.js +47 -0
- package/dist/tools/load-skill.js +48 -0
- package/dist/tools/mcp-call.js +68 -0
- package/dist/tools/move-file.js +84 -0
- package/dist/tools/path-utils.js +51 -0
- package/dist/tools/pipeline-run.js +144 -0
- package/dist/tools/preview.js +2 -0
- package/dist/tools/process-kill.js +29 -0
- package/dist/tools/process-list.js +38 -0
- package/dist/tools/process-log.js +41 -0
- package/dist/tools/question.js +142 -0
- package/dist/tools/read-file.js +73 -0
- package/dist/tools/recall.js +110 -0
- package/dist/tools/registry.js +36 -0
- package/dist/tools/remember.js +67 -0
- package/dist/tools/scope-check.js +30 -0
- package/dist/tools/search-history.js +64 -0
- package/dist/tools/subagent.js +142 -0
- package/dist/tools/types.js +1 -0
- package/dist/tools/user-input.js +123 -0
- package/dist/tools/web-browse.js +57 -0
- package/dist/tools/web-fetch.js +72 -0
- package/dist/tools/web-search.js +59 -0
- package/dist/tools/write-file.js +80 -0
- package/dist/ui/box.js +81 -0
- package/dist/ui/colors.js +4 -0
- package/dist/ui/diff.js +185 -0
- package/dist/ui/index.js +6 -0
- package/dist/ui/md-formatter.js +212 -0
- package/dist/ui/output.js +13 -0
- package/dist/ui/renderer.js +141 -0
- package/dist/ui/spinner.js +70 -0
- package/dist/ui/table.js +144 -0
- package/package.json +4 -4
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { loadConfig } from "../config/config";
|
|
2
|
+
import { Logger } from "../logger/app-logger";
|
|
3
|
+
import { OpenAICompatProvider } from "../llm/openai-compat";
|
|
4
|
+
import { ModelLoader } from "../llm/model-loader";
|
|
5
|
+
import { ToolRegistry, registerAllTools } from "../tools/index";
|
|
6
|
+
import { ToolExecutor } from "../tools/executor";
|
|
7
|
+
import { ModuleRegistry } from "../modules/registry";
|
|
8
|
+
import { PluginManager } from "../modules/plugins/manager";
|
|
9
|
+
import { PluginLoader } from "../modules/plugins/loader";
|
|
10
|
+
import { plugin as lintOnWritePlugin } from "../modules/plugins/builtin/lint-on-write";
|
|
11
|
+
import { plugin as notifyPlugin } from "../modules/plugins/builtin/notify";
|
|
12
|
+
import { ContextManager } from "../modules/context/manager";
|
|
13
|
+
import { TokenCounter } from "../llm/token-counter";
|
|
14
|
+
import { HallucinationDetector } from "../modules/hallucination/detector";
|
|
15
|
+
import { ExecutionModule } from "../modules/execution/module";
|
|
16
|
+
import { SessionStore, SessionManager, SessionModule, } from "../modules/session/index";
|
|
17
|
+
import { UserProfile } from "../modules/user-profile/profile";
|
|
18
|
+
import { SkillsLoader, SkillsMatcher, SkillsModule, } from "../modules/skills/index";
|
|
19
|
+
import { BrowserModule } from "../modules/browser/index";
|
|
20
|
+
import { IndexerModule } from "../modules/indexer/index";
|
|
21
|
+
import { MCPModule } from "../modules/mcp/index";
|
|
22
|
+
import { MemoryModule } from "../modules/memory/module";
|
|
23
|
+
import { setLocale } from "../i18n/index";
|
|
24
|
+
import { Agent } from "./agent";
|
|
25
|
+
import { homedir } from "os";
|
|
26
|
+
import { join, resolve } from "path";
|
|
27
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
28
|
+
function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
29
|
+
const now = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
30
|
+
const isWin = profileCompressed.toLowerCase().includes("win32");
|
|
31
|
+
const lines = [
|
|
32
|
+
`You are MMA v2, an AI coding agent for small models (${config.model}).`,
|
|
33
|
+
`Date: ${now}`,
|
|
34
|
+
`Workspace: ${baseDir}`,
|
|
35
|
+
`${profileCompressed}`,
|
|
36
|
+
`Reply in the user's language. Use tools for filesystem, bash, web access.`,
|
|
37
|
+
`When you need to act, call a tool immediately. Do not describe your plans in text — use tools to perform operations.`,
|
|
38
|
+
`After every tool call, check whether the user's request is fully satisfied. If any files, commands, or checks are still missing, call the next needed tool right away. Do not stop with an empty or "done" response until the task is complete.`,
|
|
39
|
+
`If you create a directory, continue creating the files that belong inside it. A created folder alone is not a completed task.`,
|
|
40
|
+
`If a tool call fails (e.g., a skill is too large), try an alternative approach or continue without it. Do not reply with empty text when the task is unfinished.`,
|
|
41
|
+
``,
|
|
42
|
+
`Design principles — apply them automatically without naming them:`,
|
|
43
|
+
`- Do not add code, files, or abstractions that are not needed right now (YAGNI — You Ain't Gonna Need It). If something is not required by the current task, omit it.`,
|
|
44
|
+
`- Prefer simple, straightforward solutions over clever or complex ones (KISS — Keep It Simple, Stupid). Flat code beats nested, minimal config beats flexible, explicit beats generic.`,
|
|
45
|
+
`- Do not duplicate code, logic, or configuration (DRY — Don't Repeat Yourself). Extract shared logic into a single place, reuse existing utilities and patterns before writing new ones.`,
|
|
46
|
+
];
|
|
47
|
+
if (isWin) {
|
|
48
|
+
lines.push(``, `Windows environment — use Windows-compatible commands:`, `- Use "dir" instead of "ls". Use "dir /b" for bare listing.`, `- Use "type" or "Get-Content" instead of "cat".`, `- Use "cd" instead of "pwd". Use "echo %cd%" to print working directory.`, `- Use "copy" instead of "cp", "move" instead of "mv", "del" instead of "rm".`, `- Do not use "mkdir -p" — Windows mkdir creates intermediate dirs by default. Use the create_dir tool instead.`, `- Use forward slashes (/) or escaped backslashes (\\\\) in file paths.`, `- Your working directory is: ${baseDir}`);
|
|
49
|
+
}
|
|
50
|
+
lines.push(``, `Bash tool rules:`, `- Use the "workdir" parameter to run commands in a specific directory. Do NOT chain "cd dir && cmd" — the security module blocks the "&&" operator.`, `- Run one command per tool call. Split multi-step shell operations into separate bash calls.`);
|
|
51
|
+
if (config.autoPlan) {
|
|
52
|
+
lines.push(``, `Plan rule: For any task with 2+ steps, create a plan first using the "plan" tool. After each step, call "plan update" to mark progress. Stay focused on the current step.`);
|
|
53
|
+
}
|
|
54
|
+
const hasMCP = config.mcpServers &&
|
|
55
|
+
Object.values(config.mcpServers).some((s) => s.enabled !== false);
|
|
56
|
+
if (hasMCP) {
|
|
57
|
+
lines.push(``, `MCP servers are available. Use the named MCP tools (prefixed with mcp__) to query external services.`);
|
|
58
|
+
}
|
|
59
|
+
return lines.join("\n");
|
|
60
|
+
}
|
|
61
|
+
export async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
62
|
+
const dir = configDir || join(homedir(), ".mma");
|
|
63
|
+
const projectConfigPath = projectDir
|
|
64
|
+
? join(projectDir, ".mmrc")
|
|
65
|
+
: join(process.cwd(), ".mmrc");
|
|
66
|
+
const config = loadConfig({ configDir: dir, projectConfigPath });
|
|
67
|
+
setLocale(config.locale);
|
|
68
|
+
// Update global audit notifier with config
|
|
69
|
+
try {
|
|
70
|
+
const { globalAuditNotifier } = await import("../modules/security/audit-notifier");
|
|
71
|
+
if (config.security?.auditNotifier) {
|
|
72
|
+
globalAuditNotifier.updateConfig(config.security.auditNotifier);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Ignore if audit notifier is not available
|
|
77
|
+
}
|
|
78
|
+
const logger = new Logger(config.logLevel);
|
|
79
|
+
logger.setLogDir(join(dir, "logs"));
|
|
80
|
+
logger.debug("MMA bootstrap", {
|
|
81
|
+
version: config.version,
|
|
82
|
+
model: config.model,
|
|
83
|
+
});
|
|
84
|
+
if (config.modelLoad.autoLoad) {
|
|
85
|
+
const modelLoader = new ModelLoader(config.provider.baseUrl, logger);
|
|
86
|
+
const loadResult = await modelLoader.ensureModelLoaded({
|
|
87
|
+
model: config.model,
|
|
88
|
+
contextLength: config.contextWindow,
|
|
89
|
+
flashAttention: config.modelLoad.flashAttention,
|
|
90
|
+
offloadKvCacheToGpu: config.modelLoad.offloadKvCacheToGpu,
|
|
91
|
+
autoLoad: config.modelLoad.autoLoad,
|
|
92
|
+
});
|
|
93
|
+
if (!loadResult.success) {
|
|
94
|
+
logger.warn(`Model auto-load failed: ${loadResult.error}. Continuing with manual load.`);
|
|
95
|
+
}
|
|
96
|
+
else if (loadResult.alreadyLoaded) {
|
|
97
|
+
logger.debug(`Model ${config.model} already loaded`);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const profile = new UserProfile(join(dir));
|
|
104
|
+
profile.load() || profile.collect();
|
|
105
|
+
profile.save();
|
|
106
|
+
const llmProvider = new OpenAICompatProvider({
|
|
107
|
+
model: config.model,
|
|
108
|
+
baseUrl: config.provider.baseUrl,
|
|
109
|
+
apiKey: config.provider.apiKey,
|
|
110
|
+
contextWindow: config.contextWindow,
|
|
111
|
+
retry: config.retry,
|
|
112
|
+
rateLimits: config.security?.rateLimits,
|
|
113
|
+
});
|
|
114
|
+
const baseDir = projectDir ? resolve(projectDir) : process.cwd();
|
|
115
|
+
const projectMapCacheDir = join(baseDir, ".mma");
|
|
116
|
+
const indexerModule = new IndexerModule({
|
|
117
|
+
baseDir,
|
|
118
|
+
cacheDir: projectMapCacheDir,
|
|
119
|
+
});
|
|
120
|
+
try {
|
|
121
|
+
await indexerModule.buildIndex();
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
logger.warn(`Project indexing failed: ${err.message}`);
|
|
125
|
+
}
|
|
126
|
+
const skillsLoader = new SkillsLoader();
|
|
127
|
+
const builtinDir = join(import.meta.dirname, "skills", "builtin");
|
|
128
|
+
const globalDir = join(homedir(), ".agents", "skills");
|
|
129
|
+
const projectSkillsDir = join(baseDir, ".mma", "skills");
|
|
130
|
+
const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
|
|
131
|
+
const skillsMatcher = new SkillsMatcher();
|
|
132
|
+
const skillsBudget = Math.floor(config.contextWindow * 0.1);
|
|
133
|
+
const skillsModule = new SkillsModule(availableSkills, skillsMatcher, skillsBudget);
|
|
134
|
+
const toolRegistry = new ToolRegistry();
|
|
135
|
+
registerAllTools(toolRegistry, skillsModule);
|
|
136
|
+
const pluginManager = new PluginManager();
|
|
137
|
+
const systemInfoPrompt = {
|
|
138
|
+
content: buildSystemInfo(config, baseDir, profile.compress()),
|
|
139
|
+
priority: "critical",
|
|
140
|
+
essential: true,
|
|
141
|
+
estimatedTokens: 250,
|
|
142
|
+
};
|
|
143
|
+
const agentsMdGlobal = join(dir, "AGENTS.md");
|
|
144
|
+
if (!existsSync(agentsMdGlobal)) {
|
|
145
|
+
writeFileSync(agentsMdGlobal, "", "utf-8");
|
|
146
|
+
}
|
|
147
|
+
const sessionDir = join(dir, "sessions");
|
|
148
|
+
const sessionStore = new SessionStore(sessionDir);
|
|
149
|
+
sessionStore.init();
|
|
150
|
+
const sessionManager = new SessionManager(sessionStore, {
|
|
151
|
+
model: config.model,
|
|
152
|
+
contextWindow: config.contextWindow,
|
|
153
|
+
projectDir: baseDir,
|
|
154
|
+
maxSessions: config.session.maxSessions,
|
|
155
|
+
isolation: config.sessionIsolation,
|
|
156
|
+
});
|
|
157
|
+
if (config.session.autoSave && !sessionManager.getActive()) {
|
|
158
|
+
sessionManager.create();
|
|
159
|
+
}
|
|
160
|
+
const tokenCounter = new TokenCounter(config.model);
|
|
161
|
+
const contextManager = new ContextManager(config.contextWindow, config.contextBudget, tokenCounter);
|
|
162
|
+
const toolCtx = {
|
|
163
|
+
config,
|
|
164
|
+
baseDir,
|
|
165
|
+
logger,
|
|
166
|
+
exitOnComplete,
|
|
167
|
+
contextManager,
|
|
168
|
+
sessionId: sessionManager.getActiveMeta()?.id,
|
|
169
|
+
sessionContext: sessionManager.getSessionContext() ?? undefined,
|
|
170
|
+
recursionDepth: 0,
|
|
171
|
+
fileOperationsCount: 0,
|
|
172
|
+
sessionHistory: {
|
|
173
|
+
append: async (type, content) => {
|
|
174
|
+
const meta = sessionManager.getActiveMeta();
|
|
175
|
+
if (!meta)
|
|
176
|
+
return;
|
|
177
|
+
sessionManager.appendMessage({
|
|
178
|
+
role: "tool",
|
|
179
|
+
content: typeof content === "string" ? content : JSON.stringify(content),
|
|
180
|
+
name: type,
|
|
181
|
+
timestamp: new Date().toISOString(),
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
const toolExecutor = new ToolExecutor(toolRegistry, toolCtx, pluginManager);
|
|
187
|
+
toolCtx.llmProvider = llmProvider;
|
|
188
|
+
toolCtx.toolExecutor = toolExecutor;
|
|
189
|
+
const hallucinationDetector = new HallucinationDetector();
|
|
190
|
+
const factualCheck = hallucinationDetector.getFactualCheck();
|
|
191
|
+
factualCheck.setBaseDir(baseDir);
|
|
192
|
+
toolCtx.trackReadPath = (p) => factualCheck.trackReadPath(p);
|
|
193
|
+
toolCtx.trackCreatedPath = (p) => factualCheck.trackCreatedPath(p);
|
|
194
|
+
toolCtx.trackDeletedPath = (p) => factualCheck.trackDeletedPath(p);
|
|
195
|
+
toolCtx.trackDocumentContent = (c) => factualCheck.trackDocumentContent(c);
|
|
196
|
+
const moduleRegistry = new ModuleRegistry();
|
|
197
|
+
const execModule = new ExecutionModule(baseDir, config.stuckThreshold);
|
|
198
|
+
moduleRegistry.register(execModule);
|
|
199
|
+
const sessionModule = new SessionModule(sessionManager);
|
|
200
|
+
moduleRegistry.register(sessionModule);
|
|
201
|
+
moduleRegistry.register(skillsModule);
|
|
202
|
+
moduleRegistry.register(indexerModule);
|
|
203
|
+
const mcpModule = new MCPModule(config);
|
|
204
|
+
await mcpModule.initialize();
|
|
205
|
+
moduleRegistry.register(mcpModule);
|
|
206
|
+
const memoryModule = new MemoryModule(join(dir, 'memory'));
|
|
207
|
+
moduleRegistry.register(memoryModule);
|
|
208
|
+
if (config.browser.enabled) {
|
|
209
|
+
const browserModule = new BrowserModule();
|
|
210
|
+
moduleRegistry.register(browserModule);
|
|
211
|
+
const browserPlugin = browserModule.getPlugin();
|
|
212
|
+
if (browserPlugin) {
|
|
213
|
+
browserPlugin.isBuiltin = true;
|
|
214
|
+
pluginManager.register(browserPlugin);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const moduleTools = moduleRegistry.collectToolDefinitions();
|
|
218
|
+
for (const tool of moduleTools) {
|
|
219
|
+
toolRegistry.register(tool);
|
|
220
|
+
}
|
|
221
|
+
const plugin = execModule.getPlugin();
|
|
222
|
+
if (plugin) {
|
|
223
|
+
plugin.isBuiltin = true;
|
|
224
|
+
pluginManager.register(plugin);
|
|
225
|
+
}
|
|
226
|
+
const sessionPlugin = sessionModule.getPlugin();
|
|
227
|
+
if (sessionPlugin) {
|
|
228
|
+
sessionPlugin.isBuiltin = true;
|
|
229
|
+
pluginManager.register(sessionPlugin);
|
|
230
|
+
}
|
|
231
|
+
const skillsPlugin = skillsModule.getPlugin();
|
|
232
|
+
if (skillsPlugin) {
|
|
233
|
+
skillsPlugin.isBuiltin = true;
|
|
234
|
+
pluginManager.register(skillsPlugin);
|
|
235
|
+
}
|
|
236
|
+
const indexerPlugin = indexerModule.getPlugin();
|
|
237
|
+
if (indexerPlugin) {
|
|
238
|
+
indexerPlugin.isBuiltin = true;
|
|
239
|
+
pluginManager.register(indexerPlugin);
|
|
240
|
+
}
|
|
241
|
+
const mcpPlugin = mcpModule.getPlugin();
|
|
242
|
+
if (mcpPlugin) {
|
|
243
|
+
mcpPlugin.isBuiltin = true;
|
|
244
|
+
pluginManager.register(mcpPlugin);
|
|
245
|
+
}
|
|
246
|
+
pluginManager.register(lintOnWritePlugin);
|
|
247
|
+
pluginManager.register(notifyPlugin);
|
|
248
|
+
const pluginLoader = new PluginLoader();
|
|
249
|
+
const globalPluginsDir = join(homedir(), ".mma", "plugins");
|
|
250
|
+
const projectPluginsDir = join(dir, ".mma", "plugins");
|
|
251
|
+
pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger);
|
|
252
|
+
pluginLoader.loadFromDir(projectPluginsDir, pluginManager, logger);
|
|
253
|
+
contextManager.onCompact = (summary) => {
|
|
254
|
+
const meta = sessionManager.getActiveMeta();
|
|
255
|
+
if (!meta || !config.session.autoSave)
|
|
256
|
+
return;
|
|
257
|
+
sessionManager.appendMessage({
|
|
258
|
+
role: summary.role,
|
|
259
|
+
content: summary.content,
|
|
260
|
+
name: summary.name,
|
|
261
|
+
timestamp: new Date().toISOString(),
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
const agentsMdBlocks = [];
|
|
265
|
+
const skipAgentsMd = noAgentsMd === true;
|
|
266
|
+
if (!skipAgentsMd) {
|
|
267
|
+
const agentsMdCandidates = [
|
|
268
|
+
join(baseDir, "AGENTS.md"),
|
|
269
|
+
join(baseDir, ".mma", "AGENTS.md"),
|
|
270
|
+
join(dir, "AGENTS.md"),
|
|
271
|
+
];
|
|
272
|
+
for (const p of agentsMdCandidates) {
|
|
273
|
+
if (existsSync(p)) {
|
|
274
|
+
const content = readFileSync(p, "utf-8").trim();
|
|
275
|
+
if (content) {
|
|
276
|
+
agentsMdBlocks.push({
|
|
277
|
+
content,
|
|
278
|
+
priority: "high",
|
|
279
|
+
essential: false,
|
|
280
|
+
estimatedTokens: Math.ceil(content.length / 4),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const promptBlocks = [
|
|
287
|
+
systemInfoPrompt,
|
|
288
|
+
...moduleRegistry.collectPromptBlocks(),
|
|
289
|
+
...agentsMdBlocks,
|
|
290
|
+
];
|
|
291
|
+
const agentDeps = {
|
|
292
|
+
config,
|
|
293
|
+
llmProvider,
|
|
294
|
+
toolExecutor,
|
|
295
|
+
pluginManager,
|
|
296
|
+
contextManager,
|
|
297
|
+
hallucinationDetector,
|
|
298
|
+
logger,
|
|
299
|
+
baseDir,
|
|
300
|
+
promptBlocks,
|
|
301
|
+
getDynamicPromptBlocks: () => {
|
|
302
|
+
const planBlock = execModule.getSystemPromptBlock();
|
|
303
|
+
return planBlock ? [planBlock] : [];
|
|
304
|
+
},
|
|
305
|
+
finalAudit: () => execModule.runFinalAudit(),
|
|
306
|
+
sessionManager,
|
|
307
|
+
exitOnComplete,
|
|
308
|
+
};
|
|
309
|
+
const agent = new Agent(agentDeps);
|
|
310
|
+
return {
|
|
311
|
+
agent,
|
|
312
|
+
config,
|
|
313
|
+
logger,
|
|
314
|
+
sessionManager,
|
|
315
|
+
skillsModule,
|
|
316
|
+
pluginManager,
|
|
317
|
+
configDir: dir,
|
|
318
|
+
baseDir,
|
|
319
|
+
noAgentsMd: skipAgentsMd,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const PRIORITY_ORDER = {
|
|
2
|
+
critical: 0,
|
|
3
|
+
high: 1,
|
|
4
|
+
normal: 2,
|
|
5
|
+
low: 3,
|
|
6
|
+
};
|
|
7
|
+
export class PromptBuilder {
|
|
8
|
+
blocks = [];
|
|
9
|
+
budget;
|
|
10
|
+
constructor(budget) {
|
|
11
|
+
this.budget = budget;
|
|
12
|
+
}
|
|
13
|
+
addBlock(block) {
|
|
14
|
+
this.blocks.push(block);
|
|
15
|
+
}
|
|
16
|
+
addBlocks(blocks) {
|
|
17
|
+
for (const b of blocks) {
|
|
18
|
+
this.blocks.push(b);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
build() {
|
|
22
|
+
const essential = [];
|
|
23
|
+
const nonEssential = [];
|
|
24
|
+
for (const block of this.blocks) {
|
|
25
|
+
if (block.essential) {
|
|
26
|
+
essential.push(block);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
nonEssential.push(block);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
nonEssential.sort((a, b) => PRIORITY_ORDER[a.priority] - PRIORITY_ORDER[b.priority]);
|
|
33
|
+
let usedTokens = 0;
|
|
34
|
+
const included = [];
|
|
35
|
+
const excluded = [];
|
|
36
|
+
for (const block of essential) {
|
|
37
|
+
included.push(block.content);
|
|
38
|
+
usedTokens += block.estimatedTokens;
|
|
39
|
+
}
|
|
40
|
+
for (const block of nonEssential) {
|
|
41
|
+
const tokens = block.estimatedTokens;
|
|
42
|
+
if (usedTokens + tokens <= this.budget) {
|
|
43
|
+
included.push(block.content);
|
|
44
|
+
usedTokens += tokens;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
excluded.push(block.content);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
prompt: included.join('\n\n'),
|
|
52
|
+
excluded,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin wrapper around SessionManager that eliminates repetitive
|
|
3
|
+
* `if (sessionManager)` + `new Date().toISOString()` boilerplate
|
|
4
|
+
* from the agent loop.
|
|
5
|
+
*/
|
|
6
|
+
export class SessionLogger {
|
|
7
|
+
session;
|
|
8
|
+
constructor(session) {
|
|
9
|
+
this.session = session;
|
|
10
|
+
}
|
|
11
|
+
get active() {
|
|
12
|
+
return !!this.session?.getActive();
|
|
13
|
+
}
|
|
14
|
+
logSystem(content) {
|
|
15
|
+
this.session?.appendLog({
|
|
16
|
+
ts: new Date().toISOString(),
|
|
17
|
+
type: "system",
|
|
18
|
+
content,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
logUser(content) {
|
|
22
|
+
this.session?.appendMessage({
|
|
23
|
+
role: "user",
|
|
24
|
+
content,
|
|
25
|
+
timestamp: new Date().toISOString(),
|
|
26
|
+
});
|
|
27
|
+
this.session?.appendLog({
|
|
28
|
+
ts: new Date().toISOString(),
|
|
29
|
+
type: "user",
|
|
30
|
+
content,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
logAssistant(content, reasoning, toolCalls, iteration) {
|
|
34
|
+
if (reasoning) {
|
|
35
|
+
this.session?.appendLog({
|
|
36
|
+
ts: new Date().toISOString(),
|
|
37
|
+
type: "reasoning",
|
|
38
|
+
content: reasoning,
|
|
39
|
+
iteration,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
this.session?.appendLog({
|
|
43
|
+
ts: new Date().toISOString(),
|
|
44
|
+
type: "assistant",
|
|
45
|
+
content,
|
|
46
|
+
...(toolCalls
|
|
47
|
+
? { tool_calls: toolCalls.map((tc) => ({ id: tc.id, name: tc.name, arguments: tc.arguments })) }
|
|
48
|
+
: {}),
|
|
49
|
+
iteration,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
saveAssistantMessage(content) {
|
|
53
|
+
this.session?.appendMessage({
|
|
54
|
+
role: "assistant",
|
|
55
|
+
content: content.slice(0, 500),
|
|
56
|
+
timestamp: new Date().toISOString(),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
logToolDefs(toolCount, toolNames, iteration) {
|
|
60
|
+
this.session?.appendLog({
|
|
61
|
+
ts: new Date().toISOString(),
|
|
62
|
+
type: "tool_defs",
|
|
63
|
+
toolCount,
|
|
64
|
+
toolNames,
|
|
65
|
+
iteration,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
logToolCall(call, iteration) {
|
|
69
|
+
this.session?.appendLog({
|
|
70
|
+
ts: new Date().toISOString(),
|
|
71
|
+
type: "tool_call",
|
|
72
|
+
tool: call.name,
|
|
73
|
+
tool_call_id: call.id,
|
|
74
|
+
args: call.arguments,
|
|
75
|
+
iteration,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
logToolResult(call, result, duration, iteration) {
|
|
79
|
+
this.session?.appendMessage({
|
|
80
|
+
role: "tool",
|
|
81
|
+
content: result.output.slice(0, 500),
|
|
82
|
+
name: call.name,
|
|
83
|
+
timestamp: new Date().toISOString(),
|
|
84
|
+
});
|
|
85
|
+
this.session?.appendLog({
|
|
86
|
+
ts: new Date().toISOString(),
|
|
87
|
+
type: "tool_result",
|
|
88
|
+
tool: call.name,
|
|
89
|
+
tool_call_id: call.id,
|
|
90
|
+
success: result.success,
|
|
91
|
+
content: result.output.slice(0, 1000),
|
|
92
|
+
diff: result.diff,
|
|
93
|
+
duration,
|
|
94
|
+
iteration,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
logCompaction(content, iteration, contextTokens, contextLimit) {
|
|
98
|
+
this.session?.appendLog({
|
|
99
|
+
ts: new Date().toISOString(),
|
|
100
|
+
type: "compaction",
|
|
101
|
+
content,
|
|
102
|
+
iteration,
|
|
103
|
+
...(contextTokens !== undefined ? { contextTokens } : {}),
|
|
104
|
+
...(contextLimit !== undefined ? { contextLimit } : {}),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
logError(message) {
|
|
108
|
+
this.session?.appendLog({
|
|
109
|
+
ts: new Date().toISOString(),
|
|
110
|
+
type: "error",
|
|
111
|
+
content: message,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
logAudit(summary, iteration) {
|
|
115
|
+
this.session?.appendLog({
|
|
116
|
+
ts: new Date().toISOString(),
|
|
117
|
+
type: "audit",
|
|
118
|
+
content: summary,
|
|
119
|
+
iteration,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|