narraeon 0.4.0 → 0.5.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.
- package/dist/node/protocol/appPreferences.js +25 -0
- package/dist/node/protocol/conversationObservation.js +67 -0
- package/dist/node/protocol/v1.js +186 -34
- package/dist/node/protocol/worldExtensions.js +16 -0
- package/dist/node/protocol/worldMaintenance.js +77 -0
- package/dist/node/protocol/worldPromptDiagnostics.js +1 -0
- package/dist/node/runtime/ConversationChanges.js +24 -0
- package/dist/node/runtime/V1Runtime.js +445 -121
- package/dist/node/runtime/artifact/FileNativeArtifactStore.js +326 -12
- package/dist/node/runtime/authoring/AuthoringRequestSnapshot.js +63 -0
- package/dist/node/runtime/authoring/ModelToolConversation.js +218 -0
- package/dist/node/runtime/config/AppPreferencesStore.js +46 -17
- package/dist/node/runtime/content/ContentTreeFingerprint.js +13 -0
- package/dist/node/runtime/content/ContentWorkspace.js +43 -13
- package/dist/node/runtime/content/CurrentTreeContentLibrary.js +128 -46
- package/dist/node/runtime/content/FileNativeContentTree.js +28 -10
- package/dist/node/runtime/content/PackageFollowups.js +80 -0
- package/dist/node/runtime/extension/FrontendExtensionBundle.js +19 -14
- package/dist/node/runtime/extension/PackageScriptPermissions.js +70 -0
- package/dist/node/runtime/extension/WorldExtensionControls.js +205 -0
- package/dist/node/runtime/extension/WorldExtensionRequests.js +64 -0
- package/dist/node/runtime/model/FileNativeModelAdapters.js +21 -466
- package/dist/node/runtime/model/ModelConnectionStore.js +13 -0
- package/dist/node/runtime/model/ModelHost.js +31 -1
- package/dist/node/runtime/model/ModelHostStream.js +51 -5
- package/dist/node/runtime/play/FileNativeContinuityCorrection.js +55 -45
- package/dist/node/runtime/play/FileNativePlayPresetStore.js +256 -238
- package/dist/node/runtime/play/FileNativePlayTimelineStore.js +118 -9
- package/dist/node/runtime/play/OrderedFollowups.js +71 -0
- package/dist/node/runtime/play/OrderedPlayPrompts.js +180 -0
- package/dist/node/runtime/play/PlayCallChain.js +814 -61
- package/dist/node/runtime/play/PlayContinuity.js +88 -0
- package/dist/node/runtime/play/PlayDocumentTools.js +205 -287
- package/dist/node/runtime/play/PlayFollowupRequests.js +34 -3
- package/dist/node/runtime/play/PlayPresetWorkbench.js +45 -54
- package/dist/node/runtime/play/PlayPromptRun.js +86 -0
- package/dist/node/runtime/prompt/FileNativePromptCompiler.js +670 -93
- package/dist/node/runtime/prompt/FileNativeToolRegistry.js +37 -21
- package/dist/node/runtime/prompt/PromptCompilationCodec.js +322 -0
- package/dist/node/runtime/prompt/WorldMaintenanceReport.js +251 -0
- package/dist/node/runtime/prompt/WorldMaterialCoverage.js +83 -0
- package/dist/node/runtime/prompt/WorldPromptDiagnostics.js +185 -0
- package/dist/node/runtime/setting/FileNativeSettingImprovementStore.js +1027 -0
- package/dist/node/runtime/setting/SettingAuthoringTransaction.js +1339 -0
- package/dist/node/runtime/setting/SettingImprovementSession.js +714 -0
- package/dist/node/runtime/world/FileNativeAuthorityV3.js +88 -1
- package/dist/node/runtime/world/FileNativeWorldStore.js +292 -27
- package/dist/node/runtime/world/PlayerViewBindings.js +30 -0
- package/dist/node/runtime/world/PlayerViewRenderer.js +27 -34
- package/dist/node/runtime/world/WorldDocumentMaintenance.js +174 -0
- package/dist/node/runtime/world/WorldDocumentStore.js +166 -96
- package/dist/node/runtime/world/WorldOperationCoordinator.js +103 -2
- package/dist/node/runtime/world-revision/FileNativeWorldRevisionStore.js +696 -0
- package/dist/node/runtime/world-revision/WorldRevisionAuthoringTransaction.js +380 -0
- package/dist/node/runtime/world-revision/WorldRevisionSession.js +709 -0
- package/dist/node/runtime/world-revision/WorldRevisionWorkspace.js +494 -0
- package/dist/node/server/ConversationStream.js +109 -0
- package/dist/node/server/createServer.js +5 -1
- package/dist/node/shared/artifact-payload-contract.js +123 -0
- package/dist/node/shared/default-play-prompts.js +25 -45
- package/dist/node/shared/default-preset-host.js +114 -138
- package/dist/node/shared/default-setting-improvement-prompt.js +52 -38
- package/dist/node/shared/display-regex.js +114 -0
- package/dist/node/shared/first-party-action-choices.js +1 -6
- package/dist/node/shared/first-party-player-view.js +1 -6
- package/dist/node/shared/ordered-author-prompts.js +64 -0
- package/dist/node/shared/ordered-followups.js +42 -0
- package/dist/node/shared/ordered-play-prompts.js +73 -0
- package/dist/web/assets/index-BXfelCi9.js +1207 -0
- package/dist/web/assets/index-BYnhUxlk.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/node/runtime/model/SettingAuthorStream.js +0 -21
- package/dist/node/runtime/setting/DocumentCandidateSettingImprovement.js +0 -1731
- package/dist/web/assets/index-D8YKfmNG.js +0 -1192
- package/dist/web/assets/index-Xa0s35CJ.css +0 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
export function validatePlayPresetArtifactPayload(contract, value) {
|
|
2
|
+
if (contract === undefined)
|
|
3
|
+
return { ok: true };
|
|
4
|
+
if (!isJsonValueValue(value))
|
|
5
|
+
return {
|
|
6
|
+
ok: false,
|
|
7
|
+
message: "JSON artifact payload must be a valid JSON value",
|
|
8
|
+
};
|
|
9
|
+
return validatePayloadNode(contract, value, "$", 0);
|
|
10
|
+
}
|
|
11
|
+
function validatePayloadNode(contract, value, path, depth) {
|
|
12
|
+
if (depth > 32)
|
|
13
|
+
return { ok: false, message: `${path} payload nesting exceeds 32 levels` };
|
|
14
|
+
const actual = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
15
|
+
const typeMatches = contract.type === actual ||
|
|
16
|
+
(contract.type === "number" && actual === "number") ||
|
|
17
|
+
(contract.type === "integer" &&
|
|
18
|
+
actual === "number" &&
|
|
19
|
+
Number.isInteger(value));
|
|
20
|
+
if (!typeMatches)
|
|
21
|
+
return {
|
|
22
|
+
ok: false,
|
|
23
|
+
message: `${path} payload type must be ${contract.type}; received ${actual}`,
|
|
24
|
+
};
|
|
25
|
+
if (contract.maxBytes !== undefined) {
|
|
26
|
+
const encoded = JSON.stringify(value);
|
|
27
|
+
if (encoded === undefined ||
|
|
28
|
+
new TextEncoder().encode(encoded).byteLength > contract.maxBytes)
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
message: `${path} payload exceeds its declared ${contract.maxBytes}-byte limit`,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (contract.type === "string") {
|
|
35
|
+
const text = value;
|
|
36
|
+
if (contract.minLength !== undefined &&
|
|
37
|
+
[...text].length < contract.minLength)
|
|
38
|
+
return {
|
|
39
|
+
ok: false,
|
|
40
|
+
message: `${path} text length is less than ${contract.minLength}`,
|
|
41
|
+
};
|
|
42
|
+
if (contract.maxLength !== undefined &&
|
|
43
|
+
[...text].length > contract.maxLength)
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
message: `${path} text length exceeds ${contract.maxLength}`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (contract.type === "array") {
|
|
50
|
+
const entries = value;
|
|
51
|
+
if (contract.minItems !== undefined && entries.length < contract.minItems)
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
message: `${path} has fewer than ${contract.minItems} items`,
|
|
55
|
+
};
|
|
56
|
+
if (contract.maxItems !== undefined && entries.length > contract.maxItems)
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
message: `${path} has more than ${contract.maxItems} items`,
|
|
60
|
+
};
|
|
61
|
+
const seen = new Set();
|
|
62
|
+
for (const [index, entry] of entries.entries()) {
|
|
63
|
+
if (contract.items !== undefined) {
|
|
64
|
+
const result = validatePayloadNode(contract.items, entry, `${path}[${index}]`, depth + 1);
|
|
65
|
+
if (!result.ok)
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
if (contract.uniqueBy !== undefined && isRecordValue(entry)) {
|
|
69
|
+
const unique = entry[contract.uniqueBy];
|
|
70
|
+
if (typeof unique !== "string" &&
|
|
71
|
+
typeof unique !== "number" &&
|
|
72
|
+
typeof unique !== "boolean")
|
|
73
|
+
return {
|
|
74
|
+
ok: false,
|
|
75
|
+
message: `${path}[${index}].${contract.uniqueBy} must be a uniquely comparable scalar`,
|
|
76
|
+
};
|
|
77
|
+
const key = JSON.stringify(unique);
|
|
78
|
+
if (seen.has(key))
|
|
79
|
+
return {
|
|
80
|
+
ok: false,
|
|
81
|
+
message: `${path} ${contract.uniqueBy} values cannot be duplicated`,
|
|
82
|
+
};
|
|
83
|
+
seen.add(key);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (contract.type === "object") {
|
|
88
|
+
const object = value;
|
|
89
|
+
const properties = contract.properties ?? {};
|
|
90
|
+
for (const required of contract.required ?? [])
|
|
91
|
+
if (!(required in object))
|
|
92
|
+
return { ok: false, message: `${path}.${required} is required` };
|
|
93
|
+
if (contract.additionalProperties === false)
|
|
94
|
+
for (const key of Object.keys(object))
|
|
95
|
+
if (!(key in properties))
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
message: `${path}.${key} is not a declared field`,
|
|
99
|
+
};
|
|
100
|
+
for (const [key, child] of Object.entries(properties)) {
|
|
101
|
+
if (!(key in object))
|
|
102
|
+
continue;
|
|
103
|
+
const result = validatePayloadNode(child, object[key], `${path}.${key}`, depth + 1);
|
|
104
|
+
if (!result.ok)
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return { ok: true };
|
|
109
|
+
}
|
|
110
|
+
function isJsonValueValue(value) {
|
|
111
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
112
|
+
return true;
|
|
113
|
+
if (typeof value === "number")
|
|
114
|
+
return Number.isFinite(value);
|
|
115
|
+
if (Array.isArray(value))
|
|
116
|
+
return value.every(isJsonValueValue);
|
|
117
|
+
if (!isRecordValue(value))
|
|
118
|
+
return false;
|
|
119
|
+
return Object.values(value).every(isJsonValueValue);
|
|
120
|
+
}
|
|
121
|
+
function isRecordValue(value) {
|
|
122
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
123
|
+
}
|
|
@@ -3,79 +3,59 @@
|
|
|
3
3
|
* first-party presets. Portable presets still receive ordinary editable file
|
|
4
4
|
* contents; this module only prevents the shipped starting points from
|
|
5
5
|
* drifting apart. The general adjudication and state-maintenance criteria live
|
|
6
|
-
* in
|
|
6
|
+
* in independently editable host recommendation blocks.
|
|
7
7
|
*/
|
|
8
8
|
export const defaultNarrationPromptZhCN = `# 玩家可见叙事规则
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
世界内游玩输出互动式小说正文,让玩家读到这次经历。以已加载材料、已经裁决的结果和成功提交的变化为依据;表达方式可以丰富,不能改变谁在哪、拿着什么、是否受伤或承诺是否成立。尝试不自动成为成功,角色声称不自动成为事实。
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## 承接与表现
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
有新玩家输入时,把其中明确行动或台词自然接入场景,补足不改变选择的表达细节,再写相应反应。已经演过的部分不用重述,不以“你说要……”机械复读。原生对话末尾已有主持正文、其后没有新玩家输入时,本次是空输入续写:从那段正文的最后局面继续,只推进既有授权动作、NPC 和环境。不重新回答已经回应的问题,不复位已完成的递接或走动,不把旧玩家输入再演一次,也不替玩家增加决定。
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
本轮新发生且玩家能感知的结果,要成为具体可读的事:物品怎样递接、人物如何离开、态度变化怎样在话语或行动中显露。文档中补录旧结果、去重和整理不要求再次演出。界面数值不能代替事件表现,叙事也不能与当前值冲突。未向玩家表露的判断和场外事实无需用旁白揭露。
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
具体表演细节随最终叙事保存,可按需追溯;不要假定每次请求自动带着全部旧段落。必须持续保存的结果按状态维护政策处理,不能只留在检查点收尾原文中。
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
## 停在哪里
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
在当前行动与反应形成有内容的局面、或下一次关键选择需要玩家时停笔。具体人物动作、原话或环境变化都可以承接下一段;有意义的沉默、独处、休息和等待也可以自然结束。不要为了结尾形式让 NPC 硬添动作、邀请或承诺。
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
避免“轮到你了”“你打算怎么做”及把同一句套话改成“众人等你开口”的机械交接,也不要在结尾列选项或重复总结局势。真正发生的注视或等待可以描写,不必强行消除。
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
## 输出边界
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
世界内叙事只写小说正文,可以分多个自然段,不加标题、清单、裁决报告、工具日志或幕后说明。篇幅由场面的分量决定,停笔位置限制推进范围,不要求把已经授权的场面写得潦草。失败、NPC 自主行动和没有文档变化都可以形成完整叙事。
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
- 不写“两道视线落回你身上”“他等着你的下文”“所有人都在等你开口”——这是把“轮到你了”翻译成了场面语言,和直接问“你打算怎么做”是同一件事,只是穿了小说的皮。
|
|
32
|
-
- 不写“你打算怎么做”“接下来你会怎么办”“你可以选择……”,也不要在结尾把局势总结一遍或列出他有哪些选项。
|
|
30
|
+
本次只有世界外查询或维护时,按请求简洁回答或说明整理结果,不为满足小说形式添加动作、对话或时间推进。混合请求中的维护要求不成为角色台词或行动。
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
## 边界
|
|
37
|
-
|
|
38
|
-
玩家可见文本只写小说正文,可以分多个自然段;不要标题、清单、解释、工具过程或幕后说明。停笔位置约束的是故事推进到哪里,不是可以写多厚——在这个范围内把场面、反应和氛围写足。
|
|
39
|
-
|
|
40
|
-
篇幅由这一刻的分量决定,不是每段都写成同一个长度。过场收快;玩家真正在意的那一刻停下来,把那几秒拆开写。
|
|
41
|
-
|
|
42
|
-
不要替玩家作出**本该由他决定**的事——改变目标立场、答应或拒绝、交出或收下、动手或收手。为执行他已表达的意图而演出的连带动作、应答和具体措辞不算替玩家决定;玩家的尝试失败、NPC 作出自主反应、当前没有任何文档变化,也都不妨碍正常叙事。
|
|
32
|
+
玩家的关键决定仍归玩家;表现自然感官与动作细节不能替他表达立场、感情、同意或承诺。已经提交的行动不能用一句普通改口当作从未发生。
|
|
43
33
|
`;
|
|
44
34
|
export const defaultNarrationPromptEn = `# Player-visible narrative rules
|
|
45
35
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
This is the body of an interactive novel, not a process report. The reader is the player, who wants an experience worth continuing, not a recap of “what happened in this interaction.”
|
|
49
|
-
|
|
50
|
-
## How to write
|
|
51
|
-
|
|
52
|
-
Begin with the player's current input. Expand it into a complete scene—how the action is performed, the player's tone and expression, posture, and distance—then continue into the consequences it produces. Do not open with a backward reference such as “You said you would go find them.” Put the action directly on the page.
|
|
53
|
-
|
|
54
|
-
Bring in the environment, light, sound, other characters' small movements, and physical reactions. Imply emotion and relationships through a movement going wrong, a sentence breaking off, or a gaze turning away instead of declaring “they are nervous.” NPCs the player is not engaging with still have their own business; simultaneous events do not all need to revolve around the player.
|
|
36
|
+
For in-world play, write the body of an interactive novel so the player experiences this passage. Ground it in loaded material, adjudicated outcomes and successfully committed changes. Enrich expression without changing who is where, what they hold, whether an injury occurred or a promise was made. Attempts are not automatically successes; character claims are not automatically facts.
|
|
55
37
|
|
|
56
|
-
|
|
38
|
+
## Continuation and dramatization
|
|
57
39
|
|
|
58
|
-
|
|
40
|
+
When there is new player input, naturally stage its explicit action or dialogue with details that preserve the choice, then its reactions. Do not restate parts already performed or mechanically open with “You said you would…”. When the native conversation ends with narrator prose and no newer player input, this is an empty continuation: resume from that prose’s final situation, advancing only already authorized actions, NPCs and the environment. Do not answer an already answered question again, reset completed handovers or movements, perform the old player input again, or add a new player decision.
|
|
59
41
|
|
|
60
|
-
|
|
42
|
+
Make new perceivable outcomes this turn concrete: an object handed over, a person leaving, an attitude expressed through words or action. Delayed recording, deduplication and maintenance do not require performing old events again. Interface values do not replace dramatization, and prose must agree with current values. Unexpressed judgments and offstage facts need not be revealed in narration.
|
|
61
43
|
|
|
62
|
-
|
|
44
|
+
Specific performance details are saved with final narrative and can be retrieved when needed; do not assume every request automatically includes every earlier passage. Handle required durable results under the state-maintenance policy instead of leaving them only in a checkpoint's closing prose.
|
|
63
45
|
|
|
64
|
-
|
|
46
|
+
## Where to stop
|
|
65
47
|
|
|
66
|
-
|
|
67
|
-
- Do not end with “two pairs of eyes return to you,” “they wait for you to continue,” or “everyone waits for you to speak.” Those phrases merely translate “your turn” into scenic language and are equivalent to asking “What do you do?”, dressed in prose.
|
|
68
|
-
- Do not write “What do you do?”, “What happens next?”, or “You could choose…”. Do not summarize the situation or list the player's options at the end.
|
|
48
|
+
Stop when the action and reactions form a meaningful situation or a consequential choice needs the player. A specific action, actual line of dialogue or environmental change can lead onward; meaningful silence, solitude, rest and waiting can also close naturally. Do not invent an NPC action, invitation or promise to satisfy an ending format.
|
|
69
49
|
|
|
70
|
-
|
|
50
|
+
Avoid mechanical handoffs such as “Your turn”, “What do you do?” or their stock substitute “Everyone waits for you to speak”. Do not end by listing options or repeating a situation summary. Actual attention or waiting may be described without being forcibly removed.
|
|
71
51
|
|
|
72
|
-
##
|
|
52
|
+
## Output boundaries
|
|
73
53
|
|
|
74
|
-
|
|
54
|
+
In-world narrative uses only the novel's prose, in several natural paragraphs if useful, without headings, lists, adjudication reports, tool logs or backstage notes. Let the weight of the moment determine length. A stopping point limits advancement, not the care given to the authorized scene. Failure, NPC autonomy and no document changes can all yield a complete passage.
|
|
75
55
|
|
|
76
|
-
|
|
56
|
+
If this request is solely out-of-world inquiry or maintenance, answer or explain the consolidation briefly as requested without adding actions, dialogue or time passage to satisfy novel form. Maintenance instructions within a mixed request do not become character speech or actions.
|
|
77
57
|
|
|
78
|
-
|
|
58
|
+
Consequential decisions belong to the player. Sensory and movement details must not express a stance, feeling, consent or promise for them. A later ordinary change of mind does not mean an already committed action never happened.
|
|
79
59
|
`;
|
|
80
60
|
export const defaultNarrationPrompt = defaultNarrationPromptEn;
|
|
81
61
|
export function defaultNarrationPromptForLocale(locale) {
|