@happyvertical/smrt-inference 0.0.0-stage → 0.60.16

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 (112) hide show
  1. package/AGENTS.md +206 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +73 -2
  5. package/agents/fusions.md +105 -0
  6. package/agents/hosted.md +161 -0
  7. package/agents/resolver.md +65 -0
  8. package/agents/settings.md +107 -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-Dat4TrK5.js +423 -0
  12. package/dist/chunks/InferenceOverrideCollection-Dat4TrK5.js.map +1 -0
  13. package/dist/chunks/provider-config-BSpIQRVM.js +1873 -0
  14. package/dist/chunks/provider-config-BSpIQRVM.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 +461 -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 +1414 -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 +291 -0
  56. package/dist/resolver.js.map +1 -0
  57. package/dist/server.d.ts +25 -0
  58. package/dist/server.d.ts.map +1 -0
  59. package/dist/server.js +1138 -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 +68 -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 +41 -0
  72. package/dist/settings/resolver.d.ts.map +1 -0
  73. package/dist/settings/settings-service.d.ts +355 -0
  74. package/dist/settings/settings-service.d.ts.map +1 -0
  75. package/dist/settings/targets.d.ts +112 -0
  76. package/dist/settings/targets.d.ts.map +1 -0
  77. package/dist/settings/transcripts.d.ts +33 -0
  78. package/dist/settings/transcripts.d.ts.map +1 -0
  79. package/dist/smrt-knowledge.json +341 -0
  80. package/dist/smrt-knowledge.okf.md +80 -0
  81. package/dist/svelte/components/InferenceAliasEditor.svelte +210 -0
  82. package/dist/svelte/components/InferenceAliasEditor.svelte.d.ts +13 -0
  83. package/dist/svelte/components/InferenceAliasEditor.svelte.d.ts.map +1 -0
  84. package/dist/svelte/components/InferenceDefaultView.svelte +330 -0
  85. package/dist/svelte/components/InferenceDefaultView.svelte.d.ts +15 -0
  86. package/dist/svelte/components/InferenceDefaultView.svelte.d.ts.map +1 -0
  87. package/dist/svelte/components/InferenceFusionList.svelte +141 -0
  88. package/dist/svelte/components/InferenceFusionList.svelte.d.ts +16 -0
  89. package/dist/svelte/components/InferenceFusionList.svelte.d.ts.map +1 -0
  90. package/dist/svelte/components/InferenceSettingsPanel.svelte +392 -0
  91. package/dist/svelte/components/InferenceSettingsPanel.svelte.d.ts +84 -0
  92. package/dist/svelte/components/InferenceSettingsPanel.svelte.d.ts.map +1 -0
  93. package/dist/svelte/components/InferenceTierRow.svelte +199 -0
  94. package/dist/svelte/components/InferenceTierRow.svelte.d.ts +14 -0
  95. package/dist/svelte/components/InferenceTierRow.svelte.d.ts.map +1 -0
  96. package/dist/svelte/components/InferenceTranscriptSettings.svelte +165 -0
  97. package/dist/svelte/components/InferenceTranscriptSettings.svelte.d.ts +18 -0
  98. package/dist/svelte/components/InferenceTranscriptSettings.svelte.d.ts.map +1 -0
  99. package/dist/svelte/components/InferenceUsageTable.svelte +177 -0
  100. package/dist/svelte/components/InferenceUsageTable.svelte.d.ts +21 -0
  101. package/dist/svelte/components/InferenceUsageTable.svelte.d.ts.map +1 -0
  102. package/dist/svelte/index.d.ts +17 -0
  103. package/dist/svelte/index.d.ts.map +1 -0
  104. package/dist/svelte/index.js +14 -0
  105. package/dist/svelte/types.d.ts +262 -0
  106. package/dist/svelte/types.d.ts.map +1 -0
  107. package/dist/svelte/types.js +124 -0
  108. package/dist/types.d.ts +47 -0
  109. package/dist/types.d.ts.map +1 -0
  110. package/dist/types.js +13 -0
  111. package/dist/types.js.map +1 -0
  112. package/package.json +105 -3
