@genesislcap/ai-assistant 15.4.1 → 15.5.0
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/dist/ai-assistant.api.json +544 -82
- package/dist/ai-assistant.d.ts +324 -36
- package/dist/chat-driver.cjs +94 -22
- package/dist/chat-driver.cjs.map +3 -3
- package/dist/chat-driver.mjs +94 -22
- package/dist/chat-driver.mjs.map +3 -3
- package/dist/custom-elements.json +303 -36
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
- package/dist/dts/components/settings-modal/settings-modal.styles.d.ts.map +1 -1
- package/dist/dts/components/settings-modal/settings-modal.template.d.ts +9 -2
- package/dist/dts/components/settings-modal/settings-modal.template.d.ts.map +1 -1
- package/dist/dts/index.d.ts +1 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/dts/main/cost-session-banking.test.d.ts +2 -0
- package/dist/dts/main/cost-session-banking.test.d.ts.map +1 -0
- package/dist/dts/main/main.d.ts +184 -24
- package/dist/dts/main/main.d.ts.map +1 -1
- package/dist/dts/provider/assistant-app-settings.d.ts +30 -5
- package/dist/dts/provider/assistant-app-settings.d.ts.map +1 -1
- package/dist/dts/state/ai-assistant-slice.d.ts +11 -8
- package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
- package/dist/dts/state/persistence/session-persistence-provider.d.ts +23 -0
- package/dist/dts/state/persistence/session-persistence-provider.d.ts.map +1 -1
- package/dist/dts/state/persistence/session-snapshot.d.ts.map +1 -1
- package/dist/dts/state/session-store.d.ts +1 -2
- package/dist/dts/state/session-store.d.ts.map +1 -1
- package/dist/dts/styles/settings-section.d.ts +29 -0
- package/dist/dts/styles/settings-section.d.ts.map +1 -0
- package/dist/dts/utils/cost-session-history.d.ts +103 -12
- package/dist/dts/utils/cost-session-history.d.ts.map +1 -1
- package/dist/dts/utils/resolve-cost-history-config.d.ts +9 -3
- package/dist/dts/utils/resolve-cost-history-config.d.ts.map +1 -1
- package/dist/dts/utils/sum-costs.d.ts.map +1 -1
- package/dist/dts/utils/sum-tokens.d.ts +8 -8
- package/dist/dts/utils/sum-tokens.d.ts.map +1 -1
- package/dist/dts/utils/sum-usage.d.ts +59 -0
- package/dist/dts/utils/sum-usage.d.ts.map +1 -0
- package/dist/dts/utils/sum-usage.test.d.ts +2 -0
- package/dist/dts/utils/sum-usage.test.d.ts.map +1 -0
- package/dist/esm/components/chat-driver/chat-driver.js +6 -0
- package/dist/esm/components/settings-modal/settings-modal.styles.js +237 -18
- package/dist/esm/components/settings-modal/settings-modal.template.js +229 -73
- package/dist/esm/index.js +1 -0
- package/dist/esm/main/cost-session-banking.test.js +308 -0
- package/dist/esm/main/main.js +424 -71
- package/dist/esm/state/ai-assistant-slice.js +11 -8
- package/dist/esm/state/ai-assistant-slice.test.js +12 -5
- package/dist/esm/state/debug-event-log.js +2 -2
- package/dist/esm/state/persistence/session-persistence.integration.test.js +5 -1
- package/dist/esm/state/persistence/session-persister.js +2 -2
- package/dist/esm/state/persistence/session-persister.test.js +10 -1
- package/dist/esm/state/persistence/session-snapshot.js +6 -2
- package/dist/esm/state/persistence/session-snapshot.test.js +4 -1
- package/dist/esm/state/persistence/stateful-restore.e2e.test.js +10 -1
- package/dist/esm/styles/settings-section.js +39 -0
- package/dist/esm/utils/cost-session-history.js +92 -15
- package/dist/esm/utils/cost-session-history.test.js +155 -13
- package/dist/esm/utils/resolve-cost-history-config.js +2 -1
- package/dist/esm/utils/sum-costs.js +2 -13
- package/dist/esm/utils/sum-tokens.js +10 -27
- package/dist/esm/utils/sum-tokens.test.js +1 -5
- package/dist/esm/utils/sum-usage.js +123 -0
- package/dist/esm/utils/sum-usage.test.js +120 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -17
- package/src/components/chat-driver/chat-driver.ts +6 -0
- package/src/components/settings-modal/settings-modal.styles.ts +237 -18
- package/src/components/settings-modal/settings-modal.template.ts +270 -81
- package/src/index.ts +1 -0
- package/src/main/cost-session-banking.test.ts +407 -0
- package/src/main/main.ts +433 -68
- package/src/provider/assistant-app-settings.ts +31 -5
- package/src/state/ai-assistant-slice.test.ts +12 -5
- package/src/state/ai-assistant-slice.ts +21 -13
- package/src/state/debug-event-log.ts +2 -2
- package/src/state/persistence/session-persistence-provider.ts +24 -0
- package/src/state/persistence/session-persistence.integration.test.ts +8 -1
- package/src/state/persistence/session-persister.test.ts +10 -1
- package/src/state/persistence/session-persister.ts +2 -2
- package/src/state/persistence/session-snapshot.test.ts +4 -1
- package/src/state/persistence/session-snapshot.ts +5 -1
- package/src/state/persistence/stateful-restore.e2e.test.ts +9 -1
- package/src/styles/settings-section.ts +40 -0
- package/src/utils/cost-session-history.test.ts +187 -16
- package/src/utils/cost-session-history.ts +142 -23
- package/src/utils/resolve-cost-history-config.ts +10 -3
- package/src/utils/sum-costs.ts +2 -9
- package/src/utils/sum-tokens.test.ts +1 -11
- package/src/utils/sum-tokens.ts +10 -26
- package/src/utils/sum-usage.test.ts +140 -0
- package/src/utils/sum-usage.ts +130 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { html, ref, repeat, slotted, when } from '@genesislcap/web-core';
|
|
2
2
|
import { ANIMATION_DEFS } from '../../main/main.types';
|
|
3
3
|
import { formatCostSessionDate, } from '../../utils/cost-session-history';
|
|
4
|
-
import {
|
|
4
|
+
import { formatCompactTokenCountSafe } from '../../utils/sum-tokens';
|
|
5
5
|
const SESSION_COST_DECIMALS = 2;
|
|
6
6
|
/** Animation options grouped by {@link ANIMATION_DEFS} category for the settings list. */
|
|
7
7
|
const animationCategoryGroups = (() => {
|
|
@@ -69,9 +69,14 @@ const animationsPickerTemplate = (switchTag) => html `
|
|
|
69
69
|
`)}
|
|
70
70
|
</div>
|
|
71
71
|
`;
|
|
72
|
+
const SETTINGS_ROW_LAYOUT_CLASS = {
|
|
73
|
+
row: '',
|
|
74
|
+
'row-centered': 'is-centered',
|
|
75
|
+
column: 'is-stacked',
|
|
76
|
+
};
|
|
72
77
|
/** Shared label + control row used for switches, buttons, and multiselects. */
|
|
73
78
|
const settingsToggleRow = (title, description, part, control, layout = 'row') => html `
|
|
74
|
-
<div class="settings-toggle-row ${layout
|
|
79
|
+
<div class="settings-toggle-row ${SETTINGS_ROW_LAYOUT_CLASS[layout]}" part="${part}-row">
|
|
75
80
|
<div class="settings-toggle-text">
|
|
76
81
|
<div class="settings-toggle-title">${title}</div>
|
|
77
82
|
<div class="settings-toggle-desc">${description}</div>
|
|
@@ -127,7 +132,27 @@ const chatBotSettingsTemplate = (switchTag, buttonTag) => html `
|
|
|
127
132
|
}))}
|
|
128
133
|
${when((x) => { var _a, _b; return ((_b = (_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.animations) === null || _b === void 0 ? void 0 : _b.userConfigurable) === true; }, settingsToggleRow('Animations', 'Choose which loading and activity indicators appear while the assistant is working.', 'toggle-animations', animationsPickerTemplate(switchTag), 'column'))}
|
|
129
134
|
`;
|
|
130
|
-
const appSettingsTemplate = (switchTag) => html `
|
|
135
|
+
const appSettingsTemplate = (switchTag, iconTag) => html `
|
|
136
|
+
<!--
|
|
137
|
+
Slot FIRST, ahead of the provider toggles. The assistant renders no heading for this
|
|
138
|
+
section, so whatever the host slots in has to be able to title it — and a heading below the
|
|
139
|
+
rows it names would title nothing. Anything the host wants under the toggles it can render
|
|
140
|
+
below them within its own slotted block.
|
|
141
|
+
-->
|
|
142
|
+
<slot name="settings-app" ${slotted('settingsAppSlotted')}></slot>
|
|
143
|
+
<!--
|
|
144
|
+
Sub-heading for the toggle group, rendered only when the host asks for one — both the text
|
|
145
|
+
and the icon come from its provider. It exists so a host whose slotted content covers other
|
|
146
|
+
ground can still mark these rows off from it.
|
|
147
|
+
-->
|
|
148
|
+
${when((x) => !!x.appSettingsTogglesHeading, html `
|
|
149
|
+
<h4 class="ai-settings-section-title settings-app-toggles-title" part="app-toggles-title">
|
|
150
|
+
${when((x) => { var _a; return !!((_a = x.appSettingsTogglesHeading) === null || _a === void 0 ? void 0 : _a.icon); }, html `
|
|
151
|
+
<${iconTag} name="${(x) => { var _a; return (_a = x.appSettingsTogglesHeading) === null || _a === void 0 ? void 0 : _a.icon; }}"></${iconTag}>
|
|
152
|
+
`)}
|
|
153
|
+
${(x) => { var _a; return (_a = x.appSettingsTogglesHeading) === null || _a === void 0 ? void 0 : _a.title; }}
|
|
154
|
+
</h4>
|
|
155
|
+
`)}
|
|
131
156
|
${repeat((x) => x.visibleAppSettingsToggles, html `
|
|
132
157
|
<div class="settings-app-toggle-block">
|
|
133
158
|
<div
|
|
@@ -154,8 +179,131 @@ const appSettingsTemplate = (switchTag) => html `
|
|
|
154
179
|
`)}
|
|
155
180
|
</div>
|
|
156
181
|
`)}
|
|
157
|
-
<slot name="settings-app" ${slotted('settingsAppSlotted')}></slot>
|
|
158
182
|
`;
|
|
183
|
+
/**
|
|
184
|
+
* One model chip. Shared by the live session and the history rows so the two can't drift — both
|
|
185
|
+
* already reduce to a distinct-model list, the live one via `uniqueProviderModels` and a row via
|
|
186
|
+
* `collectSessionModels`.
|
|
187
|
+
*/
|
|
188
|
+
const modelTagTemplate = html `
|
|
189
|
+
<span class="settings-model-tag vendor-${(entry) => entry.provider || 'generic'}">
|
|
190
|
+
${(entry) => entry.model}
|
|
191
|
+
</span>
|
|
192
|
+
`;
|
|
193
|
+
/**
|
|
194
|
+
* The four billing buckets for one `AggregateUsage`, wherever it comes from — the lifetime
|
|
195
|
+
* total, the live session, or a history row.
|
|
196
|
+
*
|
|
197
|
+
* Why four numbers instead of one: each bucket bills at a different rate, so a single token
|
|
198
|
+
* total can't explain a session that processed millions of tokens for pennies. Uncached input,
|
|
199
|
+
* cache read and cache write partition the prompt (they sum to it, never add on top), and
|
|
200
|
+
* output is what the model generated.
|
|
201
|
+
*
|
|
202
|
+
* Ordered input, output, cache read, cache write to match how Claude Code reports usage, so the
|
|
203
|
+
* two can be read side by side — comparing against it is what this breakdown exists for. Note
|
|
204
|
+
* this puts output between the three buckets that partition the prompt, so their relationship is
|
|
205
|
+
* carried by the tooltips rather than by adjacency.
|
|
206
|
+
*
|
|
207
|
+
* `partPrefix` keeps the shadow-part names caller-specific (`session-tokens-input`,
|
|
208
|
+
* `lifetime-tokens-input`, …) so a host can style one context without hitting the others.
|
|
209
|
+
*/
|
|
210
|
+
const tokenBreakdownTemplate = (usageOf, partPrefix) => html `
|
|
211
|
+
<div class="settings-token-breakdown" part="${partPrefix}-token-breakdown">
|
|
212
|
+
<!--
|
|
213
|
+
Titles the box. Nothing in it otherwise said "tokens": the four bucket names are the
|
|
214
|
+
token TYPES, not the unit, so the panel read as four unexplained numbers unless the
|
|
215
|
+
reader found the per-bucket tooltips.
|
|
216
|
+
-->
|
|
217
|
+
<div class="settings-token-breakdown-label">Tokens</div>
|
|
218
|
+
<div class="settings-token-buckets">
|
|
219
|
+
<div class="settings-token-bucket" part="${partPrefix}-tokens-input">
|
|
220
|
+
<span
|
|
221
|
+
class="settings-token-bucket-label"
|
|
222
|
+
title="Prompt tokens billed at the full uncached rate"
|
|
223
|
+
>
|
|
224
|
+
Input
|
|
225
|
+
</span>
|
|
226
|
+
<span
|
|
227
|
+
class="settings-token-bucket-value"
|
|
228
|
+
:innerHTML="${(x) => formatCompactTokenCountSafe(usageOf(x).uncachedInputTokens)}"
|
|
229
|
+
></span>
|
|
230
|
+
</div>
|
|
231
|
+
<div class="settings-token-bucket" part="${partPrefix}-tokens-output">
|
|
232
|
+
<span
|
|
233
|
+
class="settings-token-bucket-label"
|
|
234
|
+
title="Tokens the model generated, including reasoning tokens billed as output"
|
|
235
|
+
>
|
|
236
|
+
Output
|
|
237
|
+
</span>
|
|
238
|
+
<span
|
|
239
|
+
class="settings-token-bucket-value"
|
|
240
|
+
:innerHTML="${(x) => formatCompactTokenCountSafe(usageOf(x).outputTokens)}"
|
|
241
|
+
></span>
|
|
242
|
+
</div>
|
|
243
|
+
<div class="settings-token-bucket is-discounted" part="${partPrefix}-tokens-cache-read">
|
|
244
|
+
<span
|
|
245
|
+
class="settings-token-bucket-label"
|
|
246
|
+
title="Prompt tokens served from the provider cache — billed at a fraction of the uncached rate"
|
|
247
|
+
>
|
|
248
|
+
Cache read
|
|
249
|
+
</span>
|
|
250
|
+
<span
|
|
251
|
+
class="settings-token-bucket-value"
|
|
252
|
+
:innerHTML="${(x) => formatCompactTokenCountSafe(usageOf(x).cacheReadTokens)}"
|
|
253
|
+
></span>
|
|
254
|
+
</div>
|
|
255
|
+
<div class="settings-token-bucket" part="${partPrefix}-tokens-cache-write">
|
|
256
|
+
<span
|
|
257
|
+
class="settings-token-bucket-label"
|
|
258
|
+
title="Prompt tokens written to the provider cache — billed at a premium over the uncached rate"
|
|
259
|
+
>
|
|
260
|
+
Cache write
|
|
261
|
+
</span>
|
|
262
|
+
<span
|
|
263
|
+
class="settings-token-bucket-value"
|
|
264
|
+
:innerHTML="${(x) => formatCompactTokenCountSafe(usageOf(x).cacheWriteTokens)}"
|
|
265
|
+
></span>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
`;
|
|
270
|
+
/**
|
|
271
|
+
* Lifetime usage across every project in the history scope.
|
|
272
|
+
*
|
|
273
|
+
* Sits above the live session block because it is the wider figure. It used to live inside
|
|
274
|
+
* that block as a lone "Total build cost", where the live badge and project name directly
|
|
275
|
+
* above it implied the total belonged to the open project.
|
|
276
|
+
*/
|
|
277
|
+
const lifetimeUsageTemplate = () => html `
|
|
278
|
+
${when((x) => x.settingsCostLifetimeVisible, html `
|
|
279
|
+
<div class="settings-lifetime-usage" part="lifetime-usage">
|
|
280
|
+
<div class="settings-lifetime-usage-top">
|
|
281
|
+
<span class="settings-lifetime-label">Lifetime usage</span>
|
|
282
|
+
</div>
|
|
283
|
+
<div class="settings-usage-row">
|
|
284
|
+
<div
|
|
285
|
+
class="settings-build-stat"
|
|
286
|
+
part="lifetime-cost"
|
|
287
|
+
?hidden=${(x) => !x.resolvedCostHistory.showCost}
|
|
288
|
+
>
|
|
289
|
+
<div class="settings-build-stat-label">Total build cost</div>
|
|
290
|
+
<div class="settings-build-stat-value">
|
|
291
|
+
<span class="prefix">$</span>
|
|
292
|
+
<span class="value">
|
|
293
|
+
${(x) => x.cumulativeCostUsd.toFixed(SESSION_COST_DECIMALS)}
|
|
294
|
+
</span>
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
<div
|
|
298
|
+
class="settings-usage-row-tokens"
|
|
299
|
+
?hidden=${(x) => !x.resolvedCostHistory.showTokens}
|
|
300
|
+
>
|
|
301
|
+
${tokenBreakdownTemplate((x) => x.cumulativeUsage, 'lifetime')}
|
|
302
|
+
</div>
|
|
303
|
+
</div>
|
|
304
|
+
</div>
|
|
305
|
+
`)}
|
|
306
|
+
`;
|
|
159
307
|
const sessionCostSummaryTemplate = () => html `
|
|
160
308
|
${when((x) => x.settingsCostSummaryVisible, html `
|
|
161
309
|
<div class="settings-current-build" part="session-cost-summary">
|
|
@@ -168,59 +316,43 @@ const sessionCostSummaryTemplate = () => html `
|
|
|
168
316
|
<span class="settings-current-build-name">${(x) => x.liveCostSessionTitle}</span>
|
|
169
317
|
`)}
|
|
170
318
|
</div>
|
|
171
|
-
<div class="settings-
|
|
319
|
+
<div class="settings-usage-row">
|
|
172
320
|
<div
|
|
173
321
|
class="settings-build-stat"
|
|
174
322
|
part="session-cost"
|
|
175
323
|
?hidden=${(x) => !x.resolvedCostHistory.showCost}
|
|
176
324
|
>
|
|
177
|
-
|
|
325
|
+
<!--
|
|
326
|
+
Label states the scope rather than implying one. These figures are whatever
|
|
327
|
+
the open transcript proves, so they are the project's whole history exactly
|
|
328
|
+
when that transcript is restored on load, and only this page-load's when it
|
|
329
|
+
isn't. Same number, two meanings — so the caller can't be left guessing.
|
|
330
|
+
-->
|
|
331
|
+
<div class="settings-build-stat-label">
|
|
332
|
+
${(x) => (x.liveUsageIsProjectLifetime ? 'Project cost' : 'Session cost')}
|
|
333
|
+
</div>
|
|
178
334
|
<div class="settings-build-stat-value">
|
|
179
335
|
<span class="prefix">$</span>
|
|
180
336
|
<span class="value">${(x) => x.sessionCostUsd.toFixed(SESSION_COST_DECIMALS)}</span>
|
|
181
337
|
</div>
|
|
182
338
|
</div>
|
|
183
339
|
<div
|
|
184
|
-
class="settings-
|
|
185
|
-
part="session-tokens"
|
|
340
|
+
class="settings-usage-row-tokens"
|
|
186
341
|
?hidden=${(x) => !x.resolvedCostHistory.showTokens}
|
|
187
342
|
>
|
|
188
|
-
|
|
189
|
-
<div
|
|
190
|
-
class="settings-build-stat-value"
|
|
191
|
-
:innerHTML="${(x) => formatCompactTokenCountSafe(x.sessionTokensConsumed)}"
|
|
192
|
-
></div>
|
|
193
|
-
</div>
|
|
194
|
-
<div
|
|
195
|
-
class="settings-build-stat"
|
|
196
|
-
part="session-cumulative-cost"
|
|
197
|
-
?hidden=${(x) => !x.resolvedCostHistory.showCost}
|
|
198
|
-
>
|
|
199
|
-
<div class="settings-build-stat-label">Total build cost</div>
|
|
200
|
-
<div class="settings-build-stat-value">
|
|
201
|
-
<span class="prefix">$</span>
|
|
202
|
-
<span class="value">
|
|
203
|
-
${(x) => x.cumulativeCostUsd.toFixed(SESSION_COST_DECIMALS)}
|
|
204
|
-
</span>
|
|
205
|
-
</div>
|
|
343
|
+
${tokenBreakdownTemplate((x) => x.sessionUsage, 'session')}
|
|
206
344
|
</div>
|
|
207
345
|
</div>
|
|
208
|
-
${when((x) => { var _a; return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.showActiveModel) !== false && x.
|
|
346
|
+
${when((x) => { var _a; return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.showActiveModel) !== false && x.uniqueProviderModels.length > 0; }, html `
|
|
209
347
|
<div class="settings-model-tags" part="session-model-tags">
|
|
210
|
-
${repeat((x) => x.
|
|
211
|
-
<span
|
|
212
|
-
class="settings-model-tag vendor-${(entry) => { var _a; return ((_a = entry.status) === null || _a === void 0 ? void 0 : _a.provider) || 'generic'; }}"
|
|
213
|
-
>
|
|
214
|
-
${(entry) => { var _a, _b; return (_b = (_a = entry.status) === null || _a === void 0 ? void 0 : _a.model) !== null && _b !== void 0 ? _b : entry.name; }}
|
|
215
|
-
</span>
|
|
216
|
-
`)}
|
|
348
|
+
${repeat((x) => x.uniqueProviderModels, modelTagTemplate)}
|
|
217
349
|
</div>
|
|
218
350
|
`)}
|
|
219
351
|
</div>
|
|
220
352
|
`)}
|
|
221
353
|
`;
|
|
222
354
|
const costSessionHistoryTemplate = (iconTag, buttonTag) => html `
|
|
223
|
-
${repeat((x) => x.
|
|
355
|
+
${repeat((x) => x.sortedCostSessionHistory, html `
|
|
224
356
|
<div class="settings-cost-history-row" part="cost-history-row">
|
|
225
357
|
<div class="settings-cost-history-row-content">
|
|
226
358
|
<span class="settings-cost-history-icon" part="cost-history-icon" aria-hidden="true">
|
|
@@ -232,46 +364,58 @@ const costSessionHistoryTemplate = (iconTag, buttonTag) => html `
|
|
|
232
364
|
${(record) => record.title}
|
|
233
365
|
</div>
|
|
234
366
|
<div class="settings-cost-history-row-date">
|
|
235
|
-
${(record) => formatCostSessionDate(record.
|
|
367
|
+
${(record) => formatCostSessionDate(record.updatedAt)}
|
|
236
368
|
</div>
|
|
237
369
|
</div>
|
|
370
|
+
<!--
|
|
371
|
+
Cost and the delete control live together so they centre against each other.
|
|
372
|
+
The button used to sit outside the row body, held in place by a negative margin
|
|
373
|
+
tuned for when this column had a second line (a merged token total); that line
|
|
374
|
+
is gone, and a nudge measured against a removed sibling is exactly the kind that
|
|
375
|
+
rots silently.
|
|
376
|
+
-->
|
|
238
377
|
<div class="settings-cost-history-row-right">
|
|
239
378
|
<div class="settings-cost-history-row-metrics">
|
|
240
379
|
<div class="settings-cost-history-row-cost">
|
|
241
|
-
$${(record) => record.costUsd.toFixed(SESSION_COST_DECIMALS)}
|
|
242
|
-
</div>
|
|
243
|
-
<div class="settings-cost-history-row-tokens">
|
|
244
|
-
${(record) => formatCompactTokenCountPlain(record.tokensConsumed)} tokens
|
|
380
|
+
$${(record) => record.usage.costUsd.toFixed(SESSION_COST_DECIMALS)}
|
|
245
381
|
</div>
|
|
246
382
|
</div>
|
|
383
|
+
<${buttonTag}
|
|
384
|
+
class="settings-cost-history-delete"
|
|
385
|
+
part="cost-history-delete"
|
|
386
|
+
appearance="stealth"
|
|
387
|
+
aria-label="Remove from build history"
|
|
388
|
+
@click=${(record, c) => c.parent.showConfirmationDialog('Are you sure you want to remove this build from history?', c.parent.settingsModal, () => c.parent.removeCostSessionFromHistory(record.id))}
|
|
389
|
+
>
|
|
390
|
+
<${iconTag} name="trash"></${iconTag}>
|
|
391
|
+
</${buttonTag}>
|
|
247
392
|
</div>
|
|
248
393
|
</div>
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
394
|
+
</div>
|
|
395
|
+
<!--
|
|
396
|
+
The same four buckets as the live block, on its own line below the row rather than
|
|
397
|
+
beside the cost — the row's own width is spoken for by title, cost and delete.
|
|
398
|
+
Replaces a merged total that could not explain a huge token count at a small cost
|
|
399
|
+
without hovering for a tooltip.
|
|
400
|
+
-->
|
|
401
|
+
<div
|
|
402
|
+
class="settings-cost-history-row-content settings-cost-history-row-breakdown"
|
|
403
|
+
?hidden=${(record, c) => !c.parent.resolvedCostHistory.showTokens}
|
|
404
|
+
>
|
|
405
|
+
${tokenBreakdownTemplate((record) => record.usage, 'cost-history-row')}
|
|
258
406
|
</div>
|
|
259
407
|
${when((record) => record.models.length > 0, html `
|
|
260
408
|
<div
|
|
261
409
|
class="settings-cost-history-row-content settings-model-tags settings-cost-history-model-tags"
|
|
262
410
|
>
|
|
263
|
-
${repeat((record) => record.models,
|
|
264
|
-
<span class="settings-model-tag vendor-${(model) => model.provider || 'generic'}">
|
|
265
|
-
${(model) => model.model}
|
|
266
|
-
</span>
|
|
267
|
-
`)}
|
|
411
|
+
${repeat((record) => record.models, modelTagTemplate)}
|
|
268
412
|
</div>
|
|
269
413
|
`)}
|
|
270
414
|
</div>
|
|
271
415
|
`)}
|
|
272
416
|
`;
|
|
273
417
|
/**
|
|
274
|
-
* Modal shell for assistant settings —
|
|
418
|
+
* Modal shell for assistant settings — Configuration and Usage tabs, section slots for
|
|
275
419
|
* app-specific UI, and built-in chat-bot toggles.
|
|
276
420
|
*/
|
|
277
421
|
export const SettingsModalTemplate = (designSystemPrefix) => {
|
|
@@ -295,7 +439,7 @@ export const SettingsModalTemplate = (designSystemPrefix) => {
|
|
|
295
439
|
part="settings-section-model"
|
|
296
440
|
?hidden=${(x) => !x.settingsModelSectionVisible}
|
|
297
441
|
>
|
|
298
|
-
<h3 class="settings-
|
|
442
|
+
<h3 class="ai-settings-section-title">
|
|
299
443
|
<${iconTag} name="microchip"></${iconTag}> AI Model Settings
|
|
300
444
|
</h3>
|
|
301
445
|
<div class="settings-modal-section-body">
|
|
@@ -303,18 +447,11 @@ export const SettingsModalTemplate = (designSystemPrefix) => {
|
|
|
303
447
|
${platformContextUsageTemplate(progressTag)}
|
|
304
448
|
</div>
|
|
305
449
|
</section>
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
<h3 class="settings-modal-section-title">
|
|
312
|
-
<${iconTag} name="home"></${iconTag}> ${(x) => x.appSettingsSectionTitle}
|
|
313
|
-
</h3>
|
|
314
|
-
<div class="settings-modal-section-body">
|
|
315
|
-
${appSettingsTemplate(switchTag)}
|
|
316
|
-
</div>
|
|
317
|
-
</section>
|
|
450
|
+
<!--
|
|
451
|
+
Above the host section, deliberately. This is the assistant's own control, so it belongs
|
|
452
|
+
with the assistant's other sections rather than trailing the host's — where, now that the
|
|
453
|
+
host section carries no heading of its own, it read as one more of the host's settings.
|
|
454
|
+
-->
|
|
318
455
|
${when((x) => { var _a; return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.allowDebugDownload) === true; }, html `
|
|
319
456
|
<section class="settings-modal-section" part="settings-section-agent-log">
|
|
320
457
|
<div class="settings-modal-section-body">
|
|
@@ -334,12 +471,27 @@ export const SettingsModalTemplate = (designSystemPrefix) => {
|
|
|
334
471
|
`)}
|
|
335
472
|
${(x) => (x.downloadingDebugLog ? 'Downloading…' : 'Download')}
|
|
336
473
|
</${buttonTag}>
|
|
337
|
-
|
|
474
|
+
`, 'row-centered')}
|
|
338
475
|
</div>
|
|
339
476
|
</section>
|
|
340
477
|
`)}
|
|
478
|
+
<!--
|
|
479
|
+
No heading here, by design. This section belongs to the host: only it knows what its
|
|
480
|
+
settings are called, so the assistant supplies neither text nor icon and the host titles
|
|
481
|
+
the section from the slot. See assistantSettingsSectionTitleStyles for the heading style
|
|
482
|
+
it can apply to match the sections above and below.
|
|
483
|
+
-->
|
|
484
|
+
<section
|
|
485
|
+
class="settings-modal-section"
|
|
486
|
+
part="settings-section-app"
|
|
487
|
+
?hidden=${(x) => !x.settingsAppSectionVisible}
|
|
488
|
+
>
|
|
489
|
+
<div class="settings-modal-section-body">
|
|
490
|
+
${appSettingsTemplate(switchTag, iconTag)}
|
|
491
|
+
</div>
|
|
492
|
+
</section>
|
|
341
493
|
<section class="settings-modal-section" part="settings-section-chat">
|
|
342
|
-
<h3 class="settings-
|
|
494
|
+
<h3 class="ai-settings-section-title">
|
|
343
495
|
<${iconTag} name="comment"></${iconTag}> AI Chat Bot Settings
|
|
344
496
|
</h3>
|
|
345
497
|
<p class="settings-modal-section-note">These options only control what you see in the chat window and do not control model behaviour.</p>
|
|
@@ -357,6 +509,7 @@ export const SettingsModalTemplate = (designSystemPrefix) => {
|
|
|
357
509
|
part="cost-tab-panel"
|
|
358
510
|
>
|
|
359
511
|
<div class="settings-modal-body" part="settings-modal-body">
|
|
512
|
+
${lifetimeUsageTemplate()}
|
|
360
513
|
${sessionCostSummaryTemplate()}
|
|
361
514
|
<div
|
|
362
515
|
class="settings-cost-current"
|
|
@@ -406,19 +559,22 @@ export const SettingsModalTemplate = (designSystemPrefix) => {
|
|
|
406
559
|
appearance="secondary"
|
|
407
560
|
class="settings-modal-tab"
|
|
408
561
|
part="settings-modal-tab-settings"
|
|
409
|
-
><${iconTag} name="
|
|
562
|
+
><${iconTag} name="sliders"></${iconTag}> Configuration</${tabTag}>${when((x) => x.settingsCostTabVisible, html `<${tabTag}
|
|
410
563
|
slot="tab"
|
|
411
564
|
id="cost"
|
|
412
565
|
appearance="secondary"
|
|
413
566
|
class="settings-modal-tab"
|
|
414
567
|
part="settings-modal-tab-cost"
|
|
415
|
-
><${iconTag} name="
|
|
568
|
+
><${iconTag} name="chart-simple"></${iconTag}> Usage</${tabTag}>`)}${settingsTabPanel}${when((x) => x.settingsCostTabVisible, costTabPanel)}</${tabsTag}>
|
|
416
569
|
</div>
|
|
417
570
|
<div slot="bottom" class="settings-modal-footer" part="settings-modal-footer">
|
|
418
571
|
<div class="settings-modal-footer-actions">
|
|
419
572
|
${when((x) => x.settingsModalTab === 'cost', html `
|
|
420
573
|
<span class="settings-disclaimer">
|
|
421
|
-
|
|
574
|
+
${when((x) => !!x.resolvedCostHistory.summaryHint, html `
|
|
575
|
+
${(x) => x.resolvedCostHistory.summaryHint}
|
|
576
|
+
`)}Costs
|
|
577
|
+
are estimated from token usage at list price.
|
|
422
578
|
</span>
|
|
423
579
|
`)}
|
|
424
580
|
<${buttonTag}
|
package/dist/esm/index.js
CHANGED
|
@@ -15,4 +15,5 @@ export * from './state/persistence';
|
|
|
15
15
|
export * from './provider/ai-provider-switcher';
|
|
16
16
|
export * from './provider/assistant-app-settings';
|
|
17
17
|
export * from './utils/tool-fold';
|
|
18
|
+
export { assistantSettingsSectionTitleStyles } from './styles/settings-section';
|
|
18
19
|
export { AiChatMarkdown } from './components/chat-markdown/chat-markdown';
|