@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
package/dist/esm/main/main.js
CHANGED
|
@@ -54,15 +54,14 @@ import { ChatSuggestions } from '../suggestions/chat-suggestions';
|
|
|
54
54
|
import { AnimatedPanelToggle } from '../utils/animated-panel-toggle';
|
|
55
55
|
import { resolveExclusiveLoadingStyle } from '../utils/animation-exclusivity';
|
|
56
56
|
import { collectSessionModels } from '../utils/collect-session-models';
|
|
57
|
-
import {
|
|
57
|
+
import { clearCostSessionHistory, isCostSessionRecord, loadCostSessionHistory, resolveBankedUsage, saveCostSessionHistory, sortRecordsByRecency, upsertRecord, } from '../utils/cost-session-history';
|
|
58
58
|
import { deriveCostSessionTitleFromMessages, resolveCostSessionTitle, } from '../utils/derive-cost-session-title';
|
|
59
59
|
import { logger } from '../utils/logger';
|
|
60
60
|
import { filterVisibleMessages, trailingInteractionRow } from '../utils/message-partition';
|
|
61
61
|
import { resolveCostHistoryConfig, } from '../utils/resolve-cost-history-config';
|
|
62
62
|
import { resolvePreferenceBaseline } from '../utils/resolve-preference-baseline';
|
|
63
63
|
import { stripAgentHandlers } from '../utils/strip-agent-handlers';
|
|
64
|
-
import {
|
|
65
|
-
import { sumTokens } from '../utils/sum-tokens';
|
|
64
|
+
import { addUsage, emptyUsage, sumUsage, totalTokens } from '../utils/sum-usage';
|
|
66
65
|
import { expandToolTree } from '../utils/tool-fold';
|
|
67
66
|
import { styles } from './main.styles';
|
|
68
67
|
import { FoundationAiAssistantTemplate } from './main.template';
|
|
@@ -99,6 +98,13 @@ function sanitizeIconMarkup(markup) {
|
|
|
99
98
|
*/
|
|
100
99
|
const AGENT_PICKER_CLOSE_MS = 200;
|
|
101
100
|
const SESSION_MENU_CLOSE_MS = 200;
|
|
101
|
+
/**
|
|
102
|
+
* How long cost-ledger writes coalesce. Comfortably longer than the gap between the turns of a
|
|
103
|
+
* tool loop, so a multi-step run writes once rather than per turn, and short enough that a flush
|
|
104
|
+
* has landed well before a user could close the tab. Nothing reads the stored ledger while the
|
|
105
|
+
* assistant is running — the Usage tab renders the in-memory list — so the delay is invisible.
|
|
106
|
+
*/
|
|
107
|
+
const LEDGER_FLUSH_DEBOUNCE_MS = 2000;
|
|
102
108
|
/** Drag-to-resize bounds for the chat input (composer), in px. */
|
|
103
109
|
const COMPOSER_MIN_HEIGHT_PX = 48;
|
|
104
110
|
const COMPOSER_MAX_HEIGHT_PX = 400;
|
|
@@ -119,10 +125,13 @@ avoidTreeShaking(AiChatMarkdown, AiChatInteractionWrapper, AiHaloOverlay, AiWave
|
|
|
119
125
|
*
|
|
120
126
|
* Popout/collapse coordination uses `agenticActivityBus` topics `chat-popout` and `chat-popin` — not DOM `CustomEvent`s on this element.
|
|
121
127
|
*
|
|
122
|
-
* **Cost build history:** opt-in via `chatConfig.costHistory.enabled`. When enabled,
|
|
123
|
-
*
|
|
124
|
-
* element `id`, or `'default'`)
|
|
125
|
-
*
|
|
128
|
+
* **Cost build history:** opt-in via `chatConfig.costHistory.enabled`. When enabled, each
|
|
129
|
+
* session's usage is kept as exactly ONE row per session key in `localStorage` (scoped by
|
|
130
|
+
* `costHistory.scope`, the element `id`, or `'default'`), upserted as spend accrues. So a
|
|
131
|
+
* row is a project's lifetime usage rather than a visit to it, and the Usage tab's total is
|
|
132
|
+
* the sum of the rows alone — the live session is never added on top, because the active
|
|
133
|
+
* project's own row already reflects it. Hosts may call
|
|
134
|
+
* {@link FoundationAiAssistant.finalizeCostSession} to flush early; it is idempotent.
|
|
126
135
|
*
|
|
127
136
|
* @fires chat-header-mousedown - Fired when the user presses the chat header in `popout-mode="expand"` (for drag-to-popout hosts). Bubbles and composed. detail: `ChatHeaderMouseDownDetail`
|
|
128
137
|
* @fires session-cleared - Fired after the session is wiped (the lifecycle menu's Clear). The payload is captured before teardown so the host can clean up any external state the active agent was working on. Bubbles and composed. detail: `SessionClearedDetail`
|
|
@@ -176,19 +185,37 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
176
185
|
this.settingsAppSlotted = [];
|
|
177
186
|
this.settingsCostCurrentSlotted = [];
|
|
178
187
|
this.settingsCostHistorySlotted = [];
|
|
179
|
-
/** Persisted finalized cost sessions shown on the
|
|
188
|
+
/** Persisted finalized cost sessions shown on the Usage tab build history list. */
|
|
180
189
|
this.costSessionHistory = [];
|
|
181
190
|
/** Whether the splash overlay is currently showing (no messages and showSplash is enabled). Reflected as a boolean attribute on the host. */
|
|
182
191
|
this.showingSplash = false;
|
|
183
192
|
/** Title tracked for the in-flight cost session (used when `header-title` changes). */
|
|
184
193
|
this._activeCostSessionTitle = '';
|
|
185
|
-
/**
|
|
186
|
-
this.
|
|
194
|
+
/** Memoised pre-transcript spend for `_bankedFor` — see `bankedUsageFor`. */
|
|
195
|
+
this._bankedUsage = emptyUsage();
|
|
196
|
+
/**
|
|
197
|
+
* Whether the row list reflects storage yet. Gates cost writes so a project's banked
|
|
198
|
+
* spend is never derived from a ledger that simply hasn't arrived.
|
|
199
|
+
*/
|
|
200
|
+
this._costHistoryLoaded = false;
|
|
201
|
+
/**
|
|
202
|
+
* Set when a provider read failed. Latches writes off for this page-load: `saveCostHistory`
|
|
203
|
+
* replaces the whole stored list, so writing anything derived from the empty list we fell back
|
|
204
|
+
* to would destroy rows we never managed to read.
|
|
205
|
+
*/
|
|
206
|
+
this._ledgerUnreadable = false;
|
|
207
|
+
/** Pending (adopted but unwritten) ledger changes — see `persistCostHistory`. */
|
|
208
|
+
this._ledgerDirty = false;
|
|
209
|
+
// No once-guard for cost-session writes: the write is an upsert keyed by the session
|
|
210
|
+
// key, so repeat calls (pagehide, title change, per-turn) replace the same row and are
|
|
211
|
+
// idempotent. The old flag existed only because the write appended and reset.
|
|
187
212
|
// Single-view model (GENC-1351 Option A): the one assistant element always finalizes
|
|
188
213
|
// the cost session on tab close — there is no hidden twin to defer to, so this fires
|
|
189
214
|
// unconditionally (the old bubble-vs-docked gating flag is gone with the two-view model).
|
|
190
215
|
this._handlePageHide = () => {
|
|
191
216
|
this.finalizeCostSession();
|
|
217
|
+
// Straight to storage: the debounce timer will never fire once the page is going away.
|
|
218
|
+
this.flushCostHistory();
|
|
192
219
|
};
|
|
193
220
|
this.haloStartPublished = false;
|
|
194
221
|
/**
|
|
@@ -669,40 +696,114 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
669
696
|
var _a;
|
|
670
697
|
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setContextLimit(value);
|
|
671
698
|
}
|
|
672
|
-
/**
|
|
673
|
-
|
|
699
|
+
/**
|
|
700
|
+
* Cost plus the four token buckets for this session — derived from the transcript
|
|
701
|
+
* on every change, so it includes sub-agent turns and spend banked by a compaction.
|
|
702
|
+
*/
|
|
703
|
+
get sessionUsage() {
|
|
674
704
|
var _a, _b;
|
|
675
|
-
return (_b = (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.
|
|
705
|
+
return (_b = (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.sessionUsage) !== null && _b !== void 0 ? _b : emptyUsage();
|
|
676
706
|
}
|
|
677
|
-
set
|
|
707
|
+
set sessionUsage(value) {
|
|
678
708
|
var _a;
|
|
679
|
-
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.
|
|
709
|
+
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setSessionUsage(value);
|
|
680
710
|
}
|
|
681
|
-
/**
|
|
682
|
-
|
|
683
|
-
|
|
711
|
+
/**
|
|
712
|
+
* Aggregated USD cost across every chat turn in this session.
|
|
713
|
+
*
|
|
714
|
+
* Read-only (unlike previously): it is a projection of `sessionUsage`, and a
|
|
715
|
+
* host assigning it would have set a figure the next transcript change overwrites.
|
|
716
|
+
*/
|
|
717
|
+
get sessionCostUsd() {
|
|
718
|
+
return this.sessionUsage.costUsd;
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* Distinct models the registry currently resolves to — the live session's model chips.
|
|
722
|
+
*
|
|
723
|
+
* `providerStatuses` carries one entry per registry SLOT, so a vendor configured across several
|
|
724
|
+
* tiers that happen to resolve to the same model reports it once per tier, and the chips
|
|
725
|
+
* rendered it once per tier too. Which tier a model came from is not what these chips are for.
|
|
726
|
+
*
|
|
727
|
+
* Deduped on the label actually displayed, not on `status.model`: a slot whose provider reports
|
|
728
|
+
* no model falls back to the slot's own name, and those are distinct per slot, so keying on the
|
|
729
|
+
* label keeps them from collapsing into one another.
|
|
730
|
+
*/
|
|
731
|
+
get uniqueProviderModels() {
|
|
732
|
+
var _a, _b, _c, _d;
|
|
733
|
+
const seen = new Map();
|
|
734
|
+
for (const entry of this.providerStatuses) {
|
|
735
|
+
const model = (_b = (_a = entry.status) === null || _a === void 0 ? void 0 : _a.model) !== null && _b !== void 0 ? _b : entry.name;
|
|
736
|
+
if (!model)
|
|
737
|
+
continue;
|
|
738
|
+
const existing = seen.get(model);
|
|
739
|
+
if (!existing) {
|
|
740
|
+
seen.set(model, { model, provider: (_c = entry.status) === null || _c === void 0 ? void 0 : _c.provider });
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
743
|
+
// Keep whichever tier knew the vendor, so the chip still gets its colour when one slot
|
|
744
|
+
// reports a provider and another does not.
|
|
745
|
+
if (existing.provider === undefined && ((_d = entry.status) === null || _d === void 0 ? void 0 : _d.provider) !== undefined) {
|
|
746
|
+
existing.provider = entry.status.provider;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return [...seen.values()];
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Build history for display: most recently worked on first.
|
|
753
|
+
*
|
|
754
|
+
* The stored order is insertion order (see `upsertRecord`), which leaves a project returned to
|
|
755
|
+
* sitting wherever it was first seen — so ordering is applied here, on read, where it also
|
|
756
|
+
* covers rows a host provider supplied.
|
|
757
|
+
*/
|
|
758
|
+
get sortedCostSessionHistory() {
|
|
759
|
+
return sortRecordsByRecency(this.costSessionHistory);
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Lifetime usage across every project in the history scope — cost and all four token
|
|
763
|
+
* buckets. What the Usage tab's lifetime section renders.
|
|
764
|
+
*
|
|
765
|
+
* Rows ONLY — deliberately not rows + live session. Each row holds a project's lifetime
|
|
766
|
+
* usage and the active project's row is kept current on every transcript change, so
|
|
767
|
+
* adding the live total would count this project's spend twice. That double-count is what
|
|
768
|
+
* made the figure grow on every refresh: a page-hide banked a row while the restored
|
|
769
|
+
* session still carried the same spend.
|
|
770
|
+
*/
|
|
771
|
+
get cumulativeUsage() {
|
|
684
772
|
void this.costSessionHistory;
|
|
685
773
|
void this.chatConfig;
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
return
|
|
774
|
+
// With history off there are no rows to sum, so the live session IS all we know.
|
|
775
|
+
if (!this.resolvedCostHistory.enabled)
|
|
776
|
+
return this.sessionUsage;
|
|
777
|
+
return this.costSessionHistory.reduce((total, record) => addUsage(total, record.usage), emptyUsage());
|
|
778
|
+
}
|
|
779
|
+
/** Lifetime USD across every project in the history scope. */
|
|
780
|
+
get cumulativeCostUsd() {
|
|
781
|
+
return this.cumulativeUsage.costUsd;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Whether the live session figures amount to this project's whole history, which is true
|
|
785
|
+
* exactly when the transcript is restored on load. Drives the Usage tab's live labels
|
|
786
|
+
* ("Project cost" vs "Session cost") so they state the scope rather than imply one.
|
|
787
|
+
*
|
|
788
|
+
* Note this is NOT what makes the *rows* lifetime — those bank their pre-transcript spend
|
|
789
|
+
* (see `CostSessionRecord.banked`) and are lifetime either way.
|
|
790
|
+
*/
|
|
791
|
+
get liveUsageIsProjectLifetime() {
|
|
792
|
+
return this.persistenceActive;
|
|
690
793
|
}
|
|
691
794
|
/** Resolved cost tab and build-history settings from `chatConfig.costHistory`. */
|
|
692
795
|
get resolvedCostHistory() {
|
|
693
796
|
void this.chatConfig;
|
|
694
797
|
return resolveCostHistoryConfig(this.chatConfig);
|
|
695
798
|
}
|
|
696
|
-
/**
|
|
799
|
+
/**
|
|
800
|
+
* Total tokens across every chat turn in this session — all four buckets added up.
|
|
801
|
+
* Read-only; the per-bucket split is on `sessionUsage`.
|
|
802
|
+
*/
|
|
697
803
|
get sessionTokensConsumed() {
|
|
698
|
-
|
|
699
|
-
return (_b = (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.sessionTokensConsumed) !== null && _b !== void 0 ? _b : 0;
|
|
700
|
-
}
|
|
701
|
-
set sessionTokensConsumed(value) {
|
|
702
|
-
var _a;
|
|
703
|
-
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setSessionTokensConsumed(value);
|
|
804
|
+
return totalTokens(this.sessionUsage);
|
|
704
805
|
}
|
|
705
|
-
/** Label shown on the
|
|
806
|
+
/** Label shown on the Usage tab for the in-flight session (app title or first user phrase). */
|
|
706
807
|
get liveCostSessionTitle() {
|
|
707
808
|
var _a, _b;
|
|
708
809
|
void this.messages;
|
|
@@ -713,17 +814,37 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
713
814
|
return deriveCostSessionTitleFromMessages(this.messages);
|
|
714
815
|
}
|
|
715
816
|
/**
|
|
716
|
-
*
|
|
717
|
-
*
|
|
817
|
+
* Write this session's usage into persisted build history (`localStorage`) as a single
|
|
818
|
+
* row keyed by the session key, replacing any existing row for that key.
|
|
819
|
+
*
|
|
820
|
+
* **Idempotent** — safe to call per turn, on tab close, and on a title change alike.
|
|
821
|
+
* The name is historical: it does NOT end the session or reset the running totals.
|
|
822
|
+
* Resetting them is what used to double-count spend, since the row was banked while the
|
|
823
|
+
* persisted transcript still carried the same usage, so a reload restored it and the
|
|
824
|
+
* Usage tab counted both.
|
|
825
|
+
*
|
|
826
|
+
* No-op unless `chatConfig.costHistory.enabled` is `true`, when the live session has no
|
|
827
|
+
* usage yet, or when the session has no key to upsert against. Gating on the *live*
|
|
828
|
+
* figures (not the banked total) means a reload that restores nothing rewrites nothing.
|
|
718
829
|
*/
|
|
719
830
|
finalizeCostSession(options) {
|
|
720
831
|
if (!this.resolvedCostHistory.enabled)
|
|
721
832
|
return;
|
|
722
|
-
|
|
833
|
+
// Wait for the rows before writing: a provider read is async, and banking from a
|
|
834
|
+
// not-yet-loaded ledger would read as "nothing came before" and rewrite this project's
|
|
835
|
+
// row down to the current transcript. Skipping is free — this is called on every
|
|
836
|
+
// transcript change, so the next one writes.
|
|
837
|
+
if (!this._costHistoryLoaded)
|
|
838
|
+
return;
|
|
839
|
+
const live = this.sessionUsage;
|
|
840
|
+
const tokensConsumed = totalTokens(live);
|
|
841
|
+
if (live.costUsd <= 0 && tokensConsumed <= 0)
|
|
723
842
|
return;
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
843
|
+
// The session key identifies the work — a project id, for hosts that key sessions
|
|
844
|
+
// per project. Without one there is nothing stable to upsert against, so skip
|
|
845
|
+
// rather than write a row that can never be matched again.
|
|
846
|
+
const projectKey = this.getStateKey();
|
|
847
|
+
if (!projectKey)
|
|
727
848
|
return;
|
|
728
849
|
const title = resolveCostSessionTitle({
|
|
729
850
|
explicit: options === null || options === void 0 ? void 0 : options.title,
|
|
@@ -731,18 +852,62 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
731
852
|
messages: this.messages,
|
|
732
853
|
headerTitle: this.headerTitle,
|
|
733
854
|
});
|
|
855
|
+
// Lifetime = what came before this transcript + what this transcript proves. Both
|
|
856
|
+
// terms are derived from state, never incremented, so the two element instances that
|
|
857
|
+
// share a session write the same row rather than each adding their own contribution.
|
|
858
|
+
const banked = this.bankedUsageFor(projectKey);
|
|
734
859
|
const record = {
|
|
735
|
-
|
|
860
|
+
// Stable per project so repeat upserts replace the row instead of stacking, and
|
|
861
|
+
// so the delete action keeps targeting the same row across reloads.
|
|
862
|
+
id: projectKey,
|
|
863
|
+
projectKey,
|
|
736
864
|
title,
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
865
|
+
updatedAt: new Date().toISOString(),
|
|
866
|
+
usage: addUsage(banked, live),
|
|
867
|
+
banked,
|
|
740
868
|
models: collectSessionModels(this.messages, this.providerStatuses),
|
|
741
869
|
};
|
|
742
|
-
this.
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
870
|
+
this.persistCostHistory(upsertRecord(this.costSessionHistory, record));
|
|
871
|
+
// NOTE: the live counters are deliberately NOT reset here. Resetting was what
|
|
872
|
+
// double-counted spend — the row was banked while the persisted transcript still
|
|
873
|
+
// carried the same usage, so a reload restored it and the Usage tab added both.
|
|
874
|
+
// The row is a projection of the session totals, not a transfer out of them.
|
|
875
|
+
}
|
|
876
|
+
/**
|
|
877
|
+
* Spend for `projectKey` that predates the current transcript, resolved once per project
|
|
878
|
+
* and memoised (`_bankedFor`) so it cannot drift mid-session as the row it came from is
|
|
879
|
+
* rewritten by our own upserts.
|
|
880
|
+
*
|
|
881
|
+
* The two cases turn on whether the transcript is authoritative for this project:
|
|
882
|
+
*
|
|
883
|
+
* - **Transcript restored** (`persistenceActive`): it already accounts for everything after
|
|
884
|
+
* the previous row's own banked figure, so carry that figure forward unchanged. Re-banking
|
|
885
|
+
* `usage` here would add the restored history to itself on every reload.
|
|
886
|
+
* - **Transcript starts empty**: nothing on screen accounts for the previous total, so the
|
|
887
|
+
* whole of it becomes banked. Without this the next turn would rewrite the row downwards
|
|
888
|
+
* to just that turn, losing the project's earlier spend.
|
|
889
|
+
*/
|
|
890
|
+
bankedUsageFor(projectKey) {
|
|
891
|
+
if (this._bankedFor === projectKey)
|
|
892
|
+
return this._bankedUsage;
|
|
893
|
+
const existing = this.costSessionHistory.find((r) => r.projectKey === projectKey);
|
|
894
|
+
// `persistenceActive` is what decides whether the transcript speaks for the project's
|
|
895
|
+
// history: it is on only when a provider is wired AND the user is remembering the chat.
|
|
896
|
+
this._bankedUsage = resolveBankedUsage(existing, this.persistenceActive);
|
|
897
|
+
this._bankedFor = projectKey;
|
|
898
|
+
return this._bankedUsage;
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Discard the banked figure — for when the spend it stands for has been deliberately
|
|
902
|
+
* thrown away (the user clearing history, or deleting this project's row).
|
|
903
|
+
*
|
|
904
|
+
* NOT for reloads. A reload re-reads rows that already include our own upserts, so
|
|
905
|
+
* re-deriving from them would fold the live session into its own baseline; only a genuine
|
|
906
|
+
* project change should re-derive, which `bankedUsageFor`'s per-project memo handles.
|
|
907
|
+
*/
|
|
908
|
+
resetBankedUsage() {
|
|
909
|
+
this._bankedFor = undefined;
|
|
910
|
+
this._bankedUsage = emptyUsage();
|
|
746
911
|
}
|
|
747
912
|
showConfirmationDialog(confirmationMessage, modalParent, onConfirm, onCancel) {
|
|
748
913
|
showNotificationDialog({
|
|
@@ -756,10 +921,30 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
756
921
|
}
|
|
757
922
|
/** Remove one entry from persisted build history. */
|
|
758
923
|
removeCostSessionFromHistory(id) {
|
|
759
|
-
|
|
924
|
+
// Deleting the active project's row discards its banked spend by intent, so drop the
|
|
925
|
+
// memo too — otherwise the next turn would rewrite the row we just removed, restoring
|
|
926
|
+
// the total the user asked to be rid of.
|
|
927
|
+
//
|
|
928
|
+
// Resolve the row first: `id` is a row id while `_bankedFor` is a projectKey. They match
|
|
929
|
+
// only for rows this element wrote (`finalizeCostSession` sets `id: projectKey`); a row from
|
|
930
|
+
// a host provider can carry any id, and comparing across the two namespaces would silently
|
|
931
|
+
// skip the reset.
|
|
932
|
+
const removed = this.costSessionHistory.find((record) => record.id === id);
|
|
933
|
+
if (removed && this._bankedFor === removed.projectKey)
|
|
934
|
+
this.resetBankedUsage();
|
|
935
|
+
this.persistCostHistory(this.costSessionHistory.filter((record) => record.id !== id));
|
|
760
936
|
}
|
|
761
937
|
/** Clear all persisted build history for this assistant scope. */
|
|
762
938
|
clearCostSessionHistory() {
|
|
939
|
+
// Every row is gone, so nothing is banked any more — without this the active project's
|
|
940
|
+
// next turn would resurrect its pre-clear total.
|
|
941
|
+
this.resetBankedUsage();
|
|
942
|
+
// Provider-backed: write an empty ledger through. The `localStorage` path instead
|
|
943
|
+
// removes its key outright rather than leaving an empty array behind.
|
|
944
|
+
if (this.costHistoryProvider()) {
|
|
945
|
+
this.persistCostHistory([]);
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
763
948
|
clearCostSessionHistory(this.getCostHistoryScope());
|
|
764
949
|
this.costSessionHistory = [];
|
|
765
950
|
}
|
|
@@ -772,23 +957,134 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
772
957
|
return 'default';
|
|
773
958
|
}
|
|
774
959
|
reloadCostSessionHistory() {
|
|
960
|
+
// NOTE: deliberately does NOT invalidate the banked figure. This runs again whenever
|
|
961
|
+
// `chatConfig` rebinds — hosts commonly build it in a template expression, so a new
|
|
962
|
+
// object arrives mid-session — and by then the rows include our own upserts, whose
|
|
963
|
+
// `usage` already contains the live transcript. Re-deriving from those would add the
|
|
964
|
+
// current session to itself. `bankedUsageFor` keys its memo on the project instead,
|
|
965
|
+
// which handles a genuine session switch without trusting reload timing.
|
|
966
|
+
this._costHistoryLoaded = false;
|
|
967
|
+
this._ledgerUnreadable = false;
|
|
775
968
|
if (!this.resolvedCostHistory.enabled) {
|
|
776
969
|
this.costSessionHistory = [];
|
|
970
|
+
this._costHistoryLoaded = true;
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
const scope = this.getCostHistoryScope();
|
|
974
|
+
const provider = this.costHistoryProvider();
|
|
975
|
+
if (!provider) {
|
|
976
|
+
this.costSessionHistory = loadCostSessionHistory(scope);
|
|
977
|
+
this._costHistoryLoaded = true;
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
// Provider reads are async, so the Usage tab renders an empty list for a tick before
|
|
981
|
+
// this lands. Seeded empty rather than left stale so a scope change can't briefly show
|
|
982
|
+
// the previous scope's rows.
|
|
983
|
+
this.costSessionHistory = [];
|
|
984
|
+
void provider.loadCostHistory(scope)
|
|
985
|
+
.then((records) => {
|
|
986
|
+
// Guard against a scope change while the load was in flight — a late result must
|
|
987
|
+
// not overwrite the rows of whatever scope is current now.
|
|
988
|
+
if (this.getCostHistoryScope() === scope) {
|
|
989
|
+
// Filtered exactly as the localStorage path is. A host's rows are as capable of
|
|
990
|
+
// being malformed as a hand-edited storage entry, and an unchecked one poisons
|
|
991
|
+
// every total with NaN or throws in the sort during render.
|
|
992
|
+
this.costSessionHistory = (records !== null && records !== void 0 ? records : []).filter(isCostSessionRecord);
|
|
993
|
+
this._costHistoryLoaded = true;
|
|
994
|
+
}
|
|
995
|
+
})
|
|
996
|
+
.catch((e) => {
|
|
997
|
+
logger.warn('Cost history unreadable — recording locally only this page-load', e);
|
|
998
|
+
// Writes stay blocked, and `persistCostHistory` will not save even if something else
|
|
999
|
+
// calls it. `saveCostHistory` REPLACES the stored list, so writing an upsert against
|
|
1000
|
+
// the empty list we fell back to would delete every other project's row and reset
|
|
1001
|
+
// this project's banked total — destroying data we simply failed to read. The row
|
|
1002
|
+
// rebuilds from the transcript on the next successful load.
|
|
1003
|
+
this._ledgerUnreadable = true;
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* The persistence provider, but only when it implements BOTH cost-history methods.
|
|
1008
|
+
*
|
|
1009
|
+
* Both or neither: a provider that can save but not load would silently accumulate a
|
|
1010
|
+
* ledger nobody ever reads back, so a partial implementation is treated as absent and
|
|
1011
|
+
* falls back to `localStorage`.
|
|
1012
|
+
*/
|
|
1013
|
+
costHistoryProvider() {
|
|
1014
|
+
const provider = this.persistence.provider;
|
|
1015
|
+
return (provider === null || provider === void 0 ? void 0 : provider.loadCostHistory) && provider.saveCostHistory ? provider : undefined;
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Adopt `records` as the live list, and schedule a write to whichever backend owns cost
|
|
1019
|
+
* history — the provider when the host implements it, else `localStorage`.
|
|
1020
|
+
*
|
|
1021
|
+
* The list is adopted synchronously because that is what the Usage tab renders; only the
|
|
1022
|
+
* *write* is deferred. This runs on every usage change (about once per LLM call, plus once
|
|
1023
|
+
* per sub-agent turn) and each write serialises the whole ledger, so coalescing cuts a
|
|
1024
|
+
* per-turn `localStorage.setItem` or network round-trip down to one per quiet period. Safe
|
|
1025
|
+
* because the write is a full replace of idempotent state: the newest call wins and no
|
|
1026
|
+
* intermediate state is meaningful. Flushed on `pagehide` and disconnect so nothing is lost.
|
|
1027
|
+
*/
|
|
1028
|
+
persistCostHistory(records) {
|
|
1029
|
+
this.costSessionHistory = records;
|
|
1030
|
+
// A ledger we could not read must never be written back — see reloadCostSessionHistory.
|
|
1031
|
+
// Guarded here rather than only at the finalize gate so it also covers the row-removal and
|
|
1032
|
+
// clear paths, which write directly.
|
|
1033
|
+
if (this._ledgerUnreadable)
|
|
1034
|
+
return;
|
|
1035
|
+
this._ledgerDirty = true;
|
|
1036
|
+
if (this._ledgerFlushTimer !== undefined)
|
|
1037
|
+
clearTimeout(this._ledgerFlushTimer);
|
|
1038
|
+
this._ledgerFlushTimer = setTimeout(() => this.flushCostHistory(), LEDGER_FLUSH_DEBOUNCE_MS);
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Write the pending ledger now. Safe to call when nothing is pending.
|
|
1042
|
+
*
|
|
1043
|
+
* Provider writes are fire-and-forget and best-effort: the ledger is accounting, not
|
|
1044
|
+
* conversation content, so a failed write is logged and never surfaced into the chat. On
|
|
1045
|
+
* `pagehide` the `localStorage` path completes synchronously; a provider write is subject to
|
|
1046
|
+
* the same unload race as every other network save the assistant makes.
|
|
1047
|
+
*/
|
|
1048
|
+
flushCostHistory() {
|
|
1049
|
+
if (this._ledgerFlushTimer !== undefined) {
|
|
1050
|
+
clearTimeout(this._ledgerFlushTimer);
|
|
1051
|
+
this._ledgerFlushTimer = undefined;
|
|
1052
|
+
}
|
|
1053
|
+
if (!this._ledgerDirty || this._ledgerUnreadable)
|
|
1054
|
+
return;
|
|
1055
|
+
this._ledgerDirty = false;
|
|
1056
|
+
const records = this.costSessionHistory;
|
|
1057
|
+
const scope = this.getCostHistoryScope();
|
|
1058
|
+
const provider = this.costHistoryProvider();
|
|
1059
|
+
if (!provider) {
|
|
1060
|
+
saveCostSessionHistory(scope, records);
|
|
777
1061
|
return;
|
|
778
1062
|
}
|
|
779
|
-
|
|
1063
|
+
void provider.saveCostHistory(scope, records).catch((e) => {
|
|
1064
|
+
logger.warn('Cost history save failed', e);
|
|
1065
|
+
});
|
|
780
1066
|
}
|
|
781
|
-
/**
|
|
1067
|
+
/**
|
|
1068
|
+
* Finalize the previous session when the host-provided title changes — a rename should land on
|
|
1069
|
+
* the row under its old name rather than silently relabelling accrued spend.
|
|
1070
|
+
*
|
|
1071
|
+
* Only when the session key still matches the one that title accrued under. Hosts change
|
|
1072
|
+
* `costHistory.title` on project SWITCH too, and if the key has already flipped, this would
|
|
1073
|
+
* upsert the outgoing project's live usage onto the incoming project's row as
|
|
1074
|
+
* `banked + old live`, inflating it. Under the old append model a mis-keyed write left a stray
|
|
1075
|
+
* row; with the upsert it overwrites a real one.
|
|
1076
|
+
*/
|
|
782
1077
|
syncActiveCostSessionTitle() {
|
|
783
1078
|
var _a, _b;
|
|
784
1079
|
const previous = this._activeCostSessionTitle;
|
|
785
1080
|
const next = (_b = (_a = this.resolvedCostHistory.title) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : '';
|
|
786
|
-
|
|
1081
|
+
const key = this.getStateKey();
|
|
1082
|
+
if (previous && previous !== next && this._activeCostSessionKey === key) {
|
|
787
1083
|
this.finalizeCostSession({ title: previous });
|
|
788
1084
|
}
|
|
789
1085
|
if (previous !== next) {
|
|
790
1086
|
this._activeCostSessionTitle = next;
|
|
791
|
-
this.
|
|
1087
|
+
this._activeCostSessionKey = key;
|
|
792
1088
|
}
|
|
793
1089
|
}
|
|
794
1090
|
/** Active model id resolved from the AIProvider, if exposed. */
|
|
@@ -1502,6 +1798,9 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
1502
1798
|
disconnectedCallback() {
|
|
1503
1799
|
var _a, _b, _c, _d, _e, _f;
|
|
1504
1800
|
window.removeEventListener('pagehide', this._handlePageHide);
|
|
1801
|
+
// Write out anything the debounce is still holding — the timer would otherwise fire against
|
|
1802
|
+
// a torn-down element, or not at all.
|
|
1803
|
+
this.flushCostHistory();
|
|
1505
1804
|
super.disconnectedCallback();
|
|
1506
1805
|
this._sessionActive = false;
|
|
1507
1806
|
this.stopLoadingTimer();
|
|
@@ -1662,18 +1961,24 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
1662
1961
|
break;
|
|
1663
1962
|
}
|
|
1664
1963
|
}
|
|
1665
|
-
// Recompute
|
|
1666
|
-
// (rather than incrementing on append) keeps the
|
|
1667
|
-
// mutation of the message list —
|
|
1668
|
-
//
|
|
1669
|
-
//
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1964
|
+
// Recompute cost and all four token buckets from the transcript in one walk.
|
|
1965
|
+
// Recomputing (rather than incrementing on append) keeps the totals correct under
|
|
1966
|
+
// any mutation of the message list — clear-chat, re-render, restore. `sumUsage`
|
|
1967
|
+
// recurses into `toolCall.subAgentTrace`, so work a sub-agent did (possibly on
|
|
1968
|
+
// another provider at other rates) counts, and it reads the usage a compaction
|
|
1969
|
+
// banked onto its summary, so shrinking history no longer shrinks the totals.
|
|
1970
|
+
const running = sumUsage(this.messages);
|
|
1971
|
+
const current = this.sessionUsage;
|
|
1972
|
+
if (running.costUsd !== current.costUsd ||
|
|
1973
|
+
running.uncachedInputTokens !== current.uncachedInputTokens ||
|
|
1974
|
+
running.cacheReadTokens !== current.cacheReadTokens ||
|
|
1975
|
+
running.cacheWriteTokens !== current.cacheWriteTokens ||
|
|
1976
|
+
running.outputTokens !== current.outputTokens) {
|
|
1977
|
+
this.sessionUsage = running;
|
|
1978
|
+
// Keep this project's history row current as spend accrues, which is what lets
|
|
1979
|
+
// the Usage tab total be the sum of the rows alone. Idempotent (an upsert keyed
|
|
1980
|
+
// by the session key), so calling it per change is safe.
|
|
1981
|
+
this.finalizeCostSession();
|
|
1677
1982
|
}
|
|
1678
1983
|
// Record a context.updated meta event when the token count changes (≈once
|
|
1679
1984
|
// per LLM call, as a new usage-bearing message arrives), plus a one-shot
|
|
@@ -2115,16 +2420,22 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
2115
2420
|
get settingsAppSectionVisible() {
|
|
2116
2421
|
return this.settingsAppSlotted.length > 0 || this.visibleAppSettingsToggles.length > 0;
|
|
2117
2422
|
}
|
|
2118
|
-
/** Section title for the app settings block. */
|
|
2119
|
-
get appSettingsSectionTitle() {
|
|
2120
|
-
var _a;
|
|
2121
|
-
return (_a = this.appSettingsProvider.sectionTitle) !== null && _a !== void 0 ? _a : 'UI Builder Settings';
|
|
2122
|
-
}
|
|
2123
2423
|
/** App toggles currently visible per each entry's `visible()` predicate. */
|
|
2124
2424
|
get visibleAppSettingsToggles() {
|
|
2125
2425
|
void this.appSettingsRevision;
|
|
2126
2426
|
return this.appSettingsProvider.toggles.filter((toggle) => { var _a; return ((_a = toggle.visible) === null || _a === void 0 ? void 0 : _a.call(toggle)) !== false; });
|
|
2127
2427
|
}
|
|
2428
|
+
/**
|
|
2429
|
+
* Host-supplied heading for the toggle group, or `undefined` for none — the assistant has no
|
|
2430
|
+
* default. Suppressed when no toggle is currently visible, so a `visible()` predicate hiding
|
|
2431
|
+
* the last one takes its heading with it rather than leaving a label over nothing.
|
|
2432
|
+
*/
|
|
2433
|
+
get appSettingsTogglesHeading() {
|
|
2434
|
+
void this.appSettingsRevision;
|
|
2435
|
+
if (this.visibleAppSettingsToggles.length === 0)
|
|
2436
|
+
return undefined;
|
|
2437
|
+
return this.appSettingsProvider.togglesHeading;
|
|
2438
|
+
}
|
|
2128
2439
|
getAppSettingValue(id) {
|
|
2129
2440
|
void this.appSettingsRevision;
|
|
2130
2441
|
return this.appSettingsProvider.getValue(id);
|
|
@@ -2153,7 +2464,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
2153
2464
|
return false;
|
|
2154
2465
|
return this.costSessionHistory.length > 0 || this.settingsCostHistorySlotted.length > 0;
|
|
2155
2466
|
}
|
|
2156
|
-
/** Whether the built-in
|
|
2467
|
+
/** Whether the built-in Usage tab summary block has anything to show. */
|
|
2157
2468
|
get settingsCostSummaryVisible() {
|
|
2158
2469
|
var _a;
|
|
2159
2470
|
void this.chatConfig;
|
|
@@ -2167,7 +2478,30 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
2167
2478
|
}
|
|
2168
2479
|
return !!this.liveCostSessionTitle;
|
|
2169
2480
|
}
|
|
2170
|
-
/**
|
|
2481
|
+
/**
|
|
2482
|
+
* Whether the lifetime-usage section has anything to say.
|
|
2483
|
+
*
|
|
2484
|
+
* Requires build history: with it off there are no rows, so `cumulativeUsage` falls back to
|
|
2485
|
+
* the live session and the section would restate the block directly below it under a
|
|
2486
|
+
* "lifetime" heading it hasn't earned.
|
|
2487
|
+
*/
|
|
2488
|
+
get settingsCostLifetimeVisible() {
|
|
2489
|
+
void this.chatConfig;
|
|
2490
|
+
void this._sessionRef;
|
|
2491
|
+
const cost = this.resolvedCostHistory;
|
|
2492
|
+
if (!cost.enabled || !(cost.showCost || cost.showTokens))
|
|
2493
|
+
return false;
|
|
2494
|
+
// Also requires a state key, because `finalizeCostSession` skips the write without one and the
|
|
2495
|
+
// lifetime figures sum rows only — so the section would show a permanent $0.00 directly above
|
|
2496
|
+
// a live block reporting real spend.
|
|
2497
|
+
//
|
|
2498
|
+
// Narrow in practice: `getStateKey` falls back to `id::headerTitle`, and `headerTitle` has a
|
|
2499
|
+
// non-empty default, so a key is almost always derivable even with no `session-key`. This
|
|
2500
|
+
// catches the remaining case — a host that supplies no session key, no element id, AND blanks
|
|
2501
|
+
// the header title. Cheap, and the alternative is a figure that is simply wrong.
|
|
2502
|
+
return !!this.getStateKey();
|
|
2503
|
+
}
|
|
2504
|
+
/** Whether the Usage tab should appear in the settings modal. */
|
|
2171
2505
|
get settingsCostTabVisible() {
|
|
2172
2506
|
void this.chatConfig;
|
|
2173
2507
|
const cost = this.resolvedCostHistory;
|
|
@@ -2176,7 +2510,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
2176
2510
|
this.settingsCostCurrentSectionVisible ||
|
|
2177
2511
|
this.settingsCostHistorySectionVisible);
|
|
2178
2512
|
}
|
|
2179
|
-
/** Whether session token usage should render on the
|
|
2513
|
+
/** Whether session token usage should render on the Usage tab. */
|
|
2180
2514
|
get settingsSessionTokensVisible() {
|
|
2181
2515
|
void this.chatConfig;
|
|
2182
2516
|
return this.resolvedCostHistory.showTokens;
|
|
@@ -2468,6 +2802,10 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
2468
2802
|
contextUsagePercent,
|
|
2469
2803
|
sessionCostUsd: this.sessionCostUsd,
|
|
2470
2804
|
sessionTokensConsumed: this.sessionTokensConsumed,
|
|
2805
|
+
// The per-bucket split alongside the total. Without it a log shows a large
|
|
2806
|
+
// token count next to a small cost with no way to tell why — the answer is
|
|
2807
|
+
// almost always that most of the prompt was a cache hit.
|
|
2808
|
+
sessionUsage: this.sessionUsage,
|
|
2471
2809
|
},
|
|
2472
2810
|
// Snapshot captured fresh at log-export time — reflects state NOW, which
|
|
2473
2811
|
// may have transitioned since the last LLM call.
|
|
@@ -3078,9 +3416,21 @@ __decorate([
|
|
|
3078
3416
|
__decorate([
|
|
3079
3417
|
volatile
|
|
3080
3418
|
], FoundationAiAssistant.prototype, "effectiveChatInputDuringExecution", null);
|
|
3419
|
+
__decorate([
|
|
3420
|
+
volatile
|
|
3421
|
+
], FoundationAiAssistant.prototype, "uniqueProviderModels", null);
|
|
3422
|
+
__decorate([
|
|
3423
|
+
volatile
|
|
3424
|
+
], FoundationAiAssistant.prototype, "sortedCostSessionHistory", null);
|
|
3425
|
+
__decorate([
|
|
3426
|
+
volatile
|
|
3427
|
+
], FoundationAiAssistant.prototype, "cumulativeUsage", null);
|
|
3081
3428
|
__decorate([
|
|
3082
3429
|
volatile
|
|
3083
3430
|
], FoundationAiAssistant.prototype, "cumulativeCostUsd", null);
|
|
3431
|
+
__decorate([
|
|
3432
|
+
volatile
|
|
3433
|
+
], FoundationAiAssistant.prototype, "liveUsageIsProjectLifetime", null);
|
|
3084
3434
|
__decorate([
|
|
3085
3435
|
volatile
|
|
3086
3436
|
], FoundationAiAssistant.prototype, "resolvedCostHistory", null);
|
|
@@ -3170,10 +3520,10 @@ __decorate([
|
|
|
3170
3520
|
], FoundationAiAssistant.prototype, "settingsAppSectionVisible", null);
|
|
3171
3521
|
__decorate([
|
|
3172
3522
|
volatile
|
|
3173
|
-
], FoundationAiAssistant.prototype, "
|
|
3523
|
+
], FoundationAiAssistant.prototype, "visibleAppSettingsToggles", null);
|
|
3174
3524
|
__decorate([
|
|
3175
3525
|
volatile
|
|
3176
|
-
], FoundationAiAssistant.prototype, "
|
|
3526
|
+
], FoundationAiAssistant.prototype, "appSettingsTogglesHeading", null);
|
|
3177
3527
|
__decorate([
|
|
3178
3528
|
volatile
|
|
3179
3529
|
], FoundationAiAssistant.prototype, "settingsCostCurrentSectionVisible", null);
|
|
@@ -3183,6 +3533,9 @@ __decorate([
|
|
|
3183
3533
|
__decorate([
|
|
3184
3534
|
volatile
|
|
3185
3535
|
], FoundationAiAssistant.prototype, "settingsCostSummaryVisible", null);
|
|
3536
|
+
__decorate([
|
|
3537
|
+
volatile
|
|
3538
|
+
], FoundationAiAssistant.prototype, "settingsCostLifetimeVisible", null);
|
|
3186
3539
|
__decorate([
|
|
3187
3540
|
volatile
|
|
3188
3541
|
], FoundationAiAssistant.prototype, "settingsCostTabVisible", null);
|