@rk0429/agentic-relay 2.0.9 → 2.0.10
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 +199 -57
- package/package.json +1 -1
package/dist/relay.mjs
CHANGED
|
@@ -1267,7 +1267,10 @@ ${input.prompt}`;
|
|
|
1267
1267
|
} else {
|
|
1268
1268
|
effectiveNativeSessionId = input.resumeSessionId;
|
|
1269
1269
|
}
|
|
1270
|
-
return adapter.continueSession(effectiveNativeSessionId, effectivePrompt
|
|
1270
|
+
return adapter.continueSession(effectiveNativeSessionId, effectivePrompt, {
|
|
1271
|
+
...input.model ? { model: input.model } : {},
|
|
1272
|
+
...signal ? { signal } : {}
|
|
1273
|
+
});
|
|
1271
1274
|
} else {
|
|
1272
1275
|
let mcpServers;
|
|
1273
1276
|
if (childHttpUrl) {
|
|
@@ -8310,7 +8313,7 @@ var init_server = __esm({
|
|
|
8310
8313
|
this.agentEventStore
|
|
8311
8314
|
);
|
|
8312
8315
|
this.server = new McpServer(
|
|
8313
|
-
{ name: "agentic-relay", version: "2.0.
|
|
8316
|
+
{ name: "agentic-relay", version: "2.0.10" }
|
|
8314
8317
|
);
|
|
8315
8318
|
this.registerTools(this.server);
|
|
8316
8319
|
this.sessionHealthMonitor.start();
|
|
@@ -8742,7 +8745,7 @@ var init_server = __esm({
|
|
|
8742
8745
|
sessionIdGenerator: () => randomUUID()
|
|
8743
8746
|
});
|
|
8744
8747
|
const server = new McpServer(
|
|
8745
|
-
{ name: "agentic-relay", version: "2.0.
|
|
8748
|
+
{ name: "agentic-relay", version: "2.0.10" }
|
|
8746
8749
|
);
|
|
8747
8750
|
this.registerTools(server, childRelayContext, abortController.signal);
|
|
8748
8751
|
transport.onclose = () => {
|
|
@@ -10080,6 +10083,18 @@ import { homedir as homedir7 } from "os";
|
|
|
10080
10083
|
// src/infrastructure/process-manager.ts
|
|
10081
10084
|
init_logger();
|
|
10082
10085
|
import { execa } from "execa";
|
|
10086
|
+
function toProcessResultFromError(error) {
|
|
10087
|
+
const exitCode = typeof error === "object" && error !== null && "exitCode" in error && typeof error.exitCode === "number" ? error.exitCode : 1;
|
|
10088
|
+
const stdout = typeof error === "object" && error !== null && "stdout" in error && typeof error.stdout === "string" ? error.stdout : "";
|
|
10089
|
+
const stderr = typeof error === "object" && error !== null && "stderr" in error && typeof error.stderr === "string" && error.stderr.length > 0 ? error.stderr : error instanceof Error ? error.message : String(error);
|
|
10090
|
+
return { exitCode, stdout, stderr };
|
|
10091
|
+
}
|
|
10092
|
+
function getCanceledMessage(signal) {
|
|
10093
|
+
if (!signal?.aborted) {
|
|
10094
|
+
return "";
|
|
10095
|
+
}
|
|
10096
|
+
return signal.reason instanceof Error ? signal.reason.message : typeof signal.reason === "string" ? signal.reason : "";
|
|
10097
|
+
}
|
|
10083
10098
|
var ProcessManager = class {
|
|
10084
10099
|
activeProcesses = /* @__PURE__ */ new Set();
|
|
10085
10100
|
constructor() {
|
|
@@ -10093,6 +10108,7 @@ var ProcessManager = class {
|
|
|
10093
10108
|
env: options?.env,
|
|
10094
10109
|
extendEnv: options?.env ? false : true,
|
|
10095
10110
|
timeout: options?.timeout,
|
|
10111
|
+
cancelSignal: options?.signal,
|
|
10096
10112
|
reject: false
|
|
10097
10113
|
};
|
|
10098
10114
|
const proc = execa(command, args, execaOptions);
|
|
@@ -10113,6 +10129,7 @@ var ProcessManager = class {
|
|
|
10113
10129
|
env: options?.env,
|
|
10114
10130
|
extendEnv: options?.env ? false : true,
|
|
10115
10131
|
timeout: options?.timeout,
|
|
10132
|
+
cancelSignal: options?.signal,
|
|
10116
10133
|
reject: false
|
|
10117
10134
|
};
|
|
10118
10135
|
const proc = execa(command, args, execaOptions);
|
|
@@ -10122,8 +10139,10 @@ var ProcessManager = class {
|
|
|
10122
10139
|
return {
|
|
10123
10140
|
exitCode: result.exitCode ?? 1,
|
|
10124
10141
|
stdout: result.stdout?.toString() ?? "",
|
|
10125
|
-
stderr: result.stderr?.toString()
|
|
10142
|
+
stderr: result.stderr?.toString() || getCanceledMessage(options?.signal)
|
|
10126
10143
|
};
|
|
10144
|
+
} catch (error) {
|
|
10145
|
+
return toProcessResultFromError(error);
|
|
10127
10146
|
} finally {
|
|
10128
10147
|
this.activeProcesses.delete(proc);
|
|
10129
10148
|
}
|
|
@@ -10135,7 +10154,9 @@ var ProcessManager = class {
|
|
|
10135
10154
|
input: stdinData,
|
|
10136
10155
|
cwd: options?.cwd,
|
|
10137
10156
|
env: options?.env,
|
|
10157
|
+
extendEnv: options?.env ? false : true,
|
|
10138
10158
|
timeout: options?.timeout,
|
|
10159
|
+
cancelSignal: options?.signal,
|
|
10139
10160
|
reject: false
|
|
10140
10161
|
};
|
|
10141
10162
|
const proc = execa(command, args, execaOptions);
|
|
@@ -10145,8 +10166,10 @@ var ProcessManager = class {
|
|
|
10145
10166
|
return {
|
|
10146
10167
|
exitCode: result.exitCode ?? 1,
|
|
10147
10168
|
stdout: result.stdout?.toString() ?? "",
|
|
10148
|
-
stderr: result.stderr?.toString()
|
|
10169
|
+
stderr: result.stderr?.toString() || getCanceledMessage(options?.signal)
|
|
10149
10170
|
};
|
|
10171
|
+
} catch (error) {
|
|
10172
|
+
return toProcessResultFromError(error);
|
|
10150
10173
|
} finally {
|
|
10151
10174
|
this.activeProcesses.delete(proc);
|
|
10152
10175
|
}
|
|
@@ -10235,7 +10258,7 @@ var BaseAdapter = class _BaseAdapter {
|
|
|
10235
10258
|
}
|
|
10236
10259
|
return result.stdout.trim();
|
|
10237
10260
|
}
|
|
10238
|
-
async continueSession(_nativeSessionId, _prompt) {
|
|
10261
|
+
async continueSession(_nativeSessionId, _prompt, _options) {
|
|
10239
10262
|
return {
|
|
10240
10263
|
exitCode: 1,
|
|
10241
10264
|
stdout: "",
|
|
@@ -10624,9 +10647,11 @@ var ClaudeAdapter = class extends BaseAdapter {
|
|
|
10624
10647
|
if (timer !== void 0) clearTimeout(timer);
|
|
10625
10648
|
}
|
|
10626
10649
|
}
|
|
10627
|
-
async continueSession(nativeSessionId, prompt) {
|
|
10650
|
+
async continueSession(nativeSessionId, prompt, options) {
|
|
10628
10651
|
const timeoutMs = resolveClaudeSdkTimeoutMs();
|
|
10629
10652
|
const abortController = new AbortController();
|
|
10653
|
+
const onAbort = () => abortController.abort();
|
|
10654
|
+
options?.signal?.addEventListener("abort", onAbort, { once: true });
|
|
10630
10655
|
const timer = timeoutMs !== void 0 ? setTimeout(() => abortController.abort(), timeoutMs) : void 0;
|
|
10631
10656
|
try {
|
|
10632
10657
|
const { query } = await loadClaudeSDK();
|
|
@@ -10675,6 +10700,7 @@ var ClaudeAdapter = class extends BaseAdapter {
|
|
|
10675
10700
|
stderr: error instanceof Error ? error.message : String(error)
|
|
10676
10701
|
};
|
|
10677
10702
|
} finally {
|
|
10703
|
+
options?.signal?.removeEventListener("abort", onAbort);
|
|
10678
10704
|
if (timer !== void 0) clearTimeout(timer);
|
|
10679
10705
|
}
|
|
10680
10706
|
}
|
|
@@ -10777,8 +10803,8 @@ var ClaudeAdapter = class extends BaseAdapter {
|
|
|
10777
10803
|
|
|
10778
10804
|
// src/adapters/codex-adapter.ts
|
|
10779
10805
|
init_logger();
|
|
10780
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, mkdtemp, copyFile } from "fs/promises";
|
|
10781
|
-
import { homedir as homedir2 } from "os";
|
|
10806
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, mkdtemp, copyFile, rm } from "fs/promises";
|
|
10807
|
+
import { homedir as homedir2, tmpdir } from "os";
|
|
10782
10808
|
import { join as join2, dirname as dirname2 } from "path";
|
|
10783
10809
|
async function loadCodexSDK() {
|
|
10784
10810
|
return await import("@openai/codex-sdk");
|
|
@@ -10964,6 +10990,70 @@ async function copyIfExists(from, to) {
|
|
|
10964
10990
|
throw error;
|
|
10965
10991
|
}
|
|
10966
10992
|
}
|
|
10993
|
+
async function readFileIfExists(path3) {
|
|
10994
|
+
try {
|
|
10995
|
+
return await readFile2(path3, "utf-8");
|
|
10996
|
+
} catch (error) {
|
|
10997
|
+
if (isFileNotFoundError(error)) {
|
|
10998
|
+
return void 0;
|
|
10999
|
+
}
|
|
11000
|
+
throw error;
|
|
11001
|
+
}
|
|
11002
|
+
}
|
|
11003
|
+
function parseCodexExecJson(stdout) {
|
|
11004
|
+
const parsed = {
|
|
11005
|
+
completedMessages: [],
|
|
11006
|
+
errorMessages: []
|
|
11007
|
+
};
|
|
11008
|
+
for (const rawLine of stdout.split(/\r?\n/)) {
|
|
11009
|
+
const line = rawLine.trim();
|
|
11010
|
+
if (!line) continue;
|
|
11011
|
+
let event;
|
|
11012
|
+
try {
|
|
11013
|
+
event = JSON.parse(line);
|
|
11014
|
+
} catch {
|
|
11015
|
+
continue;
|
|
11016
|
+
}
|
|
11017
|
+
if (typeof event !== "object" || event === null || !("type" in event) || typeof event.type !== "string") {
|
|
11018
|
+
continue;
|
|
11019
|
+
}
|
|
11020
|
+
switch (event.type) {
|
|
11021
|
+
case "thread.started":
|
|
11022
|
+
if ("thread_id" in event && typeof event.thread_id === "string") {
|
|
11023
|
+
parsed.threadId = event.thread_id;
|
|
11024
|
+
}
|
|
11025
|
+
break;
|
|
11026
|
+
case "item.completed":
|
|
11027
|
+
if ("item" in event && typeof event.item === "object" && event.item !== null && "type" in event.item && event.item.type === "agent_message" && "text" in event.item && typeof event.item.text === "string") {
|
|
11028
|
+
parsed.completedMessages.push(event.item.text);
|
|
11029
|
+
}
|
|
11030
|
+
break;
|
|
11031
|
+
case "turn.completed":
|
|
11032
|
+
if ("usage" in event && typeof event.usage === "object" && event.usage !== null) {
|
|
11033
|
+
const cachedInputTokens = "cached_input_tokens" in event.usage && typeof event.usage.cached_input_tokens === "number" ? event.usage.cached_input_tokens : 0;
|
|
11034
|
+
parsed.tokenUsage = {
|
|
11035
|
+
inputTokens: ("input_tokens" in event.usage && typeof event.usage.input_tokens === "number" ? event.usage.input_tokens : 0) + cachedInputTokens,
|
|
11036
|
+
outputTokens: "output_tokens" in event.usage && typeof event.usage.output_tokens === "number" ? event.usage.output_tokens : 0,
|
|
11037
|
+
...cachedInputTokens > 0 ? { cachedInputTokens } : {}
|
|
11038
|
+
};
|
|
11039
|
+
}
|
|
11040
|
+
break;
|
|
11041
|
+
case "turn.failed":
|
|
11042
|
+
if ("error" in event && typeof event.error === "object" && event.error !== null && "message" in event.error && typeof event.error.message === "string") {
|
|
11043
|
+
parsed.failureMessage = event.error.message;
|
|
11044
|
+
}
|
|
11045
|
+
break;
|
|
11046
|
+
case "error":
|
|
11047
|
+
if ("message" in event && typeof event.message === "string") {
|
|
11048
|
+
parsed.errorMessages.push(event.message);
|
|
11049
|
+
}
|
|
11050
|
+
break;
|
|
11051
|
+
default:
|
|
11052
|
+
break;
|
|
11053
|
+
}
|
|
11054
|
+
}
|
|
11055
|
+
return parsed;
|
|
11056
|
+
}
|
|
10967
11057
|
var CodexAdapter = class extends BaseAdapter {
|
|
10968
11058
|
id = "codex";
|
|
10969
11059
|
command = "codex";
|
|
@@ -11097,6 +11187,62 @@ ${systemPrompt}
|
|
|
11097
11187
|
[User Request]
|
|
11098
11188
|
${prompt}`;
|
|
11099
11189
|
}
|
|
11190
|
+
shouldHardenRelayChild(flags) {
|
|
11191
|
+
return Boolean(
|
|
11192
|
+
flags.mcpContext || flags.mcpServers && Object.keys(flags.mcpServers).length > 0
|
|
11193
|
+
);
|
|
11194
|
+
}
|
|
11195
|
+
buildCodexExecBaseArgs(model, hardenRelayChild) {
|
|
11196
|
+
const args = [
|
|
11197
|
+
"-a",
|
|
11198
|
+
"never",
|
|
11199
|
+
"-C",
|
|
11200
|
+
process.cwd()
|
|
11201
|
+
];
|
|
11202
|
+
if (model) {
|
|
11203
|
+
args.unshift(model);
|
|
11204
|
+
args.unshift("--model");
|
|
11205
|
+
}
|
|
11206
|
+
if (hardenRelayChild) {
|
|
11207
|
+
args.push("-c", "project_root_markers=[]");
|
|
11208
|
+
}
|
|
11209
|
+
return args;
|
|
11210
|
+
}
|
|
11211
|
+
async runCodexExecCommand(args, prompt, env, signal, isolatedCodexHome, fallbackNativeSessionId) {
|
|
11212
|
+
const execTempDir = await mkdtemp(join2(tmpdir(), "relay-codex-exec-"));
|
|
11213
|
+
const outputPath = join2(execTempDir, "last-message.txt");
|
|
11214
|
+
try {
|
|
11215
|
+
const result = await this.processManager.executeWithInput(
|
|
11216
|
+
this.command,
|
|
11217
|
+
[...args, "--json", "-o", outputPath, "-"],
|
|
11218
|
+
prompt,
|
|
11219
|
+
{ env, signal }
|
|
11220
|
+
);
|
|
11221
|
+
const parsed = parseCodexExecJson(result.stdout);
|
|
11222
|
+
const outputFileContent = await readFileIfExists(outputPath);
|
|
11223
|
+
const finalResponse = outputFileContent ?? parsed.completedMessages.join("\n");
|
|
11224
|
+
const nativeSessionId = parsed.threadId ? encodeNativeSessionId(parsed.threadId, isolatedCodexHome) : fallbackNativeSessionId;
|
|
11225
|
+
if (result.exitCode === 0) {
|
|
11226
|
+
return {
|
|
11227
|
+
exitCode: 0,
|
|
11228
|
+
stdout: finalResponse,
|
|
11229
|
+
stderr: "",
|
|
11230
|
+
...nativeSessionId ? { nativeSessionId } : {},
|
|
11231
|
+
...parsed.tokenUsage ? { tokenUsage: parsed.tokenUsage } : {}
|
|
11232
|
+
};
|
|
11233
|
+
}
|
|
11234
|
+
const stderr = signal?.aborted ? "Codex execution cancelled: parent session disconnected" : parsed.failureMessage ?? parsed.errorMessages.at(-1) ?? (result.stderr || "Codex execution failed");
|
|
11235
|
+
return {
|
|
11236
|
+
exitCode: result.exitCode || 1,
|
|
11237
|
+
stdout: finalResponse,
|
|
11238
|
+
stderr,
|
|
11239
|
+
...nativeSessionId ? { nativeSessionId } : {},
|
|
11240
|
+
...parsed.tokenUsage ? { tokenUsage: parsed.tokenUsage } : {}
|
|
11241
|
+
};
|
|
11242
|
+
} finally {
|
|
11243
|
+
await rm(execTempDir, { recursive: true, force: true }).catch(() => void 0);
|
|
11244
|
+
}
|
|
11245
|
+
}
|
|
11100
11246
|
async execute(flags) {
|
|
11101
11247
|
if (!flags.prompt) {
|
|
11102
11248
|
throw new Error("execute requires a prompt (-p flag)");
|
|
@@ -11107,28 +11253,22 @@ ${prompt}`;
|
|
|
11107
11253
|
systemPrompt
|
|
11108
11254
|
);
|
|
11109
11255
|
try {
|
|
11110
|
-
const { Codex } = await loadCodexSDK();
|
|
11111
11256
|
const { options, isolatedCodexHome } = await this.buildCodexOptions(flags);
|
|
11112
|
-
const
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
|
|
11123
|
-
|
|
11124
|
-
|
|
11125
|
-
|
|
11126
|
-
|
|
11127
|
-
thread.id,
|
|
11128
|
-
isolatedCodexHome
|
|
11129
|
-
)
|
|
11130
|
-
} : {}
|
|
11131
|
-
};
|
|
11257
|
+
const args = this.buildCodexExecBaseArgs(
|
|
11258
|
+
flags.model,
|
|
11259
|
+
this.shouldHardenRelayChild(flags)
|
|
11260
|
+
);
|
|
11261
|
+
args.push("exec");
|
|
11262
|
+
if (this.shouldHardenRelayChild(flags)) {
|
|
11263
|
+
args.push("--disable", "multi_agent");
|
|
11264
|
+
}
|
|
11265
|
+
return await this.runCodexExecCommand(
|
|
11266
|
+
args,
|
|
11267
|
+
effectivePrompt,
|
|
11268
|
+
options.env,
|
|
11269
|
+
flags.signal,
|
|
11270
|
+
isolatedCodexHome
|
|
11271
|
+
);
|
|
11132
11272
|
} catch (error) {
|
|
11133
11273
|
if (flags.signal?.aborted) {
|
|
11134
11274
|
return {
|
|
@@ -11248,34 +11388,36 @@ ${prompt}`;
|
|
|
11248
11388
|
};
|
|
11249
11389
|
}
|
|
11250
11390
|
}
|
|
11251
|
-
async continueSession(nativeSessionId, prompt) {
|
|
11391
|
+
async continueSession(nativeSessionId, prompt, options) {
|
|
11252
11392
|
try {
|
|
11253
|
-
const { Codex } = await loadCodexSDK();
|
|
11254
11393
|
const { threadId, codexHome } = decodeNativeSessionId(nativeSessionId);
|
|
11255
|
-
const
|
|
11256
|
-
|
|
11257
|
-
env
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11263
|
-
|
|
11264
|
-
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
|
|
11268
|
-
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
const result = await thread.run(prompt);
|
|
11272
|
-
return {
|
|
11273
|
-
exitCode: 0,
|
|
11274
|
-
stdout: result.finalResponse,
|
|
11275
|
-
stderr: "",
|
|
11394
|
+
const env = codexHome ? {
|
|
11395
|
+
...Object.fromEntries(
|
|
11396
|
+
Object.entries(process.env).filter(
|
|
11397
|
+
([, value]) => value !== void 0
|
|
11398
|
+
)
|
|
11399
|
+
),
|
|
11400
|
+
CODEX_HOME: codexHome
|
|
11401
|
+
} : void 0;
|
|
11402
|
+
const args = this.buildCodexExecBaseArgs(options?.model, true);
|
|
11403
|
+
args.push("exec", "resume", "--disable", "multi_agent", threadId);
|
|
11404
|
+
return await this.runCodexExecCommand(
|
|
11405
|
+
args,
|
|
11406
|
+
prompt,
|
|
11407
|
+
env,
|
|
11408
|
+
options?.signal,
|
|
11409
|
+
codexHome,
|
|
11276
11410
|
nativeSessionId
|
|
11277
|
-
|
|
11411
|
+
);
|
|
11278
11412
|
} catch (error) {
|
|
11413
|
+
if (options?.signal?.aborted) {
|
|
11414
|
+
return {
|
|
11415
|
+
exitCode: 1,
|
|
11416
|
+
stdout: "",
|
|
11417
|
+
stderr: "Codex execution cancelled: parent session disconnected",
|
|
11418
|
+
nativeSessionId
|
|
11419
|
+
};
|
|
11420
|
+
}
|
|
11279
11421
|
return {
|
|
11280
11422
|
exitCode: 1,
|
|
11281
11423
|
stdout: "",
|
|
@@ -13386,7 +13528,7 @@ function createMCPCommand(configManager2, registry2, sessionManager2, hooksEngin
|
|
|
13386
13528
|
responseOutputDir,
|
|
13387
13529
|
relayConfig
|
|
13388
13530
|
);
|
|
13389
|
-
await server.start({ transport, port, currentVersion: "2.0.
|
|
13531
|
+
await server.start({ transport, port, currentVersion: "2.0.10" });
|
|
13390
13532
|
}
|
|
13391
13533
|
})
|
|
13392
13534
|
},
|
|
@@ -13546,7 +13688,7 @@ function createVersionCommand(registry2) {
|
|
|
13546
13688
|
description: "Show relay and backend versions"
|
|
13547
13689
|
},
|
|
13548
13690
|
async run() {
|
|
13549
|
-
const relayVersion = "2.0.
|
|
13691
|
+
const relayVersion = "2.0.10";
|
|
13550
13692
|
console.log(`agentic-relay v${relayVersion}`);
|
|
13551
13693
|
console.log("");
|
|
13552
13694
|
console.log("Backends:");
|
|
@@ -13943,7 +14085,7 @@ var subCommandNames = /* @__PURE__ */ new Set(["claude", "codex", "gemini", "upd
|
|
|
13943
14085
|
var main = defineCommand11({
|
|
13944
14086
|
meta: {
|
|
13945
14087
|
name: "relay",
|
|
13946
|
-
version: "2.0.
|
|
14088
|
+
version: "2.0.10",
|
|
13947
14089
|
description: "Unified CLI proxy for Claude Code, Codex CLI, and Gemini CLI"
|
|
13948
14090
|
},
|
|
13949
14091
|
args: {
|
package/package.json
CHANGED