feat(agent): 助手交互 - 优化推理展示、工具分组与审批反馈
This commit is contained in:
@@ -41,7 +41,7 @@ function fieldLabel(key: string, nodeType: string): string {
|
||||
}
|
||||
|
||||
function operation(value: unknown): AgentApprovalPreviewOperation | null {
|
||||
return value === "add_node" || value === "update_node" || value === "connect_nodes" || value === "generate_media" ? value : null;
|
||||
return value === "add_node" || value === "update_node" || value === "connect_nodes" || value === "generate_media" || value === "create_storyboard" || value === "edit_storyboard" ? value : null;
|
||||
}
|
||||
|
||||
function normalizeServerPreview(value: unknown): AgentApprovalPresentation | null {
|
||||
@@ -127,4 +127,4 @@ export function agentApprovalPresentation(detail: unknown): AgentApprovalPresent
|
||||
if (name === "canvas_apply_ops") return canvasFallback(args);
|
||||
if (name === "generate_media") return mediaFallback(args, payload);
|
||||
return { source: "fallback", kind: "agent_approval", title: "确认执行操作", description: "Agent 请求执行一项操作,但审批参数无法识别;请重新读取画布后再申请审批。", items: [] };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,42 @@ export const AGENT_TOOL_METADATA: Record<string, { summary: string | ((context:
|
||||
generate_media: { summary: ({ pending, detail }) => pending ? "准备创建媒体节点并生成" : field(detail, "eventType") === "tool_completed" ? "生成结果已回写画布节点" : "媒体节点已创建,生成任务已提交", failureMessage: "媒体生成未完成" },
|
||||
};
|
||||
|
||||
export type AgentToolCategory = "read" | "create" | "operate";
|
||||
|
||||
function record(value: unknown): Record<string, unknown> {
|
||||
return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : {};
|
||||
}
|
||||
|
||||
function toolArguments(detail?: unknown) {
|
||||
const value = record(detail).arguments;
|
||||
if (typeof value !== "string") return record(value);
|
||||
try { return record(JSON.parse(value)); } catch { return {}; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps the activity feed semantic instead of presenting every tool call as
|
||||
* the same check-mark row. This is intentionally based on the tool contract,
|
||||
* not on translated copy, so the visual grouping remains stable as messages
|
||||
* change or get localized.
|
||||
*/
|
||||
export function agentToolCategory(toolName: string, detail?: unknown): AgentToolCategory {
|
||||
if (["canvas_get_state", "canvas_list_node_types", "model_list", "task_get", "skills_load", "skill_read_file"].includes(toolName)) return "read";
|
||||
if (toolName === "generate_media") return "create";
|
||||
if (toolName === "canvas_apply_ops") {
|
||||
const actions = record(detail).actions;
|
||||
if (Array.isArray(actions) && actions.some((item) => record(item).action === "created" || record(item).action === "generating")) return "create";
|
||||
const ops = toolArguments(detail).ops;
|
||||
if (Array.isArray(ops) && ops.some((item) => record(item).type === "add_node")) return "create";
|
||||
}
|
||||
return "operate";
|
||||
}
|
||||
|
||||
export function agentToolCategoryLabel(toolName: string, category: AgentToolCategory): string {
|
||||
if (category === "read") return toolName === "canvas_get_state" ? "读取节点" : "读取信息";
|
||||
if (category === "create") return "创建节点";
|
||||
return "操作画布";
|
||||
}
|
||||
|
||||
type ToolStatus = "completed" | "failed" | "noop" | "rejected" | "pending";
|
||||
|
||||
function field(value: unknown, key: string): unknown {
|
||||
|
||||
@@ -29,10 +29,11 @@ export const CREATIVE_AGENT_TOOLS: ResponseFunctionTool[] = [{
|
||||
export const CREATIVE_AGENT_SYSTEM_PROMPT = `你是影策的通用创作助手,支持短片、营销、电商与一般创作。普通咨询直接回答,不强制问卷、方案或任务计划。
|
||||
用户授权在当前任务范围内持续有效,直到用户撤回、修改目标或出现范围外操作。“可以”“好的”“按你说的做”应结合紧邻的明确建议理解为同意该建议;“你决定”“自主处理”允许你决定该任务内的常规创意和操作细节。不要把模糊同意扩大到未提及的删除、额外费用或新任务。用户已授权的读取、素材挑选、文本编辑、布局和技术纠错应直接推进,不为每个子步骤重新征求同意。常规可调整的创意选择自行决定并简短说明,只对真正阻塞执行、无法从现有素材查明的信息提问。
|
||||
多步骤创作使用 creative_respond。先结合全部需求摘要、会话、用户素材、专业角色指导、选中技能与真实画布,提取已知信息;只有缺失或冲突且确实影响执行的信息才补问,通常1至3题,确需一起决定时最多6题,不凑题。允许自定义安全的需求字段,优先复用已有字段,不通过改名重复询问。用户直接输入的自然语言回答与卡片回答同等有效,可以同时更新多个字段。不得将猜测写成用户确认。用户允许自主决定时可以直接给方案。
|
||||
当前首页规划阶段唯一可调用的函数工具是 creative_respond。availableModels、references 和 canvas 是本次请求附带的只读快照,不是可继续调用的工具。不要虚构 canvas_*、model_* 或其他未注册工具调用,也不要声称已读取、创建、提交或生成快照中没有的结果;节点落地和媒体提交只会在程序完成方案校验并取得对应确认后发生。
|
||||
多步骤任务可携带 plan,按本次实际工作命名步骤,例如“确定结尾情绪”“设计商品构图”“制作首张主图”;不套固定步骤数。每步 ref 在同一工作持续时保持稳定,新工作使用新ref。phase只用于程序关联真实状态:questions=需求选择,proposal=内容方案,canvas=节点落地,media=产物生成(mediaRefs关联方案生成项ref)。可以调整未完成步骤并在reason说明原因;不编造完成状态。普通咨询不创建计划。已完成工作不可抹掉,新增任务不能复用已完成步骤ref。
|
||||
问题与方案不能在同一次响应同时推进。已经确认的题材/时长/数量/比例/风格不再问。覆盖已确认字段必须在 evidence 引用最新用户消息中明确修改该字段的原文;不能将建议或旧消息作为修改授权。素材题的 option.id 只能使用上下文提供的真实素材ID。
|
||||
方案应是可阅读的完整 Markdown,包含内容、已有素材、待生成产物、规格和真实依赖。workflow 支持 text/image/video/styleboard/story_input/script;搭建短剧工作流时使用真实的 styleboard 项目画风选择节点、story_input 故事梗概和 script 分镜表,已有节点优先沿用。script.shots 必须逐镜填写 durationSeconds、videoMotionPrompt、dialogue,不用普通文本模拟表格。styleboard 是待选择入口,不把任意文字当作已应用画风;用户已有画风时不重复创建。只有 image/video 填写 generationItems;创建分镜表和画风入口不代表生成媒体。媒体必须有完整提示词,文本必须有正文。每个待生成媒体节点有且仅有一项 generationItems,使用可用模型的完整 model ID。用户已有图片优先用 image 节点的 assetId 指向真实 references.id,此类节点不写 generationItems、不重复生成,可被其他节点用 referenceRefs 引用。
|
||||
分镜任务先检查 canvas_get_context.storyboardReadiness 或 canvas_read_storyboard.readiness。缺少画风时先 canvas_list_styles,再按用户已确认的风格或自主决策授权调用 canvas_apply_style;只有确实需要用户取舍时才提问,不重复询问已有风格。应用后重新读取上下文确认 canGenerateStoryboard,不能只在正文声称画风已设置。用户给的是剧本、剧情或要求自动拆镜时,优先 canvas_generate_storyboard 复用项目专业拆镜能力,不自己编一组 shots 替代专业任务。没有分镜节点时,在方案获批或用户已明确要求搭建的范围内调用 canvas_create_storyboard,将原始剧本保存在底部输入框,再调用 canvas_generate_storyboard;待拆镜空表不代表完成。专业任务会展示费用与整表替换确认,用户取消后停止,不重复请求。已有明确镜头清单需要录入,或局部修改时,用 canvas_read_storyboard 获取真实行 ID,再 canvas_edit_storyboard 更新或追加,保留其余行与素材。方案直接交付已拆好的 script 时仍必须提供非空 shots。拆镜后重新读取真实表格,核对总时长和镜头数;5秒、10秒等节点时长选项是单镜头时长,总片长必须写入拆镜要求。不要把项目画风全文重复灌进每行作为镜头描述,不声称有镜头行就已经生成图片视频。
|
||||
分镜任务先检查只读 canvas 快照中的现有 styleboard、story_input 和 script 节点,已有节点优先沿用,不为同一职责重复创建。用户要求交付明确镜头清单或搭建可维护的多镜头工作流时,proposal.workflow 使用 script 节点并提供非空 shots,逐镜核对总时长、单镜头时长、运动提示词和对白;不要用多个 text/Markdown 节点模拟分镜表。用户只要求单画面、单镜头试验或普通脚本文档时,可以选择更轻量的节点,不为形式强加分镜。当前规划阶段不能直接运行专业自动拆镜、应用画风或修改真实分镜行;如任务依赖这些后续能力,在方案和 plan 中如实标记为节点落地后的待执行步骤,不虚构工具调用、费用确认、真实行 ID 或已生成结果。不要把项目画风全文重复灌进每行作为镜头描述,不声称有镜头行就已经生成图片视频。
|
||||
generationItems 是方案的声明式生成配置,用于校验和之后的报价,不会立即调用媒体模型。因此“确认后再生成”仍必须填写它,不能省略。每项 ref 必须对应节点 ref,mode 必须等于节点 kind,model 必须来自 availableModels 中相同 mode 的条目;图片模型不能用于视频。上下文若有 rejectedProposal,先根据其中真实校验错误修正,保留已知需求并返回完整方案。结构化方案和费用的批准以程序记录为准;若仍缺按钮确认,直接显示对应卡片,不再先问一遍是否同意、再让用户点卡片。
|
||||
引用已有画布图片时,将真实 references.id 放到 workflow.nodes[].referenceNodeIds;referenceRefs 优先用于本次方案内其他图片节点的 ref。不要为引用现有图片再生成一张副本,不要在两个字段重复放同一张图。程序会核实真实资源并整理引用,未知ID不能通过。
|
||||
单段视频可以在正文描述多个叙事节奏,不把它们拆成未合成的几段视频。用户要求15秒时只选实际支持15秒的模型;不存在则解释缺少能力并询问可接受替代,绝不能偷偷缩短。图像引用数量、视频输入角色、尺寸均须符合上下文能力。边表达真实依赖,不为了好看造线。
|
||||
|
||||
Reference in New Issue
Block a user