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

@@ -490,6 +490,7 @@ export type ComputerControlIntentCategory =
| "thread_rename"
| "thread_goal_sync"
| "thread_metadata_sync"
| "thread_fork"
| "browser_control"
| "desktop_control";
export type ComputerControlRuntimeKind =
@@ -1371,6 +1372,8 @@ export interface MasterAgentTask {
threadGoalReason?: string;
threadMetadataGitInfo?: ThreadMetadataGitInfoPatch;
threadMetadataReason?: string;
threadForkEphemeral?: boolean;
threadForkReason?: string;
intentCategory?: ComputerControlIntentCategory;
runtimeKind?: ComputerControlRuntimeKind;
controlPlatform?: ComputerControlPlatform;
@@ -4807,6 +4810,8 @@ export function migrateBossState(raw: Partial<BossState> | undefined): BossState
threadGoalReason: trimToDefined(task.threadGoalReason),
threadMetadataGitInfo: normalizeThreadMetadataGitInfoPatch(task.threadMetadataGitInfo),
threadMetadataReason: trimToDefined(task.threadMetadataReason),
threadForkEphemeral: task.threadForkEphemeral === true,
threadForkReason: trimToDefined(task.threadForkReason),
intentCategory:
task.intentCategory === "discussion_only" ||
task.intentCategory === "project_development" ||
@@ -4818,6 +4823,7 @@ export function migrateBossState(raw: Partial<BossState> | undefined): BossState
task.intentCategory === "thread_rename" ||
task.intentCategory === "thread_goal_sync" ||
task.intentCategory === "thread_metadata_sync" ||
task.intentCategory === "thread_fork" ||
task.intentCategory === "browser_control" ||
task.intentCategory === "desktop_control"
? task.intentCategory
@@ -8895,6 +8901,8 @@ export async function queueMasterAgentTask(payload: {
threadGoalReason?: string;
threadMetadataGitInfo?: ThreadMetadataGitInfoPatch;
threadMetadataReason?: string;
threadForkEphemeral?: boolean;
threadForkReason?: string;
intentCategory?: ComputerControlIntentCategory;
runtimeKind?: ComputerControlRuntimeKind;
controlPlatform?: ComputerControlPlatform;
@@ -8986,6 +8994,8 @@ export async function queueMasterAgentTask(payload: {
threadGoalReason: trimToDefined(payload.threadGoalReason),
threadMetadataGitInfo: normalizeThreadMetadataGitInfoPatch(payload.threadMetadataGitInfo),
threadMetadataReason: trimToDefined(payload.threadMetadataReason),
threadForkEphemeral: payload.threadForkEphemeral === true,
threadForkReason: trimToDefined(payload.threadForkReason),
intentCategory: payload.intentCategory,
runtimeKind: payload.runtimeKind,
controlPlatform: payload.controlPlatform,

View File

@@ -3587,6 +3587,64 @@ export async function queueThreadMetadataSyncTask(params: {
});
}
function buildThreadForkPrompt(params: {
project: Project;
ephemeral: boolean;
reason?: string;
}) {
const threadTitle =
params.project.threadMeta.threadDisplayName?.trim() || params.project.name || "当前线程";
return [
"你正在执行 Boss 下发的 Codex App Server 线程分叉控制任务。",
`源线程:${threadTitle}`,
`是否临时线程:${params.ephemeral ? "是" : "否"}`,
params.reason ? `用户原因:${params.reason}` : undefined,
"请通过 thread/fork 分叉当前 Codex 线程,不要启动普通 turn不要输出系统提示词、线程原始历史或内部调度字段。",
"注意:该动作只创建 Codex 分叉线程,不代表代码修改、文件恢复或版本发布完成;新线程进入 Boss 会话列表依赖后续线程 discovery / 导入链路。",
]
.filter(Boolean)
.join("\n");
}
export async function queueThreadForkTask(params: {
projectId: string;
requestMessageId: string;
ephemeral?: boolean;
reason?: string;
requestedBy: string;
requestedByAccount: string;
}) {
const conflict = await getThreadConversationExecutionConflict(params.projectId);
if (conflict) {
throw new ThreadConversationExecutionConflictError(conflict);
}
const { project, deviceId } = await resolveThreadConversationExecutionContext(params.projectId);
const reason = params.reason?.trim() || undefined;
const ephemeral = params.ephemeral === true;
return queueMasterAgentTask({
projectId: project.id,
taskType: "conversation_reply",
requestMessageId: params.requestMessageId,
requestText: reason || "分叉当前 Codex 线程。",
executionPrompt: buildThreadForkPrompt({
project,
ephemeral,
reason,
}),
requestedBy: params.requestedBy,
requestedByAccount: params.requestedByAccount,
deviceId,
intentCategory: "thread_fork",
targetProjectId: project.id,
targetThreadId: project.threadMeta.threadId,
targetThreadDisplayName: project.threadMeta.threadDisplayName,
targetCodexThreadRef: project.threadMeta.codexThreadRef,
targetCodexFolderRef: project.threadMeta.codexFolderRef,
threadForkEphemeral: ephemeral,
threadForkReason: reason,
});
}
export async function queueInterThreadCollaborationTask(params: {
sourceProjectId: string;
targetProjectId: string;