@starreel/mcp 0.1.160 → 0.1.163

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -146,7 +146,14 @@ export const WORKFLOW_HINT = '★三档执行策略(别把三档混着问客户)
146
146
  'generate_portraits_and_sheets(定妆图+设定图·分镜后建:先用 delete_character 删掉**全剧任何一集都不出场、后续集也不打算用**的出镜角色再出图——角色是剧级的,删了每一集的出帧装配都不再带它,只看本集分镜判不出来、拿不准就留着(一张定妆图的钱远小于后面某集丢身份锚);定妆图步对**所有未删的出镜角色**出图、不看分镜绑定,留着的都照常扣费;' +
147
147
  '画外音角色(char_type=voiceover 的旁白/电话音)本就不出图、也没有分镜绑定,**别删**,配音还靠它)→' +
148
148
  '★generate_color_script(色彩脚本·统一调色)→assign_voices(分配音色;旁白/角色库里没合适的→design_voice 按描述造一个,定样后 set_character_voice)→' +
149
- '★quote_scene_images+generate_scene_images(空景基板·出帧前必做)→frames(默认只出首帧)→★tail_frame_plan(免费·哪几镜要独立尾帧)→frames(frame_type=last_frame)→★review_frames→videos→generate_tts→compose;' +
149
+ '★quote_scene_images+generate_scene_images(空景基板·出帧前必做)→frames(默认只出首帧)→★tail_frame_plan(免费·哪几镜要独立尾帧)→frames(frame_type=last_frame)→★chain_frames(接缝·先 dry_run:true)→★review_frames→videos→generate_tts→compose;' +
150
+ '★★【接缝别跳·尾帧补完、review_frames 之前】首尾帧齐了之后调 chain_frames(dry_run:true,免费)看平台的接缝计划与 estimated_points' +
151
+ '(copy 免费、reframe 每道一张图),讲给客户、确认后不带 dry_run 执行;已接好的缝不进计划,重复调不重复扣费。' +
152
+ '★执行后 reframe 是**异步出图**:用 get_jobs 看计划里那些镜的 first_frame 出图行,等 pending/processing 全部结束(failed 的看 error_msg,单道用 chain_shot_from 重接)再 review_frames——' +
153
+ '旧首帧还在时 get_storyboards 的 frame_status 仍是 ready,看不出新图在出还是失败了。' +
154
+ 'get_jobs 清空后再用 get_storyboards 核对 seam_state:晋升被拒的替换图不留在 get_jobs 里,那道缝会仍是 unchained(review_frames 也会报 seam_unchained),按它的 action 重接。' +
155
+ '没落地就审,审的是旧首帧,token 在新首帧落地后作废。' +
156
+ '逐镜/批量出帧的集平台多半没自动接过(get_storyboards 的 seam_state=unchained 就是),跳过它不报错——代价是镜与镜之间画面对不上,成片一处一个跳切。' +
150
157
  '★★【尾帧别跳·出帧是两趟】generate_frames 默认只出首帧。约三成的镜**末态≠首态**(大运镜/物体脱手/状态改变),这些镜需要一张独立尾帧,而判据在平台侧、你从分镜文本猜不出来——' +
151
158
  '所以首帧出完必须调一次免费的 tail_frame_plan 拿逐镜清单,再 frame_type=last_frame 补上(generate_frames 的响应体里 shots_needing_last_frame 就是这个数,不为 0 别直接去 review_frames)。' +
152
159
  '跳过不报错、不拦你——代价是那些镜出视频时只有首帧一个锚,末态由模型自由发挥:动作做不到位、大运镜结束又回到起点构图。生产实测 32 集里 30 集整集只出了首帧,其中 23 集一路出完了视频。' +
@@ -240,7 +247,13 @@ export const WORKFLOW_HINT = '★三档执行策略(别把三档混着问客户)
240
247
  '★两条导入通道都是确定性的——写错了也会原样建进去,所以**先取契约再自检再导**:分镜表走 get_storyboard_table_spec → check_storyboard_table → import_storyboard_table;' +
241
248
  '客户自己的工具/表格能导出结构化数据、或让外部 AI 直接产 JSON 时走 get_bulk_import_spec → check_bulk_import → bulk_import_storyboards(只建分镜;角色/场景/道具由 extract_assets 从剧本提取,导入按名字绑定已有的——先 extract 再导)。' +
