@happyvertical/smrt-inference 0.0.0-stage → 0.60.15

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.
Files changed (107) hide show
  1. package/AGENTS.md +201 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +73 -2
  5. package/agents/fusions.md +92 -0
  6. package/agents/hosted.md +145 -0
  7. package/agents/resolver.md +65 -0
  8. package/agents/settings.md +84 -0
  9. package/dist/__smrt-register__.d.ts +2 -0
  10. package/dist/__smrt-register__.d.ts.map +1 -0
  11. package/dist/chunks/InferenceOverrideCollection-wl7sI-3C.js +398 -0
  12. package/dist/chunks/InferenceOverrideCollection-wl7sI-3C.js.map +1 -0
  13. package/dist/chunks/provider-config-4Bx8N52X.js +1847 -0
  14. package/dist/chunks/provider-config-4Bx8N52X.js.map +1 -0
  15. package/dist/classify.d.ts +32 -0
  16. package/dist/classify.d.ts.map +1 -0
  17. package/dist/config.d.ts +89 -0
  18. package/dist/config.d.ts.map +1 -0
  19. package/dist/errors.d.ts +51 -0
  20. package/dist/errors.d.ts.map +1 -0
  21. package/dist/executor.d.ts +45 -0
  22. package/dist/executor.d.ts.map +1 -0
  23. package/dist/fusion-store.d.ts +16 -0
  24. package/dist/fusion-store.d.ts.map +1 -0
  25. package/dist/fusion.d.ts +155 -0
  26. package/dist/fusion.d.ts.map +1 -0
  27. package/dist/gate.d.ts +143 -0
  28. package/dist/gate.d.ts.map +1 -0
  29. package/dist/gate.js +94 -0
  30. package/dist/gate.js.map +1 -0
  31. package/dist/hosted.d.ts +454 -0
  32. package/dist/hosted.d.ts.map +1 -0
  33. package/dist/index.d.ts +9 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +8 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/manifest.json +453 -0
  38. package/dist/models/InferenceOverride.d.ts +38 -0
  39. package/dist/models/InferenceOverride.d.ts.map +1 -0
  40. package/dist/models/InferenceOverrideCollection.d.ts +35 -0
  41. package/dist/models/InferenceOverrideCollection.d.ts.map +1 -0
  42. package/dist/models.d.ts +11 -0
  43. package/dist/models.d.ts.map +1 -0
  44. package/dist/models.js +2 -0
  45. package/dist/node.d.ts +110 -0
  46. package/dist/node.d.ts.map +1 -0
  47. package/dist/node.js +1361 -0
  48. package/dist/node.js.map +1 -0
  49. package/dist/provider-config.d.ts +113 -0
  50. package/dist/provider-config.d.ts.map +1 -0
  51. package/dist/register.d.ts +30 -0
  52. package/dist/register.d.ts.map +1 -0
  53. package/dist/resolver.d.ts +166 -0
  54. package/dist/resolver.d.ts.map +1 -0
  55. package/dist/resolver.js +288 -0
  56. package/dist/resolver.js.map +1 -0
  57. package/dist/server.d.ts +24 -0
  58. package/dist/server.d.ts.map +1 -0
  59. package/dist/server.js +985 -0
  60. package/dist/server.js.map +1 -0
  61. package/dist/settings/cache.d.ts +5 -0
  62. package/dist/settings/cache.d.ts.map +1 -0
  63. package/dist/settings/keys.d.ts +70 -0
  64. package/dist/settings/keys.d.ts.map +1 -0
  65. package/dist/settings/layers.d.ts +54 -0
  66. package/dist/settings/layers.d.ts.map +1 -0
  67. package/dist/settings/override-service.d.ts +119 -0
  68. package/dist/settings/override-service.d.ts.map +1 -0
  69. package/dist/settings/preferences.d.ts +137 -0
  70. package/dist/settings/preferences.d.ts.map +1 -0
  71. package/dist/settings/resolver.d.ts +34 -0
  72. package/dist/settings/resolver.d.ts.map +1 -0
  73. package/dist/settings/settings-service.d.ts +282 -0
  74. package/dist/settings/settings-service.d.ts.map +1 -0
  75. package/dist/settings/targets.d.ts +93 -0
  76. package/dist/settings/targets.d.ts.map +1 -0
  77. package/dist/smrt-knowledge.json +335 -0
  78. package/dist/smrt-knowledge.okf.md +80 -0
  79. package/dist/svelte/components/InferenceAliasEditor.svelte +210 -0
  80. package/dist/svelte/components/InferenceAliasEditor.svelte.d.ts +13 -0
  81. package/dist/svelte/components/InferenceAliasEditor.svelte.d.ts.map +1 -0
  82. package/dist/svelte/components/InferenceDefaultView.svelte +330 -0
  83. package/dist/svelte/components/InferenceDefaultView.svelte.d.ts +15 -0
  84. package/dist/svelte/components/InferenceDefaultView.svelte.d.ts.map +1 -0
  85. package/dist/svelte/components/InferenceFusionList.svelte +135 -0
  86. package/dist/svelte/components/InferenceFusionList.svelte.d.ts +16 -0
  87. package/dist/svelte/components/InferenceFusionList.svelte.d.ts.map +1 -0
  88. package/dist/svelte/components/InferenceSettingsPanel.svelte +345 -0
  89. package/dist/svelte/components/InferenceSettingsPanel.svelte.d.ts +65 -0
  90. package/dist/svelte/components/InferenceSettingsPanel.svelte.d.ts.map +1 -0
  91. package/dist/svelte/components/InferenceTierRow.svelte +199 -0
  92. package/dist/svelte/components/InferenceTierRow.svelte.d.ts +14 -0
  93. package/dist/svelte/components/InferenceTierRow.svelte.d.ts.map +1 -0
  94. package/dist/svelte/components/InferenceUsageTable.svelte +127 -0
  95. package/dist/svelte/components/InferenceUsageTable.svelte.d.ts +15 -0
  96. package/dist/svelte/components/InferenceUsageTable.svelte.d.ts.map +1 -0
  97. package/dist/svelte/index.d.ts +17 -0
  98. package/dist/svelte/index.d.ts.map +1 -0
  99. package/dist/svelte/index.js +14 -0
  100. package/dist/svelte/types.d.ts +197 -0
  101. package/dist/svelte/types.d.ts.map +1 -0
  102. package/dist/svelte/types.js +96 -0
  103. package/dist/types.d.ts +47 -0
  104. package/dist/types.d.ts.map +1 -0
  105. package/dist/types.js +13 -0
  106. package/dist/types.js.map +1 -0
  107. package/package.json +105 -3
