@jungjaehoon/mama-os 0.10.4 → 0.12.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/agent/agent-loop.d.ts +13 -11
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +31 -263
- package/dist/agent/agent-loop.js.map +1 -1
- package/dist/agent/codex-mcp-process.d.ts.map +1 -1
- package/dist/agent/codex-mcp-process.js +6 -5
- package/dist/agent/codex-mcp-process.js.map +1 -1
- package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
- package/dist/agent/gateway-tool-executor.js +4 -43
- package/dist/agent/gateway-tool-executor.js.map +1 -1
- package/dist/agent/gateway-tools.md +45 -58
- package/dist/agent/model-runner.d.ts +83 -0
- package/dist/agent/model-runner.d.ts.map +1 -0
- package/dist/agent/model-runner.js +24 -0
- package/dist/agent/model-runner.js.map +1 -0
- package/dist/agent/persistent-cli-adapter.d.ts +20 -2
- package/dist/agent/persistent-cli-adapter.d.ts.map +1 -1
- package/dist/agent/persistent-cli-adapter.js +49 -6
- package/dist/agent/persistent-cli-adapter.js.map +1 -1
- package/dist/agent/persistent-cli-process.d.ts.map +1 -1
- package/dist/agent/persistent-cli-process.js +3 -2
- package/dist/agent/persistent-cli-process.js.map +1 -1
- package/dist/agent/prompt-size-monitor.d.ts +10 -10
- package/dist/agent/prompt-size-monitor.d.ts.map +1 -1
- package/dist/agent/prompt-size-monitor.js +73 -54
- package/dist/agent/prompt-size-monitor.js.map +1 -1
- package/dist/agent/session-pool.d.ts.map +1 -1
- package/dist/agent/session-pool.js +10 -9
- package/dist/agent/session-pool.js.map +1 -1
- package/dist/agent/skill-loader.d.ts +87 -0
- package/dist/agent/skill-loader.d.ts.map +1 -0
- package/dist/agent/skill-loader.js +362 -0
- package/dist/agent/skill-loader.js.map +1 -0
- package/dist/agent/token-budget.d.ts +49 -0
- package/dist/agent/token-budget.d.ts.map +1 -0
- package/dist/agent/token-budget.js +92 -0
- package/dist/agent/token-budget.js.map +1 -0
- package/dist/agent/token-estimator.d.ts +33 -0
- package/dist/agent/token-estimator.d.ts.map +1 -0
- package/dist/agent/token-estimator.js +89 -0
- package/dist/agent/token-estimator.js.map +1 -0
- package/dist/agent/tool-registry.d.ts +65 -0
- package/dist/agent/tool-registry.d.ts.map +1 -0
- package/dist/agent/tool-registry.js +324 -0
- package/dist/agent/tool-registry.js.map +1 -0
- package/dist/agent/types.d.ts +5 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/api/graph-api-types.d.ts +6 -0
- package/dist/api/graph-api-types.d.ts.map +1 -1
- package/dist/api/graph-api.d.ts.map +1 -1
- package/dist/api/graph-api.js +46 -0
- package/dist/api/graph-api.js.map +1 -1
- package/dist/api/index.d.ts +11 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +62 -24
- package/dist/api/index.js.map +1 -1
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +126 -7
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +55 -0
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/config/config-manager.d.ts +20 -0
- package/dist/cli/config/config-manager.d.ts.map +1 -1
- package/dist/cli/config/config-manager.js +174 -0
- package/dist/cli/config/config-manager.js.map +1 -1
- package/dist/cli/config/types.d.ts +110 -0
- package/dist/cli/config/types.d.ts.map +1 -1
- package/dist/cli/config/types.js +49 -0
- package/dist/cli/config/types.js.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/gateways/channel-history.d.ts.map +1 -1
- package/dist/gateways/channel-history.js +2 -1
- package/dist/gateways/channel-history.js.map +1 -1
- package/dist/gateways/slack.d.ts +1 -1
- package/dist/gateways/slack.d.ts.map +1 -1
- package/dist/gateways/slack.js +4 -1
- package/dist/gateways/slack.js.map +1 -1
- package/dist/gateways/tool-status-tracker.d.ts.map +1 -1
- package/dist/gateways/tool-status-tracker.js +5 -4
- package/dist/gateways/tool-status-tracker.js.map +1 -1
- package/dist/multi-agent/agent-message-queue.d.ts.map +1 -1
- package/dist/multi-agent/agent-message-queue.js +5 -4
- package/dist/multi-agent/agent-message-queue.js.map +1 -1
- package/dist/multi-agent/agent-process-manager.d.ts +6 -1
- package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
- package/dist/multi-agent/agent-process-manager.js +20 -9
- package/dist/multi-agent/agent-process-manager.js.map +1 -1
- package/dist/multi-agent/background-task-manager.d.ts.map +1 -1
- package/dist/multi-agent/background-task-manager.js +2 -1
- package/dist/multi-agent/background-task-manager.js.map +1 -1
- package/dist/multi-agent/multi-agent-base.d.ts +2 -2
- package/dist/multi-agent/multi-agent-base.d.ts.map +1 -1
- package/dist/multi-agent/multi-agent-base.js +6 -2
- package/dist/multi-agent/multi-agent-base.js.map +1 -1
- package/dist/multi-agent/multi-agent-discord.d.ts +1 -1
- package/dist/multi-agent/multi-agent-discord.d.ts.map +1 -1
- package/dist/multi-agent/multi-agent-discord.js +8 -5
- package/dist/multi-agent/multi-agent-discord.js.map +1 -1
- package/dist/multi-agent/multi-agent-slack.d.ts.map +1 -1
- package/dist/multi-agent/multi-agent-slack.js +5 -4
- package/dist/multi-agent/multi-agent-slack.js.map +1 -1
- package/dist/multi-agent/runtime-process.d.ts +13 -1
- package/dist/multi-agent/runtime-process.d.ts.map +1 -1
- package/dist/multi-agent/runtime-process.js +40 -0
- package/dist/multi-agent/runtime-process.js.map +1 -1
- package/dist/multi-agent/ultrawork.d.ts.map +1 -1
- package/dist/multi-agent/ultrawork.js +3 -2
- package/dist/multi-agent/ultrawork.js.map +1 -1
- package/dist/observability/health-check.d.ts +102 -0
- package/dist/observability/health-check.d.ts.map +1 -0
- package/dist/observability/health-check.js +422 -0
- package/dist/observability/health-check.js.map +1 -0
- package/dist/observability/health-score.d.ts +29 -0
- package/dist/observability/health-score.d.ts.map +1 -0
- package/dist/observability/health-score.js +83 -0
- package/dist/observability/health-score.js.map +1 -0
- package/dist/observability/metrics-cleanup.d.ts +24 -0
- package/dist/observability/metrics-cleanup.d.ts.map +1 -0
- package/dist/observability/metrics-cleanup.js +51 -0
- package/dist/observability/metrics-cleanup.js.map +1 -0
- package/dist/observability/metrics-store.d.ts +52 -0
- package/dist/observability/metrics-store.d.ts.map +1 -0
- package/dist/observability/metrics-store.js +186 -0
- package/dist/observability/metrics-store.js.map +1 -0
- package/package.json +5 -5
- package/public/viewer/js/modules/dashboard.js +147 -47
- package/public/viewer/js/modules/settings.js +44 -39
- package/public/viewer/js/modules/skills.js +25 -25
- package/public/viewer/js/utils/api.js +6 -0
- package/public/viewer/src/modules/dashboard.ts +160 -47
- package/public/viewer/src/modules/settings.ts +50 -39
- package/public/viewer/src/modules/skills.ts +25 -25
- package/public/viewer/src/utils/api.ts +42 -0
- package/public/viewer/viewer.html +47 -18
- package/scripts/generate-gateway-tools.ts +105 -0
|
@@ -12,18 +12,19 @@
|
|
|
12
12
|
import type { OAuthManager } from '../auth/index.js';
|
|
13
13
|
import type { ContentBlock, ToolDefinition, AgentLoopOptions, AgentLoopResult, ClaudeClientOptions, GatewayToolExecutorOptions, AgentContext } from './types.js';
|
|
14
14
|
/**
|
|
15
|
-
* Load
|
|
16
|
-
*
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
15
|
+
* Load composed system prompt with persona layers + CLAUDE.md + optional context
|
|
16
|
+
* Tries to load persona files from ~/.mama/ in order:
|
|
17
|
+
* 1. SOUL.md (philosophical principles)
|
|
18
|
+
* 2. IDENTITY.md (role and character)
|
|
19
|
+
* 3. USER.md (user preferences)
|
|
20
|
+
* 4. **Context Prompt** (if AgentContext provided - role awareness)
|
|
21
|
+
* 5. CLAUDE.md (base instructions)
|
|
22
|
+
*
|
|
23
|
+
* If persona files are missing, logs warning and continues with CLAUDE.md alone.
|
|
24
|
+
*
|
|
25
|
+
* @param verbose - Enable verbose logging
|
|
26
|
+
* @param context - Optional AgentContext for role-aware prompt injection
|
|
23
27
|
*/
|
|
24
|
-
export declare function loadInstalledSkills(verbose?: boolean, _options?: {
|
|
25
|
-
onlyCommands?: boolean;
|
|
26
|
-
}): string[];
|
|
27
28
|
/**
|
|
28
29
|
* Load backend-specific AGENTS.md from ~/.mama/
|
|
29
30
|
* Maps backend to file: 'claude' → AGENTS.claude.md, 'codex-mcp' → AGENTS.codex.md
|
|
@@ -45,6 +46,7 @@ export declare class AgentLoop {
|
|
|
45
46
|
private readonly onTurn?;
|
|
46
47
|
private readonly onToolUse?;
|
|
47
48
|
private readonly onTokenUsage?;
|
|
49
|
+
private readonly onMetric?;
|
|
48
50
|
private readonly laneManager;
|
|
49
51
|
private readonly useLanes;
|
|
50
52
|
private sessionKey;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../../src/agent/agent-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../../src/agent/agent-loop.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/agent-loop.js
CHANGED
|
@@ -45,16 +45,16 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
45
45
|
})();
|
|
46
46
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
47
|
exports.AgentLoop = void 0;
|
|
48
|
-
exports.loadSkillContent = loadSkillContent;
|
|
49
|
-
exports.loadInstalledSkills = loadInstalledSkills;
|
|
50
48
|
exports.loadBackendAgentsMd = loadBackendAgentsMd;
|
|
51
49
|
exports.loadComposedSystemPrompt = loadComposedSystemPrompt;
|
|
52
50
|
exports.getGatewayToolsPrompt = getGatewayToolsPrompt;
|
|
53
51
|
const fs_1 = require("fs");
|
|
54
52
|
const prompt_size_monitor_js_1 = require("./prompt-size-monitor.js");
|
|
55
|
-
const
|
|
53
|
+
const skill_loader_js_1 = require("./skill-loader.js");
|
|
56
54
|
const persistent_cli_adapter_js_1 = require("./persistent-cli-adapter.js");
|
|
55
|
+
const runtime_process_js_1 = require("../multi-agent/runtime-process.js");
|
|
57
56
|
const gateway_tool_executor_js_1 = require("./gateway-tool-executor.js");
|
|
57
|
+
const tool_registry_js_1 = require("./tool-registry.js");
|
|
58
58
|
const index_js_1 = require("./code-act/index.js");
|
|
59
59
|
const index_js_2 = require("../concurrency/index.js");
|
|
60
60
|
const session_pool_js_1 = require("./session-pool.js");
|
|
@@ -81,21 +81,6 @@ const DEFAULT_TOOLS_CONFIG = {
|
|
|
81
81
|
mcp: [],
|
|
82
82
|
mcp_config: '~/.mama/mama-mcp-config.json',
|
|
83
83
|
};
|
|
84
|
-
/**
|
|
85
|
-
* Check if a tool name matches a pattern (supports wildcards like "browser_*")
|
|
86
|
-
* Reserved for future hybrid tool routing
|
|
87
|
-
*/
|
|
88
|
-
function _matchToolPattern(toolName, pattern) {
|
|
89
|
-
if (pattern === '*')
|
|
90
|
-
return true;
|
|
91
|
-
if (pattern.endsWith('*')) {
|
|
92
|
-
const prefix = pattern.slice(0, -1);
|
|
93
|
-
return toolName.startsWith(prefix);
|
|
94
|
-
}
|
|
95
|
-
return toolName === pattern;
|
|
96
|
-
}
|
|
97
|
-
// _matchToolPattern is reserved for future hybrid routing
|
|
98
|
-
void _matchToolPattern;
|
|
99
84
|
/**
|
|
100
85
|
* Load CLAUDE.md system prompt
|
|
101
86
|
* Tries multiple paths: project root, ~/.mama, /etc/mama
|
|
@@ -133,225 +118,6 @@ function loadSystemPrompt(verbose = false) {
|
|
|
133
118
|
* @param verbose - Enable verbose logging
|
|
134
119
|
* @param context - Optional AgentContext for role-aware prompt injection
|
|
135
120
|
*/
|
|
136
|
-
/**
|
|
137
|
-
* Files to exclude from skill prompt injection (reduce token bloat)
|
|
138
|
-
*/
|
|
139
|
-
const EXCLUDED_SKILL_FILES = new Set([
|
|
140
|
-
'CONNECTORS.md',
|
|
141
|
-
'connectors.md',
|
|
142
|
-
'LICENSE.md',
|
|
143
|
-
'license.md',
|
|
144
|
-
'CHANGELOG.md',
|
|
145
|
-
'changelog.md',
|
|
146
|
-
'CONTRIBUTING.md',
|
|
147
|
-
'contributing.md',
|
|
148
|
-
'README.md',
|
|
149
|
-
'readme.md',
|
|
150
|
-
]);
|
|
151
|
-
/** Max chars per skill file to prevent prompt bloat */
|
|
152
|
-
const MAX_SKILL_FILE_CHARS = 4000;
|
|
153
|
-
/**
|
|
154
|
-
* Recursively collect all .md files from a directory (sync)
|
|
155
|
-
* Filters out non-essential files (LICENSE, CONNECTORS, etc.)
|
|
156
|
-
*/
|
|
157
|
-
function collectMarkdownFiles(dir, prefix = '') {
|
|
158
|
-
const results = [];
|
|
159
|
-
if (!(0, fs_1.existsSync)(dir))
|
|
160
|
-
return results;
|
|
161
|
-
try {
|
|
162
|
-
const entries = (0, fs_1.readdirSync)(dir, { withFileTypes: true });
|
|
163
|
-
for (const entry of entries) {
|
|
164
|
-
if (entry.name.startsWith('.'))
|
|
165
|
-
continue;
|
|
166
|
-
const fullPath = (0, path_1.join)(dir, entry.name);
|
|
167
|
-
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
168
|
-
if (entry.isDirectory()) {
|
|
169
|
-
results.push(...collectMarkdownFiles(fullPath, relativePath));
|
|
170
|
-
}
|
|
171
|
-
else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
172
|
-
if (EXCLUDED_SKILL_FILES.has(entry.name))
|
|
173
|
-
continue;
|
|
174
|
-
let content = (0, fs_1.readFileSync)(fullPath, 'utf-8');
|
|
175
|
-
// Only truncate supplementary files, never command files
|
|
176
|
-
const isCommand = relativePath.startsWith('commands/');
|
|
177
|
-
if (!isCommand && content.length > MAX_SKILL_FILE_CHARS) {
|
|
178
|
-
content = content.slice(0, MAX_SKILL_FILE_CHARS) + '\n\n[... truncated]';
|
|
179
|
-
}
|
|
180
|
-
results.push({ path: relativePath, content });
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
catch {
|
|
185
|
-
// Read failed
|
|
186
|
-
}
|
|
187
|
-
return results;
|
|
188
|
-
}
|
|
189
|
-
// ─── Skill On-Demand Injection ───────────────────────────────────────────────
|
|
190
|
-
/**
|
|
191
|
-
* Parse YAML frontmatter from skill .md file
|
|
192
|
-
*/
|
|
193
|
-
function parseSkillFrontmatter(content) {
|
|
194
|
-
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
195
|
-
if (!match)
|
|
196
|
-
return { name: '', description: '', keywords: [] };
|
|
197
|
-
const block = match[1];
|
|
198
|
-
const name = (block.match(/^name:\s*(.+)$/m)?.[1] ?? '').trim();
|
|
199
|
-
const description = (block.match(/^description:\s*(.+)$/m)?.[1] ?? '').trim();
|
|
200
|
-
const kwBlock = block.match(/^keywords:\n((?:[ \t]+-[ \t]*.+\n?)+)/m);
|
|
201
|
-
const keywords = kwBlock
|
|
202
|
-
? kwBlock[1]
|
|
203
|
-
.trim()
|
|
204
|
-
.split('\n')
|
|
205
|
-
.map((l) => l.replace(/^[ \t]*-[ \t]*/, '').trim())
|
|
206
|
-
.filter((k) => k.length > 0)
|
|
207
|
-
: [];
|
|
208
|
-
return { name, description, keywords };
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Find the main .md file for a directory skill (for frontmatter parsing)
|
|
212
|
-
*/
|
|
213
|
-
function findMainSkillFile(skillDir, skillName) {
|
|
214
|
-
for (const name of [`${skillName}.md`, 'skill.md', 'index.md']) {
|
|
215
|
-
const p = (0, path_1.join)(skillDir, name);
|
|
216
|
-
if ((0, fs_1.existsSync)(p))
|
|
217
|
-
return p;
|
|
218
|
-
}
|
|
219
|
-
try {
|
|
220
|
-
const entries = (0, fs_1.readdirSync)(skillDir, { withFileTypes: true });
|
|
221
|
-
for (const e of entries) {
|
|
222
|
-
if (e.isFile() && e.name.endsWith('.md') && !EXCLUDED_SKILL_FILES.has(e.name)) {
|
|
223
|
-
return (0, path_1.join)(skillDir, e.name);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
catch {
|
|
228
|
-
/* ignore */
|
|
229
|
-
}
|
|
230
|
-
return null;
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Build skill catalog (one line per enabled skill) for system prompt.
|
|
234
|
-
* Format: "- [source/skillId] keywords: kw1, kw2 | description"
|
|
235
|
-
*/
|
|
236
|
-
function buildSkillCatalog(verbose = false) {
|
|
237
|
-
const skillsBase = (0, path_1.join)((0, os_1.homedir)(), '.mama', 'skills');
|
|
238
|
-
const stateFile = (0, path_1.join)(skillsBase, 'state.json');
|
|
239
|
-
const catalog = [];
|
|
240
|
-
let state = {};
|
|
241
|
-
try {
|
|
242
|
-
if ((0, fs_1.existsSync)(stateFile)) {
|
|
243
|
-
state = JSON.parse((0, fs_1.readFileSync)(stateFile, 'utf-8'));
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
catch {
|
|
247
|
-
/* no state file */
|
|
248
|
-
}
|
|
249
|
-
const sources = ['mama', 'cowork', 'external'];
|
|
250
|
-
for (const source of sources) {
|
|
251
|
-
const sourceDir = (0, path_1.join)(skillsBase, source);
|
|
252
|
-
if (!(0, fs_1.existsSync)(sourceDir))
|
|
253
|
-
continue;
|
|
254
|
-
try {
|
|
255
|
-
const entries = (0, fs_1.readdirSync)(sourceDir, { withFileTypes: true });
|
|
256
|
-
for (const entry of entries) {
|
|
257
|
-
if (!entry.isDirectory())
|
|
258
|
-
continue;
|
|
259
|
-
const stateKey = `${source}/${entry.name}`;
|
|
260
|
-
if (state[stateKey]?.enabled === false)
|
|
261
|
-
continue;
|
|
262
|
-
const skillDir = (0, path_1.join)(sourceDir, entry.name);
|
|
263
|
-
const mainFile = findMainSkillFile(skillDir, entry.name);
|
|
264
|
-
if (!mainFile)
|
|
265
|
-
continue;
|
|
266
|
-
try {
|
|
267
|
-
const content = (0, fs_1.readFileSync)(mainFile, 'utf-8');
|
|
268
|
-
const fm = parseSkillFrontmatter(content);
|
|
269
|
-
const description = fm.description || '';
|
|
270
|
-
const keywords = fm.keywords.length > 0 ? fm.keywords.join(', ') : entry.name;
|
|
271
|
-
catalog.push(`- [${stateKey}] keywords: ${keywords} | ${description}`);
|
|
272
|
-
if (verbose)
|
|
273
|
-
console.log(`[AgentLoop] Skill catalog: ${stateKey}`);
|
|
274
|
-
}
|
|
275
|
-
catch {
|
|
276
|
-
/* skip unreadable */
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
catch {
|
|
281
|
-
/* directory read failed */
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
// Flat .md files at root
|
|
285
|
-
try {
|
|
286
|
-
const rootEntries = (0, fs_1.readdirSync)(skillsBase, { withFileTypes: true });
|
|
287
|
-
for (const entry of rootEntries) {
|
|
288
|
-
if (!entry.isFile() || !entry.name.endsWith('.md'))
|
|
289
|
-
continue;
|
|
290
|
-
if (EXCLUDED_SKILL_FILES.has(entry.name))
|
|
291
|
-
continue;
|
|
292
|
-
const id = entry.name.replace(/\.md$/, '');
|
|
293
|
-
const stateKey = `mama/${id}`;
|
|
294
|
-
if (state[stateKey]?.enabled === false)
|
|
295
|
-
continue;
|
|
296
|
-
if (catalog.some((l) => l.includes(`[${stateKey}]`)))
|
|
297
|
-
continue;
|
|
298
|
-
try {
|
|
299
|
-
const content = (0, fs_1.readFileSync)((0, path_1.join)(skillsBase, entry.name), 'utf-8');
|
|
300
|
-
const fm = parseSkillFrontmatter(content);
|
|
301
|
-
const description = fm.description || '';
|
|
302
|
-
const keywords = fm.keywords.length > 0 ? fm.keywords.join(', ') : id;
|
|
303
|
-
catalog.push(`- [${stateKey}] keywords: ${keywords} | ${description}`);
|
|
304
|
-
if (verbose)
|
|
305
|
-
console.log(`[AgentLoop] Skill catalog (flat): ${stateKey}`);
|
|
306
|
-
}
|
|
307
|
-
catch {
|
|
308
|
-
/* skip */
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
catch {
|
|
313
|
-
/* root directory read failed */
|
|
314
|
-
}
|
|
315
|
-
return catalog;
|
|
316
|
-
}
|
|
317
|
-
/**
|
|
318
|
-
* Load full skill content on-demand for per-message injection.
|
|
319
|
-
* @param skillId - Skill identifier like "mama/playground"
|
|
320
|
-
*/
|
|
321
|
-
function loadSkillContent(skillId) {
|
|
322
|
-
const skillsBase = (0, path_1.join)((0, os_1.homedir)(), '.mama', 'skills');
|
|
323
|
-
// Try directory skill first
|
|
324
|
-
const skillDir = (0, path_1.join)(skillsBase, skillId);
|
|
325
|
-
if ((0, fs_1.existsSync)(skillDir)) {
|
|
326
|
-
const mdFiles = collectMarkdownFiles(skillDir);
|
|
327
|
-
if (mdFiles.length > 0) {
|
|
328
|
-
const parts = mdFiles.map((f) => `## ${f.path}\n\n${f.content}`);
|
|
329
|
-
return `# [Skill: ${skillId}]\n\n${parts.join('\n\n---\n\n')}`;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
// Try flat .md file: "mama/playground" → skills/playground.md
|
|
333
|
-
const idParts = skillId.split('/');
|
|
334
|
-
if (idParts.length >= 2) {
|
|
335
|
-
const flatPath = (0, path_1.join)(skillsBase, `${idParts[idParts.length - 1]}.md`);
|
|
336
|
-
if ((0, fs_1.existsSync)(flatPath)) {
|
|
337
|
-
try {
|
|
338
|
-
return (0, fs_1.readFileSync)(flatPath, 'utf-8');
|
|
339
|
-
}
|
|
340
|
-
catch {
|
|
341
|
-
/* skip */
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
return null;
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* Load installed & enabled skills from ~/.mama/skills/
|
|
349
|
-
* Returns skill catalog lines for system prompt injection (on-demand mode).
|
|
350
|
-
* Full skill content is injected per-message via detectSkillMatch() in PromptEnhancer.
|
|
351
|
-
*/
|
|
352
|
-
function loadInstalledSkills(verbose = false, _options = {}) {
|
|
353
|
-
return buildSkillCatalog(verbose);
|
|
354
|
-
}
|
|
355
121
|
/**
|
|
356
122
|
* Load backend-specific AGENTS.md from ~/.mama/
|
|
357
123
|
* Maps backend to file: 'claude' → AGENTS.claude.md, 'codex-mcp' → AGENTS.codex.md
|
|
@@ -399,7 +165,7 @@ function loadComposedSystemPrompt(verbose = false, context) {
|
|
|
399
165
|
}
|
|
400
166
|
}
|
|
401
167
|
// Load skill catalog (on-demand mode — full content injected per-message by PromptEnhancer)
|
|
402
|
-
const skillCatalog = loadInstalledSkills(verbose);
|
|
168
|
+
const skillCatalog = (0, skill_loader_js_1.loadInstalledSkills)(verbose);
|
|
403
169
|
if (skillCatalog.length > 0) {
|
|
404
170
|
const skillDirective = [
|
|
405
171
|
'# Installed Skills',
|
|
@@ -456,22 +222,9 @@ function getGatewayToolsPrompt() {
|
|
|
456
222
|
if ((0, fs_1.existsSync)(gatewayToolsPath)) {
|
|
457
223
|
return (0, fs_1.readFileSync)(gatewayToolsPath, 'utf-8');
|
|
458
224
|
}
|
|
459
|
-
//
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
return `
|
|
463
|
-
## Gateway Tools
|
|
464
|
-
|
|
465
|
-
To call a Gateway Tool, output a JSON block:
|
|
466
|
-
|
|
467
|
-
\`\`\`tool_call
|
|
468
|
-
{"name": "tool_name", "input": {"param1": "value1"}}
|
|
469
|
-
\`\`\`
|
|
470
|
-
|
|
471
|
-
**MAMA Memory:** mama_search, mama_save, mama_update, mama_load_checkpoint
|
|
472
|
-
**Browser:** browser_navigate, browser_screenshot, browser_click, browser_type, browser_get_text, browser_scroll, browser_wait_for, browser_evaluate, browser_pdf, browser_close
|
|
473
|
-
**Utility:** discord_send, Read, Write, Bash
|
|
474
|
-
`;
|
|
225
|
+
// Fallback generated from ToolRegistry (SSOT) — no manual list to drift
|
|
226
|
+
logger.warn('gateway-tools.md not found, using registry fallback');
|
|
227
|
+
return `# Gateway Tools\n\n${tool_registry_js_1.ToolRegistry.generateFallbackPrompt()}`;
|
|
475
228
|
}
|
|
476
229
|
class AgentLoop {
|
|
477
230
|
agent;
|
|
@@ -483,6 +236,7 @@ class AgentLoop {
|
|
|
483
236
|
onTurn;
|
|
484
237
|
onToolUse;
|
|
485
238
|
onTokenUsage;
|
|
239
|
+
onMetric;
|
|
486
240
|
laneManager;
|
|
487
241
|
useLanes;
|
|
488
242
|
sessionKey;
|
|
@@ -547,7 +301,7 @@ class AgentLoop {
|
|
|
547
301
|
if ((0, fs_1.existsSync)(p))
|
|
548
302
|
personaParts.push((0, fs_1.readFileSync)(p, 'utf-8'));
|
|
549
303
|
}
|
|
550
|
-
const skillCatalog = loadInstalledSkills();
|
|
304
|
+
const skillCatalog = (0, skill_loader_js_1.loadInstalledSkills)();
|
|
551
305
|
// Only load ONBOARDING.md during initial setup (before SOUL.md exists)
|
|
552
306
|
const onboardingContent = !(0, fs_1.existsSync)((0, path_1.join)(mamaHome, 'SOUL.md'))
|
|
553
307
|
? (() => {
|
|
@@ -638,14 +392,12 @@ class AgentLoop {
|
|
|
638
392
|
if (!(0, fs_1.existsSync)(workspaceDir)) {
|
|
639
393
|
(0, fs_1.mkdirSync)(workspaceDir, { recursive: true });
|
|
640
394
|
}
|
|
641
|
-
this.agent = new
|
|
395
|
+
this.agent = new runtime_process_js_1.CodexRuntimeProcess({
|
|
642
396
|
model: options.model,
|
|
643
397
|
cwd: workspaceDir,
|
|
644
398
|
sandbox: 'workspace-write',
|
|
645
399
|
systemPrompt: defaultSystemPrompt,
|
|
646
|
-
|
|
647
|
-
timeoutMs: options.timeoutMs,
|
|
648
|
-
codexHome: (0, path_1.join)((0, os_1.homedir)(), '.mama', '.codex'),
|
|
400
|
+
requestTimeout: options.timeoutMs,
|
|
649
401
|
});
|
|
650
402
|
logger.debug('Codex MCP backend enabled');
|
|
651
403
|
}
|
|
@@ -682,6 +434,7 @@ class AgentLoop {
|
|
|
682
434
|
this.onTurn = options.onTurn;
|
|
683
435
|
this.onToolUse = options.onToolUse;
|
|
684
436
|
this.onTokenUsage = options.onTokenUsage;
|
|
437
|
+
this.onMetric = options.onMetric;
|
|
685
438
|
this.laneManager = (0, index_js_2.getGlobalLaneManager)();
|
|
686
439
|
this.useLanes = options.useLanes ?? false;
|
|
687
440
|
this.sessionKey = options.sessionKey ?? 'default';
|
|
@@ -949,11 +702,17 @@ class AgentLoop {
|
|
|
949
702
|
const shouldResume = !sessionIsNew || turn > 1;
|
|
950
703
|
// Both Claude PersistentCLI and Codex MCP preserve context - only send new messages
|
|
951
704
|
const promptText = this.formatLastMessageOnly(history);
|
|
705
|
+
const promptStart = Date.now();
|
|
952
706
|
try {
|
|
953
707
|
piResult = await this.agent.prompt(promptText, callbacks, {
|
|
954
708
|
model: options?.model,
|
|
955
709
|
resumeSession: shouldResume,
|
|
956
710
|
});
|
|
711
|
+
// Emit prompt latency metric
|
|
712
|
+
this.onMetric?.('prompt_latency_ms', Date.now() - promptStart, {
|
|
713
|
+
backend: this.backend,
|
|
714
|
+
turn: String(turn),
|
|
715
|
+
});
|
|
957
716
|
// After first successful call, mark session as not new for subsequent turns
|
|
958
717
|
if (turn === 1)
|
|
959
718
|
sessionIsNew = false;
|
|
@@ -994,6 +753,7 @@ class AgentLoop {
|
|
|
994
753
|
console.log(`[AgentLoop] Retry successful with new session: ${newSessionId}`);
|
|
995
754
|
}
|
|
996
755
|
else {
|
|
756
|
+
this.onMetric?.('prompt_error', 1, { backend: this.backend, error_type: 'CLI_ERROR' });
|
|
997
757
|
throw new types_js_1.AgentError(`CLI error: ${errorMessage}`, 'CLI_ERROR', error instanceof Error ? error : undefined, true // retryable
|
|
998
758
|
);
|
|
999
759
|
}
|
|
@@ -1209,6 +969,7 @@ class AgentLoop {
|
|
|
1209
969
|
let isError = false;
|
|
1210
970
|
// Notify stream: tool execution starting
|
|
1211
971
|
this.currentStreamCallbacks?.onToolUse?.(toolUse.name, toolUse.input);
|
|
972
|
+
const toolStart = Date.now();
|
|
1212
973
|
try {
|
|
1213
974
|
// Code-Act: execute JS code in sandbox
|
|
1214
975
|
if (toolUse.name === index_js_1.CODE_ACT_MARKER) {
|
|
@@ -1256,12 +1017,21 @@ class AgentLoop {
|
|
|
1256
1017
|
// Notify stream: tool completed (check actual status)
|
|
1257
1018
|
this.currentStreamCallbacks?.onToolComplete?.(toolUse.name, toolUse.id, isError);
|
|
1258
1019
|
}
|
|
1020
|
+
// Emit tool execution metric
|
|
1021
|
+
this.onMetric?.('tool_duration_ms', Date.now() - toolStart, {
|
|
1022
|
+
tool: toolUse.name,
|
|
1023
|
+
error: String(isError),
|
|
1024
|
+
});
|
|
1259
1025
|
}
|
|
1260
1026
|
catch (error) {
|
|
1261
1027
|
isError = true;
|
|
1262
1028
|
result = error instanceof Error ? error.message : String(error);
|
|
1263
1029
|
// Notify tool use callback with error
|
|
1264
1030
|
this.onToolUse?.(toolUse.name, toolUse.input, { error: result });
|
|
1031
|
+
this.onMetric?.('tool_duration_ms', Date.now() - toolStart, {
|
|
1032
|
+
tool: toolUse.name,
|
|
1033
|
+
error: 'true',
|
|
1034
|
+
});
|
|
1265
1035
|
// Notify stream: tool completed with error
|
|
1266
1036
|
this.currentStreamCallbacks?.onToolComplete?.(toolUse.name, toolUse.id, true);
|
|
1267
1037
|
}
|
|
@@ -1534,10 +1304,8 @@ class AgentLoop {
|
|
|
1534
1304
|
return;
|
|
1535
1305
|
this.stopped = true;
|
|
1536
1306
|
try {
|
|
1537
|
-
// Stop
|
|
1538
|
-
|
|
1539
|
-
this.persistentCLI.stopAll();
|
|
1540
|
-
}
|
|
1307
|
+
// Stop the model runner
|
|
1308
|
+
this.agent.stop();
|
|
1541
1309
|
// NOTE: sessionPool is a shared global singleton — do NOT dispose here.
|
|
1542
1310
|
// It will be cleaned up when the process exits or via a global shutdown handler.
|
|
1543
1311
|
// Lane manager doesn't have explicit stop method
|