lumiverse-spindle-types 0.5.8 → 0.5.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lumiverse-spindle-types",
3
- "version": "0.5.8",
3
+ "version": "0.5.10",
4
4
  "types": "./src/index.ts",
5
5
  "keywords": [
6
6
  "lumiverse",
package/src/api.ts CHANGED
@@ -247,6 +247,25 @@ export interface GenerationRequestDTO {
247
247
  connection_id?: string;
248
248
  /** Optional tool/function definitions for inline function calling (raw/quiet only). */
249
249
  tools?: ToolSchemaDTO[];
250
+ /**
251
+ * Optional per-request override of the user's reasoning ("extended thinking")
252
+ * settings. When omitted (or `{ source: "inherit" }`) the backend resolves
253
+ * the effective settings the same way a normal chat generation does:
254
+ * the resolved connection's `reasoning_bindings` win, falling back to the
255
+ * user's global `reasoningSettings`.
256
+ *
257
+ * Use this to bypass that resolution for a single request — e.g. to force
258
+ * `"off"` for a quick, cheap call, or to dial the effort up/down with
259
+ * `source: "custom"`. The backend translates the high-level intent into
260
+ * the provider-specific knobs (`thinking`, `thinkingConfig`,
261
+ * `reasoning_effort`, `reasoning.effort`, etc.) so the extension doesn't
262
+ * need to know the per-provider quirks.
263
+ *
264
+ * Raw values supplied in `parameters` still take precedence at the field
265
+ * level — this override only fills in what hasn't already been set,
266
+ * except `source: "off"` which unconditionally strips reasoning fields.
267
+ */
268
+ reasoning?: GenerationReasoningOverrideDTO;
250
269
  /**
251
270
  * For operator-scoped extensions: the user ID whose connection profiles
252
271
  * and generation context should be used. For user-scoped extensions this
@@ -348,6 +367,112 @@ export interface RequestInitDTO {
348
367
  mediaType?: "image" | "audio";
349
368
  }
350
369
 
370
+ /**
371
+ * Reasoning effort tier. Provider mapping:
372
+ * - Anthropic adaptive (Claude 4.6+): `low | medium | high | max` (+ `xhigh` on Opus 4.7) → `output_config.effort`.
373
+ * - Anthropic legacy: mapped to `thinking.budget_tokens` (low=2048, medium=8192, high=16384, max=32768).
374
+ * - Google (Gemini / Vertex): `minimal | low | medium | high` → `thinkingConfig.thinkingLevel`.
375
+ * - DeepSeek: `low | medium | high` → `"high"`, `max | xhigh` → `"max"` (`reasoning_effort`).
376
+ * - OpenRouter: `none | minimal | low | medium | high | xhigh` → `reasoning.effort`.
377
+ * - NanoGPT: `none | minimal | low | medium | high` → `reasoning.effort`.
378
+ * - Moonshot / Z.AI: toggle-only — effort ignored, just enables `thinking`.
379
+ * - Generic OpenAI-compatible: passed verbatim as `reasoning.effort`.
380
+ *
381
+ * `"auto"` defers to the user's preset/global setting or the provider's
382
+ * model-specific default and is the safest value to use when you don't
383
+ * have a specific tier in mind.
384
+ */
385
+ export type ReasoningEffortDTO =
386
+ | "auto"
387
+ | "none"
388
+ | "minimal"
389
+ | "low"
390
+ | "medium"
391
+ | "high"
392
+ | "max"
393
+ | "xhigh";
394
+
395
+ /**
396
+ * Anthropic-only display mode for thinking blocks. Maps to `thinking.display`
397
+ * in the Messages API. `"auto"` omits the field so Anthropic applies its
398
+ * model-specific default (`"omitted"` on Opus 4.7 / Mythos Preview,
399
+ * `"summarized"` elsewhere). Ignored by every other provider.
400
+ */
401
+ export type ThinkingDisplayDTO = "auto" | "summarized" | "omitted";
402
+
403
+ /**
404
+ * Full reasoning settings snapshot. Mirrors the user-level setting that
405
+ * Lumiverse stores under `reasoningSettings`. Surfaced on
406
+ * `ConnectionProfileDTO.reasoning_bindings.settings` when a connection has
407
+ * a binding attached.
408
+ *
409
+ * Only `apiReasoning` / `reasoningEffort` / `thinkingDisplay` influence the
410
+ * outgoing provider request — the remaining fields drive delimited-reasoning
411
+ * parsing (`prefix`, `suffix`, `autoParse`) and chat-history pruning
412
+ * (`keepInHistory`) and are included for inspection / round-tripping.
413
+ */
414
+ export interface ReasoningSettingsDTO {
415
+ /** Master switch: whether the provider should produce thinking output. */
416
+ apiReasoning: boolean;
417
+ /** Effort tier — see {@link ReasoningEffortDTO}. */
418
+ reasoningEffort: ReasoningEffortDTO;
419
+ /** Anthropic-only. */
420
+ thinkingDisplay: ThinkingDisplayDTO;
421
+ /** Opening delimiter used by the delimited-reasoning parser (e.g. `"<think>\n"`). */
422
+ prefix: string;
423
+ /** Closing delimiter used by the delimited-reasoning parser (e.g. `"\n</think>"`). */
424
+ suffix: string;
425
+ /** Whether to auto-parse delimited reasoning out of the assistant content stream. */
426
+ autoParse: boolean;
427
+ /**
428
+ * How many recent reasoning blocks to retain in assembled prompt history.
429
+ * `0` strips all, `-1` keeps everything, `N` keeps the last N.
430
+ */
431
+ keepInHistory: number;
432
+ }
433
+
434
+ /**
435
+ * Reasoning settings bound to a specific connection profile. When present,
436
+ * these override the user's global `reasoningSettings` during normal chat
437
+ * generation on this connection.
438
+ */
439
+ export interface ConnectionReasoningBindingsDTO {
440
+ /** Reasoning settings snapshot captured at bind time. */
441
+ settings: ReasoningSettingsDTO;
442
+ /**
443
+ * Optional "Start Reply With" assistant prefill captured alongside the
444
+ * reasoning snapshot. When present, overrides the user's global
445
+ * `promptBias` setting for this connection.
446
+ */
447
+ promptBias?: string;
448
+ }
449
+
450
+ /**
451
+ * Per-request reasoning override for `spindle.generate.*` calls. Use the
452
+ * `source` discriminator to pick how the backend resolves the effective
453
+ * reasoning settings:
454
+ *
455
+ * - `"inherit"` (default if `source` is omitted): apply the connection's
456
+ * `reasoning_bindings` if any, else the user's global setting. Same as
457
+ * leaving the `reasoning` field off entirely. Useful when you want to
458
+ * document intent without changing behaviour.
459
+ * - `"off"`: short-circuit. The provider's no-reasoning off-switch is
460
+ * applied unconditionally — even if `parameters` already carry an
461
+ * explicit `thinking` / `reasoning` block from the caller.
462
+ * - `"custom"`: use the explicit `apiReasoning` / `effort` / `thinkingDisplay`
463
+ * fields below for this request only. Omitted fields use their defaults
464
+ * (`apiReasoning: true`, `effort: "auto"`, `thinkingDisplay: "auto"`).
465
+ * Raw values supplied via `parameters` still win at the field level —
466
+ * the override only fills in unset fields, exactly like the inherited
467
+ * settings would.
468
+ */
469
+ export interface GenerationReasoningOverrideDTO {
470
+ source?: "inherit" | "off" | "custom";
471
+ apiReasoning?: boolean;
472
+ effort?: ReasoningEffortDTO;
473
+ thinkingDisplay?: ThinkingDisplayDTO;
474
+ }
475
+
351
476
  /**
352
477
  * Safe representation of a user's connection profile exposed to extensions.
353
478
  * Never contains the actual API key — only `has_api_key` boolean.
@@ -361,7 +486,20 @@ export interface ConnectionProfileDTO {
361
486
  preset_id: string | null;
362
487
  is_default: boolean;
363
488
  has_api_key: boolean;
489
+ /**
490
+ * Raw provider-specific metadata bag stored on the connection. Includes
491
+ * provider-quirk flags (Anthropic prompt caching, Google thinking budget
492
+ * config, etc.) and the original `reasoningBindings` blob — `reasoning_bindings`
493
+ * below is the parsed, typed view of that same blob.
494
+ */
364
495
  metadata: Record<string, unknown>;
496
+ /**
497
+ * Typed view of the connection's bound reasoning settings, parsed from
498
+ * `metadata.reasoningBindings`. `null` when the connection has no binding
499
+ * (in which case generation falls back to the user's global
500
+ * `reasoningSettings`).
501
+ */
502
+ reasoning_bindings: ConnectionReasoningBindingsDTO | null;
365
503
  created_at: number;
366
504
  updated_at: number;
367
505
  }
@@ -1637,6 +1775,50 @@ export interface SpindleCommandContextDTO {
1637
1775
  isGroupChat?: boolean;
1638
1776
  }
1639
1777
 
1778
+ // ─── UI Automation DTOs ─────────────────────────────────────────────────
1779
+
1780
+ /**
1781
+ * Read-only snapshot of a drawer tab discoverable via
1782
+ * {@link SpindleAPI.ui.getDrawerTabs}. Mirrors the metadata used by the
1783
+ * built-in Command Palette to render the "Panels" group.
1784
+ */
1785
+ export interface SpindleUIDrawerTabDTO {
1786
+ /** Stable id used by `openDrawerTab(id)`. */
1787
+ id: string;
1788
+ /** Short label shown beneath the sidebar icon (max ~8 characters). */
1789
+ shortName: string;
1790
+ /** Full title shown in menus and the command palette. */
1791
+ tabName: string;
1792
+ /** One-line description shown in the command palette. */
1793
+ tabDescription: string;
1794
+ /** Keywords used for command-palette fuzzy search. */
1795
+ keywords: string[];
1796
+ /** Whether the tab is built into Lumiverse or contributed by another extension. */
1797
+ source: "builtin" | "extension";
1798
+ /** For extension-contributed tabs, the owning extension's identifier. */
1799
+ extensionId?: string;
1800
+ }
1801
+
1802
+ /**
1803
+ * Read-only snapshot of a settings tab discoverable via
1804
+ * {@link SpindleAPI.ui.getSettingsTabs}. Restricted entries (`role` set) are
1805
+ * filtered out when the call resolves to a user that lacks the required role.
1806
+ */
1807
+ export interface SpindleUISettingsTabDTO {
1808
+ /** Stable id used by `openSettings(id)`. */
1809
+ id: string;
1810
+ /** Short label shown in the settings sidebar. */
1811
+ shortName: string;
1812
+ /** Full title shown in the settings header / command palette. */
1813
+ tabName: string;
1814
+ /** One-line description shown in the command palette. */
1815
+ tabDescription: string;
1816
+ /** Keywords used for command-palette fuzzy search. */
1817
+ keywords: string[];
1818
+ /** Set when the tab is only visible to certain roles. */
1819
+ role?: "admin" | "owner";
1820
+ }
1821
+
1640
1822
  // ─── Frontend Process Lifecycle DTOs ────────────────────────────────────
1641
1823
 
1642
1824
  /** High-level lifecycle state for a frontend process tracked by the backend host. */
@@ -2590,7 +2772,24 @@ export type WorkerToHost =
2590
2772
  scrape?: boolean;
2591
2773
  userId?: string;
2592
2774
  }
