chore(release): 版本发布 - publish v1.0.12
This commit is contained in:
@@ -86,16 +86,6 @@ export class CanvasSession {
|
||||
input = { ops: generationFlowOps({ ...(input as Record<string, unknown>), mode: "image" }, this.canvasState) };
|
||||
tool = "canvas_apply_ops";
|
||||
}
|
||||
if (tool === "canvas_create_config_node") {
|
||||
const data = input as Record<string, unknown>;
|
||||
const x = Number(data.x ?? nextCanvasX(this.canvasState));
|
||||
const y = Number(data.y ?? 0);
|
||||
const configId = `config-${crypto.randomUUID()}`;
|
||||
const mode = generationMode(data.mode);
|
||||
const prompt = String(data.prompt || "");
|
||||
input = { ops: [configNodeOp(configId, data, x, y), ...(data.autoRun ? [runGenerationOp(configId, mode, prompt)] : [])] };
|
||||
tool = "canvas_apply_ops";
|
||||
}
|
||||
if (tool === "canvas_create_generation_flow") {
|
||||
input = { ops: generationFlowOps(input as Record<string, unknown>, this.canvasState) };
|
||||
tool = "canvas_apply_ops";
|
||||
@@ -179,18 +169,21 @@ function textNodeOp(input: { id?: string; text?: string; title?: string; width?:
|
||||
return { type: "add_node", id: input.id, nodeType: "text", title: input.title, position: { x, y }, width: input.width, height: input.height, metadata: { content: input.text || "", status: "success", fontSize: 14 } };
|
||||
}
|
||||
|
||||
function configNodeOp(id: string, input: Record<string, unknown>, x: number, y: number) {
|
||||
function generationTargetNodeOp(id: string, input: Record<string, unknown>, x: number, y: number) {
|
||||
const mode = generationMode(input.mode);
|
||||
const prompt = String(input.prompt || "");
|
||||
const nodeType = generationNodeType(mode);
|
||||
return {
|
||||
type: "add_node",
|
||||
id,
|
||||
nodeType: "config",
|
||||
nodeType,
|
||||
title: String(input.title || generationTitle(mode)),
|
||||
position: { x, y },
|
||||
width: typeof input.width === "number" ? input.width : undefined,
|
||||
height: typeof input.height === "number" ? input.height : undefined,
|
||||
metadata: cleanRecord({
|
||||
content: "",
|
||||
fontSize: nodeType === "text" ? 14 : undefined,
|
||||
generationMode: mode,
|
||||
composerContent: prompt,
|
||||
prompt,
|
||||
@@ -198,6 +191,7 @@ function configNodeOp(id: string, input: Record<string, unknown>, x: number, y:
|
||||
model: input.model,
|
||||
size: input.size,
|
||||
quality: input.quality,
|
||||
transparentBackground: input.transparentBackground,
|
||||
count: input.count,
|
||||
seconds: input.seconds,
|
||||
vquality: input.vquality,
|
||||
@@ -217,20 +211,27 @@ function generationFlowOps(input: Record<string, unknown>, state: CanvasSnapshot
|
||||
const x = Number(input.x ?? nextCanvasX(state));
|
||||
const y = Number(input.y ?? 0);
|
||||
const textId = `text-${crypto.randomUUID()}`;
|
||||
const configId = `config-${crypto.randomUUID()}`;
|
||||
const targetId = `${mode}-${crypto.randomUUID()}`;
|
||||
const referenceNodeIds = Array.isArray(input.referenceNodeIds) ? input.referenceNodeIds.filter((id): id is string => typeof id === "string") : [];
|
||||
const tokens = [`@[node:${textId}]`, ...referenceNodeIds.map((id) => `@[node:${id}]`)];
|
||||
const configInput = { ...input, prompt: tokens.join("\n") };
|
||||
const targetInput = { ...input, prompt: tokens.join("\n") };
|
||||
return [
|
||||
textNodeOp({ id: textId, text: prompt, title: String(input.title || "提示词") }, x, y),
|
||||
configNodeOp(configId, configInput, x + 420, y),
|
||||
{ type: "connect_nodes", fromNodeId: textId, toNodeId: configId },
|
||||
...referenceNodeIds.map((fromNodeId) => ({ type: "connect_nodes", fromNodeId, toNodeId: configId })),
|
||||
{ type: "select_nodes", ids: [configId] },
|
||||
...(input.autoRun ? [runGenerationOp(configId, mode, tokens.join("\n"))] : []),
|
||||
generationTargetNodeOp(targetId, targetInput, x + 420, y),
|
||||
{ type: "connect_nodes", fromNodeId: textId, toNodeId: targetId },
|
||||
...referenceNodeIds.map((fromNodeId) => ({ type: "connect_nodes", fromNodeId, toNodeId: targetId })),
|
||||
{ type: "select_nodes", ids: [targetId] },
|
||||
...(input.autoRun ? [runGenerationOp(targetId, mode, tokens.join("\n"))] : []),
|
||||
];
|
||||
}
|
||||
|
||||
function generationNodeType(mode: "text" | "image" | "video" | "audio"): CanvasNodeType {
|
||||
if (mode === "text") return "text";
|
||||
if (mode === "video") return "video";
|
||||
if (mode === "audio") return "audio";
|
||||
return "image";
|
||||
}
|
||||
|
||||
function runGenerationOp(nodeId: string, mode: "text" | "image" | "video" | "audio", prompt?: string) {
|
||||
return { type: "run_generation", nodeId, mode, prompt };
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export const DEFAULT_PORT = 17371;
|
||||
export const CONFIG_DIR = path.join(os.homedir(), ".infinite-canvas");
|
||||
export const CONFIG_FILE = path.join(CONFIG_DIR, "canvas-agent.json");
|
||||
export const VERSION = readPackageVersion();
|
||||
export const AGENT_PROMPT = "你正在帮助用户操作影策网页画布。需要改动画布时优先使用已配置的 infinite-canvas MCP 工具:先 canvas_get_state 读取当前画布,再根据任务使用 canvas_create_text_node、canvas_generate_text、canvas_generate_image、canvas_generate_video、canvas_generate_audio、canvas_create_generation_flow、canvas_create_config_node、canvas_run_generation、canvas_update_node、canvas_connect_nodes 等通用工具;复杂批量改动再用 canvas_apply_ops,删除连线可用 delete_connections。需要生成内容时直接调用对应生成工具,不要绑定特定业务场景。不要模拟鼠标点击,不要要求用户手动复制 JSON。";
|
||||
export const AGENT_PROMPT = "你正在帮助用户操作影策网页画布。需要改动画布时优先使用已配置的 infinite-canvas MCP 工具:先 canvas_get_state 读取当前画布,再根据任务使用 canvas_create_text_node、canvas_generate_text、canvas_generate_image、canvas_generate_video、canvas_generate_audio、canvas_create_generation_flow、canvas_run_generation、canvas_update_node、canvas_connect_nodes 等通用工具;复杂批量改动再用 canvas_apply_ops,删除连线可用 delete_connections。需要生成内容时直接调用对应生成工具,不要绑定特定业务场景。不要模拟鼠标点击,不要要求用户手动复制 JSON。";
|
||||
|
||||
export type CanvasWorkspaceConfig = { workspacePath: string; activeThreadId?: string; pinnedThreadIds?: string[] };
|
||||
export type CanvasAgentConfig = { url: string; token: string; origins?: string[]; canvases?: Record<string, CanvasWorkspaceConfig> };
|
||||
|
||||
@@ -3,7 +3,7 @@ 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", "config", "video", "audio", "frame"]);
|
||||
const nodeTypeSchema = z.enum(["image", "text", "script", "video", "audio", "frame"]);
|
||||
const generationModeSchema = z.enum(["text", "image", "video", "audio"]);
|
||||
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: z.string().min(1), details: recordSchema.optional() });
|
||||
@@ -17,7 +17,6 @@ export const toolNames = [
|
||||
"canvas_create_node",
|
||||
"canvas_create_text_node",
|
||||
"canvas_create_text_nodes",
|
||||
"canvas_create_config_node",
|
||||
"canvas_create_image_prompt_flow",
|
||||
"canvas_create_generation_flow",
|
||||
"canvas_generate_text",
|
||||
@@ -97,7 +96,6 @@ export const toolInputSchemas = {
|
||||
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_config_node: z.object({ prompt: z.string().optional(), mode: generationModeSchema.optional(), title: z.string().optional(), x: z.number().optional(), y: z.number().optional(), width: z.number().optional(), height: z.number().optional(), autoRun: z.boolean().optional() }).merge(generationOptionsSchema),
|
||||
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),
|
||||
@@ -130,12 +128,11 @@ export const toolDescriptions: Record<ToolName, string> = {
|
||||
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_node: "创建任意类型节点:text、script、image、config、video、audio、frame。适合创建脚本、媒体占位、配置节点、背板或自定义 metadata 节点。",
|
||||
canvas_create_node: "创建任意类型节点:text、script、image、video、audio、frame。适合创建脚本、媒体占位、背板或自定义 metadata 节点。",
|
||||
canvas_create_text_node: "在当前画布创建单个文本节点。",
|
||||
canvas_create_text_nodes: "批量创建文本节点,适合生成标题、段落、脚本、说明等内容块。",
|
||||
canvas_create_config_node: "创建生成配置节点,可指定 text/image/video/audio 模式和生成参数,可选择立即触发生成。",
|
||||
canvas_create_image_prompt_flow: "创建提示词文本节点和图片生成配置节点,并自动连线,可选择立即触发生图。",
|
||||
canvas_create_generation_flow: "创建通用生成流程:提示词文本节点、生成配置节点、参考节点连线,可用于文案、生图、视频或音频。",
|
||||
canvas_create_image_prompt_flow: "创建提示词文本节点和图片目标节点并自动连线,可选择立即触发生图。",
|
||||
canvas_create_generation_flow: "创建通用生成流程:提示词文本节点、对应类型的生成目标节点和参考节点连线,可用于文案、生图、视频或音频。",
|
||||
canvas_generate_text: "创建通用文本生成流程并立即触发生成。",
|
||||
canvas_generate_image: "创建通用图片生成流程并立即触发生成。",
|
||||
canvas_generate_video: "创建通用视频生成流程并立即触发生成。",
|
||||
|
||||
Reference in New Issue
Block a user