lumiverse-spindle-types 0.4.37 → 0.4.38
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 +130 -0
- package/src/index.ts +7 -0
- package/src/permissions.ts +12 -9
- package/src/spindle-api.ts +80 -0
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -67,6 +67,112 @@ export interface MacroResolveResultDTO {
|
|
|
67
67
|
diagnostics: Array<{ message: string; offset: number; length: number }>;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
// ─── Macro Interceptor (permission: "macro_interceptor") ────────────────
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Where a macro evaluation originated. Useful for interceptors that only
|
|
74
|
+
* want to fire for certain call sites (e.g. prompt assembly vs. response
|
|
75
|
+
* post-processing vs. display-time resolution).
|
|
76
|
+
*/
|
|
77
|
+
export type MacroInterceptorPhase =
|
|
78
|
+
| "prompt"
|
|
79
|
+
| "display"
|
|
80
|
+
| "response"
|
|
81
|
+
| "other";
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Structured-clone snapshot of the live macro evaluation environment,
|
|
85
|
+
* passed to a macro interceptor. All values are read-only copies — mutating
|
|
86
|
+
* them has no effect on the real environment. Persist state via
|
|
87
|
+
* `spindle.variables.*` helpers instead.
|
|
88
|
+
*/
|
|
89
|
+
export interface MacroInterceptorEnvDTO {
|
|
90
|
+
readonly commit: boolean;
|
|
91
|
+
readonly names: Record<string, string>;
|
|
92
|
+
readonly character: Record<string, unknown>;
|
|
93
|
+
readonly chat: Record<string, unknown>;
|
|
94
|
+
readonly system: Record<string, unknown>;
|
|
95
|
+
readonly variables: {
|
|
96
|
+
readonly local: Record<string, string>;
|
|
97
|
+
readonly global: Record<string, string>;
|
|
98
|
+
readonly chat: Record<string, string>;
|
|
99
|
+
};
|
|
100
|
+
readonly extra: Record<string, unknown>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Context passed to a macro interceptor handler on every iteration of
|
|
105
|
+
* `MacroEvaluator.evaluate()`. The handler receives the current raw
|
|
106
|
+
* template (already transformed by any earlier interceptors in the chain)
|
|
107
|
+
* and returns either a transformed template string or `void` to pass through.
|
|
108
|
+
*/
|
|
109
|
+
export interface MacroInterceptorCtxDTO {
|
|
110
|
+
readonly template: string;
|
|
111
|
+
readonly env: MacroInterceptorEnvDTO;
|
|
112
|
+
readonly commit: boolean;
|
|
113
|
+
readonly phase: MacroInterceptorPhase;
|
|
114
|
+
readonly sourceHint?: string;
|
|
115
|
+
/**
|
|
116
|
+
* User ID that initiated the macro resolution (when available). Relevant
|
|
117
|
+
* for operator-scoped extensions that need to route work through other
|
|
118
|
+
* Spindle APIs on that user's behalf.
|
|
119
|
+
*/
|
|
120
|
+
readonly userId?: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Return value of a macro interceptor handler.
|
|
125
|
+
* - `string` replaces the template for subsequent interceptors + parsing.
|
|
126
|
+
* - `void` / `undefined` passes the template through unchanged.
|
|
127
|
+
*/
|
|
128
|
+
export type MacroInterceptorResultDTO = string | void;
|
|
129
|
+
|
|
130
|
+
// ─── Message Content Processor (permission: "chat_mutation") ───────────
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Which content-write path triggered a message content processor run.
|
|
134
|
+
* `"create"` covers both user-initiated `POST .../messages` writes and
|
|
135
|
+
* auto-inserted greeting rows.
|
|
136
|
+
*/
|
|
137
|
+
export type MessageContentProcessorOrigin =
|
|
138
|
+
| "create"
|
|
139
|
+
| "update"
|
|
140
|
+
| "swipe_add"
|
|
141
|
+
| "swipe_update";
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Context passed to a message content processor before a user-initiated
|
|
145
|
+
* message write reaches SQLite. Handlers can inspect this and return a
|
|
146
|
+
* patch (new `content` / merged `extra`) to transform what is stored and
|
|
147
|
+
* what WebSocket subscribers observe on first paint.
|
|
148
|
+
*/
|
|
149
|
+
export interface MessageContentProcessorCtxDTO {
|
|
150
|
+
chatId: string;
|
|
151
|
+
/** Undefined for `"create"` origins (the row doesn't exist yet). */
|
|
152
|
+
messageId?: string;
|
|
153
|
+
content: string;
|
|
154
|
+
extra?: Record<string, unknown>;
|
|
155
|
+
origin: MessageContentProcessorOrigin;
|
|
156
|
+
/** Set for `"swipe_update"` only — the zero-based index of the swipe being rewritten. */
|
|
157
|
+
swipeIndex?: number;
|
|
158
|
+
/** Owning user for the write. Pass this through to operator-scoped Spindle calls. */
|
|
159
|
+
userId: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Return value for a message content processor handler. Return `undefined`
|
|
164
|
+
* / `void` to pass through, or a partial patch to modify the write:
|
|
165
|
+
* - `content` (if present) replaces the content for downstream processors
|
|
166
|
+
* and the DB write.
|
|
167
|
+
* - `extra` (if present) shallow-merges into the existing `extra` — keys
|
|
168
|
+
* you omit are preserved. Ignored on swipe origins (swipes share the
|
|
169
|
+
* parent message's `extra`).
|
|
170
|
+
*/
|
|
171
|
+
export interface MessageContentProcessorResultDTO {
|
|
172
|
+
content?: string;
|
|
173
|
+
extra?: Record<string, unknown>;
|
|
174
|
+
}
|
|
175
|
+
|
|
70
176
|
export interface ToolRegistrationDTO {
|
|
71
177
|
name: string;
|
|
72
178
|
display_name: string;
|
|
@@ -1304,6 +1410,20 @@ export type WorkerToHost =
|
|
|
1304
1410
|
requestId: string;
|
|
1305
1411
|
context: unknown;
|
|
1306
1412
|
}
|
|
1413
|
+
// ─── Macro Interceptor (gated: "macro_interceptor") ────────────────
|
|
1414
|
+
| { type: "register_macro_interceptor"; priority?: number }
|
|
1415
|
+
| {
|
|
1416
|
+
type: "macro_interceptor_result";
|
|
1417
|
+
requestId: string;
|
|
1418
|
+
result: MacroInterceptorResultDTO;
|
|
1419
|
+
}
|
|
1420
|
+
// ─── Message Content Processor (gated: "chat_mutation") ────────────
|
|
1421
|
+
| { type: "register_message_content_processor"; priority?: number }
|
|
1422
|
+
| {
|
|
1423
|
+
type: "message_content_processor_result";
|
|
1424
|
+
requestId: string;
|
|
1425
|
+
result: MessageContentProcessorResultDTO | void;
|
|
1426
|
+
}
|
|
1307
1427
|
| {
|
|
1308
1428
|
type: "macro_result";
|
|
1309
1429
|
requestId: string;
|
|
@@ -1477,6 +1597,16 @@ export type HostToWorker =
|
|
|
1477
1597
|
requestId: string;
|
|
1478
1598
|
context: unknown;
|
|
1479
1599
|
}
|
|
1600
|
+
| {
|
|
1601
|
+
type: "macro_interceptor_request";
|
|
1602
|
+
requestId: string;
|
|
1603
|
+
ctx: MacroInterceptorCtxDTO;
|
|
1604
|
+
}
|
|
1605
|
+
| {
|
|
1606
|
+
type: "message_content_processor_request";
|
|
1607
|
+
requestId: string;
|
|
1608
|
+
ctx: MessageContentProcessorCtxDTO;
|
|
1609
|
+
}
|
|
1480
1610
|
| {
|
|
1481
1611
|
type: "response";
|
|
1482
1612
|
requestId: string;
|
package/src/index.ts
CHANGED
|
@@ -81,6 +81,13 @@ export type {
|
|
|
81
81
|
TokenModelSourceDTO,
|
|
82
82
|
TokenCountOptionsDTO,
|
|
83
83
|
TokenCountResultDTO,
|
|
84
|
+
MacroInterceptorPhase,
|
|
85
|
+
MacroInterceptorEnvDTO,
|
|
86
|
+
MacroInterceptorCtxDTO,
|
|
87
|
+
MacroInterceptorResultDTO,
|
|
88
|
+
MessageContentProcessorOrigin,
|
|
89
|
+
MessageContentProcessorCtxDTO,
|
|
90
|
+
MessageContentProcessorResultDTO,
|
|
84
91
|
WorkerToHost,
|
|
85
92
|
HostToWorker,
|
|
86
93
|
} from "./api";
|
package/src/permissions.ts
CHANGED
|
@@ -4,15 +4,16 @@
|
|
|
4
4
|
* Free tier (no declaration needed): events, storage, macros, dom, variables
|
|
5
5
|
*
|
|
6
6
|
* Gated tier (must declare):
|
|
7
|
-
* - "generation"
|
|
8
|
-
* - "interceptor"
|
|
9
|
-
* - "tools"
|
|
10
|
-
* - "cors_proxy"
|
|
11
|
-
* - "context_handler"
|
|
7
|
+
* - "generation" — fire generations on behalf of user
|
|
8
|
+
* - "interceptor" — pre-generation prompt modification
|
|
9
|
+
* - "tools" — register LLM tools
|
|
10
|
+
* - "cors_proxy" — use CORS proxy
|
|
11
|
+
* - "context_handler" — register global context middleware
|
|
12
12
|
* - "generation_parameters" — inject parameters into in-flight generations via interceptors
|
|
13
|
-
* - "characters"
|
|
14
|
-
* - "chats"
|
|
15
|
-
* - "personas"
|
|
13
|
+
* - "characters" — CRUD on character cards
|
|
14
|
+
* - "chats" — CRUD on chat sessions
|
|
15
|
+
* - "personas" — CRUD on personas
|
|
16
|
+
* - "macro_interceptor" — transform raw templates before macro parsing/dispatch
|
|
16
17
|
*/
|
|
17
18
|
export type SpindlePermission =
|
|
18
19
|
| "generation"
|
|
@@ -32,7 +33,8 @@ export type SpindlePermission =
|
|
|
32
33
|
| "personas"
|
|
33
34
|
| "push_notification"
|
|
34
35
|
| "image_gen"
|
|
35
|
-
| "generation_parameters"
|
|
36
|
+
| "generation_parameters"
|
|
37
|
+
| "macro_interceptor";
|
|
36
38
|
|
|
37
39
|
export const ALL_PERMISSIONS: readonly SpindlePermission[] = [
|
|
38
40
|
"generation",
|
|
@@ -53,6 +55,7 @@ export const ALL_PERMISSIONS: readonly SpindlePermission[] = [
|
|
|
53
55
|
"push_notification",
|
|
54
56
|
"image_gen",
|
|
55
57
|
"generation_parameters",
|
|
58
|
+
"macro_interceptor",
|
|
56
59
|
] as const;
|
|
57
60
|
|
|
58
61
|
export function isValidPermission(p: string): p is SpindlePermission {
|
package/src/spindle-api.ts
CHANGED
|
@@ -53,6 +53,10 @@ import type {
|
|
|
53
53
|
StreamChunkDTO,
|
|
54
54
|
TokenCountOptionsDTO,
|
|
55
55
|
TokenCountResultDTO,
|
|
56
|
+
MacroInterceptorCtxDTO,
|
|
57
|
+
MacroInterceptorResultDTO,
|
|
58
|
+
MessageContentProcessorCtxDTO,
|
|
59
|
+
MessageContentProcessorResultDTO,
|
|
56
60
|
} from "./api";
|
|
57
61
|
|
|
58
62
|
/** The global `spindle` object available in backend extension workers */
|
|
@@ -676,6 +680,82 @@ export interface SpindleAPI {
|
|
|
676
680
|
priority?: number
|
|
677
681
|
): void;
|
|
678
682
|
|
|
683
|
+
/**
|
|
684
|
+
* Register a macro interceptor (permission: `macro_interceptor`).
|
|
685
|
+
*
|
|
686
|
+
* Runs at the top of `MacroEvaluator.evaluate()`, once per fixed-point
|
|
687
|
+
* iteration, before Lumiverse parses the template. Receives the raw
|
|
688
|
+
* template plus a read-only env snapshot and returns either a transformed
|
|
689
|
+
* template or `void` to pass through.
|
|
690
|
+
*
|
|
691
|
+
* Use this when per-macro RPC cost dominates iteration-heavy templates
|
|
692
|
+
* (e.g. `{{#each LARGE_LIST}}…{{my_macro}}…{{/each}}`). For single macros
|
|
693
|
+
* without iteration, prefer {@link SpindleAPI.registerMacro}.
|
|
694
|
+
*
|
|
695
|
+
* Each invocation runs inside a 10-second wall-clock budget on the host.
|
|
696
|
+
* On timeout or thrown error the chain logs the failure and forwards the
|
|
697
|
+
* previous template to the next handler — macro evaluation itself never
|
|
698
|
+
* aborts. A second registration from the same extension replaces the
|
|
699
|
+
* previous handler.
|
|
700
|
+
*
|
|
701
|
+
* @param handler Returns the transformed template, or `void` to pass through.
|
|
702
|
+
* @param priority Lower values run first. Default `100`.
|
|
703
|
+
*
|
|
704
|
+
* @example
|
|
705
|
+
* ```ts
|
|
706
|
+
* spindle.registerMacroInterceptor(async (ctx) => {
|
|
707
|
+
* if (!ctx.template.includes('{{my_macro')) return
|
|
708
|
+
* return resolveInWorker(ctx.template, ctx.env)
|
|
709
|
+
* }, 100)
|
|
710
|
+
* ```
|
|
711
|
+
*/
|
|
712
|
+
registerMacroInterceptor(
|
|
713
|
+
handler: (
|
|
714
|
+
ctx: MacroInterceptorCtxDTO
|
|
715
|
+
) => Promise<MacroInterceptorResultDTO>,
|
|
716
|
+
priority?: number
|
|
717
|
+
): void;
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Register a message content processor (permission: `chat_mutation`).
|
|
721
|
+
*
|
|
722
|
+
* Runs synchronously inside every user-initiated message-write REST
|
|
723
|
+
* route (create, update, swipe add/update) and the auto-greeting path,
|
|
724
|
+
* before the row reaches SQLite. The returned patch transforms both the
|
|
725
|
+
* stored row and every `MESSAGE_SENT` / `MESSAGE_EDITED` / `MESSAGE_SWIPED`
|
|
726
|
+
* subscriber on first paint.
|
|
727
|
+
*
|
|
728
|
+
* Not invoked for `spindle.chat.*` mutations — those paths intentionally
|
|
729
|
+
* bypass the processor chain to avoid loops on an extension's own writes.
|
|
730
|
+
*
|
|
731
|
+
* Each invocation runs inside a 10-second wall-clock budget on the host.
|
|
732
|
+
* On timeout or thrown error the chain logs the failure and forwards the
|
|
733
|
+
* previous content to the next handler — the write still proceeds. A
|
|
734
|
+
* second registration from the same extension replaces the previous
|
|
735
|
+
* handler.
|
|
736
|
+
*
|
|
737
|
+
* Every millisecond of handler work is visible latency on send/edit/swipe.
|
|
738
|
+
* Keep handlers tight.
|
|
739
|
+
*
|
|
740
|
+
* @param handler Receives the about-to-be-committed content; returns a
|
|
741
|
+
* patch, or `void` to pass through.
|
|
742
|
+
* @param priority Lower values run first. Default `100`.
|
|
743
|
+
*
|
|
744
|
+
* @example
|
|
745
|
+
* ```ts
|
|
746
|
+
* spindle.registerMessageContentProcessor(async (ctx) => {
|
|
747
|
+
* if (!ctx.content.includes('{{my_macro}}')) return
|
|
748
|
+
* return { content: ctx.content.replaceAll('{{my_macro}}', 'resolved') }
|
|
749
|
+
* }, 50)
|
|
750
|
+
* ```
|
|
751
|
+
*/
|
|
752
|
+
registerMessageContentProcessor(
|
|
753
|
+
handler: (
|
|
754
|
+
ctx: MessageContentProcessorCtxDTO
|
|
755
|
+
) => Promise<MessageContentProcessorResultDTO | void>,
|
|
756
|
+
priority?: number
|
|
757
|
+
): void;
|
|
758
|
+
|
|
679
759
|
/**
|
|
680
760
|
* Send a message to the frontend module.
|
|
681
761
|
*
|