narraeon 0.7.6 → 0.7.9
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.
- package/dist/node/runtime/authoring/AuthoringRequestSnapshot.js +14 -1
- package/dist/node/runtime/history/HistoryRendering.js +25 -6
- package/dist/node/runtime/history/HistoryTools.js +31 -0
- package/dist/node/runtime/play/FileNativeContinuityCorrection.js +12 -4
- package/dist/node/runtime/play/PlayCallChain.js +10 -21
- package/dist/node/runtime/play/PlayDocumentTools.js +72 -43
- package/dist/node/runtime/prompt/FileNativePromptCompiler.js +35 -19
- package/dist/node/runtime/prompt/FileNativeToolRegistry.js +15 -12
- package/dist/node/runtime/prompt/WorldMaterialCoverage.js +0 -67
- package/dist/node/runtime/setting/SettingAuthoringTransaction.js +326 -62
- package/dist/node/runtime/setting/SettingImprovementSession.js +40 -3
- package/dist/node/runtime/world/FileNativeWorldStore.js +13 -3
- package/dist/node/runtime/world/WorldDocumentMaintenance.js +9 -2
- package/dist/node/runtime/world/WorldDocumentStore.js +441 -389
- package/dist/node/runtime/world/WorldLedgerAuthority.js +18 -2
- package/dist/node/runtime/world/WorldStateRevision.js +6 -3
- package/dist/node/runtime/world-revision/FileNativeWorldRevisionStore.js +61 -17
- package/dist/node/runtime/world-revision/LegacyWorldRevisionEpochUpgrade.js +46 -0
- package/dist/node/runtime/world-revision/WorldRevisionAuthoringTransaction.js +83 -30
- package/dist/node/runtime/world-revision/WorldRevisionSession.js +64 -4
- package/dist/node/runtime/world-revision/WorldRevisionWorkspace.js +32 -11
- package/dist/node/shared/default-setting-improvement-prompt.js +23 -8
- package/dist/node/shared/ordered-author-prompts.js +9 -7
- package/dist/node/shared/ordered-play-prompts.js +2 -2
- package/dist/web/assets/index-B2kbaOGe.js +1408 -0
- package/dist/web/assets/{index-BjxBYYQi.css → index-DH2BVsYd.css} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-Cj2JYCia.js +0 -1408
|
@@ -128,15 +128,13 @@ function createToolDefinitions(locale) {
|
|
|
128
128
|
},
|
|
129
129
|
}, ["yaml"]);
|
|
130
130
|
const markdownLocator = object({ markdown: { type: "array", items: { type: "string" }, minItems: 1 } }, ["markdown"]);
|
|
131
|
+
// add_section takes [] to add a new top-level section at the end of the body.
|
|
132
|
+
const markdownParentLocator = object({ markdown: { type: "array", items: { type: "string" } } }, ["markdown"]);
|
|
131
133
|
const definitions = {
|
|
132
134
|
...resolutionDefinitions(locale),
|
|
133
135
|
state_list: {
|
|
134
136
|
description: descriptions.state_list,
|
|
135
|
-
inputSchema: object({
|
|
136
|
-
parent: string,
|
|
137
|
-
cursor: { type: ["string", "null"] },
|
|
138
|
-
limit: { type: "integer", minimum: 1, maximum: 100 },
|
|
139
|
-
}, ["parent"]),
|
|
137
|
+
inputSchema: object({ parent: string }, ["parent"]),
|
|
140
138
|
},
|
|
141
139
|
history_list: {
|
|
142
140
|
description: descriptions.history_list,
|
|
@@ -209,10 +207,15 @@ function createToolDefinitions(locale) {
|
|
|
209
207
|
"locator",
|
|
210
208
|
]),
|
|
211
209
|
object({
|
|
212
|
-
op: {
|
|
210
|
+
op: { const: "replace_section" },
|
|
213
211
|
locator: markdownLocator,
|
|
214
212
|
markdown: { type: "string" },
|
|
215
213
|
}, ["op", "locator", "markdown"]),
|
|
214
|
+
object({
|
|
215
|
+
op: { const: "add_section" },
|
|
216
|
+
locator: markdownParentLocator,
|
|
217
|
+
markdown: { type: "string" },
|
|
218
|
+
}, ["op", "locator", "markdown"]),
|
|
216
219
|
object({
|
|
217
220
|
op: { const: "rename_section" },
|
|
218
221
|
locator: markdownLocator,
|
|
@@ -287,13 +290,13 @@ function resolutionDefinitions(locale) {
|
|
|
287
290
|
const toolDescriptions = {
|
|
288
291
|
en: {
|
|
289
292
|
world_checkpoint: "Register a gap between events and suggest that the player start a fresh context here. Arguments must be an empty object. The effect and replay scope are defined by the tools-and-settlement rules; when to register is defined by the checkpoint policy. Consolidation and maintenance do not require this tool; do not advance the story to register a checkpoint.",
|
|
290
|
-
state_list: "List document and state directory handles known to Runtime. parent must be @dir-/ for the state root or an @dir-* handle from the initial directory index or an earlier state_list result; no preliminary listing is needed for an already supplied handle. Catalog directories declared by the frozen world frame remain listed and usable when empty.
|
|
291
|
-
history_list: "Browse committed history on the current timeline. Omit anchors for the latest page; use only before or after with a Runtime ref (including refs in injected history) for the immediately adjacent page, excluding the anchor. Every page is oldest to newest. limit defaults to 20 (1–100 messages). Previews are only the first 120 Unicode code points. Use independent earlierCursor/laterCursor with {cursor} alone; no first-query parameters on continuation. Cursors bind world, tool, query and immutable ordered history. After history_changed rerun the query. Opening messages are queryable. Read full originals with history_read; positions are snapshot locations, not identities or turns.",
|
|
293
|
+
state_list: "List document and state directory handles known to Runtime. parent must be @dir-/ for the state root or an @dir-* handle from the initial directory index or an earlier state_list result; no preliminary listing is needed for an already supplied handle. Catalog directories declared by the frozen world frame remain listed and usable when empty. Each call returns the whole directory with Complete: yes. Pass returned document handles to context_read. This tool never lists committed history.",
|
|
294
|
+
history_list: "Browse committed history on the current timeline. Omit anchors for the latest page; use only before or after with a Runtime ref (including refs in injected history) for the immediately adjacent page, excluding the anchor. Every page is oldest to newest in Authority acceptance order, not story dates. limit defaults to 20 (1–100 messages). Previews are only the first 120 Unicode code points. Historical background describes the captured state, not current world state; interpret memories, dreams and local times with the original text, and it does not certify facts or grant character knowledge. Use independent earlierCursor/laterCursor with {cursor} alone; no first-query parameters on continuation. Cursors bind world, tool, query and immutable ordered history. After history_changed rerun the query. Opening messages are queryable. Read full originals with history_read; positions are snapshot locations, not identities or turns.",
|
|
292
295
|
history_search: "Search committed originals on the current timeline with queries: 1–5 nonempty literal strings (max 256 code points each); no query alias or semantic filters. match defaults to any, or all within one message. NFKC normalization always applies; caseSensitive defaults to false (locale-und case folding), normalized duplicate queries collapse. order defaults to newest_first, or oldest_first. limit defaults to 10 (1–50 matching messages). Optional after/before refs exclude timeline boundaries independently of order; after must precede before. Each result has at most 3 partial original fragments, query occurrence counts and complete-original length. Read a hit and nearby context with history_read. Continue with {cursor} alone; history_changed requires a new query.",
|
|
293
296
|
history_read: "Read complete committed originals on the current timeline, never summarized, truncated or body-paginated. Use {latest:N} alone (1–21 messages), or {ref,before,after} with defaults before=after=0 and sum at most 20; do not mix modes. Ref may come directly from Runtime prompt injections or tools without listing first. Windows are always oldest to newest, including the anchor. earlier/later are immediately outside this window and can be the next ref with before/after to avoid rereading. Boundaries and empty history are normal. Counts are messages, not turns; 21 long messages can produce large output.",
|
|
294
297
|
context_search: "Search literal source text in state documents. Use source=state; committed history uses history_search. Zero matches means only that the supplied text had no literal match; it does not prove that a world fact does not exist. Player-visible narrative must not recount the search process. within accepts only an @document or @dir-* handle returned by Runtime.",
|
|
295
298
|
context_read: "Read the complete content of an @document or @node handle previously returned by Runtime. The read heading, metadata boundaries, body boundaries, scope, and completion marker in the result are not source text. set_metadata may include only the fields that must change; Runtime preserves omitted metadata fields. Update the writable body between the boundaries with locators. YAML bodies omit the $document technical header; Markdown bodies begin at the document's level-one heading. Results are never truncated or paginated. Never pass file paths, natural-language names, or an invented world/... value.",
|
|
296
|
-
world_patch: 'Update a document that has been read precisely or whose complete body was injected with write authorization. target must be an @short-ref. When title, summary, or aliases are stale, use set_metadata and include only the title, summary, or aliases that must change. At least one is required; Runtime preserves omitted fields from the current candidate document. A YAML edit uses locator:{yaml:["field","child"]}, for example {op:"replace",locator:{yaml:["status"]},value:"new value"}. Locator segments address map keys or a zero-based array index
|
|
299
|
+
world_patch: 'Update a document that has been read precisely or whose complete body was injected with write authorization. target must be an @short-ref. When title, summary, or aliases are stale, use set_metadata and include only the title, summary, or aliases that must change. At least one is required; Runtime preserves omitted fields from the current candidate document. A YAML edit uses locator:{yaml:["field","child"]}, for example {op:"replace",locator:{yaml:["status"]},value:"new value"}. Locator segments address map keys or a zero-based array index. add and replace are upserts: each writes its value whether or not the target exists, creating missing parent maps, and an array index at or past the end appends. remove deletes the existing key or array item at its locator; a missing target is a no-op that the receipt reports. A YAML value may reference a whole document only as {$ref:"@short-ref"}; the short reference must come from a Runtime list, read, or create result. Never invent a document id. If no handle is available, use ordinary text when semantically correct or call world_create first and use its returned @short-ref. To add an item to the end of an existing sequence, use append with the locator pointing to that sequence. A Markdown locator excludes the document level-one heading: {markdown:["Responsibilities"]} points exactly to ## Responsibilities, and replace_section.markdown must begin with the same heading at the same level; when that heading does not exist yet, replace_section adds it under its parent. add_section adds a child under the locator heading, and locator [] with a level-two markdown heading adds a new top-level section at the end of the body. Use replace_preamble for text after the level-one heading and before the first level-two heading; send only that text. Use replace_body to replace the whole Markdown body and retain the original level-one heading. Each edit settles on its own: a failed edit is skipped and the others still apply. Success reports whether the document changed; when the receipt lists failed edits, the applied ones are already written, so send again only the listed edits. It does not echo the body. Call context_read again only when a later decision depends on Runtime\'s exact serialized body or current metadata. Do not use path, JSON Pointer, set, or a file name.',
|
|
297
300
|
world_create: 'Create a document inside a Runtime-known state directory. parent must be an @dir-* handle supplied by the initial directory index or state_list, such as @dir-/characters; catalog directories declared by the frozen world frame remain available when empty, and @dir-/ is the root. A syntactically valid but unknown directory is rejected. refHint is a lowercase ASCII short-reference hint, not a world/ path. A YAML body may reference a whole document only as {$ref:"@short-ref"}, and the short reference must come from a Runtime list, read, or create result. Never invent a document id.',
|
|
298
301
|
world_retire: "Retire or restore an exact state document without deleting its narrative record. target must be an @short-ref that was read precisely or injected completely. retired:true removes the document from future frame catalog injection but keeps it listed, searchable, readable, referenceable, and restorable; retired:false restores catalog participation. This changes catalog participation, not explicit full-document injection or character activity; use world_patch for ordinary location or field changes.",
|
|
299
302
|
artifact_emit: "Submit an artifact declared in advance for this follow-up request. Supply only the output name and payload; Runtime fixes the channel, key, content type, renderer, retention policy, and authority meaning in the contract.",
|
|
@@ -301,13 +304,13 @@ const toolDescriptions = {
|
|
|
301
304
|
},
|
|
302
305
|
"zh-CN": {
|
|
303
306
|
world_checkpoint: "登记事件间隙,向玩家建议从这里开始全新上下文。参数为空对象。生效条件与补入范围见“工具与响应结算”;何时登记见检查点政策。整理与归并不需要调用本工具;不要为了登记而推进剧情。",
|
|
304
|
-
state_list: "列出 Runtime 已知的文档与状态目录句柄。状态根目录的 parent 使用 @dir-/;继续下级时使用初始目录索引或 state_list 返回的 @dir-*;已有句柄无需再次列目录确认。冻结世界 frame 声明的 catalog
|
|
305
|
-
history_list: "浏览当前时间线已提交历史。无锚点时取最新一页;before 或 after 只能选一个,取锚点紧邻前/后的一页且不含锚点。页内始终由旧到新。limit 默认20,整数1–100
|
|
307
|
+
state_list: "列出 Runtime 已知的文档与状态目录句柄。状态根目录的 parent 使用 @dir-/;继续下级时使用初始目录索引或 state_list 返回的 @dir-*;已有句柄无需再次列目录确认。冻结世界 frame 声明的 catalog 目录即使为空,也会继续列出并可用。每次调用整份返回该目录,末尾 Complete: yes。返回的文档句柄交给 context_read;本工具不列出已提交历史。",
|
|
308
|
+
history_list: "浏览当前时间线已提交历史。无锚点时取最新一页;before 或 after 只能选一个,取锚点紧邻前/后的一页且不含锚点。页内始终由旧到新。limit 默认20,整数1–100。排序依据是 Authority 接受顺序,不代表故事内日期。历史背景仅说明采集位置的状态,不是当前世界状态;回忆、梦境或段内局部时间结合原文解释,不认证事实或授予角色知识。预览仅含前120个Unicode码点;完整原文用history_read。earlierCursor/laterCursor独立翻页,续页只传{cursor},不可混用首次参数。游标绑定世界、工具、查询和有序历史快照;history_changed须重新查询。开场白可查询。提示词注入中的ref可直接使用,无需再次列举;位置不是身份或回合数。",
|
|
306
309
|
history_search: "搜索当前时间线已提交原文。queries必填:1–5个非空字面词,每词最多256个Unicode码点,不接受query别名或语义筛选。match默认any,all限于同一消息。始终NFKC规范化,caseSensitive默认false(locale-und大小写折叠),规范化重复词合并。order默认newest_first,可选oldest_first;limit默认10,整数1–50条命中消息。after/before始终按时间线先后排除边界,after必须早于before,与结果排序无关。每项最多3个部分原文片段、逐词命中次数及完整原文长度;可用history_read读取前后文。续页只传{cursor};history_changed须重新查询。",
|
|
307
310
|
history_read: "完整读取当前时间线已提交原文,无摘要、无截断、无正文分页。{latest:N}单独读取最近1–21条;或{ref,before,after},before/after默认0且合计最多20;两模式互斥。ref可直接使用Runtime提示词注入或工具结果的历史句柄,不必先列举。窗口始终由旧到新且包含锚点。earlier/later是窗口外紧邻句柄,可作为下一次ref并配before/after避免重复读取;边界与空历史正常。数量单位是消息而非回合;21条长消息仍可能产生大量输出。",
|
|
308
311
|
context_search: "在状态文档原文字面中搜索,source只能为state;已提交历史使用history_search。0 命中只表示给定文本没有字面命中,不证明世界事实不存在;玩家可见叙事不得复述搜索过程。within 只能使用 Runtime 已返回的 @文档或 @dir-* 句柄。",
|
|
309
312
|
context_read: "完整读取 Runtime 先前返回的 @文档或@节点句柄。结果中的读取标题、元信息边界、正文边界、范围和完整标记不属于源文;set_metadata 可以只提交需要改变的字段,Runtime 会保留未提供的元数据字段。中间的可写正文用 locator 更新。YAML 正文不含 $document 技术头,Markdown 正文从文档 # 一级标题开始。结果不会截断或分页。不要传文件路径、自然语言名称或自行拼造的 world/...。",
|
|
310
|
-
world_patch: '更新已精确读取,或已随写入资格注入完整正文的文档。target 必须使用 @短引用;文档 title、summary 或 aliases 过时时使用 set_metadata,只提供需要改变的 title、summary 或 aliases。至少提供一项;未提供的字段由 Runtime 从当前候选文档保留。YAML edit 使用 locator:{yaml:["字段","子字段"]},例如 {op:"replace",locator:{yaml:["情况"]},value:"新值"}。locator 的每一段可以定位 map key 或从 0
|
|
313
|
+
world_patch: '更新已精确读取,或已随写入资格注入完整正文的文档。target 必须使用 @短引用;文档 title、summary 或 aliases 过时时使用 set_metadata,只提供需要改变的 title、summary 或 aliases。至少提供一项;未提供的字段由 Runtime 从当前候选文档保留。YAML edit 使用 locator:{yaml:["字段","子字段"]},例如 {op:"replace",locator:{yaml:["情况"]},value:"新值"}。locator 的每一段可以定位 map key 或从 0 开始的数组下标。add 与 replace 都是 upsert:无论目标是否已存在都写入,缺失的父级 map 会被创建,数组下标达到或超过长度时追加到末尾。remove 只删除 locator 精确指向的已有键或数组项;目标不存在时视为无操作,回执会注明。YAML value 需要引用整份文档时只能写 {$ref:"@短引用"},短引用必须来自 Runtime 的 list、read 或 create 结果;不得自行编造文档 id。没有可用句柄时,根据语义使用普通文本,或先 world_create 后使用其返回的 @短引用。向已存在的 sequence 末尾加一项必须使用 append 并把 locator 指向该 sequence。Markdown locator 不包含文档 # 一级标题:{markdown:["职责"]} 精确指向 ## 职责,replace_section.markdown 必须从同级同名标题开始;该标题尚不存在时,replace_section 会把它新增到父级之下。add_section 在 locator 标题之下新增子小节;locator 为 [] 且 markdown 以二级标题开始时,则在正文末尾新增顶层小节。修改 # 标题下、第一个 ## 前的文字用 replace_preamble(只传该段文字);替换整个 Markdown 正文用 replace_body,且 markdown 必须保留原 # 一级标题。每条 edit 独立结算:失败的 edit 被跳过,其余照常生效。成功结果只报告文档是否发生变化;回执列出失败的 edit 时,已生效的 edit 不要重发,只补上列出的 edit。不回显正文;只有后续决策依赖 Runtime 序列化后的精确正文或当前元数据时才重新 context_read。不要使用 path、JSON Pointer、set 或文件名。',
|
|
311
314
|
world_create: '在 Runtime 已知的状态目录中创建文档。parent 必须是初始目录索引或 state_list 列出的 @dir-*,例如 @dir-/characters;冻结世界 frame 声明的 catalog 目录为空时仍然可用,根目录使用 @dir-/。只有句柄形式正确但 Runtime 并不知道的目录会被拒绝。refHint 是小写 ASCII 短引用,不要传 world/ 路径。YAML body 需要引用整份文档时只能写 {$ref:"@短引用"},且短引用必须来自 Runtime 的 list、read 或 create 结果;不得自行编造文档 id。',
|
|
312
315
|
world_retire: "让一份精确状态文档退役或恢复,而不销毁叙事记录。target 必须是已精确读取或已完整注入的 @短引用。retired:true 会让文档不再进入后续 frame catalog 注入,但仍可列出、搜索、读取、引用和恢复;retired:false 恢复 catalog 参与。它只改变 catalog 参与,不取消显式全文注入、不冻结人物活动;普通位置或字段变化仍用 world_patch。",
|
|
313
316
|
artifact_emit: "提交本次后置请求预先声明的产物。只能传 output name 与 payload;频道、key、内容类型、renderer、保存策略和权威含义由 Runtime contract 固定。",
|
|
@@ -14,70 +14,3 @@ export function worldMaterialCoverage(coverage) {
|
|
|
14
14
|
});
|
|
15
15
|
return { fullInjected, nodeInjected, catalogSummary, injectedSelections };
|
|
16
16
|
}
|
|
17
|
-
export function renderFreshContextCoverage(snapshot, coverage, shortRef, locale = "en") {
|
|
18
|
-
const exposure = worldMaterialCoverage(coverage);
|
|
19
|
-
const full = exposure.fullInjected.has(shortRef);
|
|
20
|
-
const nodes = exposure.nodeInjected.has(shortRef);
|
|
21
|
-
const summary = exposure.catalogSummary.has(shortRef);
|
|
22
|
-
const zh = locale === "zh-CN";
|
|
23
|
-
const scope = full
|
|
24
|
-
? zh
|
|
25
|
-
? "完整正文"
|
|
26
|
-
: "full body"
|
|
27
|
-
: nodes
|
|
28
|
-
? zh
|
|
29
|
-
? "指定节点"
|
|
30
|
-
: "selected nodes"
|
|
31
|
-
: summary
|
|
32
|
-
? zh
|
|
33
|
-
? "仅目录摘要"
|
|
34
|
-
: "catalog summary only"
|
|
35
|
-
: zh
|
|
36
|
-
? "不直接注入,需要按需读取"
|
|
37
|
-
: "not directly injected; read on demand";
|
|
38
|
-
const lines = [
|
|
39
|
-
`${zh ? "如果现在新开上下文" : "If a fresh context started now"}: ${scope}${nodes && !full && summary ? (zh ? ",以及目录摘要" : " and catalog summary") : ""}`,
|
|
40
|
-
];
|
|
41
|
-
if (!full && nodes) {
|
|
42
|
-
const scopes = exposure.injectedSelections.filter((entry) => entry.shortRef === shortRef && entry.locator !== null);
|
|
43
|
-
lines.push(`${zh ? "节点范围" : "Node scopes"}: ${scopes.map(({ locator }) => JSON.stringify(locator)).join(", ")}`);
|
|
44
|
-
}
|
|
45
|
-
if (!full && summary) {
|
|
46
|
-
const read = snapshot.query({
|
|
47
|
-
kind: "read_document",
|
|
48
|
-
document: { shortRef },
|
|
49
|
-
});
|
|
50
|
-
if (read.kind === "read_document")
|
|
51
|
-
lines.push(`${zh ? "摘要" : "Summary"}: ${read.document.summary}`);
|
|
52
|
-
}
|
|
53
|
-
if (!full && !nodes && !summary) {
|
|
54
|
-
const references = exposure.injectedSelections.flatMap((selection) => {
|
|
55
|
-
const read = snapshot.query({
|
|
56
|
-
kind: "read_document",
|
|
57
|
-
document: { shortRef: selection.shortRef },
|
|
58
|
-
});
|
|
59
|
-
const locator = selection.locator ??
|
|
60
|
-
(read.kind === "read_document" && read.codec === "yaml"
|
|
61
|
-
? { yaml: [] }
|
|
62
|
-
: null);
|
|
63
|
-
if (locator === null)
|
|
64
|
-
return [];
|
|
65
|
-
const node = snapshot.query({
|
|
66
|
-
kind: "select_node",
|
|
67
|
-
document: { shortRef: selection.shortRef },
|
|
68
|
-
locator,
|
|
69
|
-
});
|
|
70
|
-
return node.kind === "select_node" &&
|
|
71
|
-
node.references.some(({ target }) => target.shortRef === shortRef)
|
|
72
|
-
? [`@${selection.shortRef}`]
|
|
73
|
-
: [];
|
|
74
|
-
});
|
|
75
|
-
if (references.length > 0)
|
|
76
|
-
lines.push(`${zh ? "已注入材料中的直接引用来自" : "Direct reference in injected material"}: ${[...new Set(references)].join(", ")}`);
|
|
77
|
-
else if (coverage.some(({ status }) => status === "paged_catalog"))
|
|
78
|
-
lines.push(zh
|
|
79
|
-
? "目录仍有后续页,可使用 state_list 继续查找。"
|
|
80
|
-
: "Catalogs have further pages; use state_list to continue discovery.");
|
|
81
|
-
}
|
|
82
|
-
return lines.join("\n");
|
|
83
|
-
}
|