130 lines
3.4 KiB
TypeScript
130 lines
3.4 KiB
TypeScript
import { ZodError } from "zod";
|
|
import {
|
|
canApplyCanvasAgentMutations,
|
|
type CanvasAgentFeatureFlags,
|
|
} from "@/lib/canvas/agent-feature-flags";
|
|
import {
|
|
CanvasAgentMutationError,
|
|
type CanvasOperationResult,
|
|
} from "@/lib/canvas/agent-mutations";
|
|
import { parseCanvasAgentOperationRequestBody } from "@/lib/canvas/agent-operation-request";
|
|
import type { CanvasOperationPlan } from "@/types/canvas/agent-protocol";
|
|
|
|
export type CanvasAgentOperationRouteBody =
|
|
| {
|
|
success: true;
|
|
data: CanvasOperationResult;
|
|
}
|
|
| {
|
|
success: false;
|
|
error: string;
|
|
code?: string;
|
|
writebackMode?: CanvasAgentFeatureFlags["writebackMode"];
|
|
details?: unknown;
|
|
};
|
|
|
|
export type CanvasAgentOperationRouteResponse = {
|
|
status: number;
|
|
body: CanvasAgentOperationRouteBody;
|
|
};
|
|
|
|
export async function handleCanvasAgentOperationRouteRequest(params: {
|
|
userId?: string | null;
|
|
projectId: string;
|
|
rawBody?: unknown;
|
|
readBody?: () => Promise<unknown>;
|
|
features: CanvasAgentFeatureFlags;
|
|
applyOperation: (input: {
|
|
userId: string;
|
|
projectId: string;
|
|
plan: CanvasOperationPlan;
|
|
}) => Promise<CanvasOperationResult>;
|
|
logger?: Pick<Console, "error">;
|
|
}): Promise<CanvasAgentOperationRouteResponse> {
|
|
const userId = String(params.userId || "").trim();
|
|
if (!userId) {
|
|
return {
|
|
status: 401,
|
|
body: { success: false, error: "未登录" },
|
|
};
|
|
}
|
|
|
|
if (!canApplyCanvasAgentMutations(params.features)) {
|
|
return {
|
|
status: 409,
|
|
body: {
|
|
success: false,
|
|
error: "当前画布 Agent 写回处于灰度保护,未修改画布",
|
|
code: "CANVAS_AGENT_WRITEBACK_DISABLED",
|
|
writebackMode: params.features.writebackMode,
|
|
},
|
|
};
|
|
}
|
|
|
|
try {
|
|
const rawBody = params.readBody ? await params.readBody() : params.rawBody;
|
|
const body = parseCanvasAgentOperationRequestBody(rawBody);
|
|
const planProjectId = String(body.operationPlan.projectId || "").trim();
|
|
if (planProjectId && planProjectId !== params.projectId) {
|
|
return {
|
|
status: 400,
|
|
body: {
|
|
success: false,
|
|
error: "operation projectId 与请求项目不一致",
|
|
code: "CANVAS_AGENT_PROJECT_MISMATCH",
|
|
},
|
|
};
|
|
}
|
|
const operationPlan: CanvasOperationPlan = {
|
|
...body.operationPlan,
|
|
projectId: planProjectId || params.projectId,
|
|
};
|
|
const result = await params.applyOperation({
|
|
userId,
|
|
projectId: params.projectId,
|
|
plan: operationPlan,
|
|
});
|
|
|
|
return {
|
|
status: 200,
|
|
body: {
|
|
success: true,
|
|
data: result,
|
|
},
|
|
};
|
|
} catch (error) {
|
|
if (error instanceof CanvasAgentMutationError) {
|
|
return {
|
|
status: error.status,
|
|
body: {
|
|
success: false,
|
|
error: error.message,
|
|
code: error.code,
|
|
},
|
|
};
|
|
}
|
|
if (error instanceof ZodError) {
|
|
return {
|
|
status: 400,
|
|
body: {
|
|
success: false,
|
|
error: "请求参数无效",
|
|
details: error.flatten(),
|
|
},
|
|
};
|
|
}
|
|
if (error instanceof SyntaxError) {
|
|
return {
|
|
status: 400,
|
|
body: { success: false, error: "请求 JSON 无效" },
|
|
};
|
|
}
|
|
|
|
params.logger?.error("[CanvasAgentOperations] apply operation failed:", error);
|
|
return {
|
|
status: 500,
|
|
body: { success: false, error: "执行画布操作失败" },
|
|
};
|
|
}
|
|
}
|