feat(ai-workspace): support SEO codex provider bridge
This commit is contained in:
@@ -8,6 +8,8 @@ const MAX_EVENTS_PER_AGENT = 5000;
|
||||
const MAX_REQUEST_META_PER_AGENT = 1000;
|
||||
const HEARTBEAT_INTERVAL_MS = 30000;
|
||||
const AGENT_STALE_MS = 75000;
|
||||
const DEFAULT_AGENT_EVENT_TEXT_MAX = Number(process.env.AI_WORKSPACE_AGENT_EVENT_TEXT_MAX || 12000);
|
||||
const CODEX_MESSAGE_EVENT_TEXT_MAX = Number(process.env.AI_WORKSPACE_CODEX_MESSAGE_EVENT_TEXT_MAX || 250000);
|
||||
const ASSISTANT_RELAY_POLL_TIMEOUT_MS = Number(process.env.AI_WORKSPACE_ASSISTANT_RELAY_POLL_TIMEOUT_MS || 25000);
|
||||
const ASSISTANT_RELAY_ACTION_TIMEOUT_MS = Number(process.env.AI_WORKSPACE_ASSISTANT_RELAY_ACTION_TIMEOUT_MS || 45000);
|
||||
const ASSISTANT_RELAY_MAX_PENDING = Number(process.env.AI_WORKSPACE_ASSISTANT_RELAY_MAX_PENDING || 200);
|
||||
@@ -67,6 +69,14 @@ app.post("/api/ai-workspace/hub/v1/agents/:pairingCode/dispatch", requireInterna
|
||||
});
|
||||
|
||||
app.post("/api/ai-workspace/assistant/v1/actions", requireInternalApi, asyncRoute(proxyAssistantActions));
|
||||
app.get("/api/ai-workspace/assistant/v1/executors", requireInternalApi, asyncRoute(proxyAssistantControlPlane));
|
||||
app.post("/api/ai-workspace/assistant/v1/executors", requireInternalApi, asyncRoute(proxyAssistantControlPlane));
|
||||
app.post("/api/ai-workspace/assistant/v1/executors/:executorId/agent/setup-command", requireInternalApi, asyncRoute(proxyAssistantControlPlane));
|
||||
app.post("/api/ai-workspace/assistant/v1/executors/:executorId/check", requireInternalApi, asyncRoute(proxyAssistantControlPlane));
|
||||
app.post("/api/ai-workspace/assistant/v1/threads", requireInternalApi, asyncRoute(proxyAssistantControlPlane));
|
||||
app.get("/api/ai-workspace/assistant/v1/threads/:threadId/messages", requireInternalApi, asyncRoute(proxyAssistantControlPlane));
|
||||
app.post("/api/ai-workspace/assistant/v1/threads/:threadId/messages", requireInternalApi, asyncRoute(proxyAssistantControlPlane));
|
||||
app.post("/api/ai-workspace/assistant/v1/threads/:threadId/dispatch", requireInternalApi, asyncRoute(proxyAssistantControlPlane));
|
||||
app.post("/api/ai-workspace/setup-codes/redeem", asyncRoute(proxySetupCodeRedeem));
|
||||
app.get("/api/ai-workspace/bridge-package.tgz", asyncRoute(proxyBridgePackage));
|
||||
|
||||
@@ -302,6 +312,33 @@ async function proxyAssistantActions(req, res) {
|
||||
res.send(text);
|
||||
}
|
||||
|
||||
async function proxyAssistantControlPlane(req, res) {
|
||||
if (!config.assistantInternalUrl || !config.assistantInternalAccessToken) {
|
||||
res.status(503).json({ ok: false, error: "assistant_control_plane_proxy_not_configured" });
|
||||
return;
|
||||
}
|
||||
|
||||
const method = String(req.method || "GET").toUpperCase();
|
||||
const hasBody = !["GET", "HEAD"].includes(method);
|
||||
const targetUrl = `${config.assistantInternalUrl.replace(/\/+$/, "")}${String(req.originalUrl || req.url || "")}`;
|
||||
const upstream = await fetch(targetUrl, {
|
||||
method,
|
||||
redirect: "manual",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
Authorization: `Bearer ${config.assistantInternalAccessToken}`,
|
||||
...forwardOwnerHeaders(req),
|
||||
...(hasBody ? { "Content-Type": "application/json" } : {}),
|
||||
},
|
||||
...(hasBody ? { body: JSON.stringify(req.body || {}) } : {}),
|
||||
});
|
||||
const contentType = upstream.headers.get("content-type") || "application/json; charset=utf-8";
|
||||
const text = await upstream.text();
|
||||
res.status(upstream.status);
|
||||
res.setHeader("content-type", contentType);
|
||||
res.send(text);
|
||||
}
|
||||
|
||||
async function proxySetupCodeRedeem(req, res) {
|
||||
if (!config.assistantInternalUrl || !config.assistantInternalAccessToken) {
|
||||
res.status(503).json({ ok: false, error: "assistant_setup_proxy_not_configured" });
|
||||
@@ -572,6 +609,8 @@ function pushAgentEvent(agent, requestId, rawEvent = {}) {
|
||||
const now = new Date().toISOString();
|
||||
const cleanRequestId = String(requestId || rawEvent.requestId || "");
|
||||
const meta = cleanRequestId ? agent.requestMeta?.get(cleanRequestId) : null;
|
||||
const kind = cleanString(rawEvent.kind || rawEvent.type || "event", 40);
|
||||
const eventTextMax = kind === "codex_message" ? CODEX_MESSAGE_EVENT_TEXT_MAX : DEFAULT_AGENT_EVENT_TEXT_MAX;
|
||||
const event = {
|
||||
id: ++eventSeq,
|
||||
pairingCode: agent.pairingCode,
|
||||
@@ -581,10 +620,10 @@ function pushAgentEvent(agent, requestId, rawEvent = {}) {
|
||||
threadTitle: rawEvent.threadTitle == null ? cleanString(meta?.threadTitle, 240) : cleanString(rawEvent.threadTitle, 240),
|
||||
userMessage: rawEvent.userMessage == null ? cleanString(meta?.userMessage, 12000) : cleanString(rawEvent.userMessage, 12000),
|
||||
remoteControlMode: rawEvent.remoteControlMode == null ? cleanString(meta?.remoteControlMode, 40) : cleanString(rawEvent.remoteControlMode, 40),
|
||||
kind: cleanString(rawEvent.kind || rawEvent.type || "event", 40),
|
||||
kind,
|
||||
stream: rawEvent.stream ? cleanString(rawEvent.stream, 40) : "",
|
||||
text: rawEvent.text == null ? "" : cleanString(rawEvent.text, 12000),
|
||||
message: rawEvent.message == null ? "" : cleanString(rawEvent.message, 12000),
|
||||
text: rawEvent.text == null ? "" : cleanString(rawEvent.text, eventTextMax),
|
||||
message: rawEvent.message == null ? "" : cleanString(rawEvent.message, eventTextMax),
|
||||
command: rawEvent.command == null ? "" : cleanString(rawEvent.command, 1000),
|
||||
cwd: rawEvent.cwd == null ? "" : cleanString(rawEvent.cwd, 500),
|
||||
currentFile: rawEvent.currentFile == null ? "" : cleanString(rawEvent.currentFile, 1000),
|
||||
|
||||
Reference in New Issue
Block a user