@jungjaehoon/mama-os 0.23.0 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +1 -1
- package/dist/agent/agent-loop.d.ts +3 -6
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +466 -230
- package/dist/agent/agent-loop.js.map +1 -1
- package/dist/agent/code-act/constants.d.ts +2 -2
- package/dist/agent/code-act/constants.d.ts.map +1 -1
- package/dist/agent/code-act/constants.js +16 -9
- package/dist/agent/code-act/constants.js.map +1 -1
- package/dist/agent/code-act/host-bridge.d.ts +12 -11
- package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
- package/dist/agent/code-act/host-bridge.js +92 -15
- package/dist/agent/code-act/host-bridge.js.map +1 -1
- package/dist/agent/code-act/index.d.ts +2 -0
- package/dist/agent/code-act/index.d.ts.map +1 -1
- package/dist/agent/code-act/index.js +5 -1
- package/dist/agent/code-act/index.js.map +1 -1
- package/dist/agent/code-act/tool-policy.d.ts +42 -0
- package/dist/agent/code-act/tool-policy.d.ts.map +1 -0
- package/dist/agent/code-act/tool-policy.js +122 -0
- package/dist/agent/code-act/tool-policy.js.map +1 -0
- package/dist/agent/code-act/type-definition-generator.d.ts +4 -3
- package/dist/agent/code-act/type-definition-generator.d.ts.map +1 -1
- package/dist/agent/code-act/type-definition-generator.js +26 -48
- package/dist/agent/code-act/type-definition-generator.js.map +1 -1
- package/dist/agent/codex-app-server-process.d.ts +116 -0
- package/dist/agent/codex-app-server-process.d.ts.map +1 -0
- package/dist/agent/codex-app-server-process.js +1382 -0
- package/dist/agent/codex-app-server-process.js.map +1 -0
- package/dist/agent/codex-home.d.ts +9 -0
- package/dist/agent/codex-home.d.ts.map +1 -1
- package/dist/agent/codex-home.js +626 -4
- package/dist/agent/codex-home.js.map +1 -1
- package/dist/agent/codex-thread-registry.d.ts +63 -0
- package/dist/agent/codex-thread-registry.d.ts.map +1 -0
- package/dist/agent/codex-thread-registry.js +433 -0
- package/dist/agent/codex-thread-registry.js.map +1 -0
- package/dist/agent/gateway-tool-executor.d.ts +2 -7
- package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
- package/dist/agent/gateway-tool-executor.js +69 -84
- package/dist/agent/gateway-tool-executor.js.map +1 -1
- package/dist/agent/managed-agent-runtime-sync.d.ts.map +1 -1
- package/dist/agent/managed-agent-runtime-sync.js +0 -3
- package/dist/agent/managed-agent-runtime-sync.js.map +1 -1
- package/dist/agent/managed-agent-validation.js +1 -1
- package/dist/agent/managed-agent-validation.js.map +1 -1
- package/dist/agent/model-runner.d.ts +51 -3
- package/dist/agent/model-runner.d.ts.map +1 -1
- package/dist/agent/model-runner.js +1 -1
- package/dist/agent/model-runner.js.map +1 -1
- package/dist/agent/persistent-cli-adapter.d.ts +1 -0
- package/dist/agent/persistent-cli-adapter.d.ts.map +1 -1
- package/dist/agent/persistent-cli-adapter.js +3 -0
- package/dist/agent/persistent-cli-adapter.js.map +1 -1
- package/dist/agent/session-pool.d.ts +10 -3
- package/dist/agent/session-pool.d.ts.map +1 -1
- package/dist/agent/session-pool.js +23 -8
- package/dist/agent/session-pool.js.map +1 -1
- package/dist/agent/tool-registry.d.ts +14 -0
- package/dist/agent/tool-registry.d.ts.map +1 -1
- package/dist/agent/tool-registry.js +46 -7
- package/dist/agent/tool-registry.js.map +1 -1
- package/dist/agent/types.d.ts +44 -6
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/api/graph-api.d.ts.map +1 -1
- package/dist/api/graph-api.js +19 -7
- package/dist/api/graph-api.js.map +1 -1
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +22 -14
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +7 -4
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/start.d.ts +12 -1
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +161 -27
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/status.js +2 -2
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/config/config-manager.d.ts.map +1 -1
- package/dist/cli/config/config-manager.js +21 -4
- package/dist/cli/config/config-manager.js.map +1 -1
- package/dist/cli/config/types.d.ts +4 -4
- package/dist/cli/config/types.d.ts.map +1 -1
- package/dist/cli/config/types.js +1 -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/cli/runtime/agent-loop-init.d.ts +1 -1
- package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
- package/dist/cli/runtime/agent-loop-init.js +12 -11
- package/dist/cli/runtime/agent-loop-init.js.map +1 -1
- package/dist/cli/runtime/connector-init.d.ts.map +1 -1
- package/dist/cli/runtime/connector-init.js +13 -17
- package/dist/cli/runtime/connector-init.js.map +1 -1
- package/dist/cli/runtime/envelope-bootstrap.d.ts.map +1 -1
- package/dist/cli/runtime/envelope-bootstrap.js +13 -1
- package/dist/cli/runtime/envelope-bootstrap.js.map +1 -1
- package/dist/cli/runtime/gateway-init.d.ts +1 -1
- package/dist/cli/runtime/gateway-init.d.ts.map +1 -1
- package/dist/cli/runtime/gateway-init.js.map +1 -1
- package/dist/cli/runtime/mama-core-init.d.ts +2 -2
- package/dist/cli/runtime/mama-core-init.d.ts.map +1 -1
- package/dist/cli/runtime/mama-core-init.js +17 -0
- package/dist/cli/runtime/mama-core-init.js.map +1 -1
- package/dist/cli/runtime/memory-agent-init.d.ts +1 -1
- package/dist/cli/runtime/memory-agent-init.d.ts.map +1 -1
- package/dist/cli/runtime/memory-agent-init.js +16 -6
- package/dist/cli/runtime/memory-agent-init.js.map +1 -1
- package/dist/cli/runtime/types.d.ts +4 -26
- package/dist/cli/runtime/types.d.ts.map +1 -1
- package/dist/cli/runtime/utilities.js +2 -2
- package/dist/cli/runtime/utilities.js.map +1 -1
- package/dist/connectors/config-loader.d.ts +24 -0
- package/dist/connectors/config-loader.d.ts.map +1 -0
- package/dist/connectors/config-loader.js +205 -0
- package/dist/connectors/config-loader.js.map +1 -0
- package/dist/connectors/framework/types.d.ts +2 -0
- package/dist/connectors/framework/types.d.ts.map +1 -1
- package/dist/connectors/kagemusha/query-tools.js +2 -2
- package/dist/connectors/kagemusha/query-tools.js.map +1 -1
- package/dist/envelope/reactive-config.d.ts +2 -2
- package/dist/envelope/reactive-config.d.ts.map +1 -1
- package/dist/envelope/reactive-config.js +13 -6
- package/dist/envelope/reactive-config.js.map +1 -1
- package/dist/gateways/context-injector.d.ts +2 -1
- package/dist/gateways/context-injector.d.ts.map +1 -1
- package/dist/gateways/context-injector.js.map +1 -1
- package/dist/gateways/message-router.d.ts +9 -0
- package/dist/gateways/message-router.d.ts.map +1 -1
- package/dist/gateways/message-router.js +87 -18
- package/dist/gateways/message-router.js.map +1 -1
- package/dist/gateways/types.d.ts +1 -1
- package/dist/gateways/types.d.ts.map +1 -1
- package/dist/multi-agent/agent-process-manager.d.ts +9 -1
- package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
- package/dist/multi-agent/agent-process-manager.js +197 -49
- package/dist/multi-agent/agent-process-manager.js.map +1 -1
- package/dist/multi-agent/dashboard-agent-persona.js +4 -4
- package/dist/multi-agent/multi-agent-base.d.ts.map +1 -1
- package/dist/multi-agent/multi-agent-base.js +2 -1
- package/dist/multi-agent/multi-agent-base.js.map +1 -1
- package/dist/multi-agent/runtime-process.d.ts +18 -15
- package/dist/multi-agent/runtime-process.d.ts.map +1 -1
- package/dist/multi-agent/runtime-process.js +63 -59
- package/dist/multi-agent/runtime-process.js.map +1 -1
- package/dist/multi-agent/types.d.ts +13 -7
- package/dist/multi-agent/types.d.ts.map +1 -1
- package/dist/multi-agent/types.js.map +1 -1
- package/dist/multi-agent/workflow-engine.js +3 -3
- package/dist/multi-agent/workflow-engine.js.map +1 -1
- package/dist/multi-agent/workflow-types.d.ts +2 -2
- package/dist/multi-agent/workflow-types.d.ts.map +1 -1
- package/dist/operator/operator-trigger-loop.d.ts +3 -0
- package/dist/operator/operator-trigger-loop.d.ts.map +1 -1
- package/dist/operator/operator-trigger-loop.js +1 -0
- package/dist/operator/operator-trigger-loop.js.map +1 -1
- package/dist/operator/report-run.d.ts +4 -4
- package/dist/operator/situation-report.d.ts +3 -0
- package/dist/operator/situation-report.d.ts.map +1 -1
- package/dist/operator/situation-report.js +43 -26
- package/dist/operator/situation-report.js.map +1 -1
- package/dist/operator/trigger-author.d.ts +35 -1
- package/dist/operator/trigger-author.d.ts.map +1 -1
- package/dist/operator/trigger-author.js +73 -10
- package/dist/operator/trigger-author.js.map +1 -1
- package/dist/operator/worker-run.d.ts +31 -0
- package/dist/operator/worker-run.d.ts.map +1 -1
- package/dist/operator/worker-run.js +76 -1
- package/dist/operator/worker-run.js.map +1 -1
- package/dist/operator/workorder-consumer.d.ts +7 -4
- package/dist/operator/workorder-consumer.d.ts.map +1 -1
- package/dist/operator/workorder-consumer.js +8 -3
- package/dist/operator/workorder-consumer.js.map +1 -1
- package/dist/setup/setup-prompt.d.ts +1 -1
- package/dist/setup/setup-prompt.d.ts.map +1 -1
- package/dist/setup/setup-prompt.js +4 -5
- package/dist/setup/setup-prompt.js.map +1 -1
- package/dist/utils/untrusted-content.d.ts +1 -0
- package/dist/utils/untrusted-content.d.ts.map +1 -1
- package/dist/utils/untrusted-content.js +5 -0
- package/dist/utils/untrusted-content.js.map +1 -1
- package/package.json +1 -1
- package/public/viewer/js/modules/agents.js +13 -9
- package/public/viewer/js/modules/settings.js +15 -10
- package/public/viewer/src/modules/agents.ts +12 -10
- package/public/viewer/src/modules/settings.ts +17 -12
- package/public/viewer/src/utils/api.ts +2 -2
- package/templates/AGENTS.codex.md +2 -23
- package/templates/personas/conductor.md +1 -1
- package/dist/agent/codex-mcp-process.d.ts +0 -105
- package/dist/agent/codex-mcp-process.d.ts.map +0 -1
- package/dist/agent/codex-mcp-process.js +0 -748
- package/dist/agent/codex-mcp-process.js.map +0 -1
package/dist/agent/agent-loop.js
CHANGED
|
@@ -45,6 +45,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
45
45
|
})();
|
|
46
46
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
47
|
exports.AgentLoop = void 0;
|
|
48
|
+
exports.sanitizeLegacyCodexAgentsMd = sanitizeLegacyCodexAgentsMd;
|
|
48
49
|
exports.loadBackendAgentsMd = loadBackendAgentsMd;
|
|
49
50
|
exports.loadComposedSystemPrompt = loadComposedSystemPrompt;
|
|
50
51
|
exports.getGatewayToolsPrompt = getGatewayToolsPrompt;
|
|
@@ -92,38 +93,6 @@ const SOURCE_GLOBAL_LANES = {
|
|
|
92
93
|
// because per-run state is scoped (RunScope), not instance state.
|
|
93
94
|
operator: 'operator',
|
|
94
95
|
};
|
|
95
|
-
function matchCodeActToolPattern(pattern, toolName) {
|
|
96
|
-
if (pattern === '*') {
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
if (pattern.endsWith('*')) {
|
|
100
|
-
return toolName.startsWith(pattern.slice(0, -1));
|
|
101
|
-
}
|
|
102
|
-
return pattern === toolName;
|
|
103
|
-
}
|
|
104
|
-
function resolveAllowedCodeActTools(allowedTools, blockedTools) {
|
|
105
|
-
if (!allowedTools) {
|
|
106
|
-
if (!blockedTools?.length) {
|
|
107
|
-
return undefined;
|
|
108
|
-
}
|
|
109
|
-
if (blockedTools.includes('*')) {
|
|
110
|
-
return [];
|
|
111
|
-
}
|
|
112
|
-
const registryNames = index_js_1.HostBridge.getToolRegistry().map((meta) => meta.name);
|
|
113
|
-
return registryNames.filter((toolName) => !blockedTools.some((pattern) => matchCodeActToolPattern(pattern, toolName)));
|
|
114
|
-
}
|
|
115
|
-
if (!blockedTools?.length) {
|
|
116
|
-
return [...allowedTools];
|
|
117
|
-
}
|
|
118
|
-
if (blockedTools.includes('*')) {
|
|
119
|
-
return [];
|
|
120
|
-
}
|
|
121
|
-
const registryNames = index_js_1.HostBridge.getToolRegistry().map((meta) => meta.name);
|
|
122
|
-
const expandedAllowed = allowedTools.includes('*')
|
|
123
|
-
? registryNames
|
|
124
|
-
: registryNames.filter((toolName) => allowedTools.some((pattern) => matchCodeActToolPattern(pattern, toolName)));
|
|
125
|
-
return expandedAllowed.filter((toolName) => !blockedTools.some((pattern) => matchCodeActToolPattern(pattern, toolName)));
|
|
126
|
-
}
|
|
127
96
|
/**
|
|
128
97
|
* Load CLAUDE.md system prompt
|
|
129
98
|
* Tries multiple paths: project root, ~/.mama, /etc/mama
|
|
@@ -163,8 +132,79 @@ function loadSystemPrompt(verbose = false) {
|
|
|
163
132
|
*/
|
|
164
133
|
/**
|
|
165
134
|
* Load backend-specific AGENTS.md from ~/.mama/
|
|
166
|
-
* Maps backend to file: 'claude' → AGENTS.claude.md, 'codex
|
|
135
|
+
* Maps backend to file: 'claude' → AGENTS.claude.md, 'codex' → AGENTS.codex.md
|
|
167
136
|
*/
|
|
137
|
+
function sanitizeLegacyCodexAgentsMd(content) {
|
|
138
|
+
const nativeGuidance = [
|
|
139
|
+
'MAMA exposes the tools permitted for this run as native host tools. Call those tools directly through the model tool interface.',
|
|
140
|
+
'',
|
|
141
|
+
'Do not print Markdown tool blocks or JavaScript as a substitute for a tool call. The available native tool set is injected for each run and already reflects the current role and channel permissions.',
|
|
142
|
+
].join('\n');
|
|
143
|
+
const knownLegacySections = [
|
|
144
|
+
{
|
|
145
|
+
heading: '## Tool protocol',
|
|
146
|
+
nextHeading: '## Behavioural traits to know about yourself',
|
|
147
|
+
signature: 'Gateway tools via `tool_call` JSON blocks:',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
heading: '## Tool Usage',
|
|
151
|
+
nextHeading: '### Skills',
|
|
152
|
+
signature: 'Use gateway tools via `tool_call` JSON blocks.',
|
|
153
|
+
},
|
|
154
|
+
];
|
|
155
|
+
const knownLegacyLines = [
|
|
156
|
+
'### How to Call Tools',
|
|
157
|
+
'### Available Gateway Tools',
|
|
158
|
+
'### Important',
|
|
159
|
+
'- **mama_search**(query?, type?, limit?) — Search decisions in MAMA memory',
|
|
160
|
+
'- **mama_save**(type, topic?, decision?, reasoning?) — Save decision or checkpoint',
|
|
161
|
+
'- **mama_update**(id, outcome, reason?) — Update decision outcome',
|
|
162
|
+
'- **mama_load_checkpoint**() — Load last checkpoint',
|
|
163
|
+
'- **discord_send**(channel_id, message?) — Send message to Discord channel',
|
|
164
|
+
'- **slack_send**(channel_id, message?) — Send message to Slack channel',
|
|
165
|
+
'- **Read**(path) — Read file',
|
|
166
|
+
'- **Write**(path, content) — Write file',
|
|
167
|
+
'- **Bash**(command) — Execute shell command',
|
|
168
|
+
'- Do NOT use `exec_command` or `apply_patch` — use gateway tools instead',
|
|
169
|
+
'- Tool calls are executed automatically. No need to use curl or Bash for these.',
|
|
170
|
+
"Do NOT use `exec_command` or `apply_patch` — those are Codex defaults but bypass MAMA's gateway. Tool calls are executed automatically; do not wrap in `curl` or `Bash`.",
|
|
171
|
+
'## Available gateway tools',
|
|
172
|
+
'`mama_search`, `mama_save`, `mama_recall`, `mama_update`, `mama_load_checkpoint`, `discord_send`, `slack_send`, `Read`, `Write`, `Bash`. Check the skill `SKILL.md` for skill-provided extras.',
|
|
173
|
+
];
|
|
174
|
+
const removeExactLine = (section, line) => section
|
|
175
|
+
.split(/(\r?\n)/)
|
|
176
|
+
.filter((part) => part !== line)
|
|
177
|
+
.join('');
|
|
178
|
+
let sanitized = content;
|
|
179
|
+
for (const legacy of knownLegacySections) {
|
|
180
|
+
const start = sanitized.indexOf(legacy.heading);
|
|
181
|
+
if (start === -1) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const end = sanitized.indexOf(legacy.nextHeading, start + legacy.heading.length);
|
|
185
|
+
if (end === -1) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const section = sanitized.slice(start, end);
|
|
189
|
+
if (!section.includes(legacy.signature) || !section.includes('```tool_call')) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
let transformed = section.replace(legacy.signature, nativeGuidance);
|
|
193
|
+
const toolCallExample = [
|
|
194
|
+
'```tool_call',
|
|
195
|
+
'{"name": "tool_name", "input": {"param1": "value1"}}',
|
|
196
|
+
'```',
|
|
197
|
+
].join('\n');
|
|
198
|
+
transformed = transformed
|
|
199
|
+
.replaceAll(toolCallExample, '')
|
|
200
|
+
.replaceAll(toolCallExample.replaceAll('\n', '\r\n'), '');
|
|
201
|
+
for (const line of knownLegacyLines) {
|
|
202
|
+
transformed = removeExactLine(transformed, line);
|
|
203
|
+
}
|
|
204
|
+
sanitized = `${sanitized.slice(0, start)}${transformed}${sanitized.slice(end)}`;
|
|
205
|
+
}
|
|
206
|
+
return sanitized;
|
|
207
|
+
}
|
|
168
208
|
function loadBackendAgentsMd(backend, verbose = false) {
|
|
169
209
|
if (!backend) {
|
|
170
210
|
return '';
|
|
@@ -172,7 +212,6 @@ function loadBackendAgentsMd(backend, verbose = false) {
|
|
|
172
212
|
const keyMap = {
|
|
173
213
|
claude: 'claude',
|
|
174
214
|
codex: 'codex',
|
|
175
|
-
'codex-mcp': 'codex',
|
|
176
215
|
};
|
|
177
216
|
const key = keyMap[backend];
|
|
178
217
|
if (!key) {
|
|
@@ -183,7 +222,8 @@ function loadBackendAgentsMd(backend, verbose = false) {
|
|
|
183
222
|
if (verbose) {
|
|
184
223
|
console.log(`[AgentLoop] Loaded backend AGENTS.md: AGENTS.${key}.md`);
|
|
185
224
|
}
|
|
186
|
-
|
|
225
|
+
const content = (0, fs_1.readFileSync)(filePath, 'utf-8');
|
|
226
|
+
return key === 'codex' ? sanitizeLegacyCodexAgentsMd(content) : content;
|
|
187
227
|
}
|
|
188
228
|
if (verbose) {
|
|
189
229
|
console.log(`[AgentLoop] Backend AGENTS.md not found: AGENTS.${key}.md`);
|
|
@@ -289,6 +329,98 @@ function getGatewayToolsPrompt(disallowed) {
|
|
|
289
329
|
}
|
|
290
330
|
return filtered;
|
|
291
331
|
}
|
|
332
|
+
const CANONICAL_CODE_ACT_HEADING = '## Code-Act: Gateway Tool Execution via Sandbox';
|
|
333
|
+
const CODE_ACT_MCP_COMPAT_NAME = 'mcp__code-act__code_act';
|
|
334
|
+
const GENERATED_CODE_ACT_START = '<!-- MAMA_GENERATED_CODE_ACT_START -->';
|
|
335
|
+
const GENERATED_CODE_ACT_END = '<!-- MAMA_GENERATED_CODE_ACT_END -->';
|
|
336
|
+
const GENERATED_GATEWAY_TOOLS_START = '<!-- MAMA_GENERATED_GATEWAY_TOOLS_START -->';
|
|
337
|
+
const GENERATED_GATEWAY_TOOLS_END = '<!-- MAMA_GENERATED_GATEWAY_TOOLS_END -->';
|
|
338
|
+
function removePromptSection(systemPrompt, sectionStart, sectionEnd) {
|
|
339
|
+
const prefix = systemPrompt.slice(0, sectionStart);
|
|
340
|
+
const separator = prefix.match(/\r?\n\r?\n---[ \t]*\r?\n\r?\n$/);
|
|
341
|
+
const removalStart = separator?.index ?? sectionStart;
|
|
342
|
+
return `${systemPrompt.slice(0, removalStart)}${systemPrompt.slice(sectionEnd)}`;
|
|
343
|
+
}
|
|
344
|
+
function stripMarkedPromptSection(systemPrompt, startMarker, endMarker) {
|
|
345
|
+
let stripped = systemPrompt;
|
|
346
|
+
let sectionStart = stripped.lastIndexOf(startMarker);
|
|
347
|
+
while (sectionStart >= 0) {
|
|
348
|
+
const markerEnd = stripped.indexOf(endMarker, sectionStart + startMarker.length);
|
|
349
|
+
if (markerEnd < 0) {
|
|
350
|
+
return stripped;
|
|
351
|
+
}
|
|
352
|
+
stripped = removePromptSection(stripped, sectionStart, markerEnd + endMarker.length);
|
|
353
|
+
sectionStart = stripped.lastIndexOf(startMarker);
|
|
354
|
+
}
|
|
355
|
+
return stripped;
|
|
356
|
+
}
|
|
357
|
+
function wrapGeneratedPromptSection(kind, content) {
|
|
358
|
+
const [start, end] = kind === 'codeAct'
|
|
359
|
+
? [GENERATED_CODE_ACT_START, GENERATED_CODE_ACT_END]
|
|
360
|
+
: [GENERATED_GATEWAY_TOOLS_START, GENERATED_GATEWAY_TOOLS_END];
|
|
361
|
+
return `${start}\n${content}\n${end}`;
|
|
362
|
+
}
|
|
363
|
+
function stripGenericGatewayToolsCatalog(systemPrompt) {
|
|
364
|
+
const withoutMarked = stripMarkedPromptSection(systemPrompt, GENERATED_GATEWAY_TOOLS_START, GENERATED_GATEWAY_TOOLS_END);
|
|
365
|
+
const headingPattern = /^#{1,6}\s+Gateway Tools\s*$/gm;
|
|
366
|
+
let catalogStart = -1;
|
|
367
|
+
let match;
|
|
368
|
+
while ((match = headingPattern.exec(withoutMarked)) !== null) {
|
|
369
|
+
catalogStart = match.index;
|
|
370
|
+
}
|
|
371
|
+
if (catalogStart < 0) {
|
|
372
|
+
return withoutMarked;
|
|
373
|
+
}
|
|
374
|
+
const catalog = withoutMarked.slice(catalogStart);
|
|
375
|
+
if (!catalog.includes('Call tools via JSON block:') || !catalog.includes('```tool_call')) {
|
|
376
|
+
return withoutMarked;
|
|
377
|
+
}
|
|
378
|
+
const generatedCatalog = getGatewayToolsPrompt();
|
|
379
|
+
if (withoutMarked.startsWith(generatedCatalog, catalogStart)) {
|
|
380
|
+
return removePromptSection(withoutMarked, catalogStart, catalogStart + generatedCatalog.length);
|
|
381
|
+
}
|
|
382
|
+
const boundedSeparator = catalog.match(/\r?\n\r?\n---[ \t]*\r?\n\r?\n/);
|
|
383
|
+
const sectionEnd = boundedSeparator?.index ?? catalog.length;
|
|
384
|
+
return removePromptSection(withoutMarked, catalogStart, catalogStart + sectionEnd);
|
|
385
|
+
}
|
|
386
|
+
function stripTrailingCanonicalCodeActSection(systemPrompt) {
|
|
387
|
+
const withoutMarked = stripMarkedPromptSection(systemPrompt, GENERATED_CODE_ACT_START, GENERATED_CODE_ACT_END);
|
|
388
|
+
const sectionStart = withoutMarked.lastIndexOf(CANONICAL_CODE_ACT_HEADING);
|
|
389
|
+
if (sectionStart < 0) {
|
|
390
|
+
return withoutMarked;
|
|
391
|
+
}
|
|
392
|
+
const section = withoutMarked.slice(sectionStart);
|
|
393
|
+
const typeFenceStart = section.indexOf('```typescript');
|
|
394
|
+
if (typeFenceStart >= 0) {
|
|
395
|
+
const typeFenceEnd = section.indexOf('```', typeFenceStart + '```typescript'.length);
|
|
396
|
+
if (typeFenceEnd >= 0) {
|
|
397
|
+
return removePromptSection(withoutMarked, sectionStart, sectionStart + typeFenceEnd + 3);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
const boundedSeparator = section.match(/\r?\n\r?\n---[ \t]*\r?\n\r?\n/);
|
|
401
|
+
const sectionEnd = boundedSeparator?.index ?? section.length;
|
|
402
|
+
return removePromptSection(withoutMarked, sectionStart, sectionStart + sectionEnd);
|
|
403
|
+
}
|
|
404
|
+
function stripDisabledCodeActGuidance(systemPrompt) {
|
|
405
|
+
return stripTrailingCanonicalCodeActSection(systemPrompt).replace(/^- \*\*(?:code_act|mcp__code-act__code_act)\*\*.*$/gm, '');
|
|
406
|
+
}
|
|
407
|
+
function combineCodeActSessionPolicyFingerprint(callerFingerprint, policy) {
|
|
408
|
+
return JSON.stringify({
|
|
409
|
+
version: 1,
|
|
410
|
+
callerFingerprint: callerFingerprint ?? null,
|
|
411
|
+
codeActPolicy: policy.fingerprintPayload,
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
function roleAllowsOuterCodeAct(role, disallowedTools) {
|
|
415
|
+
if (!role) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
return tool_registry_js_1.ToolRegistry.getHostToolDefinitions({
|
|
419
|
+
allowedTools: role.allowedTools,
|
|
420
|
+
blockedTools: role.blockedTools,
|
|
421
|
+
disallowedTools: disallowedTools ? [...disallowedTools] : undefined,
|
|
422
|
+
}).some((tool) => tool.name === index_js_1.CODE_ACT_MARKER);
|
|
423
|
+
}
|
|
292
424
|
function buildAgentToolExecutionContext(options) {
|
|
293
425
|
if (!options ||
|
|
294
426
|
(options.agentContext === undefined &&
|
|
@@ -363,7 +495,7 @@ class AgentLoop {
|
|
|
363
495
|
stopContinuationHandler;
|
|
364
496
|
preCompactHandler;
|
|
365
497
|
// Per-run state (stream callbacks, tier) lives in a RunScope threaded through
|
|
366
|
-
// runWithContentInternal -> executeTools
|
|
498
|
+
// runWithContentInternal -> executeTools, NEVER on the
|
|
367
499
|
// instance: concurrent runs on separate global lanes (operator report/worker
|
|
368
500
|
// overlapping owner chat) would steal each other's callbacks and leak tiers
|
|
369
501
|
// if these were instance fields.
|
|
@@ -386,9 +518,17 @@ class AgentLoop {
|
|
|
386
518
|
// Hybrid mode: Gateway + MCP both enabled
|
|
387
519
|
const useGatewayMode = gatewayTools.includes('*') || gatewayTools.length > 0;
|
|
388
520
|
const useMCPMode = mcpTools.includes('*') || mcpTools.length > 0;
|
|
389
|
-
this.isGatewayMode = useGatewayMode;
|
|
390
521
|
this.useCodeAct = options.useCodeAct ?? false;
|
|
391
|
-
this.
|
|
522
|
+
this.isGatewayMode = useGatewayMode || (options.backend === 'codex' && this.useCodeAct);
|
|
523
|
+
this.disallowedTools = this.useCodeAct
|
|
524
|
+
? options.disallowedTools
|
|
525
|
+
: [
|
|
526
|
+
...new Set([
|
|
527
|
+
...(options.disallowedTools ?? []),
|
|
528
|
+
index_js_1.CODE_ACT_MARKER,
|
|
529
|
+
CODE_ACT_MCP_COMPAT_NAME,
|
|
530
|
+
]),
|
|
531
|
+
];
|
|
392
532
|
if (useGatewayMode && useMCPMode) {
|
|
393
533
|
logger.debug('🔀 Hybrid mode: Gateway + MCP tools enabled');
|
|
394
534
|
}
|
|
@@ -459,32 +599,42 @@ class AgentLoop {
|
|
|
459
599
|
];
|
|
460
600
|
}
|
|
461
601
|
const backend = options.backend ?? 'claude';
|
|
602
|
+
if (this.useCodeAct && options.systemPrompt) {
|
|
603
|
+
promptLayers = [
|
|
604
|
+
{
|
|
605
|
+
name: 'custom',
|
|
606
|
+
content: stripTrailingCanonicalCodeActSection(stripGenericGatewayToolsCatalog(options.systemPrompt)),
|
|
607
|
+
priority: 1,
|
|
608
|
+
},
|
|
609
|
+
];
|
|
610
|
+
}
|
|
462
611
|
// Load backend-specific AGENTS.md (e.g., AGENTS.claude.md, AGENTS.codex.md)
|
|
463
612
|
const backendAgentsMd = loadBackendAgentsMd(backend);
|
|
464
613
|
if (backendAgentsMd) {
|
|
465
614
|
promptLayers.push({ name: 'backendAgents', content: backendAgentsMd, priority: 2 });
|
|
466
615
|
}
|
|
467
|
-
if (
|
|
468
|
-
if (this.useCodeAct
|
|
616
|
+
if (this.isGatewayMode) {
|
|
617
|
+
if (this.useCodeAct &&
|
|
618
|
+
roleAllowsOuterCodeAct(options.agentContext?.role, this.disallowedTools)) {
|
|
469
619
|
// Code-Act mode: replace verbose gateway tools markdown with compact .d.ts
|
|
470
|
-
const tierForTypeDefs = options.agentContext?.tier
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
:
|
|
475
|
-
|
|
476
|
-
const typeDefs = index_js_1.TypeDefinitionGenerator.generate(
|
|
477
|
-
const
|
|
478
|
-
const codeActPrompt = (0, index_js_1.getCodeActInstructions)(codeActBackend, allowedGatewayTools) +
|
|
479
|
-
'\n```typescript\n' +
|
|
480
|
-
typeDefs +
|
|
481
|
-
'\n```';
|
|
620
|
+
const tierForTypeDefs = options.agentContext?.tier ?? 1;
|
|
621
|
+
const policy = (0, index_js_1.projectCodeActToolPolicy)({
|
|
622
|
+
tier: tierForTypeDefs,
|
|
623
|
+
role: options.agentContext?.role,
|
|
624
|
+
disallowedTools: this.disallowedTools,
|
|
625
|
+
});
|
|
626
|
+
const typeDefs = index_js_1.TypeDefinitionGenerator.generate(policy);
|
|
627
|
+
const codeActPrompt = wrapGeneratedPromptSection('codeAct', (0, index_js_1.getCodeActInstructions)(backend, policy.names) + '\n```typescript\n' + typeDefs + '\n```');
|
|
482
628
|
promptLayers.push({ name: 'codeAct', content: codeActPrompt, priority: 2 });
|
|
483
629
|
}
|
|
484
|
-
else {
|
|
630
|
+
else if (!this.useCodeAct && backend !== 'codex') {
|
|
485
631
|
const gatewayToolsPrompt = getGatewayToolsPrompt(this.disallowedTools);
|
|
486
632
|
if (gatewayToolsPrompt) {
|
|
487
|
-
promptLayers.push({
|
|
633
|
+
promptLayers.push({
|
|
634
|
+
name: 'gatewayTools',
|
|
635
|
+
content: wrapGeneratedPromptSection('gatewayTools', gatewayToolsPrompt),
|
|
636
|
+
priority: 2,
|
|
637
|
+
});
|
|
488
638
|
}
|
|
489
639
|
}
|
|
490
640
|
}
|
|
@@ -508,9 +658,9 @@ class AgentLoop {
|
|
|
508
658
|
this.defaultSystemPrompt = defaultSystemPrompt;
|
|
509
659
|
// Choose backend (default: claude)
|
|
510
660
|
this.backend = backend;
|
|
511
|
-
if (this.backend === 'codex'
|
|
512
|
-
// Codex
|
|
513
|
-
const workspaceDir = (0, path_1.join)((0, os_1.homedir)(), '.mama', 'workspace');
|
|
661
|
+
if (this.backend === 'codex') {
|
|
662
|
+
// Codex app-server mode
|
|
663
|
+
const workspaceDir = options.codexCwd ?? (0, path_1.join)((0, os_1.homedir)(), '.mama', 'workspace');
|
|
514
664
|
// Ensure workspace directory exists
|
|
515
665
|
if (!(0, fs_1.existsSync)(workspaceDir)) {
|
|
516
666
|
(0, fs_1.mkdirSync)(workspaceDir, { recursive: true });
|
|
@@ -518,12 +668,18 @@ class AgentLoop {
|
|
|
518
668
|
this.agent = new runtime_process_js_1.CodexRuntimeProcess({
|
|
519
669
|
model: options.model,
|
|
520
670
|
cwd: workspaceDir,
|
|
521
|
-
sandbox: 'workspace-write',
|
|
671
|
+
sandbox: options.codexSandbox ?? 'workspace-write',
|
|
522
672
|
systemPrompt: defaultSystemPrompt,
|
|
673
|
+
command: options.codexCommand,
|
|
523
674
|
requestTimeout: options.timeoutMs,
|
|
524
|
-
|
|
675
|
+
codexHome: options.codexHome,
|
|
676
|
+
isolatedHome: options.codexIsolatedHome,
|
|
677
|
+
registryRoot: options.codexRegistryRoot,
|
|
678
|
+
mcpConfigPath: this.useCodeAct
|
|
679
|
+
? undefined
|
|
680
|
+
: (options.mcpConfigPath ?? (useMCPMode ? mcpConfigPath : undefined)),
|
|
525
681
|
});
|
|
526
|
-
logger.debug('Codex
|
|
682
|
+
logger.debug('Codex app-server backend enabled');
|
|
527
683
|
}
|
|
528
684
|
else {
|
|
529
685
|
// Claude backend: always use PersistentCLI for fast responses (~2-3s vs ~16-30s)
|
|
@@ -540,7 +696,7 @@ class AgentLoop {
|
|
|
540
696
|
// Gateway tools are processed by GatewayToolExecutor (hybrid with MCP)
|
|
541
697
|
useGatewayTools: useGatewayMode,
|
|
542
698
|
// Structurally disallow specific tools (e.g., Bash/Read for restricted agents)
|
|
543
|
-
disallowedTools:
|
|
699
|
+
disallowedTools: this.disallowedTools,
|
|
544
700
|
// Native built-ins cross with text-parsed gateway calls (hallucinated
|
|
545
701
|
// ToolSearch/Agent, native gathering that bypasses report verification).
|
|
546
702
|
// Callers opt in per loop; agent-loop-init locks down the main persona.
|
|
@@ -705,6 +861,7 @@ class AgentLoop {
|
|
|
705
861
|
* Set AgentProcessManager for delegate tool (multi-agent delegation)
|
|
706
862
|
*/
|
|
707
863
|
setAgentProcessManager(pm) {
|
|
864
|
+
pm.setGatewayToolExecutor(this.mcpExecutor);
|
|
708
865
|
this.mcpExecutor.setAgentProcessManager(pm);
|
|
709
866
|
}
|
|
710
867
|
/**
|
|
@@ -808,7 +965,11 @@ class AgentLoop {
|
|
|
808
965
|
// Track this run's tier for code-act execution and prompt sizing.
|
|
809
966
|
if (options?.agentContext) {
|
|
810
967
|
const rawTier = options.agentContext.tier ?? 1;
|
|
811
|
-
runScope.tier =
|
|
968
|
+
runScope.tier = this.useCodeAct
|
|
969
|
+
? (0, index_js_1.requireCodeActTier)(rawTier)
|
|
970
|
+
: rawTier === 1 || rawTier === 2 || rawTier === 3
|
|
971
|
+
? rawTier
|
|
972
|
+
: 1;
|
|
812
973
|
}
|
|
813
974
|
// Infinite loop prevention
|
|
814
975
|
let consecutiveToolCalls = 0;
|
|
@@ -825,7 +986,18 @@ class AgentLoop {
|
|
|
825
986
|
// Set session ID on the agent
|
|
826
987
|
// Claude PersistentCLI: process alive → CONTINUE (stdin message), process dead → NEW (spawn with --session-id)
|
|
827
988
|
// Codex: threadId alive → CONTINUE (codex-reply), threadId null → NEW (codex tool)
|
|
828
|
-
const isCodex = this.backend === 'codex'
|
|
989
|
+
const isCodex = this.backend === 'codex';
|
|
990
|
+
const codeActPolicy = this.useCodeAct
|
|
991
|
+
? (0, index_js_1.projectCodeActToolPolicy)({
|
|
992
|
+
tier: runScope.tier,
|
|
993
|
+
role: options?.agentContext?.role,
|
|
994
|
+
disallowedTools: this.disallowedTools,
|
|
995
|
+
})
|
|
996
|
+
: undefined;
|
|
997
|
+
const outerCodeActAllowed = this.useCodeAct && roleAllowsOuterCodeAct(options?.agentContext?.role, this.disallowedTools);
|
|
998
|
+
const effectiveSessionPolicyFingerprint = isCodex && codeActPolicy
|
|
999
|
+
? combineCodeActSessionPolicyFingerprint(options?.sessionPolicyFingerprint, codeActPolicy)
|
|
1000
|
+
: options?.sessionPolicyFingerprint;
|
|
829
1001
|
let resolvedCliSessionId = options?.cliSessionId ?? null;
|
|
830
1002
|
const sessionLabel = (isNew) => {
|
|
831
1003
|
if (isCodex) {
|
|
@@ -848,12 +1020,6 @@ class AgentLoop {
|
|
|
848
1020
|
sessionIsNew = true;
|
|
849
1021
|
ownedSession = true;
|
|
850
1022
|
resolvedCliSessionId = cliSessionId;
|
|
851
|
-
if (isCodex) {
|
|
852
|
-
// Codex MCP manages threadId internally and ignores external session ids
|
|
853
|
-
// (codex-mcp-process.ts:366-369) - the pool reset does NOT reset the codex
|
|
854
|
-
// thread, so the stateless guarantee does not hold there. Loud, not silent.
|
|
855
|
-
console.log('[AgentLoop] freshSession is a pool-level reset only on the codex backend - the codex thread persists (see TODO: codex report thread reset)');
|
|
856
|
-
}
|
|
857
1023
|
console.log(`[AgentLoop] [${isCodex ? 'codex' : 'claude'}] ${channelKey} (FRESH session - stateless lane)`);
|
|
858
1024
|
}
|
|
859
1025
|
else {
|
|
@@ -878,41 +1044,119 @@ class AgentLoop {
|
|
|
878
1044
|
modelRunId: ownedModelRunId,
|
|
879
1045
|
}), backgroundTasks);
|
|
880
1046
|
}
|
|
881
|
-
let
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
1047
|
+
let nativeToolCallCount = 0;
|
|
1048
|
+
let nativeConsecutiveToolCalls = 0;
|
|
1049
|
+
let nativeLastToolName = '';
|
|
1050
|
+
const hostToolBridge = isCodex && this.isGatewayMode
|
|
1051
|
+
? {
|
|
1052
|
+
tools: this.useCodeAct
|
|
1053
|
+
? outerCodeActAllowed
|
|
1054
|
+
? tool_registry_js_1.ToolRegistry.getHostToolDefinitions({ allowedTools: [index_js_1.CODE_ACT_MARKER] })
|
|
1055
|
+
: []
|
|
1056
|
+
: tool_registry_js_1.ToolRegistry.getHostToolDefinitions({
|
|
1057
|
+
allowedTools: options?.agentContext?.role.allowedTools,
|
|
1058
|
+
blockedTools: options?.agentContext?.role.blockedTools,
|
|
1059
|
+
disallowedTools: this.disallowedTools,
|
|
1060
|
+
viewer: options?.agentContext?.platform === 'viewer',
|
|
1061
|
+
}),
|
|
1062
|
+
execute: async (call) => {
|
|
1063
|
+
const callSignal = call.signal ?? new AbortController().signal;
|
|
1064
|
+
callSignal.throwIfAborted();
|
|
1065
|
+
if (nativeToolCallCount >= EMERGENCY_MAX_TURNS) {
|
|
1066
|
+
return {
|
|
1067
|
+
content: `Native tool call budget exceeded emergency maximum turns (${EMERGENCY_MAX_TURNS})`,
|
|
1068
|
+
isError: true,
|
|
1069
|
+
abort: true,
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
const nextConsecutiveCount = call.name === nativeLastToolName ? nativeConsecutiveToolCalls + 1 : 1;
|
|
1073
|
+
if (nextConsecutiveCount >= MAX_CONSECUTIVE_SAME_TOOL) {
|
|
1074
|
+
return {
|
|
1075
|
+
content: `Infinite loop detected: Tool "${call.name}" called ${nextConsecutiveCount} times consecutively`,
|
|
1076
|
+
isError: true,
|
|
1077
|
+
abort: true,
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
nativeToolCallCount += 1;
|
|
1081
|
+
nativeConsecutiveToolCalls = nextConsecutiveCount;
|
|
1082
|
+
nativeLastToolName = call.name;
|
|
1083
|
+
const toolUse = {
|
|
1084
|
+
type: 'tool_use',
|
|
1085
|
+
id: call.callId,
|
|
1086
|
+
name: call.name,
|
|
1087
|
+
input: call.input,
|
|
1088
|
+
};
|
|
1089
|
+
history.push({ role: 'assistant', content: [toolUse] });
|
|
1090
|
+
runScope.onTurn?.({
|
|
1091
|
+
turn,
|
|
1092
|
+
role: 'assistant',
|
|
1093
|
+
content: [toolUse],
|
|
1094
|
+
stopReason: 'tool_use',
|
|
1095
|
+
});
|
|
1096
|
+
const callExecutionContext = toolExecutionContext
|
|
1097
|
+
? {
|
|
1098
|
+
...toolExecutionContext,
|
|
1099
|
+
gatewayCallId: call.callId,
|
|
1100
|
+
signal: callSignal,
|
|
1101
|
+
}
|
|
1102
|
+
: null;
|
|
1103
|
+
const [toolResult] = await this.executeTools([toolUse], options?.stopAfterSuccessfulTools ?? [], callExecutionContext, runScope);
|
|
1104
|
+
callSignal.throwIfAborted();
|
|
1105
|
+
if (!toolResult) {
|
|
1106
|
+
return {
|
|
1107
|
+
content: `Native tool "${call.name}" returned no result`,
|
|
1108
|
+
isError: true,
|
|
1109
|
+
abort: true,
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
history.push({ role: 'user', content: [toolResult] });
|
|
1113
|
+
runScope.onTurn?.({
|
|
1114
|
+
turn,
|
|
1115
|
+
role: 'user',
|
|
1116
|
+
content: [toolResult],
|
|
1117
|
+
});
|
|
1118
|
+
return {
|
|
1119
|
+
content: toolResult.content,
|
|
1120
|
+
isError: toolResult.is_error === true,
|
|
1121
|
+
stop: toolResult.is_error !== true &&
|
|
1122
|
+
(options?.stopAfterSuccessfulTools ?? []).includes(call.name),
|
|
1123
|
+
};
|
|
1124
|
+
},
|
|
1125
|
+
}
|
|
1126
|
+
: undefined;
|
|
1127
|
+
const prepareSystemPrompt = (requestedSystemPrompt, isResumingSession) => {
|
|
1128
|
+
let baseSystemPrompt = requestedSystemPrompt ?? this.defaultSystemPrompt;
|
|
890
1129
|
let gatewayToolsPrompt = '';
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
if (
|
|
894
|
-
const
|
|
895
|
-
const typeDefs = index_js_1.TypeDefinitionGenerator.generate(
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
(0, index_js_1.getCodeActInstructions)(codeActBackend, allowedGatewayTools) +
|
|
901
|
-
'\n```typescript\n' +
|
|
902
|
-
typeDefs +
|
|
903
|
-
'\n```';
|
|
1130
|
+
if (this.isGatewayMode && this.useCodeAct) {
|
|
1131
|
+
baseSystemPrompt = stripTrailingCanonicalCodeActSection(stripGenericGatewayToolsCatalog(baseSystemPrompt));
|
|
1132
|
+
if (outerCodeActAllowed) {
|
|
1133
|
+
const policy = codeActPolicy;
|
|
1134
|
+
const typeDefs = index_js_1.TypeDefinitionGenerator.generate(policy);
|
|
1135
|
+
gatewayToolsPrompt = wrapGeneratedPromptSection('codeAct', (0, index_js_1.getCodeActInstructions)(isCodex ? 'codex' : 'claude', policy.names) +
|
|
1136
|
+
'\n```typescript\n' +
|
|
1137
|
+
typeDefs +
|
|
1138
|
+
'\n```');
|
|
904
1139
|
}
|
|
905
|
-
|
|
906
|
-
|
|
1140
|
+
}
|
|
1141
|
+
else if (this.isGatewayMode && !isCodex) {
|
|
1142
|
+
baseSystemPrompt = stripDisabledCodeActGuidance(baseSystemPrompt);
|
|
1143
|
+
if (!isResumingSession) {
|
|
1144
|
+
// Non-CodeAct callers may already embed the generic gateway catalog.
|
|
1145
|
+
const alreadyHasTools = baseSystemPrompt.includes('# Gateway Tools') ||
|
|
1146
|
+
baseSystemPrompt.includes('# Code Execution') ||
|
|
1147
|
+
baseSystemPrompt.includes('## Code-Act');
|
|
1148
|
+
if (!alreadyHasTools) {
|
|
1149
|
+
gatewayToolsPrompt = wrapGeneratedPromptSection('gatewayTools', getGatewayToolsPrompt(this.disallowedTools));
|
|
1150
|
+
}
|
|
907
1151
|
}
|
|
908
1152
|
}
|
|
909
1153
|
const fullPrompt = gatewayToolsPrompt
|
|
910
|
-
? `${
|
|
911
|
-
:
|
|
1154
|
+
? `${baseSystemPrompt}\n\n---\n\n${gatewayToolsPrompt}`
|
|
1155
|
+
: baseSystemPrompt;
|
|
912
1156
|
// Monitor and enforce prompt size
|
|
913
1157
|
const monitor = new prompt_size_monitor_js_1.PromptSizeMonitor();
|
|
914
1158
|
const runLayers = [
|
|
915
|
-
{ name: 'systemPrompt', content:
|
|
1159
|
+
{ name: 'systemPrompt', content: baseSystemPrompt, priority: 1 },
|
|
916
1160
|
...(gatewayToolsPrompt
|
|
917
1161
|
? [{ name: 'gatewayTools', content: gatewayToolsPrompt, priority: 2 }]
|
|
918
1162
|
: []),
|
|
@@ -927,14 +1171,18 @@ class AgentLoop {
|
|
|
927
1171
|
if (enforceResult.truncatedLayers.length > 0) {
|
|
928
1172
|
console.warn(`[AgentLoop] Truncated layers: ${enforceResult.truncatedLayers.join(', ')}`);
|
|
929
1173
|
}
|
|
930
|
-
const tBase = trimmed.find((l) => l.name === 'systemPrompt')?.content ||
|
|
1174
|
+
const tBase = trimmed.find((l) => l.name === 'systemPrompt')?.content || baseSystemPrompt;
|
|
931
1175
|
const tTools = trimmed.find((l) => l.name === 'gatewayTools')?.content || '';
|
|
932
1176
|
effectivePrompt = tTools ? `${tBase}\n\n---\n\n${tTools}` : tBase;
|
|
933
1177
|
console.log(`[AgentLoop] System prompt truncated: ${fullPrompt.length} → ${effectivePrompt.length} chars`);
|
|
934
1178
|
}
|
|
935
|
-
perCallSystemPrompt = effectivePrompt;
|
|
936
1179
|
console.log(`[AgentLoop] Prepared systemPrompt for this call: ${effectivePrompt.length} chars ` +
|
|
937
|
-
`(base: ${
|
|
1180
|
+
`(base: ${baseSystemPrompt.length}, tools: ${gatewayToolsPrompt.length})`);
|
|
1181
|
+
return effectivePrompt;
|
|
1182
|
+
};
|
|
1183
|
+
let perCallSystemPrompt;
|
|
1184
|
+
if (options?.systemPrompt || (this.isGatewayMode && this.useCodeAct)) {
|
|
1185
|
+
perCallSystemPrompt = prepareSystemPrompt(options?.systemPrompt, options?.resumeSession === true);
|
|
938
1186
|
}
|
|
939
1187
|
else {
|
|
940
1188
|
perCallSystemPrompt = this.defaultSystemPrompt;
|
|
@@ -972,6 +1220,7 @@ class AgentLoop {
|
|
|
972
1220
|
}
|
|
973
1221
|
let response;
|
|
974
1222
|
const ext = runScope.streamCallbacks;
|
|
1223
|
+
let attemptReportedError;
|
|
975
1224
|
const callbacks = {
|
|
976
1225
|
onDelta: (text) => {
|
|
977
1226
|
ext?.onDelta?.(text);
|
|
@@ -986,31 +1235,48 @@ class AgentLoop {
|
|
|
986
1235
|
ext?.onFinal?.(finalResponse);
|
|
987
1236
|
},
|
|
988
1237
|
onError: (error) => {
|
|
989
|
-
|
|
1238
|
+
// A model runner can emit onError before rejecting. Hold it until
|
|
1239
|
+
// AgentLoop knows whether the attempt is terminal so a successful
|
|
1240
|
+
// one-time session recovery does not leak a false failure event.
|
|
1241
|
+
attemptReportedError = error;
|
|
990
1242
|
},
|
|
991
1243
|
};
|
|
992
1244
|
let piResult;
|
|
993
1245
|
// Claude: First turn → --session-id (inject system prompt), subsequent → --resume
|
|
994
1246
|
// Codex: resumeSession only controls threadId reset (false=new thread, true=continue)
|
|
995
|
-
const shouldResume =
|
|
996
|
-
|
|
1247
|
+
const shouldResume = isCodex
|
|
1248
|
+
? turn > 1 || (options?.freshSession === true ? false : (options?.resumeSession ?? true))
|
|
1249
|
+
: !sessionIsNew || turn > 1;
|
|
1250
|
+
// Both Claude PersistentCLI and Codex app-server preserve context - only send new messages
|
|
997
1251
|
const promptText = this.formatLastMessageOnly(history);
|
|
998
1252
|
const promptStart = Date.now();
|
|
1253
|
+
const throwFinalCliError = (error) => {
|
|
1254
|
+
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
1255
|
+
this.onMetric?.('prompt_error', 1, {
|
|
1256
|
+
backend: this.backend,
|
|
1257
|
+
error_type: 'CLI_ERROR',
|
|
1258
|
+
});
|
|
1259
|
+
try {
|
|
1260
|
+
ext?.onError?.(attemptReportedError ?? normalizedError);
|
|
1261
|
+
}
|
|
1262
|
+
catch (callbackError) {
|
|
1263
|
+
logger.warn(`External onError callback failed: ${callbackError instanceof Error ? callbackError.message : String(callbackError)}`);
|
|
1264
|
+
}
|
|
1265
|
+
throw new types_js_1.AgentError(`CLI error: ${normalizedError.message}`, 'CLI_ERROR', normalizedError, true);
|
|
1266
|
+
};
|
|
999
1267
|
try {
|
|
1000
1268
|
piResult = await this.agent.prompt(promptText, callbacks, {
|
|
1001
1269
|
model: options?.model,
|
|
1002
1270
|
resumeSession: shouldResume,
|
|
1003
1271
|
systemPrompt: perCallSystemPrompt,
|
|
1272
|
+
sessionKey: channelKey,
|
|
1273
|
+
sessionPolicyFingerprint: effectiveSessionPolicyFingerprint,
|
|
1004
1274
|
sessionId: resolvedCliSessionId ?? undefined,
|
|
1275
|
+
// Per-run request timeout (operator worker runs); undefined leaves
|
|
1276
|
+
// the pool's construction-time default untouched (chat).
|
|
1277
|
+
requestTimeout: options?.requestTimeoutMs,
|
|
1278
|
+
hostToolBridge,
|
|
1005
1279
|
});
|
|
1006
|
-
// Emit prompt latency metric
|
|
1007
|
-
this.onMetric?.('prompt_latency_ms', Date.now() - promptStart, {
|
|
1008
|
-
backend: this.backend,
|
|
1009
|
-
turn: String(turn),
|
|
1010
|
-
});
|
|
1011
|
-
// After first successful call, mark session as not new for subsequent turns
|
|
1012
|
-
if (turn === 1)
|
|
1013
|
-
sessionIsNew = false;
|
|
1014
1280
|
}
|
|
1015
1281
|
catch (error) {
|
|
1016
1282
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -1026,42 +1292,83 @@ class AgentLoop {
|
|
|
1026
1292
|
errorMessage.includes('request_too_large') ||
|
|
1027
1293
|
errorMessage.includes('context window') ||
|
|
1028
1294
|
errorMessage.includes('context_length_exceeded');
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1295
|
+
const isCodexPolicyMismatch = errorMessage.includes('Codex app-server thread policy mismatch; reset the session explicitly');
|
|
1296
|
+
if ((isCodex && isCodexPolicyMismatch) ||
|
|
1297
|
+
(!isCodex && (isSessionNotFound || isSessionInUse || isPromptTooLong))) {
|
|
1298
|
+
const reason = isCodexPolicyMismatch
|
|
1299
|
+
? 'policy mismatch'
|
|
1300
|
+
: isSessionNotFound
|
|
1301
|
+
? 'not found in CLI'
|
|
1302
|
+
: isSessionInUse
|
|
1303
|
+
? 'already in use'
|
|
1304
|
+
: 'prompt too long (context overflow)';
|
|
1035
1305
|
console.log(`[AgentLoop] Session ${reason}, retrying with new session`);
|
|
1036
1306
|
// Reset session in pool so it creates a new one
|
|
1037
1307
|
const newSessionId = this.sessionPool.resetSession(channelKey);
|
|
1308
|
+
options?.onCliSessionReset?.(newSessionId);
|
|
1038
1309
|
// Per-call routing: hand the new id to this prompt() and update the
|
|
1039
1310
|
// resolved id so later turns follow it - no shared-adapter mutation.
|
|
1040
1311
|
resolvedCliSessionId = newSessionId;
|
|
1041
|
-
//
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1312
|
+
// A policy mismatch can occur on a resumed MessageRouter session,
|
|
1313
|
+
// whose per-call prompt is intentionally minimal. Rebuild the full
|
|
1314
|
+
// policy prompt before opening the replacement durable thread.
|
|
1315
|
+
let resetSystemPrompt = perCallSystemPrompt;
|
|
1316
|
+
try {
|
|
1317
|
+
// Discard the recoverable first-attempt error before any reset
|
|
1318
|
+
// preparation. A prompt rebuild or retry failure must surface
|
|
1319
|
+
// its own final error, never the mismatch that triggered it.
|
|
1320
|
+
attemptReportedError = undefined;
|
|
1321
|
+
if (isCodexPolicyMismatch && options?.freshSessionSystemPrompt) {
|
|
1322
|
+
resetSystemPrompt = prepareSystemPrompt(await options.freshSessionSystemPrompt(), false);
|
|
1323
|
+
}
|
|
1324
|
+
piResult = await this.agent.prompt(promptText, callbacks, {
|
|
1325
|
+
model: options?.model,
|
|
1326
|
+
resumeSession: false, // Force new session
|
|
1327
|
+
systemPrompt: resetSystemPrompt,
|
|
1328
|
+
sessionKey: channelKey,
|
|
1329
|
+
sessionPolicyFingerprint: effectiveSessionPolicyFingerprint,
|
|
1330
|
+
sessionId: newSessionId,
|
|
1331
|
+
// Carry the per-run timeout onto the reset session too.
|
|
1332
|
+
requestTimeout: options?.requestTimeoutMs,
|
|
1333
|
+
hostToolBridge,
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1336
|
+
catch (retryError) {
|
|
1337
|
+
console.error(`[AgentLoop] ${this.backend} reset retry failed:`, retryError instanceof Error ? retryError.message : String(retryError));
|
|
1338
|
+
// resetSession() creates and locks a replacement pool entry.
|
|
1339
|
+
// A failed rebuild/retry must remove it entirely; otherwise the
|
|
1340
|
+
// next MessageRouter turn sees isNew=false and can persist a
|
|
1341
|
+
// minimal resume prompt as the replacement thread's base policy.
|
|
1342
|
+
this.sessionPool.invalidateSession(channelKey, newSessionId);
|
|
1343
|
+
throwFinalCliError(retryError);
|
|
1344
|
+
}
|
|
1048
1345
|
// Prepend reset notice so user knows context was lost
|
|
1049
|
-
if (isPromptTooLong && piResult
|
|
1346
|
+
if (isPromptTooLong && piResult?.response) {
|
|
1050
1347
|
piResult.response = `⚠️ Session reset: The previous conversation was too long, starting a new session.\n\n${piResult.response}`;
|
|
1051
1348
|
}
|
|
1052
1349
|
console.log(`[AgentLoop] Retry successful with new session: ${newSessionId}`);
|
|
1053
1350
|
}
|
|
1054
1351
|
else {
|
|
1055
|
-
|
|
1056
|
-
throw new types_js_1.AgentError(`CLI error: ${errorMessage}`, 'CLI_ERROR', error instanceof Error ? error : undefined, true // retryable
|
|
1057
|
-
);
|
|
1352
|
+
throwFinalCliError(error);
|
|
1058
1353
|
}
|
|
1059
1354
|
}
|
|
1355
|
+
if (!piResult) {
|
|
1356
|
+
return throwFinalCliError(new Error('Model runner returned no prompt result'));
|
|
1357
|
+
}
|
|
1358
|
+
// Emit one terminal metric per prompt turn, including recovered calls.
|
|
1359
|
+
this.onMetric?.('prompt_latency_ms', Date.now() - promptStart, {
|
|
1360
|
+
backend: this.backend,
|
|
1361
|
+
turn: String(turn),
|
|
1362
|
+
});
|
|
1363
|
+
// After first successful call, mark session as not new for subsequent turns
|
|
1364
|
+
if (turn === 1) {
|
|
1365
|
+
sessionIsNew = false;
|
|
1366
|
+
}
|
|
1060
1367
|
// Build content blocks - include tool_use blocks if present
|
|
1061
1368
|
const contentBlocks = [];
|
|
1062
1369
|
let parsedToolCalls = [];
|
|
1063
1370
|
// Parse tool_call / code_act blocks from text response (Gateway Tools mode ONLY)
|
|
1064
|
-
if (this.isGatewayMode) {
|
|
1371
|
+
if (this.isGatewayMode && !isCodex) {
|
|
1065
1372
|
parsedToolCalls = this.parseToolCallsFromText(piResult.response || '');
|
|
1066
1373
|
// Code-Act: parse ```js blocks only if enabled
|
|
1067
1374
|
if (this.useCodeAct) {
|
|
@@ -1106,11 +1413,8 @@ class AgentLoop {
|
|
|
1106
1413
|
}
|
|
1107
1414
|
console.log(`[AgentLoop] Detected ${toolUseBlocks.length} tool calls from MCP`);
|
|
1108
1415
|
}
|
|
1109
|
-
//
|
|
1110
|
-
|
|
1111
|
-
const hasToolUse = this.isGatewayMode
|
|
1112
|
-
? parsedToolCalls.length > 0
|
|
1113
|
-
: ('hasToolUse' in piResult ? piResult.hasToolUse : false) || false;
|
|
1416
|
+
// Both parsed gateway calls and native/MCP tool blocks share executeTools.
|
|
1417
|
+
const hasToolUse = contentBlocks.some((block) => block.type === 'tool_use');
|
|
1114
1418
|
// eslint-disable-next-line prefer-const
|
|
1115
1419
|
response = {
|
|
1116
1420
|
id: `msg_${Date.now()}`,
|
|
@@ -1142,7 +1446,7 @@ class AgentLoop {
|
|
|
1142
1446
|
}
|
|
1143
1447
|
}
|
|
1144
1448
|
// Track tokens in session pool for auto-reset at 80% context
|
|
1145
|
-
const tokenBackend = this.backend === 'codex'
|
|
1449
|
+
const tokenBackend = this.backend === 'codex' ? 'codex' : 'claude';
|
|
1146
1450
|
const tokenStatus = this.sessionPool.updateTokens(channelKey, response.usage.input_tokens, tokenBackend);
|
|
1147
1451
|
// PreCompact: inject compaction summary when approaching context limit
|
|
1148
1452
|
if (tokenStatus.nearThreshold && this.preCompactHandler && !runScope.preCompactInjected) {
|
|
@@ -1342,60 +1646,36 @@ class AgentLoop {
|
|
|
1342
1646
|
for (const toolUse of toolUseBlocks) {
|
|
1343
1647
|
let result;
|
|
1344
1648
|
let isError = false;
|
|
1649
|
+
const executionToolName = toolUse.name === CODE_ACT_MCP_COMPAT_NAME ? index_js_1.CODE_ACT_MARKER : toolUse.name;
|
|
1345
1650
|
// Notify stream: tool execution starting
|
|
1346
|
-
runScope.streamCallbacks?.onToolUse?.(
|
|
1651
|
+
runScope.streamCallbacks?.onToolUse?.(executionToolName, toolUse.input);
|
|
1347
1652
|
const toolStart = Date.now();
|
|
1348
1653
|
try {
|
|
1349
|
-
//
|
|
1350
|
-
|
|
1351
|
-
if (
|
|
1352
|
-
|
|
1353
|
-
const code = typeof codeInput?.code === 'string' ? codeInput.code : '';
|
|
1354
|
-
const codeActResult = code
|
|
1355
|
-
? await this.executeCodeAct(code, runScope.tier, modelToolContext, runScope)
|
|
1356
|
-
: {
|
|
1357
|
-
success: false,
|
|
1358
|
-
error: {
|
|
1359
|
-
name: 'ValidationError',
|
|
1360
|
-
message: 'Missing or invalid "code" field in code_act input',
|
|
1361
|
-
},
|
|
1362
|
-
logs: [],
|
|
1363
|
-
metrics: { durationMs: 0, hostCallCount: 0, memoryUsedBytes: 0 },
|
|
1364
|
-
};
|
|
1365
|
-
result = JSON.stringify(codeActResult, null, 2);
|
|
1366
|
-
if (!codeActResult.success) {
|
|
1367
|
-
isError = true;
|
|
1368
|
-
}
|
|
1369
|
-
runScope.onToolUse?.(toolUse.name, toolUse.input, codeActResult);
|
|
1370
|
-
runScope.streamCallbacks?.onToolComplete?.(toolUse.name, toolUse.id, isError);
|
|
1654
|
+
// PreToolUse: search MAMA for contracts before Write operations
|
|
1655
|
+
let contractContext = '';
|
|
1656
|
+
if (executionToolName === 'Write' && toolUse.input) {
|
|
1657
|
+
contractContext = await this.searchContractsForTool(executionToolName, toolUse.input, reactiveInternalContext);
|
|
1371
1658
|
}
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
const toolFailed = hasSuccess && !toolResult.success;
|
|
1383
|
-
if (toolFailed) {
|
|
1384
|
-
isError = true;
|
|
1385
|
-
}
|
|
1386
|
-
if (contractContext) {
|
|
1387
|
-
result = `${contractContext}\n\n---\n\n${result}`;
|
|
1388
|
-
}
|
|
1389
|
-
// Notify tool use callback
|
|
1390
|
-
runScope.onToolUse?.(toolUse.name, toolUse.input, toolResult);
|
|
1391
|
-
// PostToolUse: auto-extract contracts (fire-and-forget)
|
|
1392
|
-
this.postToolHandler?.processInBackground(toolUse.name, toolUse.input, toolResult, reactiveInternalContext);
|
|
1393
|
-
// Notify stream: tool completed (check actual status)
|
|
1394
|
-
runScope.streamCallbacks?.onToolComplete?.(toolUse.name, toolUse.id, isError);
|
|
1659
|
+
const toolResult = await this.mcpExecutor.execute(executionToolName, toolUse.input, modelToolContext ?? undefined);
|
|
1660
|
+
result = JSON.stringify(toolResult, null, 2);
|
|
1661
|
+
// Check if tool execution failed
|
|
1662
|
+
const hasSuccess = 'success' in toolResult;
|
|
1663
|
+
const toolFailed = hasSuccess && !toolResult.success;
|
|
1664
|
+
if (toolFailed) {
|
|
1665
|
+
isError = true;
|
|
1666
|
+
}
|
|
1667
|
+
if (contractContext) {
|
|
1668
|
+
result = `${contractContext}\n\n---\n\n${result}`;
|
|
1395
1669
|
}
|
|
1670
|
+
// Notify tool use callback
|
|
1671
|
+
runScope.onToolUse?.(executionToolName, toolUse.input, toolResult);
|
|
1672
|
+
// PostToolUse: auto-extract contracts (fire-and-forget)
|
|
1673
|
+
this.postToolHandler?.processInBackground(executionToolName, toolUse.input, toolResult, reactiveInternalContext);
|
|
1674
|
+
// Notify stream: tool completed (check actual status)
|
|
1675
|
+
runScope.streamCallbacks?.onToolComplete?.(executionToolName, toolUse.id, isError);
|
|
1396
1676
|
// Emit tool execution metric
|
|
1397
1677
|
this.onMetric?.('tool_duration_ms', Date.now() - toolStart, {
|
|
1398
|
-
tool:
|
|
1678
|
+
tool: executionToolName,
|
|
1399
1679
|
error: String(isError),
|
|
1400
1680
|
});
|
|
1401
1681
|
}
|
|
@@ -1403,13 +1683,13 @@ class AgentLoop {
|
|
|
1403
1683
|
isError = true;
|
|
1404
1684
|
result = error instanceof Error ? error.message : String(error);
|
|
1405
1685
|
// Notify tool use callback with error
|
|
1406
|
-
runScope.onToolUse?.(
|
|
1686
|
+
runScope.onToolUse?.(executionToolName, toolUse.input, { error: result });
|
|
1407
1687
|
this.onMetric?.('tool_duration_ms', Date.now() - toolStart, {
|
|
1408
|
-
tool:
|
|
1688
|
+
tool: executionToolName,
|
|
1409
1689
|
error: 'true',
|
|
1410
1690
|
});
|
|
1411
1691
|
// Notify stream: tool completed with error
|
|
1412
|
-
runScope.streamCallbacks?.onToolComplete?.(
|
|
1692
|
+
runScope.streamCallbacks?.onToolComplete?.(executionToolName, toolUse.id, true);
|
|
1413
1693
|
}
|
|
1414
1694
|
results.push({
|
|
1415
1695
|
type: 'tool_result',
|
|
@@ -1417,7 +1697,7 @@ class AgentLoop {
|
|
|
1417
1697
|
content: result,
|
|
1418
1698
|
is_error: isError,
|
|
1419
1699
|
});
|
|
1420
|
-
if (!isError && stopAfterSuccessfulTools.includes(
|
|
1700
|
+
if (!isError && stopAfterSuccessfulTools.includes(executionToolName)) {
|
|
1421
1701
|
break;
|
|
1422
1702
|
}
|
|
1423
1703
|
}
|
|
@@ -1507,50 +1787,6 @@ class AgentLoop {
|
|
|
1507
1787
|
}
|
|
1508
1788
|
return blocks;
|
|
1509
1789
|
}
|
|
1510
|
-
/**
|
|
1511
|
-
* Execute Code-Act JS code in a sandboxed QuickJS environment
|
|
1512
|
-
*/
|
|
1513
|
-
async executeCodeAct(code, tier = 1, executionContext = null, runScope = { tier: 1 }) {
|
|
1514
|
-
try {
|
|
1515
|
-
const sandbox = new index_js_1.CodeActSandbox();
|
|
1516
|
-
const bridgeContext = withExecutionSurface(executionContext, 'code_act');
|
|
1517
|
-
const bridge = new index_js_1.HostBridge(this.mcpExecutor, undefined, bridgeContext);
|
|
1518
|
-
bridge.onToolUse = (toolName, input, result) => {
|
|
1519
|
-
if (result === undefined) {
|
|
1520
|
-
// Tool starting — surface to stream
|
|
1521
|
-
runScope.streamCallbacks?.onToolUse?.(toolName, input);
|
|
1522
|
-
}
|
|
1523
|
-
if (result !== undefined) {
|
|
1524
|
-
// Tool completed — notify callback
|
|
1525
|
-
runScope.onToolUse?.(toolName, input, result);
|
|
1526
|
-
const isError = typeof result === 'object' &&
|
|
1527
|
-
result !== null &&
|
|
1528
|
-
'success' in result &&
|
|
1529
|
-
!result.success;
|
|
1530
|
-
runScope.streamCallbacks?.onToolComplete?.(toolName, `code_act_sub_${Date.now()}`, isError);
|
|
1531
|
-
}
|
|
1532
|
-
};
|
|
1533
|
-
bridge.injectInto(sandbox, tier);
|
|
1534
|
-
const result = await sandbox.execute(code);
|
|
1535
|
-
if (result.logs.length > 0) {
|
|
1536
|
-
console.log(`[CodeAct] console output: ${result.logs.join('\n')}`);
|
|
1537
|
-
}
|
|
1538
|
-
return result;
|
|
1539
|
-
}
|
|
1540
|
-
catch (err) {
|
|
1541
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1542
|
-
console.error(`[CodeAct] Sandbox initialization failed: ${message}`);
|
|
1543
|
-
return {
|
|
1544
|
-
success: false,
|
|
1545
|
-
error: {
|
|
1546
|
-
name: 'SandboxError',
|
|
1547
|
-
message: `Failed to initialize Code-Act sandbox: ${message}`,
|
|
1548
|
-
},
|
|
1549
|
-
logs: [],
|
|
1550
|
-
metrics: { durationMs: 0, hostCallCount: 0, memoryUsedBytes: 0 },
|
|
1551
|
-
};
|
|
1552
|
-
}
|
|
1553
|
-
}
|
|
1554
1790
|
/**
|
|
1555
1791
|
* Remove tool_call and code_act blocks from text (to avoid duplication in response)
|
|
1556
1792
|
*/
|
|
@@ -1685,7 +1921,7 @@ class AgentLoop {
|
|
|
1685
1921
|
this.stopped = true;
|
|
1686
1922
|
try {
|
|
1687
1923
|
// Stop the model runner
|
|
1688
|
-
this.agent.stop();
|
|
1924
|
+
await this.agent.stop();
|
|
1689
1925
|
const waitUntil = Date.now() + 5000;
|
|
1690
1926
|
while (this.laneManager.getTotalQueueSize() > 0 && Date.now() < waitUntil) {
|
|
1691
1927
|
await new Promise((resolve) => setTimeout(resolve, 50));
|