@rk0429/agentic-relay 0.12.3 → 0.14.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 +54 -36
- package/package.json +1 -1
package/dist/relay.mjs
CHANGED
|
@@ -438,7 +438,11 @@ function buildChildMcpServers(parentMcpServers, childHttpUrl) {
|
|
|
438
438
|
}
|
|
439
439
|
return result;
|
|
440
440
|
}
|
|
441
|
-
function inferFailureReason(stderr, stdout) {
|
|
441
|
+
function inferFailureReason(stderr, stdout, sdkErrorMetadata) {
|
|
442
|
+
if (sdkErrorMetadata) {
|
|
443
|
+
if (sdkErrorMetadata.subtype === "error_max_turns") return "max_turns_exhausted";
|
|
444
|
+
return "adapter_error";
|
|
445
|
+
}
|
|
442
446
|
const combined = `${stderr} ${stdout}`.toLowerCase();
|
|
443
447
|
if (combined.includes("timed out") || combined.includes("timeout")) return "timeout";
|
|
444
448
|
if (combined.includes("max turns") || combined.includes("max_turns") || combined.includes("turn limit")) return "max_turns_exhausted";
|
|
@@ -452,8 +456,8 @@ function buildContextFromEnv() {
|
|
|
452
456
|
}
|
|
453
457
|
async function executeSpawnAgent(input, registry2, sessionManager2, guard, hooksEngine2, contextMonitor2, backendSelector, childHttpUrl, onProgress) {
|
|
454
458
|
onProgress?.({ stage: "initializing", percent: 0 });
|
|
455
|
-
let effectiveBackend
|
|
456
|
-
let selectionReason
|
|
459
|
+
let effectiveBackend;
|
|
460
|
+
let selectionReason;
|
|
457
461
|
if (backendSelector) {
|
|
458
462
|
const availableBackends = registry2.listIds();
|
|
459
463
|
const selectionContext = {
|
|
@@ -465,6 +469,12 @@ async function executeSpawnAgent(input, registry2, sessionManager2, guard, hooks
|
|
|
465
469
|
const selectionResult = backendSelector.selectBackendWithReason(selectionContext);
|
|
466
470
|
effectiveBackend = selectionResult.backend;
|
|
467
471
|
selectionReason = selectionResult.reason;
|
|
472
|
+
} else if (input.fallbackBackend) {
|
|
473
|
+
effectiveBackend = input.fallbackBackend;
|
|
474
|
+
selectionReason = "fallbackBackend";
|
|
475
|
+
} else {
|
|
476
|
+
effectiveBackend = "claude";
|
|
477
|
+
selectionReason = "default(no-selector)";
|
|
468
478
|
}
|
|
469
479
|
const envContext = buildContextFromEnv();
|
|
470
480
|
const promptHash = RecursionGuard.hashPrompt(input.prompt);
|
|
@@ -667,22 +677,11 @@ ${input.prompt}`;
|
|
|
667
677
|
maxDepth: guard.getConfig().maxDepth,
|
|
668
678
|
traceId: envContext.traceId
|
|
669
679
|
},
|
|
670
|
-
...mcpServers ? { mcpServers } : {}
|
|
671
|
-
...input.timeoutMs ? { timeoutMs: input.timeoutMs } : {}
|
|
680
|
+
...mcpServers ? { mcpServers } : {}
|
|
672
681
|
});
|
|
673
682
|
}
|
|
674
683
|
})();
|
|
675
|
-
|
|
676
|
-
const timeoutPromise = new Promise(
|
|
677
|
-
(_, reject) => setTimeout(
|
|
678
|
-
() => reject(new Error(`Agent execution timed out after ${input.timeoutMs}ms`)),
|
|
679
|
-
input.timeoutMs
|
|
680
|
-
)
|
|
681
|
-
);
|
|
682
|
-
result = await Promise.race([executePromise, timeoutPromise]);
|
|
683
|
-
} else {
|
|
684
|
-
result = await executePromise;
|
|
685
|
-
}
|
|
684
|
+
result = await executePromise;
|
|
686
685
|
if (result && "_noSession" in result) {
|
|
687
686
|
return {
|
|
688
687
|
sessionId: session.relaySessionId,
|
|
@@ -705,7 +704,7 @@ ${input.prompt}`;
|
|
|
705
704
|
}
|
|
706
705
|
guard.recordSpawn(context);
|
|
707
706
|
const status = result.exitCode === 0 ? "completed" : "error";
|
|
708
|
-
const failureReason = result.exitCode !== 0 ? inferFailureReason(result.stderr, result.stdout) : void 0;
|
|
707
|
+
const failureReason = result.exitCode !== 0 ? inferFailureReason(result.stderr, result.stdout, result.sdkErrorMetadata) : void 0;
|
|
709
708
|
await sessionManager2.update(session.relaySessionId, {
|
|
710
709
|
status,
|
|
711
710
|
...result.nativeSessionId ? { nativeSessionId: result.nativeSessionId } : {}
|
|
@@ -781,8 +780,8 @@ var init_spawn_agent = __esm({
|
|
|
781
780
|
init_recursion_guard();
|
|
782
781
|
init_logger();
|
|
783
782
|
spawnAgentInputSchema = z2.object({
|
|
784
|
-
|
|
785
|
-
"
|
|
783
|
+
fallbackBackend: z2.enum(["claude", "codex", "gemini"]).optional().describe(
|
|
784
|
+
"Optional fallback backend. Used only when BackendSelector is not active or cannot determine a backend. When BackendSelector is active, backend is auto-selected by priority: preferredBackend > agentType mapping > taskType mapping > default (claude)."
|
|
786
785
|
),
|
|
787
786
|
prompt: z2.string().describe(
|
|
788
787
|
"The task instruction for the sub-agent. Be specific and include all necessary context for autonomous execution."
|
|
@@ -815,7 +814,6 @@ var init_spawn_agent = __esm({
|
|
|
815
814
|
taskType: z2.enum(["code-writing", "code-review", "document-writing", "document-review", "research", "mixed"]).optional().describe(
|
|
816
815
|
"Task type hint for automatic backend selection (priority 3, after preferredBackend and agentType). Mapping: code-writing\u2192codex, code-review\u2192claude, document-writing\u2192claude, document-review\u2192codex, research\u2192codex, mixed\u2192claude."
|
|
817
816
|
),
|
|
818
|
-
timeoutMs: z2.number().optional().describe("Timeout in milliseconds for agent execution. Default: no timeout."),
|
|
819
817
|
taskInstructionPath: z2.string().optional().describe(
|
|
820
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."
|
|
821
819
|
),
|
|
@@ -1324,7 +1322,7 @@ var init_server = __esm({
|
|
|
1324
1322
|
this.guard = new RecursionGuard(guardConfig);
|
|
1325
1323
|
this.backendSelector = new BackendSelector();
|
|
1326
1324
|
this.server = new McpServer(
|
|
1327
|
-
{ name: "agentic-relay", version: "0.
|
|
1325
|
+
{ name: "agentic-relay", version: "0.14.0" },
|
|
1328
1326
|
createMcpServerOptions()
|
|
1329
1327
|
);
|
|
1330
1328
|
this.registerTools(this.server);
|
|
@@ -1499,7 +1497,6 @@ var init_server = __esm({
|
|
|
1499
1497
|
})).min(1).describe("Array of failed results with their original input configurations"),
|
|
1500
1498
|
overrides: z5.object({
|
|
1501
1499
|
maxTurns: z5.number().optional(),
|
|
1502
|
-
timeoutMs: z5.number().optional(),
|
|
1503
1500
|
preferredBackend: z5.enum(["claude", "codex", "gemini"]).optional()
|
|
1504
1501
|
}).optional().describe("Parameter overrides applied to all retried agents")
|
|
1505
1502
|
},
|
|
@@ -1509,7 +1506,6 @@ var init_server = __esm({
|
|
|
1509
1506
|
const input = { ...r.originalInput };
|
|
1510
1507
|
if (params.overrides) {
|
|
1511
1508
|
if (params.overrides.maxTurns !== void 0) input.maxTurns = params.overrides.maxTurns;
|
|
1512
|
-
if (params.overrides.timeoutMs !== void 0) input.timeoutMs = params.overrides.timeoutMs;
|
|
1513
1509
|
if (params.overrides.preferredBackend !== void 0) input.preferredBackend = params.overrides.preferredBackend;
|
|
1514
1510
|
}
|
|
1515
1511
|
return input;
|
|
@@ -1688,7 +1684,7 @@ var init_server = __esm({
|
|
|
1688
1684
|
sessionIdGenerator: () => randomUUID()
|
|
1689
1685
|
});
|
|
1690
1686
|
const server = new McpServer(
|
|
1691
|
-
{ name: "agentic-relay", version: "0.
|
|
1687
|
+
{ name: "agentic-relay", version: "0.14.0" },
|
|
1692
1688
|
createMcpServerOptions()
|
|
1693
1689
|
);
|
|
1694
1690
|
this.registerTools(server);
|
|
@@ -2053,10 +2049,7 @@ var CLAUDE_NESTING_ENV_VARS = [
|
|
|
2053
2049
|
"CLAUDE_CODE_SSE_PORT",
|
|
2054
2050
|
"CLAUDE_CODE_ENTRYPOINT"
|
|
2055
2051
|
];
|
|
2056
|
-
function resolveClaudeSdkTimeoutMs(
|
|
2057
|
-
if (flagsTimeoutMs !== void 0 && flagsTimeoutMs > 0) {
|
|
2058
|
-
return flagsTimeoutMs;
|
|
2059
|
-
}
|
|
2052
|
+
function resolveClaudeSdkTimeoutMs() {
|
|
2060
2053
|
const envVal = process.env["RELAY_CLAUDE_TIMEOUT_MS"];
|
|
2061
2054
|
if (envVal) {
|
|
2062
2055
|
const parsed = Number(envVal);
|
|
@@ -2103,7 +2096,7 @@ var ClaudeAdapter = class extends BaseAdapter {
|
|
|
2103
2096
|
}
|
|
2104
2097
|
const env = this.buildCleanEnv(flags);
|
|
2105
2098
|
const permissionMode = this.getPermissionMode();
|
|
2106
|
-
const timeoutMs = resolveClaudeSdkTimeoutMs(
|
|
2099
|
+
const timeoutMs = resolveClaudeSdkTimeoutMs();
|
|
2107
2100
|
const abortController = new AbortController();
|
|
2108
2101
|
const timer = timeoutMs !== void 0 ? setTimeout(() => abortController.abort(), timeoutMs) : void 0;
|
|
2109
2102
|
try {
|
|
@@ -2132,6 +2125,7 @@ var ClaudeAdapter = class extends BaseAdapter {
|
|
|
2132
2125
|
let errorMessages = [];
|
|
2133
2126
|
let totalInputTokens = 0;
|
|
2134
2127
|
let totalOutputTokens = 0;
|
|
2128
|
+
let sdkError = null;
|
|
2135
2129
|
for await (const message of q) {
|
|
2136
2130
|
if (message.type === "assistant") {
|
|
2137
2131
|
const betaMessage = message.message;
|
|
@@ -2146,18 +2140,32 @@ var ClaudeAdapter = class extends BaseAdapter {
|
|
|
2146
2140
|
resultText = message.result;
|
|
2147
2141
|
} else {
|
|
2148
2142
|
isError = true;
|
|
2149
|
-
|
|
2143
|
+
sdkError = message;
|
|
2144
|
+
errorMessages = sdkError.errors;
|
|
2150
2145
|
}
|
|
2151
2146
|
}
|
|
2152
2147
|
}
|
|
2153
2148
|
logger.debug(`Claude SDK session: ${sessionId}`);
|
|
2149
|
+
if (sdkError) {
|
|
2150
|
+
logger.warn(
|
|
2151
|
+
`Claude SDK error: subtype=${sdkError.subtype} stop_reason=${sdkError.stop_reason} num_turns=${sdkError.num_turns} errors=[${sdkError.errors.join("; ")}]`
|
|
2152
|
+
);
|
|
2153
|
+
}
|
|
2154
2154
|
const hasTokenUsage = totalInputTokens > 0 || totalOutputTokens > 0;
|
|
2155
2155
|
return {
|
|
2156
2156
|
exitCode: isError ? 1 : 0,
|
|
2157
2157
|
stdout: resultText,
|
|
2158
2158
|
stderr: errorMessages.join("\n"),
|
|
2159
2159
|
...sessionId ? { nativeSessionId: sessionId } : {},
|
|
2160
|
-
...hasTokenUsage ? { tokenUsage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens } } : {}
|
|
2160
|
+
...hasTokenUsage ? { tokenUsage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens } } : {},
|
|
2161
|
+
...sdkError ? {
|
|
2162
|
+
sdkErrorMetadata: {
|
|
2163
|
+
subtype: sdkError.subtype,
|
|
2164
|
+
numTurns: sdkError.num_turns,
|
|
2165
|
+
stopReason: sdkError.stop_reason,
|
|
2166
|
+
totalCostUsd: sdkError.total_cost_usd
|
|
2167
|
+
}
|
|
2168
|
+
} : {}
|
|
2161
2169
|
};
|
|
2162
2170
|
} catch (error) {
|
|
2163
2171
|
if (abortController.signal.aborted) {
|
|
@@ -2182,7 +2190,7 @@ var ClaudeAdapter = class extends BaseAdapter {
|
|
|
2182
2190
|
}
|
|
2183
2191
|
const env = this.buildCleanEnv(flags);
|
|
2184
2192
|
const permissionMode = this.getPermissionMode();
|
|
2185
|
-
const timeoutMs = resolveClaudeSdkTimeoutMs(
|
|
2193
|
+
const timeoutMs = resolveClaudeSdkTimeoutMs();
|
|
2186
2194
|
const abortController = new AbortController();
|
|
2187
2195
|
const timer = timeoutMs !== void 0 ? setTimeout(() => abortController.abort(), timeoutMs) : void 0;
|
|
2188
2196
|
try {
|
|
@@ -2238,13 +2246,23 @@ var ClaudeAdapter = class extends BaseAdapter {
|
|
|
2238
2246
|
nativeSessionId
|
|
2239
2247
|
};
|
|
2240
2248
|
} else {
|
|
2241
|
-
const
|
|
2249
|
+
const sdkError = message;
|
|
2250
|
+
const errors = sdkError.errors;
|
|
2251
|
+
logger.warn(
|
|
2252
|
+
`Claude SDK error: subtype=${sdkError.subtype} stop_reason=${sdkError.stop_reason} num_turns=${sdkError.num_turns} errors=[${sdkError.errors.join("; ")}]`
|
|
2253
|
+
);
|
|
2242
2254
|
yield {
|
|
2243
2255
|
type: "done",
|
|
2244
2256
|
result: {
|
|
2245
2257
|
exitCode: 1,
|
|
2246
2258
|
stdout: "",
|
|
2247
|
-
stderr: errors.join("\n")
|
|
2259
|
+
stderr: errors.join("\n"),
|
|
2260
|
+
sdkErrorMetadata: {
|
|
2261
|
+
subtype: sdkError.subtype,
|
|
2262
|
+
numTurns: sdkError.num_turns,
|
|
2263
|
+
stopReason: sdkError.stop_reason,
|
|
2264
|
+
totalCostUsd: sdkError.total_cost_usd
|
|
2265
|
+
}
|
|
2248
2266
|
},
|
|
2249
2267
|
nativeSessionId
|
|
2250
2268
|
};
|
|
@@ -4640,7 +4658,7 @@ function createVersionCommand(registry2) {
|
|
|
4640
4658
|
description: "Show relay and backend versions"
|
|
4641
4659
|
},
|
|
4642
4660
|
async run() {
|
|
4643
|
-
const relayVersion = "0.
|
|
4661
|
+
const relayVersion = "0.14.0";
|
|
4644
4662
|
console.log(`agentic-relay v${relayVersion}`);
|
|
4645
4663
|
console.log("");
|
|
4646
4664
|
console.log("Backends:");
|
|
@@ -4990,7 +5008,7 @@ void configManager.getConfig().then((config) => {
|
|
|
4990
5008
|
var main = defineCommand10({
|
|
4991
5009
|
meta: {
|
|
4992
5010
|
name: "relay",
|
|
4993
|
-
version: "0.
|
|
5011
|
+
version: "0.14.0",
|
|
4994
5012
|
description: "Unified CLI proxy for Claude Code, Codex CLI, and Gemini CLI"
|
|
4995
5013
|
},
|
|
4996
5014
|
subCommands: {
|
package/package.json
CHANGED