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.
Files changed (76) hide show
  1. package/dist/node/protocol/appPreferences.js +25 -0
  2. package/dist/node/protocol/conversationObservation.js +67 -0
  3. package/dist/node/protocol/v1.js +186 -34
  4. package/dist/node/protocol/worldExtensions.js +16 -0
  5. package/dist/node/protocol/worldMaintenance.js +77 -0
  6. package/dist/node/protocol/worldPromptDiagnostics.js +1 -0
  7. package/dist/node/runtime/ConversationChanges.js +24 -0
  8. package/dist/node/runtime/V1Runtime.js +445 -121
  9. package/dist/node/runtime/artifact/FileNativeArtifactStore.js +326 -12
  10. package/dist/node/runtime/authoring/AuthoringRequestSnapshot.js +63 -0
  11. package/dist/node/runtime/authoring/ModelToolConversation.js +218 -0
  12. package/dist/node/runtime/config/AppPreferencesStore.js +46 -17
  13. package/dist/node/runtime/content/ContentTreeFingerprint.js +13 -0
  14. package/dist/node/runtime/content/ContentWorkspace.js +43 -13
  15. package/dist/node/runtime/content/CurrentTreeContentLibrary.js +128 -46
  16. package/dist/node/runtime/content/FileNativeContentTree.js +28 -10
  17. package/dist/node/runtime/content/PackageFollowups.js +80 -0
  18. package/dist/node/runtime/extension/FrontendExtensionBundle.js +19 -14
  19. package/dist/node/runtime/extension/PackageScriptPermissions.js +70 -0
  20. package/dist/node/runtime/extension/WorldExtensionControls.js +205 -0
  21. package/dist/node/runtime/extension/WorldExtensionRequests.js +64 -0
  22. package/dist/node/runtime/model/FileNativeModelAdapters.js +21 -466
  23. package/dist/node/runtime/model/ModelConnectionStore.js +13 -0
  24. package/dist/node/runtime/model/ModelHost.js +31 -1
  25. package/dist/node/runtime/model/ModelHostStream.js +51 -5
  26. package/dist/node/runtime/play/FileNativeContinuityCorrection.js +55 -45
  27. package/dist/node/runtime/play/FileNativePlayPresetStore.js +256 -238
  28. package/dist/node/runtime/play/FileNativePlayTimelineStore.js +118 -9
  29. package/dist/node/runtime/play/OrderedFollowups.js +71 -0
  30. package/dist/node/runtime/play/OrderedPlayPrompts.js +180 -0
  31. package/dist/node/runtime/play/PlayCallChain.js +814 -61
  32. package/dist/node/runtime/play/PlayContinuity.js +88 -0
  33. package/dist/node/runtime/play/PlayDocumentTools.js +205 -287
  34. package/dist/node/runtime/play/PlayFollowupRequests.js +34 -3
  35. package/dist/node/runtime/play/PlayPresetWorkbench.js +45 -54
  36. package/dist/node/runtime/play/PlayPromptRun.js +86 -0
  37. package/dist/node/runtime/prompt/FileNativePromptCompiler.js +670 -93
  38. package/dist/node/runtime/prompt/FileNativeToolRegistry.js +37 -21
  39. package/dist/node/runtime/prompt/PromptCompilationCodec.js +322 -0
  40. package/dist/node/runtime/prompt/WorldMaintenanceReport.js +251 -0
  41. package/dist/node/runtime/prompt/WorldMaterialCoverage.js +83 -0
  42. package/dist/node/runtime/prompt/WorldPromptDiagnostics.js +185 -0
  43. package/dist/node/runtime/setting/FileNativeSettingImprovementStore.js +1027 -0
  44. package/dist/node/runtime/setting/SettingAuthoringTransaction.js +1339 -0
  45. package/dist/node/runtime/setting/SettingImprovementSession.js +714 -0
  46. package/dist/node/runtime/world/FileNativeAuthorityV3.js +88 -1
  47. package/dist/node/runtime/world/FileNativeWorldStore.js +292 -27
  48. package/dist/node/runtime/world/PlayerViewBindings.js +30 -0
  49. package/dist/node/runtime/world/PlayerViewRenderer.js +27 -34
  50. package/dist/node/runtime/world/WorldDocumentMaintenance.js +174 -0
  51. package/dist/node/runtime/world/WorldDocumentStore.js +166 -96
  52. package/dist/node/runtime/world/WorldOperationCoordinator.js +103 -2
  53. package/dist/node/runtime/world-revision/FileNativeWorldRevisionStore.js +696 -0
  54. package/dist/node/runtime/world-revision/WorldRevisionAuthoringTransaction.js +380 -0
  55. package/dist/node/runtime/world-revision/WorldRevisionSession.js +709 -0
  56. package/dist/node/runtime/world-revision/WorldRevisionWorkspace.js +494 -0
  57. package/dist/node/server/ConversationStream.js +109 -0
  58. package/dist/node/server/createServer.js +5 -1
  59. package/dist/node/shared/artifact-payload-contract.js +123 -0
  60. package/dist/node/shared/default-play-prompts.js +25 -45
  61. package/dist/node/shared/default-preset-host.js +114 -138
  62. package/dist/node/shared/default-setting-improvement-prompt.js +52 -38
  63. package/dist/node/shared/display-regex.js +114 -0
  64. package/dist/node/shared/first-party-action-choices.js +1 -6
  65. package/dist/node/shared/first-party-player-view.js +1 -6
  66. package/dist/node/shared/ordered-author-prompts.js +64 -0
  67. package/dist/node/shared/ordered-followups.js +42 -0
  68. package/dist/node/shared/ordered-play-prompts.js +73 -0
  69. package/dist/web/assets/index-BXfelCi9.js +1207 -0
  70. package/dist/web/assets/index-BYnhUxlk.css +1 -0
  71. package/dist/web/index.html +2 -2
  72. package/package.json +1 -1
  73. package/dist/node/runtime/model/SettingAuthorStream.js +0 -21
  74. package/dist/node/runtime/setting/DocumentCandidateSettingImprovement.js +0 -1731
  75. package/dist/web/assets/index-D8YKfmNG.js +0 -1192
  76. package/dist/web/assets/index-Xa0s35CJ.css +0 -1