@@ -0,0 +1,135 @@
1
+ <script lang="ts">
2
+ /**
3
+ * Fusions from the registry, config and app config entries (#4753 owns
4
+ * their meaning). Registry and config fusions are read-only; app entries
5
+ * are edited as JSON. There is deliberately no authoring form.
6
+ */
7
+ import type { InferenceFusionChange, InferenceFusionView } from '../types.js';
8
+
9
+ interface InferenceFusionListProps {
10
+ fusions: InferenceFusionView[];
11
+ editable: boolean;
12
+ busy: boolean;
13
+ onSaveFusion?: (change: InferenceFusionChange) => void;
14
+ }
15
+
16
+ const { fusions, editable, busy, onSaveFusion }: InferenceFusionListProps =
17
+ $props();
18
+
19
+ let errors = $state<Record<string, string>>({});
20
+
21
+ function parse(name: string, raw: string): Record<string, unknown> | null {
22
+ try {
23
+ const value = JSON.parse(raw) as unknown;
24
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
25
+ errors = { ...errors, [name]: 'A fusion is a JSON object.' };
26
+ return null;
27
+ }
28
+ errors = { ...errors, [name]: '' };
29
+ return value as Record<string, unknown>;
30
+ } catch {
31
+ errors = { ...errors, [name]: 'Not valid JSON.' };
32
+ return null;
33
+ }
34
+ }
35
+
36
+ function save(event: SubmitEvent, existing?: string): void {
37
+ event.preventDefault();
38
+ if (!onSaveFusion) return;
39
+ const fields = new FormData(event.currentTarget as HTMLFormElement);
40
+ const name = existing ?? String(fields.get('fusionName') ?? '').trim();
41
+ if (!name) return;
42
+ const definition = parse(
43
+ existing ?? '__new__',
44
+ String(fields.get('definition') ?? ''),
45
+ );
46
+ if (definition) onSaveFusion({ name, definition });
47
+ }
48
+ </script>
49
+
50
+ <div class="ifl" data-testid="inference-fusions">
51
+ {#each fusions as fusion (fusion.name)}
52
+ <div class="ifl-item">
53
+ <div class="ifl-head">
54
+ <strong>{fusion.name}</strong>
55
+ <span class="ifl-label">{fusion.source}</span>
56
+ {#if fusion.description}<span class="ifl-label">{fusion.description}</span>{/if}
57
+ </div>
58
+ {#if editable && fusion.editable}
59
+ <form onsubmit={(event) => save(event, fusion.name)}>
60
+ <textarea
61
+ name="definition"
62
+ aria-label={`${fusion.name} JSON`}
63
+ rows="6"
64
+ disabled={busy}
65
+ value={JSON.stringify(fusion.definition, null, 2)}
66
+ ></textarea>
67
+ {#if errors[fusion.name]}<p class="ifl-label" role="alert">{errors[fusion.name]}</p>{/if}
68
+ <div class="ifl-actions">
69
+ <button type="submit" disabled={busy || !onSaveFusion}>Save</button>
70
+ <button
71
+ type="button"
72
+ disabled={busy || !onSaveFusion}
73
+ onclick={() => onSaveFusion?.({ name: fusion.name, definition: null })}
74
+ >
75
+ Remove
76
+ </button>
77
+ </div>
78
+ </form>
79
+ {:else}
80
+ <pre class="ifl-pre">{JSON.stringify(fusion.definition, null, 2)}</pre>
81
+ {/if}
82
+ </div>
83
+ {:else}
84
+ <p class="ifl-label">No fusions are defined.</p>
85
+ {/each}
86
+ {#if editable && onSaveFusion}
87
+ <form class="ifl-item" onsubmit={(event) => save(event)} data-testid="inference-fusion-new">
88
+ <label>
89
+ <span class="ifl-label">New config entry</span>
90
+ <input name="fusionName" required disabled={busy} />
91
+ </label>
92
+ <textarea name="definition" aria-label="New fusion JSON" rows="4" disabled={busy}>{'{}'}</textarea>
93
+ {#if errors.__new__}<p class="ifl-label" role="alert">{errors.__new__}</p>{/if}
94
+ <button type="submit" disabled={busy}>Add</button>
95
+ </form>
96
+ {/if}
97
+ </div>
98
+
99
+ <style>
100
+ @layer smrt.reset, smrt.structure, smrt.theme;
101
+ @layer smrt.theme {
102
+ .ifl {
103
+ display: flex;
104
+ flex-direction: column;
105
+ gap: 0.75rem;
106
+ }
107
+ .ifl-item {
108
+ display: flex;
109
+ flex-direction: column;
110
+ gap: 0.375rem;
111
+ }
112
+ .ifl-head,
113
+ .ifl-actions {
114
+ display: flex;
115
+ gap: 0.5rem;
116
+ align-items: center;
117
+ }
118
+ .ifl-pre,
119
+ textarea {
120
+ margin: 0;
121
+ padding: 0.5rem;
122
+ border-radius: 0.375rem;
123
+ background: var(--smrt-color-surface-variant);
124
+ font-family: ui-monospace, monospace;
125
+ font-size: 0.8125rem;
126
+ white-space: pre-wrap;
127
+ width: 100%;
128
+ }
129
+ .ifl-label {
130
+ margin: 0;
131
+ font-size: 0.8125rem;
132
+ color: var(--smrt-color-on-surface-variant);
133
+ }
134
+ }
135
+ </style>
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Fusions from the registry, config and app config entries (#4753 owns
3
+ * their meaning). Registry and config fusions are read-only; app entries
4
+ * are edited as JSON. There is deliberately no authoring form.
5
+ */
6
+ import type { InferenceFusionChange, InferenceFusionView } from '../types.js';
7
+ interface InferenceFusionListProps {
8
+ fusions: InferenceFusionView[];
9
+ editable: boolean;
10
+ busy: boolean;
11
+ onSaveFusion?: (change: InferenceFusionChange) => void;
12
+ }
13
+ declare const InferenceFusionList: import("svelte").Component<InferenceFusionListProps, {}, "">;
14
+ type InferenceFusionList = ReturnType<typeof InferenceFusionList>;
15
+ export default InferenceFusionList;
16
+ //# sourceMappingURL=InferenceFusionList.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InferenceFusionList.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/InferenceFusionList.svelte.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAG9E,UAAU,wBAAwB;IAChC,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;CACxD;AAmFD,QAAA,MAAM,mBAAmB,8DAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}
@@ -0,0 +1,345 @@
1
+ <script lang="ts">
2
+ /**
3
+ * InferenceSettingsPanel — the shared inference settings surface (#4754).
4
+ *
5
+ * Purely presentational, like smrt-prompts' `PromptSettingsPanel`: rows and
6
+ * callbacks in, no fetching, no authorization decision. The host loads rows
7
+ * with `InferenceSettingsService` (`@happyvertical/smrt-inference/server`)
8
+ * and wires each callback to its own permission-checked server action.
9
+ *
10
+ * The default view is the whole screen for a one-provider app. Advanced
11
+ * (tier ladder, `auto`'s default tier, aliases, fusions) is collapsed and
12
+ * not rendered until opened. Keys leave only through `onSaveKey`; the panel
13
+ * never receives one back (`defaults.keySet` says whether one is stored).
14
+ */
15
+ import type {
16
+ InferenceAliasChange,
17
+ InferenceAliasView,
18
+ InferenceCandidateView,
19
+ InferenceConnectionRequest,
20
+ InferenceDefaultsChange,
21
+ InferenceDefaultsView,
22
+ InferenceDefaultTierChange,
23
+ InferenceDefaultTierView,
24
+ InferenceDiscoveryView,
25
+ InferenceFusionChange,
26
+ InferenceFusionView,
27
+ InferenceKeyChange,
28
+ InferenceProviderView,
29
+ InferenceSettingsScope,
30
+ InferenceSettingsTier,
31
+ InferenceTestResultView,
32
+ InferenceTierChange,
33
+ InferenceTierView,
34
+ InferenceUsageDimension,
35
+ InferenceUsageView,
36
+ } from '../types.js';
37
+ import {
38
+ defaultTierRevertPreview,
39
+ INFERENCE_SETTINGS_TIERS,
40
+ inferenceLevelLabel,
41
+ isRefAllowed,
42
+ } from '../types.js';
43
+ import InferenceAliasEditor from './InferenceAliasEditor.svelte';
44
+ import InferenceDefaultView from './InferenceDefaultView.svelte';
45
+ import InferenceFusionList from './InferenceFusionList.svelte';
46
+ import InferenceTierRow from './InferenceTierRow.svelte';
47
+ import InferenceUsageTable from './InferenceUsageTable.svelte';
48
+
49
+ export interface InferenceSettingsPanelProps {
50
+ /** The current user (or tenant) choices for the default view. */
51
+ defaults?: InferenceDefaultsView;
52
+ /** Provider choices (`InferenceSettingsService.listProviderOptions()`). */
53
+ providers?: InferenceProviderView[];
54
+ /** Local discovery results, when the host ran the #4674 probe. */
55
+ discoveredModels?: InferenceDiscoveryView[];
56
+ /** Tier rows (`listInferenceSettings()`). */
57
+ tiers?: InferenceTierView[];
58
+ /** `auto`'s default tier (`getDefaultTierSetting()`). */
59
+ defaultTier?: InferenceDefaultTierView | null;
60
+ /** Aliases (`listInferenceAliases()`). */
61
+ aliases?: InferenceAliasView[];
62
+ /** Fusions (`listInferenceFusions()`); render-only dependency on #4753. */
63
+ fusions?: InferenceFusionView[];
64
+ /** Usage report (`usage()`); the Usage tab shows when this or `onUsageGroupBy` is set. */
65
+ usage?: InferenceUsageView | null;
66
+ /**
67
+ * Which scope Advanced edits write. `tenant` restricts choices to the
68
+ * allow-list (display only; the server enforces it) and makes aliases and
69
+ * fusions read-only (they are app-scope definitions).
70
+ */
71
+ scope?: InferenceSettingsScope;
72
+ /** Open Advanced on first render. Default `false`. */
73
+ advancedOpen?: boolean;
74
+ /** Disable every control while a save is in flight. */
75
+ busy?: boolean;
76
+ message?: string | null;
77
+ error?: string | null;
78
+ /**
79
+ * Identity of what is being edited (tenant or user id). Unsaved edits are
80
+ * discarded whenever it changes, or, when omitted, whenever `tiers` or
81
+ * `defaults` is replaced (a reloaded server load).
82
+ */
83
+ contextKey?: unknown;
84
+ onSaveDefaults?: (change: InferenceDefaultsChange) => void;
85
+ /** The only way a key leaves the panel. The host stores it through smrt-secrets. */
86
+ onSaveKey?: (change: InferenceKeyChange) => void | Promise<void>;
87
+ onTestConnection?: (
88
+ request: InferenceConnectionRequest,
89
+ ) => Promise<InferenceTestResultView>;
90
+ onDiscoverModels?: () => void;
91
+ onSaveTier?: (change: InferenceTierChange) => void;
92
+ onSaveDefaultTier?: (change: InferenceDefaultTierChange) => void;
93
+ onSaveAlias?: (change: InferenceAliasChange) => void;
94
+ onTestCandidate?: (
95
+ candidate: InferenceCandidateView,
96
+ ) => Promise<InferenceTestResultView>;
97
+ onSaveFusion?: (change: InferenceFusionChange) => void;
98
+ onUsageGroupBy?: (by: InferenceUsageDimension[]) => void;
99
+ }
100
+
101
+ const {
102
+ defaults = {},
103
+ providers = [],
104
+ discoveredModels = [],
105
+ tiers = [],
106
+ defaultTier = null,
107
+ aliases = [],
108
+ fusions = [],
109
+ usage = null,
110
+ scope = 'app',
111
+ advancedOpen = false,
112
+ busy = false,
113
+ message = null,
114
+ error = null,
115
+ contextKey,
116
+ onSaveDefaults,
117
+ onSaveKey,
118
+ onTestConnection,
119
+ onDiscoverModels,
120
+ onSaveTier,
121
+ onSaveDefaultTier,
122
+ onSaveAlias,
123
+ onTestCandidate,
124
+ onSaveFusion,
125
+ onUsageGroupBy,
126
+ }: InferenceSettingsPanelProps = $props();
127
+
128
+ let tab = $state<'settings' | 'usage'>('settings');
129
+ // svelte-ignore state_referenced_locally
130
+ let advanced = $state(advancedOpen);
131
+
132
+ const showUsage = $derived(usage !== null || onUsageGroupBy !== undefined);
133
+ const definitionsEditable = $derived(scope === 'app');
134
+ // Remount on a context change so unsaved edits never cross tenants/users.
135
+ const defaultsKey = $derived(contextKey ?? defaults);
136
+ const advancedKey = $derived(contextKey ?? tiers);
137
+
138
+ function saveDefaultTier(event: SubmitEvent): void {
139
+ event.preventDefault();
140
+ if (!onSaveDefaultTier) return;
141
+ const value = String(
142
+ new FormData(event.currentTarget as HTMLFormElement).get('autoTier') ?? '',
143
+ );
144
+ onSaveDefaultTier({
145
+ scope,
146
+ tier: value === '' ? null : (value as InferenceSettingsTier),
147
+ });
148
+ }
149
+
150
+ function tierAllowed(tier: InferenceSettingsTier): boolean {
151
+ return (
152
+ scope !== 'tenant' ||
153
+ isRefAllowed(`tier:${tier}`, defaultTier?.tenantAllowList)
154
+ );
155
+ }
156
+ </script>
157
+
158
+ <section class="isp" data-testid="inference-settings-panel" data-smrt-component="InferenceSettingsPanel">
159
+ {#if message}<p class="isp-flash" role="status">{message}</p>{/if}
160
+ {#if error}<p class="isp-flash isp-flash-error" role="alert">{error}</p>{/if}
161
+
162
+ {#if showUsage}
163
+ <div class="isp-tabs" role="tablist">
164
+ <button
165
+ type="button"
166
+ role="tab"
167
+ aria-selected={tab === 'settings'}
168
+ onclick={() => (tab = 'settings')}
169
+ >
170
+ Settings
171
+ </button>
172
+ <button
173
+ type="button"
174
+ role="tab"
175
+ aria-selected={tab === 'usage'}
176
+ onclick={() => (tab = 'usage')}
177
+ >
178
+ Usage
179
+ </button>
180
+ </div>
181
+ {/if}
182
+
183
+ {#if tab === 'usage' && showUsage}
184
+ <div role="tabpanel">
185
+ <InferenceUsageTable {usage} {busy} {onUsageGroupBy} />
186
+ </div>
187
+ {:else}
188
+ <div role={showUsage ? 'tabpanel' : undefined} class="isp-settings">
189
+ {#key defaultsKey}
190
+ <InferenceDefaultView
191
+ {defaults}
192
+ {providers}
193
+ {discoveredModels}
194
+ {busy}
195
+ {onSaveDefaults}
196
+ {onSaveKey}
197
+ {onTestConnection}
198
+ {onDiscoverModels}
199
+ />
200
+ {/key}
201
+
202
+ <button
203
+ type="button"
204
+ class="isp-advanced-toggle"
205
+ aria-expanded={advanced}
206
+ aria-controls="isp-advanced"
207
+ onclick={() => (advanced = !advanced)}
208
+ >
209
+ Advanced
210
+ </button>
211
+
212
+ {#if advanced}
213
+ <div id="isp-advanced" class="isp-advanced" data-testid="inference-advanced">
214
+ {#key advancedKey}
215
+ <section class="isp-section">
216
+ <h3>Tier ladder</h3>
217
+ {#each tiers as row (row.tier)}
218
+ <InferenceTierRow
219
+ {row}
220
+ {scope}
221
+ {providers}
222
+ {aliases}
223
+ {fusions}
224
+ {busy}
225
+ {onSaveTier}
226
+ />
227
+ {:else}
228
+ <p class="isp-hint">No tier rows were provided.</p>
229
+ {/each}
230
+ </section>
231
+
232
+ {#if defaultTier}
233
+ <section class="isp-section">
234
+ <h3><code>auto</code> default tier</h3>
235
+ <form class="isp-auto" onsubmit={saveDefaultTier} data-testid="inference-auto-tier">
236
+ <span>
237
+ Now {defaultTier.effectiveTier} ({inferenceLevelLabel(defaultTier.supplyingLevel)})
238
+ </span>
239
+ <label>
240
+ <span class="isp-hint">auto resolves to</span>
241
+ <select
242
+ name="autoTier"
243
+ disabled={busy}
244
+ value={(scope === 'app' ? defaultTier.appTier : defaultTier.tenantTier) ?? ''}
245
+ >
246
+ <option value="">Inherit ({defaultTierRevertPreview(defaultTier, scope)})</option>
247
+ {#each INFERENCE_SETTINGS_TIERS as tier (tier)}
248
+ <option value={tier} disabled={!tierAllowed(tier)}>{tier}</option>
249
+ {/each}
250
+ </select>
251
+ </label>
252
+ <button type="submit" disabled={busy || !onSaveDefaultTier}>Save</button>
253
+ </form>
254
+ </section>
255
+ {/if}
256
+
257
+ <section class="isp-section">
258
+ <h3>Aliases</h3>
259
+ {#each aliases as alias (alias.name)}
260
+ <InferenceAliasEditor
261
+ {alias}
262
+ editable={definitionsEditable && !!onSaveAlias}
263
+ {busy}
264
+ {onSaveAlias}
265
+ {onTestCandidate}
266
+ />
267
+ {:else}
268
+ <p class="isp-hint">No aliases are defined.</p>
269
+ {/each}
270
+ {#if definitionsEditable && onSaveAlias}
271
+ <InferenceAliasEditor
272
+ alias={{ name: '', candidates: [] }}
273
+ editable
274
+ isNew
275
+ {busy}
276
+ {onSaveAlias}
277
+ {onTestCandidate}
278
+ />
279
+ {/if}
280
+ </section>
281
+
282
+ <section class="isp-section">
283
+ <h3>Fusions</h3>
284
+ <InferenceFusionList
285
+ {fusions}
286
+ editable={definitionsEditable}
287
+ {busy}
288
+ {onSaveFusion}
289
+ />
290
+ </section>
291
+ {/key}
292
+ </div>
293
+ {/if}
294
+ </div>
295
+ {/if}
296
+ </section>
297
+
298
+ <style>
299
+ @layer smrt.reset, smrt.structure, smrt.theme;
300
+ @layer smrt.theme {
301
+ .isp,
302
+ .isp-settings,
303
+ .isp-advanced {
304
+ display: flex;
305
+ flex-direction: column;
306
+ gap: 1rem;
307
+ }
308
+ .isp-tabs {
309
+ display: flex;
310
+ gap: 0.5rem;
311
+ border-bottom: var(--smrt-hairline);
312
+ }
313
+ .isp-tabs [aria-selected='true'] {
314
+ font-weight: 600;
315
+ }
316
+ .isp-flash {
317
+ margin: 0;
318
+ padding: 0.625rem 0.75rem;
319
+ border-radius: 0.375rem;
320
+ background: var(--smrt-color-surface-variant);
321
+ }
322
+ .isp-flash-error {
323
+ color: var(--smrt-color-error);
324
+ background: var(--smrt-color-error-container);
325
+ }
326
+ .isp-advanced-toggle {
327
+ align-self: flex-start;
328
+ }
329
+ .isp-section h3 {
330
+ margin: 0 0 0.5rem;
331
+ font-size: 1rem;
332
+ }
333
+ .isp-auto {
334
+ display: flex;
335
+ gap: 0.75rem;
336
+ align-items: flex-end;
337
+ flex-wrap: wrap;
338
+ }
339
+ .isp-hint {
340
+ margin: 0;
341
+ font-size: 0.8125rem;
342
+ color: var(--smrt-color-on-surface-variant);
343
+ }
344
+ }
345
+ </style>
@@ -0,0 +1,65 @@
1
+ /**
2
+ * InferenceSettingsPanel — the shared inference settings surface (#4754).
3
+ *
4
+ * Purely presentational, like smrt-prompts' `PromptSettingsPanel`: rows and
5
+ * callbacks in, no fetching, no authorization decision. The host loads rows
6
+ * with `InferenceSettingsService` (`@happyvertical/smrt-inference/server`)
7
+ * and wires each callback to its own permission-checked server action.
8
+ *
9
+ * The default view is the whole screen for a one-provider app. Advanced
10
+ * (tier ladder, `auto`'s default tier, aliases, fusions) is collapsed and
11
+ * not rendered until opened. Keys leave only through `onSaveKey`; the panel
12
+ * never receives one back (`defaults.keySet` says whether one is stored).
13
+ */
14
+ import type { InferenceAliasChange, InferenceAliasView, InferenceCandidateView, InferenceConnectionRequest, InferenceDefaultsChange, InferenceDefaultsView, InferenceDefaultTierChange, InferenceDefaultTierView, InferenceDiscoveryView, InferenceFusionChange, InferenceFusionView, InferenceKeyChange, InferenceProviderView, InferenceSettingsScope, InferenceTestResultView, InferenceTierChange, InferenceTierView, InferenceUsageDimension, InferenceUsageView } from '../types.js';
15
+ export interface InferenceSettingsPanelProps {
16
+ /** The current user (or tenant) choices for the default view. */
17
+ defaults?: InferenceDefaultsView;
18
+ /** Provider choices (`InferenceSettingsService.listProviderOptions()`). */
19
+ providers?: InferenceProviderView[];
20
+ /** Local discovery results, when the host ran the #4674 probe. */
21
+ discoveredModels?: InferenceDiscoveryView[];
22
+ /** Tier rows (`listInferenceSettings()`). */
23
+ tiers?: InferenceTierView[];
24
+ /** `auto`'s default tier (`getDefaultTierSetting()`). */
25
+ defaultTier?: InferenceDefaultTierView | null;
26
+ /** Aliases (`listInferenceAliases()`). */
27
+ aliases?: InferenceAliasView[];
28
+ /** Fusions (`listInferenceFusions()`); render-only dependency on #4753. */
29
+ fusions?: InferenceFusionView[];
30
+ /** Usage report (`usage()`); the Usage tab shows when this or `onUsageGroupBy` is set. */
31
+ usage?: InferenceUsageView | null;
32
+ /**
33
+ * Which scope Advanced edits write. `tenant` restricts choices to the
34
+ * allow-list (display only; the server enforces it) and makes aliases and
35
+ * fusions read-only (they are app-scope definitions).
36
+ */
37
+ scope?: InferenceSettingsScope;
38
+ /** Open Advanced on first render. Default `false`. */
39
+ advancedOpen?: boolean;
40
+ /** Disable every control while a save is in flight. */
41
+ busy?: boolean;
42
+ message?: string | null;
43
+ error?: string | null;
44
+ /**
45
+ * Identity of what is being edited (tenant or user id). Unsaved edits are
46
+ * discarded whenever it changes, or, when omitted, whenever `tiers` or
47
+ * `defaults` is replaced (a reloaded server load).
48
+ */
49
+ contextKey?: unknown;
50
+ onSaveDefaults?: (change: InferenceDefaultsChange) => void;
51
+ /** The only way a key leaves the panel. The host stores it through smrt-secrets. */
52
+ onSaveKey?: (change: InferenceKeyChange) => void | Promise<void>;
53
+ onTestConnection?: (request: InferenceConnectionRequest) => Promise<InferenceTestResultView>;
54
+ onDiscoverModels?: () => void;
55
+ onSaveTier?: (change: InferenceTierChange) => void;
56
+ onSaveDefaultTier?: (change: InferenceDefaultTierChange) => void;
57
+ onSaveAlias?: (change: InferenceAliasChange) => void;
58
+ onTestCandidate?: (candidate: InferenceCandidateView) => Promise<InferenceTestResultView>;
59
+ onSaveFusion?: (change: InferenceFusionChange) => void;
60
+ onUsageGroupBy?: (by: InferenceUsageDimension[]) => void;
61
+ }
62
+ declare const InferenceSettingsPanel: import("svelte").Component<InferenceSettingsPanelProps, {}, "">;
63
+ type InferenceSettingsPanel = ReturnType<typeof InferenceSettingsPanel>;
64
+ export default InferenceSettingsPanel;
65
+ //# sourceMappingURL=InferenceSettingsPanel.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InferenceSettingsPanel.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/InferenceSettingsPanel.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EACV,oBAAoB,EACpB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC1B,uBAAuB,EACvB,qBAAqB,EACrB,0BAA0B,EAC1B,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EAEtB,uBAAuB,EACvB,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAcrB,MAAM,WAAW,2BAA2B;IAC1C,iEAAiE;IACjE,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,2EAA2E;IAC3E,SAAS,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACpC,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAC5C,6CAA6C;IAC7C,KAAK,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC5B,yDAAyD;IACzD,WAAW,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC9C,0CAA0C;IAC1C,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC/B,2EAA2E;IAC3E,OAAO,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAChC,0FAA0F;IAC1F,KAAK,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAClC;;;;OAIG;IACH,KAAK,CAAC,EAAE,sBAAsB,CAAC;IAC/B,sDAAsD;IACtD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uDAAuD;IACvD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAC3D,oFAAoF;IACpF,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,gBAAgB,CAAC,EAAE,CACjB,OAAO,EAAE,0BAA0B,KAChC,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACtC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACnD,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACjE,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACrD,eAAe,CAAC,EAAE,CAChB,SAAS,EAAE,sBAAsB,KAC9B,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACtC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACvD,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,uBAAuB,EAAE,KAAK,IAAI,CAAC;CAC1D;AA8JD,QAAA,MAAM,sBAAsB,iEAAwC,CAAC;AACrE,KAAK,sBAAsB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACxE,eAAe,sBAAsB,CAAC"}