lumiverse-spindle-types 0.6.6 → 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 +1 -1
- package/src/api.ts +122 -7
- package/src/components.ts +2 -0
- package/src/dom.ts +4 -2
- package/src/host.ts +3 -0
- package/src/index.ts +19 -7
- package/src/spindle-api.ts +30 -16
- package/test/bound-generation-consumer.ts +32 -1
- package/test/final-response-and-host-compatibility.test.ts +3 -0
- package/test/host-runtime-contract-consumer.ts +18 -0
- package/test/image-gen-stream-consumer.ts +44 -0
- package/test/loom-block-editor-consumer.ts +192 -0
- package/tsconfig.consumer.json +1 -1
package/package.json
CHANGED
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
|
}
|
|
@@ -727,6 +739,11 @@ export interface ImageGenProviderDTO {
|
|
|
727
739
|
modelListStyle: "static" | "dynamic" | "google";
|
|
728
740
|
staticModels?: Array<{ id: string; label: string }>;
|
|
729
741
|
defaultUrl: string;
|
|
742
|
+
/** Present only when the provider supports Lumiverse's WebSocket preview/status stream. */
|
|
743
|
+
websocketPreviewStreaming?: {
|
|
744
|
+
previews: true;
|
|
745
|
+
status: true;
|
|
746
|
+
};
|
|
730
747
|
};
|
|
731
748
|
}
|
|
732
749
|
|
|
@@ -761,6 +778,47 @@ export interface ImageGenResultDTO {
|
|
|
761
778
|
imageUrl?: string;
|
|
762
779
|
}
|
|
763
780
|
|
|
781
|
+
/** Input for {@link SpindleAPI.imageGen.generateStream}. */
|
|
782
|
+
export interface ImageGenStreamRequestDTO extends ImageGenRequestDTO {
|
|
783
|
+
/** Abort the upstream generation and close its WebSocket stream. */
|
|
784
|
+
signal?: AbortSignal;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/** A progress/status update received from the provider WebSocket. */
|
|
788
|
+
export interface ImageGenStreamStatusDTO {
|
|
789
|
+
type: "status";
|
|
790
|
+
/** Current step when the provider reports numerical progress. */
|
|
791
|
+
step?: number;
|
|
792
|
+
/** Total steps when the provider reports numerical progress. */
|
|
793
|
+
totalSteps?: number;
|
|
794
|
+
/** Current workflow node, when supplied by the provider. */
|
|
795
|
+
nodeId?: string;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
/** A preview image received from the provider WebSocket. */
|
|
799
|
+
export interface ImageGenStreamPreviewDTO {
|
|
800
|
+
type: "preview";
|
|
801
|
+
/** Preview image as a base64 data URL. */
|
|
802
|
+
imageDataUrl: string;
|
|
803
|
+
/** Status reported with this preview, when available. */
|
|
804
|
+
step?: number;
|
|
805
|
+
totalSteps?: number;
|
|
806
|
+
nodeId?: string;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/** Terminal success event for an image generation stream. */
|
|
810
|
+
export interface ImageGenStreamDoneDTO {
|
|
811
|
+
type: "done";
|
|
812
|
+
/** Final image and its persisted asset identifiers. */
|
|
813
|
+
result: ImageGenResultDTO;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/** Events yielded by {@link SpindleAPI.imageGen.generateStream}. */
|
|
817
|
+
export type ImageGenStreamEventDTO =
|
|
818
|
+
| ImageGenStreamStatusDTO
|
|
819
|
+
| ImageGenStreamPreviewDTO
|
|
820
|
+
| ImageGenStreamDoneDTO;
|
|
821
|
+
|
|
764
822
|
// ─── Image DTOs ─────────────────────────────────────────────────────────
|
|
765
823
|
|
|
766
824
|
export type ImageSpecificityDTO = "full" | "sm" | "lg";
|
|
@@ -1222,7 +1280,20 @@ export type PromptBlockRoleDTO = "system" | "user" | "assistant" | "user_append"
|
|
|
1222
1280
|
export type PromptBlockPositionDTO = "pre_history" | "post_history" | "in_history";
|
|
1223
1281
|
export type PromptBlockCategoryModeDTO = "radio" | "checkbox" | null;
|
|
1224
1282
|
|
|
1225
|
-
|
|
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 {
|
|
1226
1297
|
id: string;
|
|
1227
1298
|
name: string;
|
|
1228
1299
|
content: string;
|
|
@@ -1243,11 +1314,45 @@ export interface PromptBlockDTO {
|
|
|
1243
1314
|
variables?: PromptVariableDefDTO[];
|
|
1244
1315
|
}
|
|
1245
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
|
+
|
|
1246
1351
|
export interface PromptBlockCategoryGroupDTO {
|
|
1247
1352
|
/** The category header block, or null for uncategorized leading blocks. */
|
|
1248
|
-
categoryBlock:
|
|
1353
|
+
categoryBlock: PromptBlockSnapshotDTO | null;
|
|
1249
1354
|
/** Non-category blocks after the header until the next category header. */
|
|
1250
|
-
children:
|
|
1355
|
+
children: PromptBlockSnapshotDTO[];
|
|
1251
1356
|
}
|
|
1252
1357
|
|
|
1253
1358
|
export interface HostResponseErrorDTO {
|
|
@@ -1264,7 +1369,7 @@ export interface UserPresetDTO {
|
|
|
1264
1369
|
provider: string;
|
|
1265
1370
|
engine: string;
|
|
1266
1371
|
parameters: Record<string, unknown>;
|
|
1267
|
-
prompt_order:
|
|
1372
|
+
prompt_order: PromptBlockSnapshotDTO[];
|
|
1268
1373
|
prompts: Record<string, unknown>;
|
|
1269
1374
|
metadata: Record<string, unknown>;
|
|
1270
1375
|
cache_revision: number;
|
|
@@ -1552,6 +1657,7 @@ export interface WorldInfoInterceptorResultDTO {
|
|
|
1552
1657
|
readonly enabled?: readonly string[];
|
|
1553
1658
|
readonly forced?: readonly string[];
|
|
1554
1659
|
readonly mutated?: readonly WorldInfoInterceptorMutationDTO[];
|
|
1660
|
+
readonly captured?: readonly string[];
|
|
1555
1661
|
}
|
|
1556
1662
|
|
|
1557
1663
|
// ─── Databank DTOs ───────────────────────────────────────────────────────
|
|
@@ -1913,7 +2019,7 @@ export interface BoundPrefillAttachmentDTO {
|
|
|
1913
2019
|
}
|
|
1914
2020
|
|
|
1915
2021
|
export interface BoundAssembleRequestDTO {
|
|
1916
|
-
blocks:
|
|
2022
|
+
blocks: PromptBlockSnapshotDTO[];
|
|
1917
2023
|
promptVariableValues?: PromptVariableValuesDTO;
|
|
1918
2024
|
dispatch: GenerationDispatchSourceDTO;
|
|
1919
2025
|
deadlineAt: number;
|
|
@@ -3362,7 +3468,8 @@ export type WorkerToHost =
|
|
|
3362
3468
|
| { type: "user_is_visible"; requestId: string; userId?: string }
|
|
3363
3469
|
| { type: "user_get_role"; requestId: string; userId?: string }
|
|
3364
3470
|
// ─── Text Editor (free tier) ───────────────────────────────────────
|
|
3365
|
-
| { 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 }
|
|
3366
3473
|
// ─── Modal (free tier) ────────────────────────────────────────────
|
|
3367
3474
|
| { type: "modal_open"; requestId: string; modalRequestId?: string; title: string; items: SpindleModalItemDTO[]; width?: number; maxHeight?: number; persistent?: boolean; userId?: string }
|
|
3368
3475
|
| { type: "modal_close"; requestId: string; openRequestId: string; userId?: string }
|
|
@@ -3384,6 +3491,12 @@ export type WorkerToHost =
|
|
|
3384
3491
|
| { type: "macros_resolve"; requestId: string; template: string; chatId?: string; characterId?: string; userId?: string; commit?: boolean }
|
|
3385
3492
|
// ─── Image Generation (gated: "image_gen") ──────────────────────────
|
|
3386
3493
|
| { type: "image_gen_generate"; requestId: string; input: ImageGenRequestDTO }
|
|
3494
|
+
/**
|
|
3495
|
+
* Start a WebSocket-backed image stream. Only providers that advertise
|
|
3496
|
+
* `websocketPreviewStreaming` accept this request.
|
|
3497
|
+
*/
|
|
3498
|
+
| { type: "image_gen_generate_stream"; requestId: string; input: Omit<ImageGenStreamRequestDTO, "signal"> }
|
|
3499
|
+
| { type: "image_gen_cancel_stream"; requestId: string }
|
|
3387
3500
|
| { type: "image_gen_providers"; requestId: string; userId?: string }
|
|
3388
3501
|
| { type: "image_gen_connections_list"; requestId: string; userId?: string }
|
|
3389
3502
|
| { type: "image_gen_connections_get"; requestId: string; connectionId: string; userId?: string }
|
|
@@ -3622,4 +3735,6 @@ export type HostToWorker =
|
|
|
3622
3735
|
* `request_generation_stream`. Mutually exclusive with the `done`
|
|
3623
3736
|
* chunk in `generation_stream_chunk`. Aborts surface here too.
|
|
3624
3737
|
*/
|
|
3625
|
-
| { type: "generation_stream_error"; requestId: string; error: string }
|
|
3738
|
+
| { type: "generation_stream_error"; requestId: string; error: string }
|
|
3739
|
+
| { type: "image_gen_stream_chunk"; requestId: string; event: ImageGenStreamEventDTO }
|
|
3740
|
+
| { type: "image_gen_stream_error"; requestId: string; error: 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
|
-
/**
|
|
551
|
-
|
|
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,
|
|
@@ -155,9 +159,14 @@ export type {
|
|
|
155
159
|
ImageGenConnectionDTO,
|
|
156
160
|
ImageGenParameterSchemaDTO,
|
|
157
161
|
ImageGenProviderDTO,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
162
|
+
ImageGenRequestDTO,
|
|
163
|
+
ImageGenResultDTO,
|
|
164
|
+
ImageGenStreamRequestDTO,
|
|
165
|
+
ImageGenStreamStatusDTO,
|
|
166
|
+
ImageGenStreamPreviewDTO,
|
|
167
|
+
ImageGenStreamDoneDTO,
|
|
168
|
+
ImageGenStreamEventDTO,
|
|
169
|
+
ImageGetOptionsDTO,
|
|
161
170
|
ImageDTO,
|
|
162
171
|
ImageListOptionsDTO,
|
|
163
172
|
ImageSpecificityDTO,
|
|
@@ -241,13 +250,16 @@ export { PERMISSION_DENIED_PREFIX } from "./api";
|
|
|
241
250
|
export type { ToolRegistration, JSONSchema } from "./tools";
|
|
242
251
|
|
|
243
252
|
export type {
|
|
253
|
+
SpindleMessageElement,
|
|
254
|
+
SpindleTextEditorOptions,
|
|
255
|
+
SpindleTextEditorResult,
|
|
244
256
|
SpindleDOMHelper,
|
|
245
257
|
SpindleMountPoint,
|
|
246
258
|
SpindleUploadFile,
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
259
|
+
SpindleMessageTagIntercept,
|
|
260
|
+
SpindleMessageTagInterceptorOptions,
|
|
261
|
+
SpindleMessageWidgetOptions,
|
|
262
|
+
PermissionRequestOptions,
|
|
251
263
|
SpindleFrontendContext,
|
|
252
264
|
SpindleFrontendModule,
|
|
253
265
|
SpindleFrontendTeardown,
|
package/src/spindle-api.ts
CHANGED
|
@@ -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
|
-
|
|
34
|
+
PromptBlockSnapshotDTO,
|
|
34
35
|
PromptBlockCreateDTO,
|
|
35
36
|
PromptBlockUpdateDTO,
|
|
36
37
|
PromptBlockCategoryGroupDTO,
|
|
@@ -70,6 +71,8 @@ import type {
|
|
|
70
71
|
ChatMemoryResultDTO,
|
|
71
72
|
ImageGenRequestDTO,
|
|
72
73
|
ImageGenResultDTO,
|
|
74
|
+
ImageGenStreamRequestDTO,
|
|
75
|
+
ImageGenStreamEventDTO,
|
|
73
76
|
ImageGenConnectionDTO,
|
|
74
77
|
ImageGenProviderDTO,
|
|
75
78
|
ImageGetOptionsDTO,
|
|
@@ -800,6 +803,16 @@ export interface SpindleAPI {
|
|
|
800
803
|
* Returns the image as a base64 data URL.
|
|
801
804
|
*/
|
|
802
805
|
generate(input: ImageGenRequestDTO): Promise<ImageGenResultDTO>;
|
|
806
|
+
/**
|
|
807
|
+
* Generate through a provider that supports WebSocket preview images and
|
|
808
|
+
* status updates (currently SwarmUI and ComfyUI). The terminal `done`
|
|
809
|
+
* event carries the same result as {@link generate}. Breaking from the
|
|
810
|
+
* iterator or aborting `input.signal` cancels the upstream generation.
|
|
811
|
+
*
|
|
812
|
+
* Throws if the selected provider does not advertise
|
|
813
|
+
* `websocketPreviewStreaming` in {@link getProviders}.
|
|
814
|
+
*/
|
|
815
|
+
generateStream(input: ImageGenStreamRequestDTO): AsyncGenerator<ImageGenStreamEventDTO, void, void>;
|
|
803
816
|
/**
|
|
804
817
|
* List available image generation providers with their capability schemas.
|
|
805
818
|
* The schemas describe supported parameters, models, and features.
|
|
@@ -941,10 +954,10 @@ export interface SpindleAPI {
|
|
|
941
954
|
update(presetId: string, input: UserPresetUpdateDTO, userId?: string): Promise<UserPresetDTO>;
|
|
942
955
|
delete(presetId: string, userId?: string): Promise<boolean>;
|
|
943
956
|
blocks: {
|
|
944
|
-
list(presetId: string, userId?: string): Promise<
|
|
945
|
-
get(presetId: string, blockId: string, userId?: string): Promise<
|
|
946
|
-
create(presetId: string, input: PromptBlockCreateDTO, options?: { index?: number; userId?: string }): Promise<
|
|
947
|
-
update(presetId: string, blockId: string, input: PromptBlockUpdateDTO, userId?: string): Promise<
|
|
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>;
|
|
948
961
|
delete(presetId: string, blockId: string, userId?: string): Promise<boolean>;
|
|
949
962
|
};
|
|
950
963
|
categories: {
|
|
@@ -1344,6 +1357,7 @@ export interface SpindleAPI {
|
|
|
1344
1357
|
* Host contract versions for feature detection, keyed by contract name.
|
|
1345
1358
|
* `preAssemblyGenerationContext >= 1`: generation contexts carry
|
|
1346
1359
|
* `dryRun`/`userId` and `cancelGeneration` is honored.
|
|
1360
|
+
* `worldInfoActivationCapture >= 1`: world info activation capture is supported.
|
|
1347
1361
|
*/
|
|
1348
1362
|
contracts?: Readonly<Record<string, number>>;
|
|
1349
1363
|
|
|
@@ -1392,11 +1406,14 @@ export interface SpindleAPI {
|
|
|
1392
1406
|
* Multiple handlers chain in priority order and a later handler sees the
|
|
1393
1407
|
* prior handlers' votes applied — useful for cross-entry injection
|
|
1394
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.
|
|
1395
1412
|
*
|
|
1396
1413
|
* Returning `void` passes the activation set through unchanged. Per-handler
|
|
1397
1414
|
* 10s timeout; errors are logged and the chain continues.
|
|
1398
1415
|
*
|
|
1399
|
-
* @param handler Returns the disabled / enabled / forced / mutated lists, or `void`.
|
|
1416
|
+
* @param handler Returns the disabled / enabled / forced / mutated / captured lists, or `void`.
|
|
1400
1417
|
* @param priority Lower values run first. Default `100`.
|
|
1401
1418
|
*
|
|
1402
1419
|
* @example
|
|
@@ -1671,16 +1688,13 @@ export interface SpindleAPI {
|
|
|
1671
1688
|
* }
|
|
1672
1689
|
* ```
|
|
1673
1690
|
*/
|
|
1674
|
-
open(options?:
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
text: string;
|
|
1682
|
-
cancelled: boolean;
|
|
1683
|
-
}>;
|
|
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>;
|
|
1684
1698
|
};
|
|
1685
1699
|
|
|
1686
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
|
|
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;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
HostToWorker,
|
|
3
|
+
ImageGenStreamEventDTO,
|
|
4
|
+
SpindleAPI,
|
|
5
|
+
WorkerToHost,
|
|
6
|
+
} from "lumiverse-spindle-types";
|
|
7
|
+
|
|
8
|
+
declare const spindle: SpindleAPI;
|
|
9
|
+
|
|
10
|
+
async function consumePreviews(): Promise<void> {
|
|
11
|
+
const stream = spindle.imageGen.generateStream({
|
|
12
|
+
connection_id: "swarm-connection",
|
|
13
|
+
prompt: "A quiet observatory under a starry sky",
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
for await (const event of stream) {
|
|
17
|
+
if (event.type === "preview") {
|
|
18
|
+
const preview: string = event.imageDataUrl;
|
|
19
|
+
void preview;
|
|
20
|
+
} else if (event.type === "status") {
|
|
21
|
+
const step: number | undefined = event.step;
|
|
22
|
+
void step;
|
|
23
|
+
} else {
|
|
24
|
+
const finalImage: string = event.result.imageDataUrl;
|
|
25
|
+
void finalImage;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const event: ImageGenStreamEventDTO = { type: "status", step: 2, totalSteps: 20 };
|
|
31
|
+
const startStream: WorkerToHost = {
|
|
32
|
+
type: "image_gen_generate_stream",
|
|
33
|
+
requestId: "request-1",
|
|
34
|
+
input: { prompt: "A quiet observatory under a starry sky" },
|
|
35
|
+
};
|
|
36
|
+
const preview: HostToWorker = {
|
|
37
|
+
type: "image_gen_stream_chunk",
|
|
38
|
+
requestId: "request-1",
|
|
39
|
+
event: { type: "preview", imageDataUrl: "data:image/png;base64,preview" },
|
|
40
|
+
};
|
|
41
|
+
void event;
|
|
42
|
+
void startStream;
|
|
43
|
+
void preview;
|
|
44
|
+
void consumePreviews;
|
|
@@ -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
|
+
}
|
package/tsconfig.consumer.json
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
"outDir": "./.consumer-dist",
|
|
6
6
|
"declaration": false
|
|
7
7
|
},
|
|
8
|
-
"include": ["test/loom-block-editor-consumer.ts", "test/bound-generation-consumer.ts", "test/interceptor-consumer.ts", "test/host-runtime-contract-consumer.ts"]
|
|
8
|
+
"include": ["test/loom-block-editor-consumer.ts", "test/bound-generation-consumer.ts", "test/interceptor-consumer.ts", "test/host-runtime-contract-consumer.ts", "test/image-gen-stream-consumer.ts"]
|
|
9
9
|
}
|