@@ -29,7 +29,24 @@ export async function runPlayFollowupRequests(input) {
29
29
  failure ??= "The follow-up request was cancelled.";
30
30
  break;
31
31
  }
32
- const outcome = await runOne(input, followup, prefix);
32
+ const lease = await input.controls?.acquire(input.context.worldId, {
33
+ playPresetId: input.context.playPresetId,
34
+ requestId: followup.id,
35
+ ...(followup.extensionControl === undefined
36
+ ? {}
37
+ : { extensionControl: followup.extensionControl }),
38
+ }, input.signal);
39
+ if (lease?.signal.aborted) {
40
+ lease.release();
41
+ continue;
42
+ }
43
+ let outcome;
44
+ try {
45
+ outcome = await runOne(input, followup, prefix, lease?.signal ?? input.signal);
46
+ }
47
+ finally {
48
+ lease?.release();
49
+ }
33
50
  if (signalWasAborted(input.signal)) {
34
51
  failure ??= "The follow-up request was cancelled.";
35
52
  break;
@@ -46,7 +63,7 @@ export async function runPlayFollowupRequests(input) {
46
63
  : await input.artifacts.failExtension(input.context.operationId, "recovery_required", failure, completed);
47
64
  return { outcomes, extension };
48
65
  }
49
- async function runOne(input, followup, prefix) {
66
+ async function runOne(input, followup, prefix, requestSignal) {
50
67
  const outcome = {
51
68
  id: followup.id,
52
69
  displayName: followup.displayName,
@@ -55,14 +72,25 @@ async function runOne(input, followup, prefix) {
55
72
  };
56
73
  const requestContext = {
57
74
  ...input.context,
75
+ ...(followup.extensionControl === undefined
76
+ ? {}
77
+ : { extensionControl: structuredClone(followup.extensionControl) }),
78
+ ...(input.presentations?.[followup.id] === undefined
79
+ ? {}
80
+ : { frozenPresentations: input.presentations[followup.id] }),
58
81
  requestId: followup.id,
82
+ displayName: followup.displayName,
59
83
  requestAttempt: 1,
60
84
  maxArtifactBytes: followup.maxArtifactBytes,
61
85
  declarations: structuredClone(followup.artifacts),
86
+ ...(followup.frozenResources === undefined
87
+ ? {}
88
+ : { frozenResources: structuredClone(followup.frozenResources) }),
62
89
  };
63
90
  let responseDiagnostics;
64
91
  try {
65
92
  await input.artifacts.beginRequestAttempt(requestContext);
93
+ requestSignal?.throwIfAborted();
66
94
  input.observer?.onProviderDispatch?.();
67
95
  let response;
68
96
  try {
@@ -87,7 +115,7 @@ async function runOne(input, followup, prefix) {
87
115
  exchange: 1,
88
116
  maxOutputTokens: input.maxOutputTokens,
89
117
  }, {
90
- ...(input.signal === undefined ? {} : { signal: input.signal }),
118
+ ...(requestSignal === undefined ? {} : { signal: requestSignal }),
91
119
  onDelta: (delta) => input.observer?.onProviderDelta?.(delta),
92
120
  });
93
121
  if (input.signal?.aborted === true)
@@ -117,6 +145,8 @@ async function runOne(input, followup, prefix) {
117
145
  });
118
146
  }
119
147
  const failedTools = outcome.toolCalls.filter(({ ok }) => !ok);
148
+ if (failedTools.length > 0)
149
+ outcome.failure = `Follow-up request ${followup.id} could not save its artifacts.`;
120
150
  if (failedTools.length > 0 && response.diagnostics !== undefined)
121
151
  await input.failureLog?.recordFailure({
122
152
  exchange: response.diagnostics,
@@ -168,6 +198,7 @@ async function runOne(input, followup, prefix) {
168
198
  ],
169
199
  });
170
200
  }
201
+ await input.artifacts.finishRequest?.(requestContext, outcome.failure !== undefined);
171
202
  return outcome;
172
203
  }
173
204
  function signalWasAborted(signal) {
@@ -1,15 +1,38 @@
1
- import { parsePlayPresetRegexAsset, toPlayPresetStructuredEditor, } from "./FileNativePlayPresetStore.js";
1
+ import { resolveArtifactRenderer } from "../extension/FrontendExtensionBundle.js";
2
+ import { builtinFollowupExample } from "../../shared/ordered-followups.js";
3
+ import { projectPlayerViewPanels, } from "../extension/PlayerViewPanelProjector.js";
4
+ import { parsePlayPresetRegexAsset, applyPlayPresetStructuredEditor, parsePlayPresetStructuredEditor, parsePlayPresetFiles, revisionForPlayPresetFiles, toPlayPresetStructuredEditor, } from "./FileNativePlayPresetStore.js";
2
5
  /**
3
6
  * Read-only workbench seam. It resolves the same frozen file-native binding
4
7
  * used by PromptCompiler and FrontendExtensionBundle, but never calls a model,
5
8
  * writes a world, or executes author JavaScript.
6
9
  */
7
- export function buildPlayPresetWorkbenchSnapshot(binding) {
10
+ export function buildPlayPresetWorkbenchSnapshot(binding, playerViewContext, draft) {
11
+ if (draft !== undefined) {
12
+ const files = draft.structure === undefined
13
+ ? structuredClone(draft.files)
14
+ : applyPlayPresetStructuredEditor(draft.files, parsePlayPresetStructuredEditor(draft.structure));
15
+ const parsed = parsePlayPresetFiles(files);
16
+ if (parsed.kind === "invalid")
17
+ throw parsed.error;
18
+ binding = {
19
+ ...binding,
20
+ files,
21
+ definition: parsed.definition,
22
+ revision: revisionForPlayPresetFiles(files),
23
+ };
24
+ }
8
25
  const scriptsEnabled = binding.scriptsEnabled !== false;
9
26
  const structure = toPlayPresetStructuredEditor(binding.definition);
10
27
  const staticErrors = [];
11
28
  const artifactPreviews = [];
12
- for (const followup of binding.definition.followups)
29
+ const previewFollowups = [
30
+ ...binding.definition.followups,
31
+ ...(binding.definition.followupItems === undefined
32
+ ? []
33
+ : [builtinFollowupExample("en").definition]),
34
+ ];
35
+ for (const followup of previewFollowups)
13
36
  for (const declaration of followup.artifacts) {
14
37
  const diagnostics = [];
15
38
  let regex = [];
@@ -41,57 +64,17 @@ export function buildPlayPresetWorkbenchSnapshot(binding) {
41
64
  ? "<p>This is a local HTML workbench sample.</p>"
42
65
  : "This is a local text workbench sample.";
43
66
  let renderer;
44
- if (declaration.renderer !== undefined) {
45
- const source = binding.files[declaration.renderer];
46
- if (source === undefined) {
47
- const message = `Renderer resource does not exist: ${declaration.renderer}`;
48
- diagnostics.push(message);
49
- staticErrors.push({
50
- code: "renderer_missing",
51
- message,
52
- location: declaration.renderer,
53
- });
54
- }
55
- else {
56
- const scriptSources = (declaration.scripts ?? []).flatMap((path) => {
57
- const script = binding.files[path];
58
- if (script === undefined) {
59
- diagnostics.push(`Script resource does not exist: ${path}`);
60
- staticErrors.push({
61
- code: "script_missing",
62
- message: `Script resource does not exist: ${path}`,
63
- location: path,
64
- });
65
- return [];
66
- }
67
- return [script];
68
- });
69
- const assetSources = (declaration.assets ?? []).flatMap((path) => {
70
- const asset = binding.files[path];
71
- if (asset === undefined) {
72
- diagnostics.push(`Asset resource does not exist: ${path}`);
73
- staticErrors.push({
74
- code: "asset_missing",
75
- message: `Asset resource does not exist: ${path}`,
76
- location: path,
77
- });
78
- return [];
79
- }
80
- return [{ id: path, source: asset }];
81
- });
82
- renderer = {
83
- mode: declaration.rendererMode ?? "document",
84
- ...(declaration.rendererRevision === undefined
85
- ? {}
86
- : { revision: declaration.rendererRevision }),
87
- document: source,
88
- scripts: scriptsEnabled ? scriptSources : [],
89
- assets: assetSources,
90
- trustedLocalCode: scriptsEnabled &&
91
- (declaration.contentType === "text/html" ||
92
- (declaration.scripts?.length ?? 0) > 0),
93
- };
94
- }
67
+ try {
68
+ renderer = resolveArtifactRenderer(declaration, binding);
69
+ }
70
+ catch (error) {
71
+ const message = error instanceof Error ? error.message : "Invalid renderer resources";
72
+ diagnostics.push(message);
73
+ staticErrors.push({
74
+ code: "renderer_invalid",
75
+ message,
76
+ location: declaration.renderer ?? followup.id,
77
+ });
95
78
  }
96
79
  artifactPreviews.push({
97
80
  requestId: followup.id,
@@ -125,6 +108,14 @@ export function buildPlayPresetWorkbenchSnapshot(binding) {
125
108
  revision: binding.revision,
126
109
  structure,
127
110
  artifactPreviews,
111
+ ...(playerViewContext === undefined
112
+ ? {}
113
+ : {
114
+ playerViewPreview: {
115
+ ...playerViewContext,
116
+ panels: projectPlayerViewPanels({ ...playerViewContext, binding }),
117
+ },
118
+ }),
128
119
  staticErrors,
129
120
  trustedLocalCode: artifactPreviews.some(({ renderer }) => renderer?.trustedLocalCode === true),
130
121
  scriptsEnabled,
@@ -0,0 +1,86 @@
1
+ import { validPromptCompilation, validPromptTools, validPlayFollowup, } from "../prompt/PromptCompilationCodec.js";
2
+ import { createHash } from "node:crypto";
3
+ export function currentPlayPrompt(source) {
4
+ return source.promptRuns?.at(-1) ?? source;
5
+ }
6
+ export function recordedPlayPrompt(source) {
7
+ const lastEvent = source.events.at(-1)?.id ?? 0;
8
+ return (source.promptRuns?.findLast((run) => run.firstEventId <= lastEvent) ??
9
+ source);
10
+ }
11
+ export function playPromptRunsThroughEvents(context, events) {
12
+ const lastEvent = events.at(-1)?.id ?? 0;
13
+ const runs = (context.promptRuns ?? []).filter(({ firstEventId }) => firstEventId <= lastEvent);
14
+ return structuredClone([
15
+ ...new Map(runs.map((run) => [run.firstEventId, run])).values(),
16
+ ]);
17
+ }
18
+ export function assertPlayPromptRun(value) {
19
+ if (typeof value !== "object" || value === null)
20
+ throw new Error("Invalid play prompt run");
21
+ const run = value;
22
+ if (!exactKeys(run, [
23
+ "schemaVersion",
24
+ "firstEventId",
25
+ "head",
26
+ "exchange",
27
+ "playPreset",
28
+ "bootstrap",
29
+ "tools",
30
+ "followups",
31
+ "playPresetScriptsEnabled",
32
+ "presetFiles",
33
+ ]) ||
34
+ run.schemaVersion !== 1 ||
35
+ !Number.isSafeInteger(run.firstEventId) ||
36
+ Number(run.firstEventId) < 1 ||
37
+ !Number.isSafeInteger(run.exchange) ||
38
+ Number(run.exchange) < 1 ||
39
+ typeof run.head !== "string" ||
40
+ !validPresetIdentity(run.playPreset) ||
41
+ !validPromptCompilation(run.bootstrap) ||
42
+ !validPromptTools(run.tools) ||
43
+ !Array.isArray(run.followups) ||
44
+ !run.followups.every(validPlayFollowup) ||
45
+ typeof run.playPresetScriptsEnabled !== "boolean" ||
46
+ typeof run.presetFiles !== "object" ||
47
+ run.presetFiles === null ||
48
+ Array.isArray(run.presetFiles) ||
49
+ !Object.values(run.presetFiles).every((contents) => typeof contents === "string"))
50
+ throw new Error("Invalid play prompt run");
51
+ }
52
+ export function encodePlayPromptRun(run) {
53
+ assertPlayPromptRun(run);
54
+ return {
55
+ kind: "play_prompt_run",
56
+ schemaVersion: 1,
57
+ run,
58
+ digest: createHash("sha256").update(JSON.stringify(run)).digest("hex"),
59
+ };
60
+ }
61
+ export function decodePlayPromptRun(value) {
62
+ if (typeof value !== "object" || value === null)
63
+ throw new Error("Invalid play prompt run record");
64
+ const record = value;
65
+ if (!exactKeys(record, ["kind", "schemaVersion", "run", "digest"]) ||
66
+ record.kind !== "play_prompt_run" ||
67
+ record.schemaVersion !== 1 ||
68
+ record.digest !==
69
+ createHash("sha256")
70
+ .update(JSON.stringify(record.run) ?? "")
71
+ .digest("hex"))
72
+ throw new Error("Play prompt run does not match its durable identity");
73
+ assertPlayPromptRun(record.run);
74
+ return record.run;
75
+ }
76
+ function exactKeys(record, keys) {
77
+ return (Object.keys(record).length === keys.length &&
78
+ keys.every((key) => Object.hasOwn(record, key)));
79
+ }
80
+ function validPresetIdentity(value) {
81
+ if (typeof value !== "object" || value === null || Array.isArray(value))
82
+ return false;
83
+ const preset = value;
84
+ return (exactKeys(preset, ["id", "name", "revision"]) &&
85
+ [preset.id, preset.name, preset.revision].every((part) => typeof part === "string" && part.length > 0));
86
+ }