lumiverse-spindle-types 0.6.8 → 0.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lumiverse-spindle-types",
3
- "version": "0.6.8",
3
+ "version": "0.6.9",
4
4
  "types": "./src/index.ts",
5
5
  "keywords": [
6
6
  "lumiverse",
package/src/api.ts CHANGED
@@ -65,6 +65,7 @@ export interface LlmMessageDTO {
65
65
  * Source message's `index_in_chat`, paired with `sourceMessageId`.
66
66
  */
67
67
  sourceIndexInChat?: number;
68
+ sourceMessageMetadata?: Readonly<Record<string, unknown>>;
68
69
  }
69
70
 
70
71
  export type SpindleUserRoleDTO = "operator" | "admin" | "user";
@@ -120,6 +121,8 @@ export interface InterceptorContextDTO {
120
121
  readonly characterId: string | null;
121
122
  readonly personaAddonStates: Readonly<Record<string, boolean>>;
122
123
  readonly excludeMessageId?: string;
124
+ readonly activatedWorldInfo?: readonly ActivatedWorldInfoEntryDTO[];
125
+ readonly capturedWorldInfo?: readonly ActivatedWorldInfoEntryDTO[];
123
126
  readonly rejectedSwipe?: string;
124
127
  readonly regenFeedback?: string;
125
128
  readonly regenFeedbackPosition?: "system" | "user";
@@ -136,8 +139,17 @@ export interface InterceptorContextDTO {
136
139
  readonly signal: AbortSignal;
137
140
  }
138
141
 
142
+ /**
143
+ * Deferred system guidance retained by the host terminal lease.
144
+ *
145
+ * A result may contain at most 128 entries. IDs must be unique canonical UUIDs
146
+ * (versions 1-5). Content must be non-empty, at most 1 MiB per entry when
147
+ * UTF-8 encoded, and at most 2 MiB across the result.
148
+ */
139
149
  export interface DeferredGuidanceDTO {
150
+ /** Unique canonical UUID (versions 1-5) within this interceptor result. */
140
151
  id: string;
152
+ /** Non-empty system guidance bounded by the limits above. */
141
153
  content: string;
142
154
  role: "system";
143
155
  }
@@ -1268,7 +1280,20 @@ export type PromptBlockRoleDTO = "system" | "user" | "assistant" | "user_append"
1268
1280
  export type PromptBlockPositionDTO = "pre_history" | "post_history" | "in_history";
1269
1281
  export type PromptBlockCategoryModeDTO = "radio" | "checkbox" | null;
1270
1282
 
1271
- export interface PromptBlockDTO {
1283
+ /** A native Loom placement profile selected for a prompt block. */
1284
+ export interface PromptBlockPlacementDTO {
1285
+ role: PromptBlockRoleDTO;
1286
+ position: PromptBlockPositionDTO;
1287
+ depth: number;
1288
+ }
1289
+
1290
+ /** A select variable's mapping from option ids to native Loom placement profiles. */
1291
+ export interface PromptBlockPlacementBindingDTO {
1292
+ variableId: string;
1293
+ options: Record<string, PromptBlockPlacementDTO>;
1294
+ }
1295
+
1296
+ interface PromptBlockCoreDTO {
1272
1297
  id: string;
1273
1298
  name: string;
1274
1299
  content: string;
@@ -1289,11 +1314,45 @@ export interface PromptBlockDTO {
1289
1314
  variables?: PromptVariableDefDTO[];
1290
1315
  }
1291
1316
 
1317
+ /**
1318
+ * Editable/public prompt-block value.
1319
+ *
1320
+ * Host placement and sealed/provenance fields are snapshot-only and therefore
1321
+ * cannot be supplied through mutable block or editor inputs.
1322
+ */
1323
+ export interface PromptBlockDTO extends PromptBlockCoreDTO {
1324
+ placementBinding?: never;
1325
+ sealed?: never;
1326
+ sealedKey?: never;
1327
+ sealedSource?: never;
1328
+ sealedOriginPresetId?: never;
1329
+ sealedOriginVersion?: never;
1330
+ sealedSha256?: never;
1331
+ }
1332
+
1333
+ /**
1334
+ * Host-returned snapshot of a prompt block.
1335
+ *
1336
+ * The placement binding and sealed/provenance fields are native host snapshot
1337
+ * semantics. They are intentionally absent from the editable/public
1338
+ * `PromptBlockDTO` and must not be supplied through mutable block or editor
1339
+ * inputs.
1340
+ */
1341
+ export interface PromptBlockSnapshotDTO extends PromptBlockCoreDTO {
1342
+ placementBinding?: PromptBlockPlacementBindingDTO;
1343
+ sealed?: boolean;
1344
+ sealedKey?: string;
1345
+ sealedSource?: "lumihub" | string;
1346
+ sealedOriginPresetId?: string;
1347
+ sealedOriginVersion?: string | null;
1348
+ sealedSha256?: string;
1349
+ }
1350
+
1292
1351
  export interface PromptBlockCategoryGroupDTO {
1293
1352
  /** The category header block, or null for uncategorized leading blocks. */
1294
- categoryBlock: PromptBlockDTO | null;
1353
+ categoryBlock: PromptBlockSnapshotDTO | null;
1295
1354
  /** Non-category blocks after the header until the next category header. */
1296
- children: PromptBlockDTO[];
1355
+ children: PromptBlockSnapshotDTO[];
1297
1356
  }
1298
1357
 
1299
1358
  export interface HostResponseErrorDTO {
@@ -1310,7 +1369,7 @@ export interface UserPresetDTO {
1310
1369
  provider: string;
1311
1370
  engine: string;
1312
1371
  parameters: Record<string, unknown>;
1313
- prompt_order: PromptBlockDTO[];
1372
+ prompt_order: PromptBlockSnapshotDTO[];
1314
1373
  prompts: Record<string, unknown>;
1315
1374
  metadata: Record<string, unknown>;
1316
1375
  cache_revision: number;
@@ -1598,6 +1657,7 @@ export interface WorldInfoInterceptorResultDTO {
1598
1657
  readonly enabled?: readonly string[];
1599
1658
  readonly forced?: readonly string[];
1600
1659
  readonly mutated?: readonly WorldInfoInterceptorMutationDTO[];
1660
+ readonly captured?: readonly string[];
1601
1661
  }
1602
1662
 
1603
1663
  // ─── Databank DTOs ───────────────────────────────────────────────────────
@@ -1959,7 +2019,7 @@ export interface BoundPrefillAttachmentDTO {
1959
2019
  }
1960
2020
 
1961
2021
  export interface BoundAssembleRequestDTO {
1962
- blocks: PromptBlockDTO[];
2022
+ blocks: PromptBlockSnapshotDTO[];
1963
2023
  promptVariableValues?: PromptVariableValuesDTO;
1964
2024
  dispatch: GenerationDispatchSourceDTO;
1965
2025
  deadlineAt: number;
@@ -3408,7 +3468,8 @@ export type WorkerToHost =
3408
3468
  | { type: "user_is_visible"; requestId: string; userId?: string }
3409
3469
  | { type: "user_get_role"; requestId: string; userId?: string }
3410
3470
  // ─── Text Editor (free tier) ───────────────────────────────────────
3411
- | { type: "text_editor_open"; requestId: string; title?: string; value?: string; placeholder?: string; userId?: string }
3471
+ | { type: "text_editor_open"; requestId: string; editorRequestId?: string; title?: string; value?: string; placeholder?: string; userId?: string }
3472
+ | { type: "text_editor_close"; requestId: string; editorRequestId: string; userId?: string }
3412
3473
  // ─── Modal (free tier) ────────────────────────────────────────────
3413
3474
  | { type: "modal_open"; requestId: string; modalRequestId?: string; title: string; items: SpindleModalItemDTO[]; width?: number; maxHeight?: number; persistent?: boolean; userId?: string }
3414
3475
  | { type: "modal_close"; requestId: string; openRequestId: string; userId?: string }
package/src/components.ts CHANGED
@@ -38,6 +38,8 @@ export interface SpindleLoomBlockEditorValue {
38
38
  export interface SpindleLoomBlockEditorOptions {
39
39
  value: SpindleLoomBlockEditorValue;
40
40
  onChange?: (value: SpindleLoomBlockEditorValue) => void;
41
+ /** Reports validated in-progress edits, or `null` when the native draft is discarded. */
42
+ onDraftChange?: (value: SpindleLoomBlockEditorValue | null) => void;
41
43
  readOnly?: boolean;
42
44
  compact?: boolean;
43
45
  }
package/src/dom.ts CHANGED
@@ -547,8 +547,10 @@ export interface SpindleTextEditorOptions {
547
547
  value?: string;
548
548
  /** Placeholder text. Default: "" */
549
549
  placeholder?: string;
550
- /** Enable macro syntax highlighting and insertion panel. Default: true */
551
- macros?: boolean;
550
+ /** Optional caller-owned 1–128 character ASCII token used with `textEditor.close()`. */
551
+ editorRequestId?: string;
552
+ /** For operator-scoped extensions only. */
553
+ userId?: string;
552
554
  }
553
555
 
554
556
  export interface SpindleTextEditorResult {
package/src/host.ts CHANGED
@@ -2,9 +2,12 @@ export const SPINDLE_HOST_CAPABILITIES = Object.freeze({
2
2
  "preset-extension-data-v1": 1,
3
3
  "preset-editor-v1": 1,
4
4
  "loom-block-editor-v1": 1,
5
+ "loom-block-management-v1": 1,
5
6
  "generation-assembly-v1": 1,
6
7
  "interceptor-context-v1": 1,
7
8
  "interceptor-final-response-v1": 1,
9
+ "connection-dispatch-resolution-v1": 1,
10
+ "text-editor-close-v1": 1,
8
11
  }) as Readonly<Record<string, number>>;
9
12
  /** Structured error code returned when host compatibility validation fails. */
10
13
  export const SPINDLE_COMPATIBILITY_ERROR_CODE = "SPINDLE_COMPATIBILITY_ERROR" as const;
package/src/index.ts CHANGED
@@ -27,6 +27,7 @@ export { ALL_CAPABILITIES, isValidCapability } from "./capabilities";
27
27
  export { SpindleEvent, CoreEventType } from "./events";
28
28
 
29
29
  export type {
30
+ LlmMessagePartDTO,
30
31
  LlmMessageDTO,
31
32
  LlmThinkingBlockDTO,
32
33
  SpindleUserRoleDTO,
@@ -84,7 +85,10 @@ export type {
84
85
  PromptBlockRoleDTO,
85
86
  PromptBlockPositionDTO,
86
87
  PromptBlockCategoryModeDTO,
88
+ PromptBlockPlacementDTO,
89
+ PromptBlockPlacementBindingDTO,
87
90
  PromptBlockDTO,
91
+ PromptBlockSnapshotDTO,
88
92
  PromptBlockCreateDTO,
89
93
  PromptBlockUpdateDTO,
90
94
  PromptBlockCategoryGroupDTO,
@@ -246,13 +250,16 @@ export { PERMISSION_DENIED_PREFIX } from "./api";
246
250
  export type { ToolRegistration, JSONSchema } from "./tools";
247
251
 
248
252
  export type {
253
+ SpindleMessageElement,
254
+ SpindleTextEditorOptions,
255
+ SpindleTextEditorResult,
249
256
  SpindleDOMHelper,
250
257
  SpindleMountPoint,
251
258
  SpindleUploadFile,
252
- SpindleMessageTagIntercept,
253
- SpindleMessageTagInterceptorOptions,
254
- SpindleMessageWidgetOptions,
255
- PermissionRequestOptions,
259
+ SpindleMessageTagIntercept,
260
+ SpindleMessageTagInterceptorOptions,
261
+ SpindleMessageWidgetOptions,
262
+ PermissionRequestOptions,
256
263
  SpindleFrontendContext,
257
264
  SpindleFrontendModule,
258
265
  SpindleFrontendTeardown,
@@ -1,5 +1,6 @@
1
1
  import type { SpindleManifest } from "./manifest";
2
2
  import type { SpindleHostDescriptorV1 } from "./host";
3
+ import type { SpindleTextEditorOptions, SpindleTextEditorResult } from "./dom";
3
4
  import type {
4
5
  CouncilMemberContext,
5
6
  CouncilSettings,
@@ -30,7 +31,7 @@ import type {
30
31
  UserPresetDTO,
31
32
  UserPresetCreateDTO,
32
33
  UserPresetUpdateDTO,
33
- PromptBlockDTO,
34
+ PromptBlockSnapshotDTO,
34
35
  PromptBlockCreateDTO,
35
36
  PromptBlockUpdateDTO,
36
37
  PromptBlockCategoryGroupDTO,
@@ -953,10 +954,10 @@ export interface SpindleAPI {
953
954
  update(presetId: string, input: UserPresetUpdateDTO, userId?: string): Promise<UserPresetDTO>;
954
955
  delete(presetId: string, userId?: string): Promise<boolean>;
955
956
  blocks: {
956
- list(presetId: string, userId?: string): Promise<PromptBlockDTO[]>;
957
- get(presetId: string, blockId: string, userId?: string): Promise<PromptBlockDTO | null>;
958
- create(presetId: string, input: PromptBlockCreateDTO, options?: { index?: number; userId?: string }): Promise<PromptBlockDTO>;
959
- update(presetId: string, blockId: string, input: PromptBlockUpdateDTO, userId?: string): Promise<PromptBlockDTO>;
957
+ list(presetId: string, userId?: string): Promise<PromptBlockSnapshotDTO[]>;
958
+ get(presetId: string, blockId: string, userId?: string): Promise<PromptBlockSnapshotDTO | null>;
959
+ create(presetId: string, input: PromptBlockCreateDTO, options?: { index?: number; userId?: string }): Promise<PromptBlockSnapshotDTO>;
960
+ update(presetId: string, blockId: string, input: PromptBlockUpdateDTO, userId?: string): Promise<PromptBlockSnapshotDTO>;
960
961
  delete(presetId: string, blockId: string, userId?: string): Promise<boolean>;
961
962
  };
962
963
  categories: {
@@ -1356,6 +1357,7 @@ export interface SpindleAPI {
1356
1357
  * Host contract versions for feature detection, keyed by contract name.
1357
1358
  * `preAssemblyGenerationContext >= 1`: generation contexts carry
1358
1359
  * `dryRun`/`userId` and `cancelGeneration` is honored.
1360
+ * `worldInfoActivationCapture >= 1`: world info activation capture is supported.
1359
1361
  */
1360
1362
  contracts?: Readonly<Record<string, number>>;
1361
1363
 
@@ -1404,11 +1406,14 @@ export interface SpindleAPI {
1404
1406
  * Multiple handlers chain in priority order and a later handler sees the
1405
1407
  * prior handlers' votes applied — useful for cross-entry injection
1406
1408
  * patterns where one entry merges into another and then disables itself.
1409
+ * Captured IDs are activated against the pre-vote entry view and delivered
1410
+ * only to the requesting extension as `capturedWorldInfo`; `[]` is an
1411
+ * authoritative empty result and `undefined` means no capture was requested.
1407
1412
  *
1408
1413
  * Returning `void` passes the activation set through unchanged. Per-handler
1409
1414
  * 10s timeout; errors are logged and the chain continues.
1410
1415
  *
1411
- * @param handler Returns the disabled / enabled / forced / mutated lists, or `void`.
1416
+ * @param handler Returns the disabled / enabled / forced / mutated / captured lists, or `void`.
1412
1417
  * @param priority Lower values run first. Default `100`.
1413
1418
  *
1414
1419
  * @example
@@ -1683,16 +1688,13 @@ export interface SpindleAPI {
1683
1688
  * }
1684
1689
  * ```
1685
1690
  */
1686
- open(options?: {
1687
- title?: string;
1688
- value?: string;
1689
- placeholder?: string;
1690
- /** For operator-scoped extensions only. */
1691
- userId?: string;
1692
- }): Promise<{
1693
- text: string;
1694
- cancelled: boolean;
1695
- }>;
1691
+ open(options?: SpindleTextEditorOptions): Promise<SpindleTextEditorResult>;
1692
+ /**
1693
+ * Cancel an editor opened with the matching `editorRequestId`.
1694
+ *
1695
+ * Unknown or already-settled identities are accepted as no-ops.
1696
+ */
1697
+ close(editorRequestId: string, userId?: string): Promise<void>;
1696
1698
  };
1697
1699
 
1698
1700
  /**
@@ -1,5 +1,6 @@
1
1
  import type {
2
2
  BoundAssembleRequestDTO,
3
+ PromptBlockSnapshotDTO,
3
4
  BoundAssemblyFailureDTO,
4
5
  BoundAssemblyOutcomeDTO,
5
6
  BoundAssemblySuccessDTO,
@@ -50,7 +51,37 @@ const messages: LlmMessageDTO[] = [
50
51
  },
51
52
  ];
52
53
 
53
- const promptBlocks = [] as BoundAssembleRequestDTO["blocks"];
54
+ const boundPromptSnapshot: PromptBlockSnapshotDTO = {
55
+ id: "bound-block",
56
+ name: "Bound dialogue",
57
+ content: "{{dialogue}}",
58
+ role: "system",
59
+ enabled: true,
60
+ position: "pre_history",
61
+ depth: 0,
62
+ marker: null,
63
+ isLocked: false,
64
+ color: null,
65
+ injectionTrigger: [],
66
+ group: null,
67
+ placementBinding: {
68
+ variableId: "layout",
69
+ options: {
70
+ standard: {
71
+ role: "assistant_append",
72
+ position: "in_history",
73
+ depth: 2,
74
+ },
75
+ },
76
+ },
77
+ sealed: true,
78
+ sealedKey: "dialogue.frame",
79
+ sealedSource: "lumihub",
80
+ sealedOriginPresetId: "lumihub-preset",
81
+ sealedOriginVersion: "v3",
82
+ sealedSha256: "sha256:dialogue-frame",
83
+ };
84
+ const promptBlocks: BoundAssembleRequestDTO["blocks"] = [boundPromptSnapshot];
54
85
  const boundRequest: BoundAssembleRequestDTO = {
55
86
  blocks: promptBlocks,
56
87
  promptVariableValues: {},
@@ -16,9 +16,12 @@ test("host compatibility constants are canonical and immutable", () => {
16
16
  "preset-extension-data-v1": 1,
17
17
  "preset-editor-v1": 1,
18
18
  "loom-block-editor-v1": 1,
19
+ "loom-block-management-v1": 1,
19
20
  "generation-assembly-v1": 1,
20
21
  "interceptor-context-v1": 1,
21
22
  "interceptor-final-response-v1": 1,
23
+ "connection-dispatch-resolution-v1": 1,
24
+ "text-editor-close-v1": 1,
22
25
  });
23
26
  expect(Object.isFrozen(SPINDLE_HOST_CAPABILITIES)).toBe(true);
24
27
  });
@@ -107,6 +107,24 @@ spindle.host.capabilities["interceptor-final-response-v1"] = 2;
107
107
  // @ts-expect-error descriptor scalar fields are readonly
108
108
  spindle.host.lumiverseVersion = "2.0.0";
109
109
  void backendHost;
110
+ const editorRequestId = "550e8400-e29b-41d4-a716-446655440001";
111
+ const editorResult = spindle.textEditor.open({ editorRequestId, value: "Review me" });
112
+ const editorClose = spindle.textEditor.close(editorRequestId);
113
+ const editorOpenMessage: WorkerToHost = {
114
+ type: "text_editor_open",
115
+ requestId: "transport-open",
116
+ editorRequestId,
117
+ value: "Review me",
118
+ };
119
+ const editorCloseMessage: WorkerToHost = {
120
+ type: "text_editor_close",
121
+ requestId: "transport-close",
122
+ editorRequestId,
123
+ };
124
+ void editorResult;
125
+ void editorClose;
126
+ void editorOpenMessage;
127
+ void editorCloseMessage;
110
128
 
111
129
  declare const ctx: SpindleFrontendContext;
112
130
  const frontendHost: SpindleHostDescriptorV1 = ctx.host;
@@ -1,4 +1,10 @@
1
1
  import type {
2
+ PromptBlockDTO,
3
+ PromptBlockPlacementBindingDTO,
4
+ PromptBlockPlacementDTO,
5
+ PromptBlockSnapshotDTO,
6
+ PromptBlockCreateDTO,
7
+ SpindleAPI,
2
8
  SpindleComponentTarget,
3
9
  SpindleComponentsHelper,
4
10
  SpindleLoomBlockEditorHandle,
@@ -37,3 +43,189 @@ export function compileLoomBlockEditorContract(
37
43
  void updated;
38
44
  return refreshed;
39
45
  }
46
+
47
+ /** Package-root consumer fixture for host-returned preset block snapshots. */
48
+ export async function compilePresetSnapshotContract(api: SpindleAPI): Promise<void> {
49
+ const editableBlock: PromptBlockDTO = {
50
+ id: "block-1",
51
+ name: "Dialogue",
52
+ content: "{{dialogue}}",
53
+ role: "system",
54
+ enabled: true,
55
+ position: "pre_history",
56
+ depth: 0,
57
+ marker: null,
58
+ isLocked: false,
59
+ color: null,
60
+ injectionTrigger: [],
61
+ group: null,
62
+ };
63
+ const placement: PromptBlockPlacementDTO = {
64
+ role: "assistant_append",
65
+ position: "in_history",
66
+ depth: 2,
67
+ };
68
+ const placementBinding: PromptBlockPlacementBindingDTO = {
69
+ variableId: "layout",
70
+ options: {
71
+ standard: placement,
72
+ },
73
+ };
74
+ const snapshot: PromptBlockSnapshotDTO = {
75
+ ...editableBlock,
76
+ placementBinding,
77
+ sealed: true,
78
+ sealedKey: "dialogue.frame",
79
+ sealedSource: "lumihub",
80
+ sealedOriginPresetId: "lumihub-preset",
81
+ sealedOriginVersion: "v3",
82
+ sealedSha256: "sha256:dialogue-frame",
83
+ };
84
+
85
+ const preset = await api.presets.get("preset-1");
86
+ if (preset) {
87
+ const fromPreset = preset.prompt_order[0];
88
+ if (fromPreset) {
89
+ if (fromPreset.placementBinding) {
90
+ void fromPreset.placementBinding.variableId;
91
+ }
92
+ if (fromPreset.sealedSource) {
93
+ void fromPreset.sealedSource.toUpperCase();
94
+ }
95
+ }
96
+ }
97
+ const fromList = await api.presets.blocks.list("preset-1");
98
+ const fromListBlock = fromList[0];
99
+ if (fromListBlock) {
100
+ if (fromListBlock.placementBinding) {
101
+ void fromListBlock.placementBinding.variableId;
102
+ }
103
+ if (fromListBlock.sealedSource) {
104
+ void fromListBlock.sealedSource.toUpperCase();
105
+ }
106
+ }
107
+ const fromGet = await api.presets.blocks.get("preset-1", "block-1");
108
+ if (fromGet) {
109
+ if (fromGet.placementBinding) {
110
+ void fromGet.placementBinding.variableId;
111
+ }
112
+ if (fromGet.sealedSource) {
113
+ void fromGet.sealedSource.toUpperCase();
114
+ }
115
+ }
116
+ const fromCreate = await api.presets.blocks.create("preset-1", editableBlock);
117
+ if (fromCreate.placementBinding) {
118
+ void fromCreate.placementBinding.variableId;
119
+ }
120
+ if (fromCreate.sealedSource) {
121
+ void fromCreate.sealedSource.toUpperCase();
122
+ }
123
+ const fromUpdate = await api.presets.blocks.update("preset-1", "block-1", {
124
+ name: "Updated dialogue",
125
+ });
126
+ if (fromUpdate.placementBinding) {
127
+ void fromUpdate.placementBinding.variableId;
128
+ }
129
+ if (fromUpdate.sealedSource) {
130
+ void fromUpdate.sealedSource.toUpperCase();
131
+ }
132
+ const groups = await api.presets.categories.list("preset-1");
133
+ const category = groups[0]?.categoryBlock;
134
+ if (category) {
135
+ if (category.placementBinding) {
136
+ void category.placementBinding.variableId;
137
+ }
138
+ if (category.sealedSource) {
139
+ void category.sealedSource.toUpperCase();
140
+ }
141
+ }
142
+ const child = groups[0]?.children[0];
143
+ if (child) {
144
+ if (child.placementBinding) {
145
+ void child.placementBinding.variableId;
146
+ }
147
+ if (child.sealedSource) {
148
+ void child.sealedSource.toUpperCase();
149
+ }
150
+ }
151
+
152
+ const forbiddenBlockPlacement: PromptBlockDTO = {
153
+ ...editableBlock,
154
+ // @ts-expect-error Host placement is snapshot-only.
155
+ placementBinding,
156
+ };
157
+ const forbiddenBlockProvenance: PromptBlockDTO = {
158
+ ...editableBlock,
159
+ // @ts-expect-error Host seal state is snapshot-only.
160
+ sealed: true,
161
+ };
162
+ const forbiddenCreatePlacement: PromptBlockCreateDTO = {
163
+ name: "forbidden create",
164
+ // @ts-expect-error Host placement is snapshot-only.
165
+ placementBinding,
166
+ };
167
+ const forbiddenCreateProvenance: PromptBlockCreateDTO = {
168
+ name: "forbidden create",
169
+ // @ts-expect-error Host seal state is snapshot-only.
170
+ sealed: true,
171
+ };
172
+ const forbiddenEditorPlacement: SpindleLoomBlockEditorValue = {
173
+ blocks: [{
174
+ ...editableBlock,
175
+ // @ts-expect-error Host placement is snapshot-only.
176
+ placementBinding,
177
+ }],
178
+ promptVariableValues: {},
179
+ };
180
+ const forbiddenEditorProvenance: SpindleLoomBlockEditorValue = {
181
+ blocks: [{
182
+ ...editableBlock,
183
+ // @ts-expect-error Host seal state is snapshot-only.
184
+ sealed: true,
185
+ }],
186
+ promptVariableValues: {},
187
+ };
188
+
189
+ // @ts-expect-error Read snapshots cannot cross the editable PromptBlockDTO boundary.
190
+ const mutableBlockFromSnapshot: PromptBlockDTO = fromCreate;
191
+ // @ts-expect-error Read snapshots cannot be supplied to block creation.
192
+ await api.presets.blocks.create("preset-1", fromCreate);
193
+ // @ts-expect-error Read snapshots cannot be supplied to block updates.
194
+ await api.presets.blocks.update("preset-1", "block-1", fromCreate);
195
+ const presetCreateFromSnapshot = {
196
+ name: "forbidden preset",
197
+ provider: "test",
198
+ prompt_order: [fromCreate],
199
+ };
200
+ // @ts-expect-error Read snapshots cannot be supplied to preset creation.
201
+ await api.presets.create(presetCreateFromSnapshot);
202
+ const presetUpdateFromSnapshot = {
203
+ expected_cache_revision: 0,
204
+ prompt_order: [fromCreate],
205
+ };
206
+ // @ts-expect-error Read snapshots cannot be supplied to preset updates.
207
+ await api.presets.update("preset-1", presetUpdateFromSnapshot);
208
+ const editorValueFromSnapshot: SpindleLoomBlockEditorValue = {
209
+ // @ts-expect-error Read snapshots cannot cross the Loom editor boundary.
210
+ blocks: [fromCreate],
211
+ promptVariableValues: {},
212
+ };
213
+
214
+ void snapshot;
215
+ void fromList;
216
+ void fromGet;
217
+ void fromCreate;
218
+ void fromUpdate;
219
+ void category;
220
+ void child;
221
+ void forbiddenBlockPlacement;
222
+ void forbiddenBlockProvenance;
223
+ void forbiddenCreatePlacement;
224
+ void forbiddenCreateProvenance;
225
+ void forbiddenEditorPlacement;
226
+ void forbiddenEditorProvenance;
227
+ void mutableBlockFromSnapshot;
228
+ void presetCreateFromSnapshot;
229
+ void presetUpdateFromSnapshot;
230
+ void editorValueFromSnapshot;
231
+ }