@getmarrow/mcp 3.9.56 → 3.9.58
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/README.md +21 -2
- package/dist/cli.js +244 -109
- package/dist/cli.js.map +1 -1
- package/dist/hook-context.d.ts +2 -1
- package/dist/hook-context.d.ts.map +1 -1
- package/dist/hook-context.js +2 -1
- package/dist/hook-context.js.map +1 -1
- package/dist/hook-contract.d.ts +6 -6
- package/dist/hook-contract.js +1 -1
- package/dist/hook-session.d.ts +1 -1
- package/dist/hook.d.ts +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +42 -15
- package/dist/index.js.map +1 -1
- package/dist/redact.js +1 -1
- package/dist/redact.js.map +1 -1
- package/dist/request-reliability.d.ts +27 -0
- package/dist/request-reliability.d.ts.map +1 -0
- package/dist/request-reliability.js +264 -0
- package/dist/request-reliability.js.map +1 -0
- package/dist/runtime-contract.d.ts +5 -0
- package/dist/runtime-contract.d.ts.map +1 -0
- package/dist/runtime-contract.js +107 -0
- package/dist/runtime-contract.js.map +1 -0
- package/package.json +7 -4
- package/scripts/control-path-canary.cjs +306 -0
- package/server.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -17,8 +17,12 @@ const hook_session_1 = require("./hook-session");
|
|
|
17
17
|
const hook_pre_action_1 = require("./hook-pre-action");
|
|
18
18
|
const env_1 = require("./env");
|
|
19
19
|
const lifecycle_spool_1 = require("./lifecycle-spool");
|
|
20
|
+
const guidance_cache_1 = require("./guidance-cache");
|
|
21
|
+
const request_reliability_1 = require("./request-reliability");
|
|
22
|
+
const hook_contract_1 = require("./hook-contract");
|
|
20
23
|
const ping_state_1 = require("./ping-state");
|
|
21
24
|
const redact_1 = require("./redact");
|
|
25
|
+
const runtime_contract_1 = require("./runtime-contract");
|
|
22
26
|
// Parse CLI args
|
|
23
27
|
function parseArgs() {
|
|
24
28
|
const args = process.argv.slice(2);
|
|
@@ -355,9 +359,12 @@ if (process.argv[2] !== 'keys') {
|
|
|
355
359
|
const rawBaseUrl = resolvedEnv.baseUrl || 'https://api.getmarrow.ai';
|
|
356
360
|
const BASE_URL = (0, index_1.validateBaseUrl)(rawBaseUrl);
|
|
357
361
|
const SESSION_ID = resolvedEnv.sessionId || undefined;
|
|
358
|
-
|
|
362
|
+
// One identity must bind headers, bodies, queries, cache, and lifecycle events.
|
|
363
|
+
// resolveMarrowEnv already gives MARROW_FLEET_AGENT_ID precedence over MARROW_AGENT_ID.
|
|
364
|
+
// When no identity is configured, omit it and let the API resolve the key's
|
|
365
|
+
// bound agent instead of inventing a process-local identity that changes on restart.
|
|
366
|
+
const FLEET_AGENT_ID = resolvedEnv.agentId || undefined;
|
|
359
367
|
const AUTO_ENROLL = process.env.MARROW_AUTO_ENROLL !== 'false'; // on by default
|
|
360
|
-
const AGENT_ID = process.env.MARROW_AGENT_ID || `${require('os').hostname()}-${Date.now().toString(36)}`;
|
|
361
368
|
if (!API_KEY) {
|
|
362
369
|
process.stderr.write('Error: MARROW_API_KEY environment variable is required\n');
|
|
363
370
|
process.stderr.write(`${resolvedEnv.exactFix}\n`);
|
|
@@ -389,12 +396,6 @@ if (process.argv[2] !== 'keys') {
|
|
|
389
396
|
process.stderr.write(`[marrow] Warning: failed to refresh orient warnings: ${msg}\n`);
|
|
390
397
|
}
|
|
391
398
|
}
|
|
392
|
-
// Initial orient
|
|
393
|
-
refreshOrientWarnings().then(() => {
|
|
394
|
-
if (cachedOrientWarnings.some((w) => w.failureRate > 0.4)) {
|
|
395
|
-
process.stderr.write(`[marrow] ⚠️ High failure rate detected on startup — call marrow_orient for details before acting\n`);
|
|
396
|
-
}
|
|
397
|
-
});
|
|
398
399
|
// Auto-commit tracking for session close
|
|
399
400
|
let lastDecisionId = null;
|
|
400
401
|
let lastCommitted = false;
|
|
@@ -432,6 +433,35 @@ if (process.argv[2] !== 'keys') {
|
|
|
432
433
|
function error(id, code, message) {
|
|
433
434
|
send({ jsonrpc: '2.0', id, error: { code, message } });
|
|
434
435
|
}
|
|
436
|
+
function toolSuccess(id, value, isError = false) {
|
|
437
|
+
success(id, {
|
|
438
|
+
content: [{ type: 'text', text: JSON.stringify(value, null, 2) }],
|
|
439
|
+
...(isError ? { isError: true } : {}),
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
function toolFailure(toolName, failure) {
|
|
443
|
+
const result = (0, request_reliability_1.structuredRequestFailure)(failure);
|
|
444
|
+
const transient = failure.retryable && !['authentication_required', 'permission_denied'].includes(failure.code);
|
|
445
|
+
const supportsStale = ['marrow_agent_runtime', 'marrow_orient', 'marrow_ask', 'marrow_runtime_status', 'marrow_status'].includes(toolName || '');
|
|
446
|
+
if (transient && supportsStale) {
|
|
447
|
+
let cached = null;
|
|
448
|
+
try {
|
|
449
|
+
cached = (0, guidance_cache_1.readGuidanceCache)({ apiKey: API_KEY, baseUrl: BASE_URL, agentId: FLEET_AGENT_ID });
|
|
450
|
+
}
|
|
451
|
+
catch { /* owner-only cache is best effort */ }
|
|
452
|
+
if (cached) {
|
|
453
|
+
result.stale_brief = cached.context;
|
|
454
|
+
result.stale_ms = cached.stale_ms;
|
|
455
|
+
}
|
|
456
|
+
result.disposition = 'review_required';
|
|
457
|
+
result.allow = false;
|
|
458
|
+
result.stale_can_authorize_high_risk = false;
|
|
459
|
+
result.exact_next_action = cached
|
|
460
|
+
? 'Use this last-known brief for low-risk context only. Obtain a fresh Marrow runtime gate before high-risk work.'
|
|
461
|
+
: 'Retry once after retry_after_ms. Do not perform high-risk work without a fresh Marrow runtime gate.';
|
|
462
|
+
}
|
|
463
|
+
return result;
|
|
464
|
+
}
|
|
435
465
|
// [FIX #9] Runtime validation helper for required string params
|
|
436
466
|
function requireString(args, name) {
|
|
437
467
|
const val = args[name];
|
|
@@ -440,6 +470,51 @@ if (process.argv[2] !== 'keys') {
|
|
|
440
470
|
}
|
|
441
471
|
return val;
|
|
442
472
|
}
|
|
473
|
+
function requireBoolean(args, name) {
|
|
474
|
+
const value = args[name];
|
|
475
|
+
if (typeof value !== 'boolean')
|
|
476
|
+
throw new Error(`"${name}" is required and must be boolean`);
|
|
477
|
+
return value;
|
|
478
|
+
}
|
|
479
|
+
const HIGH_RISK_ACTION = /\b(?:billing|credential|database|delete|deploy|destructive|financial|key|merge|migrat(?:e|ion)|payment|production|publish|release|remove|rollback|secret|security|token|truncate|wipe)\b/i;
|
|
480
|
+
function isHighRiskAction(action, type) {
|
|
481
|
+
return HIGH_RISK_ACTION.test(`${String(type || '')} ${String(action || '')}`);
|
|
482
|
+
}
|
|
483
|
+
function cachedGuidance() {
|
|
484
|
+
try {
|
|
485
|
+
return (0, guidance_cache_1.readGuidanceCache)({ apiKey: API_KEY, baseUrl: BASE_URL, agentId: FLEET_AGENT_ID });
|
|
486
|
+
}
|
|
487
|
+
catch {
|
|
488
|
+
return null;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
async function withControlDeadline(operation, options = {}) {
|
|
492
|
+
const hasCache = options.cacheAware !== false && Boolean(cachedGuidance());
|
|
493
|
+
const configuredCanaryMs = Number(process.env.MARROW_REQUEST_TIMEOUT_MS);
|
|
494
|
+
const timeoutMs = process.env.MARROW_CONTROL_PATH_CANARY === '1' && Number.isFinite(configuredCanaryMs)
|
|
495
|
+
? Math.min(5_000, Math.max(500, Math.floor(configuredCanaryMs)))
|
|
496
|
+
: options.highRisk ? 2_000 : hasCache ? 400 : 1_200;
|
|
497
|
+
const controller = new AbortController();
|
|
498
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
499
|
+
timer.unref?.();
|
|
500
|
+
try {
|
|
501
|
+
return await operation(controller.signal);
|
|
502
|
+
}
|
|
503
|
+
finally {
|
|
504
|
+
clearTimeout(timer);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function storeRuntimeGuidance(runtime) {
|
|
508
|
+
try {
|
|
509
|
+
(0, guidance_cache_1.writeGuidanceCache)({
|
|
510
|
+
apiKey: API_KEY,
|
|
511
|
+
baseUrl: BASE_URL,
|
|
512
|
+
agentId: FLEET_AGENT_ID,
|
|
513
|
+
context: (0, hook_context_1.compactRuntimeContext)(runtime),
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
catch { /* owner-only cache is best effort */ }
|
|
517
|
+
}
|
|
443
518
|
// [FIX #6 & #7] Safe JSON response helper for memory API functions
|
|
444
519
|
async function safeMemoryResponse(res) {
|
|
445
520
|
if (!res.ok) {
|
|
@@ -726,8 +801,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
726
801
|
},
|
|
727
802
|
{
|
|
728
803
|
name: 'marrow_run',
|
|
729
|
-
description: '
|
|
730
|
-
'Use this instead of chaining marrow_think + marrow_commit when you want Marrow to just work without managing the loop yourself.',
|
|
804
|
+
description: 'One-call governed outcome capture. Records intent, obtains a gate for risky work, and closes only with an explicit measured result.',
|
|
731
805
|
inputSchema: {
|
|
732
806
|
type: 'object',
|
|
733
807
|
properties: {
|
|
@@ -739,27 +813,28 @@ if (process.argv[2] !== 'keys') {
|
|
|
739
813
|
enum: ['implementation', 'security', 'architecture', 'process', 'general'],
|
|
740
814
|
description: 'Type of action (default: general)',
|
|
741
815
|
},
|
|
816
|
+
proof: { type: 'object', description: 'Measured evidence required to close high-risk work.' },
|
|
817
|
+
gate_receipt_id: { type: 'string', description: 'Fresh receipt returned by marrow_agent_runtime.' },
|
|
742
818
|
},
|
|
743
819
|
required: ['description', 'success', 'outcome'],
|
|
744
820
|
},
|
|
745
821
|
},
|
|
746
822
|
{
|
|
747
823
|
name: 'marrow_auto',
|
|
748
|
-
description: '
|
|
749
|
-
'Pass what you are about to do. Optionally pass outcome if already done. ' +
|
|
750
|
-
'Use for ANY action: deploys, file writes, API calls, external sends. ' +
|
|
751
|
-
'If you only have time for one call: pass action + outcome + success together — done in one shot.',
|
|
824
|
+
description: 'Durably capture low-risk activity without blocking. Outcomes remain pending unless success is explicit; risky completion still requires a fresh gate and measured proof.',
|
|
752
825
|
inputSchema: {
|
|
753
826
|
type: 'object',
|
|
754
827
|
properties: {
|
|
755
828
|
action: { type: 'string', description: 'What you are about to do or just did' },
|
|
756
829
|
outcome: { type: 'string', description: 'What happened (if already done). Omit to log intent only.' },
|
|
757
|
-
success: { type: 'boolean', description: '
|
|
830
|
+
success: { type: 'boolean', description: 'Measured result. Omit when the outcome is not yet proven.' },
|
|
758
831
|
type: {
|
|
759
832
|
type: 'string',
|
|
760
833
|
enum: ['implementation', 'security', 'architecture', 'process', 'general'],
|
|
761
834
|
description: 'Type of action (default: general)',
|
|
762
835
|
},
|
|
836
|
+
proof: { type: 'object', description: 'Measured completion evidence for gated work.' },
|
|
837
|
+
gate_receipt_id: { type: 'string', description: 'Fresh receipt returned by marrow_agent_runtime.' },
|
|
763
838
|
},
|
|
764
839
|
required: ['action'],
|
|
765
840
|
},
|
|
@@ -1022,7 +1097,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1022
1097
|
type: 'object',
|
|
1023
1098
|
properties: {
|
|
1024
1099
|
period: { type: 'string', description: 'Time period: 7d (default), 14d, or 30d' },
|
|
1025
|
-
agentId: { type: 'string', description: 'Optional agent_id/session_id filter. Defaults to
|
|
1100
|
+
agentId: { type: 'string', description: 'Optional agent_id/session_id filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1026
1101
|
},
|
|
1027
1102
|
required: [],
|
|
1028
1103
|
},
|
|
@@ -1047,7 +1122,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1047
1122
|
type: 'object',
|
|
1048
1123
|
properties: {
|
|
1049
1124
|
period: { type: 'string', description: 'Time period: 7d (default), 14d, 30d, or a day count up to 90.' },
|
|
1050
|
-
agentId: { type: 'string', description: 'Optional agent_id/session_id filter. Defaults to
|
|
1125
|
+
agentId: { type: 'string', description: 'Optional agent_id/session_id filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1051
1126
|
},
|
|
1052
1127
|
required: [],
|
|
1053
1128
|
},
|
|
@@ -1063,7 +1138,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1063
1138
|
action: { type: 'string', description: 'What the agent is about to do.' },
|
|
1064
1139
|
type: { type: 'string', description: 'Decision type, e.g. deploy, audit, patch, review.' },
|
|
1065
1140
|
role: { type: 'string', description: 'Agent role/playbook: deploy, audit, patch, review, or general.' },
|
|
1066
|
-
agentId: { type: 'string', description: 'Optional agent_id filter. Defaults to
|
|
1141
|
+
agentId: { type: 'string', description: 'Optional agent_id filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1067
1142
|
sessionId: { type: 'string', description: 'Optional session id. Defaults to MARROW_SESSION_ID.' },
|
|
1068
1143
|
surfaces: {
|
|
1069
1144
|
type: 'array',
|
|
@@ -1085,7 +1160,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1085
1160
|
action: { type: 'string', description: 'Optional action to test. Defaults to a production deploy safety prompt.' },
|
|
1086
1161
|
type: { type: 'string', description: 'Decision type, e.g. deploy, audit, patch, review.' },
|
|
1087
1162
|
role: { type: 'string', description: 'Agent role/playbook: deploy, audit, patch, review, or general.' },
|
|
1088
|
-
agentId: { type: 'string', description: 'Optional agent_id filter. Defaults to
|
|
1163
|
+
agentId: { type: 'string', description: 'Optional agent_id filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1089
1164
|
sessionId: { type: 'string', description: 'Optional session id. Defaults to MARROW_SESSION_ID.' },
|
|
1090
1165
|
surfaces: { type: 'array', items: { type: 'string' }, description: 'Surfaces to test, e.g. production, deploy, github, npm.' },
|
|
1091
1166
|
context: { type: 'object', description: 'Optional non-sensitive metadata.' },
|
|
@@ -1105,7 +1180,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1105
1180
|
action: { type: 'string', description: 'What the agent is about to do.' },
|
|
1106
1181
|
type: { type: 'string', description: 'Decision type, e.g. deploy, audit, patch, review.' },
|
|
1107
1182
|
role: { type: 'string', description: 'Agent role/playbook: deploy, audit, patch, review, or general.' },
|
|
1108
|
-
agentId: { type: 'string', description: 'Optional agent_id filter. Defaults to
|
|
1183
|
+
agentId: { type: 'string', description: 'Optional agent_id filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1109
1184
|
sessionId: { type: 'string', description: 'Optional session id. Defaults to MARROW_SESSION_ID.' },
|
|
1110
1185
|
surfaces: {
|
|
1111
1186
|
type: 'array',
|
|
@@ -1165,7 +1240,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1165
1240
|
},
|
|
1166
1241
|
action: { type: 'string', description: 'Optional runtime action label.' },
|
|
1167
1242
|
type: { type: 'string', description: 'Optional runtime action type. Defaults to coordination.' },
|
|
1168
|
-
agentId: { type: 'string', description: 'Requesting agent id. Defaults to
|
|
1243
|
+
agentId: { type: 'string', description: 'Requesting agent id. Defaults to the canonical fleet-bound agent identity.' },
|
|
1169
1244
|
sessionId: { type: 'string', description: 'Optional workflow session id.' },
|
|
1170
1245
|
surfaces: { type: 'array', items: { type: 'string' } },
|
|
1171
1246
|
context: { type: 'object', description: 'Optional non-sensitive runtime metadata.' },
|
|
@@ -1278,7 +1353,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1278
1353
|
inputSchema: {
|
|
1279
1354
|
type: 'object',
|
|
1280
1355
|
properties: {
|
|
1281
|
-
agentId: { type: 'string', description: 'Optional agent filter. Defaults to
|
|
1356
|
+
agentId: { type: 'string', description: 'Optional agent filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1282
1357
|
limit: { type: 'number', description: 'Max events to return, default 25, max 100.' },
|
|
1283
1358
|
},
|
|
1284
1359
|
required: [],
|
|
@@ -1301,7 +1376,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1301
1376
|
inputSchema: {
|
|
1302
1377
|
type: 'object',
|
|
1303
1378
|
properties: {
|
|
1304
|
-
agentId: { type: 'string', description: 'Optional agent filter. Defaults to
|
|
1379
|
+
agentId: { type: 'string', description: 'Optional agent filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1305
1380
|
periodDays: { type: 'number', description: 'Lookback period in days, default 30, max 90.' },
|
|
1306
1381
|
},
|
|
1307
1382
|
required: [],
|
|
@@ -1390,7 +1465,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1390
1465
|
type: 'object',
|
|
1391
1466
|
properties: {
|
|
1392
1467
|
period: { type: 'string', description: 'Time period: 7d (default), 14d, 30d, or day count up to 90.' },
|
|
1393
|
-
agentId: { type: 'string', description: 'Optional agent_id/session_id filter. Defaults to
|
|
1468
|
+
agentId: { type: 'string', description: 'Optional agent_id/session_id filter. Defaults to the canonical fleet-bound agent identity.' },
|
|
1394
1469
|
},
|
|
1395
1470
|
required: [],
|
|
1396
1471
|
},
|
|
@@ -1523,6 +1598,24 @@ if (process.argv[2] !== 'keys') {
|
|
|
1523
1598
|
},
|
|
1524
1599
|
},
|
|
1525
1600
|
];
|
|
1601
|
+
const CORE_TOOL_NAMES = new Set([
|
|
1602
|
+
'marrow_agent_runtime',
|
|
1603
|
+
'marrow_commit',
|
|
1604
|
+
'marrow_ask',
|
|
1605
|
+
'marrow_status',
|
|
1606
|
+
'marrow_auto',
|
|
1607
|
+
'marrow_handoff_status',
|
|
1608
|
+
]);
|
|
1609
|
+
function advertisedTools() {
|
|
1610
|
+
return process.env.MARROW_TOOL_PROFILE === 'full'
|
|
1611
|
+
? TOOLS
|
|
1612
|
+
: TOOLS.filter((tool) => CORE_TOOL_NAMES.has(tool.name));
|
|
1613
|
+
}
|
|
1614
|
+
function toolAllowedByActiveProfile(toolName) {
|
|
1615
|
+
return process.env.MARROW_TOOL_PROFILE === 'full'
|
|
1616
|
+
? Boolean(toolName && TOOLS.some((tool) => tool.name === toolName))
|
|
1617
|
+
: Boolean(toolName && CORE_TOOL_NAMES.has(toolName));
|
|
1618
|
+
}
|
|
1526
1619
|
// Request handler
|
|
1527
1620
|
async function handleRequest(req) {
|
|
1528
1621
|
const { id, method, params } = req;
|
|
@@ -1537,7 +1630,7 @@ if (process.argv[2] !== 'keys') {
|
|
|
1537
1630
|
success(id, {
|
|
1538
1631
|
protocolVersion: '2024-11-05',
|
|
1539
1632
|
capabilities: { tools: {}, prompts: {} },
|
|
1540
|
-
serverInfo: { name: 'marrow', version:
|
|
1633
|
+
serverInfo: { name: 'marrow', version: hook_contract_1.MCP_ADAPTER_VERSION },
|
|
1541
1634
|
});
|
|
1542
1635
|
// Auto-enroll: emit enrollment notification on connection
|
|
1543
1636
|
if (AUTO_ENROLL) {
|
|
@@ -1550,7 +1643,8 @@ if (process.argv[2] !== 'keys') {
|
|
|
1550
1643
|
data: {
|
|
1551
1644
|
type: 'auto_enroll',
|
|
1552
1645
|
message: 'Marrow auto-enroll active. Call marrow_orient FIRST, then marrow_think before acting, marrow_commit after. Or use marrow_auto / marrow_run for one-call logging.',
|
|
1553
|
-
agentId:
|
|
1646
|
+
agentId: FLEET_AGENT_ID,
|
|
1647
|
+
client_update: (0, request_reliability_1.localClientUpdate)(),
|
|
1554
1648
|
},
|
|
1555
1649
|
},
|
|
1556
1650
|
});
|
|
@@ -1623,29 +1717,21 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1623
1717
|
return;
|
|
1624
1718
|
}
|
|
1625
1719
|
if (method === 'tools/list') {
|
|
1626
|
-
success(id, { tools:
|
|
1720
|
+
success(id, { tools: advertisedTools() });
|
|
1627
1721
|
return;
|
|
1628
1722
|
}
|
|
1629
1723
|
if (method === 'tools/call') {
|
|
1630
1724
|
const toolName = params?.name;
|
|
1631
1725
|
const args = (params?.arguments || {});
|
|
1726
|
+
if (!toolAllowedByActiveProfile(toolName)) {
|
|
1727
|
+
error(id, -32601, 'Tool is not available in the active Marrow tool profile. Set MARROW_TOOL_PROFILE=full and restart MCP for advanced operator tools.');
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1632
1730
|
if (toolName === 'marrow_orient') {
|
|
1633
1731
|
orientCallCount++;
|
|
1634
|
-
let result;
|
|
1635
1732
|
const wantAutoWarn = args.autoWarn ?? true;
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
}
|
|
1639
|
-
catch (e) {
|
|
1640
|
-
// autoWarn endpoint may not be deployed yet — fall back to legacy orient
|
|
1641
|
-
if (wantAutoWarn) {
|
|
1642
|
-
process.stderr.write(`[marrow] autoWarn orient not available, falling back to legacy\n`);
|
|
1643
|
-
result = await (0, index_1.marrowOrient)(API_KEY, BASE_URL, { taskType: args.taskType, autoWarn: false }, SESSION_ID, FLEET_AGENT_ID);
|
|
1644
|
-
}
|
|
1645
|
-
else {
|
|
1646
|
-
throw e;
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1733
|
+
const taskType = args.taskType;
|
|
1734
|
+
const result = await withControlDeadline((signal) => (0, index_1.marrowOrient)(API_KEY, BASE_URL, { taskType, autoWarn: wantAutoWarn }, SESSION_ID, FLEET_AGENT_ID, signal), { highRisk: isHighRiskAction(`Orient before ${taskType || 'general'} work`, taskType) });
|
|
1649
1735
|
if (AUTO_ENROLL && orientCallCount === 1) {
|
|
1650
1736
|
const enrollmentText = `\n\n**Marrow control and proof active**\n\n` +
|
|
1651
1737
|
`Marrow applies relevant policy and prior lessons before consequential actions, then records evidence and the real outcome afterward.\n\n` +
|
|
@@ -1749,6 +1835,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1749
1835
|
// [FIX #9] Validate required params
|
|
1750
1836
|
const description = requireString(args, 'description');
|
|
1751
1837
|
const outcome = requireString(args, 'outcome');
|
|
1838
|
+
const measuredSuccess = requireBoolean(args, 'success');
|
|
1752
1839
|
// [FIX #16] Handle partial failures — return think result even if commit fails
|
|
1753
1840
|
let thinkResult = null;
|
|
1754
1841
|
try {
|
|
@@ -1766,18 +1853,12 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1766
1853
|
try {
|
|
1767
1854
|
commitResult = await (0, index_1.marrowCommit)(API_KEY, BASE_URL, {
|
|
1768
1855
|
decision_id: thinkResult.decision_id,
|
|
1769
|
-
success:
|
|
1856
|
+
success: measuredSuccess,
|
|
1770
1857
|
outcome,
|
|
1771
|
-
proof:
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
blockers: (args.success ?? true) ? 'none' : 'see outcome',
|
|
1776
|
-
commits_prs_shas: 'not applicable',
|
|
1777
|
-
rollback_target: 'not applicable',
|
|
1778
|
-
handoff_result_file: 'not applicable',
|
|
1779
|
-
deployment_and_smoke: 'not applicable',
|
|
1780
|
-
},
|
|
1858
|
+
proof: args.proof && typeof args.proof === 'object' && !Array.isArray(args.proof)
|
|
1859
|
+
? (0, redact_1.redactSensitiveValue)(args.proof)
|
|
1860
|
+
: undefined,
|
|
1861
|
+
gate_receipt_id: typeof args.gate_receipt_id === 'string' ? args.gate_receipt_id : undefined,
|
|
1781
1862
|
action: description,
|
|
1782
1863
|
type: args.type || 'general',
|
|
1783
1864
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
@@ -1807,50 +1888,90 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1807
1888
|
return;
|
|
1808
1889
|
}
|
|
1809
1890
|
if (toolName === 'marrow_auto') {
|
|
1810
|
-
// [FIX #9] Validate required param
|
|
1811
1891
|
const action = requireString(args, 'action');
|
|
1812
1892
|
const outcome = args.outcome;
|
|
1813
|
-
const outcomeSuccess = args.success
|
|
1893
|
+
const outcomeSuccess = typeof args.success === 'boolean' ? args.success : undefined;
|
|
1814
1894
|
const type = args.type || 'general';
|
|
1815
|
-
|
|
1895
|
+
const highRisk = isHighRiskAction(action, type);
|
|
1896
|
+
const suppliedProof = args.proof && typeof args.proof === 'object' && !Array.isArray(args.proof)
|
|
1897
|
+
? (0, redact_1.redactSensitiveValue)(args.proof)
|
|
1898
|
+
: undefined;
|
|
1899
|
+
let runtimeGate = null;
|
|
1900
|
+
if (highRisk) {
|
|
1901
|
+
runtimeGate = await withControlDeadline((signal) => (0, index_1.marrowAgentRuntime)(API_KEY, BASE_URL, {
|
|
1902
|
+
action: (0, redact_1.redactSensitiveText)(action),
|
|
1903
|
+
type,
|
|
1904
|
+
agent_id: FLEET_AGENT_ID,
|
|
1905
|
+
session_id: SESSION_ID,
|
|
1906
|
+
proof: suppliedProof,
|
|
1907
|
+
context: { source: 'mcp_auto_risk_upgrade' },
|
|
1908
|
+
}, SESSION_ID, FLEET_AGENT_ID, signal), { highRisk: true });
|
|
1909
|
+
storeRuntimeGuidance(runtimeGate);
|
|
1910
|
+
}
|
|
1911
|
+
const proofCanClose = !highRisk || (0, runtime_contract_1.highRiskRuntimeCanClose)(runtimeGate, suppliedProof, args.gate_receipt_id);
|
|
1912
|
+
const acceptedSuccess = proofCanClose ? outcomeSuccess : undefined;
|
|
1913
|
+
const receipt = await (0, lifecycle_spool_1.recordLifecycleEvent)({
|
|
1914
|
+
apiKey: API_KEY,
|
|
1915
|
+
baseUrl: BASE_URL,
|
|
1916
|
+
deferDelivery: true,
|
|
1917
|
+
event: {
|
|
1918
|
+
event_type: !highRisk && acceptedSuccess === false ? 'tool_failed' : !highRisk && acceptedSuccess === true ? 'tool_completed' : 'goal_started',
|
|
1919
|
+
harness: process.env.MARROW_CLIENT || process.env.MARROW_HARNESS || 'mcp',
|
|
1920
|
+
agent_id: FLEET_AGENT_ID,
|
|
1921
|
+
session_id: SESSION_ID,
|
|
1922
|
+
action,
|
|
1923
|
+
outcome_state: 'pending',
|
|
1924
|
+
success: highRisk ? undefined : acceptedSuccess,
|
|
1925
|
+
adapter_version: hook_contract_1.MCP_ADAPTER_VERSION,
|
|
1926
|
+
capability_level: 'mcp',
|
|
1927
|
+
},
|
|
1928
|
+
});
|
|
1816
1929
|
const response = {
|
|
1817
1930
|
action,
|
|
1818
1931
|
outcome: outcome || 'pending',
|
|
1819
1932
|
warnings: cachedOrientWarnings.map(formatWarningActionably),
|
|
1820
|
-
logging: '
|
|
1933
|
+
logging: 'durably_queued',
|
|
1934
|
+
receipt,
|
|
1935
|
+
completion_state: outcomeSuccess === undefined ? 'pending_evidence' : 'delivery_pending',
|
|
1936
|
+
client_update: (0, request_reliability_1.localClientUpdate)(),
|
|
1937
|
+
...(runtimeGate ? {
|
|
1938
|
+
runtime_gate: runtimeGate,
|
|
1939
|
+
completion_state: proofCanClose ? 'governed_delivery_pending' : 'pending_required_proof',
|
|
1940
|
+
} : {}),
|
|
1821
1941
|
};
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
handoff_result_file: 'not applicable',
|
|
1842
|
-
deployment_and_smoke: 'not applicable',
|
|
1843
|
-
},
|
|
1844
|
-
action,
|
|
1845
|
-
type,
|
|
1846
|
-
}, SESSION_ID, FLEET_AGENT_ID);
|
|
1847
|
-
}
|
|
1848
|
-
}
|
|
1849
|
-
catch (err) {
|
|
1850
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1851
|
-
process.stderr.write(`[marrow] marrow_auto background logging failed: ${msg}\n`);
|
|
1942
|
+
const delivery = () => (0, index_1.marrowAuto)(API_KEY, BASE_URL, {
|
|
1943
|
+
action,
|
|
1944
|
+
outcome,
|
|
1945
|
+
success: acceptedSuccess,
|
|
1946
|
+
type,
|
|
1947
|
+
proof: suppliedProof,
|
|
1948
|
+
gate_receipt_id: typeof args.gate_receipt_id === 'string'
|
|
1949
|
+
? args.gate_receipt_id
|
|
1950
|
+
: runtimeGate?.gate_receipt?.id,
|
|
1951
|
+
}, SESSION_ID, FLEET_AGENT_ID, 1_500);
|
|
1952
|
+
if (highRisk && acceptedSuccess !== undefined) {
|
|
1953
|
+
const delivered = await delivery();
|
|
1954
|
+
if (!delivered.committed) {
|
|
1955
|
+
throw new request_reliability_1.MarrowRequestError({
|
|
1956
|
+
code: 'invalid_response',
|
|
1957
|
+
message: 'Marrow did not confirm the governed outcome commit',
|
|
1958
|
+
retryable: true,
|
|
1959
|
+
exactFix: 'Keep the outcome pending and retry marrow_commit with the fresh gate receipt and required proof.',
|
|
1960
|
+
});
|
|
1852
1961
|
}
|
|
1853
|
-
|
|
1962
|
+
response.logging = 'governed_commit_confirmed';
|
|
1963
|
+
response.completion_state = 'closed_with_proof';
|
|
1964
|
+
response.decision_id = delivered.decision_id;
|
|
1965
|
+
}
|
|
1966
|
+
else if (!highRisk) {
|
|
1967
|
+
void delivery().catch((err) => {
|
|
1968
|
+
const failure = (0, request_reliability_1.structuredRequestFailure)(err);
|
|
1969
|
+
const errorCode = failure.error && typeof failure.error === 'object'
|
|
1970
|
+
? String(failure.error.code || 'request_failed')
|
|
1971
|
+
: 'request_failed';
|
|
1972
|
+
process.stderr.write(`[marrow] marrow_auto queued; live delivery unavailable (${errorCode})\n`);
|
|
1973
|
+
});
|
|
1974
|
+
}
|
|
1854
1975
|
success(id, {
|
|
1855
1976
|
content: [{ type: 'text', text: JSON.stringify(response, null, 2) }],
|
|
1856
1977
|
});
|
|
@@ -1858,17 +1979,25 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
1858
1979
|
}
|
|
1859
1980
|
if (toolName === 'marrow_ask') {
|
|
1860
1981
|
const query = requireString(args, 'query');
|
|
1861
|
-
const result = await (0, index_1.marrowAsk)(API_KEY, BASE_URL, { query }, SESSION_ID, FLEET_AGENT_ID);
|
|
1982
|
+
const result = await withControlDeadline((signal) => (0, index_1.marrowAsk)(API_KEY, BASE_URL, { query }, SESSION_ID, FLEET_AGENT_ID, signal));
|
|
1983
|
+
try {
|
|
1984
|
+
(0, guidance_cache_1.writeGuidanceCache)({
|
|
1985
|
+
apiKey: API_KEY,
|
|
1986
|
+
baseUrl: BASE_URL,
|
|
1987
|
+
agentId: FLEET_AGENT_ID,
|
|
1988
|
+
context: `## Marrow answer\n- ${String(result.answer || 'No relevant lesson found.').slice(0, 1200)}`,
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
catch { /* owner-only cache is best effort */ }
|
|
1862
1992
|
success(id, {
|
|
1863
1993
|
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
1864
1994
|
});
|
|
1865
1995
|
return;
|
|
1866
1996
|
}
|
|
1867
1997
|
if (toolName === 'marrow_status') {
|
|
1868
|
-
const result = await (0, index_1.marrowStatus)(API_KEY, BASE_URL, SESSION_ID, FLEET_AGENT_ID);
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
});
|
|
1998
|
+
const result = await withControlDeadline((signal) => (0, index_1.marrowStatus)(API_KEY, BASE_URL, SESSION_ID, FLEET_AGENT_ID, signal), { cacheAware: false });
|
|
1999
|
+
const statusRecord = result;
|
|
2000
|
+
toolSuccess(id, { ...statusRecord, client_update: statusRecord.client_update || (0, request_reliability_1.localClientUpdate)() });
|
|
1872
2001
|
return;
|
|
1873
2002
|
}
|
|
1874
2003
|
if (toolName === 'marrow_create_key') {
|
|
@@ -2001,17 +2130,17 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2001
2130
|
return;
|
|
2002
2131
|
}
|
|
2003
2132
|
if (toolName === 'marrow_agent_status') {
|
|
2004
|
-
const result = await (0, index_1.marrowAgentStatus)(API_KEY, BASE_URL, args.period || '7d', args.agentId ||
|
|
2133
|
+
const result = await (0, index_1.marrowAgentStatus)(API_KEY, BASE_URL, args.period || '7d', args.agentId || FLEET_AGENT_ID, SESSION_ID, FLEET_AGENT_ID);
|
|
2005
2134
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
2006
2135
|
return;
|
|
2007
2136
|
}
|
|
2008
2137
|
if (toolName === 'marrow_runtime_status') {
|
|
2009
|
-
const result = await (0, index_1.marrowRuntimeStatus)(API_KEY, BASE_URL, args.fast !== false, SESSION_ID, FLEET_AGENT_ID);
|
|
2138
|
+
const result = await withControlDeadline((signal) => (0, index_1.marrowRuntimeStatus)(API_KEY, BASE_URL, args.fast !== false, SESSION_ID, FLEET_AGENT_ID, signal), { cacheAware: false });
|
|
2010
2139
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
2011
2140
|
return;
|
|
2012
2141
|
}
|
|
2013
2142
|
if (toolName === 'marrow_value_report') {
|
|
2014
|
-
const result = await (0, index_1.marrowValueReport)(API_KEY, BASE_URL, args.period || '7d', args.agentId ||
|
|
2143
|
+
const result = await (0, index_1.marrowValueReport)(API_KEY, BASE_URL, args.period || '7d', args.agentId || FLEET_AGENT_ID, SESSION_ID, FLEET_AGENT_ID);
|
|
2015
2144
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
2016
2145
|
return;
|
|
2017
2146
|
}
|
|
@@ -2020,7 +2149,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2020
2149
|
action: args.action,
|
|
2021
2150
|
type: args.type,
|
|
2022
2151
|
role: args.role,
|
|
2023
|
-
agent_id: args.agentId ||
|
|
2152
|
+
agent_id: args.agentId || FLEET_AGENT_ID,
|
|
2024
2153
|
session_id: args.sessionId || SESSION_ID,
|
|
2025
2154
|
surfaces: Array.isArray(args.surfaces) ? args.surfaces : undefined,
|
|
2026
2155
|
period: args.period,
|
|
@@ -2033,7 +2162,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2033
2162
|
action: args.action ? (0, redact_1.redactSensitiveText)(args.action) : undefined,
|
|
2034
2163
|
type: args.type,
|
|
2035
2164
|
role: args.role,
|
|
2036
|
-
agent_id: args.agentId ||
|
|
2165
|
+
agent_id: args.agentId || FLEET_AGENT_ID,
|
|
2037
2166
|
session_id: args.sessionId || SESSION_ID,
|
|
2038
2167
|
surfaces: Array.isArray(args.surfaces) ? args.surfaces : undefined,
|
|
2039
2168
|
context: args.context && typeof args.context === 'object' && !Array.isArray(args.context)
|
|
@@ -2047,11 +2176,11 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2047
2176
|
return;
|
|
2048
2177
|
}
|
|
2049
2178
|
if (toolName === 'marrow_agent_runtime') {
|
|
2050
|
-
const
|
|
2179
|
+
const runtimeInput = {
|
|
2051
2180
|
action: (0, redact_1.redactSensitiveText)(args.action),
|
|
2052
2181
|
type: args.type,
|
|
2053
2182
|
role: args.role,
|
|
2054
|
-
agent_id: args.agentId ||
|
|
2183
|
+
agent_id: args.agentId || FLEET_AGENT_ID,
|
|
2055
2184
|
session_id: args.sessionId || SESSION_ID,
|
|
2056
2185
|
surfaces: Array.isArray(args.surfaces) ? args.surfaces : undefined,
|
|
2057
2186
|
context: args.context && typeof args.context === 'object' && !Array.isArray(args.context)
|
|
@@ -2061,7 +2190,9 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2061
2190
|
? (0, redact_1.redactSensitiveValue)(args.proof)
|
|
2062
2191
|
: undefined,
|
|
2063
2192
|
period: args.period,
|
|
2064
|
-
}
|
|
2193
|
+
};
|
|
2194
|
+
const result = await withControlDeadline((signal) => (0, index_1.marrowAgentRuntime)(API_KEY, BASE_URL, runtimeInput, SESSION_ID, FLEET_AGENT_ID, signal), { highRisk: isHighRiskAction(runtimeInput.action, runtimeInput.type) });
|
|
2195
|
+
storeRuntimeGuidance(result);
|
|
2065
2196
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
2066
2197
|
return;
|
|
2067
2198
|
}
|
|
@@ -2075,7 +2206,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2075
2206
|
: [],
|
|
2076
2207
|
action: typeof args.action === 'string' ? (0, redact_1.redactSensitiveText)(args.action) : undefined,
|
|
2077
2208
|
type: args.type,
|
|
2078
|
-
agent_id: args.agentId ||
|
|
2209
|
+
agent_id: args.agentId || FLEET_AGENT_ID,
|
|
2079
2210
|
session_id: args.sessionId || SESSION_ID,
|
|
2080
2211
|
surfaces: Array.isArray(args.surfaces) ? args.surfaces : undefined,
|
|
2081
2212
|
context: args.context && typeof args.context === 'object' && !Array.isArray(args.context)
|
|
@@ -2131,7 +2262,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2131
2262
|
}
|
|
2132
2263
|
if (toolName === 'marrow_governance_timeline') {
|
|
2133
2264
|
const result = await (0, index_1.marrowGovernanceTimeline)(API_KEY, BASE_URL, {
|
|
2134
|
-
agentId: args.agentId ||
|
|
2265
|
+
agentId: args.agentId || FLEET_AGENT_ID,
|
|
2135
2266
|
limit: args.limit,
|
|
2136
2267
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
2137
2268
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
@@ -2149,7 +2280,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2149
2280
|
}
|
|
2150
2281
|
if (toolName === 'marrow_buyer_proof') {
|
|
2151
2282
|
const result = await (0, index_1.marrowBuyerProof)(API_KEY, BASE_URL, {
|
|
2152
|
-
agentId: args.agentId ||
|
|
2283
|
+
agentId: args.agentId || FLEET_AGENT_ID,
|
|
2153
2284
|
periodDays: args.periodDays,
|
|
2154
2285
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
2155
2286
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
@@ -2165,7 +2296,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2165
2296
|
: undefined,
|
|
2166
2297
|
agent: args.agent && typeof args.agent === 'object' && !Array.isArray(args.agent)
|
|
2167
2298
|
? (0, redact_1.redactSensitiveValue)(args.agent)
|
|
2168
|
-
: { id: FLEET_AGENT_ID
|
|
2299
|
+
: { id: FLEET_AGENT_ID },
|
|
2169
2300
|
selected_mode: args.selected_mode,
|
|
2170
2301
|
selection_source: args.selection_source,
|
|
2171
2302
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
@@ -2206,7 +2337,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2206
2337
|
: undefined,
|
|
2207
2338
|
agent: args.agent && typeof args.agent === 'object' && !Array.isArray(args.agent)
|
|
2208
2339
|
? (0, redact_1.redactSensitiveValue)(args.agent)
|
|
2209
|
-
: { id: FLEET_AGENT_ID
|
|
2340
|
+
: { id: FLEET_AGENT_ID },
|
|
2210
2341
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
2211
2342
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
2212
2343
|
return;
|
|
@@ -2225,7 +2356,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2225
2356
|
return;
|
|
2226
2357
|
}
|
|
2227
2358
|
if (toolName === 'marrow_agent_performance') {
|
|
2228
|
-
const result = await (0, index_1.marrowAgentPerformance)(API_KEY, BASE_URL, args.period || '7d', args.agentId ||
|
|
2359
|
+
const result = await (0, index_1.marrowAgentPerformance)(API_KEY, BASE_URL, args.period || '7d', args.agentId || FLEET_AGENT_ID, SESSION_ID, FLEET_AGENT_ID);
|
|
2229
2360
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
2230
2361
|
return;
|
|
2231
2362
|
}
|
|
@@ -2233,7 +2364,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2233
2364
|
const result = await (0, index_1.marrowFleetLessons)(API_KEY, BASE_URL, {
|
|
2234
2365
|
query: args.query,
|
|
2235
2366
|
type: args.type,
|
|
2236
|
-
agentId: args.agentId ||
|
|
2367
|
+
agentId: args.agentId || FLEET_AGENT_ID,
|
|
2237
2368
|
limit: args.limit,
|
|
2238
2369
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
2239
2370
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
@@ -2262,7 +2393,7 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2262
2393
|
if (toolName === 'marrow_handoff_status') {
|
|
2263
2394
|
const result = await (0, index_1.marrowHandoffStatus)(API_KEY, BASE_URL, {
|
|
2264
2395
|
status: args.status,
|
|
2265
|
-
agentId: args.agentId ||
|
|
2396
|
+
agentId: args.agentId || FLEET_AGENT_ID,
|
|
2266
2397
|
limit: args.limit,
|
|
2267
2398
|
}, SESSION_ID, FLEET_AGENT_ID);
|
|
2268
2399
|
success(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
@@ -2308,8 +2439,12 @@ Marrow is not a replacement agent or a standalone memory app. Context and prior
|
|
|
2308
2439
|
error(id, -32601, `Method not found: ${method}`);
|
|
2309
2440
|
}
|
|
2310
2441
|
catch (err) {
|
|
2442
|
+
if (err instanceof request_reliability_1.MarrowRequestError && method === 'tools/call') {
|
|
2443
|
+
toolSuccess(id, toolFailure(params?.name, err), true);
|
|
2444
|
+
return;
|
|
2445
|
+
}
|
|
2311
2446
|
const message = err instanceof Error ? err.message : String(err);
|
|
2312
|
-
error(id, -
|
|
2447
|
+
error(id, -32602, (0, redact_1.redactSensitiveText)(message).slice(0, 240));
|
|
2313
2448
|
}
|
|
2314
2449
|
}
|
|
2315
2450
|
// MCP stdio loop — raw stdin, no readline (readline writes prompts to stdout which breaks MCP)
|