john-walks-slow/dsh-aivn ↗★ 0

dsh-aivn

AIVN's stage engine inside DeepSeek Harness: a workspace is a play, the playwright preset writes Stage DSL, and a Stage tab in the conversation renders it live (backgrounds, sprites, dialog, stop-point choices, line-by-line TTS). dsh-aivn:把 AIVN 的舞台引擎装进 DSH——工作区就是一部剧目,剧作家预设写 Stage DSL,对话页的「舞台」tab 实时演出(背景、立绘、台词条、停止点选项、逐句语音)。 适合需要将DSL文本实时渲染为包含背景、立绘和台词的舞台剧的用户。

Package
dsh-aivn
Compatibility
Unverified
Cordis peer range
^4.0.1
Version
0.2.0
License
MIT
Last updated
Oct 7, 2026

Install

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:john-walks-slow/dsh-aivn

dsh-aivn

简体中文 · English

把 AIVN 的舞台引擎装进 DSH。

一个工作区就是一部剧目:在里面开会话、选「剧作家」预设,对话页就多一个「AIVN」tab (只给剧作家会话——搭台助手的会话里没有这个 tab), 剧作家写的 Stage DSL 被实时演出来——背景、立绘、台词条、停止点选项都在这里;玩家点一条选项, 这句话回到剧作家手上,它接着往下写。

AIVN tab:背景、立绘、台词条,右下角是语音开关与「重听这句」

装

包是 DSH 的 bundle(package.json 里声明了 dsh.bundle.patch):

dsh plugin --profile web add dsh-aivn

从 GitHub 直装也行——lib/ 是跟踪的构建产物,所以不需要构建脚本、也不会触发 pnpm 的 allowBuilds 拦截:

dsh plugin --profile web add github:john-walks-slow/dsh-aivn
  • 手工挂:在 profile 的 cordis.patch.yml 里加一行:
- insert:
    - id: dsh-aivn
      name: dsh-aivn
      config: {}
  • 客户端半边(「AIVN」tab)挂在 conversation.view 槽上,需要 dsh-web-app。它在 package.json 的 dsh.client{platform:"web"} 里声明,不走 Loader。

可配的有六处——语音、联网检索、生图、配乐、命令行、按预设禁用工具;前五项都不配也能照常跑(只是那几项能力没有,对应工具不注册、提示词不提),禁用项默认空。

两种改法,改完都就地生效(不用重启 dsh):

  • 界面(推荐):侧边栏 Plugins → dsh-aivn 里的配置卡。分两段——P0 决定能力开不开(Key 与后端),P1 是默认就能用的口味项;顶部一行状态灯显示当前哪几项能力是开的。密钥只写不回显,卡片上另有「清除已存 Key」。
  • 配置文件:profile 的 cordis.patch.yml。界面保存的也是这里边——两种改法落在同一份配置上。
- id: dsh-aivn
  name: dsh-aivn
  config:
    ttsKeys: [""]     # 多把可轮询,摊免费额度(界面上逗号分隔)
    ttsBaseUrl: https://api.fish.audio      # 默认值,一般不用写
    ttsModel: s2.1-pro-free                 # 默认值
    ttsConcurrency: 2                       # 同时合成的上限
    searchKeys: [""]          # 给了它搭台助手才有 web_search
    searchBaseUrl: https://api.exa.ai       # 默认值
    shell: false                            # true = 给搭台助手放开 bash
    imageFormat: gemini                     # gemini | openai | modelslab(接口格式,不是产品名)
    imageBaseUrl: http://127.0.0.1:38000    # 本机 flow2api;官方 API 或别的网关填它自己的地址
    imageModel: gemini-3.0-pro-image
    imageSize: 1K                           # 1K / 2K / 4K(K 大写),或字面像素 1536x1024
    imageApiKey: ""                         # 本机网关不校验就留空(留空 = 不带鉴权头)
    imageTimeoutMs: 180000
    musicBaseUrl: http://127.0.0.1:38000
    musicModel: flow-music-lyria-3.5
    musicApiKey: ""
    musicTimeoutMs: 240000
    playwriterDisabledTools: ""             # 按预设禁用工具(逗号分隔的工具名),默认空 = 两预设一致
    stagehandDisabledTools: ""

