feat: adapt codex app-server protocol updates

This commit is contained in:
AI Bot
2026-05-31 03:25:30 +08:00
parent e1aed590f8
commit b9d3cca2e7
820 changed files with 108070 additions and 71 deletions

View File

@@ -249,7 +249,13 @@ async function resolveComputerUseCapabilityConnected(config, computerUseRuntime)
}
async function resolveCodexAppServerCapabilityConnected(codexAppServerRuntime) {
if (!codexAppServerRuntime?.enabled || !codexAppServerRuntime.command) {
if (!codexAppServerRuntime?.enabled) {
return false;
}
if (codexAppServerRuntime.transport === "ws" || codexAppServerRuntime.transport === "unix") {
return Boolean(codexAppServerRuntime.url);
}
if (!codexAppServerRuntime.command) {
return false;
}
return canExecuteCommand(codexAppServerRuntime.command, codexAppServerRuntime.cwd || process.cwd());
@@ -452,6 +458,31 @@ async function completeMasterAgentTask(config, runtime, payload) {
};
}
async function postMasterAgentTaskProgress(config, runtime, payload) {
const response = await fetch(
`${config.controlPlaneUrl.replace(/\/$/, "")}/api/v1/master-agent/tasks/${payload.taskId}/progress`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
...deviceTokenHeaders(config, runtime),
},
body: JSON.stringify({
deviceId: config.deviceId,
status: payload.status || "running",
requestId: payload.requestId,
executionProgress: payload.executionProgress,
}),
},
);
return {
ok: response.ok,
status: response.status,
body: await response.text(),
};
}
async function claimSkillLifecycleRequest(config, runtime) {
const response = await fetch(
`${config.controlPlaneUrl.replace(/\/$/, "")}/api/v1/devices/${config.deviceId}/skill-requests/claim`,
@@ -617,6 +648,45 @@ async function collectLocalExecutionProgress(cwd, replyBody) {
};
}
function mergeExecutionProgress(primary, secondary) {
const first = primary && typeof primary === "object" ? primary : {};
const second = secondary && typeof secondary === "object" ? secondary : {};
const artifacts = [];
const seenArtifacts = new Set();
for (const artifact of [...(first.artifacts || []), ...(second.artifacts || [])]) {
const label = String(artifact?.label || "").trim();
if (!label || seenArtifacts.has(label)) {
continue;
}
seenArtifacts.add(label);
artifacts.push(artifact);
}
const agents = [];
const seenAgents = new Set();
for (const agent of [...(first.agents || []), ...(second.agents || [])]) {
const name = String(agent?.name || "").trim();
const key = `${name}:${String(agent?.role || "").trim()}`;
if (!name || seenAgents.has(key)) {
continue;
}
seenAgents.add(key);
agents.push(agent);
}
return {
...(second || {}),
...(first || {}),
branch:
first.branch || second.branch
? {
...(second.branch || {}),
...(first.branch || {}),
}
: undefined,
artifacts: artifacts.length > 0 ? artifacts : undefined,
agents: agents.length > 0 ? agents : undefined,
};
}
async function runMasterAgentTask(config, runtime, task) {
const outputFile = join(os.tmpdir(), `${task.taskId}.reply.txt`);
const stderrChunks = [];
@@ -678,12 +748,38 @@ async function runMasterAgentTask(config, runtime, task) {
const codexAppServerRunner = getCodexAppServerRunnerConfig(process.env, config);
if (shouldUseCodexAppServerTaskRunner(codexAppServerRunner, task)) {
const appServerResult = await executeCodexAppServerTask(codexAppServerRunner, task);
const appServerResult = await executeCodexAppServerTask(
{
...codexAppServerRunner,
onProgress: async (executionProgress) => {
const progressResult = await postMasterAgentTaskProgress(config, runtime, {
taskId: task.taskId,
status: "running",
executionProgress,
});
if (!progressResult.ok) {
await postAppLog(config, runtime, {
projectId: task.projectId,
level: "warn",
category: "local_agent.codex_app_server_progress_failed",
message: "Codex App Server 进度实时回写失败,完成回写仍会携带最终进度。",
detail: progressResult.body,
mirrorToMaster: false,
});
}
},
},
task,
);
if (appServerResult.status === "completed") {
const executionProgress = await collectLocalExecutionProgress(
const localExecutionProgress = await collectLocalExecutionProgress(
appServerResult.cwd || task.targetCodexFolderRef || config.masterAgentWorkdir || process.cwd(),
appServerResult.replyBody,
);
const executionProgress = mergeExecutionProgress(
appServerResult.executionProgress,
localExecutionProgress,
);
try {
if (task.targetCodexThreadRef || task.targetThreadId) {
await executeCodexDesktopRefreshBridge(