@genesislcap/ai-assistant 15.4.1 → 15.6.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 +571 -82
- package/dist/ai-assistant.d.ts +336 -36
- package/dist/chat-driver.cjs +104 -26
- package/dist/chat-driver.cjs.map +3 -3
- package/dist/chat-driver.mjs +104 -26
- package/dist/chat-driver.mjs.map +3 -3
- package/dist/custom-elements.json +314 -36
- package/dist/dts/components/chat-driver/chat-driver.d.ts +12 -0
- 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/condense-history.d.ts +14 -0
- package/dist/dts/utils/condense-history.d.ts.map +1 -1
- 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 +9 -1
- 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/condense-history.js +18 -5
- package/dist/esm/utils/condense-history.test.js +67 -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 +21 -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/condense-history.test.ts +103 -0
- package/src/utils/condense-history.ts +33 -3
- 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/ai-assistant.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AgentPickerMode } from '@genesislcap/foundation-ai';
|
|
2
|
+
import type { AggregateUsage } from '@genesislcap/foundation-ai';
|
|
2
3
|
import { AIProviderRegistry } from '@genesislcap/foundation-ai';
|
|
3
4
|
import type { AIProviderRegistryStatusEntry } from '@genesislcap/foundation-ai';
|
|
4
5
|
import type { AIProviderType } from '@genesislcap/foundation-ai';
|
|
@@ -12,6 +13,7 @@ import type { ChatMessage } from '@genesislcap/foundation-ai';
|
|
|
12
13
|
import type { ChatToolChoice } from '@genesislcap/foundation-ai';
|
|
13
14
|
import type { ChatToolDefinition } from '@genesislcap/foundation-ai';
|
|
14
15
|
import type { ChatToolHandlers } from '@genesislcap/foundation-ai';
|
|
16
|
+
import { ElementStyles } from '@genesislcap/web-core';
|
|
15
17
|
import { GenesisElement } from '@genesislcap/web-core';
|
|
16
18
|
import type { InteractionRequestOptions } from '@genesislcap/foundation-ai';
|
|
17
19
|
import type { InteractionResult } from '@genesislcap/foundation-ai';
|
|
@@ -726,16 +728,42 @@ export declare const ANIMATION_DEFS: {
|
|
|
726
728
|
export declare function assembleDebugLog(entries: DiagnosticEntry[], readme: readonly string[]): DebugLog;
|
|
727
729
|
|
|
728
730
|
/**
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
*
|
|
731
|
+
* Optional heading above a provider's toggle group.
|
|
732
|
+
*
|
|
733
|
+
* Entirely host-supplied — the assistant has no default title and no default icon, because the
|
|
734
|
+
* section belongs to the host. Omit it and the toggles render bare, which is right when the
|
|
735
|
+
* host's slotted content already titles them.
|
|
736
|
+
*
|
|
737
|
+
* @beta
|
|
738
|
+
*/
|
|
739
|
+
export declare interface AssistantAppSettingsHeading {
|
|
740
|
+
readonly title: string;
|
|
741
|
+
/**
|
|
742
|
+
* Icon name for the design system's icon element (a Font Awesome free name, e.g.
|
|
743
|
+
* `'object-group'`). Omitted renders text only; an unknown name renders nothing at all, so
|
|
744
|
+
* check it against the installed Font Awesome set.
|
|
745
|
+
*/
|
|
746
|
+
readonly icon?: string;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* App-supplied settings for the host's own section of the settings modal. Register a concrete
|
|
751
|
+
* implementation on the DI token at app bootstrap; the assistant renders the toggles with the
|
|
752
|
+
* same row layout as AI Chat Bot settings.
|
|
753
|
+
*
|
|
754
|
+
* The section itself is untitled by the assistant — no heading text and no icon — because only
|
|
755
|
+
* the host knows what it is. Title it from the `settings-app` slot, which renders above these
|
|
756
|
+
* toggles, and apply `assistantSettingsSectionTitleStyles` to match the built-in headings.
|
|
732
757
|
*
|
|
733
758
|
* @beta
|
|
734
759
|
*/
|
|
735
760
|
export declare interface AssistantAppSettingsProvider {
|
|
736
|
-
/** Section heading. Default: `"UI Builder Settings"`. */
|
|
737
|
-
readonly sectionTitle?: string;
|
|
738
761
|
readonly toggles: readonly AssistantAppSettingsToggle[];
|
|
762
|
+
/**
|
|
763
|
+
* Heading for the toggle group, for hosts that put other controls in the `settings-app` slot
|
|
764
|
+
* and need these distinguished from them. No default: absent means no heading.
|
|
765
|
+
*/
|
|
766
|
+
readonly togglesHeading?: AssistantAppSettingsHeading;
|
|
739
767
|
getValue(id: string): boolean;
|
|
740
768
|
setValue(id: string, value: boolean): void;
|
|
741
769
|
/** Notify the assistant to re-read toggle values / visibility. */
|
|
@@ -770,6 +798,34 @@ export declare interface AssistantAppSettingsToggle {
|
|
|
770
798
|
hint?: () => string | undefined;
|
|
771
799
|
}
|
|
772
800
|
|
|
801
|
+
/**
|
|
802
|
+
* Heading style for a settings-modal section, published so a host can title its own section.
|
|
803
|
+
*
|
|
804
|
+
* The assistant renders no heading for the `settings-app` slot — no text and no icon — because
|
|
805
|
+
* only the host knows what that section is. The consequence is that a host supplying one has to
|
|
806
|
+
* reproduce the styling of the built-in headings beside it, and a copied rule drifts the moment
|
|
807
|
+
* either side changes. So the declarations live here, are applied by the assistant's own
|
|
808
|
+
* headings, and are exported for the host to apply to its.
|
|
809
|
+
*
|
|
810
|
+
* Compose it into a component's styles and put `ai-settings-section-title` on the heading:
|
|
811
|
+
*
|
|
812
|
+
* ```ts
|
|
813
|
+
* import { assistantSettingsSectionTitleStyles } from '@genesislcap/ai-assistant';
|
|
814
|
+
*
|
|
815
|
+
* const styles = css`
|
|
816
|
+
* ${assistantSettingsSectionTitleStyles}
|
|
817
|
+
* :host { display: block; }
|
|
818
|
+
* `;
|
|
819
|
+
* ```
|
|
820
|
+
*
|
|
821
|
+
* Carries no margin on purpose: spacing belongs to the surrounding layout, which differs
|
|
822
|
+
* between the assistant's own sections and a slotted one, and is the single declaration hosts
|
|
823
|
+
* had to diverge on when they copied this rule.
|
|
824
|
+
*
|
|
825
|
+
* @beta
|
|
826
|
+
*/
|
|
827
|
+
export declare const assistantSettingsSectionTitleStyles: ElementStyles;
|
|
828
|
+
|
|
773
829
|
declare interface BaseAgentConfig {
|
|
774
830
|
/**
|
|
775
831
|
* Stable identity for this agent. Used for classifier routing, manual
|
|
@@ -1321,6 +1377,8 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
|
|
|
1321
1377
|
private unsubscribeRegistry?;
|
|
1322
1378
|
/** Hard cap on tool-loop iterations. */
|
|
1323
1379
|
private readonly maxToolIterations;
|
|
1380
|
+
/** Model-calls per condensation batch; `1` collapses as soon as a trigger fires. */
|
|
1381
|
+
private readonly condenseBatchCalls;
|
|
1324
1382
|
/** Session identity used to file meta events onto the shared debug-log timeline. */
|
|
1325
1383
|
private readonly sessionKey;
|
|
1326
1384
|
/** Injected activity bus; defaults to a no-op off-browser (Node/tests/headless). */
|
|
@@ -1657,6 +1715,16 @@ export declare interface ChatDriverConfig {
|
|
|
1657
1715
|
maxToolIterations?: number;
|
|
1658
1716
|
/** Hard cap on fold operations. Default `5`. */
|
|
1659
1717
|
maxFoldOperations?: number;
|
|
1718
|
+
/**
|
|
1719
|
+
* Collapse `condenseWhen` payloads in batches of this many model-calls rather than as
|
|
1720
|
+
* soon as each trigger fires. A positive integer; decimals are floored and anything
|
|
1721
|
+
* below `1` becomes `1`. Default `1` — collapse immediately, the historical behaviour.
|
|
1722
|
+
*
|
|
1723
|
+
* Condensation rewrites history in place, so collapsing continuously breaks the
|
|
1724
|
+
* provider's prompt cache on nearly every call of a re-read loop. Raising this trades
|
|
1725
|
+
* up to that many calls' worth of extra context for one cache break per batch.
|
|
1726
|
+
*/
|
|
1727
|
+
condenseBatchCalls?: number;
|
|
1660
1728
|
/** Ring-buffer size for per-turn snapshots. Default `400`. */
|
|
1661
1729
|
maxTurnSnapshots?: number;
|
|
1662
1730
|
/** Session identity used to file meta events onto the shared debug-log timeline. */
|
|
@@ -1698,21 +1766,58 @@ declare type ChatInteractionEventsMap = {
|
|
|
1698
1766
|
|
|
1699
1767
|
export { ChatToolChoice }
|
|
1700
1768
|
|
|
1701
|
-
/** A model used during a
|
|
1769
|
+
/** A model used during a recorded cost session. */
|
|
1702
1770
|
export declare interface CostSessionModelEntry {
|
|
1703
1771
|
model: string;
|
|
1704
1772
|
/** Vendor id from `getStatus()` (e.g. `'anthropic'`, `'gemini'`). */
|
|
1705
1773
|
provider?: AIProviderType;
|
|
1706
1774
|
}
|
|
1707
1775
|
|
|
1708
|
-
/** Persisted
|
|
1776
|
+
/** Persisted usage record for one project's assistant work. */
|
|
1709
1777
|
export declare interface CostSessionRecord {
|
|
1710
1778
|
id: string;
|
|
1779
|
+
/**
|
|
1780
|
+
* Stable identity of the work this row stands for — the assistant's session key
|
|
1781
|
+
* (a project id, for hosts that key sessions per project). The upsert key: a row
|
|
1782
|
+
* is one project's lifetime usage, so re-reporting the same key REPLACES the row
|
|
1783
|
+
* rather than adding another.
|
|
1784
|
+
*/
|
|
1785
|
+
projectKey: string;
|
|
1711
1786
|
title: string;
|
|
1712
|
-
/**
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1787
|
+
/**
|
|
1788
|
+
* ISO-8601 timestamp of the most recent usage recorded for this row.
|
|
1789
|
+
*
|
|
1790
|
+
* Named for what it is: the row is upserted as spend accrues, so this moves. It is
|
|
1791
|
+
* NOT an end time — a row has no terminal state, because a project can always be
|
|
1792
|
+
* worked on again.
|
|
1793
|
+
*/
|
|
1794
|
+
updatedAt: string;
|
|
1795
|
+
/**
|
|
1796
|
+
* Cost plus the four token buckets — the same shape the live session tile renders, so
|
|
1797
|
+
* a history row can show the identical breakdown instead of a lone merged total that
|
|
1798
|
+
* cannot explain a large token count at a small cost.
|
|
1799
|
+
*
|
|
1800
|
+
* This is the project's **lifetime** usage: `banked` plus whatever the live transcript
|
|
1801
|
+
* currently proves.
|
|
1802
|
+
*/
|
|
1803
|
+
usage: AggregateUsage;
|
|
1804
|
+
/**
|
|
1805
|
+
* Spend that predates the current transcript, and so cannot be re-derived from it.
|
|
1806
|
+
*
|
|
1807
|
+
* Without this a row could only ever report what the open transcript proves. That is
|
|
1808
|
+
* fine when the transcript is restored on load (it *is* the project's history), but
|
|
1809
|
+
* where it starts empty every refresh the row would be rewritten downwards on the next
|
|
1810
|
+
* turn and the project's earlier spend lost. Banking it keeps `usage` a lifetime figure
|
|
1811
|
+
* in both cases.
|
|
1812
|
+
*
|
|
1813
|
+
* Deliberately part of the row rather than element state: two assistant instances (a
|
|
1814
|
+
* docked bubble and a popped-out panel) share one session, and both write this row. A
|
|
1815
|
+
* value derived from the row keeps every write idempotent, whereas an element-held
|
|
1816
|
+
* accumulator would be applied once per instance.
|
|
1817
|
+
*
|
|
1818
|
+
* Optional: rows written before this existed have none, which reads as "nothing banked".
|
|
1819
|
+
*/
|
|
1820
|
+
banked?: AggregateUsage;
|
|
1716
1821
|
models: CostSessionModelEntry[];
|
|
1717
1822
|
}
|
|
1718
1823
|
|
|
@@ -1905,10 +2010,13 @@ export declare interface FallbackAgentConfig extends BaseAgentConfig {
|
|
|
1905
2010
|
*
|
|
1906
2011
|
* Popout/collapse coordination uses `agenticActivityBus` topics `chat-popout` and `chat-popin` — not DOM `CustomEvent`s on this element.
|
|
1907
2012
|
*
|
|
1908
|
-
* **Cost build history:** opt-in via `chatConfig.costHistory.enabled`. When enabled,
|
|
1909
|
-
*
|
|
1910
|
-
* element `id`, or `'default'`)
|
|
1911
|
-
*
|
|
2013
|
+
* **Cost build history:** opt-in via `chatConfig.costHistory.enabled`. When enabled, each
|
|
2014
|
+
* session's usage is kept as exactly ONE row per session key in `localStorage` (scoped by
|
|
2015
|
+
* `costHistory.scope`, the element `id`, or `'default'`), upserted as spend accrues. So a
|
|
2016
|
+
* row is a project's lifetime usage rather than a visit to it, and the Usage tab's total is
|
|
2017
|
+
* the sum of the rows alone — the live session is never added on top, because the active
|
|
2018
|
+
* project's own row already reflects it. Hosts may call
|
|
2019
|
+
* {@link FoundationAiAssistant.finalizeCostSession} to flush early; it is idempotent.
|
|
1912
2020
|
*
|
|
1913
2021
|
* @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`
|
|
1914
2022
|
* @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`
|
|
@@ -2141,25 +2249,111 @@ export declare class FoundationAiAssistant extends GenesisElement {
|
|
|
2141
2249
|
/** Context window size for the active model, if known. */
|
|
2142
2250
|
get contextLimit(): number | undefined;
|
|
2143
2251
|
set contextLimit(value: number | undefined);
|
|
2144
|
-
/**
|
|
2252
|
+
/**
|
|
2253
|
+
* Cost plus the four token buckets for this session — derived from the transcript
|
|
2254
|
+
* on every change, so it includes sub-agent turns and spend banked by a compaction.
|
|
2255
|
+
*/
|
|
2256
|
+
get sessionUsage(): AggregateUsage;
|
|
2257
|
+
set sessionUsage(value: AggregateUsage);
|
|
2258
|
+
/**
|
|
2259
|
+
* Aggregated USD cost across every chat turn in this session.
|
|
2260
|
+
*
|
|
2261
|
+
* Read-only (unlike previously): it is a projection of `sessionUsage`, and a
|
|
2262
|
+
* host assigning it would have set a figure the next transcript change overwrites.
|
|
2263
|
+
*/
|
|
2145
2264
|
get sessionCostUsd(): number;
|
|
2146
|
-
|
|
2147
|
-
|
|
2265
|
+
/**
|
|
2266
|
+
* Distinct models the registry currently resolves to — the live session's model chips.
|
|
2267
|
+
*
|
|
2268
|
+
* `providerStatuses` carries one entry per registry SLOT, so a vendor configured across several
|
|
2269
|
+
* tiers that happen to resolve to the same model reports it once per tier, and the chips
|
|
2270
|
+
* rendered it once per tier too. Which tier a model came from is not what these chips are for.
|
|
2271
|
+
*
|
|
2272
|
+
* Deduped on the label actually displayed, not on `status.model`: a slot whose provider reports
|
|
2273
|
+
* no model falls back to the slot's own name, and those are distinct per slot, so keying on the
|
|
2274
|
+
* label keeps them from collapsing into one another.
|
|
2275
|
+
*/
|
|
2276
|
+
get uniqueProviderModels(): CostSessionModelEntry[];
|
|
2277
|
+
/**
|
|
2278
|
+
* Build history for display: most recently worked on first.
|
|
2279
|
+
*
|
|
2280
|
+
* The stored order is insertion order (see `upsertRecord`), which leaves a project returned to
|
|
2281
|
+
* sitting wherever it was first seen — so ordering is applied here, on read, where it also
|
|
2282
|
+
* covers rows a host provider supplied.
|
|
2283
|
+
*/
|
|
2284
|
+
get sortedCostSessionHistory(): CostSessionRecord[];
|
|
2285
|
+
/**
|
|
2286
|
+
* Lifetime usage across every project in the history scope — cost and all four token
|
|
2287
|
+
* buckets. What the Usage tab's lifetime section renders.
|
|
2288
|
+
*
|
|
2289
|
+
* Rows ONLY — deliberately not rows + live session. Each row holds a project's lifetime
|
|
2290
|
+
* usage and the active project's row is kept current on every transcript change, so
|
|
2291
|
+
* adding the live total would count this project's spend twice. That double-count is what
|
|
2292
|
+
* made the figure grow on every refresh: a page-hide banked a row while the restored
|
|
2293
|
+
* session still carried the same spend.
|
|
2294
|
+
*/
|
|
2295
|
+
get cumulativeUsage(): AggregateUsage;
|
|
2296
|
+
/** Lifetime USD across every project in the history scope. */
|
|
2148
2297
|
get cumulativeCostUsd(): number;
|
|
2298
|
+
/**
|
|
2299
|
+
* Whether the live session figures amount to this project's whole history, which is true
|
|
2300
|
+
* exactly when the transcript is restored on load. Drives the Usage tab's live labels
|
|
2301
|
+
* ("Project cost" vs "Session cost") so they state the scope rather than imply one.
|
|
2302
|
+
*
|
|
2303
|
+
* Note this is NOT what makes the *rows* lifetime — those bank their pre-transcript spend
|
|
2304
|
+
* (see `CostSessionRecord.banked`) and are lifetime either way.
|
|
2305
|
+
*/
|
|
2306
|
+
get liveUsageIsProjectLifetime(): boolean;
|
|
2149
2307
|
/** Resolved cost tab and build-history settings from `chatConfig.costHistory`. */
|
|
2150
2308
|
get resolvedCostHistory(): ResolvedCostHistoryConfig;
|
|
2151
|
-
/**
|
|
2309
|
+
/**
|
|
2310
|
+
* Total tokens across every chat turn in this session — all four buckets added up.
|
|
2311
|
+
* Read-only; the per-bucket split is on `sessionUsage`.
|
|
2312
|
+
*/
|
|
2152
2313
|
get sessionTokensConsumed(): number;
|
|
2153
|
-
|
|
2154
|
-
/** Label shown on the Cost tab for the in-flight session (app title or first user phrase). */
|
|
2314
|
+
/** Label shown on the Usage tab for the in-flight session (app title or first user phrase). */
|
|
2155
2315
|
get liveCostSessionTitle(): string | undefined;
|
|
2156
2316
|
/**
|
|
2157
|
-
*
|
|
2158
|
-
*
|
|
2317
|
+
* Write this session's usage into persisted build history (`localStorage`) as a single
|
|
2318
|
+
* row keyed by the session key, replacing any existing row for that key.
|
|
2319
|
+
*
|
|
2320
|
+
* **Idempotent** — safe to call per turn, on tab close, and on a title change alike.
|
|
2321
|
+
* The name is historical: it does NOT end the session or reset the running totals.
|
|
2322
|
+
* Resetting them is what used to double-count spend, since the row was banked while the
|
|
2323
|
+
* persisted transcript still carried the same usage, so a reload restored it and the
|
|
2324
|
+
* Usage tab counted both.
|
|
2325
|
+
*
|
|
2326
|
+
* No-op unless `chatConfig.costHistory.enabled` is `true`, when the live session has no
|
|
2327
|
+
* usage yet, or when the session has no key to upsert against. Gating on the *live*
|
|
2328
|
+
* figures (not the banked total) means a reload that restores nothing rewrites nothing.
|
|
2159
2329
|
*/
|
|
2160
2330
|
finalizeCostSession(options?: {
|
|
2161
2331
|
title?: string;
|
|
2162
2332
|
}): void;
|
|
2333
|
+
/**
|
|
2334
|
+
* Spend for `projectKey` that predates the current transcript, resolved once per project
|
|
2335
|
+
* and memoised (`_bankedFor`) so it cannot drift mid-session as the row it came from is
|
|
2336
|
+
* rewritten by our own upserts.
|
|
2337
|
+
*
|
|
2338
|
+
* The two cases turn on whether the transcript is authoritative for this project:
|
|
2339
|
+
*
|
|
2340
|
+
* - **Transcript restored** (`persistenceActive`): it already accounts for everything after
|
|
2341
|
+
* the previous row's own banked figure, so carry that figure forward unchanged. Re-banking
|
|
2342
|
+
* `usage` here would add the restored history to itself on every reload.
|
|
2343
|
+
* - **Transcript starts empty**: nothing on screen accounts for the previous total, so the
|
|
2344
|
+
* whole of it becomes banked. Without this the next turn would rewrite the row downwards
|
|
2345
|
+
* to just that turn, losing the project's earlier spend.
|
|
2346
|
+
*/
|
|
2347
|
+
private bankedUsageFor;
|
|
2348
|
+
/**
|
|
2349
|
+
* Discard the banked figure — for when the spend it stands for has been deliberately
|
|
2350
|
+
* thrown away (the user clearing history, or deleting this project's row).
|
|
2351
|
+
*
|
|
2352
|
+
* NOT for reloads. A reload re-reads rows that already include our own upserts, so
|
|
2353
|
+
* re-deriving from them would fold the live session into its own baseline; only a genuine
|
|
2354
|
+
* project change should re-derive, which `bankedUsageFor`'s per-project memo handles.
|
|
2355
|
+
*/
|
|
2356
|
+
private resetBankedUsage;
|
|
2163
2357
|
showConfirmationDialog(confirmationMessage: string, modalParent: HTMLElement, onConfirm: () => void, onCancel?: () => void): void;
|
|
2164
2358
|
/** Remove one entry from persisted build history. */
|
|
2165
2359
|
removeCostSessionFromHistory(id: string): void;
|
|
@@ -2167,7 +2361,45 @@ export declare class FoundationAiAssistant extends GenesisElement {
|
|
|
2167
2361
|
clearCostSessionHistory(): void;
|
|
2168
2362
|
private getCostHistoryScope;
|
|
2169
2363
|
private reloadCostSessionHistory;
|
|
2170
|
-
/**
|
|
2364
|
+
/**
|
|
2365
|
+
* The persistence provider, but only when it implements BOTH cost-history methods.
|
|
2366
|
+
*
|
|
2367
|
+
* Both or neither: a provider that can save but not load would silently accumulate a
|
|
2368
|
+
* ledger nobody ever reads back, so a partial implementation is treated as absent and
|
|
2369
|
+
* falls back to `localStorage`.
|
|
2370
|
+
*/
|
|
2371
|
+
private costHistoryProvider;
|
|
2372
|
+
/**
|
|
2373
|
+
* Adopt `records` as the live list, and schedule a write to whichever backend owns cost
|
|
2374
|
+
* history — the provider when the host implements it, else `localStorage`.
|
|
2375
|
+
*
|
|
2376
|
+
* The list is adopted synchronously because that is what the Usage tab renders; only the
|
|
2377
|
+
* *write* is deferred. This runs on every usage change (about once per LLM call, plus once
|
|
2378
|
+
* per sub-agent turn) and each write serialises the whole ledger, so coalescing cuts a
|
|
2379
|
+
* per-turn `localStorage.setItem` or network round-trip down to one per quiet period. Safe
|
|
2380
|
+
* because the write is a full replace of idempotent state: the newest call wins and no
|
|
2381
|
+
* intermediate state is meaningful. Flushed on `pagehide` and disconnect so nothing is lost.
|
|
2382
|
+
*/
|
|
2383
|
+
private persistCostHistory;
|
|
2384
|
+
/**
|
|
2385
|
+
* Write the pending ledger now. Safe to call when nothing is pending.
|
|
2386
|
+
*
|
|
2387
|
+
* Provider writes are fire-and-forget and best-effort: the ledger is accounting, not
|
|
2388
|
+
* conversation content, so a failed write is logged and never surfaced into the chat. On
|
|
2389
|
+
* `pagehide` the `localStorage` path completes synchronously; a provider write is subject to
|
|
2390
|
+
* the same unload race as every other network save the assistant makes.
|
|
2391
|
+
*/
|
|
2392
|
+
private flushCostHistory;
|
|
2393
|
+
/**
|
|
2394
|
+
* Finalize the previous session when the host-provided title changes — a rename should land on
|
|
2395
|
+
* the row under its old name rather than silently relabelling accrued spend.
|
|
2396
|
+
*
|
|
2397
|
+
* Only when the session key still matches the one that title accrued under. Hosts change
|
|
2398
|
+
* `costHistory.title` on project SWITCH too, and if the key has already flipped, this would
|
|
2399
|
+
* upsert the outgoing project's live usage onto the incoming project's row as
|
|
2400
|
+
* `banked + old live`, inflating it. Under the old append model a mis-keyed write left a stray
|
|
2401
|
+
* row; with the upsert it overwrites a real one.
|
|
2402
|
+
*/
|
|
2171
2403
|
private syncActiveCostSessionTitle;
|
|
2172
2404
|
/** Active model id resolved from the AIProvider, if exposed. */
|
|
2173
2405
|
get activeModel(): string | undefined;
|
|
@@ -2208,7 +2440,7 @@ export declare class FoundationAiAssistant extends GenesisElement {
|
|
|
2208
2440
|
settingsAppSlotted: HTMLElement[];
|
|
2209
2441
|
settingsCostCurrentSlotted: HTMLElement[];
|
|
2210
2442
|
settingsCostHistorySlotted: HTMLElement[];
|
|
2211
|
-
/** Persisted finalized cost sessions shown on the
|
|
2443
|
+
/** Persisted finalized cost sessions shown on the Usage tab build history list. */
|
|
2212
2444
|
costSessionHistory: CostSessionRecord[];
|
|
2213
2445
|
/** Whether the splash overlay is currently showing (no messages and showSplash is enabled). Reflected as a boolean attribute on the host. */
|
|
2214
2446
|
showingSplash: boolean;
|
|
@@ -2222,8 +2454,29 @@ export declare class FoundationAiAssistant extends GenesisElement {
|
|
|
2222
2454
|
private unsubAppSettingsProvider?;
|
|
2223
2455
|
/** Title tracked for the in-flight cost session (used when `header-title` changes). */
|
|
2224
2456
|
private _activeCostSessionTitle;
|
|
2225
|
-
/**
|
|
2226
|
-
|
|
2457
|
+
/**
|
|
2458
|
+
* Session key `_activeCostSessionTitle` was captured under, so a title change can tell a rename
|
|
2459
|
+
* (same key) from a project switch (key already flipped) — see `syncActiveCostSessionTitle`.
|
|
2460
|
+
*/
|
|
2461
|
+
private _activeCostSessionKey?;
|
|
2462
|
+
/** Memoised pre-transcript spend for `_bankedFor` — see `bankedUsageFor`. */
|
|
2463
|
+
private _bankedUsage;
|
|
2464
|
+
/** Project key `_bankedUsage` was resolved for; `undefined` means "not yet resolved". */
|
|
2465
|
+
private _bankedFor;
|
|
2466
|
+
/**
|
|
2467
|
+
* Whether the row list reflects storage yet. Gates cost writes so a project's banked
|
|
2468
|
+
* spend is never derived from a ledger that simply hasn't arrived.
|
|
2469
|
+
*/
|
|
2470
|
+
private _costHistoryLoaded;
|
|
2471
|
+
/**
|
|
2472
|
+
* Set when a provider read failed. Latches writes off for this page-load: `saveCostHistory`
|
|
2473
|
+
* replaces the whole stored list, so writing anything derived from the empty list we fell back
|
|
2474
|
+
* to would destroy rows we never managed to read.
|
|
2475
|
+
*/
|
|
2476
|
+
private _ledgerUnreadable;
|
|
2477
|
+
/** Pending (adopted but unwritten) ledger changes — see `persistCostHistory`. */
|
|
2478
|
+
private _ledgerDirty;
|
|
2479
|
+
private _ledgerFlushTimer?;
|
|
2227
2480
|
private _handlePageHide;
|
|
2228
2481
|
private haloStartPublished;
|
|
2229
2482
|
/** Fingerprint of the agents array used to build the current driver. Used by agentsChanged to skip spurious rebuilds. */
|
|
@@ -2600,21 +2853,33 @@ export declare class FoundationAiAssistant extends GenesisElement {
|
|
|
2600
2853
|
get settingsContextUsageVisible(): boolean;
|
|
2601
2854
|
/** Whether the settings modal UI Builder section should render. */
|
|
2602
2855
|
get settingsAppSectionVisible(): boolean;
|
|
2603
|
-
/** Section title for the app settings block. */
|
|
2604
|
-
get appSettingsSectionTitle(): string;
|
|
2605
2856
|
/** App toggles currently visible per each entry's `visible()` predicate. */
|
|
2606
2857
|
get visibleAppSettingsToggles(): AssistantAppSettingsToggle[];
|
|
2858
|
+
/**
|
|
2859
|
+
* Host-supplied heading for the toggle group, or `undefined` for none — the assistant has no
|
|
2860
|
+
* default. Suppressed when no toggle is currently visible, so a `visible()` predicate hiding
|
|
2861
|
+
* the last one takes its heading with it rather than leaving a label over nothing.
|
|
2862
|
+
*/
|
|
2863
|
+
get appSettingsTogglesHeading(): AssistantAppSettingsHeading | undefined;
|
|
2607
2864
|
getAppSettingValue(id: string): boolean;
|
|
2608
2865
|
setAppSettingValue(id: string, value: boolean): void;
|
|
2609
2866
|
private wireAppSettingsProvider;
|
|
2610
2867
|
private unwireAppSettingsProvider;
|
|
2611
2868
|
get settingsCostCurrentSectionVisible(): boolean;
|
|
2612
2869
|
get settingsCostHistorySectionVisible(): boolean;
|
|
2613
|
-
/** Whether the built-in
|
|
2870
|
+
/** Whether the built-in Usage tab summary block has anything to show. */
|
|
2614
2871
|
get settingsCostSummaryVisible(): boolean;
|
|
2615
|
-
/**
|
|
2872
|
+
/**
|
|
2873
|
+
* Whether the lifetime-usage section has anything to say.
|
|
2874
|
+
*
|
|
2875
|
+
* Requires build history: with it off there are no rows, so `cumulativeUsage` falls back to
|
|
2876
|
+
* the live session and the section would restate the block directly below it under a
|
|
2877
|
+
* "lifetime" heading it hasn't earned.
|
|
2878
|
+
*/
|
|
2879
|
+
get settingsCostLifetimeVisible(): boolean;
|
|
2880
|
+
/** Whether the Usage tab should appear in the settings modal. */
|
|
2616
2881
|
get settingsCostTabVisible(): boolean;
|
|
2617
|
-
/** Whether session token usage should render on the
|
|
2882
|
+
/** Whether session token usage should render on the Usage tab. */
|
|
2618
2883
|
get settingsSessionTokensVisible(): boolean;
|
|
2619
2884
|
/** Whether the chat header (and settings cog) should render. */
|
|
2620
2885
|
get settingsCogVisible(): boolean;
|
|
@@ -3262,12 +3527,18 @@ declare interface ResolvedCostHistoryConfig {
|
|
|
3262
3527
|
title?: string;
|
|
3263
3528
|
/** `localStorage` scope key; falls back to element `id` then `'default'`. */
|
|
3264
3529
|
scope?: string;
|
|
3265
|
-
/** Show running session USD on the
|
|
3530
|
+
/** Show running session USD on the Usage tab. Default: `true`. */
|
|
3266
3531
|
showCost: boolean;
|
|
3267
|
-
/** Show cumulative session tokens on the
|
|
3532
|
+
/** Show cumulative session tokens on the Usage tab. Default: `true`. */
|
|
3268
3533
|
showTokens: boolean;
|
|
3269
|
-
/** Live-session badge label on the
|
|
3534
|
+
/** Live-session badge label on the Usage tab summary. */
|
|
3270
3535
|
badgeLabel: string;
|
|
3536
|
+
/**
|
|
3537
|
+
* Host-supplied disclosure line for the Usage tab. Stays optional — unlike
|
|
3538
|
+
* `badgeLabel` there is no default, because only the host knows what its `scope`
|
|
3539
|
+
* spans, and the library must not assert it.
|
|
3540
|
+
*/
|
|
3541
|
+
summaryHint?: string;
|
|
3271
3542
|
}
|
|
3272
3543
|
|
|
3273
3544
|
/**
|
|
@@ -3385,6 +3656,28 @@ export declare interface SessionPersistenceProvider {
|
|
|
3385
3656
|
loadPreferences?(sessionKey: string): Promise<SessionPreferences | undefined>;
|
|
3386
3657
|
/** Persist the user's UI preferences for `sessionKey` (kept across `clear`). */
|
|
3387
3658
|
savePreferences?(sessionKey: string, preferences: SessionPreferences): Promise<void>;
|
|
3659
|
+
/**
|
|
3660
|
+
* Scoped cost/build history — the per-project usage rows behind the Usage tab.
|
|
3661
|
+
*
|
|
3662
|
+
* ‼️ **Keyed by SCOPE, not `sessionKey`**, unlike every other method on this interface.
|
|
3663
|
+
* A row holds one project's lifetime usage and the list spans projects, so keying it
|
|
3664
|
+
* per session would defeat the model. The scope comes from
|
|
3665
|
+
* `chatConfig.costHistory.scope`, falling back to the element `id`, then `'default'`.
|
|
3666
|
+
*
|
|
3667
|
+
* Optional: when a provider omits these, the assistant falls back to `localStorage`, so
|
|
3668
|
+
* hosts that don't implement them are unaffected. Implementing them moves the ledger to
|
|
3669
|
+
* the host's own backend, which is what stops it being stranded in one browser.
|
|
3670
|
+
*
|
|
3671
|
+
* Read/written **independently of the `enabled` toggle** (as with preferences and
|
|
3672
|
+
* diagnostics): usage accounting is not conversation content, so a user turning off
|
|
3673
|
+
* chat retention should not lose their cost ledger. Best-effort — a failed write must
|
|
3674
|
+
* never affect the chat.
|
|
3675
|
+
*
|
|
3676
|
+
* `undefined` from `loadCostHistory` means "nothing stored", the same as `[]`.
|
|
3677
|
+
*/
|
|
3678
|
+
loadCostHistory?(scope: string): Promise<CostSessionRecord[] | undefined>;
|
|
3679
|
+
/** Replace the stored row list for `scope`. See {@link SessionPersistenceProvider.loadCostHistory}. */
|
|
3680
|
+
saveCostHistory?(scope: string, records: CostSessionRecord[]): Promise<void>;
|
|
3388
3681
|
/**
|
|
3389
3682
|
* Server-saved diagnostics (GENC-1351 §5.8) — a **forward-only append** stream
|
|
3390
3683
|
* that lets the downloadable debug log span the whole session lifetime, not just
|
|
@@ -3428,7 +3721,14 @@ export declare interface SessionPreferences {
|
|
|
3428
3721
|
animations?: string[];
|
|
3429
3722
|
}
|
|
3430
3723
|
|
|
3431
|
-
/**
|
|
3724
|
+
/**
|
|
3725
|
+
* Tab identifiers for the modal tab bar.
|
|
3726
|
+
*
|
|
3727
|
+
* The values are deliberately NOT renamed to match the visible labels ("Configuration" and
|
|
3728
|
+
* "Usage"): they are the public API that hosts read and write via `settingsModalTab`, and are
|
|
3729
|
+
* matched by the `settings-modal-tab-*` shadow parts. Renaming a label is cosmetic; renaming
|
|
3730
|
+
* these would break consumers.
|
|
3731
|
+
*/
|
|
3432
3732
|
declare type SettingsModalTab = 'settings' | 'cost';
|
|
3433
3733
|
|
|
3434
3734
|
/** Design-system tabs element bound to the settings modal tab bar. */
|