qcanvas-local-agent
v0.5.8
Published
QCanvas 本机 Agent —— 在本机驱动 Codex、Claude 或 WorkBuddy 操控 QCanvas 网页画布的本地桥接服务。
Maintainers
Readme
qcanvas-local-agent
发布新版固定流程
每次修改本地 Agent 后,如需让 npx -y qcanvas-local-agent@latest 获取新能力,必须按以下顺序发布:
cd "D:\胡东山\py学习\QCanvas\apps\qcanvas-local-agent"
npm run build
# 手动将 package.json 的 version 提升到一个从未发布过的新版本
npm publish
# npm 要求双重验证时:npm publish --otp=手机显示的6位验证码发布后使用 npm view qcanvas-local-agent version 验证 registry 已更新。禁止重复使用已经发布过的版本号,也不要使用会自动创建 Git tag 的 npm version。
QCanvas 「本机 Agent」:在你自己的电脑上运行一个本地桥接服务,让 QCanvas 网页画布可以调用本机登录的 Codex、Claude 或 WorkBuddy 来读写画布。
一条命令启动
npx -y qcanvas-local-agent@latest@latest 不能省略:不带 tag 时 npx 命中本地 _npx 缓存就直接跑旧版本,不会回 registry 检查新版;带 @latest 每次都会解析 registry 上的最新版本。
启动后会打印本地地址(默认 http://127.0.0.1:17372)和一个连接令牌(Connect token)。在 QCanvas 网页里切到「本机模式」,把地址和令牌填进去即可连接。
本机 Agent 按端口单实例运行。重复启动时会明确提示端口已占用;先访问对应地址的 /health,若返回 QCanvas Local Agent 健康信息,说明已有实例正在服务,无需再次启动。若是其他程序占用,再停止该程序或通过 QCANVAS_LOCAL_AGENT_PORT 改用新端口,并同步修改 QCanvas 中的本机地址。
需要 Node.js(建议 22 或更新版本)。首次运行会自动下载依赖(含 Codex、WorkBuddy Agent SDK,可选 Claude)。
登录 AI(每台电脑一次)
本机 Agent 驱动的是你本机的 CLI,需各自登录:
- Codex:
npx -y @openai/codex login --device-auth - Claude(可选):随包安装的 Claude Code,
claude auth login - WorkBuddy:QCanvas 使用官方 WorkBuddy Agent SDK。若本机还没有 CodeBuddy Agent 登录凭据,第一次发送消息时会在对话中显示腾讯登录链接,完成后本轮自动继续;它不连接桌面客户端的私有端口。
QCanvas 的执行约束不会写入画布工作空间的 AGENTS.md:Codex 通过 app-server thread/start / thread/resume 的 developerInstructions 接收,Claude 通过临时 --append-system-prompt-file 接收;不挂载画布工具的一次性总结线程不注入这些约束。
WorkBuddy 模型选择
WorkBuddy 桌面客户端与 QCanvas 启动的 Agent SDK 会话彼此独立,桌面客户端右下角选择的模型不会自动同步到 QCanvas。QCanvas 会通过 SDK 动态读取当前账号的可用模型目录,在本机 Agent 菜单中选择后,每轮通过 SDK 的 model 参数显式指定;SDK 初始化事件返回的实际模型也会在界面回显。若实际模型与选择不一致,本轮会明确失败,不会静默回退到混元或其他模型。
WorkBuddy QCanvas 工具连接
WorkBuddy 对话使用官方 Agent SDK 的单轮 query() 流式接口创建或恢复会话,并显式启用 CLI headless print 模式,把本机 QCanvas MCP 注入同一执行链。每轮完成后进程退出,后续对话通过 SDK 的 resume 参数恢复同一个 WorkBuddy session;续写前会先核对该 session 属于当前画布工作区。不使用当前 SDK 与随包 CLI 不兼容的 requestTimeoutMs 启动参数。
工具白名单必须写成 NoDefer(mcp__qcanvas__*)。CodeBuddy CLI 默认把 MCP 工具 defer 掉——只索引进 ToolSearch,不放进模型的工具清单;而本机桥为了不开放任何内置工具会传 --tools "",这又把 ToolSearch 这个唯一入口关掉。两者叠加时画布工具对模型完全不可见,模型只能照着 system prompt 里的名字编造伪调用,WorkBuddy 会静默退化成纯对话。NoDefer(...) 强制把这些 MCP 工具直接摊给模型,同时保持内置工具全关。
需要注意初始化事件里的 tools 是 CLI 的完整注册表而非模型可见清单:即使 MCP 工具全被 defer、模型一个都拿不到,它照样会列出全部 10 个名字。因此本机桥的启动校验(工作区、session id、实际模型、qcanvas MCP 连接状态、mcp__qcanvas__tapcanvas_* 工具名)只证明服务端注册成功,模型侧可见性由上面的白名单保证,真出问题时由伪调用检测在本轮兜底报错。
模型必须通过 SDK 的结构化 tool_use 调用完整命名空间工具。未加命名空间的 tapcanvas_*、原样输出的 <tool_calls> / <arg_key> 文本、工具名称:mcp__… 这类自然语言伪调用、以及 Tool not found 结果,都会显式失败,不会被当作真实画布操作或普通回答放行。CLI stderr 会经凭据脱敏后实时上报为 agent_log,启动失败时也保留原因,不再只显示笼统的 stdout closed。MCP 子进程只读取已经存在的本机配置,不在每次启动时重写配置文件。
可配置的环境变量
| 变量 | 说明 | 默认 |
|------|------|------|
| QCANVAS_LOCAL_AGENT_PORT | 监听端口 | 17372 |
| QCANVAS_LOCAL_AGENT_HOST | 监听地址 | 127.0.0.1 |
| QCANVAS_LOCAL_AGENT_TOKEN | 连接令牌(不设则随机生成) | 随机 |
| QCANVAS_CLAUDE_COMMAND | Claude 可执行文件路径(默认自动定位随包安装的版本,找不到再用 PATH 的 claude) | 自动 |
| QCANVAS_WORKBUDDY_ENVIRONMENT | WorkBuddy 认证环境:internal、external、ioa 或 cloudhosted;未知值会显式失败 | internal |
| QCANVAS_LOCAL_AGENT_CONFIG_DIR | 配置与本机工作空间目录(主要用于隔离测试/多实例) | ~/.qcanvas |
配置持久化在 ~/.qcanvas/qcanvas-local-agent.json。
说明
- 手动模式下,画布写入与真实素材生成都会先由浏览器确认;自动模式下,Agent 可连续执行这些工具动作。
- 审批模式只控制工具动作是否弹窗。创作方向、资产顺序与质量标准由本轮选择的 Skill 和 Agent 对真实画布证据的分析决定,不在本机桥接层固化导演流程。
- 用户挂载的 Skill 不再依赖“只把正文塞进线程一次”的浏览器账本。网页每一轮都会把 Skill 文件注册到该次
agent + canvasId + chatSessionId请求作用域,Agent 必须先通过tapcanvas_user_skill_get(skillId, path="SKILL.md")读取正文;续轮、恢复会话或上下文压缩后也重新注册和读取。Skill 名称、描述或上一轮记忆不能冒充本轮已读证据,读取失败会直接中止本轮。 - Agent 按“读取画布 → 对照期望交付与真实证据 → 找关键缺口 → 执行可验证动作 → 检查结果 → 必要时询问 → 继续”的通用闭环工作。
- 当质量判断依赖生成图的真实像素时,Agent 可按所选 Skill 加载视觉分析能力,并统一通过
tapcanvas-api的/public/vision复核;配置不可用时会显式说明,不能把“有 URL”冒充“已完成视觉审片”。 - 在本机 Agent 面板选择“将本次对话转化为 Skill”时,桥接服务会让当前选中的 Codex、Claude 或 WorkBuddy 执行一次隔离的单次总结;该请求不写入当前聊天线程,也不会把本机会话交给网站 Agent。Codex 使用禁用 QCanvas MCP 的只读临时 thread,Claude 与 WorkBuddy 使用不加载 QCanvas MCP 且禁用内置工具的一次性调用;Codex 临时 thread 完成后立即归档,生成或清理失败都会显式返回。
- 每轮对话按
canvasId + chatSessionId + agentId + threadId显式隔离。新对话和续写必须由浏览器明确声明;缺少作用域、跨项目 thread、跨项目画布快照或旧版无作用域事件都会显式拒绝/忽略,不会恢复最近一次会话作为兜底。 - Agent 主动读取画布时,刷新请求与浏览器快照通过唯一
refreshRequestId关联;普通 5 秒轮询和较早的异步快照不能满足本次读取。浏览器先同步返回此刻的节点、选中状态和提示词,模型/预设目录从新鲜缓存读取或标记为正在刷新,不得阻塞节点事实。 - WorkBuddy 只获得 QCanvas MCP 工具和本轮附件的精确读取权限,不会获得任意 shell 或工作区文件读写权限;恢复会话时还会核对 SDK 返回的 session id 与工作区路径。
- 令牌仅用于本机
127.0.0.1回环连接的鉴权。
画布 MCP 工具
tapcanvas_user_skill_get:读取当前请求明确挂载的用户 Skill。无path时只返回文件清单;path="SKILL.md"返回入口正文,入口引用的其他文本文件按精确相对路径继续读取。跨请求、跨画布、路径穿越、未知文件和二进制正文读取都会显式失败。tapcanvas_flow_get:读取浏览器实时画布快照。tapcanvas_node_context_bundle_get:按nodeId读取节点完整data、上下游、节点契约、已绑定预设和当前启用模型;省略nodeId时只允许画布恰好选中一个节点。歌词时间码、对白、脚本等决定交付物的精确正文必须通过它读取,tapcanvas_flow_get的截断预览只用于导航。节点原始data是独立事实,即使预设或模型目录暂时不可用也会照常返回,并在presetBinding、modelCatalog与capabilityErrors中显式标记故障。tapcanvas_node_presets_get:读取浏览器已同步的真实节点预设,可按精确id和type筛选。tapcanvas_node_prompt_preview:查看节点当前提示词、绑定预设、精确差异和结构性就绪状态;它不会伪装成生成 runner 的最终提示词编译结果。省略nodeId时同样要求恰好选中一个节点。预设或模型目录不可用时仍返回当前提示词,并把差异/就绪度标成unavailable及明确错误。tapcanvas_assets_search:搜索当前项目资产、当前画布真实产物,并可按bookId/chapter纳入书籍中已确认的角色卡与语义资产;返回稳定entityId/entityType,只读,不触发写入确认。tapcanvas_prompt_reference_bind:把搜索后确定的实体绑定到目标节点。调用方必须提交包含全部所选稳定 token 的完整最终prompt,并把 token 放在真正引用该身份的语义位置;角色、场景、道具优先选择锚点暴露的role/scene/prop候选,只有整张图片作为普通视觉参考时才选择canvasNode。工具不再用append/prepend猜位置,会写入原子@tc_ref_*、promptReferenceBindings、assetInputs、参考 URL 与必要的画布连线,并替换旧 managed contract;写入后回读节点,只有verification.satisfied=true且 required/used 数量相等才算完成。回读前会先等画布真正落库(见下),并允许少量重试;回读始终不满足时,报错里会同时给出persistence(saved/persistedVia/persistDetail)与readbackAttempts,用于区分"引用没绑上"和"画布改动没写进服务端"。tapcanvas_generation_status_get:读取节点当前执行状态、executionId、实际模型与真实素材 URL。媒体生成启动后必须用它轮询;只有status=success且hasOutput=true才构成素材交付证据。- 项目与书籍事实工具:
tapcanvas_project_flows_list、tapcanvas_project_context_get、tapcanvas_books_list、tapcanvas_book_index_get、tapcanvas_book_chapter_get。 - 分镜与审片事实工具:
tapcanvas_book_storyboard_plan_get、tapcanvas_storyboard_source_bundle_get、tapcanvas_storyboard_continuity_get、tapcanvas_video_review_bundle_get;tapcanvas_book_storyboard_plan_upsert可写入计划,overwriteMode=replace或resetChapterChunks=true时始终要求浏览器明确确认。 - 运行诊断工具:
tapcanvas_pipeline_runs_list、tapcanvas_pipeline_run_get、tapcanvas_executions_list、tapcanvas_execution_get、tapcanvas_execution_node_runs_get、tapcanvas_execution_events_list。
上述节点取证工具与云端 Agents Bridge 使用同一组顶层响应契约(nodeContract、presetBinding、modelCatalog、divergence、structuralReadiness);浏览器会同时同步运行时节点 kind 到规范契约的真实映射,因此 storyboardImage、composeVideo 等派生 kind 不需要本地 Agent 维护第二套节点知识。
tapcanvas_create_generation_flow:按与网络 Agent 相同的nodes[1..50]服务端契约批量创建普通媒体生成节点。浏览器先持久化当前 live canvas,服务端一次性编译节点、稳定引用、真实 URL 槽位和连线,成功后浏览器重新加载当前 flow;它不会自动提交生成。结构化工作台节点继续使用tapcanvas_flow_patch。tapcanvas_media_node_generate:显式启动一个真实存在的图片或视频节点,并立即返回accepted/status=queued/executionId,不再让 MCP 工具调用阻塞等待供应商生成完成。创建或 patch 节点不会自动生成;只有 Agent 规划的参考/创意批次下游步骤使用approvalPolicy=require_direct_upstream,其他直接生成、重生成与审片资产使用none;只有明确写生产/书籍语义元数据时使用productionMetadataPolicy=persist,普通生成使用canvas_only。accepted只表示真实执行已启动,不是素材交付;Agent 必须继续调用tapcanvas_generation_status_get,直到节点status=success且至少存在一个非空真实素材 URL,失败状态必须原样上报。tapcanvas_flow_patch:提交需浏览器确认的画布结构变更。必须至少包含一项真实 mutation;空 patch、只有allowOverwrite、空的patchNodeData.data,以及新建但没有text/prompt/content/textResults正文的 text 节点都会被拒绝。只有“完整MV提示词”一类标题而没有正文的节点不算交付。写入后 Agent 必须通过tapcanvas_node_context_bundle_get回读交付节点并逐项对照用户请求与本轮 Skill;当前画布无法持久化时也不会把本地内存变更误报成成功。
画布有两条互斥的落库路径,按"协作通道此刻是否真的在写"切换:实时协作握手完成(ready)时,改动经协作通道逐条 op 写入 flow 行,整图 REST 保存让路;协作正在连接、断开、重连耗尽或压根没开时,落库交还给整图 REST 保存。唯一例外是"协作断线但别的协作者仍在线"——对方的会话还在重写 flow 行,本地这份落后的整图会覆盖他们的成果,因此宁可不写,并如实报成未落库。
所有浏览器侧写画布的工具都会给出真实的 saved 与 persistedVia(rest/collaboration/null):REST 保存被跳过或失败会如实报出原因,协作通道路径则等服务端 ack 完本地队列才算落库。因此工具结果里的 saved=false 表示"这次写入没有落库证据",不能当作已保存。
当资产搜索返回多个会实质改变产物的候选时,本机 Agent 使用 tapcanvas_request_user_input 把候选渲染为选择卡,并在该回合停止;用户回答后才绑定精确实体。浏览器桥不通过关键词自动选择候选,也不会把显示名称当作资产身份。
实时节点、选中态、预设、模型目录、资产搜索与生成状态来自已连接浏览器同步的 live snapshot;项目、书籍、分镜、pipeline 和 execution 工具则由浏览器使用当前登录态代理到统一的 /public/agents/tools/execute,继续执行相同的用户/project/flow 隔离。本机 Agent 不读取服务端数据库,也不持有长期 API Key。未知节点、按精确 id 查询的未知预设会显式报错;预设或模型目录加载失败不会伪造成成功空目录,也不会阻断 tapcanvas_node_context_bundle_get 返回真实节点 data 或 tapcanvas_node_prompt_preview 返回当前提示词,而是返回明确的 unavailable/error 诊断。只有确实要求完整预设目录的 tapcanvas_node_presets_get 会因目录不可用显式失败。每次主动刷新都会返回 snapshotFreshness.refreshConfirmed;未收到关联响应时,即使缓存年龄很短也标记 stale=true。
每轮聊天提交的图片/视频模型是结构化硬约束。模型选择器、画布快照与实际 runner 统一读取 /generation/models/:kind 的可执行目录;本机 Agent 创建节点和启动生成时都会强制写入该轮选择的精确 execution model id。目录缺失、目录在执行前变化、Agent 请求其他模型或执行结果模型不一致时分别显式返回 MODEL_UNAVAILABLE、MODEL_CATALOG_CHANGED、MODEL_SELECTION_CONFLICT 或 MODEL_EXECUTION_MISMATCH,禁止静默切到目录第一项或其他供应商。
