lumiverse-spindle-types 0.4.21 → 0.4.25
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 +117 -1
- package/src/council.ts +41 -0
- package/src/index.ts +3 -0
- package/src/spindle-api.ts +83 -1
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SpindleManifest } from "./manifest";
|
|
2
|
+
import type { CouncilMemberContext } from "./council";
|
|
2
3
|
|
|
3
4
|
// ─── DTO types for messages ──────────────────────────────────────────────
|
|
4
5
|
|
|
@@ -66,8 +67,67 @@ export interface GenerationRequestDTO {
|
|
|
66
67
|
* is inferred from the extension owner and can be omitted.
|
|
67
68
|
*/
|
|
68
69
|
userId?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Optional `AbortSignal` to cancel an in-flight generation. When the
|
|
72
|
+
* signal fires, the upstream LLM HTTP request is torn down and the
|
|
73
|
+
* returned promise rejects with an `AbortError` (`err.name === "AbortError"`).
|
|
74
|
+
*
|
|
75
|
+
* The signal is consumed inside the extension worker and never crosses
|
|
76
|
+
* the host boundary — it is stripped before the RPC message is posted.
|
|
77
|
+
* The worker notifies the host via an internal `cancel_generation`
|
|
78
|
+
* message so the host can abort the in-flight request.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* const controller = new AbortController()
|
|
83
|
+
* const timer = setTimeout(() => controller.abort(), 10_000)
|
|
84
|
+
* try {
|
|
85
|
+
* const result = await spindle.generate.raw({
|
|
86
|
+
* provider: "openai",
|
|
87
|
+
* model: "gpt-4o-mini",
|
|
88
|
+
* messages: [{ role: "user", content: "hello" }],
|
|
89
|
+
* signal: controller.signal,
|
|
90
|
+
* })
|
|
91
|
+
* } catch (err) {
|
|
92
|
+
* if (err instanceof Error && err.name === "AbortError") {
|
|
93
|
+
* // user/timeout cancelled — not an error condition
|
|
94
|
+
* }
|
|
95
|
+
* } finally {
|
|
96
|
+
* clearTimeout(timer)
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
signal?: AbortSignal;
|
|
69
101
|
}
|
|
70
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Streamed chunk yielded by `spindle.generate.rawStream()` and
|
|
105
|
+
* `spindle.generate.quietStream()`.
|
|
106
|
+
*
|
|
107
|
+
* The stream emits one or more `token` / `reasoning` chunks and then
|
|
108
|
+
* exactly one terminal `done` chunk carrying the aggregated response.
|
|
109
|
+
* If the stream fails or is aborted, the async generator rejects instead
|
|
110
|
+
* of emitting `done`.
|
|
111
|
+
*/
|
|
112
|
+
export type StreamChunkDTO =
|
|
113
|
+
/** Incremental content token. */
|
|
114
|
+
| { type: "token"; token: string }
|
|
115
|
+
/** Incremental chain-of-thought / reasoning token. */
|
|
116
|
+
| { type: "reasoning"; token: string }
|
|
117
|
+
/** Terminal chunk — emitted exactly once, on successful completion. */
|
|
118
|
+
| {
|
|
119
|
+
type: "done";
|
|
120
|
+
content: string;
|
|
121
|
+
reasoning?: string;
|
|
122
|
+
finish_reason: string;
|
|
123
|
+
tool_calls?: ToolCallDTO[];
|
|
124
|
+
usage?: {
|
|
125
|
+
prompt_tokens: number;
|
|
126
|
+
completion_tokens: number;
|
|
127
|
+
total_tokens: number;
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
|
|
71
131
|
export interface RequestInitDTO {
|
|
72
132
|
method?: string;
|
|
73
133
|
headers?: Record<string, string>;
|
|
@@ -887,6 +947,29 @@ export interface MessageSwipedPayloadDTO {
|
|
|
887
947
|
previousSwipeId?: number;
|
|
888
948
|
}
|
|
889
949
|
|
|
950
|
+
/**
|
|
951
|
+
* Payload delivered to `spindle.on("TOOL_INVOCATION", ...)` handlers.
|
|
952
|
+
*
|
|
953
|
+
* Fires whenever an extension-registered tool is invoked by Lumiverse. Handlers
|
|
954
|
+
* must return a string (or promise thereof) with the tool's result — the host
|
|
955
|
+
* coerces `undefined` / `null` to an empty string.
|
|
956
|
+
*
|
|
957
|
+
* `councilMember` is populated when the invocation originates from a council
|
|
958
|
+
* execution cycle, providing the assigned member's identity, role, chance,
|
|
959
|
+
* avatar URL, and Lumia personality fields. It is `undefined` for all other
|
|
960
|
+
* invocation paths.
|
|
961
|
+
*/
|
|
962
|
+
export interface ToolInvocationPayloadDTO {
|
|
963
|
+
/** The bare (unqualified) tool name, matching what was passed to `registerTool`. */
|
|
964
|
+
toolName: string;
|
|
965
|
+
/** Arguments delivered to the tool. Shape depends on the tool's JSON Schema. */
|
|
966
|
+
args: Record<string, unknown>;
|
|
967
|
+
/** Host-side correlation id for this invocation. */
|
|
968
|
+
requestId: string;
|
|
969
|
+
/** Council member snapshot when invoked via council — otherwise `undefined`. */
|
|
970
|
+
councilMember?: CouncilMemberContext;
|
|
971
|
+
}
|
|
972
|
+
|
|
890
973
|
/**
|
|
891
974
|
* Observer handle returned by `spindle.generate.observe()`.
|
|
892
975
|
* Provides a high-level API for watching an in-flight generation on a
|
|
@@ -924,6 +1007,18 @@ export type WorkerToHost =
|
|
|
924
1007
|
| { type: "register_tool"; tool: ToolRegistrationDTO }
|
|
925
1008
|
| { type: "unregister_tool"; name: string }
|
|
926
1009
|
| { type: "request_generation"; requestId: string; input: GenerationRequestDTO }
|
|
1010
|
+
/**
|
|
1011
|
+
* Start a streaming generation. The host responds asynchronously with
|
|
1012
|
+
* one or more `generation_stream_chunk` messages, terminating with a
|
|
1013
|
+
* `done` chunk on success or a `generation_stream_error` on failure.
|
|
1014
|
+
*/
|
|
1015
|
+
| { type: "request_generation_stream"; requestId: string; input: GenerationRequestDTO }
|
|
1016
|
+
/**
|
|
1017
|
+
* Cancel an in-flight generation started via `request_generation` or
|
|
1018
|
+
* `request_generation_stream`. `requestId` matches the original request.
|
|
1019
|
+
* The host aborts the upstream LLM fetch and responds with an `AbortError`.
|
|
1020
|
+
*/
|
|
1021
|
+
| { type: "cancel_generation"; requestId: string }
|
|
927
1022
|
| { type: "storage_read"; requestId: string; path: string }
|
|
928
1023
|
| { type: "storage_write"; requestId: string; path: string; data: string }
|
|
929
1024
|
| { type: "storage_read_binary"; requestId: string; path: string }
|
|
@@ -1230,6 +1325,15 @@ export type HostToWorker =
|
|
|
1230
1325
|
requestId: string;
|
|
1231
1326
|
toolName: string;
|
|
1232
1327
|
args: Record<string, unknown>;
|
|
1328
|
+
/**
|
|
1329
|
+
* Populated when the invocation originates from a council execution
|
|
1330
|
+
* cycle — carries the assigned council member's identity, role, chance,
|
|
1331
|
+
* avatar URL, and Lumia personality fields so the extension can tailor
|
|
1332
|
+
* its tool pipeline to the member on whose behalf it is running.
|
|
1333
|
+
*
|
|
1334
|
+
* Undefined for non-council invocation paths.
|
|
1335
|
+
*/
|
|
1336
|
+
councilMember?: CouncilMemberContext;
|
|
1233
1337
|
}
|
|
1234
1338
|
| { type: "shutdown" }
|
|
1235
1339
|
| { type: "frontend_message"; payload: unknown; userId: string }
|
|
@@ -1243,4 +1347,16 @@ export type HostToWorker =
|
|
|
1243
1347
|
commandId: string;
|
|
1244
1348
|
context: SpindleCommandContextDTO;
|
|
1245
1349
|
userId: string;
|
|
1246
|
-
}
|
|
1350
|
+
}
|
|
1351
|
+
/**
|
|
1352
|
+
* One streamed chunk for a generation started via
|
|
1353
|
+
* `request_generation_stream`. Multiple `token` / `reasoning` chunks
|
|
1354
|
+
* may arrive, terminating with exactly one `done` chunk on success.
|
|
1355
|
+
*/
|
|
1356
|
+
| { type: "generation_stream_chunk"; requestId: string; chunk: StreamChunkDTO }
|
|
1357
|
+
/**
|
|
1358
|
+
* Terminal failure for a generation started via
|
|
1359
|
+
* `request_generation_stream`. Mutually exclusive with the `done`
|
|
1360
|
+
* chunk in `generation_stream_chunk`. Aborts surface here too.
|
|
1361
|
+
*/
|
|
1362
|
+
| { type: "generation_stream_error"; requestId: string; error: string };
|
package/src/council.ts
CHANGED
|
@@ -77,6 +77,47 @@ export interface CouncilSettings {
|
|
|
77
77
|
toolsSettings: CouncilToolsSettings;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
// ---- Tool Invocation Context ----
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Personality snapshot of the council member that triggered a tool invocation.
|
|
84
|
+
*
|
|
85
|
+
* Delivered to extension `TOOL_INVOCATION` handlers when an extension-provided
|
|
86
|
+
* council tool is executed as part of a council cycle. Allows extensions to
|
|
87
|
+
* personalise their tool pipeline with the assigned member's identity, role,
|
|
88
|
+
* and Lumia personality fields.
|
|
89
|
+
*
|
|
90
|
+
* This field is optional — it is only populated when the tool is invoked via
|
|
91
|
+
* the council execution path. Tools invoked outside council (e.g. future
|
|
92
|
+
* inline function calling) will not see this context.
|
|
93
|
+
*/
|
|
94
|
+
export interface CouncilMemberContext {
|
|
95
|
+
/** Unique council member id (council settings row id). */
|
|
96
|
+
memberId: string;
|
|
97
|
+
/** Source Lumia item id this member is backed by. */
|
|
98
|
+
itemId: string;
|
|
99
|
+
/** Pack id the Lumia item lives in. */
|
|
100
|
+
packId: string;
|
|
101
|
+
/** Pack name the Lumia item lives in. */
|
|
102
|
+
packName: string;
|
|
103
|
+
/** Display name of the Lumia item (also used as the member name). */
|
|
104
|
+
name: string;
|
|
105
|
+
/** Freeform role description assigned by the user (e.g. "Plot Enforcer"). */
|
|
106
|
+
role: string;
|
|
107
|
+
/** Probability (0–100) that this member participates each generation. */
|
|
108
|
+
chance: number;
|
|
109
|
+
/** Relative URL to the member's avatar (e.g. `/api/v1/images/{id}`), or null. */
|
|
110
|
+
avatarUrl: string | null;
|
|
111
|
+
/** Lumia item "definition" field — physical/identity description. */
|
|
112
|
+
definition: string;
|
|
113
|
+
/** Lumia item "personality" field. */
|
|
114
|
+
personality: string;
|
|
115
|
+
/** Lumia item "behavior" field — behavioural patterns. */
|
|
116
|
+
behavior: string;
|
|
117
|
+
/** Gender identity marker (0=unspecified, 1=feminine, 2=masculine). */
|
|
118
|
+
genderIdentity: 0 | 1 | 2;
|
|
119
|
+
}
|
|
120
|
+
|
|
80
121
|
// ---- Execution Results ----
|
|
81
122
|
|
|
82
123
|
/** Result of a single tool invocation for a single member. */
|
package/src/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ export type {
|
|
|
20
20
|
ToolSchemaDTO,
|
|
21
21
|
ToolCallDTO,
|
|
22
22
|
GenerationRequestDTO,
|
|
23
|
+
StreamChunkDTO,
|
|
23
24
|
RequestInitDTO,
|
|
24
25
|
ConnectionProfileDTO,
|
|
25
26
|
PermissionDeniedDetail,
|
|
@@ -70,6 +71,7 @@ export type {
|
|
|
70
71
|
ChatMessageDTO,
|
|
71
72
|
MessageSwipeAction,
|
|
72
73
|
MessageSwipedPayloadDTO,
|
|
74
|
+
ToolInvocationPayloadDTO,
|
|
73
75
|
WorkerToHost,
|
|
74
76
|
HostToWorker,
|
|
75
77
|
} from "./api";
|
|
@@ -113,6 +115,7 @@ export type { SpindleAPI } from "./spindle-api";
|
|
|
113
115
|
|
|
114
116
|
export type {
|
|
115
117
|
CouncilMember,
|
|
118
|
+
CouncilMemberContext,
|
|
116
119
|
SidecarConfig,
|
|
117
120
|
CouncilSidecarConfig,
|
|
118
121
|
CouncilToolsSettings,
|
package/src/spindle-api.ts
CHANGED
|
@@ -45,6 +45,8 @@ import type {
|
|
|
45
45
|
GenerationStoppedPayloadDTO,
|
|
46
46
|
GenerationObserver,
|
|
47
47
|
MessageSwipedPayloadDTO,
|
|
48
|
+
ToolInvocationPayloadDTO,
|
|
49
|
+
StreamChunkDTO,
|
|
48
50
|
} from "./api";
|
|
49
51
|
|
|
50
52
|
/** The global `spindle` object available in backend extension workers */
|
|
@@ -63,6 +65,21 @@ export interface SpindleAPI {
|
|
|
63
65
|
* `swipeId` identifies which slot the event concerns.
|
|
64
66
|
*/
|
|
65
67
|
on(event: "MESSAGE_SWIPED", handler: (payload: MessageSwipedPayloadDTO, userId?: string) => void): () => void;
|
|
68
|
+
/**
|
|
69
|
+
* Receive invocations for tools registered via {@link SpindleAPI.registerTool}.
|
|
70
|
+
*
|
|
71
|
+
* The handler must return the tool's textual result (or a promise thereof).
|
|
72
|
+
* Undefined / null returns are coerced to an empty string by the host.
|
|
73
|
+
*
|
|
74
|
+
* When the invocation originates from a council execution cycle, the payload
|
|
75
|
+
* includes a `councilMember` snapshot describing the assigned member
|
|
76
|
+
* (identity, role, chance, avatar URL, and Lumia personality fields) so the
|
|
77
|
+
* extension can tailor its tool output to that member's voice.
|
|
78
|
+
*/
|
|
79
|
+
on(
|
|
80
|
+
event: "TOOL_INVOCATION",
|
|
81
|
+
handler: (payload: ToolInvocationPayloadDTO) => string | Promise<string> | void | Promise<void>
|
|
82
|
+
): () => void;
|
|
66
83
|
/** Subscribe to a Lumiverse event. */
|
|
67
84
|
on(event: string, handler: (payload: unknown, userId?: string) => void): () => void;
|
|
68
85
|
|
|
@@ -102,11 +119,76 @@ export interface SpindleAPI {
|
|
|
102
119
|
/** Unregister an LLM tool */
|
|
103
120
|
unregisterTool(name: string): void;
|
|
104
121
|
|
|
105
|
-
/**
|
|
122
|
+
/**
|
|
123
|
+
* Generation helpers.
|
|
124
|
+
*
|
|
125
|
+
* All three entry points (`raw`, `quiet`, `batch`) accept a standard
|
|
126
|
+
* `AbortSignal` via `input.signal`. Aborting the signal tears down the
|
|
127
|
+
* upstream LLM HTTP request and rejects the returned promise with an
|
|
128
|
+
* `AbortError` (`err.name === "AbortError"`). This is the same pattern
|
|
129
|
+
* `fetch()` uses, so it composes with `AbortSignal.timeout()` and
|
|
130
|
+
* `AbortSignal.any([...])`.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```ts
|
|
134
|
+
* const controller = new AbortController()
|
|
135
|
+
* const result = spindle.generate.raw({
|
|
136
|
+
* provider: "openai",
|
|
137
|
+
* model: "gpt-4o-mini",
|
|
138
|
+
* messages,
|
|
139
|
+
* signal: controller.signal,
|
|
140
|
+
* })
|
|
141
|
+
* // Cancel from elsewhere — e.g. user closed the panel
|
|
142
|
+
* controller.abort()
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
106
145
|
generate: {
|
|
107
146
|
raw(input: GenerationRequestDTO): Promise<unknown>;
|
|
108
147
|
quiet(input: GenerationRequestDTO): Promise<unknown>;
|
|
109
148
|
batch(input: GenerationRequestDTO): Promise<unknown>;
|
|
149
|
+
/**
|
|
150
|
+
* Streaming variant of {@link raw}. Returns an async generator that
|
|
151
|
+
* yields incremental {@link StreamChunkDTO} values:
|
|
152
|
+
*
|
|
153
|
+
* - `{ type: 'token', token }` — content chunk
|
|
154
|
+
* - `{ type: 'reasoning', token }` — chain-of-thought chunk
|
|
155
|
+
* - `{ type: 'done', ... }` — final aggregated response (emitted exactly once)
|
|
156
|
+
*
|
|
157
|
+
* Tool-call deltas, finish reason, and token usage live on the terminal
|
|
158
|
+
* `done` chunk. If the upstream call fails or the request is aborted
|
|
159
|
+
* via `input.signal`, the generator rejects with the underlying error
|
|
160
|
+
* (`AbortError` for cancellations).
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* const ctrl = new AbortController()
|
|
165
|
+
* setTimeout(() => ctrl.abort(), 30_000)
|
|
166
|
+
* try {
|
|
167
|
+
* for await (const chunk of spindle.generate.rawStream({
|
|
168
|
+
* provider: 'openai',
|
|
169
|
+
* model: 'gpt-4o-mini',
|
|
170
|
+
* messages,
|
|
171
|
+
* signal: ctrl.signal,
|
|
172
|
+
* })) {
|
|
173
|
+
* if (chunk.type === 'token') process.stdout.write(chunk.token)
|
|
174
|
+
* else if (chunk.type === 'done') usage = chunk.usage
|
|
175
|
+
* }
|
|
176
|
+
* } catch (err) {
|
|
177
|
+
* if (err instanceof Error && err.name === 'AbortError') return
|
|
178
|
+
* throw err
|
|
179
|
+
* }
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
rawStream(input: GenerationRequestDTO): AsyncGenerator<StreamChunkDTO, void, void>;
|
|
183
|
+
/**
|
|
184
|
+
* Streaming variant of {@link quiet}. Same chunk schema and abort
|
|
185
|
+
* semantics as {@link rawStream}.
|
|
186
|
+
*
|
|
187
|
+
* Note: streaming is not exposed for `batch` — compose multiple
|
|
188
|
+
* `rawStream` / `quietStream` calls yourself if you need parallel
|
|
189
|
+
* streamed responses.
|
|
190
|
+
*/
|
|
191
|
+
quietStream(input: GenerationRequestDTO): AsyncGenerator<StreamChunkDTO, void, void>;
|
|
110
192
|
/** Run a dry-run prompt assembly without calling the LLM. */
|
|
111
193
|
dryRun(input: DryRunRequestDTO, userId?: string): Promise<DryRunResultDTO>;
|
|
112
194
|
/**
|