feat(*): Agent工作流 - 完善审批、分镜协作与资源交互体验
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import { AGENT_APPROVAL_SUPERSEDED_BY_NODE, agentApprovalMatchesSettings, agentApprovalModel, agentApprovalModelSelection, agentApprovalTargetGenerating, agentImageApproval, agentMediaApprovalTargetNodeId } from "../src/lib/canvas/agent-media-approval";
|
||||
import { AGENT_APPROVAL_SUPERSEDED_BY_NODE, agentApprovalMatchesSettings, agentApprovalModel, agentApprovalModelSelection, agentApprovalTargetGenerating, agentImageApproval, agentMediaApprovalTargetNodeId, agentVideoApproval } from "../src/lib/canvas/agent-media-approval";
|
||||
import type { CanvasNodeData } from "../src/types/canvas";
|
||||
import { createModelChannel, defaultConfig, encodeChannelModel } from "../src/stores/use-config-store";
|
||||
|
||||
@@ -40,6 +40,15 @@ describe("image generation approval settings", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("video generation approval settings", () => {
|
||||
it("reads video duration and audio options", () => {
|
||||
const approval = agentVideoApproval({ toolName: "generate_media", arguments: { mode: "video", prompt: "镜头运动", size: "9:16", quality: "720p", durationSeconds: 8, videoGenerateAudio: true, channelId: "platform", channelModelKey: "seedance-test", referenceNodeIds: ["image"] } });
|
||||
expect(approval?.durationSeconds).toBe(8);
|
||||
expect(approval?.videoGenerateAudio).toBe(true);
|
||||
expect(approval?.referenceNodeIds).toEqual(["image"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("approval target already generating on the canvas", () => {
|
||||
const detail = { toolName: "generate_media", arguments: JSON.stringify({ mode: "image", prompt: "p", size: "1:1", nodeId: "draft-1" }) };
|
||||
const node = (metadata: Record<string, unknown>) => ({ id: "draft-1", type: "image", title: "开场分镜", position: { x: 0, y: 0 }, width: 200, height: 200, metadata }) as unknown as CanvasNodeData;
|
||||
|
||||
@@ -20,6 +20,12 @@ const styleNode = node("style", CanvasNodeType.Text, {
|
||||
});
|
||||
|
||||
describe("storyboard generation context", () => {
|
||||
it("does not require a project style node", () => {
|
||||
const context = resolveStoryboardGenerationContext([]);
|
||||
|
||||
expect(context.characters).toEqual([]);
|
||||
});
|
||||
|
||||
it("ignores standalone character-design workflows without a linked asset", () => {
|
||||
const context = resolveStoryboardGenerationContext([
|
||||
styleNode,
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
|
||||
import { withStoryboardOutputContract } from "../src/lib/canvas/canvas-project-domain";
|
||||
import { stripProjectStyleExecutionBlocks, withStoryboardOutputContract } from "../src/lib/canvas/canvas-project-domain";
|
||||
|
||||
describe("stripProjectStyleExecutionBlocks", () => {
|
||||
test("removes repeated legacy style suffixes while preserving the original story", () => {
|
||||
const prompt = "@图片1 冬天\n\n【项目画风执行规范】\n旧风格规范\n\n【项目画风执行规范】\n重复旧风格规范";
|
||||
|
||||
expect(stripProjectStyleExecutionBlocks(prompt)).toBe("@图片1 冬天");
|
||||
});
|
||||
});
|
||||
|
||||
// 画布「分镜脚本」节点与章节分镜都把用户输入原样交给模型,拆镜要求与 JSON 契约只能由调用方显式拼上:
|
||||
// 漏掉契约时模型按自然语言习惯回复(Markdown 表格、甚至续写正文),storyboardRowsFromTask 便报
|
||||
|
||||
@@ -28,4 +28,10 @@ describe("storyboard prompt panel boundaries", () => {
|
||||
expect(project).toContain("onOpen={() => setScriptEditorNodeId(contentNode.id)}");
|
||||
expect(project).toContain("onGenerateScript={(prompt) => void generateScriptRows(contentNode.id, prompt)}");
|
||||
});
|
||||
|
||||
test("storyboard generation strips legacy style instructions without sending project style", () => {
|
||||
const storyboard = source("use-canvas-storyboard.ts");
|
||||
expect(storyboard).toContain("stripProjectStyleExecutionBlocks(prompt)");
|
||||
expect(storyboard).not.toContain("projectStyle: storyboardContext.projectStyle");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -40,11 +40,6 @@ describe("latestAgentPlanItems", () => {
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 回归(2026-09-16):运行中输入框是禁用的,模型在正文里提问用户根本答不了
|
||||
* (生产实测它连问 4 轮、白烧十几步)。`ask_user` 让本轮收尾并把问题结构化,
|
||||
* 这个选择器决定「现在该不该把选项面板亮给用户」。
|
||||
*/
|
||||
describe("pendingAgentQuestion", () => {
|
||||
const question = { question: "选哪个模型?", options: [{ label: "H3文生视频" }, { label: "Seedance 2.5" }] };
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ test("welcome contributors parse the README HTML table", () => {
|
||||
expect(people[0]?.signature).toContain("没有任何黑魔法");
|
||||
expect(people.some((person) => person.name === "爱笑的毛毛虫")).toBe(true);
|
||||
expect(people.some((person) => person.name === "morrow" && person.email === "3201190041@qq.com" && person.signature === "最难不过坚持")).toBe(true);
|
||||
expect(people.some((person) => person.name === "Wyatt_K" && person.avatar === "assets/user-Wyatt_K.png" && person.signature === "千里之行,始于足下。")).toBe(true);
|
||||
expect(people.some((person) => person.name === "亿媒网老宋" && person.avatar === "assets/user-song.jpg" && person.email === "61731514@qq.com" && person.signature === "全国10W+媒体、自媒体,助力企业品牌传播")).toBe(true);
|
||||
expect(people.filter((person) => person.isFounder)).toHaveLength(1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user