@@ -0,0 +1,199 @@
1
+ <script lang="ts">
2
+ /**
3
+ * One rung of the tier ladder: "same as default", a model, an alias or a
4
+ * fusion. In the tenant scope, targets the allow-list does not open are
5
+ * disabled (display only; the server enforces the list on every write).
6
+ */
7
+ import { untrack } from 'svelte';
8
+ import type {
9
+ InferenceAliasView,
10
+ InferenceFusionView,
11
+ InferenceProviderView,
12
+ InferenceSettingsScope,
13
+ InferenceTargetView,
14
+ InferenceTierChange,
15
+ InferenceTierView,
16
+ } from '../types.js';
17
+ import {
18
+ inferenceLevelLabel,
19
+ isRefAllowed,
20
+ targetViewRef,
21
+ tierRevertPreview,
22
+ } from '../types.js';
23
+
24
+ interface InferenceTierRowProps {
25
+ row: InferenceTierView;
26
+ scope: InferenceSettingsScope;
27
+ providers: InferenceProviderView[];
28
+ aliases: InferenceAliasView[];
29
+ fusions: InferenceFusionView[];
30
+ busy: boolean;
31
+ onSaveTier?: (change: InferenceTierChange) => void;
32
+ }
33
+
34
+ const {
35
+ row,
36
+ scope,
37
+ providers,
38
+ aliases,
39
+ fusions,
40
+ busy,
41
+ onSaveTier,
42
+ }: InferenceTierRowProps = $props();
43
+
44
+ type Kind = 'default' | 'model' | 'alias' | 'fusion';
45
+
46
+ function kindOf(target: InferenceTargetView | null | undefined): Kind {
47
+ if (!target || Object.keys(target).length === 0) return 'default';
48
+ if (target.kind === 'fusion' || target.fusion) return 'fusion';
49
+ if (target.alias) return 'alias';
50
+ return 'model';
51
+ }
52
+
53
+ const own = untrack(
54
+ () => (scope === 'app' ? row.appTarget : row.tenantTarget) ?? null,
55
+ );
56
+ let kind = $state<Kind>(kindOf(own));
57
+ let provider = $state(own?.provider ?? '');
58
+ let model = $state(own?.model ?? '');
59
+ let alias = $state(own?.alias ?? '');
60
+ let fusion = $state(own?.fusion ?? '');
61
+
62
+ const restricted = $derived(scope === 'tenant');
63
+ const allowed = (target: InferenceTargetView) =>
64
+ !restricted || isRefAllowed(targetViewRef(target), row.tenantAllowList);
65
+ const modelAllowed = $derived(
66
+ !restricted ||
67
+ (row.tenantAllowList ?? []).some(
68
+ (pattern) => pattern === '*' || pattern.startsWith('model:'),
69
+ ),
70
+ );
71
+ const aliasAllowed = $derived(
72
+ aliases.some((entry) => allowed({ alias: entry.name })),
73
+ );
74
+ const fusionAllowed = $derived(
75
+ fusions.some((entry) => allowed({ kind: 'fusion', fusion: entry.name })),
76
+ );
77
+
78
+ function target(): InferenceTargetView | null {
79
+ if (kind === 'model') {
80
+ return provider
81
+ ? { provider, model: model.trim() }
82
+ : { model: model.trim() };
83
+ }
84
+ if (kind === 'alias') return { alias };
85
+ if (kind === 'fusion') return { kind: 'fusion', fusion };
86
+ return null;
87
+ }
88
+
89
+ function submit(event: SubmitEvent): void {
90
+ event.preventDefault();
91
+ onSaveTier?.({ tier: row.tier, scope, target: target() });
92
+ }
93
+ </script>
94
+
95
+ <form class="itr" onsubmit={submit} data-testid={`inference-tier-${row.tier}`}>
96
+ <div class="itr-head">
97
+ <strong class="itr-tier">{row.tier}</strong>
98
+ <span class="itr-effective">{row.effectiveLabel}</span>
99
+ <span class="itr-level">{inferenceLevelLabel(row.supplyingLevel)}</span>
100
+ </div>
101
+ {#if restricted && row.tenantBlocked}
102
+ <p class="itr-note" role="note">
103
+ This tenant binding is no longer on the allow-list and is not in effect.
104
+ </p>
105
+ {/if}
106
+ <div class="itr-controls">
107
+ <label>
108
+ <span class="itr-label">Target for {row.tier}</span>
109
+ <select name="kind" bind:value={kind} disabled={busy}>
110
+ <option value="default">Same as default</option>
111
+ <option value="model" disabled={!modelAllowed}>Model</option>
112
+ <option value="alias" disabled={!aliasAllowed}>Alias</option>
113
+ <option value="fusion" disabled={!fusionAllowed}>Fusion</option>
114
+ </select>
115
+ </label>
116
+ {#if kind === 'model'}
117
+ <label>
118
+ <span class="itr-label">Provider</span>
119
+ <select name="provider" bind:value={provider} disabled={busy}>
120
+ <option value="">Configured provider</option>
121
+ {#each providers.filter((option) => option.kind === 'provider') as option (option.id)}
122
+ <option value={option.id}>{option.label}</option>
123
+ {/each}
124
+ </select>
125
+ </label>
126
+ <label>
127
+ <span class="itr-label">Model</span>
128
+ <input name="model" bind:value={model} required disabled={busy} />
129
+ </label>
130
+ {:else if kind === 'alias'}
131
+ <label>
132
+ <span class="itr-label">Alias</span>
133
+ <select name="alias" bind:value={alias} required disabled={busy}>
134
+ <option value="" disabled>Choose an alias</option>
135
+ {#each aliases as entry (entry.name)}
136
+ <option value={entry.name} disabled={!allowed({ alias: entry.name })}>{entry.name}</option>
137
+ {/each}
138
+ </select>
139
+ </label>
140
+ {:else if kind === 'fusion'}
141
+ <label>
142
+ <span class="itr-label">Fusion</span>
143
+ <select name="fusion" bind:value={fusion} required disabled={busy}>
144
+ <option value="" disabled>Choose a fusion</option>
145
+ {#each fusions as entry (entry.name)}
146
+ <option value={entry.name} disabled={!allowed({ kind: 'fusion', fusion: entry.name })}>
147
+ {entry.name}
148
+ </option>
149
+ {/each}
150
+ </select>
151
+ </label>
152
+ {/if}
153
+ <button type="submit" disabled={busy || !onSaveTier}>Save</button>
154
+ </div>
155
+ <p class="itr-hint">"Same as default" reverts to: {tierRevertPreview(row, scope)}</p>
156
+ </form>
157
+
158
+ <style>
159
+ @layer smrt.reset, smrt.structure, smrt.theme;
160
+ @layer smrt.theme {
161
+ .itr {
162
+ display: flex;
163
+ flex-direction: column;
164
+ gap: 0.375rem;
165
+ padding: 0.5rem 0;
166
+ border-bottom: var(--smrt-hairline);
167
+ }
168
+ .itr-head {
169
+ display: flex;
170
+ gap: 0.75rem;
171
+ align-items: baseline;
172
+ flex-wrap: wrap;
173
+ }
174
+ .itr-tier {
175
+ text-transform: capitalize;
176
+ min-width: 4rem;
177
+ }
178
+ .itr-level,
179
+ .itr-hint,
180
+ .itr-note,
181
+ .itr-label {
182
+ font-size: 0.8125rem;
183
+ color: var(--smrt-color-on-surface-variant);
184
+ }
185
+ .itr-hint,
186
+ .itr-note {
187
+ margin: 0;
188
+ }
189
+ .itr-label {
190
+ display: block;
191
+ }
192
+ .itr-controls {
193
+ display: flex;
194
+ gap: 0.5rem;
195
+ align-items: flex-end;
196
+ flex-wrap: wrap;
197
+ }
198
+ }
199
+ </style>
@@ -0,0 +1,14 @@
1
+ import type { InferenceAliasView, InferenceFusionView, InferenceProviderView, InferenceSettingsScope, InferenceTierChange, InferenceTierView } from '../types.js';
2
+ interface InferenceTierRowProps {
3
+ row: InferenceTierView;
4
+ scope: InferenceSettingsScope;
5
+ providers: InferenceProviderView[];
6
+ aliases: InferenceAliasView[];
7
+ fusions: InferenceFusionView[];
8
+ busy: boolean;
9
+ onSaveTier?: (change: InferenceTierChange) => void;
10
+ }
11
+ declare const InferenceTierRow: import("svelte").Component<InferenceTierRowProps, {}, "">;
12
+ type InferenceTierRow = ReturnType<typeof InferenceTierRow>;
13
+ export default InferenceTierRow;
14
+ //# sourceMappingURL=InferenceTierRow.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InferenceTierRow.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/InferenceTierRow.svelte.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EAEtB,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,aAAa,CAAC;AASrB,UAAU,qBAAqB;IAC7B,GAAG,EAAE,iBAAiB,CAAC;IACvB,KAAK,EAAE,sBAAsB,CAAC;IAC9B,SAAS,EAAE,qBAAqB,EAAE,CAAC;IACnC,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;CACpD;AAyID,QAAA,MAAM,gBAAgB,2DAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,165 @@
1
+ <script lang="ts">
2
+ /**
3
+ * The app's transcript setting in Advanced (#4781). Read-only unless the
4
+ * host passes `editable` (platform admin, `appEditable` on the panel):
5
+ * tenants cannot override transcripts, and a save always writes the app
6
+ * row. Retention is the sweep's policy and stays read-only. Renders no
7
+ * transcript content.
8
+ */
9
+ import type {
10
+ InferenceTranscriptSettingsChange,
11
+ InferenceTranscriptSettingsView,
12
+ } from '../types.js';
13
+
14
+ interface InferenceTranscriptSettingsProps {
15
+ settings: InferenceTranscriptSettingsView;
16
+ editable: boolean;
17
+ busy: boolean;
18
+ onSaveTranscripts?: (change: InferenceTranscriptSettingsChange) => void;
19
+ }
20
+
21
+ const {
22
+ settings,
23
+ editable,
24
+ busy,
25
+ onSaveTranscripts,
26
+ }: InferenceTranscriptSettingsProps = $props();
27
+
28
+ const LEVELS: Record<string, string> = {
29
+ env: 'SMRT_INFERENCE_TRANSCRIPTS',
30
+ app: 'App setting',
31
+ config: 'Config',
32
+ default: 'Default',
33
+ };
34
+
35
+ const retention = $derived(
36
+ settings.retentionDays === null || settings.retentionDays === undefined
37
+ ? 'not pruned'
38
+ : `${settings.retentionDays} days`,
39
+ );
40
+
41
+ function percent(value: number): string {
42
+ return `${Math.round(value * 1000) / 10}%`;
43
+ }
44
+
45
+ function save(event: SubmitEvent): void {
46
+ event.preventDefault();
47
+ if (!onSaveTranscripts) return;
48
+ const data = new FormData(event.currentTarget as HTMLFormElement);
49
+ onSaveTranscripts({
50
+ settings: {
51
+ enabled: data.get('enabled') === 'on',
52
+ sample: Number(data.get('sample')),
53
+ maxBytes: Number(data.get('maxBytes')),
54
+ },
55
+ });
56
+ }
57
+
58
+ function revert(): void {
59
+ onSaveTranscripts?.({ settings: null });
60
+ }
61
+ </script>
62
+
63
+ <div class="its" data-testid="inference-transcripts">
64
+ {#if settings.envEnabled !== null && settings.envEnabled !== undefined}
65
+ <p class="its-hint" data-testid="inference-transcripts-env">
66
+ SMRT_INFERENCE_TRANSCRIPTS turns transcripts {settings.envEnabled ? 'on' : 'off'} over this setting.
67
+ </p>
68
+ {/if}
69
+ {#if editable}
70
+ <form class="its-form" onsubmit={save} data-testid="inference-transcripts-form">
71
+ <label>
72
+ <input type="checkbox" name="enabled" checked={settings.enabled} disabled={busy} />
73
+ Store transcripts
74
+ </label>
75
+ <label>
76
+ <span class="its-hint">Success sample rate (0–1)</span>
77
+ <input
78
+ type="number"
79
+ name="sample"
80
+ min="0"
81
+ max="1"
82
+ step="0.01"
83
+ value={settings.sample}
84
+ disabled={busy}
85
+ required
86
+ />
87
+ </label>
88
+ <label>
89
+ <span class="its-hint">Max bytes per call</span>
90
+ <input
91
+ type="number"
92
+ name="maxBytes"
93
+ min="1024"
94
+ step="1"
95
+ value={settings.maxBytes}
96
+ disabled={busy}
97
+ required
98
+ />
99
+ </label>
100
+ <button type="submit" disabled={busy}>Save</button>
101
+ {#if settings.appValue}
102
+ <button type="button" disabled={busy} onclick={revert}>
103
+ Revert to config{settings.appRevert
104
+ ? ` (${settings.appRevert.enabled ? 'on' : 'off'})`
105
+ : ''}
106
+ </button>
107
+ {/if}
108
+ </form>
109
+ {/if}
110
+ <dl class="its-values">
111
+ {#if !editable}
112
+ <dt>Stored</dt>
113
+ <dd data-testid="inference-transcripts-enabled">{settings.enabled ? 'On' : 'Off'}</dd>
114
+ <dt>Success sample rate</dt>
115
+ <dd>{percent(settings.sample)}</dd>
116
+ <dt>Max bytes per call</dt>
117
+ <dd>{settings.maxBytes}</dd>
118
+ {/if}
119
+ <dt>Retention</dt>
120
+ <dd data-testid="inference-transcripts-retention">{retention}</dd>
121
+ {#if settings.supplyingLevel}
122
+ <dt>Set by</dt>
123
+ <dd>{LEVELS[settings.supplyingLevel] ?? settings.supplyingLevel}</dd>
124
+ {/if}
125
+ </dl>
126
+ {#if settings.promptOverrides && settings.promptOverrides.length > 0}
127
+ <p class="its-hint">
128
+ Config sets its own sample rate for {settings.promptOverrides.length} prompt key(s).
129
+ </p>
130
+ {/if}
131
+ {#if !editable}
132
+ <p class="its-hint">App-wide setting; tenants cannot change it.</p>
133
+ {/if}
134
+ </div>
135
+
136
+ <style>
137
+ @layer smrt.reset, smrt.structure, smrt.theme;
138
+ @layer smrt.theme {
139
+ .its {
140
+ display: flex;
141
+ flex-direction: column;
142
+ gap: 0.5rem;
143
+ }
144
+ .its-form {
145
+ display: flex;
146
+ gap: 0.75rem;
147
+ align-items: flex-end;
148
+ flex-wrap: wrap;
149
+ }
150
+ .its-values {
151
+ display: grid;
152
+ grid-template-columns: max-content 1fr;
153
+ gap: 0.25rem 0.75rem;
154
+ margin: 0;
155
+ }
156
+ .its-values dd {
157
+ margin: 0;
158
+ }
159
+ .its-hint {
160
+ margin: 0;
161
+ font-size: 0.8125rem;
162
+ color: var(--smrt-color-on-surface-variant);
163
+ }
164
+ }
165
+ </style>
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The app's transcript setting in Advanced (#4781). Read-only unless the
3
+ * host passes `editable` (platform admin, `appEditable` on the panel):
4
+ * tenants cannot override transcripts, and a save always writes the app
5
+ * row. Retention is the sweep's policy and stays read-only. Renders no
6
+ * transcript content.
7
+ */
8
+ import type { InferenceTranscriptSettingsChange, InferenceTranscriptSettingsView } from '../types.js';
9
+ interface InferenceTranscriptSettingsProps {
10
+ settings: InferenceTranscriptSettingsView;
11
+ editable: boolean;
12
+ busy: boolean;
13
+ onSaveTranscripts?: (change: InferenceTranscriptSettingsChange) => void;
14
+ }
15
+ declare const InferenceTranscriptSettings: import("svelte").Component<InferenceTranscriptSettingsProps, {}, "">;
16
+ type InferenceTranscriptSettings = ReturnType<typeof InferenceTranscriptSettings>;
17
+ export default InferenceTranscriptSettings;
18
+ //# sourceMappingURL=InferenceTranscriptSettings.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InferenceTranscriptSettings.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/InferenceTranscriptSettings.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,OAAO,KAAK,EACV,iCAAiC,EACjC,+BAA+B,EAChC,MAAM,aAAa,CAAC;AAGrB,UAAU,gCAAgC;IACxC,QAAQ,EAAE,+BAA+B,CAAC;IAC1C,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,iCAAiC,KAAK,IAAI,CAAC;CACzE;AA4GD,QAAA,MAAM,2BAA2B,sEAAwC,CAAC;AAC1E,KAAK,2BAA2B,GAAG,UAAU,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAClF,eAAe,2BAA2B,CAAC"}
@@ -0,0 +1,177 @@
1
+ <script lang="ts">
2
+ /**
3
+ * The Usage tab: `reportAiUsage()` buckets (#4751) by model, tier, prompt
4
+ * key, fusion and/or template hash. Renders only the dimensions the report
5
+ * was grouped by, so it works with the model dimension alone. With
6
+ * transcript counts (#4781) each row shows how many calls have a stored
7
+ * transcript and links them (and each outcome label) to the host's
8
+ * transcript route; transcript content is never rendered here.
9
+ */
10
+ import type {
11
+ InferenceTranscriptLinkFilters,
12
+ InferenceUsageDimension,
13
+ InferenceUsageView,
14
+ } from '../types.js';
15
+ import { transcriptLinkFilters, usageColumns } from '../types.js';
16
+
17
+ interface InferenceUsageTableProps {
18
+ usage: InferenceUsageView | null;
19
+ busy: boolean;
20
+ /** Whether the app stores transcripts; `false` shows the status line. */
21
+ transcriptsEnabled?: boolean | null;
22
+ transcriptHref?: (
23
+ filters: InferenceTranscriptLinkFilters,
24
+ ) => string | null | undefined;
25
+ onUsageGroupBy?: (by: InferenceUsageDimension[]) => void;
26
+ }
27
+
28
+ const {
29
+ usage,
30
+ busy,
31
+ transcriptsEnabled = null,
32
+ transcriptHref,
33
+ onUsageGroupBy,
34
+ }: InferenceUsageTableProps = $props();
35
+
36
+ const DIMENSIONS: Array<{ id: InferenceUsageDimension; label: string }> = [
37
+ { id: 'model', label: 'Model' },
38
+ { id: 'tier', label: 'Tier' },
39
+ { id: 'prompt', label: 'Prompt key' },
40
+ { id: 'fusion', label: 'Fusion' },
41
+ { id: 'template', label: 'Template' },
42
+ ];
43
+
44
+ const columns = $derived(usage ? usageColumns(usage) : []);
45
+ const showTranscripts = $derived(
46
+ !!usage?.buckets.some((bucket) => typeof bucket.transcripts === 'number'),
47
+ );
48
+
49
+ function href(
50
+ key: Record<string, string | null | undefined>,
51
+ outcome?: string,
52
+ ): string | null {
53
+ if (!usage || !transcriptHref) return null;
54
+ return transcriptHref(transcriptLinkFilters(usage, key, outcome)) || null;
55
+ }
56
+
57
+ function outcomeEntries(
58
+ value: Record<string, number> | undefined,
59
+ ): Array<[string, number]> {
60
+ return Object.entries(value ?? {});
61
+ }
62
+
63
+ function regroup(event: Event): void {
64
+ const form = (event.currentTarget as HTMLInputElement).form;
65
+ if (!form || !onUsageGroupBy) return;
66
+ const by = new FormData(form)
67
+ .getAll('by')
68
+ .map(String) as InferenceUsageDimension[];
69
+ onUsageGroupBy(by.length > 0 ? by : ['model']);
70
+ }
71
+ </script>
72
+
73
+ <div class="iut" data-testid="inference-usage">
74
+ {#if transcriptsEnabled === false}
75
+ <p class="iut-label" role="status" data-testid="inference-transcripts-off">
76
+ Transcripts are off; turn them on with <code>inference.transcripts.enabled</code> (Advanced, Transcripts) or <code>SMRT_INFERENCE_TRANSCRIPTS=1</code>.
77
+ </p>
78
+ {/if}
79
+ {#if onUsageGroupBy}
80
+ <form class="iut-group">
81
+ <span class="iut-label">Group by</span>
82
+ {#each DIMENSIONS as dimension (dimension.id)}
83
+ <label>
84
+ <input
85
+ type="checkbox"
86
+ name="by"
87
+ value={dimension.id}
88
+ checked={columns.includes(dimension.id)}
89
+ disabled={busy}
90
+ onchange={regroup}
91
+ />
92
+ {dimension.label}
93
+ </label>
94
+ {/each}
95
+ </form>
96
+ {/if}
97
+ {#if !usage || usage.buckets.length === 0}
98
+ <p class="iut-label">No usage recorded yet.</p>
99
+ {:else}
100
+ <table class="iut-table">
101
+ <thead>
102
+ <tr>
103
+ {#each columns as column (column)}
104
+ <th scope="col">{DIMENSIONS.find((entry) => entry.id === column)?.label ?? column}</th>
105
+ {/each}
106
+ <th scope="col">Calls</th>
107
+ <th scope="col">Tokens</th>
108
+ <th scope="col">Est. cost</th>
109
+ <th scope="col">Outcomes</th>
110
+ {#if showTranscripts}<th scope="col">Transcripts</th>{/if}
111
+ </tr>
112
+ </thead>
113
+ <tbody>
114
+ {#each usage.buckets as bucket, index (index)}
115
+ <tr>
116
+ {#each columns as column (column)}
117
+ <td>{bucket.key[column] ?? '(unattributed)'}</td>
118
+ {/each}
119
+ <td>{bucket.calls}</td>
120
+ <td>{bucket.totalTokens}</td>
121
+ <td>
122
+ ${bucket.estimatedCost.toFixed(4)}
123
+ {#if bucket.uncostedCalls}<span class="iut-label">({bucket.uncostedCalls} uncosted)</span>{/if}
124
+ </td>
125
+ <td>
126
+ {#each outcomeEntries(bucket.outcomes) as [label, count], position (label)}
127
+ {@const link = (bucket.transcripts ?? 0) > 0 ? href(bucket.key, label) : null}
128
+ {#if position > 0}, {/if}
129
+ {#if link}<a href={link} data-testid="inference-transcript-outcome-link">{label} {count}</a>{:else}{label} {count}{/if}
130
+ {:else}
131
+ –
132
+ {/each}
133
+ </td>
134
+ {#if showTranscripts}
135
+ {@const link = (bucket.transcripts ?? 0) > 0 ? href(bucket.key) : null}
136
+ <td data-testid="inference-transcript-count">
137
+ {#if link}<a href={link} data-testid="inference-transcript-link">{bucket.transcripts}</a>{:else}{bucket.transcripts ?? 0}{/if}
138
+ </td>
139
+ {/if}
140
+ </tr>
141
+ {/each}
142
+ </tbody>
143
+ </table>
144
+ {#if usage.costBasis}<p class="iut-label">{usage.costBasis}</p>{/if}
145
+ {/if}
146
+ </div>
147
+
148
+ <style>
149
+ @layer smrt.reset, smrt.structure, smrt.theme;
150
+ @layer smrt.theme {
151
+ .iut {
152
+ display: flex;
153
+ flex-direction: column;
154
+ gap: 0.75rem;
155
+ }
156
+ .iut-group {
157
+ display: flex;
158
+ gap: 0.75rem;
159
+ align-items: center;
160
+ }
161
+ .iut-table {
162
+ border-collapse: collapse;
163
+ font-size: 0.875rem;
164
+ }
165
+ .iut-table th,
166
+ .iut-table td {
167
+ text-align: left;
168
+ padding: 0.25rem 0.75rem 0.25rem 0;
169
+ border-bottom: var(--smrt-hairline);
170
+ }
171
+ .iut-label {
172
+ margin: 0;
173
+ font-size: 0.8125rem;
174
+ color: var(--smrt-color-on-surface-variant);
175
+ }
176
+ }
177
+ </style>
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The Usage tab: `reportAiUsage()` buckets (#4751) by model, tier, prompt
3
+ * key, fusion and/or template hash. Renders only the dimensions the report
4
+ * was grouped by, so it works with the model dimension alone. With
5
+ * transcript counts (#4781) each row shows how many calls have a stored
6
+ * transcript and links them (and each outcome label) to the host's
7
+ * transcript route; transcript content is never rendered here.
8
+ */
9
+ import type { InferenceTranscriptLinkFilters, InferenceUsageDimension, InferenceUsageView } from '../types.js';
10
+ interface InferenceUsageTableProps {
11
+ usage: InferenceUsageView | null;
12
+ busy: boolean;
13
+ /** Whether the app stores transcripts; `false` shows the status line. */
14
+ transcriptsEnabled?: boolean | null;
15
+ transcriptHref?: (filters: InferenceTranscriptLinkFilters) => string | null | undefined;
16
+ onUsageGroupBy?: (by: InferenceUsageDimension[]) => void;
17
+ }
18
+ declare const InferenceUsageTable: import("svelte").Component<InferenceUsageTableProps, {}, "">;
19
+ type InferenceUsageTable = ReturnType<typeof InferenceUsageTable>;
20
+ export default InferenceUsageTable;
21
+ //# sourceMappingURL=InferenceUsageTable.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InferenceUsageTable.svelte.d.ts","sourceRoot":"","sources":["../../../src/svelte/components/InferenceUsageTable.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,OAAO,KAAK,EACV,8BAA8B,EAC9B,uBAAuB,EACvB,kBAAkB,EACnB,MAAM,aAAa,CAAC;AAIrB,UAAU,wBAAwB;IAChC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACpC,cAAc,CAAC,EAAE,CACf,OAAO,EAAE,8BAA8B,KACpC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC/B,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,uBAAuB,EAAE,KAAK,IAAI,CAAC;CAC1D;AA0HD,QAAA,MAAM,mBAAmB,8DAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @happyvertical/smrt-inference/svelte
3
+ *
4
+ * Optional Svelte 5 UI for inference settings (#4754). Presentational only:
5
+ * the panel takes rows and callbacks, does no fetching, and makes no
6
+ * authorization decision. Hosts render it from a server load that used
7
+ * `InferenceSettingsService` (`./server`) and wire saves to their own
8
+ * permission-checked actions. The root entry stays Svelte-free.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import type { ComponentProps } from 'svelte';
13
+ import InferenceSettingsPanel from './components/InferenceSettingsPanel.svelte';
14
+ export { InferenceSettingsPanel };
15
+ export type InferenceSettingsPanelProps = ComponentProps<typeof InferenceSettingsPanel>;
16
+ export { candidateViewLabel, defaultTierRevertPreview, describeTargetView, INFERENCE_SETTINGS_MODES, INFERENCE_SETTINGS_TIERS, type InferenceAliasChange, type InferenceAliasView, type InferenceCandidateView, type InferenceConnectionRequest, type InferenceDefaultsChange, type InferenceDefaultsView, type InferenceDefaultTierChange, type InferenceDefaultTierView, type InferenceDiscoveryView, type InferenceFusionChange, type InferenceFusionView, type InferenceKeyChange, type InferenceProviderView, type InferenceSettingsLevelView, type InferenceSettingsMode, type InferenceSettingsScope, type InferenceSettingsTier, type InferenceTargetView, type InferenceTestResultView, type InferenceTierChange, type InferenceTierView, type InferenceTranscriptLinkFilters, type InferenceTranscriptSettingsChange, type InferenceTranscriptSettingsView, type InferenceTranscriptValuesView, type InferenceUsageDimension, type InferenceUsageView, inferenceLevelLabel, isRefAllowed, targetViewRef, tierRevertPreview, transcriptLinkFilters, usageColumns, } from './types.js';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/svelte/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,sBAAsB,MAAM,4CAA4C,CAAC;AAEhF,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAClC,MAAM,MAAM,2BAA2B,GAAG,cAAc,CACtD,OAAO,sBAAsB,CAC9B,CAAC;AAEF,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,wBAAwB,EACxB,wBAAwB,EACxB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,8BAA8B,EACnC,KAAK,iCAAiC,EACtC,KAAK,+BAA+B,EACpC,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,YAAY,GACb,MAAM,YAAY,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @happyvertical/smrt-inference/svelte
3
+ *
4
+ * Optional Svelte 5 UI for inference settings (#4754). Presentational only:
5
+ * the panel takes rows and callbacks, does no fetching, and makes no
6
+ * authorization decision. Hosts render it from a server load that used
7
+ * `InferenceSettingsService` (`./server`) and wire saves to their own
8
+ * permission-checked actions. The root entry stays Svelte-free.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import InferenceSettingsPanel from './components/InferenceSettingsPanel.svelte';
13
+ export { InferenceSettingsPanel };
14
+ export { candidateViewLabel, defaultTierRevertPreview, describeTargetView, INFERENCE_SETTINGS_MODES, INFERENCE_SETTINGS_TIERS, inferenceLevelLabel, isRefAllowed, targetViewRef, tierRevertPreview, transcriptLinkFilters, usageColumns, } from './types.js';