Files
ttstd-infinite-canvas/canvas-agent/src/schemas.ts

210 lines
16 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { z } from "zod";
const recordSchema = z.record(z.unknown());
const positionSchema = z.object({ x: z.number(), y: z.number() });
const viewportSchema = z.object({ x: z.number(), y: z.number(), k: z.number() });
const nodeTypeSchema = z.enum(["image", "text", "script", "video", "audio", "frame"]);
const generationModeSchema = z.enum(["text", "image", "video", "audio"]);
const assetCategorySchema = z.enum(["character", "environment", "prop", "material", "other"]);
const agentCandidateCategorySchema = z.enum(["environment", "prop", "material", "other"]);
const projectIdSchema = z.string().min(1).optional();
const projectCandidateSchema = z.object({ unitId: z.string().optional(), shotId: z.string().optional(), name: z.string().min(1), category: agentCandidateCategorySchema, details: recordSchema.optional() });
const projectShotSchema = z.object({ id: z.string().optional(), unitId: z.string().optional(), title: z.string().min(1), description: z.string().optional(), position: z.number().int().min(0).optional(), durationMs: z.number().int().min(0).optional(), status: z.string().optional() });
export const toolNames = [
"canvas_get_state",
"canvas_get_context",
"canvas_find_nodes",
"canvas_get_node",
"canvas_get_connection",
"canvas_get_generation_tasks",
"canvas_get_resources",
"canvas_validate_ops",
"canvas_get_selection",
"canvas_export_snapshot",
"canvas_apply_ops",
"canvas_create_workflow",
"canvas_create_node",
"canvas_create_text_node",
"canvas_create_text_nodes",
"canvas_create_image_prompt_flow",
"canvas_create_generation_flow",
"canvas_generate_text",
"canvas_generate_image",
"canvas_generate_video",
"canvas_generate_audio",
"canvas_update_node",
"canvas_update_node_text",
"canvas_move_nodes",
"canvas_resize_node",
"canvas_delete_nodes",
"canvas_connect_nodes",
"canvas_select_nodes",
"canvas_set_viewport",
"canvas_run_generation",
"project_get_context",
"project_list_units",
"project_extract_asset_candidates",
"project_confirm_asset_candidate",
"project_create_or_update_shots",
"project_link_shot_asset",
"project_start_workflow_step",
"project_link_asset",
"project_upsert_asset_version",
"project_register_task_output",
] as const;
export type ToolName = (typeof toolNames)[number];
export const canvasOpSchema = z.discriminatedUnion("type", [
z.object({ type: z.literal("add_node"), nodeType: nodeTypeSchema.optional(), id: z.string().optional(), title: z.string().optional(), x: z.number().optional(), y: z.number().optional(), width: z.number().optional(), height: z.number().optional(), position: positionSchema.optional(), metadata: recordSchema.optional() }).passthrough(),
z.object({ type: z.literal("update_node"), id: z.string(), patch: recordSchema.optional(), metadata: recordSchema.optional() }).passthrough(),
z.object({ type: z.literal("delete_node"), id: z.string().optional(), ids: z.array(z.string()).optional(), nodeType: nodeTypeSchema.optional() }).passthrough(),
z.object({ type: z.literal("delete_connections"), id: z.string().optional(), ids: z.array(z.string()).optional(), all: z.boolean().optional() }).passthrough(),
z.object({ type: z.literal("connect_nodes"), id: z.string().optional(), fromNodeId: z.string(), toNodeId: z.string(), fromHandleId: z.string().optional(), toHandleId: z.string().optional() }).passthrough(),
z.object({ type: z.literal("set_viewport"), viewport: viewportSchema }).passthrough(),
z.object({ type: z.literal("select_nodes"), ids: z.array(z.string()) }).passthrough(),
z.object({ type: z.literal("run_generation"), nodeId: z.string(), mode: generationModeSchema.optional(), prompt: z.string().optional() }).passthrough(),
]);
const textNodeSchema = z.object({
text: z.string(),
title: z.string().optional(),
x: z.number().optional(),
y: z.number().optional(),
width: z.number().optional(),
height: z.number().optional(),
});
const workflowNodeSchema = z.object({
ref: z.string().min(1),
kind: z.enum(["text", "script", "image", "video", "audio", "character_cards", "character_three_view", "storyboard_video"]),
title: z.string().min(1),
content: z.string().optional(),
prompt: z.string().optional(),
description: z.string().optional(),
referenceRefs: z.array(z.string()).optional(),
referenceNodeIds: z.array(z.string()).optional(),
runGeneration: z.boolean().optional(),
width: z.number().positive().optional(),
height: z.number().positive().optional(),
});
const workflowSchema = z.object({
title: z.string().optional(),
description: z.string().optional(),
nodes: z.array(workflowNodeSchema).min(1),
edges: z.array(z.object({ from: z.string().min(1), to: z.string().min(1) })).optional(),
direction: z.enum(["horizontal", "vertical"]).optional(),
start: positionSchema.optional(),
gap: z.number().min(48).optional(),
autoRun: z.boolean().optional(),
});
const generationOptionsSchema = z.object({
model: z.string().optional(),
size: z.string().optional(),
quality: z.string().optional(),
count: z.number().optional(),
seconds: z.string().optional(),
vquality: z.string().optional(),
generateAudio: z.string().optional(),
watermark: z.string().optional(),
audioVoice: z.string().optional(),
audioFormat: z.string().optional(),
audioSpeed: z.string().optional(),
audioInstructions: z.string().optional(),
});
const generationFlowSchema = z.object({
prompt: z.string(),
title: z.string().optional(),
x: z.number().optional(),
y: z.number().optional(),
referenceNodeIds: z.array(z.string()).optional(),
});
export const toolInputSchemas = {
canvas_get_state: z.object({}).passthrough(),
canvas_get_context: z.object({}).passthrough(),
canvas_find_nodes: z.object({ query: z.string().optional(), ids: z.array(z.string()).optional(), types: z.array(z.string()).optional(), statuses: z.array(z.string()).optional(), resourceOnly: z.boolean().optional(), limit: z.number().int().min(1).max(200).optional() }),
canvas_get_node: z.object({ id: z.string().min(1) }),
canvas_get_connection: z.object({ id: z.string().min(1) }),
canvas_get_generation_tasks: z.object({ status: z.string().optional(), nodeIds: z.array(z.string()).optional(), limit: z.number().int().min(1).max(200).optional() }),
canvas_get_resources: z.object({ nodeIds: z.array(z.string()).optional(), status: z.string().optional(), limit: z.number().int().min(1).max(300).optional() }),
canvas_validate_ops: z.object({ ops: z.array(canvasOpSchema) }),
canvas_get_selection: z.object({}).passthrough(),
canvas_export_snapshot: z.object({}).passthrough(),
canvas_apply_ops: z.object({ ops: z.array(canvasOpSchema), expectedRevision: z.number().int().nonnegative().optional(), expectedStateHash: z.string().min(1).optional() }),
canvas_create_workflow: workflowSchema,
canvas_create_node: z.object({ nodeType: nodeTypeSchema, title: z.string().optional(), x: z.number().optional(), y: z.number().optional(), width: z.number().optional(), height: z.number().optional(), metadata: recordSchema.optional() }),
canvas_create_text_node: z.object({ text: z.string().optional(), x: z.number().optional(), y: z.number().optional(), title: z.string().optional(), width: z.number().optional(), height: z.number().optional() }),
canvas_create_text_nodes: z.object({ items: z.array(textNodeSchema).min(1), x: z.number().optional(), y: z.number().optional(), gap: z.number().optional(), direction: z.enum(["row", "column"]).optional() }),
canvas_create_image_prompt_flow: z.object({ prompt: z.string(), x: z.number().optional(), y: z.number().optional(), autoRun: z.boolean().optional() }).merge(generationOptionsSchema),
canvas_create_generation_flow: generationFlowSchema.extend({ mode: generationModeSchema.optional(), autoRun: z.boolean().optional() }).merge(generationOptionsSchema),
canvas_generate_text: generationFlowSchema.merge(generationOptionsSchema),
canvas_generate_image: generationFlowSchema.merge(generationOptionsSchema),
canvas_generate_video: generationFlowSchema.merge(generationOptionsSchema),
canvas_generate_audio: generationFlowSchema.merge(generationOptionsSchema),
canvas_update_node: z.object({ id: z.string(), patch: recordSchema.optional(), metadata: recordSchema.optional() }),
canvas_update_node_text: z.object({ id: z.string(), text: z.string(), title: z.string().optional() }),
canvas_move_nodes: z.object({ items: z.array(z.object({ id: z.string(), x: z.number().optional(), y: z.number().optional(), dx: z.number().optional(), dy: z.number().optional() })).min(1) }),
canvas_resize_node: z.object({ id: z.string(), width: z.number(), height: z.number(), freeResize: z.boolean().optional() }),
canvas_delete_nodes: z.object({ ids: z.array(z.string()).min(1) }),
canvas_connect_nodes: z.object({ connections: z.array(z.object({ fromNodeId: z.string(), toNodeId: z.string(), fromHandleId: z.string().optional(), toHandleId: z.string().optional() })).min(1) }),
canvas_select_nodes: z.object({ ids: z.array(z.string()) }),
canvas_set_viewport: z.object({ viewport: viewportSchema }),
canvas_run_generation: z.object({ nodeId: z.string(), mode: generationModeSchema.optional(), prompt: z.string().optional(), retry: z.boolean().optional() }),
project_get_context: z.object({ projectId: projectIdSchema }),
project_list_units: z.object({ projectId: projectIdSchema, kind: z.string().optional(), status: z.string().optional() }),
project_extract_asset_candidates: z.object({ projectId: projectIdSchema, candidates: z.array(projectCandidateSchema).min(1).max(100) }),
project_confirm_asset_candidate: z.object({ projectId: projectIdSchema, candidateId: z.string().min(1), assetId: z.string().optional() }),
project_create_or_update_shots: z.object({ projectId: projectIdSchema, shots: z.array(projectShotSchema).min(1).max(100) }),
project_link_shot_asset: z.object({ projectId: projectIdSchema, shotId: z.string().min(1), assetVersionId: z.string().min(1), role: z.enum(["reference", "start_frame", "end_frame", "keyframe", "storyboard", "output"]) }),
project_start_workflow_step: z.object({ projectId: projectIdSchema, stepId: z.string().min(1) }),
project_link_asset: z.object({ projectId: projectIdSchema, assetId: z.string().min(1), category: assetCategorySchema }),
project_upsert_asset_version: z.object({ projectId: projectIdSchema, assetId: z.string().min(1), prompt: z.string().optional(), definitionJson: z.string().optional(), note: z.string().optional() }),
project_register_task_output: z.object({ projectId: projectIdSchema, stepId: z.string().min(1), taskId: z.string().min(1), assetVersionId: z.string().optional(), resourceId: z.string().optional(), mediaType: z.string().optional(), role: z.enum(["reference", "start_frame", "end_frame", "keyframe", "storyboard", "output"]).optional(), metadataJson: z.string().optional(), outputJson: z.string().optional() }),
} satisfies Record<ToolName, z.AnyZodObject>;
export const toolDescriptions: Record<ToolName, string> = {
canvas_get_state: "读取当前网页画布的节点、连线、选区和视口。",
canvas_get_context: "读取面向 Agent 的语义化画布上下文:节点用途、连接关系、选区、资源引用、生成状态和状态哈希。优先于直接猜测节点 metadata。",
canvas_find_nodes: "按标题、内容、提示词、类型、状态、资产或工作流检索真实节点,返回可用于后续写操作的节点 id。",
canvas_get_node: "按真实节点 id 精确读取单个节点的语义、完整安全 metadata、资源状态和关联连线;找不到时明确返回未找到。",
canvas_get_connection: "按真实连线 id 精确读取连线端点、端点节点摘要和 handle 信息;找不到时明确返回未找到。",
canvas_get_generation_tasks: "读取当前画布节点已经绑定的生成任务观察状态,包括 taskId、节点、任务状态、进度、阶段和错误;这是画布快照观察,不会主动轮询上游。",
canvas_get_resources: "读取当前画布引用的媒体资源清单,包括资源/资产引用、类型、尺寸、大小、时长和就绪状态;不会返回媒体 URL。",
canvas_validate_ops: "在真正写入前校验批量操作中的节点 id、连接关系和参数,避免对不存在节点或错误资源执行操作。",
canvas_get_selection: "读取当前网页画布选中的节点。",
canvas_export_snapshot: "导出当前画布快照,用于理解布局。",
canvas_apply_ops: "批量操作当前网页画布。ops 支持 add_node、update_node、delete_node、delete_connections、connect_nodes、set_viewport、select_nodes、run_generation。",
canvas_create_workflow: "创建语义化工作流/流水线。character_cards 是角色拆分图片卡片,character_three_view 是角色三视图,storyboard_video 是分镜剧情视频。媒体节点必须有 prompt/content;已有素材使用先读取到的真实 node id 填入 referenceNodeIds。自动分配 id、根据真实节点尺寸布局、建立 edges/referenceRefs/referenceNodeIds 连线并返回可验证结果;不要用批量文本节点代替工作流。",
canvas_create_node: "创建任意类型节点:text、script、image、video、audio、frame。适合创建脚本、媒体占位、背板或自定义 metadata 节点。",
canvas_create_text_node: "在当前画布创建单个文本节点。",
canvas_create_text_nodes: "批量创建文本节点,适合生成标题、段落、脚本、说明等内容块。",
canvas_create_image_prompt_flow: "创建提示词文本节点和图片目标节点并自动连线,可选择立即触发生图。",
canvas_create_generation_flow: "创建通用生成流程:提示词文本节点、对应类型的生成目标节点和参考节点连线,可用于文案、生图、视频或音频。",
canvas_generate_text: "创建通用文本生成流程并立即触发生成。",
canvas_generate_image: "创建通用图片生成流程并立即触发生成。",
canvas_generate_video: "创建通用视频生成流程并立即触发生成。",
canvas_generate_audio: "创建通用音频生成流程并立即触发生成。",
canvas_update_node: "更新节点基础字段或 metadata。",
canvas_update_node_text: "更新文本节点内容和标题。",
canvas_move_nodes: "移动一个或多个节点,支持绝对坐标或 dx/dy 偏移。",
canvas_resize_node: "调整节点尺寸。",
canvas_delete_nodes: "删除指定节点及相关连线。",
canvas_connect_nodes: "批量连接节点。",
canvas_select_nodes: "设置当前选中节点。",
canvas_set_viewport: "调整画布视口。",
canvas_run_generation: "触发指定节点生成;对已有生成任务明确重试时传 retry=true,以复用产品级重试幂等身份。",
project_get_context: "读取当前短剧项目的章节、画布、资产、镜头、候选和工作流事实。",
project_list_units: "按类型或状态筛选当前短剧项目的章节/项目单元。",
project_extract_asset_candidates: "将分镜识别出的场景、道具、素材或其他需求登记为待确认资产候选;角色只在剧情章节提取,不通过此工具重复创建。",
project_confirm_asset_candidate: "确认一个资产候选,创建正式资产或关联已有个人资产。",
project_create_or_update_shots: "创建或更新项目镜头业务数据,不把镜头状态写进画布 metadata。",
project_link_shot_asset: "将具体资产版本按首帧、尾帧或参考等用途关联到镜头。",
project_start_workflow_step: "启动项目或章节制作流程中的一个步骤。",
project_link_asset: "将个人资产引用到当前短剧项目,不复制媒体文件。",
project_upsert_asset_version: "为项目资产创建新的设定和提示词版本,保留历史版本。",
project_register_task_output: "将成功生成任务挂到流程步骤,并登记到具体资产版本和资源表示。",
};