@agentrq/codex-gateway 0.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/LICENSE +201 -0
- package/README.md +186 -0
- package/dist/__tests__/codexClient.test.js +290 -0
- package/dist/__tests__/codexClient.test.js.map +1 -0
- package/dist/__tests__/config.test.js +103 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/index.test.js +298 -0
- package/dist/__tests__/index.test.js.map +1 -0
- package/dist/__tests__/taskIdentity.test.js +47 -0
- package/dist/__tests__/taskIdentity.test.js.map +1 -0
- package/dist/codexClient.js +157 -0
- package/dist/codexClient.js.map +1 -0
- package/dist/config.js +57 -0
- package/dist/config.js.map +1 -0
- package/dist/index.js +186 -0
- package/dist/index.js.map +1 -0
- package/dist/mcpClient.js +164 -0
- package/dist/mcpClient.js.map +1 -0
- package/dist/taskIdentity.js +28 -0
- package/dist/taskIdentity.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* codexClient.ts
|
|
3
|
+
*
|
|
4
|
+
* JSON-RPC 2.0 client for the Codex app server.
|
|
5
|
+
* Communicates over stdio (JSONL) — the wire format omits the "jsonrpc":"2.0" header
|
|
6
|
+
* as documented in the Codex app-server protocol spec.
|
|
7
|
+
*/
|
|
8
|
+
import { spawn } from "node:child_process";
|
|
9
|
+
import * as readline from "node:readline";
|
|
10
|
+
import { EventEmitter } from "node:events";
|
|
11
|
+
export class CodexClient extends EventEmitter {
|
|
12
|
+
command;
|
|
13
|
+
cmdArgs;
|
|
14
|
+
pendingRequests = new Map();
|
|
15
|
+
nextId = 1;
|
|
16
|
+
stdin = null;
|
|
17
|
+
process = null;
|
|
18
|
+
constructor(command = "codex", cmdArgs = ["app-server"]) {
|
|
19
|
+
super();
|
|
20
|
+
this.command = command;
|
|
21
|
+
this.cmdArgs = cmdArgs;
|
|
22
|
+
}
|
|
23
|
+
async start() {
|
|
24
|
+
const proc = spawn(this.command, this.cmdArgs, {
|
|
25
|
+
stdio: ["pipe", "pipe", "inherit"],
|
|
26
|
+
});
|
|
27
|
+
this.process = proc;
|
|
28
|
+
this.stdin = proc.stdin;
|
|
29
|
+
const rl = readline.createInterface({
|
|
30
|
+
input: proc.stdout,
|
|
31
|
+
crlfDelay: Infinity,
|
|
32
|
+
});
|
|
33
|
+
rl.on("line", (line) => {
|
|
34
|
+
const trimmed = line.trim();
|
|
35
|
+
if (!trimmed)
|
|
36
|
+
return;
|
|
37
|
+
try {
|
|
38
|
+
const msg = JSON.parse(trimmed);
|
|
39
|
+
this._handleMessage(msg);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
console.error("[codex] Failed to parse line:", trimmed.slice(0, 120), err);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
proc.on("exit", (code) => {
|
|
46
|
+
console.error(`[codex] Process exited with code ${code}`);
|
|
47
|
+
this.emit("exit", code);
|
|
48
|
+
});
|
|
49
|
+
await this._initialize();
|
|
50
|
+
}
|
|
51
|
+
async _initialize() {
|
|
52
|
+
await this._request("initialize", {
|
|
53
|
+
clientInfo: {
|
|
54
|
+
name: "codex-gateway",
|
|
55
|
+
title: "Codex Gateway for AgentRQ",
|
|
56
|
+
version: "0.1.0",
|
|
57
|
+
},
|
|
58
|
+
capabilities: {},
|
|
59
|
+
});
|
|
60
|
+
this._sendNotification("initialized");
|
|
61
|
+
console.error("[codex] Connected to codex app-server");
|
|
62
|
+
}
|
|
63
|
+
_handleMessage(msg) {
|
|
64
|
+
if ("id" in msg && msg.id !== undefined && "method" in msg) {
|
|
65
|
+
// Server-initiated request (e.g., elicitation/create for approval)
|
|
66
|
+
const method = msg.method;
|
|
67
|
+
this.emit(`server-request:${method}`, { id: msg.id, params: msg.params });
|
|
68
|
+
}
|
|
69
|
+
else if ("id" in msg && msg.id !== undefined) {
|
|
70
|
+
const id = msg.id;
|
|
71
|
+
const pending = this.pendingRequests.get(id);
|
|
72
|
+
if (pending) {
|
|
73
|
+
this.pendingRequests.delete(id);
|
|
74
|
+
if (msg.error) {
|
|
75
|
+
const err = msg.error;
|
|
76
|
+
pending.reject(new Error(`${err.message} (code ${err.code})`));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
pending.resolve(msg.result);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else if ("method" in msg) {
|
|
84
|
+
const method = msg.method;
|
|
85
|
+
this.emit(`notification:${method}`, msg.params);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
_sendResponse(id, result) {
|
|
89
|
+
this._send({ id, result });
|
|
90
|
+
}
|
|
91
|
+
_request(method, params) {
|
|
92
|
+
const id = this.nextId++;
|
|
93
|
+
const msg = { method, id };
|
|
94
|
+
if (params !== undefined)
|
|
95
|
+
msg.params = params;
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
98
|
+
this._send(msg);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
_sendNotification(method, params) {
|
|
102
|
+
const msg = { method };
|
|
103
|
+
if (params !== undefined)
|
|
104
|
+
msg.params = params;
|
|
105
|
+
this._send(msg);
|
|
106
|
+
}
|
|
107
|
+
_send(msg) {
|
|
108
|
+
if (!this.stdin)
|
|
109
|
+
throw new Error("CodexClient not started — call start() first");
|
|
110
|
+
this.stdin.write(JSON.stringify(msg) + "\n");
|
|
111
|
+
}
|
|
112
|
+
async startThread(params = {}) {
|
|
113
|
+
const reqParams = {
|
|
114
|
+
cwd: params.cwd ?? process.cwd(),
|
|
115
|
+
approvalPolicy: params.approvalPolicy ?? "on-request",
|
|
116
|
+
sandbox: params.sandbox ?? "read-only",
|
|
117
|
+
};
|
|
118
|
+
if (params.model)
|
|
119
|
+
reqParams.model = params.model;
|
|
120
|
+
const result = (await this._request("thread/start", reqParams));
|
|
121
|
+
return result.thread.id;
|
|
122
|
+
}
|
|
123
|
+
async startTurn(threadId, text, model) {
|
|
124
|
+
const reqParams = {
|
|
125
|
+
threadId,
|
|
126
|
+
input: [{ type: "text", text }],
|
|
127
|
+
};
|
|
128
|
+
if (model)
|
|
129
|
+
reqParams.model = model;
|
|
130
|
+
const result = (await this._request("turn/start", reqParams));
|
|
131
|
+
return result.turn.id;
|
|
132
|
+
}
|
|
133
|
+
waitForTurnCompletion(threadId, turnId) {
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
const onCompleted = (params) => {
|
|
136
|
+
if (params.threadId !== threadId || params.turn.id !== turnId)
|
|
137
|
+
return;
|
|
138
|
+
this.off("notification:turn/completed", onCompleted);
|
|
139
|
+
if (params.turn.status === "failed") {
|
|
140
|
+
reject(new Error(`Turn failed: ${params.turn.error?.message ?? "unknown error"}`));
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
resolve(params.turn.status);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
this.on("notification:turn/completed", onCompleted);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
close() {
|
|
150
|
+
if (this.process) {
|
|
151
|
+
this.process.kill();
|
|
152
|
+
this.process = null;
|
|
153
|
+
this.stdin = null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=codexClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codexClient.js","sourceRoot":"","sources":["../src/codexClient.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* config.ts
|
|
3
|
+
*
|
|
4
|
+
* Reads the .mcp.json file from the workspace root and returns the first
|
|
5
|
+
* HTTP MCP server config (preferring any server whose name contains "agentrq").
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
import { resolve } from "node:path";
|
|
9
|
+
/**
|
|
10
|
+
* Find and parse the .mcp.json config file.
|
|
11
|
+
* Searches CWD and then up to 3 parent directories.
|
|
12
|
+
*/
|
|
13
|
+
export function loadMcpConfig(startDir = process.cwd()) {
|
|
14
|
+
const candidates = [
|
|
15
|
+
resolve(startDir, ".mcp.json"),
|
|
16
|
+
resolve(startDir, "..", ".mcp.json"),
|
|
17
|
+
resolve(startDir, "..", "..", ".mcp.json"),
|
|
18
|
+
resolve(startDir, "..", "..", "..", ".mcp.json"),
|
|
19
|
+
];
|
|
20
|
+
for (const candidate of candidates) {
|
|
21
|
+
try {
|
|
22
|
+
const raw = readFileSync(candidate, "utf-8");
|
|
23
|
+
const parsed = JSON.parse(raw);
|
|
24
|
+
const servers = Object.entries(parsed.mcpServers ?? {}).map(([name, cfg]) => ({
|
|
25
|
+
name,
|
|
26
|
+
type: cfg.type ?? (cfg.url ? "http" : "stdio"),
|
|
27
|
+
url: cfg.url,
|
|
28
|
+
command: cfg.command,
|
|
29
|
+
args: cfg.args,
|
|
30
|
+
env: cfg.env,
|
|
31
|
+
headers: cfg.headers,
|
|
32
|
+
}));
|
|
33
|
+
if (servers.length > 0) {
|
|
34
|
+
console.error(`[config] Loaded .mcp.json from ${candidate}`);
|
|
35
|
+
return servers;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Not found here, try next
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
throw new Error("Could not find .mcp.json — run codex-gateway from your workspace root");
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Pick the primary agentrq MCP server from the list.
|
|
46
|
+
* Prefers servers with "agentrq" in the name; falls back to the first HTTP server.
|
|
47
|
+
*/
|
|
48
|
+
export function pickAgentrqServer(servers) {
|
|
49
|
+
const named = servers.find((s) => s.name.toLowerCase().includes("agentrq") && s.type === "http" && s.url);
|
|
50
|
+
if (named)
|
|
51
|
+
return named;
|
|
52
|
+
const http = servers.find((s) => s.type === "http" && s.url);
|
|
53
|
+
if (http)
|
|
54
|
+
return http;
|
|
55
|
+
throw new Error("No HTTP MCP server found in .mcp.json — expected at least one entry with type=http and url");
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0BpC;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;IAC5D,MAAM,UAAU,GAAG;QACjB,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC;QAC9B,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,CAAC;QACpC,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC;QAC1C,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC;KACjD,CAAC;IAEF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACxC,MAAM,OAAO,GAAsB,MAAM,CAAC,OAAO,CAC/C,MAAM,CAAC,UAAU,IAAI,EAAE,CACxB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;gBACtB,IAAI;gBACJ,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;gBAC9C,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,OAAO,EAAE,GAAG,CAAC,OAAO;aACrB,CAAC,CAAC,CAAC;YAEJ,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,KAAK,CAAC,kCAAkC,SAAS,EAAE,CAAC,CAAC;gBAC7D,OAAO,OAAO,CAAC;YACjB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,2BAA2B;QAC7B,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb,uEAAuE,CACxE,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAA0B;IAE1B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CACxB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,GAAG,CAC9E,CAAC;IACF,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IAExB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7D,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IAEtB,MAAM,IAAI,KAAK,CACb,4FAA4F,CAC7F,CAAC;AACJ,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* index.ts
|
|
4
|
+
*
|
|
5
|
+
* Main entry point for codex-gateway.
|
|
6
|
+
* Bridges the agentrq MCP server with the OpenAI Codex app server.
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
10
|
+
import { loadMcpConfig, pickAgentrqServer } from "./config.js";
|
|
11
|
+
import { MCPBridge } from "./mcpClient.js";
|
|
12
|
+
import { CodexClient, } from "./codexClient.js";
|
|
13
|
+
import { extractTaskIdFromMeta, extractTaskIdFromText } from "./taskIdentity.js";
|
|
14
|
+
export function buildTaskPrompt(taskId, content) {
|
|
15
|
+
return [
|
|
16
|
+
`[agentrq task_id: ${taskId}]`,
|
|
17
|
+
`You have been assigned an agentrq task. Follow these steps:`,
|
|
18
|
+
`1. Call \`updateTaskStatus\` with taskId="${taskId}" and status="ongoing" before starting work.`,
|
|
19
|
+
`2. Complete the task described below.`,
|
|
20
|
+
`3. When finished, call \`updateTaskStatus\` with taskId="${taskId}" and status="completed".`,
|
|
21
|
+
`Your text output will be automatically relayed as the reply — do not call the \`reply\` tool.`,
|
|
22
|
+
``,
|
|
23
|
+
content,
|
|
24
|
+
].join("\n");
|
|
25
|
+
}
|
|
26
|
+
export async function handleTask(content, meta, codexClient, mcpBridge, threadMap, model) {
|
|
27
|
+
const chatId = extractTaskIdFromMeta(meta);
|
|
28
|
+
let threadId = chatId ? threadMap.get(chatId) : undefined;
|
|
29
|
+
if (!threadId) {
|
|
30
|
+
const sandbox = (process.env.CODEX_SANDBOX ?? "read-only");
|
|
31
|
+
const threadParams = {
|
|
32
|
+
cwd: process.cwd(),
|
|
33
|
+
sandbox,
|
|
34
|
+
};
|
|
35
|
+
if (model)
|
|
36
|
+
threadParams.model = model;
|
|
37
|
+
threadId = await codexClient.startThread(threadParams);
|
|
38
|
+
if (chatId)
|
|
39
|
+
threadMap.set(chatId, threadId);
|
|
40
|
+
console.error(`[codex] Created thread ${threadId} for chat ${chatId ?? "unknown"}`);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
console.error(`[codex] Reusing thread ${threadId} for chat ${chatId}`);
|
|
44
|
+
}
|
|
45
|
+
const taskContent = chatId ? buildTaskPrompt(chatId, content) : content;
|
|
46
|
+
const AGENTRQ_PATTERN = /agentrq-[a-zA-Z0-9]{11}/;
|
|
47
|
+
const onApprovalRequest = async (data) => {
|
|
48
|
+
const params = data.params;
|
|
49
|
+
const reason = typeof params?.reason === "string" ? params.reason : "Unknown command";
|
|
50
|
+
const command = typeof params?.command === "string" ? params.command : "";
|
|
51
|
+
const toolTitle = typeof params?.tool_title === "string" ? params.tool_title : "";
|
|
52
|
+
const connectorId = typeof params?.connector_id === "string" ? params.connector_id : "";
|
|
53
|
+
// Auto-allow agentrq MCP tool calls (same pattern as acp-gateway)
|
|
54
|
+
const isAgentrqTool = AGENTRQ_PATTERN.test(toolTitle) || AGENTRQ_PATTERN.test(connectorId) || AGENTRQ_PATTERN.test(reason);
|
|
55
|
+
if (isAgentrqTool) {
|
|
56
|
+
console.error(`\n🔓 [codex] Auto-allowing agentrq tool: ${toolTitle || reason}`);
|
|
57
|
+
codexClient._sendResponse(data.id, { decision: "acceptForSession" });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const requestId = `codex-approval-${data.id}-${Date.now()}`;
|
|
61
|
+
console.error(`\n🔐 [codex] Approval requested: ${reason}`);
|
|
62
|
+
try {
|
|
63
|
+
await mcpBridge.sendNotification("notifications/claude/channel/permission_request", {
|
|
64
|
+
request_id: requestId,
|
|
65
|
+
tool_name: command || reason,
|
|
66
|
+
description: reason,
|
|
67
|
+
input_preview: command,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
console.error("[codex] Failed to forward permission request:", err);
|
|
72
|
+
codexClient._sendResponse(data.id, { decision: "decline" });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
console.error("⌛ [codex] Waiting for human approval in agentrq dashboard...");
|
|
76
|
+
const handler = (verdict) => {
|
|
77
|
+
if (verdict.requestId === requestId) {
|
|
78
|
+
mcpBridge.off("verdict", handler);
|
|
79
|
+
const decision = verdict.behavior === "allow" ? "accept" : "decline";
|
|
80
|
+
console.error(`✅ [codex] Permission verdict: ${verdict.behavior} → ${decision}`);
|
|
81
|
+
codexClient._sendResponse(data.id, { decision });
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
mcpBridge.on("verdict", handler);
|
|
85
|
+
};
|
|
86
|
+
let replyText = "";
|
|
87
|
+
const onDelta = (params) => {
|
|
88
|
+
if (params.threadId === threadId) {
|
|
89
|
+
replyText += params.delta;
|
|
90
|
+
process.stdout.write(params.delta);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
codexClient.on("server-request:item/commandExecution/requestApproval", onApprovalRequest);
|
|
94
|
+
codexClient.on("notification:item/agentMessage/delta", onDelta);
|
|
95
|
+
try {
|
|
96
|
+
const turnId = await codexClient.startTurn(threadId, taskContent, model);
|
|
97
|
+
console.error(`[codex] Turn ${turnId} started in thread ${threadId}`);
|
|
98
|
+
await codexClient.waitForTurnCompletion(threadId, turnId);
|
|
99
|
+
console.error(`[codex] Turn ${turnId} completed`);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
console.error("[codex] Turn error:", err);
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
codexClient.off("server-request:item/commandExecution/requestApproval", onApprovalRequest);
|
|
106
|
+
codexClient.off("notification:item/agentMessage/delta", onDelta);
|
|
107
|
+
}
|
|
108
|
+
if (replyText.trim() && chatId) {
|
|
109
|
+
try {
|
|
110
|
+
await mcpBridge.callTool("reply", { chatId, text: replyText });
|
|
111
|
+
console.error(`[codex] Reply sent to chat ${chatId}`);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.error("[codex] Failed to send reply:", err);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if (!replyText.trim()) {
|
|
118
|
+
console.error("[codex] No reply text to send");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
export async function checkForNextTask(mcpBridge, codexClient, threadMap, model) {
|
|
122
|
+
console.error("[bridge] Checking for next task via MCP server...");
|
|
123
|
+
try {
|
|
124
|
+
const result = await mcpBridge.callTool("getNextTask");
|
|
125
|
+
if (result.isError) {
|
|
126
|
+
console.error("[mcp] Error getting next task:", result.content);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const contentBlock = result.content;
|
|
130
|
+
const first = contentBlock[0];
|
|
131
|
+
if (first?.text && !first.text.includes("no pending tasks exist")) {
|
|
132
|
+
const text = first.text;
|
|
133
|
+
console.error(`[bridge] Found task: "${text.slice(0, 50).replace(/\n/g, " ")}..."`);
|
|
134
|
+
const taskId = extractTaskIdFromText(text);
|
|
135
|
+
const meta = taskId ? { chat_id: taskId } : undefined;
|
|
136
|
+
await handleTask(text, meta, codexClient, mcpBridge, threadMap, model);
|
|
137
|
+
// Recursively check for next task
|
|
138
|
+
await checkForNextTask(mcpBridge, codexClient, threadMap, model);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
console.error("[bridge] No pending tasks available.");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
console.error("[bridge] Failed to check for next task:", err);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async function main() {
|
|
149
|
+
console.log(`Starting [codex-gateway] ${pkg.name} v${pkg.version}`);
|
|
150
|
+
const args = process.argv.slice(2);
|
|
151
|
+
const cmdStartIndex = args.indexOf("--");
|
|
152
|
+
const codexArgs = cmdStartIndex !== -1 ? args.slice(cmdStartIndex + 1) : [];
|
|
153
|
+
const [codexCmd, ...codexCmdArgs] = codexArgs.length > 0 ? codexArgs : ["codex", "app-server"];
|
|
154
|
+
// Load MCP config and connect to agentrq
|
|
155
|
+
const configs = loadMcpConfig();
|
|
156
|
+
const agentrqConfig = pickAgentrqServer(configs);
|
|
157
|
+
const mcpBridge = new MCPBridge(agentrqConfig);
|
|
158
|
+
await mcpBridge.connect();
|
|
159
|
+
// Start codex app-server
|
|
160
|
+
console.error(`[codex] Spawning: ${codexCmd} ${codexCmdArgs.join(" ")}`);
|
|
161
|
+
const codexClient = new CodexClient(codexCmd, codexCmdArgs);
|
|
162
|
+
await codexClient.start();
|
|
163
|
+
const model = process.env.CODEX_MODEL;
|
|
164
|
+
const threadMap = new Map(); // chatId → threadId
|
|
165
|
+
// Bridge: MCP → Codex
|
|
166
|
+
mcpBridge.on("task", async ({ content, meta }) => {
|
|
167
|
+
console.error("\n[bridge] Incoming task from MCP server. Forwarding to Codex...");
|
|
168
|
+
try {
|
|
169
|
+
await handleTask(content, meta, codexClient, mcpBridge, threadMap, model);
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
console.error("[bridge] Error handling task:", err);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
// Initial check for pending tasks
|
|
176
|
+
await checkForNextTask(mcpBridge, codexClient, threadMap, model);
|
|
177
|
+
// Keep the process alive
|
|
178
|
+
await new Promise(() => { });
|
|
179
|
+
}
|
|
180
|
+
if (process.env.NODE_ENV !== "test") {
|
|
181
|
+
main().catch((err) => {
|
|
182
|
+
console.error("[fatal]", err);
|
|
183
|
+
process.exit(1);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpClient.ts
|
|
3
|
+
*
|
|
4
|
+
* Connects to the agentrq MCP server using the MCP TypeScript SDK.
|
|
5
|
+
* Listens for 'notifications/claude/channel' and handles tool calls.
|
|
6
|
+
*/
|
|
7
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
8
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
9
|
+
import { EventEmitter } from "node:events";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
export class MCPBridge extends EventEmitter {
|
|
12
|
+
config;
|
|
13
|
+
client = null;
|
|
14
|
+
transport = null;
|
|
15
|
+
isConnected = false;
|
|
16
|
+
isConnecting = false;
|
|
17
|
+
isClosed = false;
|
|
18
|
+
getSessionId() {
|
|
19
|
+
return this.transport?._sessionId;
|
|
20
|
+
}
|
|
21
|
+
constructor(config) {
|
|
22
|
+
super();
|
|
23
|
+
this.config = config;
|
|
24
|
+
if (!config.url) {
|
|
25
|
+
throw new Error(`MCP server ${config.name} has no URL`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async connect() {
|
|
29
|
+
if (this.isConnecting || this.isConnected)
|
|
30
|
+
return;
|
|
31
|
+
this.isConnecting = true;
|
|
32
|
+
this.isClosed = false;
|
|
33
|
+
let attempt = 0;
|
|
34
|
+
const initialDelay = 1000;
|
|
35
|
+
const maxDelay = 900000; // 15 minutes
|
|
36
|
+
while (!this.isConnected && !this.isClosed) {
|
|
37
|
+
try {
|
|
38
|
+
await this._connectOnce();
|
|
39
|
+
this.isConnected = true;
|
|
40
|
+
console.error(`[mcp] Connected to ${this.config.name}`);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (this.isClosed)
|
|
44
|
+
break;
|
|
45
|
+
const delay = Math.min(initialDelay * Math.pow(2, attempt), maxDelay);
|
|
46
|
+
console.error(`[mcp] Connection failed to ${this.config.name} (attempt ${attempt + 1}): ${error.message || error}. Retrying in ${delay / 1000}s...`);
|
|
47
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
48
|
+
attempt++;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
this.isConnecting = false;
|
|
52
|
+
}
|
|
53
|
+
async _connectOnce() {
|
|
54
|
+
if (this.transport) {
|
|
55
|
+
this.transport.onclose = undefined;
|
|
56
|
+
this.transport.onerror = undefined;
|
|
57
|
+
await this.transport.close().catch(() => { });
|
|
58
|
+
this.transport = null;
|
|
59
|
+
}
|
|
60
|
+
if (this.client) {
|
|
61
|
+
await this.client.close().catch(() => { });
|
|
62
|
+
this.client = null;
|
|
63
|
+
}
|
|
64
|
+
if (!this.config.url) {
|
|
65
|
+
throw new Error("MCP server URL is not configured");
|
|
66
|
+
}
|
|
67
|
+
const url = new URL(this.config.url);
|
|
68
|
+
this.transport = new StreamableHTTPClientTransport(url, {
|
|
69
|
+
reconnectionOptions: {
|
|
70
|
+
maxRetries: 100,
|
|
71
|
+
initialReconnectionDelay: 1000,
|
|
72
|
+
maxReconnectionDelay: 900000,
|
|
73
|
+
reconnectionDelayGrowFactor: 2,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
this.client = new Client({
|
|
77
|
+
name: "codex-gateway",
|
|
78
|
+
version: "0.1.0",
|
|
79
|
+
}, {
|
|
80
|
+
capabilities: {},
|
|
81
|
+
});
|
|
82
|
+
this.transport.onclose = () => {
|
|
83
|
+
console.error(`[mcp] Connection to ${this.config.name} lost.`);
|
|
84
|
+
this.isConnected = false;
|
|
85
|
+
this.connect();
|
|
86
|
+
};
|
|
87
|
+
this.transport.onerror = (error) => {
|
|
88
|
+
console.error(`[mcp] Transport error:`, error.message || error);
|
|
89
|
+
};
|
|
90
|
+
await this.client.connect(this.transport);
|
|
91
|
+
this.client.setNotificationHandler(z.object({
|
|
92
|
+
method: z.literal("notifications/claude/channel"),
|
|
93
|
+
params: z.object({
|
|
94
|
+
content: z.string(),
|
|
95
|
+
meta: z.any().optional(),
|
|
96
|
+
}),
|
|
97
|
+
}), (notification) => {
|
|
98
|
+
console.error("[mcp] Received channel notification");
|
|
99
|
+
const { content, meta } = notification.params;
|
|
100
|
+
this.emit("task", { content, meta });
|
|
101
|
+
});
|
|
102
|
+
this.client.setNotificationHandler(z.object({
|
|
103
|
+
method: z.literal("notifications/claude/channel/permission"),
|
|
104
|
+
params: z.object({
|
|
105
|
+
request_id: z.string(),
|
|
106
|
+
behavior: z.string(),
|
|
107
|
+
}),
|
|
108
|
+
}), (notification) => {
|
|
109
|
+
console.error("[mcp] Received permission verdict");
|
|
110
|
+
const { request_id, behavior } = notification.params;
|
|
111
|
+
this.emit("verdict", { requestId: request_id, behavior });
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
async ensureConnected() {
|
|
115
|
+
if (this.isConnected)
|
|
116
|
+
return;
|
|
117
|
+
if (!this.isConnecting) {
|
|
118
|
+
this.connect().catch((err) => {
|
|
119
|
+
console.error(`[mcp] Unexpected error in connect loop:`, err);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
let waited = 0;
|
|
123
|
+
while (!this.isConnected && waited < 10000) {
|
|
124
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
125
|
+
waited += 500;
|
|
126
|
+
}
|
|
127
|
+
if (!this.isConnected) {
|
|
128
|
+
throw new Error(`MCP not connected after 10s timeout`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async callTool(name, args = {}) {
|
|
132
|
+
await this.ensureConnected();
|
|
133
|
+
if (!this.client)
|
|
134
|
+
throw new Error("MCP client not initialized");
|
|
135
|
+
return await this.client.callTool({
|
|
136
|
+
name,
|
|
137
|
+
arguments: args,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
async sendNotification(method, params) {
|
|
141
|
+
await this.ensureConnected();
|
|
142
|
+
if (!this.client)
|
|
143
|
+
throw new Error("MCP client not initialized");
|
|
144
|
+
await this.client.notification({
|
|
145
|
+
method,
|
|
146
|
+
params,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
async close() {
|
|
150
|
+
this.isClosed = true;
|
|
151
|
+
this.isConnected = false;
|
|
152
|
+
if (this.transport) {
|
|
153
|
+
this.transport.onclose = undefined;
|
|
154
|
+
this.transport.onerror = undefined;
|
|
155
|
+
await this.transport.close().catch(() => { });
|
|
156
|
+
this.transport = null;
|
|
157
|
+
}
|
|
158
|
+
if (this.client) {
|
|
159
|
+
await this.client.close().catch(() => { });
|
|
160
|
+
this.client = null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=mcpClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpClient.js","sourceRoot":"","sources":["../src/mcpClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task identity from MCP channel `meta` for thread management (agentrq `chat_id`).
|
|
3
|
+
*/
|
|
4
|
+
/** Extract task ID from `notifications/claude/channel` `meta` (agentrq uses `chat_id`). */
|
|
5
|
+
export function extractTaskIdFromMeta(meta) {
|
|
6
|
+
if (!meta || typeof meta !== "object")
|
|
7
|
+
return undefined;
|
|
8
|
+
const m = meta;
|
|
9
|
+
if (typeof m.chat_id === "string" && m.chat_id.length > 0)
|
|
10
|
+
return m.chat_id;
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
/** Try to extract taskId from text content as a fallback. */
|
|
14
|
+
export function extractTaskIdFromText(text) {
|
|
15
|
+
const patterns = [
|
|
16
|
+
/Next assigned task:\s*ID:\s*([a-zA-Z0-9_-]+)/i, // agentrq getNextTask format
|
|
17
|
+
/Task ID[:\s]+([a-zA-Z0-9_-]+)/i,
|
|
18
|
+
/Response to task[:\s]+([a-zA-Z0-9_-]+)/i,
|
|
19
|
+
/task[:\s]+([a-zA-Z0-9_-]+)/i,
|
|
20
|
+
];
|
|
21
|
+
for (const pattern of patterns) {
|
|
22
|
+
const match = text.match(pattern);
|
|
23
|
+
if (match && match[1])
|
|
24
|
+
return match[1];
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=taskIdentity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taskIdentity.js","sourceRoot":"","sources":["../src/taskIdentity.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,2FAA2F;AAC3F,MAAM,UAAU,qBAAqB,CAAC,IAAa;IACjD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACxD,MAAM,CAAC,GAAG,IAA+B,CAAC;IAC1C,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC,OAAO,CAAC;IAC5E,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,MAAM,QAAQ,GAAG;QACf,+CAA+C,EAAE,6BAA6B;QAC9E,gCAAgC;QAChC,yCAAyC;QACzC,6BAA6B;KAC9B,CAAC;IACF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|