配置面是扁平的 19 个字段(DSH 设置界面的控件只认顶层字段,嵌套写法它寻址不到):

配置项默认给了会怎样环境变量兜底
ttsKeys空舞台有语音开关,两个预设多一个 list_voices(音色库与合成共用这池 key)DSH_AIVN_TTS_KEYS
ttsBaseUrl / ttsModel / ttsConcurrencyFish 官方 / s2.1-pro-free / 2——
searchKeys空两个预设多一个 web_search(一次调用同时拿回结果与正文)DSH_AIVN_EXA_KEYS
searchBaseUrlhttps://api.exa.ai换代理 / 镜像时改—
shellfalse两个预设的 tool-bash 行真装上(默认关,与 AIVN 的 defaultOff 同口径)。bash 是预设的「一行」,只对新建会话生效—
imageFormat / imageBaseUrl / imageModel—地址与模型都给齐才有 generate_image / generate_asset(两个预设都有);cut / import_asset 不依赖它。格式是接口协议形状,不是产品名—
imageSize1K档位 1K/2K/4K(K 大写)或字面像素 1536x1024;gemini 格式只认档位,openai/modelslab 两种都收(modelslab 封顶 1024)—
imageApiKey / imageTimeoutMs空 / 180000本机网关不校验就把 key 留空(不带鉴权头);出图慢就把超时调大—
musicBaseUrl / musicModel—都给齐才有 generate_bgm(只有 Gemini 形状,没有 format)—
musicApiKey / musicTimeoutMs空 / 240000同上;一首曲子实测约 84 秒—
playwriterDisabledTools / stagehandDisabledTools空按预设禁用工具(逗号分隔的工具名,取值为「Agent 工具」清单里的工具名)。默认空 = 两预设工具面完全一致—
抠底调参见「素材生成」DSH_AIVN_CUTOUT_TOLERANCE / _KEY_SMOOTH / _EDGE_BAND / _SPILL / _SOLID_RESIDUAL 五个环境变量同名环境变量

key 两处都没有 = 那项能力停用:工具不注册、提示词里也不提。两个预设、一条 /new-play 命令、 /aivn 路由都是固定的,不可配。

改完的配置由 loader 原位提交进运行中的引用,插件据此重建能力面:那一轮的工具装/卸、搭台助手 提示词里门控的那几章、语音后端,开着的会话下一轮就用新的;唯一例外是 shell——它翻的是预设行集, 已开着的会话保持原样,新建一个才吃到。

开发期 @aivn/core 与 @aivn/stage 走 file: 依赖(指向 stage-ai 仓库)。发布版换成版本号。

用

  1. 新建会话,在座位 chip 上选 剧作家(备料的那位是 搭台助手)。 预设是在会话开始时定下的,中途换不了——想换就新建一个会话。
  2. 会话的工作目录根要有 play.json。没有的话舞台会明说「这个会话的工作目录里没有 play.json, 还不是一座剧目」——那就先把它立起来,见下。
  3. 说一句话开演。之后的一切都在舞台上发生——那句话会把剧目的开局指令(opening)一并带给剧作家, 所以不必照着剧本念开场白,随便说句什么(「开始吧」)就行。

「AIVN」tab 是会话头部的第三个 tab(Chat / Trajectory / AIVN),只在这个会话是剧作家预设时出现。

导演工具栏(提示 / 改写 / 重写)

舞台右上角那排键是给导演用的,三轮动作都走宿主侧的同一条路:

