lumiverse-spindle-types 0.5.1 → 0.5.2
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 +104 -1
- package/src/index.ts +6 -0
- package/src/permissions.ts +6 -1
- package/src/spindle-api.ts +71 -0
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -1266,6 +1266,99 @@ export interface PermissionChangedDetail {
|
|
|
1266
1266
|
allGranted: string[];
|
|
1267
1267
|
}
|
|
1268
1268
|
|
|
1269
|
+
// ─── Web Search DTOs ────────────────────────────────────────────────────
|
|
1270
|
+
|
|
1271
|
+
/** Identifies which provider backs the user's configured web search engine. */
|
|
1272
|
+
export type WebSearchProviderDTO = "searxng";
|
|
1273
|
+
|
|
1274
|
+
/**
|
|
1275
|
+
* Safe view of a user's web search configuration. The raw API key is never
|
|
1276
|
+
* exposed — only `hasApiKey` indicates whether one is on file.
|
|
1277
|
+
*/
|
|
1278
|
+
export interface WebSearchSettingsDTO {
|
|
1279
|
+
enabled: boolean;
|
|
1280
|
+
provider: WebSearchProviderDTO;
|
|
1281
|
+
apiUrl: string;
|
|
1282
|
+
requestTimeoutMs: number;
|
|
1283
|
+
defaultResultCount: number;
|
|
1284
|
+
maxResultCount: number;
|
|
1285
|
+
maxPagesToScrape: number;
|
|
1286
|
+
maxCharsPerPage: number;
|
|
1287
|
+
language: string;
|
|
1288
|
+
safeSearch: 0 | 1 | 2;
|
|
1289
|
+
engines: string[];
|
|
1290
|
+
hasApiKey: boolean;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
/** A single search result row, normalized across providers. */
|
|
1294
|
+
export interface WebSearchResultDTO {
|
|
1295
|
+
title: string;
|
|
1296
|
+
url: string;
|
|
1297
|
+
snippet: string;
|
|
1298
|
+
/** Provider-reported engine identifier when available (e.g. `"google"`, `"bing"`). */
|
|
1299
|
+
engine?: string;
|
|
1300
|
+
/** Provider-reported relevance score when available. */
|
|
1301
|
+
score?: number;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
/**
|
|
1305
|
+
* A search result enriched with scraped page content. Only present when the
|
|
1306
|
+
* query was run with `scrape: true` (the default).
|
|
1307
|
+
*/
|
|
1308
|
+
export interface WebSearchDocumentDTO {
|
|
1309
|
+
title: string;
|
|
1310
|
+
url: string;
|
|
1311
|
+
snippet: string;
|
|
1312
|
+
/** How the page content was extracted (e.g. `"html"`, `"pdf"`). */
|
|
1313
|
+
sourceType?: string;
|
|
1314
|
+
/** Extracted page text, clipped to `WebSearchSettingsDTO.maxCharsPerPage`. */
|
|
1315
|
+
content?: string;
|
|
1316
|
+
/** Length of the source page content before clipping. */
|
|
1317
|
+
contentLength?: number;
|
|
1318
|
+
/** Populated when scraping failed for this result; `content` is then absent. */
|
|
1319
|
+
error?: string;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
/** Options forwarded to `spindle.webSearch.query()`. */
|
|
1323
|
+
export interface WebSearchRequestDTO {
|
|
1324
|
+
/** Free-text search query. Trimmed by the host; empty values are rejected. */
|
|
1325
|
+
query: string;
|
|
1326
|
+
/**
|
|
1327
|
+
* Desired number of results. Clamped to `WebSearchSettingsDTO.maxResultCount`
|
|
1328
|
+
* on the host; omit to use the user's `defaultResultCount`.
|
|
1329
|
+
*/
|
|
1330
|
+
count?: number;
|
|
1331
|
+
/**
|
|
1332
|
+
* When `true` (default), the host scrapes the first
|
|
1333
|
+
* `WebSearchSettingsDTO.maxPagesToScrape` results, fills in
|
|
1334
|
+
* `documents[].content`, and assembles the `context` block. Set to `false`
|
|
1335
|
+
* to skip scraping entirely — only `results` are returned, and
|
|
1336
|
+
* `documents` / `context` are omitted from the response. Useful when the
|
|
1337
|
+
* extension only needs titles, URLs, and snippets.
|
|
1338
|
+
*/
|
|
1339
|
+
scrape?: boolean;
|
|
1340
|
+
/** For operator-scoped extensions; ignored on user-scoped extensions. */
|
|
1341
|
+
userId?: string;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
/**
|
|
1345
|
+
* Result of a successful `spindle.webSearch.query()` call. `documents` and
|
|
1346
|
+
* `context` are omitted when the request was issued with `scrape: false`.
|
|
1347
|
+
*/
|
|
1348
|
+
export interface WebSearchResponseDTO {
|
|
1349
|
+
/** The (trimmed) query that was executed. */
|
|
1350
|
+
query: string;
|
|
1351
|
+
/** Raw normalized results from the search provider. */
|
|
1352
|
+
results: WebSearchResultDTO[];
|
|
1353
|
+
/** Per-result scraped page content. Absent when `scrape: false`. */
|
|
1354
|
+
documents?: WebSearchDocumentDTO[];
|
|
1355
|
+
/**
|
|
1356
|
+
* Pre-assembled, prompt-ready context block summarizing the query plus the
|
|
1357
|
+
* scraped documents. Absent when `scrape: false`.
|
|
1358
|
+
*/
|
|
1359
|
+
context?: string;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1269
1362
|
// ─── Theme DTOs ──────────────────────────────────────────────────────────
|
|
1270
1363
|
|
|
1271
1364
|
/**
|
|
@@ -2448,7 +2541,17 @@ export type WorkerToHost =
|
|
|
2448
2541
|
model?: string;
|
|
2449
2542
|
modelSource?: TokenModelSourceDTO;
|
|
2450
2543
|
userId?: string;
|
|
2451
|
-
}
|
|
2544
|
+
}
|
|
2545
|
+
// ─── Web Search (gated: "web_search") ─────────────────────────────────
|
|
2546
|
+
| {
|
|
2547
|
+
type: "web_search_query";
|
|
2548
|
+
requestId: string;
|
|
2549
|
+
query: string;
|
|
2550
|
+
count?: number;
|
|
2551
|
+
scrape?: boolean;
|
|
2552
|
+
userId?: string;
|
|
2553
|
+
}
|
|
2554
|
+
| { type: "web_search_get_settings"; requestId: string; userId?: string };
|
|
2452
2555
|
|
|
2453
2556
|
// ─── Host → Worker messages ──────────────────────────────────────────────
|
|
2454
2557
|
|
package/src/index.ts
CHANGED
|
@@ -155,6 +155,12 @@ export type {
|
|
|
155
155
|
MessageContentProcessorOrigin,
|
|
156
156
|
MessageContentProcessorCtxDTO,
|
|
157
157
|
MessageContentProcessorResultDTO,
|
|
158
|
+
WebSearchProviderDTO,
|
|
159
|
+
WebSearchSettingsDTO,
|
|
160
|
+
WebSearchResultDTO,
|
|
161
|
+
WebSearchDocumentDTO,
|
|
162
|
+
WebSearchRequestDTO,
|
|
163
|
+
WebSearchResponseDTO,
|
|
158
164
|
WorkerToHost,
|
|
159
165
|
HostToWorker,
|
|
160
166
|
} from "./api";
|
package/src/permissions.ts
CHANGED
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
* links, consolidations) and long-term chat memory (vectorized
|
|
20
20
|
* chat-chunk retrieval, warmup, cache).
|
|
21
21
|
* - "macro_interceptor" — transform raw templates before macro parsing/dispatch
|
|
22
|
+
* - "web_search" — execute searches via the user's configured web search
|
|
23
|
+
* provider (e.g. SearXNG) and read the safe view of their
|
|
24
|
+
* web search settings (never the API key).
|
|
22
25
|
*/
|
|
23
26
|
export type SpindlePermission =
|
|
24
27
|
| "generation"
|
|
@@ -44,7 +47,8 @@ export type SpindlePermission =
|
|
|
44
47
|
| "image_gen"
|
|
45
48
|
| "images"
|
|
46
49
|
| "generation_parameters"
|
|
47
|
-
| "macro_interceptor"
|
|
50
|
+
| "macro_interceptor"
|
|
51
|
+
| "web_search";
|
|
48
52
|
|
|
49
53
|
export const ALL_PERMISSIONS: readonly SpindlePermission[] = [
|
|
50
54
|
"generation",
|
|
@@ -71,6 +75,7 @@ export const ALL_PERMISSIONS: readonly SpindlePermission[] = [
|
|
|
71
75
|
"images",
|
|
72
76
|
"generation_parameters",
|
|
73
77
|
"macro_interceptor",
|
|
78
|
+
"web_search",
|
|
74
79
|
] as const;
|
|
75
80
|
|
|
76
81
|
export function isValidPermission(p: string): p is SpindlePermission {
|
package/src/spindle-api.ts
CHANGED
|
@@ -103,6 +103,9 @@ import type {
|
|
|
103
103
|
MessageContentProcessorResultDTO,
|
|
104
104
|
SharedRpcRequestContextDTO,
|
|
105
105
|
SharedRpcEndpointPolicyDTO,
|
|
106
|
+
WebSearchRequestDTO,
|
|
107
|
+
WebSearchResponseDTO,
|
|
108
|
+
WebSearchSettingsDTO,
|
|
106
109
|
} from "./api";
|
|
107
110
|
import type {
|
|
108
111
|
ChatChunkDTO,
|
|
@@ -1370,6 +1373,74 @@ export interface SpindleAPI {
|
|
|
1370
1373
|
}>;
|
|
1371
1374
|
};
|
|
1372
1375
|
|
|
1376
|
+
/**
|
|
1377
|
+
* Web search (permission: `"web_search"`).
|
|
1378
|
+
*
|
|
1379
|
+
* Execute searches via the user's configured web search provider
|
|
1380
|
+
* (currently SearXNG; additional providers will be added over time) and
|
|
1381
|
+
* read the safe view of their web search settings. The host enforces all
|
|
1382
|
+
* upstream limits (engine list, max result count, max pages to scrape,
|
|
1383
|
+
* timeouts) — extensions cannot supply their own endpoint or API key.
|
|
1384
|
+
*
|
|
1385
|
+
* For user-scoped extensions, `userId` is inferred from the extension
|
|
1386
|
+
* owner. Operator-scoped extensions should pass the `userId` of the user
|
|
1387
|
+
* whose search engine should run the query.
|
|
1388
|
+
*
|
|
1389
|
+
* @example
|
|
1390
|
+
* ```ts
|
|
1391
|
+
* // Pre-flight: confirm web search is configured before issuing a query.
|
|
1392
|
+
* const settings = await spindle.webSearch.getSettings()
|
|
1393
|
+
* if (!settings.enabled) {
|
|
1394
|
+
* spindle.toast.warning('Configure a web search provider in Settings → Web Search first.')
|
|
1395
|
+
* return
|
|
1396
|
+
* }
|
|
1397
|
+
*
|
|
1398
|
+
* // Full enriched query — scrapes the top-N pages and returns a
|
|
1399
|
+
* // ready-to-inject context block.
|
|
1400
|
+
* const enriched = await spindle.webSearch.query({
|
|
1401
|
+
* query: 'latest LLM benchmark results',
|
|
1402
|
+
* count: 5,
|
|
1403
|
+
* })
|
|
1404
|
+
* await spindle.chat.appendMessage(chatId, {
|
|
1405
|
+
* role: 'system',
|
|
1406
|
+
* content: enriched.context ?? '',
|
|
1407
|
+
* })
|
|
1408
|
+
*
|
|
1409
|
+
* // Lightweight query — titles, URLs, snippets only.
|
|
1410
|
+
* const quick = await spindle.webSearch.query({
|
|
1411
|
+
* query: 'who won the 2026 world cup',
|
|
1412
|
+
* scrape: false,
|
|
1413
|
+
* })
|
|
1414
|
+
* for (const row of quick.results) {
|
|
1415
|
+
* spindle.log.info(`${row.title} — ${row.url}`)
|
|
1416
|
+
* }
|
|
1417
|
+
* ```
|
|
1418
|
+
*/
|
|
1419
|
+
webSearch: {
|
|
1420
|
+
/**
|
|
1421
|
+
* Run a search against the user's configured provider.
|
|
1422
|
+
*
|
|
1423
|
+
* Rejects with `"Web search is disabled"` when the user has not
|
|
1424
|
+
* configured a provider, and with `"Web search API URL is not configured"`
|
|
1425
|
+
* when the upstream endpoint is missing. Other upstream errors surface
|
|
1426
|
+
* as `Error("SearXNG returned HTTP NNN")` (or equivalent for future
|
|
1427
|
+
* providers).
|
|
1428
|
+
*
|
|
1429
|
+
* When `input.scrape` is `false`, `documents` and `context` are omitted
|
|
1430
|
+
* from the response. Otherwise the host scrapes up to
|
|
1431
|
+
* `WebSearchSettingsDTO.maxPagesToScrape` results, fills in
|
|
1432
|
+
* `documents[].content`, and assembles a prompt-ready `context` block.
|
|
1433
|
+
*/
|
|
1434
|
+
query(input: WebSearchRequestDTO): Promise<WebSearchResponseDTO>;
|
|
1435
|
+
/**
|
|
1436
|
+
* Read the safe view of the user's web search configuration. The raw
|
|
1437
|
+
* API key is never exposed — only `hasApiKey` indicates whether one is
|
|
1438
|
+
* on file. Useful for branching on `enabled` / `provider` /
|
|
1439
|
+
* `maxResultCount` before issuing a query.
|
|
1440
|
+
*/
|
|
1441
|
+
getSettings(userId?: string): Promise<WebSearchSettingsDTO>;
|
|
1442
|
+
};
|
|
1443
|
+
|
|
1373
1444
|
/**
|
|
1374
1445
|
* Text editor (free tier — no permission needed).
|
|
1375
1446
|
* Opens the native Lumiverse expanded text editor modal on the user's
|