@rk0429/agentic-relay 0.16.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/relay.mjs +53 -156
- package/package.json +1 -1
package/dist/relay.mjs
CHANGED
|
@@ -817,13 +817,7 @@ var init_spawn_agent = __esm({
|
|
|
817
817
|
taskInstructionPath: z2.string().optional().describe(
|
|
818
818
|
"Path to a file containing task instructions. Content is prepended to the prompt. Path is resolved relative to the project root and validated against path traversal."
|
|
819
819
|
),
|
|
820
|
-
label: z2.string().optional().describe("Human-readable label for identifying this agent in parallel results and logs.")
|
|
821
|
-
maxResponseLength: z2.number().int().positive().optional().describe(
|
|
822
|
-
"Maximum response length in characters. When exceeded, response is truncated or summarized based on responseMode."
|
|
823
|
-
),
|
|
824
|
-
responseMode: z2.enum(["truncate", "summarize"]).optional().describe(
|
|
825
|
-
"How to handle responses exceeding maxResponseLength. 'truncate' (default) cuts at limit with file save. 'summarize' uses AI to condense."
|
|
826
|
-
)
|
|
820
|
+
label: z2.string().optional().describe("Human-readable label for identifying this agent in parallel results and logs.")
|
|
827
821
|
});
|
|
828
822
|
}
|
|
829
823
|
});
|
|
@@ -1213,83 +1207,23 @@ var init_types = __esm({
|
|
|
1213
1207
|
}
|
|
1214
1208
|
});
|
|
1215
1209
|
|
|
1216
|
-
// src/mcp-server/response-summarizer.ts
|
|
1217
|
-
async function loadClaudeSDK2() {
|
|
1218
|
-
return await import("@anthropic-ai/claude-agent-sdk");
|
|
1219
|
-
}
|
|
1220
|
-
function buildCleanEnv() {
|
|
1221
|
-
const env = {};
|
|
1222
|
-
for (const [key, value] of Object.entries(process.env)) {
|
|
1223
|
-
if (value !== void 0 && !CLAUDE_NESTING_ENV_VARS2.includes(key)) {
|
|
1224
|
-
env[key] = value;
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
return env;
|
|
1228
|
-
}
|
|
1229
|
-
async function summarizeResponse(text, targetLength) {
|
|
1230
|
-
const { query } = await loadClaudeSDK2();
|
|
1231
|
-
const prompt = `Summarize the following text in ${targetLength} characters or less. Prioritize:
|
|
1232
|
-
1. Key deliverables, artifacts, and file changes
|
|
1233
|
-
2. Important decisions and conclusions
|
|
1234
|
-
3. Action items and next steps
|
|
1235
|
-
|
|
1236
|
-
Preserve technical details (file paths, function names, error messages) when possible.
|
|
1237
|
-
|
|
1238
|
-
<text>
|
|
1239
|
-
${text}
|
|
1240
|
-
</text>`;
|
|
1241
|
-
const q = query({
|
|
1242
|
-
prompt,
|
|
1243
|
-
options: {
|
|
1244
|
-
model: "haiku",
|
|
1245
|
-
maxTurns: 1,
|
|
1246
|
-
env: buildCleanEnv(),
|
|
1247
|
-
cwd: process.cwd(),
|
|
1248
|
-
permissionMode: "bypassPermissions",
|
|
1249
|
-
allowDangerouslySkipPermissions: true
|
|
1250
|
-
}
|
|
1251
|
-
});
|
|
1252
|
-
let resultText = "";
|
|
1253
|
-
for await (const message of q) {
|
|
1254
|
-
if (message.type === "result") {
|
|
1255
|
-
if (message.subtype === "success") {
|
|
1256
|
-
resultText = message.result;
|
|
1257
|
-
} else {
|
|
1258
|
-
const errors = message.errors;
|
|
1259
|
-
throw new Error(`Summarization failed: ${errors?.join("; ") ?? "unknown error"}`);
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
if (!resultText) {
|
|
1264
|
-
throw new Error("No result from summarization");
|
|
1265
|
-
}
|
|
1266
|
-
return resultText;
|
|
1267
|
-
}
|
|
1268
|
-
var CLAUDE_NESTING_ENV_VARS2;
|
|
1269
|
-
var init_response_summarizer = __esm({
|
|
1270
|
-
"src/mcp-server/response-summarizer.ts"() {
|
|
1271
|
-
"use strict";
|
|
1272
|
-
CLAUDE_NESTING_ENV_VARS2 = [
|
|
1273
|
-
"CLAUDECODE",
|
|
1274
|
-
"CLAUDE_CODE_SSE_PORT",
|
|
1275
|
-
"CLAUDE_CODE_ENTRYPOINT"
|
|
1276
|
-
];
|
|
1277
|
-
}
|
|
1278
|
-
});
|
|
1279
|
-
|
|
1280
1210
|
// src/mcp-server/response-formatter.ts
|
|
1281
1211
|
import * as fs from "fs";
|
|
1282
1212
|
import * as path from "path";
|
|
1283
|
-
|
|
1284
|
-
|
|
1213
|
+
function resolveResponseDir(dir) {
|
|
1214
|
+
const target = dir ?? DEFAULT_RESPONSE_OUTPUT_DIR;
|
|
1215
|
+
return path.isAbsolute(target) ? target : path.resolve(process.cwd(), target);
|
|
1216
|
+
}
|
|
1217
|
+
function saveFullResponse(content, sessionId, responseOutputDir) {
|
|
1285
1218
|
try {
|
|
1286
|
-
const
|
|
1219
|
+
const baseDir = resolveResponseDir(responseOutputDir);
|
|
1220
|
+
const dir = sessionId ? path.join(baseDir, sessionId) : path.join(baseDir, `anonymous-${Date.now()}`);
|
|
1287
1221
|
fs.mkdirSync(dir, { recursive: true });
|
|
1288
1222
|
const filePath = path.join(dir, "response.txt");
|
|
1289
1223
|
fs.writeFileSync(filePath, content, "utf-8");
|
|
1290
1224
|
try {
|
|
1291
|
-
const entries = fs.readdirSync(
|
|
1292
|
-
const fullPath = path.join(
|
|
1225
|
+
const entries = fs.readdirSync(baseDir).map((name) => {
|
|
1226
|
+
const fullPath = path.join(baseDir, name);
|
|
1293
1227
|
try {
|
|
1294
1228
|
const stat = fs.statSync(fullPath);
|
|
1295
1229
|
return { name, fullPath, mtimeMs: stat.mtimeMs };
|
|
@@ -1311,28 +1245,17 @@ function saveFullResponse(content, sessionId) {
|
|
|
1311
1245
|
}
|
|
1312
1246
|
}
|
|
1313
1247
|
async function processStdout(stdout, options) {
|
|
1314
|
-
const
|
|
1315
|
-
|
|
1316
|
-
if (stdout.length <= maxLength) {
|
|
1248
|
+
const inlineSummaryLength = options?.inlineSummaryLength ?? DEFAULT_INLINE_SUMMARY_LENGTH;
|
|
1249
|
+
if (stdout.length <= inlineSummaryLength) {
|
|
1317
1250
|
return { text: stdout, truncated: false };
|
|
1318
1251
|
}
|
|
1319
|
-
const savedFilePath = saveFullResponse(stdout, options?.sessionId);
|
|
1320
|
-
const
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
const summary = await summarizeResponse(stdout, maxLength);
|
|
1324
|
-
const footer2 = `
|
|
1252
|
+
const savedFilePath = saveFullResponse(stdout, options?.sessionId, options?.responseOutputDir);
|
|
1253
|
+
const summary = stdout.slice(0, inlineSummaryLength);
|
|
1254
|
+
const fileRef = savedFilePath ?? "(file save failed)";
|
|
1255
|
+
const footer = `...
|
|
1325
1256
|
|
|
1326
|
-
[RESPONSE
|
|
1327
|
-
|
|
1328
|
-
} catch {
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
const truncated = stdout.slice(0, maxLength);
|
|
1332
|
-
const footer = `
|
|
1333
|
-
|
|
1334
|
-
[RESPONSE TRUNCATED: original ${stdout.length} chars exceeded limit ${maxLength} chars.${savedInfo}]`;
|
|
1335
|
-
return { text: truncated + footer, truncated: true, savedFilePath };
|
|
1257
|
+
[FULL RESPONSE: ${stdout.length} chars \u2192 ${fileRef}]`;
|
|
1258
|
+
return { text: summary + footer, truncated: true, savedFilePath };
|
|
1336
1259
|
}
|
|
1337
1260
|
function truncateStderr(stderr) {
|
|
1338
1261
|
if (!stderr) return stderr;
|
|
@@ -1388,7 +1311,7 @@ ${JSON.stringify(result.metadata, null, 2)}
|
|
|
1388
1311
|
}
|
|
1389
1312
|
return { text, isError };
|
|
1390
1313
|
}
|
|
1391
|
-
async function formatParallelResponse(result, options
|
|
1314
|
+
async function formatParallelResponse(result, options) {
|
|
1392
1315
|
const isError = result.failureCount === result.totalCount;
|
|
1393
1316
|
const parts = [];
|
|
1394
1317
|
if (result.hasConflicts && result.conflicts) {
|
|
@@ -1408,7 +1331,7 @@ async function formatParallelResponse(result, options, perAgentOptions) {
|
|
|
1408
1331
|
const duration = r.metadata?.durationMs !== void 0 ? `${(r.metadata.durationMs / 1e3).toFixed(1)}s` : "?s";
|
|
1409
1332
|
if (r.exitCode === 0) {
|
|
1410
1333
|
parts.push(`--- Agent ${r.index}${labelPart} (${backend}, ${duration}) SUCCESS ---`);
|
|
1411
|
-
const agentOptions =
|
|
1334
|
+
const agentOptions = { ...options, sessionId: r.sessionId };
|
|
1412
1335
|
const processed = await processStdout(r.stdout || "", agentOptions);
|
|
1413
1336
|
parts.push(processed.text || "(no output)");
|
|
1414
1337
|
} else {
|
|
@@ -1427,15 +1350,14 @@ ${JSON.stringify(sanitizedResult, null, 2)}
|
|
|
1427
1350
|
</metadata>`);
|
|
1428
1351
|
return { text: parts.join("\n"), isError };
|
|
1429
1352
|
}
|
|
1430
|
-
var STDERR_MAX_LENGTH,
|
|
1353
|
+
var STDERR_MAX_LENGTH, DEFAULT_INLINE_SUMMARY_LENGTH, MAX_SAVED_RESPONSES, DEFAULT_RESPONSE_OUTPUT_DIR;
|
|
1431
1354
|
var init_response_formatter = __esm({
|
|
1432
1355
|
"src/mcp-server/response-formatter.ts"() {
|
|
1433
1356
|
"use strict";
|
|
1434
|
-
init_response_summarizer();
|
|
1435
1357
|
STDERR_MAX_LENGTH = 2e3;
|
|
1436
|
-
|
|
1358
|
+
DEFAULT_INLINE_SUMMARY_LENGTH = 500;
|
|
1437
1359
|
MAX_SAVED_RESPONSES = 100;
|
|
1438
|
-
|
|
1360
|
+
DEFAULT_RESPONSE_OUTPUT_DIR = ".relay/responses";
|
|
1439
1361
|
}
|
|
1440
1362
|
});
|
|
1441
1363
|
|
|
@@ -1482,16 +1404,17 @@ var init_server = __esm({
|
|
|
1482
1404
|
};
|
|
1483
1405
|
MAX_CHILD_HTTP_SESSIONS = 100;
|
|
1484
1406
|
RelayMCPServer = class {
|
|
1485
|
-
constructor(registry2, sessionManager2, guardConfig, hooksEngine2, contextMonitor2,
|
|
1407
|
+
constructor(registry2, sessionManager2, guardConfig, hooksEngine2, contextMonitor2, inlineSummaryLength, responseOutputDir) {
|
|
1486
1408
|
this.registry = registry2;
|
|
1487
1409
|
this.sessionManager = sessionManager2;
|
|
1488
1410
|
this.hooksEngine = hooksEngine2;
|
|
1489
1411
|
this.contextMonitor = contextMonitor2;
|
|
1490
|
-
this.
|
|
1412
|
+
this.inlineSummaryLength = inlineSummaryLength;
|
|
1413
|
+
this.responseOutputDir = responseOutputDir;
|
|
1491
1414
|
this.guard = new RecursionGuard(guardConfig);
|
|
1492
1415
|
this.backendSelector = new BackendSelector();
|
|
1493
1416
|
this.server = new McpServer(
|
|
1494
|
-
{ name: "agentic-relay", version: "
|
|
1417
|
+
{ name: "agentic-relay", version: "1.1.0" },
|
|
1495
1418
|
createMcpServerOptions()
|
|
1496
1419
|
);
|
|
1497
1420
|
this.registerTools(this.server);
|
|
@@ -1527,9 +1450,9 @@ var init_server = __esm({
|
|
|
1527
1450
|
this._childHttpUrl
|
|
1528
1451
|
);
|
|
1529
1452
|
const controlOptions = {
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1453
|
+
inlineSummaryLength: this.inlineSummaryLength ?? DEFAULT_INLINE_SUMMARY_LENGTH,
|
|
1454
|
+
sessionId: result.sessionId,
|
|
1455
|
+
responseOutputDir: this.responseOutputDir
|
|
1533
1456
|
};
|
|
1534
1457
|
const { text, isError } = await formatSpawnAgentResponse(result, controlOptions);
|
|
1535
1458
|
const callToolResult = {
|
|
@@ -1579,25 +1502,10 @@ var init_server = __esm({
|
|
|
1579
1502
|
this._childHttpUrl
|
|
1580
1503
|
);
|
|
1581
1504
|
const controlOptions = {
|
|
1582
|
-
|
|
1583
|
-
|
|
1505
|
+
inlineSummaryLength: this.inlineSummaryLength ?? DEFAULT_INLINE_SUMMARY_LENGTH,
|
|
1506
|
+
responseOutputDir: this.responseOutputDir
|
|
1584
1507
|
};
|
|
1585
|
-
const
|
|
1586
|
-
for (let i = 0; i < agents.length; i++) {
|
|
1587
|
-
const agent = agents[i];
|
|
1588
|
-
if (agent.maxResponseLength !== void 0 || agent.responseMode !== void 0) {
|
|
1589
|
-
perAgentOptions.set(i, {
|
|
1590
|
-
maxLength: agent.maxResponseLength ?? controlOptions.maxLength,
|
|
1591
|
-
mode: agent.responseMode ?? controlOptions.mode,
|
|
1592
|
-
sessionId: result.results[i]?.sessionId
|
|
1593
|
-
});
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
|
-
const { text, isError } = await formatParallelResponse(
|
|
1597
|
-
result,
|
|
1598
|
-
controlOptions,
|
|
1599
|
-
perAgentOptions.size > 0 ? perAgentOptions : void 0
|
|
1600
|
-
);
|
|
1508
|
+
const { text, isError } = await formatParallelResponse(result, controlOptions);
|
|
1601
1509
|
const callToolResult = {
|
|
1602
1510
|
content: [{ type: "text", text }],
|
|
1603
1511
|
isError
|
|
@@ -1714,25 +1622,10 @@ var init_server = __esm({
|
|
|
1714
1622
|
this._childHttpUrl
|
|
1715
1623
|
);
|
|
1716
1624
|
const controlOptions = {
|
|
1717
|
-
|
|
1718
|
-
|
|
1625
|
+
inlineSummaryLength: this.inlineSummaryLength ?? DEFAULT_INLINE_SUMMARY_LENGTH,
|
|
1626
|
+
responseOutputDir: this.responseOutputDir
|
|
1719
1627
|
};
|
|
1720
|
-
const
|
|
1721
|
-
for (let i = 0; i < agents.length; i++) {
|
|
1722
|
-
const agent = agents[i];
|
|
1723
|
-
if (agent.maxResponseLength !== void 0 || agent.responseMode !== void 0) {
|
|
1724
|
-
perAgentOptions.set(i, {
|
|
1725
|
-
maxLength: agent.maxResponseLength ?? controlOptions.maxLength,
|
|
1726
|
-
mode: agent.responseMode ?? controlOptions.mode,
|
|
1727
|
-
sessionId: result.results[i]?.sessionId
|
|
1728
|
-
});
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
const { text, isError } = await formatParallelResponse(
|
|
1732
|
-
result,
|
|
1733
|
-
controlOptions,
|
|
1734
|
-
perAgentOptions.size > 0 ? perAgentOptions : void 0
|
|
1735
|
-
);
|
|
1628
|
+
const { text, isError } = await formatParallelResponse(result, controlOptions);
|
|
1736
1629
|
return {
|
|
1737
1630
|
content: [{ type: "text", text }],
|
|
1738
1631
|
isError
|
|
@@ -1859,14 +1752,14 @@ var init_server = __esm({
|
|
|
1859
1752
|
});
|
|
1860
1753
|
this._httpServer = httpServer;
|
|
1861
1754
|
await this.server.connect(httpTransport);
|
|
1862
|
-
await new Promise((
|
|
1755
|
+
await new Promise((resolve3) => {
|
|
1863
1756
|
httpServer.listen(port, "127.0.0.1", () => {
|
|
1864
1757
|
logger.info(`MCP server listening on http://localhost:${port}/mcp`);
|
|
1865
|
-
|
|
1758
|
+
resolve3();
|
|
1866
1759
|
});
|
|
1867
1760
|
});
|
|
1868
|
-
await new Promise((
|
|
1869
|
-
httpServer.on("close",
|
|
1761
|
+
await new Promise((resolve3) => {
|
|
1762
|
+
httpServer.on("close", resolve3);
|
|
1870
1763
|
});
|
|
1871
1764
|
}
|
|
1872
1765
|
/**
|
|
@@ -1896,7 +1789,7 @@ var init_server = __esm({
|
|
|
1896
1789
|
sessionIdGenerator: () => randomUUID()
|
|
1897
1790
|
});
|
|
1898
1791
|
const server = new McpServer(
|
|
1899
|
-
{ name: "agentic-relay", version: "
|
|
1792
|
+
{ name: "agentic-relay", version: "1.1.0" },
|
|
1900
1793
|
createMcpServerOptions()
|
|
1901
1794
|
);
|
|
1902
1795
|
this.registerTools(server);
|
|
@@ -1932,12 +1825,12 @@ var init_server = __esm({
|
|
|
1932
1825
|
}
|
|
1933
1826
|
});
|
|
1934
1827
|
this._childHttpServer = httpServer;
|
|
1935
|
-
await new Promise((
|
|
1828
|
+
await new Promise((resolve3) => {
|
|
1936
1829
|
httpServer.listen(0, "127.0.0.1", () => {
|
|
1937
1830
|
const addr = httpServer.address();
|
|
1938
1831
|
this._childHttpUrl = `http://127.0.0.1:${addr.port}/mcp`;
|
|
1939
1832
|
logger.info(`Child MCP server listening on ${this._childHttpUrl}`);
|
|
1940
|
-
|
|
1833
|
+
resolve3();
|
|
1941
1834
|
});
|
|
1942
1835
|
});
|
|
1943
1836
|
}
|
|
@@ -3497,7 +3390,8 @@ var relayConfigSchema = z.object({
|
|
|
3497
3390
|
maxDepth: z.number().int().positive(),
|
|
3498
3391
|
maxCallsPerSession: z.number().int().positive(),
|
|
3499
3392
|
timeoutSec: z.number().positive(),
|
|
3500
|
-
|
|
3393
|
+
inlineSummaryLength: z.number().int().positive().optional(),
|
|
3394
|
+
responseOutputDir: z.string().optional()
|
|
3501
3395
|
}).optional(),
|
|
3502
3396
|
telemetry: z.object({
|
|
3503
3397
|
enabled: z.boolean()
|
|
@@ -4728,7 +4622,8 @@ function createMCPCommand(configManager2, registry2, sessionManager2, hooksEngin
|
|
|
4728
4622
|
return;
|
|
4729
4623
|
}
|
|
4730
4624
|
let guardConfig;
|
|
4731
|
-
let
|
|
4625
|
+
let inlineSummaryLength;
|
|
4626
|
+
let responseOutputDir;
|
|
4732
4627
|
try {
|
|
4733
4628
|
const config = await configManager2.getConfig();
|
|
4734
4629
|
if (config.mcpServerMode) {
|
|
@@ -4737,7 +4632,8 @@ function createMCPCommand(configManager2, registry2, sessionManager2, hooksEngin
|
|
|
4737
4632
|
maxCallsPerSession: config.mcpServerMode.maxCallsPerSession ?? 20,
|
|
4738
4633
|
timeoutSec: config.mcpServerMode.timeoutSec ?? 86400
|
|
4739
4634
|
};
|
|
4740
|
-
|
|
4635
|
+
inlineSummaryLength = config.mcpServerMode.inlineSummaryLength;
|
|
4636
|
+
responseOutputDir = config.mcpServerMode.responseOutputDir;
|
|
4741
4637
|
}
|
|
4742
4638
|
} catch {
|
|
4743
4639
|
}
|
|
@@ -4749,7 +4645,8 @@ function createMCPCommand(configManager2, registry2, sessionManager2, hooksEngin
|
|
|
4749
4645
|
guardConfig,
|
|
4750
4646
|
hooksEngine2,
|
|
4751
4647
|
contextMonitor2,
|
|
4752
|
-
|
|
4648
|
+
inlineSummaryLength,
|
|
4649
|
+
responseOutputDir
|
|
4753
4650
|
);
|
|
4754
4651
|
await server.start({ transport, port });
|
|
4755
4652
|
}
|
|
@@ -4911,7 +4808,7 @@ function createVersionCommand(registry2) {
|
|
|
4911
4808
|
description: "Show relay and backend versions"
|
|
4912
4809
|
},
|
|
4913
4810
|
async run() {
|
|
4914
|
-
const relayVersion = "
|
|
4811
|
+
const relayVersion = "1.1.0";
|
|
4915
4812
|
console.log(`agentic-relay v${relayVersion}`);
|
|
4916
4813
|
console.log("");
|
|
4917
4814
|
console.log("Backends:");
|
|
@@ -5261,7 +5158,7 @@ void configManager.getConfig().then((config) => {
|
|
|
5261
5158
|
var main = defineCommand10({
|
|
5262
5159
|
meta: {
|
|
5263
5160
|
name: "relay",
|
|
5264
|
-
version: "
|
|
5161
|
+
version: "1.1.0",
|
|
5265
5162
|
description: "Unified CLI proxy for Claude Code, Codex CLI, and Gemini CLI"
|
|
5266
5163
|
},
|
|
5267
5164
|
subCommands: {
|
package/package.json
CHANGED