@lingjingai/scriptctl 0.44.0 → 0.46.0

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.
Files changed (42) hide show
  1. package/changes/0.45.0.md +39 -0
  2. package/dist/domain/ingest/serial-context.d.ts +15 -27
  3. package/dist/domain/ingest/serial-context.js +106 -57
  4. package/dist/domain/ingest/serial-context.js.map +1 -1
  5. package/dist/infra/ingest/review-renderer.js +11 -2
  6. package/dist/infra/ingest/review-renderer.js.map +1 -1
  7. package/dist/infra/ingest/video-transcode.js +16 -3
  8. package/dist/infra/ingest/video-transcode.js.map +1 -1
  9. package/dist/llm/config.js +5 -1
  10. package/dist/llm/config.js.map +1 -1
  11. package/dist/llm/registry.d.ts +1 -0
  12. package/dist/llm/registry.js +10 -4
  13. package/dist/llm/registry.js.map +1 -1
  14. package/dist/llm/tasks/ingest/episode-assets.d.ts +3 -2
  15. package/dist/llm/tasks/ingest/episode-assets.js +119 -25
  16. package/dist/llm/tasks/ingest/episode-assets.js.map +1 -1
  17. package/dist/llm/tasks/ingest/name-fix.d.ts +9 -0
  18. package/dist/llm/tasks/ingest/name-fix.js +64 -0
  19. package/dist/llm/tasks/ingest/name-fix.js.map +1 -0
  20. package/dist/llm/tasks/ingest/video-serial.d.ts +2 -1
  21. package/dist/llm/tasks/ingest/video-serial.js +184 -85
  22. package/dist/llm/tasks/ingest/video-serial.js.map +1 -1
  23. package/dist/llm/tasks/schemas.d.ts +3 -0
  24. package/dist/llm/tasks/schemas.js +240 -0
  25. package/dist/llm/tasks/schemas.js.map +1 -1
  26. package/dist/llm/types.d.ts +1 -1
  27. package/dist/llm/types.js.map +1 -1
  28. package/dist/usecases/ingest/pipeline.js +13 -2
  29. package/dist/usecases/ingest/pipeline.js.map +1 -1
  30. package/dist/usecases/ingest/serial-govern.d.ts +4 -0
  31. package/dist/usecases/ingest/serial-govern.js +211 -40
  32. package/dist/usecases/ingest/serial-govern.js.map +1 -1
  33. package/dist/usecases/ingest/status.js +3 -3
  34. package/dist/usecases/ingest/status.js.map +1 -1
  35. package/dist/usecases/ingest/view-server.js +1 -1
  36. package/dist/usecases/ingest/view-server.js.map +1 -1
  37. package/package.json +1 -1
  38. package/skills/scriptctl/SKILL.md +13 -2
  39. package/skills/scriptctl/references/atomic-write-workflow.md +45 -16
  40. package/dist/domain/ingest/asset-state-md-parser.d.ts +0 -2
  41. package/dist/domain/ingest/asset-state-md-parser.js +0 -133
  42. package/dist/domain/ingest/asset-state-md-parser.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/llm/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/llm/registry.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
- import type { Delta } from "../../../domain/ingest/serial-context.js";
1
+ import { type Delta } from "../../../domain/ingest/serial-context.js";
2
2
  import type { LlmTaskExecutor } from "../../types.js";
3
3
  export declare const EPISODE_ASSETS_SYSTEM: string;
4
4
  export declare function buildEpisodeAssetsUser(contextMd: string, bodyMd: string): string;
5
5
  export declare function runEpisodeAssets(executor: LlmTaskExecutor, contextMd: string, bodyMd: string, signal?: AbortSignal): Promise<{
6
- markdown: string;
7
6
  delta: Delta;
7
+ raw: string;
8
8
  }>;
9
+ export declare function toDelta(input: unknown): Delta;
@@ -2,33 +2,41 @@
2
2
  // dialogue/action, speakers by name) — no pre-extracted cast/props/state. Walking
3
3
  // episodes IN ORDER with a running context that starts EMPTY, the model discovers
4
4
  // entities, importance, 造型 (looks), identity merges, and — per scene — who is
