@rk0429/agentic-relay 0.14.1 → 0.16.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 +214 -40
- package/package.json +2 -1
package/dist/relay.mjs
CHANGED
|
@@ -446,6 +446,7 @@ function inferFailureReason(stderr, stdout, sdkErrorMetadata) {
|
|
|
446
446
|
const combined = `${stderr} ${stdout}`.toLowerCase();
|
|
447
447
|
if (combined.includes("timed out") || combined.includes("timeout")) return "timeout";
|
|
448
448
|
if (combined.includes("max turns") || combined.includes("max_turns") || combined.includes("turn limit")) return "max_turns_exhausted";
|
|
449
|
+
if (combined.includes("429") || combined.includes("capacity_exhausted") || combined.includes("model_capacity_exhausted") || combined.includes("ratelimitexceeded") || combined.includes("resource_exhausted")) return "rate_limit";
|
|
449
450
|
return "adapter_error";
|
|
450
451
|
}
|
|
451
452
|
function buildContextFromEnv() {
|
|
@@ -617,7 +618,6 @@ ${input.prompt}`;
|
|
|
617
618
|
}
|
|
618
619
|
onProgress?.({ stage: "spawning", percent: 10 });
|
|
619
620
|
try {
|
|
620
|
-
let result;
|
|
621
621
|
const executePromise = (async () => {
|
|
622
622
|
if (input.resumeSessionId) {
|
|
623
623
|
if (!adapter.continueSession) {
|
|
@@ -681,7 +681,7 @@ ${input.prompt}`;
|
|
|
681
681
|
});
|
|
682
682
|
}
|
|
683
683
|
})();
|
|
684
|
-
result = await executePromise;
|
|
684
|
+
const result = await executePromise;
|
|
685
685
|
if (result && "_noSession" in result) {
|
|
686
686
|
return {
|
|
687
687
|
sessionId: session.relaySessionId,
|
|
@@ -817,7 +817,13 @@ 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.")
|
|
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
|
+
)
|
|
821
827
|
});
|
|
822
828
|
}
|
|
823
829
|
});
|
|
@@ -858,11 +864,11 @@ function extractMentionedPaths(stdout) {
|
|
|
858
864
|
for (const pattern of patterns) {
|
|
859
865
|
let match;
|
|
860
866
|
while ((match = pattern.exec(stdout)) !== null) {
|
|
861
|
-
let
|
|
862
|
-
if (
|
|
863
|
-
|
|
867
|
+
let path2 = match[1];
|
|
868
|
+
if (path2.startsWith("./")) {
|
|
869
|
+
path2 = path2.slice(2);
|
|
864
870
|
}
|
|
865
|
-
paths.add(
|
|
871
|
+
paths.add(path2);
|
|
866
872
|
}
|
|
867
873
|
}
|
|
868
874
|
return paths;
|
|
@@ -897,7 +903,7 @@ async function detectConflicts(before, after, agentResults) {
|
|
|
897
903
|
}
|
|
898
904
|
}
|
|
899
905
|
const conflicts = Array.from(fileToAgents.entries()).map(
|
|
900
|
-
([
|
|
906
|
+
([path2, agents]) => ({ path: path2, agents })
|
|
901
907
|
);
|
|
902
908
|
return {
|
|
903
909
|
conflicts,
|
|
@@ -1207,8 +1213,128 @@ var init_types = __esm({
|
|
|
1207
1213
|
}
|
|
1208
1214
|
});
|
|
1209
1215
|
|
|
1216
|
+
// src/mcp-server/response-summarizer.ts
|
|
1217
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
1218
|
+
async function summarizeResponse(text, targetLength) {
|
|
1219
|
+
const client = new Anthropic();
|
|
1220
|
+
const message = await client.messages.create({
|
|
1221
|
+
model: "claude-haiku-4-5-20251001",
|
|
1222
|
+
max_tokens: Math.max(1024, Math.ceil(targetLength / 3)),
|
|
1223
|
+
messages: [
|
|
1224
|
+
{
|
|
1225
|
+
role: "user",
|
|
1226
|
+
content: `Summarize the following text in ${targetLength} characters or less. Prioritize:
|
|
1227
|
+
1. Key deliverables, artifacts, and file changes
|
|
1228
|
+
2. Important decisions and conclusions
|
|
1229
|
+
3. Action items and next steps
|
|
1230
|
+
|
|
1231
|
+
Preserve technical details (file paths, function names, error messages) when possible.
|
|
1232
|
+
|
|
1233
|
+
<text>
|
|
1234
|
+
${text}
|
|
1235
|
+
</text>`
|
|
1236
|
+
}
|
|
1237
|
+
]
|
|
1238
|
+
});
|
|
1239
|
+
const content = message.content[0];
|
|
1240
|
+
if (content?.type !== "text") {
|
|
1241
|
+
throw new Error("Unexpected response format from summarization API");
|
|
1242
|
+
}
|
|
1243
|
+
return content.text;
|
|
1244
|
+
}
|
|
1245
|
+
var init_response_summarizer = __esm({
|
|
1246
|
+
"src/mcp-server/response-summarizer.ts"() {
|
|
1247
|
+
"use strict";
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
|
|
1210
1251
|
// src/mcp-server/response-formatter.ts
|
|
1211
|
-
|
|
1252
|
+
import * as fs from "fs";
|
|
1253
|
+
import * as path from "path";
|
|
1254
|
+
import * as os from "os";
|
|
1255
|
+
function saveFullResponse(content, sessionId) {
|
|
1256
|
+
try {
|
|
1257
|
+
const dir = sessionId ? path.join(RESPONSE_DIR, sessionId) : path.join(RESPONSE_DIR, `anonymous-${Date.now()}`);
|
|
1258
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1259
|
+
const filePath = path.join(dir, "response.txt");
|
|
1260
|
+
fs.writeFileSync(filePath, content, "utf-8");
|
|
1261
|
+
try {
|
|
1262
|
+
const entries = fs.readdirSync(RESPONSE_DIR).map((name) => {
|
|
1263
|
+
const fullPath = path.join(RESPONSE_DIR, name);
|
|
1264
|
+
try {
|
|
1265
|
+
const stat = fs.statSync(fullPath);
|
|
1266
|
+
return { name, fullPath, mtimeMs: stat.mtimeMs };
|
|
1267
|
+
} catch {
|
|
1268
|
+
return null;
|
|
1269
|
+
}
|
|
1270
|
+
}).filter((e) => e !== null).sort((a, b) => a.mtimeMs - b.mtimeMs);
|
|
1271
|
+
if (entries.length > MAX_SAVED_RESPONSES) {
|
|
1272
|
+
const toRemove = entries.slice(0, entries.length - MAX_SAVED_RESPONSES);
|
|
1273
|
+
for (const entry of toRemove) {
|
|
1274
|
+
fs.rmSync(entry.fullPath, { recursive: true, force: true });
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
} catch {
|
|
1278
|
+
}
|
|
1279
|
+
return filePath;
|
|
1280
|
+
} catch {
|
|
1281
|
+
return void 0;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
async function processStdout(stdout, options) {
|
|
1285
|
+
const maxLength = options?.maxLength ?? STDOUT_DEFAULT_MAX_LENGTH;
|
|
1286
|
+
const mode = options?.mode ?? "truncate";
|
|
1287
|
+
if (stdout.length <= maxLength) {
|
|
1288
|
+
return { text: stdout, truncated: false };
|
|
1289
|
+
}
|
|
1290
|
+
const savedFilePath = saveFullResponse(stdout, options?.sessionId);
|
|
1291
|
+
const savedInfo = savedFilePath ? ` Full response saved to: ${savedFilePath}` : "";
|
|
1292
|
+
if (mode === "summarize") {
|
|
1293
|
+
try {
|
|
1294
|
+
const summary = await summarizeResponse(stdout, maxLength);
|
|
1295
|
+
const footer2 = `
|
|
1296
|
+
|
|
1297
|
+
[RESPONSE SUMMARIZED: original ${stdout.length} chars exceeded limit ${maxLength} chars.${savedInfo}]`;
|
|
1298
|
+
return { text: summary + footer2, truncated: true, savedFilePath };
|
|
1299
|
+
} catch {
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
const truncated = stdout.slice(0, maxLength);
|
|
1303
|
+
const footer = `
|
|
1304
|
+
|
|
1305
|
+
[RESPONSE TRUNCATED: original ${stdout.length} chars exceeded limit ${maxLength} chars.${savedInfo}]`;
|
|
1306
|
+
return { text: truncated + footer, truncated: true, savedFilePath };
|
|
1307
|
+
}
|
|
1308
|
+
function truncateStderr(stderr) {
|
|
1309
|
+
if (!stderr) return stderr;
|
|
1310
|
+
const blocks = stderr.split("\n\n");
|
|
1311
|
+
if (blocks.length > 1) {
|
|
1312
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1313
|
+
const unique = [];
|
|
1314
|
+
let duplicateCount = 0;
|
|
1315
|
+
for (const block of blocks) {
|
|
1316
|
+
const trimmed = block.trim();
|
|
1317
|
+
if (!trimmed) continue;
|
|
1318
|
+
if (seen.has(trimmed)) {
|
|
1319
|
+
duplicateCount++;
|
|
1320
|
+
} else {
|
|
1321
|
+
seen.add(trimmed);
|
|
1322
|
+
unique.push(block);
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
if (duplicateCount > 0) {
|
|
1326
|
+
stderr = unique.join("\n\n") + `
|
|
1327
|
+
[${duplicateCount} duplicate block(s) removed]`;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
if (stderr.length > STDERR_MAX_LENGTH) {
|
|
1331
|
+
const totalLength = stderr.length;
|
|
1332
|
+
stderr = stderr.slice(0, STDERR_MAX_LENGTH) + `
|
|
1333
|
+
[truncated, ${totalLength} total chars]`;
|
|
1334
|
+
}
|
|
1335
|
+
return stderr;
|
|
1336
|
+
}
|
|
1337
|
+
async function formatSpawnAgentResponse(result, options) {
|
|
1212
1338
|
const isError = result.exitCode !== 0;
|
|
1213
1339
|
let text;
|
|
1214
1340
|
if (isError) {
|
|
@@ -1216,12 +1342,13 @@ function formatSpawnAgentResponse(result) {
|
|
|
1216
1342
|
text = `FAILED (exit ${result.exitCode}${reasonPart})`;
|
|
1217
1343
|
if (result.stderr) {
|
|
1218
1344
|
text += `
|
|
1219
|
-
${result.stderr}`;
|
|
1345
|
+
${truncateStderr(result.stderr)}`;
|
|
1220
1346
|
}
|
|
1221
1347
|
} else {
|
|
1348
|
+
const processed = await processStdout(result.stdout, options);
|
|
1222
1349
|
text = `Session: ${result.sessionId}
|
|
1223
1350
|
|
|
1224
|
-
${
|
|
1351
|
+
${processed.text}`;
|
|
1225
1352
|
}
|
|
1226
1353
|
if (result.metadata) {
|
|
1227
1354
|
text += `
|
|
@@ -1232,7 +1359,7 @@ ${JSON.stringify(result.metadata, null, 2)}
|
|
|
1232
1359
|
}
|
|
1233
1360
|
return { text, isError };
|
|
1234
1361
|
}
|
|
1235
|
-
function formatParallelResponse(result) {
|
|
1362
|
+
async function formatParallelResponse(result, options, perAgentOptions) {
|
|
1236
1363
|
const isError = result.failureCount === result.totalCount;
|
|
1237
1364
|
const parts = [];
|
|
1238
1365
|
if (result.hasConflicts && result.conflicts) {
|
|
@@ -1252,11 +1379,13 @@ function formatParallelResponse(result) {
|
|
|
1252
1379
|
const duration = r.metadata?.durationMs !== void 0 ? `${(r.metadata.durationMs / 1e3).toFixed(1)}s` : "?s";
|
|
1253
1380
|
if (r.exitCode === 0) {
|
|
1254
1381
|
parts.push(`--- Agent ${r.index}${labelPart} (${backend}, ${duration}) SUCCESS ---`);
|
|
1255
|
-
|
|
1382
|
+
const agentOptions = perAgentOptions?.get(r.index) ?? options;
|
|
1383
|
+
const processed = await processStdout(r.stdout || "", agentOptions);
|
|
1384
|
+
parts.push(processed.text || "(no output)");
|
|
1256
1385
|
} else {
|
|
1257
1386
|
const reasonPart = r.failureReason ? `, reason: ${r.failureReason}` : "";
|
|
1258
1387
|
parts.push(`--- Agent ${r.index}${labelPart} FAILED (${backend}, ${duration}${reasonPart}) ---`);
|
|
1259
|
-
parts.push(r.stderr || r.error || "(no output)");
|
|
1388
|
+
parts.push(truncateStderr(r.stderr || r.error || "") || "(no output)");
|
|
1260
1389
|
}
|
|
1261
1390
|
parts.push("");
|
|
1262
1391
|
}
|
|
@@ -1265,9 +1394,15 @@ ${JSON.stringify(result, null, 2)}
|
|
|
1265
1394
|
</metadata>`);
|
|
1266
1395
|
return { text: parts.join("\n"), isError };
|
|
1267
1396
|
}
|
|
1397
|
+
var STDERR_MAX_LENGTH, STDOUT_DEFAULT_MAX_LENGTH, MAX_SAVED_RESPONSES, RESPONSE_DIR;
|
|
1268
1398
|
var init_response_formatter = __esm({
|
|
1269
1399
|
"src/mcp-server/response-formatter.ts"() {
|
|
1270
1400
|
"use strict";
|
|
1401
|
+
init_response_summarizer();
|
|
1402
|
+
STDERR_MAX_LENGTH = 2e3;
|
|
1403
|
+
STDOUT_DEFAULT_MAX_LENGTH = 2e4;
|
|
1404
|
+
MAX_SAVED_RESPONSES = 100;
|
|
1405
|
+
RESPONSE_DIR = path.join(os.tmpdir(), "agentic-relay-responses");
|
|
1271
1406
|
}
|
|
1272
1407
|
});
|
|
1273
1408
|
|
|
@@ -1314,15 +1449,16 @@ var init_server = __esm({
|
|
|
1314
1449
|
};
|
|
1315
1450
|
MAX_CHILD_HTTP_SESSIONS = 100;
|
|
1316
1451
|
RelayMCPServer = class {
|
|
1317
|
-
constructor(registry2, sessionManager2, guardConfig, hooksEngine2, contextMonitor2) {
|
|
1452
|
+
constructor(registry2, sessionManager2, guardConfig, hooksEngine2, contextMonitor2, defaultMaxResponseLength) {
|
|
1318
1453
|
this.registry = registry2;
|
|
1319
1454
|
this.sessionManager = sessionManager2;
|
|
1320
1455
|
this.hooksEngine = hooksEngine2;
|
|
1321
1456
|
this.contextMonitor = contextMonitor2;
|
|
1457
|
+
this.defaultMaxResponseLength = defaultMaxResponseLength;
|
|
1322
1458
|
this.guard = new RecursionGuard(guardConfig);
|
|
1323
1459
|
this.backendSelector = new BackendSelector();
|
|
1324
1460
|
this.server = new McpServer(
|
|
1325
|
-
{ name: "agentic-relay", version: "0.
|
|
1461
|
+
{ name: "agentic-relay", version: "0.16.0" },
|
|
1326
1462
|
createMcpServerOptions()
|
|
1327
1463
|
);
|
|
1328
1464
|
this.registerTools(this.server);
|
|
@@ -1357,7 +1493,12 @@ var init_server = __esm({
|
|
|
1357
1493
|
this.backendSelector,
|
|
1358
1494
|
this._childHttpUrl
|
|
1359
1495
|
);
|
|
1360
|
-
const
|
|
1496
|
+
const controlOptions = {
|
|
1497
|
+
maxLength: params.maxResponseLength ?? this.defaultMaxResponseLength ?? STDOUT_DEFAULT_MAX_LENGTH,
|
|
1498
|
+
mode: params.responseMode ?? "truncate",
|
|
1499
|
+
sessionId: result.sessionId
|
|
1500
|
+
};
|
|
1501
|
+
const { text, isError } = await formatSpawnAgentResponse(result, controlOptions);
|
|
1361
1502
|
const callToolResult = {
|
|
1362
1503
|
content: [{ type: "text", text }],
|
|
1363
1504
|
isError
|
|
@@ -1404,7 +1545,11 @@ var init_server = __esm({
|
|
|
1404
1545
|
this.backendSelector,
|
|
1405
1546
|
this._childHttpUrl
|
|
1406
1547
|
);
|
|
1407
|
-
const
|
|
1548
|
+
const controlOptions = {
|
|
1549
|
+
maxLength: this.defaultMaxResponseLength ?? STDOUT_DEFAULT_MAX_LENGTH,
|
|
1550
|
+
mode: "truncate"
|
|
1551
|
+
};
|
|
1552
|
+
const { text, isError } = await formatParallelResponse(result, controlOptions);
|
|
1408
1553
|
const callToolResult = {
|
|
1409
1554
|
content: [{ type: "text", text }],
|
|
1410
1555
|
isError
|
|
@@ -1520,7 +1665,11 @@ var init_server = __esm({
|
|
|
1520
1665
|
this.backendSelector,
|
|
1521
1666
|
this._childHttpUrl
|
|
1522
1667
|
);
|
|
1523
|
-
const
|
|
1668
|
+
const controlOptions = {
|
|
1669
|
+
maxLength: this.defaultMaxResponseLength ?? STDOUT_DEFAULT_MAX_LENGTH,
|
|
1670
|
+
mode: "truncate"
|
|
1671
|
+
};
|
|
1672
|
+
const { text, isError } = await formatParallelResponse(result, controlOptions);
|
|
1524
1673
|
return {
|
|
1525
1674
|
content: [{ type: "text", text }],
|
|
1526
1675
|
isError
|
|
@@ -1684,7 +1833,7 @@ var init_server = __esm({
|
|
|
1684
1833
|
sessionIdGenerator: () => randomUUID()
|
|
1685
1834
|
});
|
|
1686
1835
|
const server = new McpServer(
|
|
1687
|
-
{ name: "agentic-relay", version: "0.
|
|
1836
|
+
{ name: "agentic-relay", version: "0.16.0" },
|
|
1688
1837
|
createMcpServerOptions()
|
|
1689
1838
|
);
|
|
1690
1839
|
this.registerTools(server);
|
|
@@ -1740,7 +1889,7 @@ var init_server = __esm({
|
|
|
1740
1889
|
|
|
1741
1890
|
// src/bin/relay.ts
|
|
1742
1891
|
import { defineCommand as defineCommand10, runMain } from "citty";
|
|
1743
|
-
import { join as
|
|
1892
|
+
import { join as join10 } from "path";
|
|
1744
1893
|
import { homedir as homedir6 } from "os";
|
|
1745
1894
|
|
|
1746
1895
|
// src/infrastructure/process-manager.ts
|
|
@@ -2856,6 +3005,12 @@ init_logger();
|
|
|
2856
3005
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
2857
3006
|
import { homedir as homedir3 } from "os";
|
|
2858
3007
|
import { join as join3, dirname as dirname3 } from "path";
|
|
3008
|
+
var GEMINI_FALLBACK_CHAIN = [
|
|
3009
|
+
"gemini-3.1-pro-preview",
|
|
3010
|
+
"gemini-2.5-pro",
|
|
3011
|
+
"gemini-2.5-flash"
|
|
3012
|
+
];
|
|
3013
|
+
var RATE_LIMIT_PATTERN = /429|MODEL_CAPACITY_EXHAUSTED|rateLimitExceeded|RESOURCE_EXHAUSTED/i;
|
|
2859
3014
|
var GeminiAdapter = class extends BaseAdapter {
|
|
2860
3015
|
id = "gemini";
|
|
2861
3016
|
command = "gemini";
|
|
@@ -2935,6 +3090,21 @@ ${prompt}`;
|
|
|
2935
3090
|
if (!flags.prompt) {
|
|
2936
3091
|
throw new Error("execute requires a prompt (-p flag)");
|
|
2937
3092
|
}
|
|
3093
|
+
if (flags.model) {
|
|
3094
|
+
return this.executeOnce(flags);
|
|
3095
|
+
}
|
|
3096
|
+
let lastResult;
|
|
3097
|
+
for (const model of GEMINI_FALLBACK_CHAIN) {
|
|
3098
|
+
const result = await this.executeOnce({ ...flags, model });
|
|
3099
|
+
if (result.exitCode === 0 || !RATE_LIMIT_PATTERN.test(result.stderr)) {
|
|
3100
|
+
return result;
|
|
3101
|
+
}
|
|
3102
|
+
logger.warn(`Gemini model ${model} rate limited, trying next fallback...`);
|
|
3103
|
+
lastResult = result;
|
|
3104
|
+
}
|
|
3105
|
+
return lastResult;
|
|
3106
|
+
}
|
|
3107
|
+
async executeOnce(flags) {
|
|
2938
3108
|
const effectivePrompt = this.buildEffectivePrompt(flags);
|
|
2939
3109
|
const args = [];
|
|
2940
3110
|
if (flags.model) {
|
|
@@ -3263,7 +3433,8 @@ var relayConfigSchema = z.object({
|
|
|
3263
3433
|
mcpServerMode: z.object({
|
|
3264
3434
|
maxDepth: z.number().int().positive(),
|
|
3265
3435
|
maxCallsPerSession: z.number().int().positive(),
|
|
3266
|
-
timeoutSec: z.number().positive()
|
|
3436
|
+
timeoutSec: z.number().positive(),
|
|
3437
|
+
maxResponseLength: z.number().int().positive().optional()
|
|
3267
3438
|
}).optional(),
|
|
3268
3439
|
telemetry: z.object({
|
|
3269
3440
|
enabled: z.boolean()
|
|
@@ -3292,8 +3463,8 @@ function deepMerge(target, source) {
|
|
|
3292
3463
|
function isPlainObject(value) {
|
|
3293
3464
|
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
|
|
3294
3465
|
}
|
|
3295
|
-
function getByPath(obj,
|
|
3296
|
-
const parts =
|
|
3466
|
+
function getByPath(obj, path2) {
|
|
3467
|
+
const parts = path2.split(".");
|
|
3297
3468
|
let current = obj;
|
|
3298
3469
|
for (const part of parts) {
|
|
3299
3470
|
if (!isPlainObject(current)) return void 0;
|
|
@@ -3301,8 +3472,8 @@ function getByPath(obj, path) {
|
|
|
3301
3472
|
}
|
|
3302
3473
|
return current;
|
|
3303
3474
|
}
|
|
3304
|
-
function setByPath(obj,
|
|
3305
|
-
const parts =
|
|
3475
|
+
function setByPath(obj, path2, value) {
|
|
3476
|
+
const parts = path2.split(".");
|
|
3306
3477
|
let current = obj;
|
|
3307
3478
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
3308
3479
|
const part = parts[i];
|
|
@@ -4494,6 +4665,7 @@ function createMCPCommand(configManager2, registry2, sessionManager2, hooksEngin
|
|
|
4494
4665
|
return;
|
|
4495
4666
|
}
|
|
4496
4667
|
let guardConfig;
|
|
4668
|
+
let defaultMaxResponseLength;
|
|
4497
4669
|
try {
|
|
4498
4670
|
const config = await configManager2.getConfig();
|
|
4499
4671
|
if (config.mcpServerMode) {
|
|
@@ -4502,6 +4674,7 @@ function createMCPCommand(configManager2, registry2, sessionManager2, hooksEngin
|
|
|
4502
4674
|
maxCallsPerSession: config.mcpServerMode.maxCallsPerSession ?? 20,
|
|
4503
4675
|
timeoutSec: config.mcpServerMode.timeoutSec ?? 86400
|
|
4504
4676
|
};
|
|
4677
|
+
defaultMaxResponseLength = config.mcpServerMode.maxResponseLength;
|
|
4505
4678
|
}
|
|
4506
4679
|
} catch {
|
|
4507
4680
|
}
|
|
@@ -4512,7 +4685,8 @@ function createMCPCommand(configManager2, registry2, sessionManager2, hooksEngin
|
|
|
4512
4685
|
sessionManager2,
|
|
4513
4686
|
guardConfig,
|
|
4514
4687
|
hooksEngine2,
|
|
4515
|
-
contextMonitor2
|
|
4688
|
+
contextMonitor2,
|
|
4689
|
+
defaultMaxResponseLength
|
|
4516
4690
|
);
|
|
4517
4691
|
await server.start({ transport, port });
|
|
4518
4692
|
}
|
|
@@ -4674,7 +4848,7 @@ function createVersionCommand(registry2) {
|
|
|
4674
4848
|
description: "Show relay and backend versions"
|
|
4675
4849
|
},
|
|
4676
4850
|
async run() {
|
|
4677
|
-
const relayVersion = "0.
|
|
4851
|
+
const relayVersion = "0.16.0";
|
|
4678
4852
|
console.log(`agentic-relay v${relayVersion}`);
|
|
4679
4853
|
console.log("");
|
|
4680
4854
|
console.log("Backends:");
|
|
@@ -4699,7 +4873,7 @@ function createVersionCommand(registry2) {
|
|
|
4699
4873
|
// src/commands/doctor.ts
|
|
4700
4874
|
import { defineCommand as defineCommand8 } from "citty";
|
|
4701
4875
|
import { access, constants, readdir as readdir2 } from "fs/promises";
|
|
4702
|
-
import { join as
|
|
4876
|
+
import { join as join8 } from "path";
|
|
4703
4877
|
import { homedir as homedir5 } from "os";
|
|
4704
4878
|
import { execFile as execFile2 } from "child_process";
|
|
4705
4879
|
import { promisify as promisify2 } from "util";
|
|
@@ -4760,8 +4934,8 @@ async function checkConfig(configManager2) {
|
|
|
4760
4934
|
}
|
|
4761
4935
|
}
|
|
4762
4936
|
async function checkSessionsDir() {
|
|
4763
|
-
const relayHome2 = process.env["RELAY_HOME"] ??
|
|
4764
|
-
const sessionsDir =
|
|
4937
|
+
const relayHome2 = process.env["RELAY_HOME"] ?? join8(homedir5(), ".relay");
|
|
4938
|
+
const sessionsDir = join8(relayHome2, "sessions");
|
|
4765
4939
|
try {
|
|
4766
4940
|
await access(sessionsDir, constants.W_OK);
|
|
4767
4941
|
return {
|
|
@@ -4874,8 +5048,8 @@ async function checkBackendAuthEnv() {
|
|
|
4874
5048
|
return results;
|
|
4875
5049
|
}
|
|
4876
5050
|
async function checkSessionsDiskUsage() {
|
|
4877
|
-
const relayHome2 = process.env["RELAY_HOME"] ??
|
|
4878
|
-
const sessionsDir =
|
|
5051
|
+
const relayHome2 = process.env["RELAY_HOME"] ?? join8(homedir5(), ".relay");
|
|
5052
|
+
const sessionsDir = join8(relayHome2, "sessions");
|
|
4879
5053
|
try {
|
|
4880
5054
|
const entries = await readdir2(sessionsDir);
|
|
4881
5055
|
const fileCount = entries.length;
|
|
@@ -4949,7 +5123,7 @@ function createDoctorCommand(registry2, configManager2) {
|
|
|
4949
5123
|
init_logger();
|
|
4950
5124
|
import { defineCommand as defineCommand9 } from "citty";
|
|
4951
5125
|
import { mkdir as mkdir6, writeFile as writeFile6, access as access2, readFile as readFile6 } from "fs/promises";
|
|
4952
|
-
import { join as
|
|
5126
|
+
import { join as join9 } from "path";
|
|
4953
5127
|
var DEFAULT_CONFIG2 = {
|
|
4954
5128
|
defaultBackend: "claude",
|
|
4955
5129
|
backends: {},
|
|
@@ -4963,8 +5137,8 @@ function createInitCommand() {
|
|
|
4963
5137
|
},
|
|
4964
5138
|
async run() {
|
|
4965
5139
|
const projectDir = process.cwd();
|
|
4966
|
-
const relayDir =
|
|
4967
|
-
const configPath =
|
|
5140
|
+
const relayDir = join9(projectDir, ".relay");
|
|
5141
|
+
const configPath = join9(relayDir, "config.json");
|
|
4968
5142
|
try {
|
|
4969
5143
|
await access2(relayDir);
|
|
4970
5144
|
logger.info(
|
|
@@ -4980,7 +5154,7 @@ function createInitCommand() {
|
|
|
4980
5154
|
"utf-8"
|
|
4981
5155
|
);
|
|
4982
5156
|
logger.success(`Created ${configPath}`);
|
|
4983
|
-
const gitignorePath =
|
|
5157
|
+
const gitignorePath = join9(projectDir, ".gitignore");
|
|
4984
5158
|
try {
|
|
4985
5159
|
const gitignoreContent = await readFile6(gitignorePath, "utf-8");
|
|
4986
5160
|
if (!gitignoreContent.includes(".relay/config.local.json")) {
|
|
@@ -5006,8 +5180,8 @@ registry.registerLazy("claude", () => new ClaudeAdapter(processManager));
|
|
|
5006
5180
|
registry.registerLazy("codex", () => new CodexAdapter(processManager));
|
|
5007
5181
|
registry.registerLazy("gemini", () => new GeminiAdapter(processManager));
|
|
5008
5182
|
var sessionManager = new SessionManager();
|
|
5009
|
-
var relayHome = process.env["RELAY_HOME"] ??
|
|
5010
|
-
var projectRelayDir =
|
|
5183
|
+
var relayHome = process.env["RELAY_HOME"] ?? join10(homedir6(), ".relay");
|
|
5184
|
+
var projectRelayDir = join10(process.cwd(), ".relay");
|
|
5011
5185
|
var configManager = new ConfigManager(relayHome, projectRelayDir);
|
|
5012
5186
|
var authManager = new AuthManager(registry);
|
|
5013
5187
|
var eventBus = new EventBus();
|
|
@@ -5024,7 +5198,7 @@ void configManager.getConfig().then((config) => {
|
|
|
5024
5198
|
var main = defineCommand10({
|
|
5025
5199
|
meta: {
|
|
5026
5200
|
name: "relay",
|
|
5027
|
-
version: "0.
|
|
5201
|
+
version: "0.16.0",
|
|
5028
5202
|
description: "Unified CLI proxy for Claude Code, Codex CLI, and Gemini CLI"
|
|
5029
5203
|
},
|
|
5030
5204
|
subCommands: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rk0429/agentic-relay",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Unified CLI proxy for Claude Code, Codex CLI, and Gemini CLI with MCP-based multi-layer sub-agent orchestration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@anthropic-ai/claude-agent-sdk": "^0.2.59",
|
|
53
|
+
"@anthropic-ai/sdk": "^0.78.0",
|
|
53
54
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
54
55
|
"@openai/codex-sdk": "^0.105.0",
|
|
55
56
|
"citty": "^0.1.6",
|