动作它会做什么什么时候能点
提示 · 引导把这句话排进剧作家的下一轮。正在演的这一拍不受影响,停止点还在,玩家照选不误随时
提示 · 打断先停下正在写的这一轮,再用这句话接着写随时
改写把最后一步写出来的内容作废,让剧作家按你交代的那句重写一遍(弹窗里预填的是当前这一句,改完提交)不在写的时候
重写把这一拍整段作废,让剧作家重新写(指令可留空 = 纯重写)不在写的时候

两件要紧的事:

  • 改写 / 重写和 AIVN 那边的同名功能不是一回事。AIVN 有一份自己的脚本模型,「改写」是直接改 那一行脚本、不经过模型;DSH 这边的剧本就是剧作家的输出、会话日志才是权威,所以「改这一句」 只能是让剧作家重写这一拍:插件往会话里追加一条替换标记(surfaceOp.replace,与 dsh-rewind 同一个手法),被作废的那一段从上下文里真的消失,模型看不到旧内容。 代价是一次重写要花一轮 LLM(AIVN 的原地改写不花),换来的是上下文不会和画面对不上。
  • 生图不在这一排:出图在搭台助手那条会话里做(generate_asset / generate_image),舞台这排键点了也没有落点, 所以不摆。

导演说的话带自己一支来源(dsh-aivn-director),不会变成一行玩家台词:舞台的时间线上 只有玩家真正说过的话。剧作家那边由系统提示词的《演出契约》第 7 条交代「(导演…」是片场喊话。

回退与分支:舞台跟着会话走

  • 回退(dsh-rewind 的「回退到这里」):它往会话里追加一条替换标记,插件收到就把舞台 整段重投影一遍——回退之后刷新或重新打开,「AIVN」tab 演到的就是你回退到的那个点。
  • 在新对话中分支(DSH 原生的分支):新会话带着父会话的前缀,插件这边不做任何事—— 第一次打开它的舞台时,帧流里一帧都没有,插件就从会话面重铺一遍,于是新会话停在分叉那一刻 (连同那一刻的停止点)。
  • 插件不做自己那一套谱系分支(AIVN 的路线图 / 旧枝那套):要分岔就用 DSH 原生的两样。

进行中浮层

右上角那枚「进行中」徽标(有东西时才出现)里是两样:排队中的提示(还没进会话的那些) 与正在合成的语音。出图与配乐不在里面——插件里它们是同步的工具调用,没有回合之外的作业可报。 玩家按了 HIDE 时它跟着舞台一起收起来。

起一座新剧目

工作区里没有 play.json 就是「这还不是一座剧目」:写一份出来就是立起一座剧目,没有生成器。 字段与布局写在两个预设的提示词里(《剧目文件》那一章,同一段文本),模型用文件工具直接写。

  • 人:输入框敲 /new-play 雨中的旧校舍。不给剧目名就取工作目录名——这一步替你写 play.json 与骨架文件,不花一次 LLM 往返。
  • Agent:照《剧目文件》写。搭台助手备料时就顺手立起来了。

/new-play 只写不存在的文件:play.json 已经在那儿就直接报错(这里已经是一座剧目, 要起新的就换一个空目录开会话),memory/always/premise.md 与角色卡已经写好就跳过、 在回执里列成「保留」。落下的骨架就是下面那张目录表里的前几行——之后缺什么补什么。 写完想知道对不对,让搭台助手调 validate_play。

一部剧目长什么样

工作目录根就是剧目根:

play.json                          剧目配置(唯一的必填文件)
memory/always/premise.md           世界观前提
memory/always/craft.md             文风与禁忌(散文,只能拿话说)
memory/always/state/scene.md       当下场景(剧作家自己写)
memory/always/state/threads.md     未了线索(剧作家自己写)
memory/always/state/state.json     好感度与旗标(同上:好感度是 0~100 的整数,键是角色 id)
characters/.md                 角色卡
assets/backgrounds/…               背景
assets/cg/…                        插图
assets/sprites//…              立绘:每个主体一个目录
assets/sfx/…  assets/bgm/…         音效与音乐
assets/manifest.json               素材描述表:素材 id → 一句话画面
endings.json                       结局账本(引擎维护、跨周目累加;不要手改)

play.json

必需字段只有两个:

{ "id": "my-play", "title": "我的剧目" }

其余字段(全部可选):

字段作用
opening开局那条 user 消息的正文。玩家在这条会话里说第一句话时,它与那句话一起发给剧作家;空舞台上的「开演」按钮发的也是它。缺省 (游戏开始,请演出第一轮)
characters[{ id, name }]。只用来给台词条配名字:立绘绑定在角色卡的 frontmatter 上
craft写作参数,见下
initialState / initialScene剧目的起始状态与起始场景
newGamePlus多周目开关(缺省 false)。开启后,同工作区新开的会话(新周目)会在提示词里注入此前已达成的结局,见「结局与多周目」
scriptLanguage剧本语言(ISO 639-1)。缺省跟随玩家说什么话
voiceLanguage / defaultVoiceId / cover语音与封面:属于 AIVN app,本插件当前不读
image{"model": "…", "size": "2K"}:这座剧目自己的出图模型与档位,覆盖部署级设置(两个字段各覆盖各的,留空即跟随部署配置)。比如一部剧的立绘要 2K 抠底、另一部的小剧场插图 1K 就够
agentsagent 运行设置:属于 AIVN app,本插件当前不读

结局与多周目

故事走到真正的终点时,剧作家把那一轮的最后一行写成结局标签(它取代那一轮的 ``):

到达结局后舞台进入终局态:不给任何按钮、不能继续,想再玩只能走 DSH 的「在新对话中分支」 (回到结局之前)或新建一条会话。结局之后引擎会单开一轮请剧作家写一段收束散文 (…),流式填进结局卡。

结局由引擎自动记到工作区根的 endings.json:跨周目累加、按 id 去重、reachedIn 记它在第几周目 达成。这份账本引擎独占,不要手改。

play.json 打开 newGamePlus 后,同工作区新开的会话(新周目)开头会把此前已达成的结局注入 剧作家的提示词,让它安排多周目要素(角色隐约记得、某些路线 / 选项不同)。引擎只保证账本可见, 不强制解锁任何内容——怎么用完全由剧作家决定。新周目开始时引擎会把 memory/always/state/ 三个状态文件重置回起点(premise.md / craft.md / 记忆索引 / 角色卡都不动)。

characters/<id>.md

一张角色卡就是一份 Markdown,可选 frontmatter:

---
name: 林
sprite: lin
voice: 短句,少用形容词
---

十七岁,话少,习惯先看窗外再看人。
  • name —— 台词条上的名字。
  • sprite —— 绑到哪个立绘目录(assets/sprites//)。不写就是角色自己的 id。 立绘是立绘自己的事:characters/ 可以没有立绘,sprites/ 也可以没有卡。
  • body —— 人设正文。

assets/manifest.json

剧作家认 id 认不出画面,靠这份描述:

{
  "veranda": { "description": "黄昏时分的走廊,木地板反着暖光" },
  "lin/normal": { "description": "林,常服,平静的神色" }
}

键是素材 id,不是路径——不带目录前缀,也不带扩展名。写成 backgrounds/veranda.png 不会报错,只是永远匹配不上,剧作家会以为这件素材没有描述。三种键形:

素材键
背景 / 插图 / 音效 / 音乐文件名去掉扩展名(veranda)
立绘(整主体)立绘目录名(lin)
立绘(单个差分)/(lin/normal)

值里除了 description 还能写 tags、title、framing、stature、anchor (立绘摆位),音乐还能写 mood、scene、durationSec、loop、volume。

背景、插图、音效、音乐按扩展名白名单收(png/jpg/jpeg/webp/mp3/ogg/wav/m4a);立绘按 sprites// 分目录,每个目录里的第一个文件是找不到指定差分时的兜底。

craft:写作参数

play.json 的 craft 段,三个字段都可不写(不写 = 引擎默认):

字段取值默认
beatLengthshort / medium / longmedium
stopOptionstwo / three / four / freethree
assets.backgroundlibrary-first / library / generatelibrary-first
assets.cglibrary / generate / offgenerate
assets.spritegenerate / offgenerate
assets.audiolibrary / offlibrary

free = 固定停在自由输入框,不给选项面板。

素材来源四类是给剧作家的意向指令:引擎按这四项把「缺素材时怎么办」写进剧作家的《写作参数》——例如 cg: off 让它别写 ``、background: generate 让它自己出图。注意两点:

  • 没有跨剧目素材库(应用级 library/ 永久不做):library / library-first 里「用库」那一支永远走不到,会退化成「用本剧目已有的 / 出图」;
  • 生图那几支还要看有没有配生图后端:没配时会自动改成「用已有素材或旁白交代」,不会教剧作家去调一个不存在的工具。

文风、禁忌、称呼习惯这类只能拿话说的口径写在 memory/always/craft.md,不在 play.json 里。

这一段用 edit 定点改(只动 craft 这一个键,文件里其余部分一个字节都不碰)。工具里没有 set_craft:写文件就是写文件。写错的值引擎静默当没写——改完让搭台助手调 validate_play, 它会把不认的取值报出来。

theme.json:舞台皮肤

剧目根可以放一份 theme.json,改这座剧目的舞台外观:键就是 @aivn/stage/stage.css 里 .stage-root 上的 CSS 变量名,值过白名单校验。不放这份文件就是默认皮——一个变量都不注, 画面与从前逐像素一致。

{
  "--dialog-bg": "linear-gradient(178deg, rgb(16 14 20 / 0.94), rgb(8 7 10 / 0.96))",
  "--dialog-ink": "#f4eee0",
  "--stage-bg": "#0b0a12",
  "--stage-radius": "6px",
  "--accent": "#8a5cf6",
  "--accent-ink": "#f7fbff",
  "--font-ui": "\"Noto Serif CJK SC\", serif"
}

十七个可设置的键,分五组:

组键取值
台词条--dialog-bg颜色,或 linear-gradient(deg, , )
--dialog-line、--dialog-ink、--dialog-ink-soft、--dialog-ink-thought、--dialog-ink-faint颜色
--dialog-shadownone,或 0 10px 30px rgb(0 0 0 / 0.45) 这样的「x y 模糊 颜色」
衬底与圆角--stage-bg颜色(图片未到或加载中露出的底)
--stage-radius0px–24px
--sprite-dim0.2–1(1 = 非发言人立绘完全不压暗)
选肢卡--choice-bg、--choice-line、--choice-ink颜色
字体--font-ui逗号分隔的字体名,整串 ≤ 200 字符
主色--accent、--accent-ink、--accent-soft颜色

颜色写法:#rgb / #rrggbb / #rrggbbaa / rgb() / rgba() / hsl() / hsla()(空格与逗号两种 参数语法都认)。不认颜色名、var()、calc()、url()——这条通道收的是值,不是 CSS 文本。

两个入口:

  • 让搭台助手改:把想要的基调说清楚,它调 set_stage_style 写文件,写完立刻把新皮肤推给 同一座剧目已经打开的舞台(不用刷新)。不给参数调用一次 = 看当前生效值与默认值对照。
  • 自己手改:改完刷新页面或切一次会话生效(手改不广播)。

白名单外的键与非法值,手改时只丢那一项,工具调用时整次拒绝(一个字节都不写);文件整个坏掉时 舞台回默认皮、剧目照常开演。

两个预设

id名字干什么
aivn-playwriter剧作家实时写 Stage DSL 的那位;它的输出被接进舞台
aivn-stagehand搭台助手备料:写设定、角色卡、创作口径、挑音色、出图与入库、配乐、查资料

两个预设的行集同构:指令文件发现(AGENTS.md)+ persona(就是那份提示词)+ 文件工具 + 文件检索 + 技能库(自带的 skills/,见下)+ 一行默认关的 tool-bash(shell: true 才真装上)。 工具面也完全一致(见「Agent 工具」),角色差别只剩 persona、注入内容与舞台管线。 预设里不会再列一行 dsh-aivn——宿主已经装了本插件,再来一行会把路由与事件订阅重复装一遍。

只有剧作家预设的会话会进舞台管线。搭台助手说什么都不上台。

技能库(两个预设)

插件自带三份做法速查,随包发布(skills/),装进两个预设的会话:

技能讲什么
aivn-play-setup起新剧目 / 改设定的四步做法与各文件写法(premise / craft.md / craft 段 / 角色卡 / 记忆卡 / 素材表)、craft 取值、备料顺序
aivn-visual-craft画风锚点写在哪、角色外形怎么锁(头身比 / 五官 / 服装)、差分布局与命名、图单怎么写、可直接粘贴的生图提示词写法
aivn-audio免费 BGM / 音效去哪里找、哪档授权能商用、六大场景与常见音效类别的选源、再分发与 AI 训练红线

清单进 system prompt(只列名字与一句话),模型觉得对上了才加载全文——三份都是长篇,不该每轮全读。 includeDefaultRoots: false 是刻意的:宿主上那几十个本机运维技能不该挤进这两个预设的清单。

上下文注入

剧作家的系统提示词由两部分拼成,中间夹着每轮注入的剧目上下文——剧作家不需要自己去 ls + read 一圈就知道这部戏的设定、有谁、有什么素材、现在演到哪儿:

段内容来源
静态前半身份、怎么工作、剧目在哪persona 的 prefix
《剧本语言》正文用哪种语言写play.json 的 scriptLanguage
《剧目设定》世界观前提memory/always/premise.md
《角色表》每张卡的正文 + 音色 + 立绘差分;只有立绘没有卡的主体单列一节characters/*.md
《素材清单》背景 / 音乐 / 音效 / 插图的 id + 描述;有音乐音效时附编排规则assets/ + assets/manifest.json
《写作参数》每轮多长、给几条选项、素材来源,外加创作口径散文play.json 的 craft + memory/always/craft.md
《记忆索引》每张设定卡一行(分类 / 标题 / 路径 / 摘要)memory/index/**
静态后半剧本格式、记忆卡怎么写、引入新角色、演出契约插件注册的尾段
【状态】场景、好感度、旗标、活跃剧情线(每轮变化的 user 角色快照)memory/always/state/*

这些段只挂给剧作家的会话(注册在 Agent scope 上),搭台助手看不到舞台契约。 快照按秒级 TTL 缓存:一个 turn 里的多个 step 读到同一份,跨轮自然重读。 改完文件不用做别的,下一轮就生效。

搭台助手的注入是另一套(同样注册在它自己的 scope 上):

段内容来源
《剧本语言》给演出看的内容用哪种语言写(与用户对话仍是中文)play.json 的 scriptLanguage
《当前状态》剧目文件清单(路径 + 大小,三层深)+ 开演条件报告工作目录 + readiness

它不需要舞台契约(不写剧本),也不需要角色表那种逐条展开——它要的是「现在盘上有什么、 还缺什么」,刚写完文件下一轮就看得见。

Agent 工具

工具跟着预设装、跟着预设卸。validate_play 两个预设都有;其余按角色分。 剧作家的停止点不是工具:它是剧本正文最后一行的一个标签——(选项面板)、 (自由输入框)、(这一段自然演完)。轮尾因此是一条助手消息, DSH 的「在新对话中分支」与舞台重建(只重放助手文本)都认得上。**故事真正的终点改用 ** (同为末行标签、取代那一轮的 ``,见「结局与多周目」)。 模型用文件工具就能做的事一律没有:play.json、craft 段、memory/always/state/ 都是文件工具 写出来的,写成什么样由提示词说清(见上「起一座新剧目」);「这座剧目有什么素材」也一样—— 剧作家的 A 区每轮注入《素材清单》与《角色表》(id + 描述),搭台助手看《当前状态》的文件清单、 要描述就 read assets/manifest.json。

两个预设装同一套 AIVN 工具(工具清单见 src/tool-catalog.ts);「门控」列只有配了对应后端 / key 才注册的项。 按预设禁用某几个工具,用插件配置 playwriterDisabledTools / stagehandDisabledTools(逗号分隔的工具名,默认空 = 两预设完全一致)。

工具门控作用
validate_play—剧目自查:play.json 读不读得出来(缺字段、坏 JSON 会给原因)、craft 里有没有引擎不认的取值、状态文件好不好、故事前提、角色卡张数、立绘、背景、素材条数、出图台账里有没有指向不存在文件的登记。刚写过剧目文件之后调它。没有硬门槛,缺什么都能开演
set_stage_style—写剧目根的 theme.json(舞台皮肤:台词条、选项卡、衬底、圆角、字体、主色),写完把全量皮肤推给同剧目已打开的舞台。三态:省略 = 不动、给值 = 改、null = 回默认;不带参数调用 = 看当前值。值格式与可设置的键见上
generate_image生图后端纯生成:一段画面描述 → 一张候选图(回执给文件路径与预览),返回时不绑定任何剧目目标、不抠底、不登记。画幅用 aspectRatio(默认 16:9);references 可垫主体 id / 剧目内路径 / http(s) 网址。落成素材另走 cut / import_asset(或直接 generate_asset)
cut—抠底:纯色底的图 → 透明 PNG(只写输出,不改源图)。source 给剧目内相对路径,output 不给就写到候选区。五档调参见下(tolerance / spill / edgeBand / keySmooth / solidResidual)。立绘登记前先跑它;抠脏了就对着同一张源图重调再跑。不依赖生图后端
import_asset—把一张图登记成剧目素材:写 assets/、补素材表(呈现声明 + 描述)、记台账,不抠底。source 给剧目内相对路径或 http(s) 网址;落位显式给——kind(background / cg / sprite)必填,立绘再给 spriteId / variant / framing / stature / title。立绘要传已抠好的透明 PNG(外部来源先 cut);original 可留抠底前原片以便重抠。不依赖生图后端
generate_asset生图后端一键:出图 +(立绘)自动抠底 + 登记,一次完成,回执给最终素材路径。参数与 import_asset 的落位一致(kind + name / spriteId / variant / framing / stature)。只有这条路由引擎自动做色键底、身份锁、差分垫 neutral;同名素材已有则直接跳过
generate_bgm音乐后端生成一首 BGM 落 assets/bgm/;同步等待(约 84 秒),name 就是剧本里 `` 引用的 id
list_voicestts.keys查 Fish 音色库挑音色:按语言 / 标签 / 标题关键词取窗口,本地按 gender 筛,按热度排序出前 25 条。挑好的 id 填进角色卡的 voice
web_searchsearch.keys联网检索:一次调用同时拿回结果与正文。只查剧目之外的事实——设定、角色、剧情都在工作区文件里

list_voices / web_search / generate_image / generate_asset / generate_bgm 在没配对应 key / 后端时 不注册,提示词里也不提它们。validate_play / set_stage_style / cut / import_asset 不门控: 它们只读写剧目文件、跑抠底,不碰生图后端——所以没配生图也能用外部工具出图、cut 抠底、import_asset 登记。 文件工具(read / write / edit / glob / grep / read_image)由预设的行集提供,两个预设都有。

素材生成

「像素从哪来」和「像素怎么变成剧目素材」是两步,工具也是分开的:

  • 一键(generate_asset):出图 +(立绘)自动抠底 + 登记,一步到位——「就想要一张能用的图」走这条。
  • **原子三件套(generate_image / cut