2593
- | { type: "web_search_get_settings"; requestId: string; userId?: string };
2775
+ | { type: "web_search_get_settings"; requestId: string; userId?: string }
2776
+ // ─── UI Automation (free tier) ────────────────────────────────────────
2777
+ | { type: "ui_get_drawer_tabs"; requestId: string; userId?: string }
2778
+ | { type: "ui_get_settings_tabs"; requestId: string; userId?: string }
2779
+ | {
2780
+ type: "ui_navigate";
2781
+ requestId: string;
2782
+ action:
2783
+ | "open_drawer_tab"
2784
+ | "close_drawer"
2785
+ | "open_settings"
2786
+ | "close_settings"
2787
+ | "open_command_palette"
2788
+ | "close_command_palette";
2789
+ tabId?: string;
2790
+ viewId?: string;
2791
+ userId?: string;
2792
+ };
2594
2793
 
2595
2794
  // ─── Host → Worker messages ──────────────────────────────────────────────
2596
2795
 
package/src/index.ts CHANGED
@@ -29,6 +29,11 @@ export type {
29
29
  ToolSchemaDTO,
30
30
  ToolCallDTO,
31
31
  GenerationRequestDTO,
32
+ GenerationReasoningOverrideDTO,
33
+ ReasoningEffortDTO,
34
+ ReasoningSettingsDTO,
35
+ ThinkingDisplayDTO,
36
+ ConnectionReasoningBindingsDTO,
32
37
  ChatAppendGenerationOptionsDTO,
33
38
  ChatAppendMessageOptionsDTO,
34
39
  StreamChunkDTO,
@@ -121,6 +126,8 @@ export type {
121
126
  SpindleModalItemDTO,
122
127
  SpindleCommandDTO,
123
128
  SpindleCommandContextDTO,
129
+ SpindleUIDrawerTabDTO,
130
+ SpindleUISettingsTabDTO,
124
131
  FrontendProcessStateDTO,
125
132
  FrontendProcessExitReasonDTO,
126
133
  FrontendProcessSpawnOptionsDTO,
@@ -72,6 +72,8 @@ import type {
72
72
  SpindleModalItemDTO,
73
73
  SpindleCommandDTO,
74
74
  SpindleCommandContextDTO,
75
+ SpindleUIDrawerTabDTO,
76
+ SpindleUISettingsTabDTO,
75
77
  FrontendProcessSpawnOptionsDTO,
76
78
  FrontendProcessListOptionsDTO,
77
79
  FrontendProcessInfoDTO,
@@ -299,6 +301,21 @@ export interface SpindleAPI {
299
301
  * `fetch()` uses, so it composes with `AbortSignal.timeout()` and
300
302
  * `AbortSignal.any([...])`.
301
303
  *
304
+ * ## Reasoning / extended thinking
305
+ *
306
+ * By default every generation inherits the resolved user's reasoning
307
+ * settings — the connection's `reasoning_bindings` if any, else the
308
+ * user-global `reasoningSettings`. The host translates that into the
309
+ * correct provider-specific knob (`thinking.budget_tokens`,
310
+ * `thinkingConfig.thinkingLevel`, `reasoning.effort`, `reasoning_effort`,
311
+ * etc.) so extensions don't have to.
312
+ *
313
+ * Use `input.reasoning` to override that resolution per-request:
314
+ * - `{ source: "off" }` — disable thinking for one cheap call.
315
+ * - `{ source: "custom", effort: "high" }` — dial effort up just for this call.
316
+ *
317
+ * See {@link GenerationReasoningOverrideDTO} for the full shape.
318
+ *
302
319
  * @example
303
320
  * ```ts
304
321
  * const controller = new AbortController()
@@ -614,6 +631,25 @@ export interface SpindleAPI {
614
631
  /**
615
632
  * Connection profile access (permission: "generation").
616
633
  * Returns safe representations — API keys are never exposed.
634
+ *
635
+ * The returned DTO carries a typed `reasoning_bindings` view of the
636
+ * connection's bound reasoning settings (parsed from `metadata.reasoningBindings`).
637
+ * Pair this with `GenerationRequestDTO.reasoning` to inspect what the
638
+ * connection is configured for and optionally override it per-request:
639
+ *
640
+ * @example
641
+ * ```ts
642
+ * const conn = await spindle.connections.get(connId);
643
+ * const bound = conn?.reasoning_bindings?.settings;
644
+ * if (bound?.apiReasoning) {
645
+ * await spindle.generate.raw({
646
+ * messages,
647
+ * connection_id: connId,
648
+ * // Force the bound effort one tier higher, just for this request.
649
+ * reasoning: { source: "custom", apiReasoning: true, effort: "max" },
650
+ * });
651
+ * }
652
+ * ```
617
653
  */
618
654
  connections: {
619
655
  /**
@@ -1522,6 +1558,77 @@ export interface SpindleAPI {
1522
1558
  getRole(userId?: string): Promise<SpindleUserRoleDTO>;
1523
1559
  };
1524
1560
 
1561
+ /**
1562
+ * UI automation (free tier — no permission needed).
1563
+ *
1564
+ * Enumerate the built-in drawer / settings tabs and trigger navigation
1565
+ * on the user's frontend. Same primitives the Command Palette uses, but
1566
+ * exposed to extensions so agents and automations can guide the user to
1567
+ * the right surface — for example, an onboarding flow that opens the
1568
+ * Connections drawer, or a "fix it" prompt that jumps to the relevant
1569
+ * settings tab.
1570
+ *
1571
+ * Listings include both built-in tabs (mirrored on the backend) and
1572
+ * extension-contributed drawer tabs the user's frontend has registered.
1573
+ * Navigation calls accept any tab id the frontend recognises — including
1574
+ * extension-added ids — so an extension can deep-link into another
1575
+ * extension's tab if it knows the id.
1576
+ *
1577
+ * @example
1578
+ * ```ts
1579
+ * // Enumerate every drawer tab the user can see and surface our own
1580
+ * // command-palette-style picker.
1581
+ * const tabs = await spindle.ui.getDrawerTabs({ userId })
1582
+ * await spindle.modal.open({
1583
+ * title: "Jump to…",
1584
+ * items: tabs.map((t) => ({ type: "key_value", label: t.tabName, value: t.tabDescription })),
1585
+ * })
1586
+ *
1587
+ * // Take the user straight to the Connections drawer.
1588
+ * await spindle.ui.openDrawerTab("connections", { userId })
1589
+ * ```
1590
+ */
1591
+ ui: {
1592
+ /**
1593
+ * Read the discoverable drawer tabs (built-in + extension-contributed)
1594
+ * visible to the resolved user. Extension tabs are only included once
1595
+ * the user's frontend has synced its registry over the WebSocket;
1596
+ * during connection bootstrap the list may be limited to built-ins.
1597
+ *
1598
+ * For user-scoped extensions, `userId` defaults to the installer.
1599
+ * Operator-scoped extensions should pass `userId` to scope the call.
1600
+ */
1601
+ getDrawerTabs(options?: { userId?: string }): Promise<SpindleUIDrawerTabDTO[]>;
1602
+ /**
1603
+ * Read the discoverable settings tabs visible to the resolved user.
1604
+ * Restricted tabs (e.g. `role: "owner"`) are filtered out for users
1605
+ * lacking the required role. When `userId` is omitted on operator-scoped
1606
+ * extensions, role gating is skipped and every tab is returned.
1607
+ */
1608
+ getSettingsTabs(options?: { userId?: string }): Promise<SpindleUISettingsTabDTO[]>;
1609
+ /**
1610
+ * Open the drawer to a specific tab. The id is forwarded verbatim, so
1611
+ * extension-contributed tabs are addressable too. The call resolves
1612
+ * once the host has dispatched the navigation event — the frontend
1613
+ * applies it asynchronously.
1614
+ */
1615
+ openDrawerTab(tabId: string, options?: { userId?: string }): Promise<void>;
1616
+ /** Close the drawer if it is currently open. */
1617
+ closeDrawer(options?: { userId?: string }): Promise<void>;
1618
+ /**
1619
+ * Open the settings modal. Pass a settings tab id (e.g. `"connections"`,
1620
+ * `"display"`) to land on a specific view; omit to open the user's last
1621
+ * settings view.
1622
+ */
1623
+ openSettings(viewId?: string, options?: { userId?: string }): Promise<void>;
1624
+ /** Close the settings modal if it is currently open. */
1625
+ closeSettings(options?: { userId?: string }): Promise<void>;
1626
+ /** Open the command palette overlay. */
1627
+ openCommandPalette(options?: { userId?: string }): Promise<void>;
1628
+ /** Close the command palette overlay if it is currently open. */
1629
+ closeCommandPalette(options?: { userId?: string }): Promise<void>;
1630
+ };
1631
+
1525
1632
  /** Show toast notifications in the frontend UI (free tier — no permission needed) */
1526
1633
  toast: {
1527
1634
  success(message: string, options?: { title?: string; duration?: number; /** For operator-scoped extensions only. */ userId?: string }): void;