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
|
@@ -1,26 +1,36 @@
|
|
|
1
|
+
import { PackageScriptPermissions } from "./extension/PackageScriptPermissions.js";
|
|
2
|
+
import { comparePromptPrefixes } from "./prompt/WorldPromptDiagnostics.js";
|
|
1
3
|
import { join } from "node:path";
|
|
2
4
|
import { maxPortableContentArchiveBase64Characters, maxPortableContentArchiveBytes, } from "../protocol/contentTree.js";
|
|
3
5
|
import { V1ProtocolError, v1Protocol, } from "../protocol/v1.js";
|
|
4
6
|
import { defaultAppLocale, } from "../protocol/appPreferences.js";
|
|
5
7
|
import { ContentPackageImportError, ContentWorkspace, InvalidContentTreeError, } from "./content/ContentWorkspace.js";
|
|
8
|
+
import { contentTreeFingerprint } from "./content/ContentTreeFingerprint.js";
|
|
6
9
|
import { inspectContentPackageCurrentTree } from "./content/FileNativeContentTree.js";
|
|
7
|
-
import { FileNativeModelHost
|
|
8
|
-
import {} from "./model/ModelHost.js";
|
|
10
|
+
import { FileNativeModelHost } from "./model/FileNativeModelAdapters.js";
|
|
11
|
+
import { equalModelHostBinding, } from "./model/ModelHost.js";
|
|
9
12
|
import { ModelConnectionStore } from "./model/ModelConnectionStore.js";
|
|
10
13
|
import { FileNativeContinuityCorrection } from "./play/FileNativeContinuityCorrection.js";
|
|
14
|
+
import { fingerprintControl } from "./play/PlayDocumentTools.js";
|
|
11
15
|
import { PlayCallChain, PlayCallChainError, } from "./play/PlayCallChain.js";
|
|
12
|
-
import { FileNativePlayPresetError, FileNativePlayPresetStore, presetHostBinding,
|
|
16
|
+
import { FileNativePlayPresetError, FileNativePlayPresetStore, presetHostBinding, } from "./play/FileNativePlayPresetStore.js";
|
|
13
17
|
import { buildPlayPresetWorkbenchSnapshot } from "./play/PlayPresetWorkbench.js";
|
|
14
18
|
import { FileNativeArtifactStore } from "./artifact/FileNativeArtifactStore.js";
|
|
15
19
|
import { projectArtifactForFrontend, projectDebugArtifactForFrontend, } from "./extension/FrontendExtensionBundle.js";
|
|
16
20
|
import { projectPlayerViewPanels, } from "./extension/PlayerViewPanelProjector.js";
|
|
17
21
|
import { FileNativePromptCompiler } from "./prompt/FileNativePromptCompiler.js";
|
|
18
|
-
import {
|
|
22
|
+
import { FileNativeSettingImprovementStore } from "./setting/FileNativeSettingImprovementStore.js";
|
|
23
|
+
import { SettingImprovementRollbackError, SettingImprovementSession, } from "./setting/SettingImprovementSession.js";
|
|
19
24
|
import { FileNativeWorldStore } from "./world/FileNativeWorldStore.js";
|
|
20
25
|
import { WorldDocumentStore } from "./world/WorldDocumentStore.js";
|
|
21
26
|
import { FileNativeAiFailureLog } from "./model/AiFailureLog.js";
|
|
22
27
|
import { AppPreferencesStore } from "./config/AppPreferencesStore.js";
|
|
28
|
+
import { FileNativeWorldRevisionStore } from "./world-revision/FileNativeWorldRevisionStore.js";
|
|
29
|
+
import { WorldRevisionSession } from "./world-revision/WorldRevisionSession.js";
|
|
30
|
+
import { WorldRevisionWorkspace, WorldRevisionWorkspaceError, } from "./world-revision/WorldRevisionWorkspace.js";
|
|
31
|
+
import { ConversationChanges } from "./ConversationChanges.js";
|
|
23
32
|
export class V1Runtime {
|
|
33
|
+
#conversationChanges = new ConversationChanges();
|
|
24
34
|
#content;
|
|
25
35
|
#playPresets;
|
|
26
36
|
#worlds;
|
|
@@ -30,7 +40,8 @@ export class V1Runtime {
|
|
|
30
40
|
#playCallChains;
|
|
31
41
|
#failureLog;
|
|
32
42
|
#preferences;
|
|
33
|
-
#settingImprovements
|
|
43
|
+
#settingImprovements;
|
|
44
|
+
#worldRevisions;
|
|
34
45
|
#compiler = new FileNativePromptCompiler();
|
|
35
46
|
#locale = defaultAppLocale;
|
|
36
47
|
constructor(input) {
|
|
@@ -47,9 +58,75 @@ export class V1Runtime {
|
|
|
47
58
|
input.logRoot === undefined
|
|
48
59
|
? undefined
|
|
49
60
|
: new FileNativeAiFailureLog(join(input.logRoot, "ai-failures"));
|
|
50
|
-
this.#playCallChains = new PlayCallChain(this.#worlds, this.#compiler, this.#artifacts, this.#failureLog);
|
|
61
|
+
this.#playCallChains = new PlayCallChain(this.#worlds, this.#compiler, this.#artifacts, this.#failureLog, (id) => this.#conversationChanges.publish(`play:${id}`));
|
|
51
62
|
this.#models = new ModelConnectionStore(input.configRoot);
|
|
52
|
-
this.#corrections = new FileNativeContinuityCorrection(this.#worlds
|
|
63
|
+
this.#corrections = new FileNativeContinuityCorrection(this.#worlds, {
|
|
64
|
+
compiler: this.#compiler,
|
|
65
|
+
});
|
|
66
|
+
this.#settingImprovements = new SettingImprovementSession({
|
|
67
|
+
changed: (id, durable) => this.#conversationChanges.publish(`setting:${id}`, durable),
|
|
68
|
+
store: new FileNativeSettingImprovementStore(input.dataRoot, {
|
|
69
|
+
content: this.#content,
|
|
70
|
+
}),
|
|
71
|
+
content: this.#content,
|
|
72
|
+
compiler: this.#compiler,
|
|
73
|
+
locale: () => this.#locale,
|
|
74
|
+
bindModelHost: () => this.#modelHost(),
|
|
75
|
+
bindExistingModelHost: (binding) => this.#matchingModelHost(binding),
|
|
76
|
+
bindPlayPreset: () => this.#playPresets.freeze(),
|
|
77
|
+
preview: (snapshot, modelBinding, playPreset) => this.#compiler.preview({
|
|
78
|
+
endpoint: { id: "setting-authoring", commit: "current-tree" },
|
|
79
|
+
hostBinding: playPreset === undefined
|
|
80
|
+
? {
|
|
81
|
+
hostPresetId: "legacy-setting-authoring",
|
|
82
|
+
files: defaultSettingPreviewHost(),
|
|
83
|
+
}
|
|
84
|
+
: presetHostBinding(playPreset),
|
|
85
|
+
world: previewWorld(snapshot, "setting-authoring.message.genesis.narrator", "setting-authoring"),
|
|
86
|
+
playerInputPlacement: "append",
|
|
87
|
+
playerInput: this.#locale === "zh-CN"
|
|
88
|
+
? "检查内容包当前树。"
|
|
89
|
+
: "Inspect the content package current tree.",
|
|
90
|
+
modelBinding,
|
|
91
|
+
}, playPreset),
|
|
92
|
+
});
|
|
93
|
+
const worldRevisionStore = new FileNativeWorldRevisionStore(input.dataRoot);
|
|
94
|
+
const worldRevisionWorkspace = new WorldRevisionWorkspace({
|
|
95
|
+
store: worldRevisionStore,
|
|
96
|
+
worlds: this.#worlds,
|
|
97
|
+
});
|
|
98
|
+
this.#worldRevisions = new WorldRevisionSession({
|
|
99
|
+
changed: (id, durable) => this.#conversationChanges.publish(`revision:${id}`, durable),
|
|
100
|
+
store: worldRevisionStore,
|
|
101
|
+
workspace: worldRevisionWorkspace,
|
|
102
|
+
worlds: this.#worlds,
|
|
103
|
+
compiler: this.#compiler,
|
|
104
|
+
locale: () => this.#locale,
|
|
105
|
+
bindModelHost: () => this.#modelHost(),
|
|
106
|
+
bindExistingModelHost: (binding) => this.#matchingModelHost(binding),
|
|
107
|
+
bindPlayPreset: () => this.#playPresets.freeze(),
|
|
108
|
+
preview: ({ snapshot, modelBinding, playPreset, binding, epoch, maintenance, }) => this.#compiler.preview({
|
|
109
|
+
endpoint: {
|
|
110
|
+
id: `${epoch.worldId}:${epoch.baseHead}:revision`,
|
|
111
|
+
commit: `worktree:${contentTreeFingerprint(snapshot.files)}`,
|
|
112
|
+
operationId: epoch.epochId,
|
|
113
|
+
},
|
|
114
|
+
hostBinding: presetHostBinding(playPreset),
|
|
115
|
+
world: {
|
|
116
|
+
controlFingerprint: fingerprintControl(Object.fromEntries(snapshot.files.map(({ path, contents }) => [path, contents]))),
|
|
117
|
+
documentSnapshot: snapshot,
|
|
118
|
+
history: structuredClone(binding.history),
|
|
119
|
+
narrativeCheckpoint: binding.narrativeCheckpoint,
|
|
120
|
+
...maintenance,
|
|
121
|
+
additionalMaterials: structuredClone(binding.additionalMaterials),
|
|
122
|
+
},
|
|
123
|
+
playerInputPlacement: "append",
|
|
124
|
+
playerInput: this.#locale === "zh-CN"
|
|
125
|
+
? "检查世界修订工作树。"
|
|
126
|
+
: "Inspect the world-revision worktree.",
|
|
127
|
+
modelBinding,
|
|
128
|
+
}, playPreset),
|
|
129
|
+
});
|
|
53
130
|
}
|
|
54
131
|
async initialize() {
|
|
55
132
|
this.#locale = (await this.#preferences.view()).locale;
|
|
@@ -57,8 +134,58 @@ export class V1Runtime {
|
|
|
57
134
|
await this.#playPresets.initialize();
|
|
58
135
|
}
|
|
59
136
|
async handle(request, playCallChainObserver) {
|
|
60
|
-
|
|
61
|
-
|
|
137
|
+
try {
|
|
138
|
+
const result = await this.#dispatch(request, playCallChainObserver);
|
|
139
|
+
return { protocol: v1Protocol, result };
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
// Explicit commands may partially settle before failing. Readers recover
|
|
143
|
+
// through the same Runtime projection, never infer success from this signal.
|
|
144
|
+
if (!/\.(read|status|overview|inspect|page|detail|list|preview)$/.test(request.type)) {
|
|
145
|
+
if ("packageId" in request)
|
|
146
|
+
this.#conversationChanges.publish(`setting:${request.packageId}`);
|
|
147
|
+
if ("worldId" in request) {
|
|
148
|
+
this.#conversationChanges.publish(`play:${request.worldId}`);
|
|
149
|
+
this.#conversationChanges.publish(`revision:${request.worldId}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
subscribeConversation(target, changed) {
|
|
155
|
+
return this.#conversationChanges.subscribe(`${target.kind}:${target.id}`, changed);
|
|
156
|
+
}
|
|
157
|
+
async readConversation(target, previous) {
|
|
158
|
+
switch (target.kind) {
|
|
159
|
+
case "play":
|
|
160
|
+
return {
|
|
161
|
+
kind: "play",
|
|
162
|
+
value: await this.#playCallChains.observeWorld(target.id),
|
|
163
|
+
extensionsRevision: await this.#worlds.extensionControlsRevision(target.id),
|
|
164
|
+
};
|
|
165
|
+
case "setting": {
|
|
166
|
+
if (previous?.kind === "setting")
|
|
167
|
+
return {
|
|
168
|
+
kind: "setting",
|
|
169
|
+
value: this.#settingImprovements.observeProgress(previous.value),
|
|
170
|
+
};
|
|
171
|
+
const status = await this.#settingImprovements.status(target.id, target.sessionId);
|
|
172
|
+
const content = await this.#content.readCurrentTreeContentPackage(target.id);
|
|
173
|
+
return {
|
|
174
|
+
kind: "setting",
|
|
175
|
+
value: {
|
|
176
|
+
...status,
|
|
177
|
+
revision: `${status.revision}:${contentTreeFingerprint(content.files)}`,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
case "revision":
|
|
182
|
+
return {
|
|
183
|
+
kind: "revision",
|
|
184
|
+
value: previous?.kind === "revision"
|
|
185
|
+
? this.#worldRevisions.observeProgress(previous.value)
|
|
186
|
+
: await this.#worldRevisions.status(target.id, target.sessionId),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
62
189
|
}
|
|
63
190
|
async #dispatch(request, playCallChainObserver) {
|
|
64
191
|
switch (request.type) {
|
|
@@ -74,7 +201,12 @@ export class V1Runtime {
|
|
|
74
201
|
case "preferences.read":
|
|
75
202
|
return this.#preferences.view();
|
|
76
203
|
case "preferences.save": {
|
|
77
|
-
const preferences = await this.#preferences.save(
|
|
204
|
+
const preferences = await this.#preferences.save({
|
|
205
|
+
...(request.locale === undefined ? {} : { locale: request.locale }),
|
|
206
|
+
...(request.reading === undefined
|
|
207
|
+
? {}
|
|
208
|
+
: { reading: request.reading }),
|
|
209
|
+
});
|
|
78
210
|
this.#locale = preferences.locale;
|
|
79
211
|
this.#compiler.setLocale(this.#locale);
|
|
80
212
|
await this.#playPresets.syncBuiltinDefaultLocale();
|
|
@@ -94,6 +226,14 @@ export class V1Runtime {
|
|
|
94
226
|
return this.#models.listModels(request);
|
|
95
227
|
case "content.create":
|
|
96
228
|
return this.#content.createCurrentTreeContentPackage();
|
|
229
|
+
case "content.scripts.read":
|
|
230
|
+
return this.#content.packageScriptPermissions(request.packageId);
|
|
231
|
+
case "content.scripts.set":
|
|
232
|
+
return this.#content.packageScriptPermissions(request.packageId, request.enabled);
|
|
233
|
+
case "world.package-scripts.read":
|
|
234
|
+
return this.#worlds.packageScriptPermissions(request.worldId);
|
|
235
|
+
case "world.package-scripts.set":
|
|
236
|
+
return this.#worlds.packageScriptPermissions(request.worldId, request.enabled);
|
|
97
237
|
case "content.read":
|
|
98
238
|
return this.#content.readCurrentTreeContentPackage(request.packageId);
|
|
99
239
|
case "content.replace":
|
|
@@ -108,7 +248,7 @@ export class V1Runtime {
|
|
|
108
248
|
case "content.import": {
|
|
109
249
|
const archive = decodePortableContentArchive(request.archiveBase64);
|
|
110
250
|
try {
|
|
111
|
-
return await this.#content.importPortableContentPackageArchive(archive);
|
|
251
|
+
return await this.#content.importPortableContentPackageArchive(archive, request.title === undefined ? {} : { title: request.title });
|
|
112
252
|
}
|
|
113
253
|
catch (error) {
|
|
114
254
|
if (error instanceof ContentPackageImportError ||
|
|
@@ -126,82 +266,33 @@ export class V1Runtime {
|
|
|
126
266
|
base64: exported.archive.toString("base64"),
|
|
127
267
|
};
|
|
128
268
|
}
|
|
129
|
-
case "setting-improvement.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
: { failureLog: this.#failureLog }),
|
|
143
|
-
operationId: request.improvementId,
|
|
144
|
-
locale: this.#locale,
|
|
145
|
-
}),
|
|
146
|
-
authorPrompt: settingImprovementPromptForBinding(preset, this.#locale),
|
|
147
|
-
locale: this.#locale,
|
|
148
|
-
...(this.#failureLog === undefined
|
|
149
|
-
? {}
|
|
150
|
-
: { failureLog: this.#failureLog }),
|
|
151
|
-
preview: (snapshot) => this.#compiler.preview({
|
|
152
|
-
endpoint: { id: "setting-candidate", commit: "candidate" },
|
|
153
|
-
hostBinding: {
|
|
154
|
-
hostPresetId: "setting-candidate",
|
|
155
|
-
files: defaultSettingPreviewHost(),
|
|
156
|
-
},
|
|
157
|
-
world: previewWorld(snapshot, "setting-candidate.message.genesis.narrator", "setting-candidate"),
|
|
158
|
-
playerInputPlacement: "bootstrap",
|
|
159
|
-
playerInput: this.#locale === "zh-CN"
|
|
160
|
-
? "预览设定候选。"
|
|
161
|
-
: "Preview the setting candidate.",
|
|
162
|
-
modelBinding: new FileNativeModelHost(connection).binding(),
|
|
163
|
-
}),
|
|
164
|
-
});
|
|
165
|
-
if (this.#settingImprovements.has(request.improvementId))
|
|
166
|
-
throw new Error("Setting-improvement ID already exists");
|
|
167
|
-
this.#settingImprovements.set(request.improvementId, {
|
|
168
|
-
packageId: request.packageId,
|
|
169
|
-
improvement,
|
|
170
|
-
});
|
|
269
|
+
case "setting-improvement.preview":
|
|
270
|
+
return this.#settingImprovements.preview(request.packageId, request.sessionId);
|
|
271
|
+
case "setting-improvement.read":
|
|
272
|
+
return this.#settingImprovements.read(request.packageId);
|
|
273
|
+
case "setting-improvement.status":
|
|
274
|
+
return this.#settingImprovements.status(request.packageId, request.sessionId);
|
|
275
|
+
case "setting-improvement.overview":
|
|
276
|
+
return this.#settingImprovements.overview(request.packageId);
|
|
277
|
+
case "setting-improvement.session.read":
|
|
278
|
+
return this.#settingImprovements.readSession(request.packageId, request.sessionId);
|
|
279
|
+
case "setting-improvement.session.delete":
|
|
280
|
+
return this.#settingImprovements.deleteSession(request.packageId, request.sessionId);
|
|
281
|
+
case "setting-improvement.rollback":
|
|
171
282
|
try {
|
|
172
|
-
return await
|
|
173
|
-
goal: request.goal,
|
|
174
|
-
contextPaths: request.contextPaths,
|
|
175
|
-
mode: request.mode,
|
|
176
|
-
});
|
|
283
|
+
return await this.#settingImprovements.rollback(request);
|
|
177
284
|
}
|
|
178
285
|
catch (error) {
|
|
179
|
-
|
|
286
|
+
if (error instanceof SettingImprovementRollbackError)
|
|
287
|
+
throw new V1ProtocolError("invalid_request", error.message, {
|
|
288
|
+
cause: error,
|
|
289
|
+
});
|
|
180
290
|
throw error;
|
|
181
291
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
// yield the event loop, so this read observes the run in flight.
|
|
187
|
-
case "setting-improvement.progress":
|
|
188
|
-
return this.#settingImprovement(request.improvementId).improvement.progress();
|
|
189
|
-
case "setting-improvement.revise-plan":
|
|
190
|
-
return this.#settingImprovement(request.improvementId).improvement.revisePlan(request.feedback);
|
|
191
|
-
case "setting-improvement.revise-candidate":
|
|
192
|
-
return this.#settingImprovement(request.improvementId).improvement.reviseCandidate(request.feedback);
|
|
193
|
-
case "setting-improvement.apply": {
|
|
194
|
-
const active = this.#settingImprovement(request.improvementId);
|
|
195
|
-
await active.improvement.apply(async (files) => {
|
|
196
|
-
await this.#content.replaceCurrentTreeContentPackage(active.packageId, files);
|
|
197
|
-
});
|
|
198
|
-
this.#settingImprovements.delete(request.improvementId);
|
|
199
|
-
return { applied: true };
|
|
200
|
-
}
|
|
201
|
-
case "setting-improvement.discard":
|
|
202
|
-
this.#settingImprovement(request.improvementId).improvement.discard();
|
|
203
|
-
this.#settingImprovements.delete(request.improvementId);
|
|
204
|
-
return { discarded: true };
|
|
292
|
+
case "setting-improvement.message":
|
|
293
|
+
return this.#settingImprovements.send(request);
|
|
294
|
+
case "setting-improvement.cancel":
|
|
295
|
+
return this.#settingImprovements.cancel(request.sessionId);
|
|
205
296
|
case "play.read":
|
|
206
297
|
return this.#playPresets.list();
|
|
207
298
|
case "play.create":
|
|
@@ -230,7 +321,11 @@ export class V1Runtime {
|
|
|
230
321
|
const binding = request.presetId === undefined
|
|
231
322
|
? await this.#playPresets.bindCurrent()
|
|
232
323
|
: await this.#playPresets.bindRevision(request.presetId, request.revision);
|
|
233
|
-
|
|
324
|
+
if (request.worldId === undefined)
|
|
325
|
+
return buildPlayPresetWorkbenchSnapshot(binding, undefined, request.draft);
|
|
326
|
+
const head = await this.#worlds.currentHead(request.worldId);
|
|
327
|
+
const playerViews = await this.#worlds.renderPlayerViewsAtHead(request.worldId, head);
|
|
328
|
+
return buildPlayPresetWorkbenchSnapshot(binding, { worldId: request.worldId, head, playerViews }, request.draft);
|
|
234
329
|
}
|
|
235
330
|
case "prompt.preview": {
|
|
236
331
|
const [package_, connection, playPreset] = await Promise.all([
|
|
@@ -268,6 +363,9 @@ export class V1Runtime {
|
|
|
268
363
|
appended: preview.initialAppend === undefined
|
|
269
364
|
? []
|
|
270
365
|
: [
|
|
366
|
+
...(preview.initialAppend.beforePlayer === undefined
|
|
367
|
+
? []
|
|
368
|
+
: [preview.initialAppend.beforePlayer.logical]),
|
|
271
369
|
{
|
|
272
370
|
kind: "player",
|
|
273
371
|
text: preview.initialAppend.logical.text,
|
|
@@ -290,6 +388,8 @@ export class V1Runtime {
|
|
|
290
388
|
return this.#worlds.createFromContentPackage({
|
|
291
389
|
operationId: request.operationId,
|
|
292
390
|
sourcePackageId: request.packageId,
|
|
391
|
+
sourcePackageTitle: package_.title,
|
|
392
|
+
packageScriptGrants: await this.#content.readPackageScriptGrants(request.packageId),
|
|
293
393
|
packageFiles: package_.files,
|
|
294
394
|
prompt: {
|
|
295
395
|
hostBinding: presetHostBinding(preset),
|
|
@@ -303,15 +403,18 @@ export class V1Runtime {
|
|
|
303
403
|
return this.#worlds.renameWorld(request.worldId, request.name);
|
|
304
404
|
case "world.delete":
|
|
305
405
|
return playCall(async () => {
|
|
406
|
+
await this.#worlds.assertWorldRevisionUnlocked(request.worldId);
|
|
306
407
|
this.#playCallChains.forgetWorld(request.worldId);
|
|
307
408
|
return this.#worlds.deleteWorld(request.worldId);
|
|
308
409
|
});
|
|
309
410
|
case "world.read": {
|
|
310
411
|
const head = await this.#worlds.currentHead(request.worldId);
|
|
311
412
|
const playerViews = await this.#worlds.renderPlayerViewsAtHead(request.worldId, head);
|
|
312
|
-
const
|
|
313
|
-
|
|
413
|
+
const extensionControls = await this.#currentExtensionControls(request.worldId);
|
|
414
|
+
const [playerViewPanels, playTimeline, revisionEpoch] = await Promise.all([
|
|
415
|
+
this.#frontendPlayerViewPanels(request.worldId, head, playerViews, extensionControls),
|
|
314
416
|
this.#worlds.playTimeline.readPage(request.worldId, 40),
|
|
417
|
+
this.#worldRevisions.activeEpoch(request.worldId),
|
|
315
418
|
]);
|
|
316
419
|
return {
|
|
317
420
|
worldId: request.worldId,
|
|
@@ -325,27 +428,54 @@ export class V1Runtime {
|
|
|
325
428
|
artifacts: [],
|
|
326
429
|
extensions: [],
|
|
327
430
|
playerViewPanels,
|
|
431
|
+
extensionControls,
|
|
432
|
+
suppressedPlayerViewIds: await this.#suppressedPlayerViewIds(extensionControls),
|
|
328
433
|
artifactDebug: [],
|
|
329
434
|
playCallChain: null,
|
|
330
435
|
playTimeline,
|
|
436
|
+
worldRevision: revisionEpoch,
|
|
331
437
|
};
|
|
332
438
|
}
|
|
333
439
|
case "world.surface.read":
|
|
334
440
|
return request.surface === "runtime"
|
|
335
441
|
? this.#worlds.readSurface(request.worldId, "runtime")
|
|
336
442
|
: this.#worlds.readSurface(request.worldId, request.surface);
|
|
443
|
+
case "world.extensions.read":
|
|
444
|
+
return this.#worlds.extensionControls(request.worldId, await this.#playPresets.bindCurrent(), this.#locale);
|
|
445
|
+
case "world.extensions.set": {
|
|
446
|
+
const result = await this.#worlds.extensionControls(request.worldId, await this.#playPresets.bindCurrent(), this.#locale, request);
|
|
447
|
+
return result;
|
|
448
|
+
}
|
|
337
449
|
case "world.play-decorations.read": {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
this.#
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
450
|
+
for (;;) {
|
|
451
|
+
const extensionControls = await this.#currentExtensionControls(request.worldId);
|
|
452
|
+
const head = await this.#reconcileArtifacts(request.worldId);
|
|
453
|
+
const [projection, artifactDebug] = await Promise.all([
|
|
454
|
+
this.#frontendDecorations(request.worldId),
|
|
455
|
+
this.#frontendDebug(request.worldId),
|
|
456
|
+
]);
|
|
457
|
+
const playerViews = await this.#worlds.renderPlayerViewsAtHead(request.worldId, head);
|
|
458
|
+
const playerViewPanels = await this.#frontendPlayerViewPanels(request.worldId, head, playerViews, extensionControls);
|
|
459
|
+
const suppressedPlayerViewIds = await this.#suppressedPlayerViewIds(extensionControls);
|
|
460
|
+
// Never attach a newer controls revision to a projection read before
|
|
461
|
+
// that choice was accepted. Concurrent toggles restart this read.
|
|
462
|
+
if ((await this.#worlds.extensionControlsRevision(request.worldId)) !==
|
|
463
|
+
extensionControls.revision)
|
|
464
|
+
continue;
|
|
465
|
+
return {
|
|
466
|
+
head,
|
|
467
|
+
...projection,
|
|
468
|
+
artifactDebug,
|
|
469
|
+
playerViews,
|
|
470
|
+
playerViewPanels,
|
|
471
|
+
extensionControls,
|
|
472
|
+
suppressedPlayerViewIds,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
345
475
|
}
|
|
346
476
|
case "artifacts.read":
|
|
347
477
|
await this.#reconcileArtifacts(request.worldId);
|
|
348
|
-
return this.#
|
|
478
|
+
return (await this.#frontendDecorations(request.worldId, request.channel)).artifacts;
|
|
349
479
|
case "artifacts.debug":
|
|
350
480
|
await this.#reconcileArtifacts(request.worldId);
|
|
351
481
|
return this.#frontendDebug(request.worldId, request.operationId);
|
|
@@ -355,6 +485,7 @@ export class V1Runtime {
|
|
|
355
485
|
return result;
|
|
356
486
|
}
|
|
357
487
|
case "world.control-draft.save":
|
|
488
|
+
await this.#worlds.assertWorldRevisionUnlocked(request.worldId);
|
|
358
489
|
return this.#worlds.saveControlDraft(request.worldId, request.files);
|
|
359
490
|
case "world.control-draft.preview": {
|
|
360
491
|
const prompt = {
|
|
@@ -374,6 +505,33 @@ export class V1Runtime {
|
|
|
374
505
|
};
|
|
375
506
|
return this.#worlds.applyControlDraft(request.worldId, prompt);
|
|
376
507
|
}
|
|
508
|
+
case "world.revision.open":
|
|
509
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.open(request.worldId));
|
|
510
|
+
case "world.revision.overview":
|
|
511
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.overview(request.worldId));
|
|
512
|
+
case "world.revision.preview":
|
|
513
|
+
return this.#worldRevisions.preview(request.worldId, request.sessionId);
|
|
514
|
+
case "world.revision.status":
|
|
515
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.status(request.worldId, request.sessionId));
|
|
516
|
+
case "world.revision.session.read":
|
|
517
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.readSession(request.worldId, request.sessionId));
|
|
518
|
+
case "world.revision.session.delete":
|
|
519
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.deleteSession(request.worldId, request.sessionId));
|
|
520
|
+
case "world.revision.message":
|
|
521
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.send(request));
|
|
522
|
+
case "world.revision.cancel":
|
|
523
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.cancel(request.sessionId));
|
|
524
|
+
case "world.revision.files.replace":
|
|
525
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.replaceFiles(request));
|
|
526
|
+
case "world.revision.rollback":
|
|
527
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.rollback(request));
|
|
528
|
+
case "world.revision.apply": {
|
|
529
|
+
const result = await this.#worldRevisionCall(() => this.#worldRevisions.apply(request));
|
|
530
|
+
await this.#reconcileArtifacts(request.worldId);
|
|
531
|
+
return result;
|
|
532
|
+
}
|
|
533
|
+
case "world.revision.discard":
|
|
534
|
+
return this.#worldRevisionCall(() => this.#worldRevisions.discard(request));
|
|
377
535
|
case "world.derive": {
|
|
378
536
|
const preset = await this.#playPresets.bindCurrent();
|
|
379
537
|
const result = await this.#playCallChains.deriveWorld({
|
|
@@ -386,18 +544,33 @@ export class V1Runtime {
|
|
|
386
544
|
return result;
|
|
387
545
|
}
|
|
388
546
|
case "play.chain.revise-player": {
|
|
389
|
-
const
|
|
547
|
+
const base = {
|
|
390
548
|
operationId: request.operationId,
|
|
391
549
|
worldId: request.worldId,
|
|
392
550
|
chainId: request.chainId,
|
|
393
551
|
eventId: request.eventId,
|
|
394
552
|
replacementExchangeId: request.replacementExchangeId,
|
|
395
553
|
replacementText: request.replacementText,
|
|
396
|
-
}
|
|
554
|
+
};
|
|
555
|
+
const result = await playCall(async () => {
|
|
556
|
+
await this.#worlds.assertWorldRevisionUnlocked(request.worldId);
|
|
557
|
+
if (request.continuation === "continue_context")
|
|
558
|
+
return this.#playCallChains.revisePlayer({
|
|
559
|
+
...base,
|
|
560
|
+
continuation: request.continuation,
|
|
561
|
+
});
|
|
562
|
+
const { hostBinding, playPreset, modelBinding } = await this.#continuousBinding();
|
|
563
|
+
return this.#playCallChains.revisePlayer({
|
|
564
|
+
...base,
|
|
565
|
+
continuation: request.continuation,
|
|
566
|
+
freshContext: { hostBinding, playPreset, modelBinding },
|
|
567
|
+
});
|
|
568
|
+
});
|
|
397
569
|
await this.#reconcileArtifacts(request.worldId);
|
|
398
570
|
return result;
|
|
399
571
|
}
|
|
400
572
|
case "play.chain.start": {
|
|
573
|
+
await this.#worlds.assertWorldRevisionUnlocked(request.worldId);
|
|
401
574
|
const { modelHost, hostBinding, playPreset, modelBinding } = await this.#continuousBinding();
|
|
402
575
|
return playCall(() => this.#playCallChains.start({
|
|
403
576
|
worldId: request.worldId,
|
|
@@ -414,16 +587,20 @@ export class V1Runtime {
|
|
|
414
587
|
}));
|
|
415
588
|
}
|
|
416
589
|
case "play.chain.append":
|
|
417
|
-
return playCall(async () =>
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
:
|
|
426
|
-
|
|
590
|
+
return playCall(async () => {
|
|
591
|
+
await this.#worlds.assertWorldRevisionUnlocked(request.worldId);
|
|
592
|
+
return this.#playCallChains.append({
|
|
593
|
+
worldId: request.worldId,
|
|
594
|
+
chainId: request.chainId,
|
|
595
|
+
exchangeId: request.exchangeId,
|
|
596
|
+
playerText: request.playerText,
|
|
597
|
+
modelHost: await this.#modelHost(),
|
|
598
|
+
resolvePrompt: () => this.#continuousBinding(),
|
|
599
|
+
...(playCallChainObserver === undefined
|
|
600
|
+
? {}
|
|
601
|
+
: { observer: playCallChainObserver }),
|
|
602
|
+
});
|
|
603
|
+
});
|
|
427
604
|
case "play.chain.cancel":
|
|
428
605
|
return playCall(() => this.#playCallChains.cancel({
|
|
429
606
|
worldId: request.worldId,
|
|
@@ -438,6 +615,88 @@ export class V1Runtime {
|
|
|
438
615
|
case "play.timeline.detail":
|
|
439
616
|
await this.#worlds.ensureCurrentStorage(request.worldId);
|
|
440
617
|
return this.#worlds.playTimeline.readDetail(request.worldId, request.chainId, request.eventId);
|
|
618
|
+
case "world.play-context.read": {
|
|
619
|
+
const binding = await this.#worlds.bindPlayCallChain(request.worldId);
|
|
620
|
+
const currentContext = await this.#playCallChains.inspectReading(request.worldId, binding.parentHead);
|
|
621
|
+
const model = await this.#models.view();
|
|
622
|
+
if (!model.configured)
|
|
623
|
+
return {
|
|
624
|
+
worldId: request.worldId,
|
|
625
|
+
worldHead: binding.parentHead,
|
|
626
|
+
currentContext,
|
|
627
|
+
nextFreshContext: null,
|
|
628
|
+
};
|
|
629
|
+
const { modelHost, hostBinding, playPreset, modelBinding } = await this.#continuousBinding();
|
|
630
|
+
const persisted = currentContext === null
|
|
631
|
+
? null
|
|
632
|
+
: await this.#worlds.playTimeline.readCurrent(request.worldId);
|
|
633
|
+
const frozenBinding = persisted?.value.modelBinding;
|
|
634
|
+
const continueContext = currentContext !== null &&
|
|
635
|
+
!currentContext.stale &&
|
|
636
|
+
frozenBinding !== undefined &&
|
|
637
|
+
equalModelHostBinding(frozenBinding, modelBinding);
|
|
638
|
+
const baseline = continueContext
|
|
639
|
+
? await this.#worlds.bindPlayCallChainAt(request.worldId, currentContext.baselineHead)
|
|
640
|
+
: binding;
|
|
641
|
+
const preview = this.#compiler.preview({
|
|
642
|
+
extensionControls: await this.#worlds.extensionControls(request.worldId, playPreset, this.#locale),
|
|
643
|
+
endpoint: {
|
|
644
|
+
id: `${request.worldId}:${binding.parentHead}`,
|
|
645
|
+
commit: binding.parentHead,
|
|
646
|
+
},
|
|
647
|
+
hostBinding,
|
|
648
|
+
world: {
|
|
649
|
+
controlFingerprint: fingerprintControl(binding.files),
|
|
650
|
+
documentSnapshot: WorldDocumentStore.open({
|
|
651
|
+
layout: "world_state",
|
|
652
|
+
files: Object.entries(binding.files).map(([path, contents]) => ({ path, contents })),
|
|
653
|
+
}),
|
|
654
|
+
additionalMaterials: structuredClone(binding.additionalMaterials),
|
|
655
|
+
history: structuredClone(binding.history),
|
|
656
|
+
narrativeCheckpoint: baseline.narrativeCheckpoint,
|
|
657
|
+
historyAlreadyAppended: Object.keys(binding.history).filter((key) => !(key in baseline.history)),
|
|
658
|
+
...(await this.#worlds.inspectDocumentMaintenance(request.worldId, binding.parentHead)),
|
|
659
|
+
},
|
|
660
|
+
playerInputPlacement: "append",
|
|
661
|
+
playerInput: "",
|
|
662
|
+
modelBinding,
|
|
663
|
+
}, playPreset);
|
|
664
|
+
const tools = preview.compilation.toolUniverse;
|
|
665
|
+
const nextEncoding = modelHost.previewRequest({
|
|
666
|
+
bootstrap: preview.compilation,
|
|
667
|
+
tools,
|
|
668
|
+
toolUniverse: tools,
|
|
669
|
+
allowedTools: tools.map(({ name }) => name),
|
|
670
|
+
toolStrategy: preview.compilation.toolStrategy,
|
|
671
|
+
appended: continueContext ? (persisted?.value.transcript ?? []) : [],
|
|
672
|
+
operationId: continueContext
|
|
673
|
+
? currentContext.chainId
|
|
674
|
+
: "next-fresh-context-preview",
|
|
675
|
+
maxOutputTokens: modelBinding.maxOutputTokens,
|
|
676
|
+
});
|
|
677
|
+
const currentEncoding = currentContext === null
|
|
678
|
+
? null
|
|
679
|
+
: await this.#worlds.playTimeline
|
|
680
|
+
.readInitialEncoding(request.worldId, currentContext.chainId, currentContext.requestExchange)
|
|
681
|
+
.catch(() => null);
|
|
682
|
+
const prefixDiagnostics = comparePromptPrefixes(currentContext === null
|
|
683
|
+
? null
|
|
684
|
+
: {
|
|
685
|
+
bootstrap: currentContext.bootstrap,
|
|
686
|
+
encoding: currentEncoding,
|
|
687
|
+
}, { bootstrap: preview.compilation, encoding: nextEncoding });
|
|
688
|
+
return {
|
|
689
|
+
worldId: request.worldId,
|
|
690
|
+
worldHead: binding.parentHead,
|
|
691
|
+
currentContext,
|
|
692
|
+
nextFreshContext: {
|
|
693
|
+
contextMode: continueContext ? "append" : "fresh",
|
|
694
|
+
head: binding.parentHead,
|
|
695
|
+
preview,
|
|
696
|
+
prefixDiagnostics,
|
|
697
|
+
},
|
|
698
|
+
};
|
|
699
|
+
}
|
|
441
700
|
case "correction.begin":
|
|
442
701
|
return this.#corrections.begin({
|
|
443
702
|
worldId: request.worldId,
|
|
@@ -450,12 +709,14 @@ export class V1Runtime {
|
|
|
450
709
|
return this.#corrections.patchDocument(request);
|
|
451
710
|
case "correction.replace":
|
|
452
711
|
return this.#corrections.replaceDocument(request);
|
|
453
|
-
case "correction.preview":
|
|
712
|
+
case "correction.preview": {
|
|
713
|
+
const { hostBinding, modelBinding, playPreset } = await this.#continuousBinding();
|
|
454
714
|
return this.#corrections.preview({
|
|
455
715
|
candidateId: request.candidateId,
|
|
456
716
|
expectedVersion: request.expectedVersion,
|
|
457
|
-
prompt:
|
|
717
|
+
prompt: { hostBinding, modelBinding, playPreset },
|
|
458
718
|
});
|
|
719
|
+
}
|
|
459
720
|
case "correction.apply": {
|
|
460
721
|
const result = await this.#corrections.apply(request);
|
|
461
722
|
await this.#reconcileResultArtifacts(result);
|
|
@@ -469,6 +730,21 @@ export class V1Runtime {
|
|
|
469
730
|
async #modelHost() {
|
|
470
731
|
return new FileNativeModelHost(await this.#models.bind(), fetch, this.#failureLog);
|
|
471
732
|
}
|
|
733
|
+
async #worldRevisionCall(operation) {
|
|
734
|
+
try {
|
|
735
|
+
return await operation();
|
|
736
|
+
}
|
|
737
|
+
catch (error) {
|
|
738
|
+
if (error instanceof WorldRevisionWorkspaceError)
|
|
739
|
+
throw new V1ProtocolError("invalid_request", error.message, {
|
|
740
|
+
cause: error,
|
|
741
|
+
});
|
|
742
|
+
throw error;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
async #matchingModelHost(binding) {
|
|
746
|
+
return new FileNativeModelHost(await this.#models.bindMatching(binding), fetch, this.#failureLog);
|
|
747
|
+
}
|
|
472
748
|
async #reconcileArtifacts(worldId) {
|
|
473
749
|
const [head, currentOperationId] = await Promise.all([
|
|
474
750
|
this.#worlds.currentHead(worldId),
|
|
@@ -477,19 +753,71 @@ export class V1Runtime {
|
|
|
477
753
|
await this.#artifacts.reconcileHead(worldId, head, currentOperationId ?? undefined);
|
|
478
754
|
return head;
|
|
479
755
|
}
|
|
480
|
-
async #
|
|
481
|
-
|
|
482
|
-
|
|
756
|
+
async #frontendDecorations(worldId, channel) {
|
|
757
|
+
await this.#currentExtensionControls(worldId);
|
|
758
|
+
const summaries = await this.#artifacts.readExtensionSummaries(worldId);
|
|
759
|
+
const targets = await this.#worlds.playTimeline.resolveReplies(worldId, summaries.flatMap((item) => item.attachment === undefined ? [] : [item.attachment]));
|
|
760
|
+
const matches = (attachment) => targets.find((target) => target.contextId === attachment.contextId &&
|
|
761
|
+
target.eventId === attachment.eventId &&
|
|
762
|
+
target.head === attachment.head);
|
|
763
|
+
const extensions = summaries
|
|
764
|
+
.filter((item) => item.attachment === undefined ||
|
|
765
|
+
matches(item.attachment) !== undefined)
|
|
766
|
+
.sort((left, right) => Number(left.head?.replace("commit:", "") ?? 0) -
|
|
767
|
+
Number(right.head?.replace("commit:", "") ?? 0));
|
|
768
|
+
const artifacts = await this.#artifacts.readActiveProjection(worldId, channel, targets);
|
|
769
|
+
const projected = (await Promise.all(artifacts.map(async (artifact) => {
|
|
483
770
|
const { renderer, ...safeArtifact } = artifact;
|
|
484
771
|
void renderer;
|
|
485
772
|
const resolved = await this.#frontendBinding(artifact.playPresetId, artifact.playPresetRevision);
|
|
486
773
|
return {
|
|
487
774
|
...safeArtifact,
|
|
488
|
-
|
|
775
|
+
...(artifact.attachment === undefined
|
|
776
|
+
? {}
|
|
777
|
+
: {
|
|
778
|
+
reply: matches(artifact.attachment),
|
|
779
|
+
}),
|
|
780
|
+
frontend: projectArtifactForFrontend(artifact, resolved.binding, resolved.failure, artifact.requestId.startsWith("package:") &&
|
|
781
|
+
artifact.frozenPresentation !== undefined &&
|
|
782
|
+
(await this.#worlds.readPackageScriptGrants(worldId)).includes(PackageScriptPermissions.fingerprint(artifact.frozenPresentation.files))),
|
|
489
783
|
};
|
|
490
|
-
}));
|
|
784
|
+
}))).filter((artifact) => artifact.frontend.mount !== "story" || artifact.reply !== undefined);
|
|
785
|
+
return { artifacts: projected, extensions };
|
|
786
|
+
}
|
|
787
|
+
async #currentExtensionControls(worldId) {
|
|
788
|
+
try {
|
|
789
|
+
return await this.#worlds.extensionControls(worldId, await this.#playPresets.bindCurrent(), this.#locale);
|
|
790
|
+
}
|
|
791
|
+
catch (error) {
|
|
792
|
+
if (!(error instanceof FileNativePlayPresetError))
|
|
793
|
+
throw error;
|
|
794
|
+
return {
|
|
795
|
+
revision: await this.#worlds.extensionControlsRevision(worldId),
|
|
796
|
+
items: [],
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
async #suppressedPlayerViewIds(controls) {
|
|
801
|
+
let binding;
|
|
802
|
+
try {
|
|
803
|
+
binding = await this.#playPresets.bindCurrent();
|
|
804
|
+
}
|
|
805
|
+
catch (error) {
|
|
806
|
+
if (error instanceof FileNativePlayPresetError)
|
|
807
|
+
return [];
|
|
808
|
+
throw error;
|
|
809
|
+
}
|
|
810
|
+
// Every declared panel owns its view's fallback even while hidden.
|
|
811
|
+
return [
|
|
812
|
+
...new Set([
|
|
813
|
+
...binding.definition.playerViewPanels.map((panel) => panel.source.view),
|
|
814
|
+
...controls.items
|
|
815
|
+
.filter((item) => item.kind === "view" && !item.enabled)
|
|
816
|
+
.map((item) => item.id),
|
|
817
|
+
]),
|
|
818
|
+
];
|
|
491
819
|
}
|
|
492
|
-
async #frontendPlayerViewPanels(worldId, head, playerViews) {
|
|
820
|
+
async #frontendPlayerViewPanels(worldId, head, playerViews, controls) {
|
|
493
821
|
try {
|
|
494
822
|
const binding = await this.#playPresets.bindCurrent();
|
|
495
823
|
return projectPlayerViewPanels({
|
|
@@ -497,7 +825,7 @@ export class V1Runtime {
|
|
|
497
825
|
head,
|
|
498
826
|
playerViews,
|
|
499
827
|
binding,
|
|
500
|
-
});
|
|
828
|
+
}).filter((panel) => controls.items.some((item) => item.kind === "panel" && item.id === panel.panelId && item.enabled));
|
|
501
829
|
}
|
|
502
830
|
catch (error) {
|
|
503
831
|
// Panels are decoration on top of a world read. Any unusable preset —
|
|
@@ -516,7 +844,9 @@ export class V1Runtime {
|
|
|
516
844
|
const resolved = await this.#frontendBinding(record.playPresetId, record.playPresetRevision);
|
|
517
845
|
return {
|
|
518
846
|
...safeRecord,
|
|
519
|
-
frontend: projectDebugArtifactForFrontend(record, resolved.binding, resolved.failure)
|
|
847
|
+
frontend: projectDebugArtifactForFrontend(record, resolved.binding, resolved.failure, record.requestId.startsWith("package:") &&
|
|
848
|
+
record.frozenPresentation !== undefined &&
|
|
849
|
+
(await this.#worlds.readPackageScriptGrants(worldId)).includes(PackageScriptPermissions.fingerprint(record.frozenPresentation.files))),
|
|
520
850
|
};
|
|
521
851
|
}));
|
|
522
852
|
}
|
|
@@ -556,12 +886,6 @@ export class V1Runtime {
|
|
|
556
886
|
return;
|
|
557
887
|
await this.#reconcileArtifacts(worldId);
|
|
558
888
|
}
|
|
559
|
-
#settingImprovement(improvementId) {
|
|
560
|
-
const active = this.#settingImprovements.get(improvementId);
|
|
561
|
-
if (active === undefined)
|
|
562
|
-
throw new Error("Setting-improvement session does not exist");
|
|
563
|
-
return active;
|
|
564
|
-
}
|
|
565
889
|
async #promptBinding() {
|
|
566
890
|
const [preset, connection] = await Promise.all([
|
|
567
891
|
this.#playPresets.bindCurrent(),
|