feat: fork codex threads

This commit is contained in:
AI Bot
2026-06-03 14:49:43 +08:00
parent 5537fde7a6
commit 0c3437a36f
11 changed files with 393 additions and 1 deletions

View File

@@ -82,6 +82,10 @@ function isThreadMetadataSyncTask(task) {
return task?.intentCategory === "thread_metadata_sync" || task?.taskType === "thread_metadata_sync";
}
function isThreadForkTask(task) {
return task?.intentCategory === "thread_fork" || task?.taskType === "thread_fork";
}
function resolveThreadRenameName(task) {
return trimToDefined(task?.threadRenameName || task?.threadName || task?.name);
}
@@ -127,6 +131,10 @@ function resolveThreadMetadataGitInfo(task) {
return Object.keys(gitInfo).length > 0 ? gitInfo : undefined;
}
function resolveThreadForkEphemeral(task) {
return task?.threadForkEphemeral === true || task?.ephemeral === true;
}
function resolveThreadLifecycleAction(task) {
if (
task?.threadLifecycleAction === "archive" ||
@@ -3229,6 +3237,42 @@ export async function executeCodexAppServerTask(runnerConfig, task) {
};
}
if (isThreadForkTask(task)) {
const forkSourceThreadId = targetThreadRef;
const ephemeral = resolveThreadForkEphemeral(task);
if (!forkSourceThreadId) {
throw new Error("CODEX_APP_SERVER_THREAD_ID_MISSING");
}
const forkResponse = await request("thread/fork", {
threadId: forkSourceThreadId,
ephemeral,
});
const forkedThread = forkResponse?.thread && typeof forkResponse.thread === "object"
? forkResponse.thread
: {};
const forkedThreadId = trimToDefined(forkedThread.id);
return {
status: "completed",
replyBody: forkedThreadId
? `已分叉 Codex 线程:${forkedThread.name || forkedThreadId}`
: "已分叉 Codex 线程。",
threadId: forkSourceThreadId,
turnControl: "fork",
threadFork: {
sourceThreadId: forkSourceThreadId,
forkedThreadId,
forkedThreadName: trimToDefined(forkedThread.name),
forkedThreadPreview: trimToDefined(forkedThread.preview),
ephemeral: forkedThread.ephemeral === true,
status: trimToDefined(forkedThread.status),
},
cwd,
transport: runnerConfig.transport,
executionProgress: progressCollector.snapshot(),
canFallbackToCli: false,
};
}
if (isThreadRenameTask(task)) {
const renameThreadId = targetThreadRef;
const name = resolveThreadRenameName(task);