5
- // present, where, and in which look. Output is the `# 更新` md (decisions);
6
- // asset-state-md-parser turns it into a Delta. Text mode, no tool-call JSON.
7
- import { parseUpdateMarkdown } from "../../../domain/ingest/asset-state-md-parser.js";
5
+ // present, where, and in which look. Output is a structured Delta via native
6
+ // tool-calling (SERIAL_DELTA_SCHEMA): `name` and `aliases` are separate fields, so
7
+ // a canonical name can never be mangled by a markdown `名 | 名` delimiter — the
8
+ // failure mode where a model that wrote `大骨头(Big Bones / Marcus Vale)` got
9
+ // fragmented into ghost entities. Tool mode → serial profile must call functions.
10
+ import { emptyDelta } from "../../../domain/ingest/serial-context.js";
11
+ import { SERIAL_DELTA_SCHEMA } from "../schemas.js";
8
12
  export const EPISODE_ASSETS_SYSTEM = [
9
13
  "你是剧本资产/造型标注器。前段只给了正文(场景、台词、动作),**没有任何现成的人物/道具/造型清单**——资产与造型全部由你从正文里逐集发现、逐集维护。",
10
- "结合【已知设定】(到目前为止你已建立的登记)与【本段正文】,输出一份 `# 更新` markdown:不要代码围栏,前后无多余文字,空小节整节省略。",
11
- "**【本段正文】可能包含若干集**(每集以 `# ep_NNN` 开头);把它们当作连续推进的一段整体处理,跨集沿用同一 canonical 名字,`# 更新` 覆盖这一整段里的所有场景。",
14
+ "结合【已知设定】(到目前为止你已建立的登记)与【本段正文】,调用 `emit_delta` 工具返回一个结构化对象覆盖这一整段的所有决策。空数组就传 `[]`。",
15
+ "**【本段正文】可能包含若干集**(每集以 `# ep_NNN` 开头);把它们当作连续推进的一段整体处理,跨集沿用同一 canonical 名字。",
12
16
  "始终使用【已知设定】里的既有 canonical 名字;同一个人全剧保持同一名字。",
13
17
  "",
14
- "## 新增 本段**首次出现**、且【已知设定】里还没有的实体,每行 `- <类型> <名字> | <重要度> | <简介>`:",
15
- " 类型=人物/场景/道具;重要度=featured(值得单独出图:有名有戏的人物、反复出现的关键场景/道具)|background(龙套/背景/一次性);简介=一句话是谁/是什么。",
16
- " **凡在【本段正文】里出现的实体都要登记并给非空简介**——包括场景在场的人物/地点/道具,以及背景龙套(背景也至少给一句最简描述,别留空)。",
17
- " **简介优先照抄/概括原文自带的描写**(角色卡、场景说明、动作里的外貌服饰刻画);原文没写才结合剧情补一句。",
18
- " 群体名或复合名一律 background(轿夫4名、众人、丫鬟们、李叔和张妈)。推动剧情的关键物件即使只出现一两次也 featured(婚书、密信、玉佩、毒药)。已登记的不要重复新增。",
19
- " 人物名字**尽量用最完整的姓名**(带姓,如『苏若雪』而非『若雪』、『顾夜渊』而非『夜渊』)。",
20
- "## 合并 本集发现某名字其实是某已知实体(化名/别称/先前只用了短名或未点名):`- 本集名字 -> 已知canonical`。方向随意——系统会自动用更完整的姓名做 canonical。",
21
- "## 造型 **featured 人物 / 场景 / 道具**的**视觉外观**,每种一行 `- 实体 | 造型名(=同义) | 描述`:",
22
- " **每个 featured 实体首次出现时,先给一条『常态』基础造型**(它平时/最常见的样子)作为默认外观;之后再给特殊变化。人物=整体扮相;场景=环境外观(布景、光线、氛围);道具=物件外观。",
23
- " 造型名=需要美术单独画一张图的外观档位(常态、婚服、西装、龙形、素缟孝服;场景的 白天/夜晚/被毁;道具的 破损/发光);同一外观不同叫法用 `=` 合并(婚服=大红嫁衣)。",
24
- " **造型名必须用中文**:正文里的英文专名(套装/职业/形态名,如 Sean's Revenge、Flamecaster、Grave Priest、Shieldguard)一律译成中文再作造型名(肖恩的复仇套装、焰术师、墓祭司、盾卫);绝不把英文原名或『中文(English)』夹注写进造型名。",
25
- " 描述=这套外观长什么样的一句话(**优先用原文描写**:服饰/颜色/发型/配饰,或场景布景/道具形制),如『大红喜服,凤冠霞帔,金线云纹』。**常态描述不能留空。**",
26
- " **绝不写心情/身体状况/胖瘦**:满脸泪痕、愤怒、雍容华贵、虚弱濒死、白嫩圆润、消耗福气、受伤、昏迷、消瘦、站立、坐轮椅——这些不是造型。判据:换成它,美术要不要另画一张图。",
27
- "## 场景 本段正文里**每一个**场景谁在场、在哪、什么造型,每场一行:`- <场景id> | 地点:<场景名> | 人物:张三(婚服),李四 | 道具:婚戒`",
28
- " 场景id 用正文里给的(如 scn_012);地点/人物/道具都用 canonical 名;造型写在人物名后的括号里(没换装/沿用上场造型可不写)。**凡正文里出现的场景(跨这一段的所有集)都要有一行。**",
29
- "## 重要度 需要修订某个已登记实体的重要度时:`- 名字: featured` 或 `- 名字: background`",
30
- "## 子事件 本段关键剧情原子,每条一句话(维护剧情理解与压缩)",
31
- "## 梗概 本段一句话梗概(散文,不加 `-`);若本段含多集,概括为整段一句话。",
18
+ "**newEntities —— 本段【已知设定】里还没有的实体,每个登记一条**:",
19
+ " · name = 纯 canonical 名,**绝不含括号/斜杠/译名夹注/对白标记**(不要 name=『大骨头(Big Bones / Marcus Vale)』或『Big Bones,魂语』,而是 name=『大骨头』)。人名尽量用最完整姓名(『苏若雪』而非『若雪』)。",
20
+ " · aliases = 这段里该实体的**所有其他叫法**,逐个单列(纯名,别带『(心)』『:』『,魂语』这类对白/情绪标记):别名、译名、前世名、短名/全名、英文原名,**尤其对白说话人在正文里的写法**。正文说话人写『伊文·布鲁克斯』而你 canonical 是『大牛』→ 把『伊文·布鲁克斯』放进 aliases;写『大骨』而 canonical 是『大骨头』→ aliases 放『大骨』。系统靠 aliases 把正文里的说话人/称呼归到你这个实体,**aliases 漏了就会新造重复鬼影**。",
21
+ " · **同一个实体只登记一条,绝不拆成多条**。**不同的角色绝不互相列为别名**——哪怕关系密切、常同框:大牛 和 丹尼·克罗斯 是两个人,别把丹尼的名字写进大牛的 aliases,反之亦然。判据:aliases 只放**同一个人/物**的不同叫法,不放另一个角色。",
22
+ " · kind=actor/location/prop。",
23
+ " · description=一句话说明**这个实体本身是谁 / 什么身份 / 什么东西**,非空。**只写它自身的身份、角色、关系或外形,绝不写它所处的场景 / 环境 / 地点 / 当时在发生什么**——「夜晚,私人飞机,黑色轿车列队」「苏家餐厅,满桌酒菜」这类是场景旁白,**不是人物描述**,严禁抄进人物 description。原文有对这个实体的自我描写就照抄 / 概括;原文没写(尤其龙套)就据台词 / 称呼 / 戏份补一句最简身份(如『苏家中间人』『急诊护士』『赵长河的手下』),实在无信息就写最简类属(『白发老者』『黑衣保镖』)。场景的 description 才写环境;道具写物件本身。",
24
+ " · **登记范围**:人物、地点——凡在【本段正文】里出现的都登记(含背景龙套,群体/复合名如 轿夫4名/众人 照登);但**同一个地方只登记一次**,它的其它写法用 merges 归过去,别把一个地方的多种写法登成多条。道具——**只登记关键道具**:①剧情关键(信物/线索/推动情节,如第一集丢了第三集寻回的手机)或 ②跨≥2场需稳定复现、要美术保持一致的物件;一次性/纯功能/视觉无需追踪的(随手打电话的手机、背景杯子/路人车)不登记。",
25
+ " · 已登记过的实体不要重复登记;若它这段有了新叫法,用 merges 补,不用在 newEntities 再列一遍。",
26
+ "**merges —— 本段冒出一个称呼,其实是某个【已知设定】里已登记实体的别名(尚未登记过这个称呼)**:{from: 本段这个称呼, into: 已登记实体的 canonical}。判据:(1) 字面变体(大骨=大骨头=大骨(BigBull)、苏若雪=若雪);(2) 剧情推断同一(上下文/外观/关系/连续动作,如前文『小骨』本段点名『杰克·莱德』)。**只有当 from 确实是 into 的另一叫法时才 merge;名字或外观相似但是不同角色(如同为骷髅但身份不同)绝不 merge。** from 已经是独立登记的实体时,不要 merge(系统不会合并两个已登记实体)。",
27
+ " · **地点同样要 merge——判据一样:是不是同一个场**。同一个地方的不同写法要合成一条:①字面变体(『车轮旁』『矿车车轮旁』『矿车车轮』是同一处;带不带平台/区域前缀如『Dawnfall Online - 棺木铺』=『棺木铺』);②剧情确定同一处(同一场戏在同一空间发生)。**不是同一个场就各自独立**(矿轨修造铺 和 棺木铺 是两个地方,不合)。别因为写法带了长前缀就当成新地点。",
28
+ "**正文里每个和已登记 canonical 写法不同的名字,都要用 merges 归过去**——系统会照 merges + aliases 把正文(对白说话人、旁白文本)里的这些写法直接改写成 canonical。**漏掉某个写法,它就会变成一个游离的重复实体。** 所以本段正文里出现的每个人名/称呼,要么本身就是某 canonical,要么在 aliases/merges 里登记过。",
29
+ "looks:**featured 人物 / 场景 / 道具**的视觉外观。entity=实体 canonical 名;name=造型名;aliases=同义造型名;description=这套外观一句话。",
30
+ " **复用优先——造型默认从【已知设定】里该实体已列出的造型清单里选一个,逐字照抄那个已有造型名**。除非本段外观与所有已有造型都有实质差异(换了整套衣服/场景被毁/道具明显改形),才新开一条造型。不要因为本段原文用词不同就另造近义新名——已知设定里已有『黑色连帽卫衣』,本段又见黑色卫衣,照抄『黑色连帽卫衣』即可;同义换名只会把同一套衣服拆成多张图。",
31
+ " **每个 featured 实体首次出现时,先给一条 name=『常态』的基础造型**(它平时/最常见的样子)作为默认外观;之后再给特殊变化。人物=整体扮相;场景=环境外观(布景、光线、氛围);道具=物件外观。",
32
+ " 造型名=需要美术单独画一张图的外观档位(常态、婚服、西装、龙形;场景的 白天/夜晚/被毁;道具的 破损/发光)。**造型名必须用中文**:正文里的英文专名(套装/职业/形态名,如 Sean's Revenge、Flamecaster、Grave Priest、Shieldguard)一律译成中文再作造型名(肖恩的复仇套装、焰术师、墓祭司、盾卫)。",
33
+ " description=这套外观长什么样的一句话(优先用原文描写:服饰/颜色/发型/配饰,或场景布景/道具形制)。**常态 description 不能留空。绝不写心情/身体状况/胖瘦**(满脸泪痕、愤怒、虚弱濒死、受伤、昏迷、消瘦——这些不是造型;判据:换成它,美术要不要另画一张图)。",
34
+ "**lookChanges —— 造型变化(稀疏,只标变化处)**:某个实体的造型从某一场起变了,就标一条 {scene, entity, look}。scene=变化发生的场景id(scn_012);entity=canonical 名;look=从这场起穿的造型(必须是你在 looks 里注册过的档位名)。",
35
+ " · **只标造型真的改变的那一场**(换装/变身/受损/回归日常)。例:大骨头在 scn_050 变身焰术师 → {scene:scn_050, entity:大骨头, look:焰术师态};后面若换回常态,在那一场再标 {..., look:常态}。",
36
+ " · 没变化的场**不用标**——系统自动沿用上一次的造型一直到下一次变化。首次出现默认常态,也不用特意标。",
37
+ " · 你**不需要**列出每一场谁在场——谁在场系统直接从正文(对白说话人、旁白)读,你只管注册实体、归一名字、标造型变化。",
38
+ "subEvents:本段关键剧情原子,每条一句话(维护剧情理解与压缩)。",
39
+ "summary:本段一句话梗概;若本段含多集,概括为整段一句话。",
32
40
  ].join("\n");
