@jungjaehoon/mama-os 0.22.1 → 0.24.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/CHANGELOG.md +22 -0
- package/README.md +3 -1
- package/dist/agent/agent-loop.d.ts +3 -9
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +419 -216
- 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 +20 -7
- package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
- package/dist/agent/gateway-tool-executor.js +254 -90
- package/dist/agent/gateway-tool-executor.js.map +1 -1
- package/dist/agent/gateway-tools.md +10 -5
- 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/role-manager.d.ts +22 -1
- package/dist/agent/role-manager.d.ts.map +1 -1
- package/dist/agent/role-manager.js +39 -2
- package/dist/agent/role-manager.js.map +1 -1
- package/dist/agent/session-pool.d.ts +2 -2
- package/dist/agent/session-pool.d.ts.map +1 -1
- package/dist/agent/session-pool.js +6 -6
- 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 +81 -12
- package/dist/agent/tool-registry.js.map +1 -1
- package/dist/agent/types.d.ts +49 -7
- 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 +62 -40
- package/dist/api/graph-api.js.map +1 -1
- package/dist/api/operator-tasks-handler.d.ts.map +1 -1
- package/dist/api/operator-tasks-handler.js +6 -2
- package/dist/api/operator-tasks-handler.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 +2 -0
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +259 -23
- 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 +0 -5
- package/dist/cli/config/config-manager.d.ts.map +1 -1
- package/dist/cli/config/config-manager.js +78 -6
- 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 +36 -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 +106 -60
- package/dist/cli/runtime/agent-loop-init.js.map +1 -1
- package/dist/cli/runtime/api-routes-init.d.ts +3 -0
- package/dist/cli/runtime/api-routes-init.d.ts.map +1 -1
- package/dist/cli/runtime/api-routes-init.js +226 -51
- package/dist/cli/runtime/api-routes-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 +5 -0
- 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 +36 -4
- 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 +19 -1
- package/dist/gateways/message-router.d.ts.map +1 -1
- package/dist/gateways/message-router.js +179 -24
- package/dist/gateways/message-router.js.map +1 -1
- package/dist/gateways/telegram.d.ts.map +1 -1
- package/dist/gateways/telegram.js +13 -0
- package/dist/gateways/telegram.js.map +1 -1
- package/dist/gateways/types.d.ts +4 -1
- package/dist/gateways/types.d.ts.map +1 -1
- package/dist/memory/history-extractor.d.ts +0 -24
- package/dist/memory/history-extractor.d.ts.map +1 -1
- package/dist/memory/history-extractor.js +0 -132
- package/dist/memory/history-extractor.js.map +1 -1
- package/dist/memory/save-candidate-extractor.d.ts +3 -0
- package/dist/memory/save-candidate-extractor.d.ts.map +1 -1
- package/dist/memory/save-candidate-extractor.js +12 -1
- package/dist/memory/save-candidate-extractor.js.map +1 -1
- package/dist/memory/secret-filter.d.ts +22 -0
- package/dist/memory/secret-filter.d.ts.map +1 -0
- package/dist/memory/secret-filter.js +77 -0
- package/dist/memory/secret-filter.js.map +1 -0
- 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/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/observability/code-audit.d.ts +4 -0
- package/dist/observability/code-audit.d.ts.map +1 -1
- package/dist/observability/code-audit.js +69 -0
- package/dist/observability/code-audit.js.map +1 -1
- package/dist/operator/briefs.d.ts +26 -0
- package/dist/operator/briefs.d.ts.map +1 -0
- package/dist/operator/briefs.js +128 -0
- package/dist/operator/briefs.js.map +1 -0
- package/dist/operator/operator-trigger-loop.d.ts +27 -0
- package/dist/operator/operator-trigger-loop.d.ts.map +1 -1
- package/dist/operator/operator-trigger-loop.js +72 -12
- package/dist/operator/operator-trigger-loop.js.map +1 -1
- package/dist/operator/report-carry.d.ts +29 -0
- package/dist/operator/report-carry.d.ts.map +1 -0
- package/dist/operator/report-carry.js +81 -0
- package/dist/operator/report-carry.js.map +1 -0
- package/dist/operator/report-run.d.ts +4 -4
- package/dist/operator/shadow-capture.d.ts +20 -0
- package/dist/operator/shadow-capture.d.ts.map +1 -0
- package/dist/operator/shadow-capture.js +34 -0
- package/dist/operator/shadow-capture.js.map +1 -0
- package/dist/operator/situation-report.d.ts +9 -0
- package/dist/operator/situation-report.d.ts.map +1 -1
- package/dist/operator/situation-report.js +56 -26
- package/dist/operator/situation-report.js.map +1 -1
- package/dist/operator/task-ledger.d.ts +90 -2
- package/dist/operator/task-ledger.d.ts.map +1 -1
- package/dist/operator/task-ledger.js +359 -23
- package/dist/operator/task-ledger.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 +89 -0
- package/dist/operator/worker-run.d.ts.map +1 -0
- package/dist/operator/worker-run.js +127 -0
- package/dist/operator/worker-run.js.map +1 -0
- package/dist/operator/workorder-consumer.d.ts +121 -0
- package/dist/operator/workorder-consumer.d.ts.map +1 -0
- package/dist/operator/workorder-consumer.js +253 -0
- package/dist/operator/workorder-consumer.js.map +1 -0
- package/dist/operator/workorder-hooks.d.ts +30 -0
- package/dist/operator/workorder-hooks.d.ts.map +1 -0
- package/dist/operator/workorder-hooks.js +70 -0
- package/dist/operator/workorder-hooks.js.map +1 -0
- package/dist/operator/workorder-publishers.d.ts +68 -0
- package/dist/operator/workorder-publishers.d.ts.map +1 -0
- package/dist/operator/workorder-publishers.js +150 -0
- package/dist/operator/workorder-publishers.js.map +1 -0
- package/dist/security/security-monitor.d.ts +7 -0
- package/dist/security/security-monitor.d.ts.map +1 -1
- package/dist/security/security-monitor.js +17 -0
- package/dist/security/security-monitor.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 +13 -0
- package/dist/utils/untrusted-content.d.ts.map +1 -1
- package/dist/utils/untrusted-content.js +43 -0
- package/dist/utils/untrusted-content.js.map +1 -1
- package/package.json +2 -2
- 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;
|
|
@@ -86,39 +87,12 @@ const DEFAULT_TOOLS_CONFIG = {
|
|
|
86
87
|
const SOURCE_GLOBAL_LANES = {
|
|
87
88
|
viewer: 'viewer',
|
|
88
89
|
system: 'system',
|
|
90
|
+
// Operator work (scheduled reports, briefed worker runs) serializes among
|
|
91
|
+
// itself but must not block owner chat on 'main': a 260s full report was
|
|
92
|
+
// measurably blocking chat replies before this lane existed. Safe only
|
|
93
|
+
// because per-run state is scoped (RunScope), not instance state.
|
|
94
|
+
operator: 'operator',
|
|
89
95
|
};
|
|
90
|
-
function matchCodeActToolPattern(pattern, toolName) {
|
|
91
|
-
if (pattern === '*') {
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
if (pattern.endsWith('*')) {
|
|
95
|
-
return toolName.startsWith(pattern.slice(0, -1));
|
|
96
|
-
}
|
|
97
|
-
return pattern === toolName;
|
|
98
|
-
}
|
|
99
|
-
function resolveAllowedCodeActTools(allowedTools, blockedTools) {
|
|
100
|
-
if (!allowedTools) {
|
|
101
|
-
if (!blockedTools?.length) {
|
|
102
|
-
return undefined;
|
|
103
|
-
}
|
|
104
|
-
if (blockedTools.includes('*')) {
|
|
105
|
-
return [];
|
|
106
|
-
}
|
|
107
|
-
const registryNames = index_js_1.HostBridge.getToolRegistry().map((meta) => meta.name);
|
|
108
|
-
return registryNames.filter((toolName) => !blockedTools.some((pattern) => matchCodeActToolPattern(pattern, toolName)));
|
|
109
|
-
}
|
|
110
|
-
if (!blockedTools?.length) {
|
|
111
|
-
return [...allowedTools];
|
|
112
|
-
}
|
|
113
|
-
if (blockedTools.includes('*')) {
|
|
114
|
-
return [];
|
|
115
|
-
}
|
|
116
|
-
const registryNames = index_js_1.HostBridge.getToolRegistry().map((meta) => meta.name);
|
|
117
|
-
const expandedAllowed = allowedTools.includes('*')
|
|
118
|
-
? registryNames
|
|
119
|
-
: registryNames.filter((toolName) => allowedTools.some((pattern) => matchCodeActToolPattern(pattern, toolName)));
|
|
120
|
-
return expandedAllowed.filter((toolName) => !blockedTools.some((pattern) => matchCodeActToolPattern(pattern, toolName)));
|
|
121
|
-
}
|
|
122
96
|
/**
|
|
123
97
|
* Load CLAUDE.md system prompt
|
|
124
98
|
* Tries multiple paths: project root, ~/.mama, /etc/mama
|
|
@@ -158,8 +132,79 @@ function loadSystemPrompt(verbose = false) {
|
|
|
158
132
|
*/
|
|
159
133
|
/**
|
|
160
134
|
* Load backend-specific AGENTS.md from ~/.mama/
|
|
161
|
-
* Maps backend to file: 'claude' → AGENTS.claude.md, 'codex
|
|
135
|
+
* Maps backend to file: 'claude' → AGENTS.claude.md, 'codex' → AGENTS.codex.md
|
|
162
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
|
+
}
|
|
163
208
|
function loadBackendAgentsMd(backend, verbose = false) {
|
|
164
209
|
if (!backend) {
|
|
165
210
|
return '';
|
|
@@ -167,7 +212,6 @@ function loadBackendAgentsMd(backend, verbose = false) {
|
|
|
167
212
|
const keyMap = {
|
|
168
213
|
claude: 'claude',
|
|
169
214
|
codex: 'codex',
|
|
170
|
-
'codex-mcp': 'codex',
|
|
171
215
|
};
|
|
172
216
|
const key = keyMap[backend];
|
|
173
217
|
if (!key) {
|
|
@@ -178,7 +222,8 @@ function loadBackendAgentsMd(backend, verbose = false) {
|
|
|
178
222
|
if (verbose) {
|
|
179
223
|
console.log(`[AgentLoop] Loaded backend AGENTS.md: AGENTS.${key}.md`);
|
|
180
224
|
}
|
|
181
|
-
|
|
225
|
+
const content = (0, fs_1.readFileSync)(filePath, 'utf-8');
|
|
226
|
+
return key === 'codex' ? sanitizeLegacyCodexAgentsMd(content) : content;
|
|
182
227
|
}
|
|
183
228
|
if (verbose) {
|
|
184
229
|
console.log(`[AgentLoop] Backend AGENTS.md not found: AGENTS.${key}.md`);
|
|
@@ -273,7 +318,7 @@ function getGatewayToolsPrompt(disallowed) {
|
|
|
273
318
|
}
|
|
274
319
|
if (!disallowed?.length)
|
|
275
320
|
return _gatewayToolsCache;
|
|
276
|
-
const cacheKey = disallowed.sort().join(',');
|
|
321
|
+
const cacheKey = [...disallowed].sort().join(',');
|
|
277
322
|
let filtered = _filteredCache.get(cacheKey);
|
|
278
323
|
if (!filtered) {
|
|
279
324
|
filtered = _gatewayToolsCache;
|
|
@@ -284,6 +329,98 @@ function getGatewayToolsPrompt(disallowed) {
|
|
|
284
329
|
}
|
|
285
330
|
return filtered;
|
|
286
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
|
+
}
|
|
287
424
|
function buildAgentToolExecutionContext(options) {
|
|
288
425
|
if (!options ||
|
|
289
426
|
(options.agentContext === undefined &&
|
|
@@ -292,7 +429,8 @@ function buildAgentToolExecutionContext(options) {
|
|
|
292
429
|
options.envelope === undefined &&
|
|
293
430
|
options.sourceTurnId === undefined &&
|
|
294
431
|
options.sourceMessageRef === undefined &&
|
|
295
|
-
options.modelRunId === undefined
|
|
432
|
+
options.modelRunId === undefined &&
|
|
433
|
+
options.reportPublisherOverride === undefined)) {
|
|
296
434
|
return null;
|
|
297
435
|
}
|
|
298
436
|
const agentContext = options.agentContext;
|
|
@@ -317,6 +455,9 @@ function buildAgentToolExecutionContext(options) {
|
|
|
317
455
|
if (options.modelRunId !== undefined) {
|
|
318
456
|
context.modelRunId = options.modelRunId;
|
|
319
457
|
}
|
|
458
|
+
if (options.reportPublisherOverride !== undefined) {
|
|
459
|
+
context.reportPublisherOverride = options.reportPublisherOverride;
|
|
460
|
+
}
|
|
320
461
|
return context;
|
|
321
462
|
}
|
|
322
463
|
function withExecutionSurface(executionContext, executionSurface) {
|
|
@@ -353,9 +494,11 @@ class AgentLoop {
|
|
|
353
494
|
postToolHandler;
|
|
354
495
|
stopContinuationHandler;
|
|
355
496
|
preCompactHandler;
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
497
|
+
// Per-run state (stream callbacks, tier) lives in a RunScope threaded through
|
|
498
|
+
// runWithContentInternal -> executeTools, NEVER on the
|
|
499
|
+
// instance: concurrent runs on separate global lanes (operator report/worker
|
|
500
|
+
// overlapping owner chat) would steal each other's callbacks and leak tiers
|
|
501
|
+
// if these were instance fields.
|
|
359
502
|
disallowedTools;
|
|
360
503
|
constructor(_oauthManager, options = {}, _clientOptions, executorOptions) {
|
|
361
504
|
// Initialize tools config (hybrid Gateway/MCP routing)
|
|
@@ -375,9 +518,17 @@ class AgentLoop {
|
|
|
375
518
|
// Hybrid mode: Gateway + MCP both enabled
|
|
376
519
|
const useGatewayMode = gatewayTools.includes('*') || gatewayTools.length > 0;
|
|
377
520
|
const useMCPMode = mcpTools.includes('*') || mcpTools.length > 0;
|
|
378
|
-
this.isGatewayMode = useGatewayMode;
|
|
379
521
|
this.useCodeAct = options.useCodeAct ?? false;
|
|
380
|
-
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
|
+
];
|
|
381
532
|
if (useGatewayMode && useMCPMode) {
|
|
382
533
|
logger.debug('🔀 Hybrid mode: Gateway + MCP tools enabled');
|
|
383
534
|
}
|
|
@@ -448,32 +599,42 @@ class AgentLoop {
|
|
|
448
599
|
];
|
|
449
600
|
}
|
|
450
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
|
+
}
|
|
451
611
|
// Load backend-specific AGENTS.md (e.g., AGENTS.claude.md, AGENTS.codex.md)
|
|
452
612
|
const backendAgentsMd = loadBackendAgentsMd(backend);
|
|
453
613
|
if (backendAgentsMd) {
|
|
454
614
|
promptLayers.push({ name: 'backendAgents', content: backendAgentsMd, priority: 2 });
|
|
455
615
|
}
|
|
456
|
-
if (
|
|
457
|
-
if (this.useCodeAct
|
|
616
|
+
if (this.isGatewayMode) {
|
|
617
|
+
if (this.useCodeAct &&
|
|
618
|
+
roleAllowsOuterCodeAct(options.agentContext?.role, this.disallowedTools)) {
|
|
458
619
|
// Code-Act mode: replace verbose gateway tools markdown with compact .d.ts
|
|
459
|
-
const tierForTypeDefs = options.agentContext?.tier
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
:
|
|
464
|
-
|
|
465
|
-
const typeDefs = index_js_1.TypeDefinitionGenerator.generate(
|
|
466
|
-
const
|
|
467
|
-
const codeActPrompt = (0, index_js_1.getCodeActInstructions)(codeActBackend, allowedGatewayTools) +
|
|
468
|
-
'\n```typescript\n' +
|
|
469
|
-
typeDefs +
|
|
470
|
-
'\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```');
|
|
471
628
|
promptLayers.push({ name: 'codeAct', content: codeActPrompt, priority: 2 });
|
|
472
629
|
}
|
|
473
|
-
else {
|
|
630
|
+
else if (!this.useCodeAct && backend !== 'codex') {
|
|
474
631
|
const gatewayToolsPrompt = getGatewayToolsPrompt(this.disallowedTools);
|
|
475
632
|
if (gatewayToolsPrompt) {
|
|
476
|
-
promptLayers.push({
|
|
633
|
+
promptLayers.push({
|
|
634
|
+
name: 'gatewayTools',
|
|
635
|
+
content: wrapGeneratedPromptSection('gatewayTools', gatewayToolsPrompt),
|
|
636
|
+
priority: 2,
|
|
637
|
+
});
|
|
477
638
|
}
|
|
478
639
|
}
|
|
479
640
|
}
|
|
@@ -497,9 +658,9 @@ class AgentLoop {
|
|
|
497
658
|
this.defaultSystemPrompt = defaultSystemPrompt;
|
|
498
659
|
// Choose backend (default: claude)
|
|
499
660
|
this.backend = backend;
|
|
500
|
-
if (this.backend === 'codex'
|
|
501
|
-
// Codex
|
|
502
|
-
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');
|
|
503
664
|
// Ensure workspace directory exists
|
|
504
665
|
if (!(0, fs_1.existsSync)(workspaceDir)) {
|
|
505
666
|
(0, fs_1.mkdirSync)(workspaceDir, { recursive: true });
|
|
@@ -507,12 +668,18 @@ class AgentLoop {
|
|
|
507
668
|
this.agent = new runtime_process_js_1.CodexRuntimeProcess({
|
|
508
669
|
model: options.model,
|
|
509
670
|
cwd: workspaceDir,
|
|
510
|
-
sandbox: 'workspace-write',
|
|
671
|
+
sandbox: options.codexSandbox ?? 'workspace-write',
|
|
511
672
|
systemPrompt: defaultSystemPrompt,
|
|
673
|
+
command: options.codexCommand,
|
|
512
674
|
requestTimeout: options.timeoutMs,
|
|
513
|
-
|
|
675
|
+
codexHome: options.codexHome,
|
|
676
|
+
isolatedHome: options.codexIsolatedHome,
|
|
677
|
+
registryRoot: options.codexRegistryRoot,
|
|
678
|
+
mcpConfigPath: this.useCodeAct
|
|
679
|
+
? undefined
|
|
680
|
+
: (options.mcpConfigPath ?? (useMCPMode ? mcpConfigPath : undefined)),
|
|
514
681
|
});
|
|
515
|
-
logger.debug('Codex
|
|
682
|
+
logger.debug('Codex app-server backend enabled');
|
|
516
683
|
}
|
|
517
684
|
else {
|
|
518
685
|
// Claude backend: always use PersistentCLI for fast responses (~2-3s vs ~16-30s)
|
|
@@ -529,7 +696,7 @@ class AgentLoop {
|
|
|
529
696
|
// Gateway tools are processed by GatewayToolExecutor (hybrid with MCP)
|
|
530
697
|
useGatewayTools: useGatewayMode,
|
|
531
698
|
// Structurally disallow specific tools (e.g., Bash/Read for restricted agents)
|
|
532
|
-
disallowedTools:
|
|
699
|
+
disallowedTools: this.disallowedTools,
|
|
533
700
|
// Native built-ins cross with text-parsed gateway calls (hallucinated
|
|
534
701
|
// ToolSearch/Agent, native gathering that bypasses report verification).
|
|
535
702
|
// Callers opt in per loop; agent-loop-init locks down the main persona.
|
|
@@ -694,6 +861,7 @@ class AgentLoop {
|
|
|
694
861
|
* Set AgentProcessManager for delegate tool (multi-agent delegation)
|
|
695
862
|
*/
|
|
696
863
|
setAgentProcessManager(pm) {
|
|
864
|
+
pm.setGatewayToolExecutor(this.mcpExecutor);
|
|
697
865
|
this.mcpExecutor.setAgentProcessManager(pm);
|
|
698
866
|
}
|
|
699
867
|
/**
|
|
@@ -771,7 +939,12 @@ class AgentLoop {
|
|
|
771
939
|
if (this.stopped) {
|
|
772
940
|
throw new types_js_1.AgentError('Agent loop is stopping', 'AGENT_STOPPED', undefined, false);
|
|
773
941
|
}
|
|
774
|
-
|
|
942
|
+
const runScope = {
|
|
943
|
+
streamCallbacks: options?.streamCallbacks,
|
|
944
|
+
tier: 1,
|
|
945
|
+
onTurn: options?.onTurn ?? this.onTurn,
|
|
946
|
+
onToolUse: options?.onToolUse ?? this.onToolUse,
|
|
947
|
+
};
|
|
775
948
|
const history = [];
|
|
776
949
|
const totalUsage = { input_tokens: 0, output_tokens: 0 };
|
|
777
950
|
let turn = 0;
|
|
@@ -789,13 +962,14 @@ class AgentLoop {
|
|
|
789
962
|
},
|
|
790
963
|
};
|
|
791
964
|
let toolExecutionContext = this.withBackgroundTaskRegistry(this.buildToolExecutionContext(options), backgroundTasks);
|
|
792
|
-
// Track
|
|
965
|
+
// Track this run's tier for code-act execution and prompt sizing.
|
|
793
966
|
if (options?.agentContext) {
|
|
794
967
|
const rawTier = options.agentContext.tier ?? 1;
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
968
|
+
runScope.tier = this.useCodeAct
|
|
969
|
+
? (0, index_js_1.requireCodeActTier)(rawTier)
|
|
970
|
+
: rawTier === 1 || rawTier === 2 || rawTier === 3
|
|
971
|
+
? rawTier
|
|
972
|
+
: 1;
|
|
799
973
|
}
|
|
800
974
|
// Infinite loop prevention
|
|
801
975
|
let consecutiveToolCalls = 0;
|
|
@@ -812,7 +986,18 @@ class AgentLoop {
|
|
|
812
986
|
// Set session ID on the agent
|
|
813
987
|
// Claude PersistentCLI: process alive → CONTINUE (stdin message), process dead → NEW (spawn with --session-id)
|
|
814
988
|
// Codex: threadId alive → CONTINUE (codex-reply), threadId null → NEW (codex tool)
|
|
815
|
-
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;
|
|
816
1001
|
let resolvedCliSessionId = options?.cliSessionId ?? null;
|
|
817
1002
|
const sessionLabel = (isNew) => {
|
|
818
1003
|
if (isCodex) {
|
|
@@ -835,12 +1020,6 @@ class AgentLoop {
|
|
|
835
1020
|
sessionIsNew = true;
|
|
836
1021
|
ownedSession = true;
|
|
837
1022
|
resolvedCliSessionId = cliSessionId;
|
|
838
|
-
if (isCodex) {
|
|
839
|
-
// Codex MCP manages threadId internally and ignores external session ids
|
|
840
|
-
// (codex-mcp-process.ts:366-369) - the pool reset does NOT reset the codex
|
|
841
|
-
// thread, so the stateless guarantee does not hold there. Loud, not silent.
|
|
842
|
-
console.log('[AgentLoop] freshSession is a pool-level reset only on the codex backend - the codex thread persists (see TODO: codex report thread reset)');
|
|
843
|
-
}
|
|
844
1023
|
console.log(`[AgentLoop] [${isCodex ? 'codex' : 'claude'}] ${channelKey} (FRESH session - stateless lane)`);
|
|
845
1024
|
}
|
|
846
1025
|
else {
|
|
@@ -865,38 +1044,121 @@ class AgentLoop {
|
|
|
865
1044
|
modelRunId: ownedModelRunId,
|
|
866
1045
|
}), backgroundTasks);
|
|
867
1046
|
}
|
|
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;
|
|
868
1127
|
let perCallSystemPrompt;
|
|
869
|
-
if (options?.systemPrompt) {
|
|
870
|
-
|
|
871
|
-
const alreadyHasTools = options.systemPrompt.includes('## Gateway Tools') ||
|
|
872
|
-
options.systemPrompt.includes('# Code Execution') ||
|
|
873
|
-
options.systemPrompt.includes('## Code-Act');
|
|
1128
|
+
if (options?.systemPrompt || (this.isGatewayMode && this.useCodeAct)) {
|
|
1129
|
+
let baseSystemPrompt = options?.systemPrompt ?? this.defaultSystemPrompt;
|
|
874
1130
|
let gatewayToolsPrompt = '';
|
|
875
1131
|
const isResumingSession = options?.resumeSession === true;
|
|
876
|
-
if (this.isGatewayMode &&
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
const
|
|
880
|
-
const
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
'\n```typescript\n' +
|
|
886
|
-
typeDefs +
|
|
887
|
-
'\n```';
|
|
1132
|
+
if (this.isGatewayMode && this.useCodeAct) {
|
|
1133
|
+
baseSystemPrompt = stripTrailingCanonicalCodeActSection(stripGenericGatewayToolsCatalog(baseSystemPrompt));
|
|
1134
|
+
if (outerCodeActAllowed) {
|
|
1135
|
+
const policy = codeActPolicy;
|
|
1136
|
+
const typeDefs = index_js_1.TypeDefinitionGenerator.generate(policy);
|
|
1137
|
+
gatewayToolsPrompt = wrapGeneratedPromptSection('codeAct', (0, index_js_1.getCodeActInstructions)(isCodex ? 'codex' : 'claude', policy.names) +
|
|
1138
|
+
'\n```typescript\n' +
|
|
1139
|
+
typeDefs +
|
|
1140
|
+
'\n```');
|
|
888
1141
|
}
|
|
889
|
-
|
|
890
|
-
|
|
1142
|
+
}
|
|
1143
|
+
else if (this.isGatewayMode && !isCodex) {
|
|
1144
|
+
baseSystemPrompt = stripDisabledCodeActGuidance(baseSystemPrompt);
|
|
1145
|
+
if (!isResumingSession) {
|
|
1146
|
+
// Non-CodeAct callers may already embed the generic gateway catalog.
|
|
1147
|
+
const alreadyHasTools = baseSystemPrompt.includes('# Gateway Tools') ||
|
|
1148
|
+
baseSystemPrompt.includes('# Code Execution') ||
|
|
1149
|
+
baseSystemPrompt.includes('## Code-Act');
|
|
1150
|
+
if (!alreadyHasTools) {
|
|
1151
|
+
gatewayToolsPrompt = wrapGeneratedPromptSection('gatewayTools', getGatewayToolsPrompt(this.disallowedTools));
|
|
1152
|
+
}
|
|
891
1153
|
}
|
|
892
1154
|
}
|
|
893
1155
|
const fullPrompt = gatewayToolsPrompt
|
|
894
|
-
? `${
|
|
895
|
-
:
|
|
1156
|
+
? `${baseSystemPrompt}\n\n---\n\n${gatewayToolsPrompt}`
|
|
1157
|
+
: baseSystemPrompt;
|
|
896
1158
|
// Monitor and enforce prompt size
|
|
897
1159
|
const monitor = new prompt_size_monitor_js_1.PromptSizeMonitor();
|
|
898
1160
|
const runLayers = [
|
|
899
|
-
{ name: 'systemPrompt', content:
|
|
1161
|
+
{ name: 'systemPrompt', content: baseSystemPrompt, priority: 1 },
|
|
900
1162
|
...(gatewayToolsPrompt
|
|
901
1163
|
? [{ name: 'gatewayTools', content: gatewayToolsPrompt, priority: 2 }]
|
|
902
1164
|
: []),
|
|
@@ -911,14 +1173,14 @@ class AgentLoop {
|
|
|
911
1173
|
if (enforceResult.truncatedLayers.length > 0) {
|
|
912
1174
|
console.warn(`[AgentLoop] Truncated layers: ${enforceResult.truncatedLayers.join(', ')}`);
|
|
913
1175
|
}
|
|
914
|
-
const tBase = trimmed.find((l) => l.name === 'systemPrompt')?.content ||
|
|
1176
|
+
const tBase = trimmed.find((l) => l.name === 'systemPrompt')?.content || baseSystemPrompt;
|
|
915
1177
|
const tTools = trimmed.find((l) => l.name === 'gatewayTools')?.content || '';
|
|
916
1178
|
effectivePrompt = tTools ? `${tBase}\n\n---\n\n${tTools}` : tBase;
|
|
917
1179
|
console.log(`[AgentLoop] System prompt truncated: ${fullPrompt.length} → ${effectivePrompt.length} chars`);
|
|
918
1180
|
}
|
|
919
1181
|
perCallSystemPrompt = effectivePrompt;
|
|
920
1182
|
console.log(`[AgentLoop] Prepared systemPrompt for this call: ${effectivePrompt.length} chars ` +
|
|
921
|
-
`(base: ${
|
|
1183
|
+
`(base: ${baseSystemPrompt.length}, tools: ${gatewayToolsPrompt.length})`);
|
|
922
1184
|
}
|
|
923
1185
|
else {
|
|
924
1186
|
perCallSystemPrompt = this.defaultSystemPrompt;
|
|
@@ -955,7 +1217,7 @@ class AgentLoop {
|
|
|
955
1217
|
throw new types_js_1.AgentError(`Emergency stop: Agent loop exceeded emergency maximum turns (${EMERGENCY_MAX_TURNS})`, 'EMERGENCY_MAX_TURNS', undefined, false);
|
|
956
1218
|
}
|
|
957
1219
|
let response;
|
|
958
|
-
const ext =
|
|
1220
|
+
const ext = runScope.streamCallbacks;
|
|
959
1221
|
const callbacks = {
|
|
960
1222
|
onDelta: (text) => {
|
|
961
1223
|
ext?.onDelta?.(text);
|
|
@@ -976,8 +1238,10 @@ class AgentLoop {
|
|
|
976
1238
|
let piResult;
|
|
977
1239
|
// Claude: First turn → --session-id (inject system prompt), subsequent → --resume
|
|
978
1240
|
// Codex: resumeSession only controls threadId reset (false=new thread, true=continue)
|
|
979
|
-
const shouldResume =
|
|
980
|
-
|
|
1241
|
+
const shouldResume = isCodex
|
|
1242
|
+
? turn > 1 || (options?.freshSession === true ? false : (options?.resumeSession ?? true))
|
|
1243
|
+
: !sessionIsNew || turn > 1;
|
|
1244
|
+
// Both Claude PersistentCLI and Codex app-server preserve context - only send new messages
|
|
981
1245
|
const promptText = this.formatLastMessageOnly(history);
|
|
982
1246
|
const promptStart = Date.now();
|
|
983
1247
|
try {
|
|
@@ -985,7 +1249,13 @@ class AgentLoop {
|
|
|
985
1249
|
model: options?.model,
|
|
986
1250
|
resumeSession: shouldResume,
|
|
987
1251
|
systemPrompt: perCallSystemPrompt,
|
|
1252
|
+
sessionKey: channelKey,
|
|
1253
|
+
sessionPolicyFingerprint: effectiveSessionPolicyFingerprint,
|
|
988
1254
|
sessionId: resolvedCliSessionId ?? undefined,
|
|
1255
|
+
// Per-run request timeout (operator worker runs); undefined leaves
|
|
1256
|
+
// the pool's construction-time default untouched (chat).
|
|
1257
|
+
requestTimeout: options?.requestTimeoutMs,
|
|
1258
|
+
hostToolBridge,
|
|
989
1259
|
});
|
|
990
1260
|
// Emit prompt latency metric
|
|
991
1261
|
this.onMetric?.('prompt_latency_ms', Date.now() - promptStart, {
|
|
@@ -1010,7 +1280,7 @@ class AgentLoop {
|
|
|
1010
1280
|
errorMessage.includes('request_too_large') ||
|
|
1011
1281
|
errorMessage.includes('context window') ||
|
|
1012
1282
|
errorMessage.includes('context_length_exceeded');
|
|
1013
|
-
if (isSessionNotFound || isSessionInUse || isPromptTooLong) {
|
|
1283
|
+
if (!isCodex && (isSessionNotFound || isSessionInUse || isPromptTooLong)) {
|
|
1014
1284
|
const reason = isSessionNotFound
|
|
1015
1285
|
? 'not found in CLI'
|
|
1016
1286
|
: isSessionInUse
|
|
@@ -1027,7 +1297,12 @@ class AgentLoop {
|
|
|
1027
1297
|
model: options?.model,
|
|
1028
1298
|
resumeSession: false, // Force new session
|
|
1029
1299
|
systemPrompt: perCallSystemPrompt,
|
|
1300
|
+
sessionKey: channelKey,
|
|
1301
|
+
sessionPolicyFingerprint: effectiveSessionPolicyFingerprint,
|
|
1030
1302
|
sessionId: newSessionId,
|
|
1303
|
+
// Carry the per-run timeout onto the reset session too.
|
|
1304
|
+
requestTimeout: options?.requestTimeoutMs,
|
|
1305
|
+
hostToolBridge,
|
|
1031
1306
|
});
|
|
1032
1307
|
// Prepend reset notice so user knows context was lost
|
|
1033
1308
|
if (isPromptTooLong && piResult.response) {
|
|
@@ -1045,7 +1320,7 @@ class AgentLoop {
|
|
|
1045
1320
|
const contentBlocks = [];
|
|
1046
1321
|
let parsedToolCalls = [];
|
|
1047
1322
|
// Parse tool_call / code_act blocks from text response (Gateway Tools mode ONLY)
|
|
1048
|
-
if (this.isGatewayMode) {
|
|
1323
|
+
if (this.isGatewayMode && !isCodex) {
|
|
1049
1324
|
parsedToolCalls = this.parseToolCallsFromText(piResult.response || '');
|
|
1050
1325
|
// Code-Act: parse ```js blocks only if enabled
|
|
1051
1326
|
if (this.useCodeAct) {
|
|
@@ -1090,11 +1365,8 @@ class AgentLoop {
|
|
|
1090
1365
|
}
|
|
1091
1366
|
console.log(`[AgentLoop] Detected ${toolUseBlocks.length} tool calls from MCP`);
|
|
1092
1367
|
}
|
|
1093
|
-
//
|
|
1094
|
-
|
|
1095
|
-
const hasToolUse = this.isGatewayMode
|
|
1096
|
-
? parsedToolCalls.length > 0
|
|
1097
|
-
: ('hasToolUse' in piResult ? piResult.hasToolUse : false) || false;
|
|
1368
|
+
// Both parsed gateway calls and native/MCP tool blocks share executeTools.
|
|
1369
|
+
const hasToolUse = contentBlocks.some((block) => block.type === 'tool_use');
|
|
1098
1370
|
// eslint-disable-next-line prefer-const
|
|
1099
1371
|
response = {
|
|
1100
1372
|
id: `msg_${Date.now()}`,
|
|
@@ -1126,11 +1398,11 @@ class AgentLoop {
|
|
|
1126
1398
|
}
|
|
1127
1399
|
}
|
|
1128
1400
|
// Track tokens in session pool for auto-reset at 80% context
|
|
1129
|
-
const tokenBackend = this.backend === 'codex'
|
|
1401
|
+
const tokenBackend = this.backend === 'codex' ? 'codex' : 'claude';
|
|
1130
1402
|
const tokenStatus = this.sessionPool.updateTokens(channelKey, response.usage.input_tokens, tokenBackend);
|
|
1131
1403
|
// PreCompact: inject compaction summary when approaching context limit
|
|
1132
|
-
if (tokenStatus.nearThreshold && this.preCompactHandler && !
|
|
1133
|
-
|
|
1404
|
+
if (tokenStatus.nearThreshold && this.preCompactHandler && !runScope.preCompactInjected) {
|
|
1405
|
+
runScope.preCompactInjected = true;
|
|
1134
1406
|
try {
|
|
1135
1407
|
const historyText = history.map((msg) => {
|
|
1136
1408
|
if (typeof msg.content === 'string')
|
|
@@ -1160,7 +1432,7 @@ class AgentLoop {
|
|
|
1160
1432
|
content: response.content,
|
|
1161
1433
|
});
|
|
1162
1434
|
// Notify turn callback
|
|
1163
|
-
|
|
1435
|
+
runScope.onTurn?.({
|
|
1164
1436
|
turn,
|
|
1165
1437
|
role: 'assistant',
|
|
1166
1438
|
content: response.content,
|
|
@@ -1205,14 +1477,14 @@ class AgentLoop {
|
|
|
1205
1477
|
lastToolName = currentToolName;
|
|
1206
1478
|
}
|
|
1207
1479
|
}
|
|
1208
|
-
const toolResults = await this.executeTools(response.content, options?.stopAfterSuccessfulTools ?? [], toolExecutionContext);
|
|
1480
|
+
const toolResults = await this.executeTools(response.content, options?.stopAfterSuccessfulTools ?? [], toolExecutionContext, runScope);
|
|
1209
1481
|
// Add tool results to history
|
|
1210
1482
|
history.push({
|
|
1211
1483
|
role: 'user',
|
|
1212
1484
|
content: toolResults,
|
|
1213
1485
|
});
|
|
1214
1486
|
// Notify turn callback for tool results
|
|
1215
|
-
|
|
1487
|
+
runScope.onTurn?.({
|
|
1216
1488
|
turn,
|
|
1217
1489
|
role: 'user',
|
|
1218
1490
|
content: toolResults,
|
|
@@ -1273,7 +1545,6 @@ class AgentLoop {
|
|
|
1273
1545
|
if (ownedSession) {
|
|
1274
1546
|
this.sessionPool.releaseSession(channelKey);
|
|
1275
1547
|
}
|
|
1276
|
-
this.currentStreamCallbacks = undefined;
|
|
1277
1548
|
}
|
|
1278
1549
|
}
|
|
1279
1550
|
shouldBeginModelRun(options) {
|
|
@@ -1319,7 +1590,7 @@ class AgentLoop {
|
|
|
1319
1590
|
/**
|
|
1320
1591
|
* Execute tools from response content blocks
|
|
1321
1592
|
*/
|
|
1322
|
-
async executeTools(content, stopAfterSuccessfulTools = [], executionContext = null) {
|
|
1593
|
+
async executeTools(content, stopAfterSuccessfulTools = [], executionContext = null, runScope = { tier: 1 }) {
|
|
1323
1594
|
const modelToolContext = withExecutionSurface(executionContext, 'model_tool');
|
|
1324
1595
|
const reactiveInternalContext = withExecutionSurface(executionContext, 'reactive_internal');
|
|
1325
1596
|
const toolUseBlocks = content.filter((block) => block.type === 'tool_use');
|
|
@@ -1327,60 +1598,36 @@ class AgentLoop {
|
|
|
1327
1598
|
for (const toolUse of toolUseBlocks) {
|
|
1328
1599
|
let result;
|
|
1329
1600
|
let isError = false;
|
|
1601
|
+
const executionToolName = toolUse.name === CODE_ACT_MCP_COMPAT_NAME ? index_js_1.CODE_ACT_MARKER : toolUse.name;
|
|
1330
1602
|
// Notify stream: tool execution starting
|
|
1331
|
-
|
|
1603
|
+
runScope.streamCallbacks?.onToolUse?.(executionToolName, toolUse.input);
|
|
1332
1604
|
const toolStart = Date.now();
|
|
1333
1605
|
try {
|
|
1334
|
-
//
|
|
1335
|
-
|
|
1336
|
-
if (
|
|
1337
|
-
|
|
1338
|
-
const code = typeof codeInput?.code === 'string' ? codeInput.code : '';
|
|
1339
|
-
const codeActResult = code
|
|
1340
|
-
? await this.executeCodeAct(code, this.currentTier, modelToolContext)
|
|
1341
|
-
: {
|
|
1342
|
-
success: false,
|
|
1343
|
-
error: {
|
|
1344
|
-
name: 'ValidationError',
|
|
1345
|
-
message: 'Missing or invalid "code" field in code_act input',
|
|
1346
|
-
},
|
|
1347
|
-
logs: [],
|
|
1348
|
-
metrics: { durationMs: 0, hostCallCount: 0, memoryUsedBytes: 0 },
|
|
1349
|
-
};
|
|
1350
|
-
result = JSON.stringify(codeActResult, null, 2);
|
|
1351
|
-
if (!codeActResult.success) {
|
|
1352
|
-
isError = true;
|
|
1353
|
-
}
|
|
1354
|
-
this.onToolUse?.(toolUse.name, toolUse.input, codeActResult);
|
|
1355
|
-
this.currentStreamCallbacks?.onToolComplete?.(toolUse.name, toolUse.id, isError);
|
|
1606
|
+
// PreToolUse: search MAMA for contracts before Write operations
|
|
1607
|
+
let contractContext = '';
|
|
1608
|
+
if (executionToolName === 'Write' && toolUse.input) {
|
|
1609
|
+
contractContext = await this.searchContractsForTool(executionToolName, toolUse.input, reactiveInternalContext);
|
|
1356
1610
|
}
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
const toolFailed = hasSuccess && !toolResult.success;
|
|
1368
|
-
if (toolFailed) {
|
|
1369
|
-
isError = true;
|
|
1370
|
-
}
|
|
1371
|
-
if (contractContext) {
|
|
1372
|
-
result = `${contractContext}\n\n---\n\n${result}`;
|
|
1373
|
-
}
|
|
1374
|
-
// Notify tool use callback
|
|
1375
|
-
this.onToolUse?.(toolUse.name, toolUse.input, toolResult);
|
|
1376
|
-
// PostToolUse: auto-extract contracts (fire-and-forget)
|
|
1377
|
-
this.postToolHandler?.processInBackground(toolUse.name, toolUse.input, toolResult, reactiveInternalContext);
|
|
1378
|
-
// Notify stream: tool completed (check actual status)
|
|
1379
|
-
this.currentStreamCallbacks?.onToolComplete?.(toolUse.name, toolUse.id, isError);
|
|
1611
|
+
const toolResult = await this.mcpExecutor.execute(executionToolName, toolUse.input, modelToolContext ?? undefined);
|
|
1612
|
+
result = JSON.stringify(toolResult, null, 2);
|
|
1613
|
+
// Check if tool execution failed
|
|
1614
|
+
const hasSuccess = 'success' in toolResult;
|
|
1615
|
+
const toolFailed = hasSuccess && !toolResult.success;
|
|
1616
|
+
if (toolFailed) {
|
|
1617
|
+
isError = true;
|
|
1618
|
+
}
|
|
1619
|
+
if (contractContext) {
|
|
1620
|
+
result = `${contractContext}\n\n---\n\n${result}`;
|
|
1380
1621
|
}
|
|
1622
|
+
// Notify tool use callback
|
|
1623
|
+
runScope.onToolUse?.(executionToolName, toolUse.input, toolResult);
|
|
1624
|
+
// PostToolUse: auto-extract contracts (fire-and-forget)
|
|
1625
|
+
this.postToolHandler?.processInBackground(executionToolName, toolUse.input, toolResult, reactiveInternalContext);
|
|
1626
|
+
// Notify stream: tool completed (check actual status)
|
|
1627
|
+
runScope.streamCallbacks?.onToolComplete?.(executionToolName, toolUse.id, isError);
|
|
1381
1628
|
// Emit tool execution metric
|
|
1382
1629
|
this.onMetric?.('tool_duration_ms', Date.now() - toolStart, {
|
|
1383
|
-
tool:
|
|
1630
|
+
tool: executionToolName,
|
|
1384
1631
|
error: String(isError),
|
|
1385
1632
|
});
|
|
1386
1633
|
}
|
|
@@ -1388,13 +1635,13 @@ class AgentLoop {
|
|
|
1388
1635
|
isError = true;
|
|
1389
1636
|
result = error instanceof Error ? error.message : String(error);
|
|
1390
1637
|
// Notify tool use callback with error
|
|
1391
|
-
|
|
1638
|
+
runScope.onToolUse?.(executionToolName, toolUse.input, { error: result });
|
|
1392
1639
|
this.onMetric?.('tool_duration_ms', Date.now() - toolStart, {
|
|
1393
|
-
tool:
|
|
1640
|
+
tool: executionToolName,
|
|
1394
1641
|
error: 'true',
|
|
1395
1642
|
});
|
|
1396
1643
|
// Notify stream: tool completed with error
|
|
1397
|
-
|
|
1644
|
+
runScope.streamCallbacks?.onToolComplete?.(executionToolName, toolUse.id, true);
|
|
1398
1645
|
}
|
|
1399
1646
|
results.push({
|
|
1400
1647
|
type: 'tool_result',
|
|
@@ -1402,7 +1649,7 @@ class AgentLoop {
|
|
|
1402
1649
|
content: result,
|
|
1403
1650
|
is_error: isError,
|
|
1404
1651
|
});
|
|
1405
|
-
if (!isError && stopAfterSuccessfulTools.includes(
|
|
1652
|
+
if (!isError && stopAfterSuccessfulTools.includes(executionToolName)) {
|
|
1406
1653
|
break;
|
|
1407
1654
|
}
|
|
1408
1655
|
}
|
|
@@ -1492,50 +1739,6 @@ class AgentLoop {
|
|
|
1492
1739
|
}
|
|
1493
1740
|
return blocks;
|
|
1494
1741
|
}
|
|
1495
|
-
/**
|
|
1496
|
-
* Execute Code-Act JS code in a sandboxed QuickJS environment
|
|
1497
|
-
*/
|
|
1498
|
-
async executeCodeAct(code, tier = 1, executionContext = null) {
|
|
1499
|
-
try {
|
|
1500
|
-
const sandbox = new index_js_1.CodeActSandbox();
|
|
1501
|
-
const bridgeContext = withExecutionSurface(executionContext, 'code_act');
|
|
1502
|
-
const bridge = new index_js_1.HostBridge(this.mcpExecutor, undefined, bridgeContext);
|
|
1503
|
-
bridge.onToolUse = (toolName, input, result) => {
|
|
1504
|
-
if (result === undefined) {
|
|
1505
|
-
// Tool starting — surface to stream
|
|
1506
|
-
this.currentStreamCallbacks?.onToolUse?.(toolName, input);
|
|
1507
|
-
}
|
|
1508
|
-
if (result !== undefined) {
|
|
1509
|
-
// Tool completed — notify callback
|
|
1510
|
-
this.onToolUse?.(toolName, input, result);
|
|
1511
|
-
const isError = typeof result === 'object' &&
|
|
1512
|
-
result !== null &&
|
|
1513
|
-
'success' in result &&
|
|
1514
|
-
!result.success;
|
|
1515
|
-
this.currentStreamCallbacks?.onToolComplete?.(toolName, `code_act_sub_${Date.now()}`, isError);
|
|
1516
|
-
}
|
|
1517
|
-
};
|
|
1518
|
-
bridge.injectInto(sandbox, tier);
|
|
1519
|
-
const result = await sandbox.execute(code);
|
|
1520
|
-
if (result.logs.length > 0) {
|
|
1521
|
-
console.log(`[CodeAct] console output: ${result.logs.join('\n')}`);
|
|
1522
|
-
}
|
|
1523
|
-
return result;
|
|
1524
|
-
}
|
|
1525
|
-
catch (err) {
|
|
1526
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1527
|
-
console.error(`[CodeAct] Sandbox initialization failed: ${message}`);
|
|
1528
|
-
return {
|
|
1529
|
-
success: false,
|
|
1530
|
-
error: {
|
|
1531
|
-
name: 'SandboxError',
|
|
1532
|
-
message: `Failed to initialize Code-Act sandbox: ${message}`,
|
|
1533
|
-
},
|
|
1534
|
-
logs: [],
|
|
1535
|
-
metrics: { durationMs: 0, hostCallCount: 0, memoryUsedBytes: 0 },
|
|
1536
|
-
};
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
1742
|
/**
|
|
1540
1743
|
* Remove tool_call and code_act blocks from text (to avoid duplication in response)
|
|
1541
1744
|
*/
|
|
@@ -1670,7 +1873,7 @@ class AgentLoop {
|
|
|
1670
1873
|
this.stopped = true;
|
|
1671
1874
|
try {
|
|
1672
1875
|
// Stop the model runner
|
|
1673
|
-
this.agent.stop();
|
|
1876
|
+
await this.agent.stop();
|
|
1674
1877
|
const waitUntil = Date.now() + 5000;
|
|
1675
1878
|
while (this.laneManager.getTotalQueueSize() > 0 && Date.now() < waitUntil) {
|
|
1676
1879
|
await new Promise((resolve) => setTimeout(resolve, 50));
|