lumiverse-spindle-types 0.6.8 → 0.6.10
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 +118 -10
- package/src/components.ts +2 -0
- package/src/dom.ts +4 -2
- package/src/host.ts +3 -0
- package/src/index.ts +15 -4
- package/src/spindle-api.ts +23 -17
- 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/interceptor-consumer.ts +18 -0
- package/test/loom-block-editor-consumer.ts +192 -0
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
|
}
|
|
@@ -240,11 +252,25 @@ export type MacroInterceptorPhase =
|
|
|
240
252
|
* them has no effect on the real environment. Persist state via
|
|
241
253
|
* `spindle.variables.*` helpers instead.
|
|
242
254
|
*/
|
|
255
|
+
export type MacroInterceptorCharacterEnvDTO =
|
|
256
|
+
Readonly<Record<string, unknown>> & {
|
|
257
|
+
/** Selected greeting stored in the current chat, including edits. */
|
|
258
|
+
readonly firstMessage: string;
|
|
259
|
+
/** Card-defined alternatives, excluding the default greeting. */
|
|
260
|
+
readonly alternateGreetings: readonly string[];
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
export type MacroInterceptorChatEnvDTO =
|
|
264
|
+
Readonly<Record<string, unknown>> & {
|
|
265
|
+
/** Selected index in [default greeting, ...alternate greetings]. */
|
|
266
|
+
readonly greetingIndex: number;
|
|
267
|
+
};
|
|
268
|
+
|
|
243
269
|
export interface MacroInterceptorEnvDTO {
|
|
244
270
|
readonly commit: boolean;
|
|
245
271
|
readonly names: Record<string, string>;
|
|
246
|
-
readonly character:
|
|
247
|
-
readonly chat:
|
|
272
|
+
readonly character: MacroInterceptorCharacterEnvDTO;
|
|
273
|
+
readonly chat: MacroInterceptorChatEnvDTO;
|
|
248
274
|
readonly system: Record<string, unknown>;
|
|
249
275
|
readonly variables: {
|
|
250
276
|
readonly local: Record<string, string>;
|
|
@@ -325,6 +351,8 @@ export interface MessageContentProcessorCtxDTO {
|
|
|
325
351
|
/** Undefined for `"create"` origins (the row doesn't exist yet). */
|
|
326
352
|
messageId?: string;
|
|
327
353
|
content: string;
|
|
354
|
+
/** True when the message was authored by the user. */
|
|
355
|
+
isUser: boolean;
|
|
328
356
|
extra?: Record<string, unknown>;
|
|
329
357
|
origin: MessageContentProcessorOrigin;
|
|
330
358
|
/** Set for `"swipe_update"` only — the zero-based index of the swipe being rewritten. */
|
|
@@ -1268,7 +1296,20 @@ export type PromptBlockRoleDTO = "system" | "user" | "assistant" | "user_append"
|
|
|
1268
1296
|
export type PromptBlockPositionDTO = "pre_history" | "post_history" | "in_history";
|
|
1269
1297
|
export type PromptBlockCategoryModeDTO = "radio" | "checkbox" | null;
|
|
1270
1298
|
|
|
1271
|
-
|
|
1299
|
+
/** A native Loom placement profile selected for a prompt block. */
|
|
1300
|
+
export interface PromptBlockPlacementDTO {
|
|
1301
|
+
role: PromptBlockRoleDTO;
|
|
1302
|
+
position: PromptBlockPositionDTO;
|
|
1303
|
+
depth: number;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
/** A select variable's mapping from option ids to native Loom placement profiles. */
|
|
1307
|
+
export interface PromptBlockPlacementBindingDTO {
|
|
1308
|
+
variableId: string;
|
|
1309
|
+
options: Record<string, PromptBlockPlacementDTO>;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
interface PromptBlockCoreDTO {
|
|
1272
1313
|
id: string;
|
|
1273
1314
|
name: string;
|
|
1274
1315
|
content: string;
|
|
@@ -1289,11 +1330,45 @@ export interface PromptBlockDTO {
|
|
|
1289
1330
|
variables?: PromptVariableDefDTO[];
|
|
1290
1331
|
}
|
|
1291
1332
|
|
|
1333
|
+
/**
|
|
1334
|
+
* Editable/public prompt-block value.
|
|
1335
|
+
*
|
|
1336
|
+
* Host placement and sealed/provenance fields are snapshot-only and therefore
|
|
1337
|
+
* cannot be supplied through mutable block or editor inputs.
|
|
1338
|
+
*/
|
|
1339
|
+
export interface PromptBlockDTO extends PromptBlockCoreDTO {
|
|
1340
|
+
placementBinding?: never;
|
|
1341
|
+
sealed?: never;
|
|
1342
|
+
sealedKey?: never;
|
|
1343
|
+
sealedSource?: never;
|
|
1344
|
+
sealedOriginPresetId?: never;
|
|
1345
|
+
sealedOriginVersion?: never;
|
|
1346
|
+
sealedSha256?: never;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
/**
|
|
1350
|
+
* Host-returned snapshot of a prompt block.
|
|
1351
|
+
*
|
|
1352
|
+
* The placement binding and sealed/provenance fields are native host snapshot
|
|
1353
|
+
* semantics. They are intentionally absent from the editable/public
|
|
1354
|
+
* `PromptBlockDTO` and must not be supplied through mutable block or editor
|
|
1355
|
+
* inputs.
|
|
1356
|
+
*/
|
|
1357
|
+
export interface PromptBlockSnapshotDTO extends PromptBlockCoreDTO {
|
|
1358
|
+
placementBinding?: PromptBlockPlacementBindingDTO;
|
|
1359
|
+
sealed?: boolean;
|
|
1360
|
+
sealedKey?: string;
|
|
1361
|
+
sealedSource?: "lumihub" | string;
|
|
1362
|
+
sealedOriginPresetId?: string;
|
|
1363
|
+
sealedOriginVersion?: string | null;
|
|
1364
|
+
sealedSha256?: string;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1292
1367
|
export interface PromptBlockCategoryGroupDTO {
|
|
1293
1368
|
/** The category header block, or null for uncategorized leading blocks. */
|
|
1294
|
-
categoryBlock:
|
|
1369
|
+
categoryBlock: PromptBlockSnapshotDTO | null;
|
|
1295
1370
|
/** Non-category blocks after the header until the next category header. */
|
|
1296
|
-
children:
|
|
1371
|
+
children: PromptBlockSnapshotDTO[];
|
|
1297
1372
|
}
|
|
1298
1373
|
|
|
1299
1374
|
export interface HostResponseErrorDTO {
|
|
@@ -1310,7 +1385,7 @@ export interface UserPresetDTO {
|
|
|
1310
1385
|
provider: string;
|
|
1311
1386
|
engine: string;
|
|
1312
1387
|
parameters: Record<string, unknown>;
|
|
1313
|
-
prompt_order:
|
|
1388
|
+
prompt_order: PromptBlockSnapshotDTO[];
|
|
1314
1389
|
prompts: Record<string, unknown>;
|
|
1315
1390
|
metadata: Record<string, unknown>;
|
|
1316
1391
|
cache_revision: number;
|
|
@@ -1383,6 +1458,8 @@ export interface WorldBookEntryDTO {
|
|
|
1383
1458
|
group_weight: number;
|
|
1384
1459
|
probability: number;
|
|
1385
1460
|
scan_depth: number | null;
|
|
1461
|
+
/** Exclude the synthetic character greeting from lexical activation scans. */
|
|
1462
|
+
exclude_greeting: boolean;
|
|
1386
1463
|
case_sensitive: boolean;
|
|
1387
1464
|
match_whole_words: boolean;
|
|
1388
1465
|
automation_id: string | null;
|
|
@@ -1419,6 +1496,8 @@ export interface WorldBookEntryCreateDTO {
|
|
|
1419
1496
|
group_weight?: number;
|
|
1420
1497
|
probability?: number;
|
|
1421
1498
|
scan_depth?: number;
|
|
1499
|
+
/** Exclude the synthetic character greeting from lexical activation scans. */
|
|
1500
|
+
exclude_greeting?: boolean;
|
|
1422
1501
|
case_sensitive?: boolean;
|
|
1423
1502
|
match_whole_words?: boolean;
|
|
1424
1503
|
automation_id?: string;
|
|
@@ -1541,6 +1620,8 @@ export interface WorldInfoInterceptorEntryDTO {
|
|
|
1541
1620
|
readonly prevent_recursion: boolean;
|
|
1542
1621
|
readonly exclude_recursion: boolean;
|
|
1543
1622
|
readonly delay_until_recursion: boolean;
|
|
1623
|
+
/** Exclude the synthetic character greeting from lexical activation scans. */
|
|
1624
|
+
readonly exclude_greeting: boolean;
|
|
1544
1625
|
readonly scan_depth: number | null;
|
|
1545
1626
|
readonly order_value: number;
|
|
1546
1627
|
/** Attachment scope that contributed the entry's book to this chat. */
|
|
@@ -1563,6 +1644,22 @@ export interface WorldInfoInterceptorMessageDTO {
|
|
|
1563
1644
|
readonly index_in_chat: number;
|
|
1564
1645
|
}
|
|
1565
1646
|
|
|
1647
|
+
/** Effective host settings for world-info activation. */
|
|
1648
|
+
export interface WorldInfoActivationSettingsDTO {
|
|
1649
|
+
/** Default entry scan depth, or null to scan all available messages. */
|
|
1650
|
+
readonly globalScanDepth: number | null;
|
|
1651
|
+
readonly maxRecursionPasses: number;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
/**
|
|
1655
|
+
* Restrictive, prompt-local changes to world info activation. Overrides from
|
|
1656
|
+
* multiple interceptors compose monotonically: `true` always wins.
|
|
1657
|
+
*/
|
|
1658
|
+
export interface WorldInfoActivationOverridesDTO {
|
|
1659
|
+
/** Set the effective recursion-pass limit to zero for this prompt. */
|
|
1660
|
+
readonly disableRecursion?: true;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1566
1663
|
/**
|
|
1567
1664
|
* Context passed to a `registerWorldInfoInterceptor` handler. Fires inside
|
|
1568
1665
|
* `assemblePrompt` immediately before `activateWorldInfo` runs, so any
|
|
@@ -1577,15 +1674,23 @@ export interface WorldInfoInterceptorCtxDTO {
|
|
|
1577
1674
|
readonly messages: readonly WorldInfoInterceptorMessageDTO[];
|
|
1578
1675
|
readonly chatTurn: number;
|
|
1579
1676
|
readonly chatMetadata: Readonly<Record<string, unknown>>;
|
|
1677
|
+
readonly activationSettings: WorldInfoActivationSettingsDTO;
|
|
1580
1678
|
}
|
|
1581
1679
|
|
|
1582
1680
|
/**
|
|
1583
|
-
* Per-entry content
|
|
1584
|
-
* handler.
|
|
1681
|
+
* Per-entry content overrides emitted by a `registerWorldInfoInterceptor`
|
|
1682
|
+
* handler. Both values are prompt-local and never persist to the world book.
|
|
1585
1683
|
*/
|
|
1586
1684
|
export interface WorldInfoInterceptorMutationDTO {
|
|
1587
1685
|
readonly id: string;
|
|
1686
|
+
/** Replaces the entry content used for final prompt insertion. */
|
|
1588
1687
|
readonly content?: string;
|
|
1688
|
+
/**
|
|
1689
|
+
* Alternate content used only for empty filtering, content deduplication,
|
|
1690
|
+
* token accounting, and activation caps. Final insertion still uses
|
|
1691
|
+
* `content` (or the stored entry content when `content` is omitted).
|
|
1692
|
+
*/
|
|
1693
|
+
readonly selectionContent?: string;
|
|
1589
1694
|
}
|
|
1590
1695
|
|
|
1591
1696
|
/**
|
|
@@ -1598,6 +1703,8 @@ export interface WorldInfoInterceptorResultDTO {
|
|
|
1598
1703
|
readonly enabled?: readonly string[];
|
|
1599
1704
|
readonly forced?: readonly string[];
|
|
1600
1705
|
readonly mutated?: readonly WorldInfoInterceptorMutationDTO[];
|
|
1706
|
+
readonly captured?: readonly string[];
|
|
1707
|
+
readonly activationOverrides?: WorldInfoActivationOverridesDTO;
|
|
1601
1708
|
}
|
|
1602
1709
|
|
|
1603
1710
|
// ─── Databank DTOs ───────────────────────────────────────────────────────
|
|
@@ -1959,7 +2066,7 @@ export interface BoundPrefillAttachmentDTO {
|
|
|
1959
2066
|
}
|
|
1960
2067
|
|
|
1961
2068
|
export interface BoundAssembleRequestDTO {
|
|
1962
|
-
blocks:
|
|
2069
|
+
blocks: PromptBlockSnapshotDTO[];
|
|
1963
2070
|
promptVariableValues?: PromptVariableValuesDTO;
|
|
1964
2071
|
dispatch: GenerationDispatchSourceDTO;
|
|
1965
2072
|
deadlineAt: number;
|
|
@@ -3408,7 +3515,8 @@ export type WorkerToHost =
|
|
|
3408
3515
|
| { type: "user_is_visible"; requestId: string; userId?: string }
|
|
3409
3516
|
| { type: "user_get_role"; requestId: string; userId?: string }
|
|
3410
3517
|
// ─── Text Editor (free tier) ───────────────────────────────────────
|
|
3411
|
-
| { type: "text_editor_open"; requestId: string; title?: string; value?: string; placeholder?: string; userId?: string }
|
|
3518
|
+
| { type: "text_editor_open"; requestId: string; editorRequestId?: string; title?: string; value?: string; placeholder?: string; userId?: string }
|
|
3519
|
+
| { type: "text_editor_close"; requestId: string; editorRequestId: string; userId?: string }
|
|
3412
3520
|
// ─── Modal (free tier) ────────────────────────────────────────────
|
|
3413
3521
|
| { type: "modal_open"; requestId: string; modalRequestId?: string; title: string; items: SpindleModalItemDTO[]; width?: number; maxHeight?: number; persistent?: boolean; userId?: string }
|
|
3414
3522
|
| { 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
|
-
/**
|
|
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,
|
|
@@ -109,6 +113,8 @@ export type {
|
|
|
109
113
|
RegexScriptActiveOptionsDTO,
|
|
110
114
|
WorldInfoInterceptorEntryDTO,
|
|
111
115
|
WorldInfoInterceptorMessageDTO,
|
|
116
|
+
WorldInfoActivationSettingsDTO,
|
|
117
|
+
WorldInfoActivationOverridesDTO,
|
|
112
118
|
WorldInfoInterceptorCtxDTO,
|
|
113
119
|
WorldInfoInterceptorMutationDTO,
|
|
114
120
|
WorldInfoInterceptorResultDTO,
|
|
@@ -225,6 +231,8 @@ export type {
|
|
|
225
231
|
SharedRpcRequestContextDTO,
|
|
226
232
|
SharedRpcEndpointPolicyDTO,
|
|
227
233
|
MacroInterceptorPhase,
|
|
234
|
+
MacroInterceptorCharacterEnvDTO,
|
|
235
|
+
MacroInterceptorChatEnvDTO,
|
|
228
236
|
MacroInterceptorEnvDTO,
|
|
229
237
|
MacroInterceptorCtxDTO,
|
|
230
238
|
MacroInterceptorResultDTO,
|
|
@@ -246,13 +254,16 @@ export { PERMISSION_DENIED_PREFIX } from "./api";
|
|
|
246
254
|
export type { ToolRegistration, JSONSchema } from "./tools";
|
|
247
255
|
|
|
248
256
|
export type {
|
|
257
|
+
SpindleMessageElement,
|
|
258
|
+
SpindleTextEditorOptions,
|
|
259
|
+
SpindleTextEditorResult,
|
|
249
260
|
SpindleDOMHelper,
|
|
250
261
|
SpindleMountPoint,
|
|
251
262
|
SpindleUploadFile,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
263
|
+
SpindleMessageTagIntercept,
|
|
264
|
+
SpindleMessageTagInterceptorOptions,
|
|
265
|
+
SpindleMessageWidgetOptions,
|
|
266
|
+
PermissionRequestOptions,
|
|
256
267
|
SpindleFrontendContext,
|
|
257
268
|
SpindleFrontendModule,
|
|
258
269
|
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,
|
|
@@ -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<
|
|
957
|
-
get(presetId: string, blockId: string, userId?: string): Promise<
|
|
958
|
-
create(presetId: string, input: PromptBlockCreateDTO, options?: { index?: number; userId?: string }): Promise<
|
|
959
|
-
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>;
|
|
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
|
|
|
@@ -1400,15 +1402,22 @@ export interface SpindleAPI {
|
|
|
1400
1402
|
*
|
|
1401
1403
|
* Fires inside `assemblePrompt` immediately before `activateWorldInfo`
|
|
1402
1404
|
* runs. Handlers can disable, force-enable, or content-override world info
|
|
1403
|
-
* entries based on chat state, message history, or external rules.
|
|
1405
|
+
* entries based on chat state, message history, or external rules. A
|
|
1406
|
+
* separate selection-only content view can influence empty filtering,
|
|
1407
|
+
* deduplication, and host budget selection without changing final inserted
|
|
1408
|
+
* content. Handlers can also narrow the prompt-local activation scope by
|
|
1409
|
+
* disabling recursive keyword chaining.
|
|
1404
1410
|
* Multiple handlers chain in priority order and a later handler sees the
|
|
1405
1411
|
* prior handlers' votes applied — useful for cross-entry injection
|
|
1406
1412
|
* patterns where one entry merges into another and then disables itself.
|
|
1413
|
+
* Captured IDs are activated against the pre-vote entry view and delivered
|
|
1414
|
+
* only to the requesting extension as `capturedWorldInfo`; `[]` is an
|
|
1415
|
+
* authoritative empty result and `undefined` means no capture was requested.
|
|
1407
1416
|
*
|
|
1408
1417
|
* Returning `void` passes the activation set through unchanged. Per-handler
|
|
1409
1418
|
* 10s timeout; errors are logged and the chain continues.
|
|
1410
1419
|
*
|
|
1411
|
-
* @param handler Returns
|
|
1420
|
+
* @param handler Returns entry changes, capture requests, activation overrides, or `void`.
|
|
1412
1421
|
* @param priority Lower values run first. Default `100`.
|
|
1413
1422
|
*
|
|
1414
1423
|
* @example
|
|
@@ -1683,16 +1692,13 @@ export interface SpindleAPI {
|
|
|
1683
1692
|
* }
|
|
1684
1693
|
* ```
|
|
1685
1694
|
*/
|
|
1686
|
-
open(options?:
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
text: string;
|
|
1694
|
-
cancelled: boolean;
|
|
1695
|
-
}>;
|
|
1695
|
+
open(options?: SpindleTextEditorOptions): Promise<SpindleTextEditorResult>;
|
|
1696
|
+
/**
|
|
1697
|
+
* Cancel an editor opened with the matching `editorRequestId`.
|
|
1698
|
+
*
|
|
1699
|
+
* Unknown or already-settled identities are accepted as no-ops.
|
|
1700
|
+
*/
|
|
1701
|
+
close(editorRequestId: string, userId?: string): Promise<void>;
|
|
1696
1702
|
};
|
|
1697
1703
|
|
|
1698
1704
|
/**
|
|
@@ -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;
|
|
@@ -127,6 +127,24 @@ const legacyArrayCallback: InterceptorHandler = async (input) => input;
|
|
|
127
127
|
const legacyResultCallback: InterceptorHandler = async (input) => ({ messages: input });
|
|
128
128
|
|
|
129
129
|
declare const spindle: SpindleAPI;
|
|
130
|
+
spindle.registerWorldInfoInterceptor(async (worldInfoContext) => {
|
|
131
|
+
const globalScanDepth: number | null =
|
|
132
|
+
worldInfoContext.activationSettings.globalScanDepth;
|
|
133
|
+
void globalScanDepth;
|
|
134
|
+
});
|
|
135
|
+
spindle.registerMessageContentProcessor(async (messageContext) => {
|
|
136
|
+
const isUser: boolean = messageContext.isUser;
|
|
137
|
+
void isUser;
|
|
138
|
+
});
|
|
139
|
+
spindle.registerMacroInterceptor(async (macroContext) => {
|
|
140
|
+
const firstMessage: string = macroContext.env.character.firstMessage;
|
|
141
|
+
const alternateGreetings: readonly string[] =
|
|
142
|
+
macroContext.env.character.alternateGreetings;
|
|
143
|
+
const greetingIndex: number = macroContext.env.chat.greetingIndex;
|
|
144
|
+
void firstMessage;
|
|
145
|
+
void alternateGreetings;
|
|
146
|
+
void greetingIndex;
|
|
147
|
+
});
|
|
130
148
|
const priorityDisposer: InterceptorDisposer = spindle.registerInterceptor(callback, 900, matchOptions);
|
|
131
149
|
const optionsDisposer: InterceptorDisposer = spindle.registerInterceptor(callback, options);
|
|
132
150
|
const handlerOnlyDisposer: InterceptorDisposer = spindle.registerInterceptor(legacyArrayCallback);
|
|
@@ -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
|
+
}
|