33
41
  export function buildEpisodeAssetsUser(contextMd, bodyMd) {
34
42
  return [
@@ -40,11 +48,97 @@ export function buildEpisodeAssetsUser(contextMd, bodyMd) {
40
48
  ].join("\n");
41
49
  }
42
50
  export async function runEpisodeAssets(executor, contextMd, bodyMd, signal) {
43
- const response = await executor.generateText("ingest.episode-assets", {
51
+ const response = await executor.generateTool("ingest.episode-assets", {
44
52
  system: EPISODE_ASSETS_SYSTEM,
45
53
  user: buildEpisodeAssetsUser(contextMd, bodyMd),
54
+ tool: { name: "emit_delta", description: "返回本段的资产/造型/场景 Delta", inputSchema: SERIAL_DELTA_SCHEMA },
46
55
  ...(signal ? { signal } : {}),
47
56
  });
48
- return { markdown: response.text, delta: parseUpdateMarkdown(response.text) };
57
+ return { delta: toDelta(response.input), raw: JSON.stringify(response.input) };
58
+ }
59
+ // Schema-validated tool input → Delta. The schema guarantees shape, so this is a
60
+ // straight, defensive projection: entity `aliases` become immediate merges into
61
+ // the canonical name (so translations/past-life/alt names fold in), and look
62
+ // name+aliases become the `names[]` list (names[0]=canonical) applyDelta expects.
63
+ const KIND = new Set(["actor", "location", "prop"]);
64
+ const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
65
+ const arr = (v) => (Array.isArray(v) ? v : []);
66
+ const str = (v) => (typeof v === "string" ? v.trim() : "");
67
+ // Deterministic backstop for the one thing the model still slips on: a canonical
68
+ // name carrying an inline paren annotation — `大骨头(Big Bones / Marcus Vale)`,
69
+ // `银蕾丝(SilverLace)`. The schema asks for name/aliases split, but a few leak
70
+ // through, so we split mechanically here (100% reliable, model-independent): the
71
+ // text before the first paren is the clean name; the paren's inner content, split
72
+ // on / , 、; separators, is preserved as aliases (never discarded — an inline
73
+ // annotation is the source explicitly declaring the alias mapping). Tolerates an
74
+ // unclosed paren (`大骨(Big Bones`). A leading paren (no name before it) is left
75
+ // whole — it isn't a name annotation.
76
+ const PAREN_RE = /[((]([^))]*)[))]?/;
77
+ function splitParen(raw) {
78
+ const s = str(raw);
79
+ const m = PAREN_RE.exec(s);
80
+ if (!m)
81
+ return { name: s, aliases: [] };
82
+ const name = s.slice(0, m.index).trim();
83
+ if (!name)
84
+ return { name: s, aliases: [] };
85
+ const aliases = (m[1] ?? "").split(/[//,,、;;]/).map((x) => x.trim()).filter(Boolean);
86
+ return { name, aliases };
87
+ }
88
+ const cleanName = (raw) => splitParen(str(raw)).name;
89
+ export function toDelta(input) {
90
+ const d = emptyDelta();
91
+ if (!isObj(input))
92
+ return d;
93
+ for (const e of arr(input.newEntities)) {
94
+ if (!isObj(e))
95
+ continue;
96
+ const kind = str(e.kind);
97
+ const { name, aliases: parenAliases } = splitParen(str(e.name));
98
+ if (!KIND.has(kind) || !name)
99
+ continue;
100
+ // Every 叫法 → clean alias. A declared alias may ITSELF carry a paren
101
+ // (`旧药箱(带三角划痕)`) — split it, else the polluted form registers as an
102
+ // alias and its extra length promotes it to canonical (fuller-name rule).
103
+ const aliasNames = [...parenAliases];
104
+ for (const a of arr(e.aliases)) {
105
+ const { name: base, aliases: inner } = splitParen(str(a));
106
+ if (base)
107
+ aliasNames.push(base);
108
+ aliasNames.push(...inner);
109
+ }
110
+ const aliases = [...new Set(aliasNames.filter((a) => a && a !== name))];
111
+ d.newEntities.push({ name, kind: kind, description: str(e.description), aliases });
112
+ }
113
+ for (const m of arr(input.merges)) {
114
+ if (!isObj(m))
115
+ continue;
116
+ const from = cleanName(m.from);
117
+ const into = cleanName(m.into);
118
+ if (from && into && from !== into)
119
+ d.merges.push({ from, into });
120
+ }
121
+ for (const l of arr(input.looks)) {
122
+ if (!isObj(l))
123
+ continue;
124
+ const entity = cleanName(l.entity);
125
+ const name = cleanName(l.name);
126
+ if (!entity || !name)
127
+ continue;
128
+ const names = [name, ...arr(l.aliases).map(cleanName).filter(Boolean)];
129
+ d.looks.push({ entity, names, description: str(l.description) });
130
+ }
131
+ for (const c of arr(input.lookChanges)) {
132
+ if (!isObj(c))
133
+ continue;
134
+ const scene = str(c.scene);
135
+ const entity = cleanName(c.entity);
136
+ const look = cleanName(c.look);
137
+ if (scene && entity && look)
138
+ d.lookChanges.push({ scene, entity, look });
139
+ }
140
+ d.subEvents = arr(input.subEvents).map(str).filter(Boolean);
141
+ d.summary = str(input.summary);
142
+ return d;
49
143
  }
50
144
  //# sourceMappingURL=episode-assets.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"episode-assets.js","sourceRoot":"","sources":["../../../../src/llm/tasks/ingest/episode-assets.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,kFAAkF;AAClF,kFAAkF;AAClF,8EAA8E;AAC9E,0EAA0E;AAC1E,6EAA6E;AAE7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,iDAAiD,CAAC;AAItF,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,+EAA+E;IAC/E,4EAA4E;IAC5E,gGAAgG;IAChG,2CAA2C;IAC3C,EAAE;IACF,oEAAoE;IACpE,qGAAqG;IACrG,mFAAmF;IACnF,mEAAmE;IACnE,wGAAwG;IACxG,2DAA2D;IAC3D,mGAAmG;IACnG,yEAAyE;IACzE,8GAA8G;IAC9G,mGAAmG;IACnG,+JAA+J;IAC/J,+FAA+F;IAC/F,oGAAoG;IACpG,qFAAqF;IACrF,mHAAmH;IACnH,+DAA+D;IAC/D,kCAAkC;IAClC,6CAA6C;CAC9C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,UAAU,sBAAsB,CAAC,SAAiB,EAAE,MAAc;IACtE,OAAO;QACL,4BAA4B;QAC5B,SAAS,CAAC,IAAI,EAAE,IAAI,cAAc;QAClC,EAAE;QACF,iCAAiC;QACjC,MAAM,CAAC,IAAI,EAAE;KACd,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAyB,EAAE,SAAiB,EAAE,MAAc,EAAE,MAAoB;IACvH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,uBAAuB,EAAE;QACpE,MAAM,EAAE,qBAAqB;QAC7B,IAAI,EAAE,sBAAsB,CAAC,SAAS,EAAE,MAAM,CAAC;QAC/C,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9B,CAAC,CAAC;IACH,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,mBAAmB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;AAChF,CAAC"}
1
+ {"version":3,"file":"episode-assets.js","sourceRoot":"","sources":["../../../../src/llm/tasks/ingest/episode-assets.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,kFAAkF;AAClF,kFAAkF;AAClF,8EAA8E;AAC9E,6EAA6E;AAC7E,mFAAmF;AACnF,8EAA8E;AAC9E,2EAA2E;AAC3E,kFAAkF;AAElF,OAAO,EAAE,UAAU,EAAc,MAAM,0CAA0C,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGpD,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,+EAA+E;IAC/E,kFAAkF;IAClF,4EAA4E;IAC5E,2CAA2C;IAC3C,EAAE;IACF,4CAA4C;IAC5C,+IAA+I;IAC/I,iQAAiQ;IACjQ,0IAA0I;IAC1I,+BAA+B;IAC/B,gTAAgT;IAChT,iOAAiO;IACjO,8DAA8D;IAC9D,qSAAqS;IACrS,wMAAwM;IACxM,oMAAoM;IACpM,wGAAwG;IACxG,mLAAmL;IACnL,6GAA6G;IAC7G,kLAAkL;IAClL,oJAAoJ;IACpJ,8JAA8J;IAC9J,kIAAkI;IAClI,yDAAyD;IACzD,iEAAiE;IACjE,sCAAsC;IACtC,kCAAkC;CACnC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,UAAU,sBAAsB,CAAC,SAAiB,EAAE,MAAc;IACtE,OAAO;QACL,4BAA4B;QAC5B,SAAS,CAAC,IAAI,EAAE,IAAI,cAAc;QAClC,EAAE;QACF,iCAAiC;QACjC,MAAM,CAAC,IAAI,EAAE;KACd,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAyB,EAAE,SAAiB,EAAE,MAAc,EAAE,MAAoB;IACvH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,uBAAuB,EAAE;QACpE,MAAM,EAAE,qBAAqB;QAC7B,IAAI,EAAE,sBAAsB,CAAC,SAAS,EAAE,MAAM,CAAC;QAC/C,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,qBAAqB,EAAE,WAAW,EAAE,mBAAmB,EAAE;QAClG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9B,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AACjF,CAAC;AAED,iFAAiF;AACjF,gFAAgF;AAChF,6EAA6E;AAC7E,kFAAkF;AAClF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AACpD,MAAM,KAAK,GAAG,CAAC,CAAU,EAAgC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrH,MAAM,GAAG,GAAG,CAAC,CAAU,EAAa,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACnE,MAAM,GAAG,GAAG,CAAC,CAAU,EAAU,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAE5E,iFAAiF;AACjF,6EAA6E;AAC7E,4EAA4E;AAC5E,iFAAiF;AACjF,kFAAkF;AAClF,6EAA6E;AAC7E,iFAAiF;AACjF,+EAA+E;AAC/E,sCAAsC;AACtC,MAAM,QAAQ,GAAG,mBAAmB,CAAC;AACrC,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACxC,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACrF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC;AACD,MAAM,SAAS,GAAG,CAAC,GAAY,EAAU,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAEtE,MAAM,UAAU,OAAO,CAAC,KAAc;IACpC,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;IACvB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAAE,SAAS;QACxB,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAChE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,SAAS;QACvC,oEAAoE;QACpE,oEAAoE;QACpE,0EAA0E;QAC1E,MAAM,UAAU,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC;QACrC,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;YAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAAC,IAAI,IAAI;gBAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAC,UAAU,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QAAC,CAAC;QAC1J,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;QACxE,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAqC,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IACtH,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAAE,SAAS;QACxB,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI;YAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAAE,SAAS;QACxB,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI;YAAE,SAAS;QAC/B,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QACvE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAAE,SAAS;QACxB,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3B,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,KAAK,IAAI,MAAM,IAAI,IAAI;YAAE,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5D,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { type Delta } from "../../../domain/ingest/serial-context.js";
2
+ import type { LlmTaskExecutor } from "../../types.js";
3
+ export declare const NAME_FIX_SYSTEM: string;
4
+ export declare function buildNameFixUser(contextMd: string, names: string[]): string;
5
+ export declare function runNameFix(executor: LlmTaskExecutor, contextMd: string, names: string[], signal?: AbortSignal): Promise<{
6
+ delta: Delta;
7
+ raw: string;
8
+ }>;
9
+ export declare function nameFixToDelta(input: unknown): Delta;
@@ -0,0 +1,64 @@
1
+ // ingest.name-fix task (§ serial repair). After the serial pass, some names appear
2
+ // in the body but resolve to NO registry entity — the model missed a merge. Rather
3
+ // than mint ghost assets, we ask once: for each such name, is it another叫法 of an
4
+ // already-registered entity (→ merge), or a genuinely new entity (→ newEntity)?
5
+ // Output is a Delta with only newEntities + merges (no looks/scenes). Tool mode.
6
+ import { emptyDelta } from "../../../domain/ingest/serial-context.js";
7
+ import { NAME_FIX_SCHEMA } from "../schemas.js";
8
+ export const NAME_FIX_SYSTEM = [
9
+ "你是剧本实体归一修复器。【已知设定】是已建立的实体登记(register)。下面【待归一名字】是正文里出现、但还没能对应到 register 里任何实体的名字。",
10
+ "对**每一个**待归一名字,判断它是不是 register 里某个已登记实体的另一种叫法:",
11
+ " · **是**(字面变体如 大骨=大骨头、苏若雪=若雪;或剧情/身份能确定是同一个,如前世名/化名/全名短名)→ 放进 `merges`:{from: 这个名字, into: 已登记实体的 canonical}。",
12
+ " · **不是**(它确实是 register 里从没登记过的一个新实体)→ 放进 `newEntities`:{kind, name(纯 canonical), description(一句话身份), aliases}。",
13
+ "**不同角色绝不互相当别名**。拿不准是哪一个已有实体时,宁可当新实体登记,也不要 merge 错人。",
14
+ "地点同理:同一个地方的不同写法(带不带平台/区域前缀、『车轮旁』=『矿车车轮旁』)merge 到已有那条;确实是新地方才 newEntity。",
15
+ "只输出 merges 和 newEntities 两项,覆盖**每一个**待归一名字。",
16
+ ].join("\n");
17
+ export function buildNameFixUser(contextMd, names) {
18
+ return [
19
+ "【已知设定】(已登记的实体)",
20
+ contextMd.trim() || "(空)",
21
+ "",
22
+ "【待归一名字】(正文里出现但未对应到任何已登记实体,逐个处理)",
23
+ names.map((n) => `- ${n}`).join("\n"),
24
+ ].join("\n");
25
+ }
26
+ // Runs the fix and returns a Delta carrying only its newEntities + merges.
27
+ export async function runNameFix(executor, contextMd, names, signal) {
28
+ const response = await executor.generateTool("ingest.name-fix", {
29
+ system: NAME_FIX_SYSTEM,
30
+ user: buildNameFixUser(contextMd, names),
31
+ tool: { name: "emit_fix", description: "把待归一名字 merge 到已有或登记为新实体", inputSchema: NAME_FIX_SCHEMA },
32
+ ...(signal ? { signal } : {}),
33
+ });
34
+ return { delta: nameFixToDelta(response.input), raw: JSON.stringify(response.input) };
35
+ }
36
+ const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
37
+ const arr = (v) => (Array.isArray(v) ? v : []);
38
+ const str = (v) => (typeof v === "string" ? v.trim() : "");
39
+ const KIND = new Set(["actor", "location", "prop"]);
40
+ export function nameFixToDelta(input) {
41
+ const d = emptyDelta();
42
+ if (!isObj(input))
43
+ return d;
44
+ for (const m of arr(input.merges)) {
45
+ if (!isObj(m))
46
+ continue;
47
+ const from = str(m.from);
48
+ const into = str(m.into);
49
+ if (from && into && from !== into)
50
+ d.merges.push({ from, into });
51
+ }
52
+ for (const e of arr(input.newEntities)) {
53
+ if (!isObj(e))
54
+ continue;
55
+ const kind = str(e.kind);
56
+ const name = str(e.name);
57
+ if (!KIND.has(kind) || !name)
58
+ continue;
59
+ const aliases = [...new Set(arr(e.aliases).map(str).filter((a) => a && a !== name))];
60
+ d.newEntities.push({ name, kind: kind, description: str(e.description), aliases });
61
+ }
62
+ return d;
63
+ }
64
+ //# sourceMappingURL=name-fix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"name-fix.js","sourceRoot":"","sources":["../../../../src/llm/tasks/ingest/name-fix.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,mFAAmF;AACnF,iFAAiF;AACjF,gFAAgF;AAChF,iFAAiF;AAEjF,OAAO,EAAE,UAAU,EAAc,MAAM,0CAA0C,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,kFAAkF;IAClF,+CAA+C;IAC/C,8GAA8G;IAC9G,kHAAkH;IAClH,qDAAqD;IACrD,yEAAyE;IACzE,6CAA6C;CAC9C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,KAAe;IACjE,OAAO;QACL,gBAAgB;QAChB,SAAS,CAAC,IAAI,EAAE,IAAI,KAAK;QACzB,EAAE;QACF,iCAAiC;QACjC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;KACtC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,2EAA2E;AAC3E,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAyB,EAAE,SAAiB,EAAE,KAAe,EAAE,MAAoB;IAClH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,YAAY,CAAC,iBAAiB,EAAE;QAC9D,MAAM,EAAE,eAAe;QACvB,IAAI,EAAE,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC;QACxC,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,EAAE,yBAAyB,EAAE,WAAW,EAAE,eAAe,EAAE;QAChG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9B,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;AACxF,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,CAAU,EAAgC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrH,MAAM,GAAG,GAAG,CAAC,CAAU,EAAa,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACnE,MAAM,GAAG,GAAG,CAAC,CAAU,EAAU,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC5E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;AAEpD,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;IACvB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAAE,SAAS;QACxB,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI;YAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAAE,SAAS;QACxB,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,SAAS;QACvC,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;QACrF,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAqC,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IACtH,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -1,8 +1,9 @@
1
- import { type SerialOutput } from "../../../domain/ingest/video-serial-md.js";
1
+ import type { SerialOutput } from "../../../domain/ingest/video-serial-md.js";
2
2
  import type { TaskVideoPort, VideoFileHandle } from "../../types.js";
3
3
  export type { SerialOutput, SerialScene, SerialEntity } from "../../../domain/ingest/video-serial-md.js";
4
4
  export declare const VIDEO_SERIAL_SYSTEM: string;
5
5
  export declare function buildSerialUser(episodeNo: number, contextText: string): string;
6
+ export declare function toSerialOutput(input: unknown): SerialOutput;
6
7
  export declare function runVideoSerial(port: TaskVideoPort, file: VideoFileHandle, episodeNo: number, contextText: string, fps: number, signal?: AbortSignal): Promise<{
7
8
  md: string;
8
9
  output: SerialOutput;