242
249
  '两条导入默认带 auto_complete(后台 AI 补专业字段 + 出图/视频提示词,文本步后付,调用前告知客户):回执 started=true 就用 get_autofill_status 轮询到 done 再 review_storyboards——补全会改镜,先审的 token 会失效。' +
243
- '用 get_pipeline_status 查进度(按项目类型返回专属步骤)。';
250
+ '用 get_pipeline_status 查进度(按项目类型返回专属步骤)。' +
251
+ '★★【开场方案·建剧后第一件事·免费】先问基本视频参数(项目类型/画幅/集数×每集分钟/题材:写实真人 realistic_human·动漫风格化 stylized·产品空镜 product/原声还是配音),' +
252
+ '再调 get_production_menu 拿**当前可用**的三档套餐(效果说明+实时预估+不计入项)讲给客户——别凭记忆推荐模型,某些模型对某些题材会临时不可用,菜单已过滤;' +
253
+ '然后让客户选执行模式(pro 每步自己把控 / auto 一键出片 / custom 选环节托管)、预算 budget_points 与自动追加上限(0/10/20/30%),' +
254
+ '把汇总讲清楚、客户明确同意后才调 confirm_production_plan(customer_confirmed:true)——不许替客户确认。' +
255
+ '确认过方案的剧:收费派发前平台复核模型仍可用、报价上界不超过预算×(1+追加%),被拦(402 BUDGET_WOULD_EXCEED / 409 MODEL_UNAVAILABLE)就停下问客户,别自己换模型或调预算。' +
256
+ 'confirm 返回 403 PRODUCTION_PLAN_NOT_OPEN = 本剧未开放(灰度),照原流程逐步确认。';
244
257
  const ETHNICITY_CODES = [
245
258
  'east_asian', 'southeast_asian', 'south_asian', 'central_asian',
246
259
  'caucasian', 'middle_eastern', 'african', 'latin_american',
@@ -824,6 +837,7 @@ export function registerProduceTools(server, client) {
824
837
  '返回 shots_needing_last_frame(总数)、ready(已有首帧、现在就能补尾帧的镜)、' +
825
838
  'pending_first_frame(还需要尾帧但首帧尚未落地的镜——等首帧出完再调一次本工具)。' +
826
839
  '拿到 ready 清单后:quote_frames + generate_frames 带 frame_type=last_frame 即可批量补。' +
840
+ '★尾帧补完(或本工具报 0)之后的下一步是接缝:chain_frames(dry_run:true) 看计划与预估、客户确认后执行,再 review_frames。' +
827
841
  '★跳过尾帧不会报错,但那些镜出视频时只有首帧一个锚,末态由模型自由发挥——' +
828
842
  '动作做不到位、大运镜结束又回到起点构图,多半就是这么来的。零扣费,可随时调。', { episode_id: z.number().int().positive() }, async ({ episode_id }) => jsonResult(await client.produceGet(`/episodes/${episode_id}/frames/tail-plan`)));
829
843
  server.tool('quote_frames', '报价:给某一集批量出帧要多少点。返回 frames_to_generate、estimated_points、quote_id。零扣费。' +
@@ -1873,6 +1887,66 @@ export function registerProduceTools(server, client) {
1873
1887
  'spent_source=usage_mirror 表示账本暂不可达、回退到本地镜像(偏少,不含文本/配乐),向客户报数时须注明。' +
1874
1888
  '★不含账号级语音扣费:音色库克隆、音色设计、音色试听不属于任何一部剧,只记在账号账单里——' +
1875
1889
  '客户问「一共花了多少」时要说明这部分另计,不要把 spent 当成全部费用。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.produceGet(`/dramas/${drama_id}/budget-status`)));
1890
+ // ========== 一键出片开场方案(2026-10-15)==========
1891
+ server.tool('get_production_menu', '★开场第二步(免费·只读·不需要剧号):按客户的基本视频参数,返回**当前可用**的三档模型套餐(省钱/标准/高品质)。' +
1892
+ '每档给:图片模型+视频引擎+分辨率、效果说明(effect)、实时预估(estimate:每集与全剧的 typical 通常花费与 upper 上界,breakdown 分项)、' +
1893
+ 'warnings(所选模型近期繁忙/失败偏多)、substitutions(本档首选模型暂不可用、退到后备组合的原因)。' +
1894
+ '某档 available=false 表示该档模型当前都不可用(unavailable_reason 说明),别推荐它。' +
1895
+ 'estimate=null 表示价格服务暂时取不到实时单价——如实告诉客户「暂时估不出」,别自己编数字。' +
1896
+ 'not_included 列出不在预估里的花费(文本步、配音配乐、质检重出),一并讲给客户;质检重出这部分正是「自动追加」兜底的。' +
1897
+ 'availability 是全部模型对该题材的可用性(专业客户自选模型时用,unavailable 的不能选)。' +
1898
+ '★题材 content_class 决定可用性:同一引擎可能动漫可用、写实真人暂不可用——按剧情实际画面选,别为了用某个模型改题材。', {
1899
+ content_class: z.enum(['realistic_human', 'stylized', 'product']).describe('题材:realistic_human 写实真人 / stylized 动漫·风格化 / product 产品·空镜'),
1900
+ episodes: z.number().int().min(1).max(200).describe('集数'),
1901
+ minutes_per_episode: z.number().positive().max(30).describe('每集时长(分钟),预估按每镜约 5.3 秒折算镜数'),
1902
+ aspect_ratio: z.string().optional().describe('画幅,如 9:16 / 16:9(只影响视频报价)'),
1903
+ assets: z.object({
1904
+ characters: z.number().int().min(0).max(100).optional(),
1905
+ scenes: z.number().int().min(0).max(200).optional(),
1906
+ props: z.number().int().min(0).max(200).optional(),
1907
+ }).optional().describe('资产图粗估的数量假设(默认 6 角色/8 场景/6 道具),知道大概数量就传,预估更准'),
1908
+ }, async (args) => jsonResult(await client.producePost('/production-menu', args)));
1909
+ server.tool('confirm_production_plan', '★开场最后一步:把客户**明确同意**的整份方案写进本剧(免费)。写入图片模型/视频引擎/分辨率/预算,并记录题材、执行模式、自动追加上限与确认快照。' +
1910
+ '调用前必须把汇总完整讲给客户:所选套餐与效果、全剧预估(通常值与上界)、执行模式、预算、追加比例,以及「追加只在预算用完后才动用、到硬上限会停下来问」——客户点头才传 customer_confirmed:true。' +
1911
+ '★确认后平台在每次收费派发前复核:①本剧模型对本剧题材仍可用,否则 409 MODEL_UNAVAILABLE;②报价上界+已花 ≤ 预算×(1+追加%),否则 402 BUDGET_WOULD_EXCEED(都未扣费)。' +
1912
+ '被拦就停下问客户,别自己换模型、别自己调预算。' +
1913
+ '★执行模式本期只记录:各层审查(review_*)与 agent 质检照旧,error 照旧要客户知情才能 acknowledge_review。' +
1914
+ '★选套餐要带 expected_combo(该档 combo 原样)与 expected_total_upper:确认的必须是客户看到的那组模型与预估。' +
1915
+ '409 PACKAGE_CHANGED = 菜单返回后该档换了组合或预估明显上涨,返回体里有新的组合与预估,重新讲给客户、同意后带新值再确认;' +
1916
+ '409 PACKAGE_UNAVAILABLE / MODEL_UNAVAILABLE = 确认这一刻该模型不可用了,重新 get_production_menu 让客户改选。403 PRODUCTION_PLAN_NOT_OPEN = 本剧未开放(灰度),照原流程逐步确认。', {
1917
+ drama_id: z.number().int().positive(),
1918
+ customer_confirmed: z.literal(true).describe('客户已听完汇总并明确同意(必须为 true;不许替客户确认)'),
1919
+ content_class: z.enum(['realistic_human', 'stylized', 'product']),
1920
+ package_key: z.enum(['economy', 'standard', 'premium']).optional().describe('选菜单里的一档;与 custom 二选一'),
1921
+ expected_combo: z.object({
1922
+ image_model: z.string(),
1923
+ video_engine: z.string(),
1924
+ video_resolution: z.string(),
1925
+ }).optional().describe('选 package_key 时必填:把 get_production_menu 里该档的 combo 原样传回。确认这一刻若该档已换成别的组合,平台回 409 PACKAGE_CHANGED、不写入'),
1926
+ expected_total_upper: z.number().positive().optional().describe('该档的 estimate.total.upper(客户看到的全剧预估上界)。重算后涨幅超过 5% 也会 409 PACKAGE_CHANGED'),
1927
+ assets: z.object({
1928
+ characters: z.number().int().min(0).max(200).optional(),
1929
+ scenes: z.number().int().min(0).max(200).optional(),
1930
+ props: z.number().int().min(0).max(200).optional(),
1931
+ }).optional().describe('调 get_production_menu 时传过 assets 就原样再传一次,否则按默认数量重算的预估对不上客户看到的'),
1932
+ custom: z.object({
1933
+ image_model: z.string(),
1934
+ video_engine: z.string(),
1935
+ video_resolution: z.enum(['480p', '720p', '1080p']).optional(),
1936
+ }).optional().describe('专业客户自选模型(须在 get_production_menu 的 availability 里是可用的);与 package_key 二选一'),
1937
+ execution_mode: z.enum(['pro', 'auto', 'custom']).describe('pro 每步客户把控 / auto 一键出片 / custom 按环节选托管'),
1938
+ stage_control: z.object({
1939
+ script: z.enum(['customer', 'agent']), storyboards: z.enum(['customer', 'agent']), assets: z.enum(['customer', 'agent']),
1940
+ frames: z.enum(['customer', 'agent']), videos: z.enum(['customer', 'agent']), compose: z.enum(['customer', 'agent']),
1941
+ }).optional().describe('execution_mode=custom 时必填:每个环节 customer(客户把控)或 agent(托管)'),
1942
+ budget_points: z.number().int().positive().optional().describe('预算(点)。auto / custom 必填(客户授权 agent 自主花费的上限);建议不低于所选套餐的 estimate.total.upper'),
1943
+ overrun_pct: z.union([z.literal(0), z.literal(10), z.literal(20), z.literal(30)]).optional().describe('自动追加上限(%),默认 0。硬上限 = 预算 × (1 + 本值/100)'),
1944
+ episodes: z.number().int().min(1).max(200),
1945
+ minutes_per_episode: z.number().positive().max(30),
1946
+ }, async ({ drama_id, ...body }) => jsonResult(await client.producePost(`/dramas/${drama_id}/production-plan`, body)));
1947
+ server.tool('get_production_plan', '查本剧已确认的开场方案(免费)。返回方案快照、当前模型、models_unavailable_now(本剧模型此刻已不可用时非空——出图/出视频前要先问客户怎么办)、' +
1948
+ 'budget(含 hard_cap 硬上限、overrun_in_use 是否已在动用追加额度)。confirmed=false 表示还没确认过方案。' +
1949
+ '★budget.overrun_in_use 变成 true 时主动告诉客户「预算已用完、正在动用追加额度,还剩 cap_remaining 点」。', { drama_id: z.number().int().positive() }, async ({ drama_id }) => jsonResult(await client.produceGet(`/dramas/${drama_id}/production-plan`)));
1876
1950
  // ========== P1 · 整集配音(成片前的强制音频步)==========
1877
1951
  server.tool('assign_voices', '★给本集所有角色分配音色(配音导演 agent 按性别/性格/年龄/角色定位+项目语言选)。' +
1878
1952
  'voiceStyle 不是提取时自动填的——不分配,generate_tts 就没音色。文本步(LLM)后付。' +
@@ -2081,7 +2155,9 @@ export function registerProduceTools(server, client) {
2081
2155
  '★平台自己判哪道缝该接:有意切换(换场/时间跳跃/换装/插入镜)、已出视频的镜、已经接好的缝都会跳过——' +
2082
2156
  '「已接好」= 首帧就是上镜尾帧,或 reframe 接在上镜**当前**尾帧上,所以重复执行不会重复扣费。' +
2083
2157
  '上镜尾帧后来被重生过的缝会重新出现在计划里,那道缝确实断了。只补个别缝用 chain_shot_from_prev / chain_shot_from。' +
2084
- '执行后改了首帧的镜若已有视频会被标为待重生。执行完用 get_storyboards 核对 seam_state。', {
2158
+ '执行后改了首帧的镜若已有视频会被标为待重生。★执行只派发 reframe、不等出图:用 get_jobs 看这些镜的 first_frame 出图行,' +
2159
+ '等 pending/processing 全部结束(failed 的看 error_msg,单道用 chain_shot_from 重接;旧首帧还在时 get_storyboards 的 frame_status 仍是 ready、看不出失败),' +
2160
+ '再用 get_storyboards 核对 seam_state、review_frames——提前审会审到旧首帧,token 随后作废。', {
2085
2161
  episode_id: z.number().int().positive(),
2086
2162
  dry_run: z.boolean().optional().describe('true=只看计划与预估(免费,推荐先调一次);不传=真执行'),
2087
2163
  }, async ({ episode_id, dry_run }) => jsonResult(await client.producePost(`/episodes/${episode_id}/chain-frames`, dry_run ? { dry_run: true } : {})));