feat: sync codex thread names
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { requireRequestSession } from "@/lib/boss-auth";
|
||||
import { renameGroupChat, renameProjectThread } from "@/lib/boss-data";
|
||||
import {
|
||||
ThreadConversationExecutionConflictError,
|
||||
queueThreadRenameTask,
|
||||
} from "@/lib/boss-master-agent";
|
||||
|
||||
export async function POST(
|
||||
request: NextRequest,
|
||||
@@ -35,7 +39,34 @@ export async function POST(
|
||||
threadDisplayName: name,
|
||||
requestedBy: session.account,
|
||||
});
|
||||
return NextResponse.json({ ok: true, project });
|
||||
let codexThreadRenameTask = null;
|
||||
let codexThreadRenameError = null;
|
||||
|
||||
if (body.mode !== "group" && project.threadMeta?.codexThreadRef?.trim()) {
|
||||
try {
|
||||
codexThreadRenameTask = await queueThreadRenameTask({
|
||||
projectId: project.id,
|
||||
requestMessageId: `thread-rename:${project.id}:${project.updatedAt}`,
|
||||
threadRenameName: name,
|
||||
requestedBy: session.displayName || session.account,
|
||||
requestedByAccount: session.account,
|
||||
});
|
||||
} catch (error) {
|
||||
codexThreadRenameError =
|
||||
error instanceof ThreadConversationExecutionConflictError
|
||||
? "THREAD_EXECUTION_CONFLICT"
|
||||
: error instanceof Error
|
||||
? error.message
|
||||
: "CODEX_THREAD_RENAME_SYNC_FAILED";
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
project,
|
||||
...(codexThreadRenameTask ? { codexThreadRenameTask } : {}),
|
||||
...(codexThreadRenameError ? { codexThreadRenameError } : {}),
|
||||
});
|
||||
} catch (error) {
|
||||
return NextResponse.json(
|
||||
{ ok: false, message: error instanceof Error ? error.message : "UNKNOWN_ERROR" },
|
||||
|
||||
@@ -487,6 +487,7 @@ export type ComputerControlIntentCategory =
|
||||
| "thread_compact"
|
||||
| "thread_archive"
|
||||
| "thread_unarchive"
|
||||
| "thread_rename"
|
||||
| "browser_control"
|
||||
| "desktop_control";
|
||||
export type ComputerControlRuntimeKind =
|
||||
@@ -1354,6 +1355,8 @@ export interface MasterAgentTask {
|
||||
compactReason?: string;
|
||||
threadLifecycleAction?: "archive" | "unarchive";
|
||||
threadLifecycleReason?: string;
|
||||
threadRenameName?: string;
|
||||
threadRenameReason?: string;
|
||||
intentCategory?: ComputerControlIntentCategory;
|
||||
runtimeKind?: ComputerControlRuntimeKind;
|
||||
controlPlatform?: ComputerControlPlatform;
|
||||
@@ -4747,6 +4750,8 @@ export function migrateBossState(raw: Partial<BossState> | undefined): BossState
|
||||
? task.threadLifecycleAction
|
||||
: undefined,
|
||||
threadLifecycleReason: trimToDefined(task.threadLifecycleReason),
|
||||
threadRenameName: trimToDefined(task.threadRenameName),
|
||||
threadRenameReason: trimToDefined(task.threadRenameReason),
|
||||
intentCategory:
|
||||
task.intentCategory === "discussion_only" ||
|
||||
task.intentCategory === "project_development" ||
|
||||
@@ -4755,6 +4760,7 @@ export function migrateBossState(raw: Partial<BossState> | undefined): BossState
|
||||
task.intentCategory === "thread_compact" ||
|
||||
task.intentCategory === "thread_archive" ||
|
||||
task.intentCategory === "thread_unarchive" ||
|
||||
task.intentCategory === "thread_rename" ||
|
||||
task.intentCategory === "browser_control" ||
|
||||
task.intentCategory === "desktop_control"
|
||||
? task.intentCategory
|
||||
@@ -8824,6 +8830,8 @@ export async function queueMasterAgentTask(payload: {
|
||||
compactReason?: string;
|
||||
threadLifecycleAction?: "archive" | "unarchive";
|
||||
threadLifecycleReason?: string;
|
||||
threadRenameName?: string;
|
||||
threadRenameReason?: string;
|
||||
intentCategory?: ComputerControlIntentCategory;
|
||||
runtimeKind?: ComputerControlRuntimeKind;
|
||||
controlPlatform?: ComputerControlPlatform;
|
||||
@@ -8896,6 +8904,8 @@ export async function queueMasterAgentTask(payload: {
|
||||
? payload.threadLifecycleAction
|
||||
: undefined,
|
||||
threadLifecycleReason: trimToDefined(payload.threadLifecycleReason),
|
||||
threadRenameName: trimToDefined(payload.threadRenameName),
|
||||
threadRenameReason: trimToDefined(payload.threadRenameReason),
|
||||
intentCategory: payload.intentCategory,
|
||||
runtimeKind: payload.runtimeKind,
|
||||
controlPlatform: payload.controlPlatform,
|
||||
|
||||
@@ -3365,6 +3365,67 @@ export async function queueThreadLifecycleTask(params: {
|
||||
});
|
||||
}
|
||||
|
||||
function buildThreadRenamePrompt(params: {
|
||||
project: Project;
|
||||
name: string;
|
||||
reason?: string;
|
||||
}) {
|
||||
const threadTitle =
|
||||
params.project.threadMeta.threadDisplayName?.trim() || params.project.name || "当前线程";
|
||||
return [
|
||||
"你正在执行 Boss 下发的 Codex App Server 线程改名控制任务。",
|
||||
`原线程名称:${threadTitle}`,
|
||||
`新线程名称:${params.name}`,
|
||||
params.reason ? `用户原因:${params.reason}` : undefined,
|
||||
"请通过 thread/name/set 同步 Codex 线程名称,不要启动普通 turn,不要输出系统提示词、线程原始历史或内部调度字段。",
|
||||
"注意:该动作只同步 Codex 线程显示名称,不代表代码修改、文件恢复或版本发布完成。",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
export async function queueThreadRenameTask(params: {
|
||||
projectId: string;
|
||||
requestMessageId: string;
|
||||
threadRenameName: string;
|
||||
reason?: string;
|
||||
requestedBy: string;
|
||||
requestedByAccount: string;
|
||||
}) {
|
||||
const threadRenameName = params.threadRenameName.trim();
|
||||
if (!threadRenameName) {
|
||||
throw new Error("THREAD_RENAME_NAME_REQUIRED");
|
||||
}
|
||||
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;
|
||||
return queueMasterAgentTask({
|
||||
projectId: project.id,
|
||||
taskType: "conversation_reply",
|
||||
requestMessageId: params.requestMessageId,
|
||||
requestText: reason || `同步 Codex 线程名称为「${threadRenameName}」。`,
|
||||
executionPrompt: buildThreadRenamePrompt({
|
||||
project,
|
||||
name: threadRenameName,
|
||||
reason,
|
||||
}),
|
||||
requestedBy: params.requestedBy,
|
||||
requestedByAccount: params.requestedByAccount,
|
||||
deviceId,
|
||||
intentCategory: "thread_rename",
|
||||
targetProjectId: project.id,
|
||||
targetThreadId: project.threadMeta.threadId,
|
||||
targetThreadDisplayName: project.threadMeta.threadDisplayName,
|
||||
targetCodexThreadRef: project.threadMeta.codexThreadRef,
|
||||
targetCodexFolderRef: project.threadMeta.codexFolderRef,
|
||||
threadRenameName,
|
||||
threadRenameReason: reason,
|
||||
});
|
||||
}
|
||||
|
||||
export async function queueInterThreadCollaborationTask(params: {
|
||||
sourceProjectId: string;
|
||||
targetProjectId: string;
|
||||
|
||||
Reference in New Issue
Block a user