@genesislcap/ai-assistant 15.19.0 → 15.19.1
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 +17 -18
- package/api-extractor.json +0 -11
- package/dist/dts/components/chat-driver/chat-driver.compact.test.d.ts +0 -2
- package/dist/dts/components/chat-driver/chat-driver.compact.test.d.ts.map +0 -1
- package/dist/dts/components/chat-driver/chat-driver.invocation-scope.test.d.ts +0 -2
- package/dist/dts/components/chat-driver/chat-driver.invocation-scope.test.d.ts.map +0 -1
- package/dist/dts/components/chat-driver/chat-driver.test.d.ts +0 -2
- package/dist/dts/components/chat-driver/chat-driver.test.d.ts.map +0 -1
- package/dist/dts/components/chat-driver/chat-driver.thinking-policy.test.d.ts +0 -2
- package/dist/dts/components/chat-driver/chat-driver.thinking-policy.test.d.ts.map +0 -1
- package/dist/dts/components/chat-driver/chat-driver.trace-capture.test.d.ts +0 -2
- package/dist/dts/components/chat-driver/chat-driver.trace-capture.test.d.ts.map +0 -1
- package/dist/dts/components/chat-driver/chat-driver.turn-usage.test.d.ts +0 -2
- package/dist/dts/components/chat-driver/chat-driver.turn-usage.test.d.ts.map +0 -1
- package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.test.d.ts +0 -2
- package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.test.d.ts.map +0 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.budget.test.d.ts +0 -2
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.budget.test.d.ts.map +0 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.cost.test.d.ts +0 -2
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.cost.test.d.ts.map +0 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.pin.test.d.ts +0 -2
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.pin.test.d.ts.map +0 -1
- package/dist/dts/components/settings-modal/settings-modal.styles.test.d.ts +0 -2
- package/dist/dts/components/settings-modal/settings-modal.styles.test.d.ts.map +0 -1
- package/dist/dts/components/settings-modal/settings-modal.template.test.d.ts +0 -2
- package/dist/dts/components/settings-modal/settings-modal.template.test.d.ts.map +0 -1
- package/dist/dts/config/define-stateful-agent.test.d.ts +0 -2
- package/dist/dts/config/define-stateful-agent.test.d.ts.map +0 -1
- package/dist/dts/config/validate-providers.test.d.ts +0 -2
- package/dist/dts/config/validate-providers.test.d.ts.map +0 -1
- package/dist/dts/main/blocked-state.test.d.ts +0 -2
- package/dist/dts/main/blocked-state.test.d.ts.map +0 -1
- package/dist/dts/main/budget-meter.test.d.ts +0 -2
- package/dist/dts/main/budget-meter.test.d.ts.map +0 -1
- package/dist/dts/main/cost-session-banking.test.d.ts +0 -2
- package/dist/dts/main/cost-session-banking.test.d.ts.map +0 -1
- package/dist/dts/main/file-attachments.test.d.ts +0 -2
- package/dist/dts/main/file-attachments.test.d.ts.map +0 -1
- package/dist/dts/main/interaction-cost.test.d.ts +0 -2
- package/dist/dts/main/interaction-cost.test.d.ts.map +0 -1
- package/dist/dts/main/main.styles.test.d.ts +0 -2
- package/dist/dts/main/main.styles.test.d.ts.map +0 -1
- package/dist/dts/main/persistence-broken-sources.test.d.ts +0 -2
- package/dist/dts/main/persistence-broken-sources.test.d.ts.map +0 -1
- package/dist/dts/main/popout-interaction-gate.test.d.ts +0 -2
- package/dist/dts/main/popout-interaction-gate.test.d.ts.map +0 -1
- package/dist/dts/state/ai-assistant-slice.test.d.ts +0 -2
- package/dist/dts/state/ai-assistant-slice.test.d.ts.map +0 -1
- package/dist/dts/state/debug-event-log.test.d.ts +0 -2
- package/dist/dts/state/debug-event-log.test.d.ts.map +0 -1
- package/dist/dts/state/driver-registry.test.d.ts +0 -2
- package/dist/dts/state/driver-registry.test.d.ts.map +0 -1
- package/dist/dts/state/interaction-context.test.d.ts +0 -2
- package/dist/dts/state/interaction-context.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/diagnostics-cursors.test.d.ts +0 -2
- package/dist/dts/state/persistence/diagnostics-cursors.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/diagnostics.test.d.ts +0 -2
- package/dist/dts/state/persistence/diagnostics.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/session-persistence-provider.test.d.ts +0 -2
- package/dist/dts/state/persistence/session-persistence-provider.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/session-persistence.integration.test.d.ts +0 -2
- package/dist/dts/state/persistence/session-persistence.integration.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/session-persister.test.d.ts +0 -2
- package/dist/dts/state/persistence/session-persister.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/session-snapshot.test.d.ts +0 -2
- package/dist/dts/state/persistence/session-snapshot.test.d.ts.map +0 -1
- package/dist/dts/state/persistence/stateful-restore.e2e.test.d.ts +0 -2
- package/dist/dts/state/persistence/stateful-restore.e2e.test.d.ts.map +0 -1
- package/dist/dts/utils/animation-exclusivity.test.d.ts +0 -2
- package/dist/dts/utils/animation-exclusivity.test.d.ts.map +0 -1
- package/dist/dts/utils/collect-session-models.test.d.ts +0 -2
- package/dist/dts/utils/collect-session-models.test.d.ts.map +0 -1
- package/dist/dts/utils/condense-history.test.d.ts +0 -2
- package/dist/dts/utils/condense-history.test.d.ts.map +0 -1
- package/dist/dts/utils/cost-session-history.test.d.ts +0 -2
- package/dist/dts/utils/cost-session-history.test.d.ts.map +0 -1
- package/dist/dts/utils/derive-cost-session-title.test.d.ts +0 -2
- package/dist/dts/utils/derive-cost-session-title.test.d.ts.map +0 -1
- package/dist/dts/utils/flatten-sub-agent-messages.test.d.ts +0 -2
- package/dist/dts/utils/flatten-sub-agent-messages.test.d.ts.map +0 -1
- package/dist/dts/utils/history-transform.test.d.ts +0 -2
- package/dist/dts/utils/history-transform.test.d.ts.map +0 -1
- package/dist/dts/utils/message-partition.test.d.ts +0 -2
- package/dist/dts/utils/message-partition.test.d.ts.map +0 -1
- package/dist/dts/utils/resolve-cost-history-config.test.d.ts +0 -2
- package/dist/dts/utils/resolve-cost-history-config.test.d.ts.map +0 -1
- package/dist/dts/utils/resolve-preference-baseline.test.d.ts +0 -2
- package/dist/dts/utils/resolve-preference-baseline.test.d.ts.map +0 -1
- package/dist/dts/utils/strip-agent-handlers.test.d.ts +0 -2
- package/dist/dts/utils/strip-agent-handlers.test.d.ts.map +0 -1
- package/dist/dts/utils/sum-costs.test.d.ts +0 -2
- package/dist/dts/utils/sum-costs.test.d.ts.map +0 -1
- package/dist/dts/utils/sum-tokens.test.d.ts +0 -2
- package/dist/dts/utils/sum-tokens.test.d.ts.map +0 -1
- package/dist/dts/utils/sum-usage.test.d.ts +0 -2
- package/dist/dts/utils/sum-usage.test.d.ts.map +0 -1
- package/dist/dts/utils/usage-rows.test.d.ts +0 -2
- package/dist/dts/utils/usage-rows.test.d.ts.map +0 -1
- package/dist/esm/components/chat-driver/chat-driver.compact.test.js +0 -93
- package/dist/esm/components/chat-driver/chat-driver.invocation-scope.test.js +0 -238
- package/dist/esm/components/chat-driver/chat-driver.test.js +0 -2770
- package/dist/esm/components/chat-driver/chat-driver.thinking-policy.test.js +0 -137
- package/dist/esm/components/chat-driver/chat-driver.trace-capture.test.js +0 -200
- package/dist/esm/components/chat-driver/chat-driver.turn-usage.test.js +0 -268
- package/dist/esm/components/chat-interaction-wrapper/chat-interaction-wrapper.test.js +0 -104
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.budget.test.js +0 -312
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.cost.test.js +0 -76
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.pin.test.js +0 -61
- package/dist/esm/components/settings-modal/settings-modal.styles.test.js +0 -80
- package/dist/esm/components/settings-modal/settings-modal.template.test.js +0 -91
- package/dist/esm/config/define-stateful-agent.test.js +0 -53
- package/dist/esm/config/validate-providers.test.js +0 -100
- package/dist/esm/main/blocked-state.test.js +0 -1065
- package/dist/esm/main/budget-meter.test.js +0 -359
- package/dist/esm/main/cost-session-banking.test.js +0 -538
- package/dist/esm/main/file-attachments.test.js +0 -164
- package/dist/esm/main/interaction-cost.test.js +0 -107
- package/dist/esm/main/main.styles.test.js +0 -161
- package/dist/esm/main/persistence-broken-sources.test.js +0 -180
- package/dist/esm/main/popout-interaction-gate.test.js +0 -54
- package/dist/esm/state/ai-assistant-slice.test.js +0 -229
- package/dist/esm/state/debug-event-log.test.js +0 -117
- package/dist/esm/state/driver-registry.test.js +0 -55
- package/dist/esm/state/interaction-context.test.js +0 -78
- package/dist/esm/state/persistence/diagnostics-cursors.test.js +0 -30
- package/dist/esm/state/persistence/diagnostics.test.js +0 -280
- package/dist/esm/state/persistence/session-persistence-provider.test.js +0 -110
- package/dist/esm/state/persistence/session-persistence.integration.test.js +0 -113
- package/dist/esm/state/persistence/session-persister.test.js +0 -613
- package/dist/esm/state/persistence/session-snapshot.test.js +0 -256
- package/dist/esm/state/persistence/stateful-restore.e2e.test.js +0 -158
- package/dist/esm/utils/animation-exclusivity.test.js +0 -52
- package/dist/esm/utils/collect-session-models.test.js +0 -53
- package/dist/esm/utils/condense-history.test.js +0 -547
- package/dist/esm/utils/cost-session-history.test.js +0 -174
- package/dist/esm/utils/derive-cost-session-title.test.js +0 -37
- package/dist/esm/utils/flatten-sub-agent-messages.test.js +0 -139
- package/dist/esm/utils/history-transform.test.js +0 -158
- package/dist/esm/utils/message-partition.test.js +0 -90
- package/dist/esm/utils/resolve-cost-history-config.test.js +0 -32
- package/dist/esm/utils/resolve-preference-baseline.test.js +0 -69
- package/dist/esm/utils/strip-agent-handlers.test.js +0 -81
- package/dist/esm/utils/sum-costs.test.js +0 -114
- package/dist/esm/utils/sum-tokens.test.js +0 -51
- package/dist/esm/utils/sum-usage.test.js +0 -164
- package/dist/esm/utils/usage-rows.test.js +0 -189
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/license.txt +0 -46
- package/sandbox/tsconfig.json +0 -8
- package/src/channel/ai-activity-bus.ts +0 -209
- package/src/channel/ai-activity-channel.ts +0 -146
- package/src/chat-driver-node.ts +0 -159
- package/src/components/activity-halo/activity-halo.ts +0 -106
- package/src/components/agent-picker/agent-picker.constants.ts +0 -2
- package/src/components/agent-picker/agent-picker.styles.ts +0 -24
- package/src/components/agent-picker/agent-picker.template.ts +0 -54
- package/src/components/agent-picker/agent-picker.ts +0 -99
- package/src/components/agent-picker/index.ts +0 -1
- package/src/components/ai-driver/ai-driver.ts +0 -166
- package/src/components/ai-driver/index.ts +0 -1
- package/src/components/chat-bubble/chat-bubble.styles.ts +0 -194
- package/src/components/chat-bubble/chat-bubble.template.ts +0 -67
- package/src/components/chat-bubble/chat-bubble.ts +0 -436
- package/src/components/chat-bubble/index.ts +0 -1
- package/src/components/chat-driver/align-event-globals.ts +0 -23
- package/src/components/chat-driver/chat-driver.compact.test.ts +0 -131
- package/src/components/chat-driver/chat-driver.invocation-scope.test.ts +0 -285
- package/src/components/chat-driver/chat-driver.test.ts +0 -3679
- package/src/components/chat-driver/chat-driver.thinking-policy.test.ts +0 -185
- package/src/components/chat-driver/chat-driver.trace-capture.test.ts +0 -251
- package/src/components/chat-driver/chat-driver.ts +0 -3925
- package/src/components/chat-driver/chat-driver.turn-usage.test.ts +0 -362
- package/src/components/chat-driver/index.ts +0 -1
- package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.ts +0 -7
- package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.template.ts +0 -6
- package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.test.ts +0 -144
- package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.ts +0 -243
- package/src/components/chat-interaction-wrapper/index.ts +0 -3
- package/src/components/chat-markdown/chat-markdown.ts +0 -89
- package/src/components/chat-markdown/index.ts +0 -1
- package/src/components/flowing-waves-indicator.ts +0 -286
- package/src/components/halo-overlay.ts +0 -184
- package/src/components/orchestrating-driver/index.ts +0 -1
- package/src/components/orchestrating-driver/orchestrating-driver.budget.test.ts +0 -438
- package/src/components/orchestrating-driver/orchestrating-driver.cost.test.ts +0 -107
- package/src/components/orchestrating-driver/orchestrating-driver.pin.test.ts +0 -96
- package/src/components/orchestrating-driver/orchestrating-driver.ts +0 -813
- package/src/components/plasma-orb-indicator.ts +0 -281
- package/src/components/popout-manager/index.ts +0 -1
- package/src/components/popout-manager/popout-manager.ts +0 -212
- package/src/components/settings-modal/index.ts +0 -2
- package/src/components/settings-modal/settings-modal.styles.test.ts +0 -94
- package/src/components/settings-modal/settings-modal.styles.ts +0 -853
- package/src/components/settings-modal/settings-modal.template.test.ts +0 -124
- package/src/components/settings-modal/settings-modal.template.ts +0 -943
- package/src/components/waves-indicator.ts +0 -241
- package/src/config/config.ts +0 -608
- package/src/config/define-stateful-agent.test.ts +0 -64
- package/src/config/define-stateful-agent.ts +0 -642
- package/src/config/fallback-agents.ts +0 -29
- package/src/config/index.ts +0 -2
- package/src/config/validate-providers.test.ts +0 -148
- package/src/config/validate-providers.ts +0 -58
- package/src/index.ts +0 -29
- package/src/main/blocked-state.test.ts +0 -1444
- package/src/main/budget-meter.test.ts +0 -477
- package/src/main/cost-session-banking.test.ts +0 -679
- package/src/main/file-attachments.test.ts +0 -215
- package/src/main/index.ts +0 -3
- package/src/main/interaction-cost.test.ts +0 -140
- package/src/main/main.styles.test.ts +0 -216
- package/src/main/main.styles.ts +0 -995
- package/src/main/main.template.ts +0 -1119
- package/src/main/main.ts +0 -5432
- package/src/main/main.types.ts +0 -225
- package/src/main/persistence-broken-sources.test.ts +0 -219
- package/src/main/popout-interaction-gate.test.ts +0 -87
- package/src/provider/ai-provider-switcher.ts +0 -40
- package/src/provider/assistant-app-settings.ts +0 -84
- package/src/state/ai-assistant-slice.test.ts +0 -336
- package/src/state/ai-assistant-slice.ts +0 -604
- package/src/state/debug-event-log.test.ts +0 -154
- package/src/state/debug-event-log.ts +0 -358
- package/src/state/driver-registry.test.ts +0 -70
- package/src/state/driver-registry.ts +0 -79
- package/src/state/interaction-context.test.ts +0 -90
- package/src/state/interaction-context.ts +0 -101
- package/src/state/persistence/build-timeline-entries.ts +0 -66
- package/src/state/persistence/diagnostics-cursors.test.ts +0 -53
- package/src/state/persistence/diagnostics-cursors.ts +0 -80
- package/src/state/persistence/diagnostics.test.ts +0 -346
- package/src/state/persistence/diagnostics.ts +0 -220
- package/src/state/persistence/index.ts +0 -10
- package/src/state/persistence/persister-registry.ts +0 -55
- package/src/state/persistence/session-persistence-provider.test.ts +0 -136
- package/src/state/persistence/session-persistence-provider.ts +0 -226
- package/src/state/persistence/session-persistence.integration.test.ts +0 -141
- package/src/state/persistence/session-persister.test.ts +0 -787
- package/src/state/persistence/session-persister.ts +0 -917
- package/src/state/persistence/session-snapshot.test.ts +0 -352
- package/src/state/persistence/session-snapshot.ts +0 -344
- package/src/state/persistence/stateful-restore.e2e.test.ts +0 -229
- package/src/state/session-store.ts +0 -56
- package/src/styles/ai-colours.ts +0 -30
- package/src/styles/menu.ts +0 -187
- package/src/styles/settings-section.ts +0 -40
- package/src/suggestions/chat-suggestions.ts +0 -186
- package/src/tags/index.ts +0 -1
- package/src/types/ai-chat-widget.ts +0 -67
- package/src/types/interaction-context.ts +0 -82
- package/src/utils/animated-panel-toggle.ts +0 -62
- package/src/utils/animation-exclusivity.test.ts +0 -72
- package/src/utils/animation-exclusivity.ts +0 -40
- package/src/utils/banked-usage-baselines.ts +0 -90
- package/src/utils/collect-session-models.test.ts +0 -82
- package/src/utils/collect-session-models.ts +0 -65
- package/src/utils/condense-history.test.ts +0 -746
- package/src/utils/condense-history.ts +0 -448
- package/src/utils/cost-session-history.test.ts +0 -226
- package/src/utils/cost-session-history.ts +0 -218
- package/src/utils/derive-cost-session-title.test.ts +0 -63
- package/src/utils/derive-cost-session-title.ts +0 -76
- package/src/utils/flatten-sub-agent-messages.test.ts +0 -163
- package/src/utils/flatten-sub-agent-messages.ts +0 -88
- package/src/utils/format-usd.ts +0 -26
- package/src/utils/history-transform.test.ts +0 -228
- package/src/utils/history-transform.ts +0 -163
- package/src/utils/index.ts +0 -3
- package/src/utils/logger.ts +0 -3
- package/src/utils/message-partition.test.ts +0 -129
- package/src/utils/message-partition.ts +0 -115
- package/src/utils/resolve-cost-history-config.test.ts +0 -38
- package/src/utils/resolve-cost-history-config.ts +0 -38
- package/src/utils/resolve-preference-baseline.test.ts +0 -84
- package/src/utils/resolve-preference-baseline.ts +0 -80
- package/src/utils/strip-agent-handlers.test.ts +0 -99
- package/src/utils/strip-agent-handlers.ts +0 -53
- package/src/utils/sum-costs.test.ts +0 -136
- package/src/utils/sum-costs.ts +0 -18
- package/src/utils/sum-tokens.test.ts +0 -93
- package/src/utils/sum-tokens.ts +0 -68
- package/src/utils/sum-usage.test.ts +0 -191
- package/src/utils/sum-usage.ts +0 -208
- package/src/utils/tool-fold.ts +0 -181
- package/src/utils/usage-rows.test.ts +0 -237
- package/src/utils/usage-rows.ts +0 -187
- package/src/utils/with-timeout.ts +0 -24
- package/tsconfig.json +0 -9
|
@@ -1,943 +0,0 @@
|
|
|
1
|
-
import type { AggregateUsage } from '@genesislcap/foundation-ai';
|
|
2
|
-
import { html, ref, repeat, slotted, when, type ViewTemplate } from '@genesislcap/web-core';
|
|
3
|
-
import type { FoundationAiAssistant } from '../../main/main';
|
|
4
|
-
import {
|
|
5
|
-
ANIMATION_DEFS,
|
|
6
|
-
type AiAssistantAnimation,
|
|
7
|
-
type SettingsBudgetRow,
|
|
8
|
-
} from '../../main/main.types';
|
|
9
|
-
import type { AssistantAppSettingsToggle } from '../../provider/assistant-app-settings';
|
|
10
|
-
import {
|
|
11
|
-
formatCostSessionDate,
|
|
12
|
-
type CostSessionModelEntry,
|
|
13
|
-
type CostSessionRecord,
|
|
14
|
-
} from '../../utils/cost-session-history';
|
|
15
|
-
import { formatUsd, formatUsdAmount } from '../../utils/format-usd';
|
|
16
|
-
import { formatCompactTokenCountSafe } from '../../utils/sum-tokens';
|
|
17
|
-
|
|
18
|
-
type AnimationCategoryGroup = {
|
|
19
|
-
category: string;
|
|
20
|
-
items: Array<{ value: AiAssistantAnimation; label: string; description: string }>;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
type AnimationPickerRow =
|
|
24
|
-
| { kind: 'category'; category: string }
|
|
25
|
-
| {
|
|
26
|
-
kind: 'option';
|
|
27
|
-
value: AiAssistantAnimation;
|
|
28
|
-
label: string;
|
|
29
|
-
description: string;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/** Animation options grouped by {@link ANIMATION_DEFS} category for the settings list. */
|
|
33
|
-
const animationCategoryGroups: AnimationCategoryGroup[] = (() => {
|
|
34
|
-
const groups = new Map<string, AnimationCategoryGroup['items']>();
|
|
35
|
-
for (const [value, def] of Object.entries(ANIMATION_DEFS) as Array<
|
|
36
|
-
[AiAssistantAnimation, (typeof ANIMATION_DEFS)[AiAssistantAnimation]]
|
|
37
|
-
>) {
|
|
38
|
-
const items = groups.get(def.category) ?? [];
|
|
39
|
-
items.push({ value, label: def.label, description: def.description });
|
|
40
|
-
groups.set(def.category, items);
|
|
41
|
-
}
|
|
42
|
-
return [...groups.entries()].map(([category, items]) => ({ category, items }));
|
|
43
|
-
})();
|
|
44
|
-
|
|
45
|
-
const animationPickerRows: AnimationPickerRow[] = animationCategoryGroups.flatMap((group) => [
|
|
46
|
-
{ kind: 'category', category: group.category },
|
|
47
|
-
...group.items.map(
|
|
48
|
-
(item): AnimationPickerRow => ({
|
|
49
|
-
kind: 'option',
|
|
50
|
-
value: item.value,
|
|
51
|
-
label: item.label,
|
|
52
|
-
description: item.description,
|
|
53
|
-
}),
|
|
54
|
-
),
|
|
55
|
-
]);
|
|
56
|
-
|
|
57
|
-
const toggleAnimationEnabled = (
|
|
58
|
-
host: FoundationAiAssistant,
|
|
59
|
-
value: AiAssistantAnimation,
|
|
60
|
-
enabled: boolean,
|
|
61
|
-
): void => {
|
|
62
|
-
const next = enabled
|
|
63
|
-
? [...host.enabledAnimations, value]
|
|
64
|
-
: host.enabledAnimations?.filter((animation) => animation !== value);
|
|
65
|
-
host.setEnabledAnimations(next);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const readSwitchChecked = (event: Event): boolean => (event.target as HTMLInputElement).checked;
|
|
69
|
-
|
|
70
|
-
/** Inline animation picker — categories and options always visible (no multiselect popup). */
|
|
71
|
-
const animationsPickerTemplate = (
|
|
72
|
-
switchTag: string,
|
|
73
|
-
): ViewTemplate<FoundationAiAssistant> => html<FoundationAiAssistant>`
|
|
74
|
-
<div class="settings-animation-list" part="toggle-animations">
|
|
75
|
-
${repeat(
|
|
76
|
-
(x) => {
|
|
77
|
-
void x.enabledAnimations;
|
|
78
|
-
return animationPickerRows;
|
|
79
|
-
},
|
|
80
|
-
html<AnimationPickerRow, FoundationAiAssistant>`
|
|
81
|
-
${when(
|
|
82
|
-
(row) => row.kind === 'category',
|
|
83
|
-
html<AnimationPickerRow>`
|
|
84
|
-
<div class="settings-animation-category-label" part="animation-category">
|
|
85
|
-
${(row) => (row.kind === 'category' ? row.category : '')}
|
|
86
|
-
</div>
|
|
87
|
-
`,
|
|
88
|
-
)}
|
|
89
|
-
${when(
|
|
90
|
-
(row) => row.kind === 'option',
|
|
91
|
-
html<AnimationPickerRow, FoundationAiAssistant>`
|
|
92
|
-
<div class="settings-toggle-row settings-animation-option" part="animation-option">
|
|
93
|
-
<div class="settings-toggle-text">
|
|
94
|
-
<div class="settings-toggle-title">
|
|
95
|
-
${(row) => (row.kind === 'option' ? row.label : '')}
|
|
96
|
-
</div>
|
|
97
|
-
<div class="settings-toggle-desc">
|
|
98
|
-
${(row) => (row.kind === 'option' ? row.description : '')}
|
|
99
|
-
</div>
|
|
100
|
-
</div>
|
|
101
|
-
<div class="settings-toggle-control">
|
|
102
|
-
<${switchTag}
|
|
103
|
-
part="animation-toggle"
|
|
104
|
-
:checked=${(row, c) =>
|
|
105
|
-
row.kind === 'option' && c.parent.enabledAnimations.includes(row.value)}
|
|
106
|
-
@change=${(row, c) => {
|
|
107
|
-
if (row.kind !== 'option') return;
|
|
108
|
-
toggleAnimationEnabled(c.parent, row.value, readSwitchChecked(c.event));
|
|
109
|
-
}}
|
|
110
|
-
></${switchTag}>
|
|
111
|
-
</div>
|
|
112
|
-
</div>
|
|
113
|
-
`,
|
|
114
|
-
)}
|
|
115
|
-
`,
|
|
116
|
-
)}
|
|
117
|
-
</div>
|
|
118
|
-
`;
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Tab identifiers for the modal tab bar.
|
|
122
|
-
*
|
|
123
|
-
* The values are deliberately NOT renamed to match the visible labels ("Configuration" and
|
|
124
|
-
* "Usage"): they are the public API that hosts read and write via `settingsModalTab`, and are
|
|
125
|
-
* matched by the `settings-modal-tab-*` shadow parts. Renaming a label is cosmetic; renaming
|
|
126
|
-
* these would break consumers.
|
|
127
|
-
*/
|
|
128
|
-
export type SettingsModalTab = 'settings' | 'cost';
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* How a settings row places its control.
|
|
132
|
-
*
|
|
133
|
-
* `row` top-aligns it, which is what a switch wants — it then sits level with the title rather
|
|
134
|
-
* than floating beside a two-line description. `row-centered` is for a taller control such as a
|
|
135
|
-
* button, which top-aligned reads as hanging above the text it belongs to. `column` stacks the
|
|
136
|
-
* control under the text, for controls that need the full width.
|
|
137
|
-
*/
|
|
138
|
-
type SettingsRowLayout = 'row' | 'row-centered' | 'column';
|
|
139
|
-
|
|
140
|
-
const SETTINGS_ROW_LAYOUT_CLASS: Record<SettingsRowLayout, string> = {
|
|
141
|
-
row: '',
|
|
142
|
-
'row-centered': 'is-centered',
|
|
143
|
-
column: 'is-stacked',
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
/** Shared label + control row used for switches, buttons, and multiselects. */
|
|
147
|
-
const settingsToggleRow = (
|
|
148
|
-
title: string,
|
|
149
|
-
description: string,
|
|
150
|
-
part: string,
|
|
151
|
-
control: ViewTemplate<FoundationAiAssistant>,
|
|
152
|
-
layout: SettingsRowLayout = 'row',
|
|
153
|
-
) => html<FoundationAiAssistant>`
|
|
154
|
-
<div class="settings-toggle-row ${SETTINGS_ROW_LAYOUT_CLASS[layout]}" part="${part}-row">
|
|
155
|
-
<div class="settings-toggle-text">
|
|
156
|
-
<div class="settings-toggle-title">${title}</div>
|
|
157
|
-
<div class="settings-toggle-desc">${description}</div>
|
|
158
|
-
</div>
|
|
159
|
-
<div class="settings-toggle-control">${control}</div>
|
|
160
|
-
</div>
|
|
161
|
-
`;
|
|
162
|
-
|
|
163
|
-
const chatBotToggleRow = (
|
|
164
|
-
title: string,
|
|
165
|
-
description: string,
|
|
166
|
-
switchTag: string,
|
|
167
|
-
part: string,
|
|
168
|
-
checked: (x: FoundationAiAssistant) => boolean,
|
|
169
|
-
onChange: (x: FoundationAiAssistant, c: { event: Event }) => void,
|
|
170
|
-
) =>
|
|
171
|
-
settingsToggleRow(
|
|
172
|
-
title,
|
|
173
|
-
description,
|
|
174
|
-
part,
|
|
175
|
-
html<FoundationAiAssistant>`
|
|
176
|
-
<${switchTag}
|
|
177
|
-
part="${part}"
|
|
178
|
-
:checked=${checked}
|
|
179
|
-
@change=${onChange}
|
|
180
|
-
></${switchTag}>
|
|
181
|
-
`,
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
const platformContextUsageTemplate = (
|
|
185
|
-
progressTag: string,
|
|
186
|
-
): ViewTemplate<FoundationAiAssistant> => html<FoundationAiAssistant>`
|
|
187
|
-
${when(
|
|
188
|
-
// The getter, not a copy of its expression: `settingsUsageMetersTemplate`
|
|
189
|
-
// gates its shared wrapper on this same getter, and the two must agree —
|
|
190
|
-
// a drifted copy would leave the wrapper rendering around nothing.
|
|
191
|
-
(x) => x.settingsContextUsageVisible,
|
|
192
|
-
html<FoundationAiAssistant>`
|
|
193
|
-
<div class="settings-context-usage" part="context-usage">
|
|
194
|
-
<div class="settings-context-header">
|
|
195
|
-
<span class="settings-context-label">Context window</span>
|
|
196
|
-
<span class="settings-context-tokens">
|
|
197
|
-
${(x) => x.contextTokens!.toLocaleString()} /
|
|
198
|
-
${(x) => x.contextLimit!.toLocaleString()} tokens
|
|
199
|
-
(${(x) => Math.round((x.contextTokens! / x.contextLimit!) * 100)}%)
|
|
200
|
-
</span>
|
|
201
|
-
</div>
|
|
202
|
-
<${progressTag}
|
|
203
|
-
part="context-progress"
|
|
204
|
-
value="${(x) => Math.min(100, Math.round((x.contextTokens! / x.contextLimit!) * 100))}"
|
|
205
|
-
></${progressTag}>
|
|
206
|
-
</div>
|
|
207
|
-
`,
|
|
208
|
-
)}
|
|
209
|
-
`;
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Per-vendor AI budget meter (GENC-1464) — the money sibling of
|
|
213
|
-
* {@link platformContextUsageTemplate}, one row per vendor the host has fed
|
|
214
|
-
* figures for. The row text is unclamped (overshoot is real and shown); only
|
|
215
|
-
* the bar clamps — both computed in `settingsBudgetRows`, so the bindings here
|
|
216
|
-
* stay pure reads and the arithmetic is unit-testable.
|
|
217
|
-
*/
|
|
218
|
-
const platformBudgetUsageTemplate = (
|
|
219
|
-
progressTag: string,
|
|
220
|
-
buttonTag: string,
|
|
221
|
-
iconTag: string,
|
|
222
|
-
): ViewTemplate<FoundationAiAssistant> => html<FoundationAiAssistant>`
|
|
223
|
-
${when(
|
|
224
|
-
(x) => x.settingsBudgetUsageVisible,
|
|
225
|
-
html<FoundationAiAssistant>`
|
|
226
|
-
<div class="settings-budget-usage" part="budget-usage">
|
|
227
|
-
${repeat(
|
|
228
|
-
(x) => x.settingsBudgetRows,
|
|
229
|
-
html<SettingsBudgetRow, FoundationAiAssistant>`
|
|
230
|
-
<div class="settings-budget-vendor">
|
|
231
|
-
<div class="settings-budget-header">
|
|
232
|
-
<span class="settings-budget-label">${(row) => row.label} budget</span>
|
|
233
|
-
<span class="settings-budget-figures">${(row) => row.figures}</span>
|
|
234
|
-
</div>
|
|
235
|
-
<${progressTag}
|
|
236
|
-
part="budget-progress"
|
|
237
|
-
value="${(row) => row.barValue}"
|
|
238
|
-
></${progressTag}>
|
|
239
|
-
</div>
|
|
240
|
-
`,
|
|
241
|
-
)}
|
|
242
|
-
<!--
|
|
243
|
-
Freshness footer (GENC-1464): the rows above update per turn and at
|
|
244
|
-
the wall, which reads as "stale" to anyone watching the modal — the
|
|
245
|
-
label says when the figures arrived, the button asks the host for new
|
|
246
|
-
ones (see FoundationAiAssistant.requestBudgetRefresh). Below the rows
|
|
247
|
-
and left-aligned, reading as a footnote to the figures it describes.
|
|
248
|
-
-->
|
|
249
|
-
<div class="settings-budget-toolbar" part="budget-toolbar">
|
|
250
|
-
<${buttonTag}
|
|
251
|
-
appearance="stealth"
|
|
252
|
-
class="settings-budget-refresh"
|
|
253
|
-
part="budget-refresh"
|
|
254
|
-
title="Refresh budget figures"
|
|
255
|
-
aria-label="Refresh budget figures"
|
|
256
|
-
@click=${(x: FoundationAiAssistant) => x.requestBudgetRefresh()}
|
|
257
|
-
>
|
|
258
|
-
<${iconTag} name="arrows-rotate"></${iconTag}>
|
|
259
|
-
</${buttonTag}>
|
|
260
|
-
<span class="settings-budget-updated">${(x) => x.settingsBudgetUpdatedLabel}</span>
|
|
261
|
-
</div>
|
|
262
|
-
</div>
|
|
263
|
-
`,
|
|
264
|
-
)}
|
|
265
|
-
`;
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* The two usage meters in one shared, evenly-gapped column.
|
|
269
|
-
*
|
|
270
|
-
* Without it the context row and the FIRST budget row sit the section body's
|
|
271
|
-
* 4 units apart while the budget rows sit 2 apart — three visually identical
|
|
272
|
-
* meter rows reading as an uneven 4/2/2. The wrapper puts every meter row on
|
|
273
|
-
* the same 2-unit rhythm; see `.settings-usage-meters` in the styles.
|
|
274
|
-
*
|
|
275
|
-
* CONDITIONAL on purpose. An always-present wrapper is a permanent flex child
|
|
276
|
-
* of `.settings-modal-section-body`, so a host with neither meter would get a
|
|
277
|
-
* stray 4-unit gap after its model slot from a div that renders nothing. The
|
|
278
|
-
* gate is exactly the disjunction of the two children's own gates — both of
|
|
279
|
-
* which are `when`, which emplaces only comment markers when false, so a
|
|
280
|
-
* hidden meter contributes no flex child inside the wrapper either.
|
|
281
|
-
*
|
|
282
|
-
* Exported for `settings-modal.template.test.ts`, which renders it in isolation
|
|
283
|
-
* to pin both of those properties; `index.ts` does not re-export it, so it is
|
|
284
|
-
* not package API.
|
|
285
|
-
*
|
|
286
|
-
* @internal
|
|
287
|
-
*/
|
|
288
|
-
export const settingsUsageMetersTemplate = (
|
|
289
|
-
progressTag: string,
|
|
290
|
-
buttonTag: string,
|
|
291
|
-
iconTag: string,
|
|
292
|
-
): ViewTemplate<FoundationAiAssistant> => html<FoundationAiAssistant>`
|
|
293
|
-
${when(
|
|
294
|
-
(x) => x.settingsContextUsageVisible || x.settingsBudgetUsageVisible,
|
|
295
|
-
html<FoundationAiAssistant>`
|
|
296
|
-
<div class="settings-usage-meters">
|
|
297
|
-
${platformContextUsageTemplate(progressTag)}
|
|
298
|
-
${platformBudgetUsageTemplate(progressTag, buttonTag, iconTag)}
|
|
299
|
-
</div>
|
|
300
|
-
`,
|
|
301
|
-
)}
|
|
302
|
-
`;
|
|
303
|
-
|
|
304
|
-
const chatBotSettingsTemplate = (
|
|
305
|
-
switchTag: string,
|
|
306
|
-
buttonTag: string,
|
|
307
|
-
): ViewTemplate<FoundationAiAssistant> => html<FoundationAiAssistant>`
|
|
308
|
-
${when(
|
|
309
|
-
(x) => x.chatConfig.ui?.showToolCalls != null,
|
|
310
|
-
chatBotToggleRow(
|
|
311
|
-
'Show tool calls',
|
|
312
|
-
"Display each tool the chatbot invokes — file reads, searches, edits and commands — inline as it works, so you can follow exactly what it's doing behind the scenes.",
|
|
313
|
-
switchTag,
|
|
314
|
-
'toggle-tool-calls',
|
|
315
|
-
(x) => x.showToolCalls,
|
|
316
|
-
(x, c) => {
|
|
317
|
-
x.showToolCalls = readSwitchChecked(c.event);
|
|
318
|
-
},
|
|
319
|
-
),
|
|
320
|
-
)}
|
|
321
|
-
${when(
|
|
322
|
-
(x) => x.chatConfig.ui?.showThinkingSteps != null,
|
|
323
|
-
chatBotToggleRow(
|
|
324
|
-
'Show thinking',
|
|
325
|
-
"Reveal the assistant's reasoning as it works through your request, surfacing its intermediate thought process before it commits to a response.",
|
|
326
|
-
switchTag,
|
|
327
|
-
'toggle-thinking',
|
|
328
|
-
(x) => x.showThinkingSteps,
|
|
329
|
-
(x, c) => {
|
|
330
|
-
x.showThinkingSteps = readSwitchChecked(c.event);
|
|
331
|
-
},
|
|
332
|
-
),
|
|
333
|
-
)}
|
|
334
|
-
${when(
|
|
335
|
-
(x) => x.chatConfig.ui?.showNarration != null,
|
|
336
|
-
chatBotToggleRow(
|
|
337
|
-
'Show working',
|
|
338
|
-
"Show the assistant's running commentary — the short notes it writes alongside its actions as it works, separate from its reasoning and its final answer.",
|
|
339
|
-
switchTag,
|
|
340
|
-
'toggle-narration',
|
|
341
|
-
(x) => x.showNarration,
|
|
342
|
-
(x, c) => {
|
|
343
|
-
x.showNarration = readSwitchChecked(c.event);
|
|
344
|
-
},
|
|
345
|
-
),
|
|
346
|
-
)}
|
|
347
|
-
${when(
|
|
348
|
-
(x) => x.chatConfig.ui?.showAgentSwitchIndicator != null,
|
|
349
|
-
chatBotToggleRow(
|
|
350
|
-
'Show delegation',
|
|
351
|
-
'Show in the chat window when tasks are delegated to different agents.',
|
|
352
|
-
switchTag,
|
|
353
|
-
'toggle-agent-switch',
|
|
354
|
-
(x) => x.showAgentSwitchIndicator,
|
|
355
|
-
(x, c) => {
|
|
356
|
-
x.showAgentSwitchIndicator = readSwitchChecked(c.event);
|
|
357
|
-
},
|
|
358
|
-
),
|
|
359
|
-
)}
|
|
360
|
-
${when(
|
|
361
|
-
(x) => x.persistenceToggleable,
|
|
362
|
-
chatBotToggleRow(
|
|
363
|
-
'Remember chat',
|
|
364
|
-
'Save this conversation so it can be restored after a page refresh. Turning this off deletes the saved copy.',
|
|
365
|
-
switchTag,
|
|
366
|
-
'toggle-remember-chat',
|
|
367
|
-
(x) => x.persistenceActive,
|
|
368
|
-
(x, c) => {
|
|
369
|
-
x.setPersistenceEnabled(readSwitchChecked(c.event));
|
|
370
|
-
},
|
|
371
|
-
),
|
|
372
|
-
)}
|
|
373
|
-
${when(
|
|
374
|
-
(x) => x.chatConfig.ui?.animations?.userConfigurable === true,
|
|
375
|
-
settingsToggleRow(
|
|
376
|
-
'Animations',
|
|
377
|
-
'Choose which loading and activity indicators appear while the assistant is working.',
|
|
378
|
-
'toggle-animations',
|
|
379
|
-
animationsPickerTemplate(switchTag),
|
|
380
|
-
'column',
|
|
381
|
-
),
|
|
382
|
-
)}
|
|
383
|
-
`;
|
|
384
|
-
|
|
385
|
-
const appSettingsTemplate = (
|
|
386
|
-
switchTag: string,
|
|
387
|
-
iconTag: string,
|
|
388
|
-
): ViewTemplate<FoundationAiAssistant> => html<FoundationAiAssistant>`
|
|
389
|
-
<!--
|
|
390
|
-
Slot FIRST, ahead of the provider toggles. The assistant renders no heading for this
|
|
391
|
-
section, so whatever the host slots in has to be able to title it — and a heading below the
|
|
392
|
-
rows it names would title nothing. Anything the host wants under the toggles it can render
|
|
393
|
-
below them within its own slotted block.
|
|
394
|
-
-->
|
|
395
|
-
<slot name="settings-app" ${slotted('settingsAppSlotted')}></slot>
|
|
396
|
-
<!--
|
|
397
|
-
Sub-heading for the toggle group, rendered only when the host asks for one — both the text
|
|
398
|
-
and the icon come from its provider. It exists so a host whose slotted content covers other
|
|
399
|
-
ground can still mark these rows off from it.
|
|
400
|
-
-->
|
|
401
|
-
${when(
|
|
402
|
-
(x) => !!x.appSettingsTogglesHeading,
|
|
403
|
-
html<FoundationAiAssistant>`
|
|
404
|
-
<h4 class="ai-settings-section-title settings-app-toggles-title" part="app-toggles-title">
|
|
405
|
-
${when(
|
|
406
|
-
(x) => !!x.appSettingsTogglesHeading?.icon,
|
|
407
|
-
html<FoundationAiAssistant>`
|
|
408
|
-
<${iconTag} name="${(x) => x.appSettingsTogglesHeading?.icon}"></${iconTag}>
|
|
409
|
-
`,
|
|
410
|
-
)}
|
|
411
|
-
${(x) => x.appSettingsTogglesHeading?.title}
|
|
412
|
-
</h4>
|
|
413
|
-
`,
|
|
414
|
-
)}
|
|
415
|
-
${repeat(
|
|
416
|
-
(x) => x.visibleAppSettingsToggles,
|
|
417
|
-
html<AssistantAppSettingsToggle, FoundationAiAssistant>`
|
|
418
|
-
<div class="settings-app-toggle-block">
|
|
419
|
-
<div
|
|
420
|
-
class="settings-toggle-row"
|
|
421
|
-
part="${(toggle) => `${toggle.part ?? `app-toggle-${toggle.id}`}-row`}"
|
|
422
|
-
>
|
|
423
|
-
<div class="settings-toggle-text">
|
|
424
|
-
<div class="settings-toggle-title">${(toggle) => toggle.title}</div>
|
|
425
|
-
<div class="settings-toggle-desc">${(toggle) => toggle.description}</div>
|
|
426
|
-
</div>
|
|
427
|
-
<div class="settings-toggle-control">
|
|
428
|
-
<${switchTag}
|
|
429
|
-
part="${(toggle) => toggle.part ?? `app-toggle-${toggle.id}`}"
|
|
430
|
-
:checked=${(toggle, c) => c.parent.getAppSettingValue(toggle.id)}
|
|
431
|
-
?disabled=${(toggle) => toggle.disabled?.() ?? false}
|
|
432
|
-
@change=${(toggle, c) => {
|
|
433
|
-
c.parent.setAppSettingValue(toggle.id, readSwitchChecked(c.event));
|
|
434
|
-
}}
|
|
435
|
-
></${switchTag}>
|
|
436
|
-
</div>
|
|
437
|
-
</div>
|
|
438
|
-
${when(
|
|
439
|
-
(toggle) => !!toggle.hint?.(),
|
|
440
|
-
html<AssistantAppSettingsToggle>`
|
|
441
|
-
<div class="settings-toggle-hint">${(toggle) => toggle.hint?.() ?? ''}</div>
|
|
442
|
-
`,
|
|
443
|
-
)}
|
|
444
|
-
</div>
|
|
445
|
-
`,
|
|
446
|
-
)}
|
|
447
|
-
`;
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* One model chip. Shared by the live session and the history rows so the two can't drift — both
|
|
451
|
-
* already reduce to a distinct-model list, the live one via `uniqueProviderModels` and a row via
|
|
452
|
-
* `collectSessionModels`.
|
|
453
|
-
*/
|
|
454
|
-
const modelTagTemplate = html<CostSessionModelEntry>`
|
|
455
|
-
<span class="settings-model-tag vendor-${(entry) => entry.provider || 'generic'}">
|
|
456
|
-
${(entry) => entry.model}
|
|
457
|
-
</span>
|
|
458
|
-
`;
|
|
459
|
-
|
|
460
|
-
/**
|
|
461
|
-
* The four billing buckets for one `AggregateUsage`, wherever it comes from — the lifetime
|
|
462
|
-
* total, the live session, or a history row.
|
|
463
|
-
*
|
|
464
|
-
* Why four numbers instead of one: each bucket bills at a different rate, so a single token
|
|
465
|
-
* total can't explain a session that processed millions of tokens for pennies. Uncached input,
|
|
466
|
-
* cache read and cache write partition the prompt (they sum to it, never add on top), and
|
|
467
|
-
* output is what the model generated.
|
|
468
|
-
*
|
|
469
|
-
* Ordered input, output, cache read, cache write to match how Claude Code reports usage, so the
|
|
470
|
-
* two can be read side by side — comparing against it is what this breakdown exists for. Note
|
|
471
|
-
* this puts output between the three buckets that partition the prompt, so their relationship is
|
|
472
|
-
* carried by the tooltips rather than by adjacency.
|
|
473
|
-
*
|
|
474
|
-
* The two cache buckets carry a direction marker on their LABEL, not their value: below the input
|
|
475
|
-
* rate for reads, above it for writes. On the label because the rate is a fixed property of the
|
|
476
|
-
* bucket, whereas the value changes every turn — and because styling the values instead means a
|
|
477
|
-
* bucket reading 0 (every Gemini cache write, which has no write bucket to bill) renders in a
|
|
478
|
-
* dimmed treatment that looks disabled beside a normal 0. All four values stay identical.
|
|
479
|
-
*
|
|
480
|
-
* `partPrefix` keeps the shadow-part names caller-specific (`session-tokens-input`,
|
|
481
|
-
* `lifetime-tokens-input`, …) so a host can style one context without hitting the others.
|
|
482
|
-
*/
|
|
483
|
-
const tokenBreakdownTemplate = <T>(
|
|
484
|
-
usageOf: (x: T) => AggregateUsage,
|
|
485
|
-
partPrefix: string,
|
|
486
|
-
): ViewTemplate<T> => html<T>`
|
|
487
|
-
<div class="settings-token-breakdown" part="${partPrefix}-token-breakdown">
|
|
488
|
-
<!--
|
|
489
|
-
Titles the box. Nothing in it otherwise said "tokens": the four bucket names are the
|
|
490
|
-
token TYPES, not the unit, so the panel read as four unexplained numbers unless the
|
|
491
|
-
reader found the per-bucket tooltips.
|
|
492
|
-
-->
|
|
493
|
-
<div class="settings-token-breakdown-label">Tokens</div>
|
|
494
|
-
<div class="settings-token-buckets">
|
|
495
|
-
<div class="settings-token-bucket" part="${partPrefix}-tokens-input">
|
|
496
|
-
<span
|
|
497
|
-
class="settings-token-bucket-label"
|
|
498
|
-
title="Prompt tokens billed at the full uncached rate"
|
|
499
|
-
>
|
|
500
|
-
Input
|
|
501
|
-
</span>
|
|
502
|
-
<span
|
|
503
|
-
class="settings-token-bucket-value"
|
|
504
|
-
:innerHTML="${(x: T) => formatCompactTokenCountSafe(usageOf(x).uncachedInputTokens)}"
|
|
505
|
-
></span>
|
|
506
|
-
</div>
|
|
507
|
-
<div class="settings-token-bucket" part="${partPrefix}-tokens-output">
|
|
508
|
-
<span
|
|
509
|
-
class="settings-token-bucket-label"
|
|
510
|
-
title="Tokens the model generated, including reasoning tokens billed as output"
|
|
511
|
-
>
|
|
512
|
-
Output
|
|
513
|
-
</span>
|
|
514
|
-
<span
|
|
515
|
-
class="settings-token-bucket-value"
|
|
516
|
-
:innerHTML="${(x: T) => formatCompactTokenCountSafe(usageOf(x).outputTokens)}"
|
|
517
|
-
></span>
|
|
518
|
-
</div>
|
|
519
|
-
<div class="settings-token-bucket" part="${partPrefix}-tokens-cache-read">
|
|
520
|
-
<span
|
|
521
|
-
class="settings-token-bucket-label"
|
|
522
|
-
title="Prompt tokens served from the provider cache — billed at a fraction of the uncached rate"
|
|
523
|
-
>
|
|
524
|
-
Cache read
|
|
525
|
-
<!--
|
|
526
|
-
aria-hidden: the marker is a restatement of the tooltip this label already carries, and
|
|
527
|
-
a screen reader announcing "black down-pointing small triangle" mid-heading is noise.
|
|
528
|
-
-->
|
|
529
|
-
<span class="settings-token-bucket-rate" aria-hidden="true">▾</span>
|
|
530
|
-
</span>
|
|
531
|
-
<span
|
|
532
|
-
class="settings-token-bucket-value"
|
|
533
|
-
:innerHTML="${(x: T) => formatCompactTokenCountSafe(usageOf(x).cacheReadTokens)}"
|
|
534
|
-
></span>
|
|
535
|
-
</div>
|
|
536
|
-
<div class="settings-token-bucket" part="${partPrefix}-tokens-cache-write">
|
|
537
|
-
<span
|
|
538
|
-
class="settings-token-bucket-label"
|
|
539
|
-
title="Prompt tokens written to the provider cache — billed at a premium over the uncached rate"
|
|
540
|
-
>
|
|
541
|
-
Cache write
|
|
542
|
-
<span class="settings-token-bucket-rate" aria-hidden="true">▴</span>
|
|
543
|
-
</span>
|
|
544
|
-
<span
|
|
545
|
-
class="settings-token-bucket-value"
|
|
546
|
-
:innerHTML="${(x: T) => formatCompactTokenCountSafe(usageOf(x).cacheWriteTokens)}"
|
|
547
|
-
></span>
|
|
548
|
-
</div>
|
|
549
|
-
</div>
|
|
550
|
-
</div>
|
|
551
|
-
`;
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* Lifetime usage across every project in the history scope.
|
|
555
|
-
*
|
|
556
|
-
* Sits under the "Build history" heading, above the rows it totals — the live block leads the tab
|
|
557
|
-
* instead, because the project open now is what a user came to check. Being inside the history
|
|
558
|
-
* grouping is also what identifies this figure: it is the sum of the rows below it, not a rival
|
|
559
|
-
* reading of the block above it.
|
|
560
|
-
*
|
|
561
|
-
* It must not sit inside the live block, which is where it began life as a lone "Total build
|
|
562
|
-
* cost": the live badge and project name directly above it implied the total belonged to the open
|
|
563
|
-
* project.
|
|
564
|
-
*/
|
|
565
|
-
const lifetimeUsageTemplate =
|
|
566
|
-
(): ViewTemplate<FoundationAiAssistant> => html<FoundationAiAssistant>`
|
|
567
|
-
${when(
|
|
568
|
-
(x) => x.settingsCostLifetimeVisible,
|
|
569
|
-
html<FoundationAiAssistant>`
|
|
570
|
-
<div class="settings-lifetime-usage" part="lifetime-usage">
|
|
571
|
-
<div class="settings-lifetime-usage-top">
|
|
572
|
-
<span class="settings-lifetime-label">Lifetime usage</span>
|
|
573
|
-
</div>
|
|
574
|
-
<div class="settings-usage-row">
|
|
575
|
-
<div
|
|
576
|
-
class="settings-build-stat"
|
|
577
|
-
part="lifetime-cost"
|
|
578
|
-
?hidden=${(x) => !x.resolvedCostHistory.showCost}
|
|
579
|
-
>
|
|
580
|
-
<div class="settings-build-stat-label">Total build cost</div>
|
|
581
|
-
<div class="settings-build-stat-value">
|
|
582
|
-
<span class="prefix">$</span>
|
|
583
|
-
<span class="value">${(x) => formatUsdAmount(x.cumulativeCostUsd)}</span>
|
|
584
|
-
</div>
|
|
585
|
-
</div>
|
|
586
|
-
<div
|
|
587
|
-
class="settings-usage-row-tokens"
|
|
588
|
-
?hidden=${(x) => !x.resolvedCostHistory.showTokens}
|
|
589
|
-
>
|
|
590
|
-
${tokenBreakdownTemplate<FoundationAiAssistant>((x) => x.cumulativeUsage, 'lifetime')}
|
|
591
|
-
</div>
|
|
592
|
-
</div>
|
|
593
|
-
</div>
|
|
594
|
-
`,
|
|
595
|
-
)}
|
|
596
|
-
`;
|
|
597
|
-
|
|
598
|
-
const sessionCostSummaryTemplate =
|
|
599
|
-
(): ViewTemplate<FoundationAiAssistant> => html<FoundationAiAssistant>`
|
|
600
|
-
${when(
|
|
601
|
-
(x) => x.settingsCostSummaryVisible,
|
|
602
|
-
html<FoundationAiAssistant>`
|
|
603
|
-
<div class="settings-current-build" part="session-cost-summary">
|
|
604
|
-
<div class="settings-current-build-top">
|
|
605
|
-
<span class="settings-live-badge">
|
|
606
|
-
<span class="settings-live-dot"></span>
|
|
607
|
-
${(x) => x.resolvedCostHistory.badgeLabel}
|
|
608
|
-
</span>
|
|
609
|
-
${when(
|
|
610
|
-
(x) => !!x.liveCostSessionTitle,
|
|
611
|
-
html<FoundationAiAssistant>`
|
|
612
|
-
<span class="settings-current-build-name">${(x) => x.liveCostSessionTitle}</span>
|
|
613
|
-
`,
|
|
614
|
-
)}
|
|
615
|
-
</div>
|
|
616
|
-
<div class="settings-usage-row">
|
|
617
|
-
<div
|
|
618
|
-
class="settings-build-stat"
|
|
619
|
-
part="session-cost"
|
|
620
|
-
?hidden=${(x) => !x.resolvedCostHistory.showCost}
|
|
621
|
-
>
|
|
622
|
-
<!--
|
|
623
|
-
Label states the scope rather than implying one. These figures are whatever
|
|
624
|
-
the open transcript proves, so they are the project's whole history exactly
|
|
625
|
-
when that transcript is restored on load, and only this page-load's when it
|
|
626
|
-
isn't. Same number, two meanings — so the caller can't be left guessing.
|
|
627
|
-
-->
|
|
628
|
-
<div class="settings-build-stat-label">
|
|
629
|
-
${(x) => (x.liveUsageIsProjectLifetime ? 'Project cost' : 'Session cost')}
|
|
630
|
-
</div>
|
|
631
|
-
<div class="settings-build-stat-value">
|
|
632
|
-
<span class="prefix">$</span>
|
|
633
|
-
<span class="value">${(x) => formatUsdAmount(x.sessionCostUsd)}</span>
|
|
634
|
-
</div>
|
|
635
|
-
</div>
|
|
636
|
-
<div
|
|
637
|
-
class="settings-usage-row-tokens"
|
|
638
|
-
?hidden=${(x) => !x.resolvedCostHistory.showTokens}
|
|
639
|
-
>
|
|
640
|
-
${tokenBreakdownTemplate<FoundationAiAssistant>((x) => x.sessionUsage, 'session')}
|
|
641
|
-
</div>
|
|
642
|
-
</div>
|
|
643
|
-
${when(
|
|
644
|
-
(x) => x.chatConfig.ui?.showActiveModel !== false && x.uniqueProviderModels.length > 0,
|
|
645
|
-
html<FoundationAiAssistant>`
|
|
646
|
-
<div class="settings-model-tags" part="session-model-tags">
|
|
647
|
-
${repeat((x) => x.uniqueProviderModels, modelTagTemplate)}
|
|
648
|
-
</div>
|
|
649
|
-
`,
|
|
650
|
-
)}
|
|
651
|
-
</div>
|
|
652
|
-
`,
|
|
653
|
-
)}
|
|
654
|
-
`;
|
|
655
|
-
|
|
656
|
-
const costSessionHistoryTemplate = (
|
|
657
|
-
iconTag: string,
|
|
658
|
-
buttonTag: string,
|
|
659
|
-
): ViewTemplate<FoundationAiAssistant> => html<FoundationAiAssistant>`
|
|
660
|
-
${repeat(
|
|
661
|
-
(x) => x.sortedCostSessionHistory,
|
|
662
|
-
html<CostSessionRecord>`
|
|
663
|
-
<div class="settings-cost-history-row" part="cost-history-row">
|
|
664
|
-
<div class="settings-cost-history-row-content">
|
|
665
|
-
<span class="settings-cost-history-icon" part="cost-history-icon" aria-hidden="true">
|
|
666
|
-
<${iconTag} name="table-cells-large"></${iconTag}>
|
|
667
|
-
</span>
|
|
668
|
-
<div class="settings-cost-history-row-body">
|
|
669
|
-
<div class="settings-cost-history-row-left">
|
|
670
|
-
<div class="settings-cost-history-row-title">
|
|
671
|
-
${(record) => record.title}
|
|
672
|
-
</div>
|
|
673
|
-
<div class="settings-cost-history-row-date">
|
|
674
|
-
${(record) => formatCostSessionDate(record.updatedAt)}
|
|
675
|
-
</div>
|
|
676
|
-
</div>
|
|
677
|
-
<!--
|
|
678
|
-
Cost and the delete control live together so they centre against each other.
|
|
679
|
-
The button used to sit outside the row body, held in place by a negative margin
|
|
680
|
-
tuned for when this column had a second line (a merged token total); that line
|
|
681
|
-
is gone, and a nudge measured against a removed sibling is exactly the kind that
|
|
682
|
-
rots silently.
|
|
683
|
-
-->
|
|
684
|
-
<div class="settings-cost-history-row-right">
|
|
685
|
-
<div class="settings-cost-history-row-metrics">
|
|
686
|
-
<div class="settings-cost-history-row-cost">
|
|
687
|
-
${(record) => formatUsd(record.usage.costUsd)}
|
|
688
|
-
</div>
|
|
689
|
-
</div>
|
|
690
|
-
<${buttonTag}
|
|
691
|
-
class="settings-cost-history-delete"
|
|
692
|
-
part="cost-history-delete"
|
|
693
|
-
appearance="stealth"
|
|
694
|
-
aria-label="Remove from build history"
|
|
695
|
-
@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))}
|
|
696
|
-
>
|
|
697
|
-
<${iconTag} name="trash"></${iconTag}>
|
|
698
|
-
</${buttonTag}>
|
|
699
|
-
</div>
|
|
700
|
-
</div>
|
|
701
|
-
</div>
|
|
702
|
-
<!--
|
|
703
|
-
The same four buckets as the live block, on its own line below the row rather than
|
|
704
|
-
beside the cost — the row's own width is spoken for by title, cost and delete.
|
|
705
|
-
Replaces a merged total that could not explain a huge token count at a small cost
|
|
706
|
-
without hovering for a tooltip.
|
|
707
|
-
-->
|
|
708
|
-
<div
|
|
709
|
-
class="settings-cost-history-row-content settings-cost-history-row-breakdown"
|
|
710
|
-
?hidden=${(record, c) =>
|
|
711
|
-
!(c.parent as FoundationAiAssistant).resolvedCostHistory.showTokens}
|
|
712
|
-
>
|
|
713
|
-
${tokenBreakdownTemplate<CostSessionRecord>((record) => record.usage, 'cost-history-row')}
|
|
714
|
-
</div>
|
|
715
|
-
${when(
|
|
716
|
-
(record) => record.models.length > 0,
|
|
717
|
-
html<CostSessionRecord>`
|
|
718
|
-
<div
|
|
719
|
-
class="settings-cost-history-row-content settings-model-tags settings-cost-history-model-tags"
|
|
720
|
-
>
|
|
721
|
-
${repeat((record) => record.models, modelTagTemplate)}
|
|
722
|
-
</div>
|
|
723
|
-
`,
|
|
724
|
-
)}
|
|
725
|
-
</div>
|
|
726
|
-
`,
|
|
727
|
-
)}
|
|
728
|
-
`;
|
|
729
|
-
|
|
730
|
-
/**
|
|
731
|
-
* Modal shell for assistant settings — Configuration and Usage tabs, section slots for
|
|
732
|
-
* app-specific UI, and built-in chat-bot toggles.
|
|
733
|
-
*/
|
|
734
|
-
export const SettingsModalTemplate = (
|
|
735
|
-
designSystemPrefix: string,
|
|
736
|
-
): ViewTemplate<FoundationAiAssistant> => {
|
|
737
|
-
const modalTag = `${designSystemPrefix}-modal`;
|
|
738
|
-
const buttonTag = `${designSystemPrefix}-button`;
|
|
739
|
-
const switchTag = `${designSystemPrefix}-switch`;
|
|
740
|
-
const iconTag = `${designSystemPrefix}-icon`;
|
|
741
|
-
const progressTag = `${designSystemPrefix}-progress`;
|
|
742
|
-
const tabsTag = `${designSystemPrefix}-tabs`;
|
|
743
|
-
const tabTag = `${designSystemPrefix}-tab`;
|
|
744
|
-
const tabPanelTag = `${designSystemPrefix}-tab-panel`;
|
|
745
|
-
|
|
746
|
-
const settingsTabPanel = html<FoundationAiAssistant>`
|
|
747
|
-
<${tabPanelTag}
|
|
748
|
-
slot="tabpanel"
|
|
749
|
-
class="settings-modal-tab-panel"
|
|
750
|
-
part="settings-tab-panel"
|
|
751
|
-
>
|
|
752
|
-
<div class="settings-modal-body" part="settings-modal-body">
|
|
753
|
-
<section
|
|
754
|
-
class="settings-modal-section"
|
|
755
|
-
part="settings-section-model"
|
|
756
|
-
?hidden=${(x) => !x.settingsModelSectionVisible}
|
|
757
|
-
>
|
|
758
|
-
<h3 class="ai-settings-section-title">
|
|
759
|
-
<${iconTag} name="microchip"></${iconTag}> AI Model Settings
|
|
760
|
-
</h3>
|
|
761
|
-
<div class="settings-modal-section-body">
|
|
762
|
-
<slot name="settings-model" ${slotted('settingsModelSlotted')}></slot>
|
|
763
|
-
${settingsUsageMetersTemplate(progressTag, buttonTag, iconTag)}
|
|
764
|
-
</div>
|
|
765
|
-
</section>
|
|
766
|
-
<!--
|
|
767
|
-
Above the host section, deliberately. This is the assistant's own control, so it belongs
|
|
768
|
-
with the assistant's other sections rather than trailing the host's — where, now that the
|
|
769
|
-
host section carries no heading of its own, it read as one more of the host's settings.
|
|
770
|
-
-->
|
|
771
|
-
${when(
|
|
772
|
-
(x) => x.chatConfig.ui?.allowDebugDownload === true,
|
|
773
|
-
html<FoundationAiAssistant>`
|
|
774
|
-
<section class="settings-modal-section" part="settings-section-agent-log">
|
|
775
|
-
<div class="settings-modal-section-body">
|
|
776
|
-
${settingsToggleRow(
|
|
777
|
-
'Download agent log',
|
|
778
|
-
"Export a structured debug timeline of this session's agent activity.",
|
|
779
|
-
'download-agent-log',
|
|
780
|
-
html<FoundationAiAssistant>`
|
|
781
|
-
<${buttonTag}
|
|
782
|
-
part="download-button"
|
|
783
|
-
appearance="outline"
|
|
784
|
-
?disabled=${(x) => x.downloadingDebugLog}
|
|
785
|
-
@click=${(x) => x.downloadDebugLog()}
|
|
786
|
-
>
|
|
787
|
-
${when(
|
|
788
|
-
(x) => x.downloadingDebugLog,
|
|
789
|
-
html<FoundationAiAssistant>`
|
|
790
|
-
<span
|
|
791
|
-
class="download-spinner"
|
|
792
|
-
part="download-spinner"
|
|
793
|
-
aria-hidden="true"
|
|
794
|
-
></span>
|
|
795
|
-
`,
|
|
796
|
-
)}
|
|
797
|
-
${(x) => (x.downloadingDebugLog ? 'Downloading…' : 'Download')}
|
|
798
|
-
</${buttonTag}>
|
|
799
|
-
`,
|
|
800
|
-
'row-centered',
|
|
801
|
-
)}
|
|
802
|
-
</div>
|
|
803
|
-
</section>
|
|
804
|
-
`,
|
|
805
|
-
)}
|
|
806
|
-
<!--
|
|
807
|
-
No heading here, by design. This section belongs to the host: only it knows what its
|
|
808
|
-
settings are called, so the assistant supplies neither text nor icon and the host titles
|
|
809
|
-
the section from the slot. See assistantSettingsSectionTitleStyles for the heading style
|
|
810
|
-
it can apply to match the sections above and below.
|
|
811
|
-
-->
|
|
812
|
-
<section
|
|
813
|
-
class="settings-modal-section"
|
|
814
|
-
part="settings-section-app"
|
|
815
|
-
?hidden=${(x) => !x.settingsAppSectionVisible}
|
|
816
|
-
>
|
|
817
|
-
<div class="settings-modal-section-body">
|
|
818
|
-
${appSettingsTemplate(switchTag, iconTag)}
|
|
819
|
-
</div>
|
|
820
|
-
</section>
|
|
821
|
-
<section class="settings-modal-section" part="settings-section-chat">
|
|
822
|
-
<h3 class="ai-settings-section-title">
|
|
823
|
-
<${iconTag} name="comment"></${iconTag}> AI Chat Bot Settings
|
|
824
|
-
</h3>
|
|
825
|
-
<p class="settings-modal-section-note">These options only control what you see in the chat window and do not control model behaviour.</p>
|
|
826
|
-
<div class="settings-modal-section-body">
|
|
827
|
-
${chatBotSettingsTemplate(switchTag, buttonTag)}
|
|
828
|
-
</div>
|
|
829
|
-
</section>
|
|
830
|
-
</div>
|
|
831
|
-
</${tabPanelTag}>
|
|
832
|
-
`;
|
|
833
|
-
|
|
834
|
-
const costTabPanel = html<FoundationAiAssistant>`
|
|
835
|
-
<${tabPanelTag}
|
|
836
|
-
slot="tabpanel"
|
|
837
|
-
class="settings-modal-tab-panel"
|
|
838
|
-
part="cost-tab-panel"
|
|
839
|
-
>
|
|
840
|
-
<div class="settings-modal-body" part="settings-modal-body">
|
|
841
|
-
${sessionCostSummaryTemplate()}
|
|
842
|
-
<div
|
|
843
|
-
class="settings-cost-current"
|
|
844
|
-
part="settings-cost-current"
|
|
845
|
-
?hidden=${(x) => !x.settingsCostCurrentSectionVisible}
|
|
846
|
-
>
|
|
847
|
-
<slot name="settings-cost-current" ${slotted('settingsCostCurrentSlotted')}></slot>
|
|
848
|
-
</div>
|
|
849
|
-
<!--
|
|
850
|
-
The heading covers everything below it, lifetime total included — that total IS the sum of
|
|
851
|
-
the history rows, so it reads as their summary rather than a rival figure. Hence the
|
|
852
|
-
heading's own visibility gate, which is broader than the rows'.
|
|
853
|
-
-->
|
|
854
|
-
<p class="settings-cost-history-title" ?hidden=${(x) => !x.settingsCostHistoryHeadingVisible}>
|
|
855
|
-
Build history
|
|
856
|
-
</p>
|
|
857
|
-
${lifetimeUsageTemplate()}
|
|
858
|
-
<div
|
|
859
|
-
class="settings-cost-history"
|
|
860
|
-
part="settings-cost-history"
|
|
861
|
-
?hidden=${(x) => !x.settingsCostHistorySectionVisible}
|
|
862
|
-
>
|
|
863
|
-
${costSessionHistoryTemplate(iconTag, buttonTag)}
|
|
864
|
-
<slot name="settings-cost-history" ${slotted('settingsCostHistorySlotted')}></slot>
|
|
865
|
-
</div>
|
|
866
|
-
</div>
|
|
867
|
-
</${tabPanelTag}>
|
|
868
|
-
`;
|
|
869
|
-
|
|
870
|
-
return html<FoundationAiAssistant>`
|
|
871
|
-
<${modalTag}
|
|
872
|
-
class="settings-modal"
|
|
873
|
-
part="settings-modal"
|
|
874
|
-
exportparts="dialog: settings-dialog, content: settings-content, top: settings-top, bottom: settings-footer"
|
|
875
|
-
${ref('settingsModal')}
|
|
876
|
-
initial-width="620"
|
|
877
|
-
@close=${(x) => x.onSettingsModalClosed()}
|
|
878
|
-
>
|
|
879
|
-
<div slot="top" class="settings-modal-header" part="settings-modal-header">
|
|
880
|
-
<h2 class="settings-modal-title">
|
|
881
|
-
<${iconTag} name="cog"></${iconTag}> Settings
|
|
882
|
-
</h2>
|
|
883
|
-
</div>
|
|
884
|
-
<div class="settings-modal-content" part="settings-modal-content">
|
|
885
|
-
<${tabsTag}
|
|
886
|
-
class="settings-modal-tabs"
|
|
887
|
-
part="settings-modal-tabs"
|
|
888
|
-
appearance="secondary"
|
|
889
|
-
${ref('settingsTabsEl')}
|
|
890
|
-
@change=${(x, c) => x.onSettingsModalTabsChange(c.event)}
|
|
891
|
-
><${tabTag}
|
|
892
|
-
slot="tab"
|
|
893
|
-
id="settings"
|
|
894
|
-
appearance="secondary"
|
|
895
|
-
class="settings-modal-tab"
|
|
896
|
-
part="settings-modal-tab-settings"
|
|
897
|
-
><${iconTag} name="sliders"></${iconTag}> Configuration</${tabTag}>${when(
|
|
898
|
-
(x) => x.settingsCostTabVisible,
|
|
899
|
-
html<FoundationAiAssistant>`<${tabTag}
|
|
900
|
-
slot="tab"
|
|
901
|
-
id="cost"
|
|
902
|
-
appearance="secondary"
|
|
903
|
-
class="settings-modal-tab"
|
|
904
|
-
part="settings-modal-tab-cost"
|
|
905
|
-
><${iconTag} name="chart-simple"></${iconTag}> Usage</${tabTag}>`,
|
|
906
|
-
)}${settingsTabPanel}${when((x) => x.settingsCostTabVisible, costTabPanel)}</${tabsTag}>
|
|
907
|
-
</div>
|
|
908
|
-
<div slot="bottom" class="settings-modal-footer" part="settings-modal-footer">
|
|
909
|
-
<div class="settings-modal-footer-actions">
|
|
910
|
-
${when(
|
|
911
|
-
(x) => x.settingsModalTab === 'cost',
|
|
912
|
-
html<FoundationAiAssistant>`
|
|
913
|
-
<span class="settings-disclaimer">
|
|
914
|
-
${when(
|
|
915
|
-
(x) => !!x.resolvedCostHistory.summaryHint,
|
|
916
|
-
html<FoundationAiAssistant>`
|
|
917
|
-
${(x) => x.resolvedCostHistory.summaryHint}
|
|
918
|
-
`,
|
|
919
|
-
)}Costs
|
|
920
|
-
are estimated from token usage at list
|
|
921
|
-
price.${when(
|
|
922
|
-
// Only where the markers actually render. Every place they appear is gated on
|
|
923
|
-
// showTokens, so with cost figures but no token buckets this sentence would
|
|
924
|
-
// define two glyphs that are nowhere on screen.
|
|
925
|
-
(x) => x.resolvedCostHistory.showTokens,
|
|
926
|
-
html<FoundationAiAssistant>`
|
|
927
|
-
Cache reads bill below the input rate (▾) and cache writes above it (▴).
|
|
928
|
-
`,
|
|
929
|
-
)}
|
|
930
|
-
</span>
|
|
931
|
-
`,
|
|
932
|
-
)}
|
|
933
|
-
<${buttonTag}
|
|
934
|
-
appearance="outline"
|
|
935
|
-
part="settings-done-button"
|
|
936
|
-
class="settings-done-button"
|
|
937
|
-
@click=${(x) => x.closeSettingsModal()}
|
|
938
|
-
>Done</${buttonTag}>
|
|
939
|
-
</div>
|
|
940
|
-
</div>
|
|
941
|
-
</${modalTag}>
|
|
942
|
-
`;
|
|
943
|
-
};
|