@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.
Files changed (98) hide show
  1. package/dist/ai-assistant.api.json +571 -82
  2. package/dist/ai-assistant.d.ts +336 -36
  3. package/dist/chat-driver.cjs +104 -26
  4. package/dist/chat-driver.cjs.map +3 -3
  5. package/dist/chat-driver.mjs +104 -26
  6. package/dist/chat-driver.mjs.map +3 -3
  7. package/dist/custom-elements.json +314 -36
  8. package/dist/dts/components/chat-driver/chat-driver.d.ts +12 -0
  9. package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
  10. package/dist/dts/components/settings-modal/settings-modal.styles.d.ts.map +1 -1
  11. package/dist/dts/components/settings-modal/settings-modal.template.d.ts +9 -2
  12. package/dist/dts/components/settings-modal/settings-modal.template.d.ts.map +1 -1
  13. package/dist/dts/index.d.ts +1 -0
  14. package/dist/dts/index.d.ts.map +1 -1
  15. package/dist/dts/main/cost-session-banking.test.d.ts +2 -0
  16. package/dist/dts/main/cost-session-banking.test.d.ts.map +1 -0
  17. package/dist/dts/main/main.d.ts +184 -24
  18. package/dist/dts/main/main.d.ts.map +1 -1
  19. package/dist/dts/provider/assistant-app-settings.d.ts +30 -5
  20. package/dist/dts/provider/assistant-app-settings.d.ts.map +1 -1
  21. package/dist/dts/state/ai-assistant-slice.d.ts +11 -8
  22. package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
  23. package/dist/dts/state/persistence/session-persistence-provider.d.ts +23 -0
  24. package/dist/dts/state/persistence/session-persistence-provider.d.ts.map +1 -1
  25. package/dist/dts/state/persistence/session-snapshot.d.ts.map +1 -1
  26. package/dist/dts/state/session-store.d.ts +1 -2
  27. package/dist/dts/state/session-store.d.ts.map +1 -1
  28. package/dist/dts/styles/settings-section.d.ts +29 -0
  29. package/dist/dts/styles/settings-section.d.ts.map +1 -0
  30. package/dist/dts/utils/condense-history.d.ts +14 -0
  31. package/dist/dts/utils/condense-history.d.ts.map +1 -1
  32. package/dist/dts/utils/cost-session-history.d.ts +103 -12
  33. package/dist/dts/utils/cost-session-history.d.ts.map +1 -1
  34. package/dist/dts/utils/resolve-cost-history-config.d.ts +9 -3
  35. package/dist/dts/utils/resolve-cost-history-config.d.ts.map +1 -1
  36. package/dist/dts/utils/sum-costs.d.ts.map +1 -1
  37. package/dist/dts/utils/sum-tokens.d.ts +8 -8
  38. package/dist/dts/utils/sum-tokens.d.ts.map +1 -1
  39. package/dist/dts/utils/sum-usage.d.ts +59 -0
  40. package/dist/dts/utils/sum-usage.d.ts.map +1 -0
  41. package/dist/dts/utils/sum-usage.test.d.ts +2 -0
  42. package/dist/dts/utils/sum-usage.test.d.ts.map +1 -0
  43. package/dist/esm/components/chat-driver/chat-driver.js +9 -1
  44. package/dist/esm/components/settings-modal/settings-modal.styles.js +237 -18
  45. package/dist/esm/components/settings-modal/settings-modal.template.js +229 -73
  46. package/dist/esm/index.js +1 -0
  47. package/dist/esm/main/cost-session-banking.test.js +308 -0
  48. package/dist/esm/main/main.js +424 -71
  49. package/dist/esm/state/ai-assistant-slice.js +11 -8
  50. package/dist/esm/state/ai-assistant-slice.test.js +12 -5
  51. package/dist/esm/state/debug-event-log.js +2 -2
  52. package/dist/esm/state/persistence/session-persistence.integration.test.js +5 -1
  53. package/dist/esm/state/persistence/session-persister.js +2 -2
  54. package/dist/esm/state/persistence/session-persister.test.js +10 -1
  55. package/dist/esm/state/persistence/session-snapshot.js +6 -2
  56. package/dist/esm/state/persistence/session-snapshot.test.js +4 -1
  57. package/dist/esm/state/persistence/stateful-restore.e2e.test.js +10 -1
  58. package/dist/esm/styles/settings-section.js +39 -0
  59. package/dist/esm/utils/condense-history.js +18 -5
  60. package/dist/esm/utils/condense-history.test.js +67 -0
  61. package/dist/esm/utils/cost-session-history.js +92 -15
  62. package/dist/esm/utils/cost-session-history.test.js +155 -13
  63. package/dist/esm/utils/resolve-cost-history-config.js +2 -1
  64. package/dist/esm/utils/sum-costs.js +2 -13
  65. package/dist/esm/utils/sum-tokens.js +10 -27
  66. package/dist/esm/utils/sum-tokens.test.js +1 -5
  67. package/dist/esm/utils/sum-usage.js +123 -0
  68. package/dist/esm/utils/sum-usage.test.js +120 -0
  69. package/dist/tsconfig.tsbuildinfo +1 -1
  70. package/package.json +17 -17
  71. package/src/components/chat-driver/chat-driver.ts +21 -0
  72. package/src/components/settings-modal/settings-modal.styles.ts +237 -18
  73. package/src/components/settings-modal/settings-modal.template.ts +270 -81
  74. package/src/index.ts +1 -0
  75. package/src/main/cost-session-banking.test.ts +407 -0
  76. package/src/main/main.ts +433 -68
  77. package/src/provider/assistant-app-settings.ts +31 -5
  78. package/src/state/ai-assistant-slice.test.ts +12 -5
  79. package/src/state/ai-assistant-slice.ts +21 -13
  80. package/src/state/debug-event-log.ts +2 -2
  81. package/src/state/persistence/session-persistence-provider.ts +24 -0
  82. package/src/state/persistence/session-persistence.integration.test.ts +8 -1
  83. package/src/state/persistence/session-persister.test.ts +10 -1
  84. package/src/state/persistence/session-persister.ts +2 -2
  85. package/src/state/persistence/session-snapshot.test.ts +4 -1
  86. package/src/state/persistence/session-snapshot.ts +5 -1
  87. package/src/state/persistence/stateful-restore.e2e.test.ts +9 -1
  88. package/src/styles/settings-section.ts +40 -0
  89. package/src/utils/condense-history.test.ts +103 -0
  90. package/src/utils/condense-history.ts +33 -3
  91. package/src/utils/cost-session-history.test.ts +187 -16
  92. package/src/utils/cost-session-history.ts +142 -23
  93. package/src/utils/resolve-cost-history-config.ts +10 -3
  94. package/src/utils/sum-costs.ts +2 -9
  95. package/src/utils/sum-tokens.test.ts +1 -11
  96. package/src/utils/sum-tokens.ts +10 -26
  97. package/src/utils/sum-usage.test.ts +140 -0
  98. package/src/utils/sum-usage.ts +130 -0
@@ -3629,10 +3629,82 @@
3629
3629
  ],
3630
3630
  "name": "assembleDebugLog"
3631
3631
  },
3632
+ {
3633
+ "kind": "Interface",
3634
+ "canonicalReference": "@genesislcap/ai-assistant!AssistantAppSettingsHeading:interface",
3635
+ "docComment": "/**\n * Optional heading above a provider's toggle group.\n *\n * Entirely host-supplied — the assistant has no default title and no default icon, because the section belongs to the host. Omit it and the toggles render bare, which is right when the host's slotted content already titles them.\n *\n * @beta\n */\n",
3636
+ "excerptTokens": [
3637
+ {
3638
+ "kind": "Content",
3639
+ "text": "export interface AssistantAppSettingsHeading "
3640
+ }
3641
+ ],
3642
+ "fileUrlPath": "src/provider/assistant-app-settings.ts",
3643
+ "releaseTag": "Beta",
3644
+ "name": "AssistantAppSettingsHeading",
3645
+ "preserveMemberOrder": false,
3646
+ "members": [
3647
+ {
3648
+ "kind": "PropertySignature",
3649
+ "canonicalReference": "@genesislcap/ai-assistant!AssistantAppSettingsHeading#icon:member",
3650
+ "docComment": "/**\n * Icon name for the design system's icon element (a Font Awesome free name, e.g. `'object-group'`). Omitted renders text only; an unknown name renders nothing at all, so check it against the installed Font Awesome set.\n */\n",
3651
+ "excerptTokens": [
3652
+ {
3653
+ "kind": "Content",
3654
+ "text": "readonly icon?: "
3655
+ },
3656
+ {
3657
+ "kind": "Content",
3658
+ "text": "string"
3659
+ },
3660
+ {
3661
+ "kind": "Content",
3662
+ "text": ";"
3663
+ }
3664
+ ],
3665
+ "isReadonly": true,
3666
+ "isOptional": true,
3667
+ "releaseTag": "Beta",
3668
+ "name": "icon",
3669
+ "propertyTypeTokenRange": {
3670
+ "startIndex": 1,
3671
+ "endIndex": 2
3672
+ }
3673
+ },
3674
+ {
3675
+ "kind": "PropertySignature",
3676
+ "canonicalReference": "@genesislcap/ai-assistant!AssistantAppSettingsHeading#title:member",
3677
+ "docComment": "",
3678
+ "excerptTokens": [
3679
+ {
3680
+ "kind": "Content",
3681
+ "text": "readonly title: "
3682
+ },
3683
+ {
3684
+ "kind": "Content",
3685
+ "text": "string"
3686
+ },
3687
+ {
3688
+ "kind": "Content",
3689
+ "text": ";"
3690
+ }
3691
+ ],
3692
+ "isReadonly": true,
3693
+ "isOptional": false,
3694
+ "releaseTag": "Beta",
3695
+ "name": "title",
3696
+ "propertyTypeTokenRange": {
3697
+ "startIndex": 1,
3698
+ "endIndex": 2
3699
+ }
3700
+ }
3701
+ ],
3702
+ "extendsTokenRanges": []
3703
+ },
3632
3704
  {
3633
3705
  "kind": "Interface",
3634
3706
  "canonicalReference": "@genesislcap/ai-assistant!AssistantAppSettingsProvider:interface",
3635
- "docComment": "/**\n * App-supplied settings for the platform settings modal UI Builder section. Register a concrete implementation on the DI token at app bootstrap; the assistant renders toggles with the same row layout as AI Chat Bot settings.\n *\n * @beta\n */\n",
3707
+ "docComment": "/**\n * App-supplied settings for the host's own section of the settings modal. Register a concrete implementation on the DI token at app bootstrap; the assistant renders the toggles with the same row layout as AI Chat Bot settings.\n *\n * The section itself is untitled by the assistant — no heading text and no icon — because only the host knows what it is. Title it from the `settings-app` slot, which renders above these toggles, and apply `assistantSettingsSectionTitleStyles` to match the built-in headings.\n *\n * @beta\n */\n",
3636
3708
  "excerptTokens": [
3637
3709
  {
3638
3710
  "kind": "Content",
@@ -3689,33 +3761,6 @@
3689
3761
  ],
3690
3762
  "name": "getValue"
3691
3763
  },
3692
- {
3693
- "kind": "PropertySignature",
3694
- "canonicalReference": "@genesislcap/ai-assistant!AssistantAppSettingsProvider#sectionTitle:member",
3695
- "docComment": "/**\n * Section heading. Default: `\"UI Builder Settings\"`.\n */\n",
3696
- "excerptTokens": [
3697
- {
3698
- "kind": "Content",
3699
- "text": "readonly sectionTitle?: "
3700
- },
3701
- {
3702
- "kind": "Content",
3703
- "text": "string"
3704
- },
3705
- {
3706
- "kind": "Content",
3707
- "text": ";"
3708
- }
3709
- ],
3710
- "isReadonly": true,
3711
- "isOptional": true,
3712
- "releaseTag": "Beta",
3713
- "name": "sectionTitle",
3714
- "propertyTypeTokenRange": {
3715
- "startIndex": 1,
3716
- "endIndex": 2
3717
- }
3718
- },
3719
3764
  {
3720
3765
  "kind": "MethodSignature",
3721
3766
  "canonicalReference": "@genesislcap/ai-assistant!AssistantAppSettingsProvider#setValue:member(1)",
@@ -3857,6 +3902,34 @@
3857
3902
  "startIndex": 1,
3858
3903
  "endIndex": 4
3859
3904
  }
3905
+ },
3906
+ {
3907
+ "kind": "PropertySignature",
3908
+ "canonicalReference": "@genesislcap/ai-assistant!AssistantAppSettingsProvider#togglesHeading:member",
3909
+ "docComment": "/**\n * Heading for the toggle group, for hosts that put other controls in the `settings-app` slot and need these distinguished from them. No default: absent means no heading.\n */\n",
3910
+ "excerptTokens": [
3911
+ {
3912
+ "kind": "Content",
3913
+ "text": "readonly togglesHeading?: "
3914
+ },
3915
+ {
3916
+ "kind": "Reference",
3917
+ "text": "AssistantAppSettingsHeading",
3918
+ "canonicalReference": "@genesislcap/ai-assistant!AssistantAppSettingsHeading:interface"
3919
+ },
3920
+ {
3921
+ "kind": "Content",
3922
+ "text": ";"
3923
+ }
3924
+ ],
3925
+ "isReadonly": true,
3926
+ "isOptional": true,
3927
+ "releaseTag": "Beta",
3928
+ "name": "togglesHeading",
3929
+ "propertyTypeTokenRange": {
3930
+ "startIndex": 1,
3931
+ "endIndex": 2
3932
+ }
3860
3933
  }
3861
3934
  ],
3862
3935
  "extendsTokenRanges": []
@@ -4109,6 +4182,30 @@
4109
4182
  ],
4110
4183
  "extendsTokenRanges": []
4111
4184
  },
4185
+ {
4186
+ "kind": "Variable",
4187
+ "canonicalReference": "@genesislcap/ai-assistant!assistantSettingsSectionTitleStyles:var",
4188
+ "docComment": "/**\n * Heading style for a settings-modal section, published so a host can title its own section.\n *\n * The assistant renders no heading for the `settings-app` slot — no text and no icon — because only the host knows what that section is. The consequence is that a host supplying one has to reproduce the styling of the built-in headings beside it, and a copied rule drifts the moment either side changes. So the declarations live here, are applied by the assistant's own headings, and are exported for the host to apply to its.\n *\n * Compose it into a component's styles and put `ai-settings-section-title` on the heading:\n * ```ts\n * import { assistantSettingsSectionTitleStyles } from '@genesislcap/ai-assistant';\n *\n * const styles = css`\n * ${assistantSettingsSectionTitleStyles}\n * :host { display: block; }\n * `;\n * ```\n *\n * Carries no margin on purpose: spacing belongs to the surrounding layout, which differs between the assistant's own sections and a slotted one, and is the single declaration hosts had to diverge on when they copied this rule.\n *\n * @beta\n */\n",
4189
+ "excerptTokens": [
4190
+ {
4191
+ "kind": "Content",
4192
+ "text": "assistantSettingsSectionTitleStyles: "
4193
+ },
4194
+ {
4195
+ "kind": "Reference",
4196
+ "text": "ElementStyles",
4197
+ "canonicalReference": "@microsoft/fast-element!ElementStyles:class"
4198
+ }
4199
+ ],
4200
+ "fileUrlPath": "src/styles/settings-section.ts",
4201
+ "isReadonly": true,
4202
+ "releaseTag": "Beta",
4203
+ "name": "assistantSettingsSectionTitleStyles",
4204
+ "variableTypeTokenRange": {
4205
+ "startIndex": 1,
4206
+ "endIndex": 2
4207
+ }
4208
+ },
4112
4209
  {
4113
4210
  "kind": "TypeAlias",
4114
4211
  "canonicalReference": "@genesislcap/ai-assistant!CachePolicyInput:type",
@@ -5565,6 +5662,33 @@
5565
5662
  "endIndex": 2
5566
5663
  }
5567
5664
  },
5665
+ {
5666
+ "kind": "PropertySignature",
5667
+ "canonicalReference": "@genesislcap/ai-assistant!ChatDriverConfig#condenseBatchCalls:member",
5668
+ "docComment": "/**\n * Collapse `condenseWhen` payloads in batches of this many model-calls rather than as soon as each trigger fires. A positive integer; decimals are floored and anything below `1` becomes `1`. Default `1` — collapse immediately, the historical behaviour.\n *\n * Condensation rewrites history in place, so collapsing continuously breaks the provider's prompt cache on nearly every call of a re-read loop. Raising this trades up to that many calls' worth of extra context for one cache break per batch.\n */\n",
5669
+ "excerptTokens": [
5670
+ {
5671
+ "kind": "Content",
5672
+ "text": "condenseBatchCalls?: "
5673
+ },
5674
+ {
5675
+ "kind": "Content",
5676
+ "text": "number"
5677
+ },
5678
+ {
5679
+ "kind": "Content",
5680
+ "text": ";"
5681
+ }
5682
+ ],
5683
+ "isReadonly": false,
5684
+ "isOptional": true,
5685
+ "releaseTag": "Beta",
5686
+ "name": "condenseBatchCalls",
5687
+ "propertyTypeTokenRange": {
5688
+ "startIndex": 1,
5689
+ "endIndex": 2
5690
+ }
5691
+ },
5568
5692
  {
5569
5693
  "kind": "PropertySignature",
5570
5694
  "canonicalReference": "@genesislcap/ai-assistant!ChatDriverConfig#maxFoldOperations:member",
@@ -5916,7 +6040,7 @@
5916
6040
  {
5917
6041
  "kind": "Interface",
5918
6042
  "canonicalReference": "@genesislcap/ai-assistant!CostSessionModelEntry:interface",
5919
- "docComment": "/**\n * A model used during a finalized cost session.\n */\n",
6043
+ "docComment": "/**\n * A model used during a recorded cost session.\n */\n",
5920
6044
  "excerptTokens": [
5921
6045
  {
5922
6046
  "kind": "Content",
@@ -5989,7 +6113,7 @@
5989
6113
  {
5990
6114
  "kind": "Interface",
5991
6115
  "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord:interface",
5992
- "docComment": "/**\n * Persisted snapshot of a completed assistant cost session.\n */\n",
6116
+ "docComment": "/**\n * Persisted usage record for one project's assistant work.\n */\n",
5993
6117
  "excerptTokens": [
5994
6118
  {
5995
6119
  "kind": "Content",
@@ -6003,16 +6127,17 @@
6003
6127
  "members": [
6004
6128
  {
6005
6129
  "kind": "PropertySignature",
6006
- "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord#costUsd:member",
6007
- "docComment": "",
6130
+ "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord#banked:member",
6131
+ "docComment": "/**\n * Spend that predates the current transcript, and so cannot be re-derived from it.\n *\n * Without this a row could only ever report what the open transcript proves. That is fine when the transcript is restored on load (it *is* the project's history), but where it starts empty every refresh the row would be rewritten downwards on the next turn and the project's earlier spend lost. Banking it keeps `usage` a lifetime figure in both cases.\n *\n * Deliberately part of the row rather than element state: two assistant instances (a docked bubble and a popped-out panel) share one session, and both write this row. A value derived from the row keeps every write idempotent, whereas an element-held accumulator would be applied once per instance.\n *\n * Optional: rows written before this existed have none, which reads as \"nothing banked\".\n */\n",
6008
6132
  "excerptTokens": [
6009
6133
  {
6010
6134
  "kind": "Content",
6011
- "text": "costUsd: "
6135
+ "text": "banked?: "
6012
6136
  },
6013
6137
  {
6014
- "kind": "Content",
6015
- "text": "number"
6138
+ "kind": "Reference",
6139
+ "text": "AggregateUsage",
6140
+ "canonicalReference": "@genesislcap/foundation-ai!AggregateUsage:interface"
6016
6141
  },
6017
6142
  {
6018
6143
  "kind": "Content",
@@ -6020,9 +6145,9 @@
6020
6145
  }
6021
6146
  ],
6022
6147
  "isReadonly": false,
6023
- "isOptional": false,
6148
+ "isOptional": true,
6024
6149
  "releaseTag": "Public",
6025
- "name": "costUsd",
6150
+ "name": "banked",
6026
6151
  "propertyTypeTokenRange": {
6027
6152
  "startIndex": 1,
6028
6153
  "endIndex": 2
@@ -6030,12 +6155,12 @@
6030
6155
  },
6031
6156
  {
6032
6157
  "kind": "PropertySignature",
6033
- "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord#endedAt:member",
6034
- "docComment": "/**\n * ISO-8601 timestamp when the session was finalized.\n */\n",
6158
+ "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord#id:member",
6159
+ "docComment": "",
6035
6160
  "excerptTokens": [
6036
6161
  {
6037
6162
  "kind": "Content",
6038
- "text": "endedAt: "
6163
+ "text": "id: "
6039
6164
  },
6040
6165
  {
6041
6166
  "kind": "Content",
@@ -6049,7 +6174,7 @@
6049
6174
  "isReadonly": false,
6050
6175
  "isOptional": false,
6051
6176
  "releaseTag": "Public",
6052
- "name": "endedAt",
6177
+ "name": "id",
6053
6178
  "propertyTypeTokenRange": {
6054
6179
  "startIndex": 1,
6055
6180
  "endIndex": 2
@@ -6057,16 +6182,21 @@
6057
6182
  },
6058
6183
  {
6059
6184
  "kind": "PropertySignature",
6060
- "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord#id:member",
6185
+ "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord#models:member",
6061
6186
  "docComment": "",
6062
6187
  "excerptTokens": [
6063
6188
  {
6064
6189
  "kind": "Content",
6065
- "text": "id: "
6190
+ "text": "models: "
6191
+ },
6192
+ {
6193
+ "kind": "Reference",
6194
+ "text": "CostSessionModelEntry",
6195
+ "canonicalReference": "@genesislcap/ai-assistant!CostSessionModelEntry:interface"
6066
6196
  },
6067
6197
  {
6068
6198
  "kind": "Content",
6069
- "text": "string"
6199
+ "text": "[]"
6070
6200
  },
6071
6201
  {
6072
6202
  "kind": "Content",
@@ -6076,29 +6206,24 @@
6076
6206
  "isReadonly": false,
6077
6207
  "isOptional": false,
6078
6208
  "releaseTag": "Public",
6079
- "name": "id",
6209
+ "name": "models",
6080
6210
  "propertyTypeTokenRange": {
6081
6211
  "startIndex": 1,
6082
- "endIndex": 2
6212
+ "endIndex": 3
6083
6213
  }
6084
6214
  },
6085
6215
  {
6086
6216
  "kind": "PropertySignature",
6087
- "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord#models:member",
6088
- "docComment": "",
6217
+ "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord#projectKey:member",
6218
+ "docComment": "/**\n * Stable identity of the work this row stands for — the assistant's session key (a project id, for hosts that key sessions per project). The upsert key: a row is one project's lifetime usage, so re-reporting the same key REPLACES the row rather than adding another.\n */\n",
6089
6219
  "excerptTokens": [
6090
6220
  {
6091
6221
  "kind": "Content",
6092
- "text": "models: "
6093
- },
6094
- {
6095
- "kind": "Reference",
6096
- "text": "CostSessionModelEntry",
6097
- "canonicalReference": "@genesislcap/ai-assistant!CostSessionModelEntry:interface"
6222
+ "text": "projectKey: "
6098
6223
  },
6099
6224
  {
6100
6225
  "kind": "Content",
6101
- "text": "[]"
6226
+ "text": "string"
6102
6227
  },
6103
6228
  {
6104
6229
  "kind": "Content",
@@ -6108,10 +6233,10 @@
6108
6233
  "isReadonly": false,
6109
6234
  "isOptional": false,
6110
6235
  "releaseTag": "Public",
6111
- "name": "models",
6236
+ "name": "projectKey",
6112
6237
  "propertyTypeTokenRange": {
6113
6238
  "startIndex": 1,
6114
- "endIndex": 3
6239
+ "endIndex": 2
6115
6240
  }
6116
6241
  },
6117
6242
  {
@@ -6143,16 +6268,16 @@
6143
6268
  },
6144
6269
  {
6145
6270
  "kind": "PropertySignature",
6146
- "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord#tokensConsumed:member",
6147
- "docComment": "",
6271
+ "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord#updatedAt:member",
6272
+ "docComment": "/**\n * ISO-8601 timestamp of the most recent usage recorded for this row.\n *\n * Named for what it is: the row is upserted as spend accrues, so this moves. It is NOT an end time — a row has no terminal state, because a project can always be worked on again.\n */\n",
6148
6273
  "excerptTokens": [
6149
6274
  {
6150
6275
  "kind": "Content",
6151
- "text": "tokensConsumed: "
6276
+ "text": "updatedAt: "
6152
6277
  },
6153
6278
  {
6154
6279
  "kind": "Content",
6155
- "text": "number"
6280
+ "text": "string"
6156
6281
  },
6157
6282
  {
6158
6283
  "kind": "Content",
@@ -6162,7 +6287,35 @@
6162
6287
  "isReadonly": false,
6163
6288
  "isOptional": false,
6164
6289
  "releaseTag": "Public",
6165
- "name": "tokensConsumed",
6290
+ "name": "updatedAt",
6291
+ "propertyTypeTokenRange": {
6292
+ "startIndex": 1,
6293
+ "endIndex": 2
6294
+ }
6295
+ },
6296
+ {
6297
+ "kind": "PropertySignature",
6298
+ "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord#usage:member",
6299
+ "docComment": "/**\n * Cost plus the four token buckets — the same shape the live session tile renders, so a history row can show the identical breakdown instead of a lone merged total that cannot explain a large token count at a small cost.\n *\n * This is the project's **lifetime** usage: `banked` plus whatever the live transcript currently proves.\n */\n",
6300
+ "excerptTokens": [
6301
+ {
6302
+ "kind": "Content",
6303
+ "text": "usage: "
6304
+ },
6305
+ {
6306
+ "kind": "Reference",
6307
+ "text": "AggregateUsage",
6308
+ "canonicalReference": "@genesislcap/foundation-ai!AggregateUsage:interface"
6309
+ },
6310
+ {
6311
+ "kind": "Content",
6312
+ "text": ";"
6313
+ }
6314
+ ],
6315
+ "isReadonly": false,
6316
+ "isOptional": false,
6317
+ "releaseTag": "Public",
6318
+ "name": "usage",
6166
6319
  "propertyTypeTokenRange": {
6167
6320
  "startIndex": 1,
6168
6321
  "endIndex": 2
@@ -6801,7 +6954,7 @@
6801
6954
  {
6802
6955
  "kind": "Class",
6803
6956
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant:class",
6804
- "docComment": "/**\n * Foundation AI Assistant component.\n *\n * @remarks\n *\n * Register one or more AI providers via `registerAIProviders` from `@genesislcap/foundation-ai`; this element resolves the `AIProviderRegistry` through the DI container. Pass agent configuration via the `agents` property — each agent can override which registered provider it uses via `provider:`. The component creates a `ChatDriver` (single agent) or `OrchestratingDriver` (multiple agents) to manage the conversation loop.\n *\n * Popout/collapse coordination uses `agenticActivityBus` topics `chat-popout` and `chat-popin` — not DOM `CustomEvent`s on this element.\n *\n * **Cost build history:** opt-in via `chatConfig.costHistory.enabled`. When enabled, finalized sessions persist in `localStorage` (scoped by `costHistory.scope`, the element `id`, or `'default'`). Snapshots run on tab close and when the session title changes; hosts may call {@link FoundationAiAssistant.finalizeCostSession}.\n *\n * @fires\n *\n * 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`\n *\n * @fires\n *\n * 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`\n *\n * @beta\n */\n",
6957
+ "docComment": "/**\n * Foundation AI Assistant component.\n *\n * @remarks\n *\n * Register one or more AI providers via `registerAIProviders` from `@genesislcap/foundation-ai`; this element resolves the `AIProviderRegistry` through the DI container. Pass agent configuration via the `agents` property — each agent can override which registered provider it uses via `provider:`. The component creates a `ChatDriver` (single agent) or `OrchestratingDriver` (multiple agents) to manage the conversation loop.\n *\n * Popout/collapse coordination uses `agenticActivityBus` topics `chat-popout` and `chat-popin` — not DOM `CustomEvent`s on this element.\n *\n * **Cost build history:** opt-in via `chatConfig.costHistory.enabled`. When enabled, each session's usage is kept as exactly ONE row per session key in `localStorage` (scoped by `costHistory.scope`, the element `id`, or `'default'`), upserted as spend accrues. So a row is a project's lifetime usage rather than a visit to it, and the Usage tab's total is the sum of the rows alone — the live session is never added on top, because the active project's own row already reflects it. Hosts may call {@link FoundationAiAssistant.finalizeCostSession} to flush early; it is idempotent.\n *\n * @fires\n *\n * 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`\n *\n * @fires\n *\n * 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`\n *\n * @beta\n */\n",
6805
6958
  "excerptTokens": [
6806
6959
  {
6807
6960
  "kind": "Content",
@@ -7221,16 +7374,21 @@
7221
7374
  },
7222
7375
  {
7223
7376
  "kind": "Property",
7224
- "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#appSettingsSectionTitle:member",
7225
- "docComment": "/**\n * Section title for the app settings block.\n */\n",
7377
+ "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#appSettingsTogglesHeading:member",
7378
+ "docComment": "/**\n * Host-supplied heading for the toggle group, or `undefined` for none — the assistant has no default. Suppressed when no toggle is currently visible, so a `visible()` predicate hiding the last one takes its heading with it rather than leaving a label over nothing.\n */\n",
7226
7379
  "excerptTokens": [
7227
7380
  {
7228
7381
  "kind": "Content",
7229
- "text": "get appSettingsSectionTitle(): "
7382
+ "text": "get appSettingsTogglesHeading(): "
7383
+ },
7384
+ {
7385
+ "kind": "Reference",
7386
+ "text": "AssistantAppSettingsHeading",
7387
+ "canonicalReference": "@genesislcap/ai-assistant!AssistantAppSettingsHeading:interface"
7230
7388
  },
7231
7389
  {
7232
7390
  "kind": "Content",
7233
- "text": "string"
7391
+ "text": " | undefined"
7234
7392
  },
7235
7393
  {
7236
7394
  "kind": "Content",
@@ -7240,10 +7398,10 @@
7240
7398
  "isReadonly": true,
7241
7399
  "isOptional": false,
7242
7400
  "releaseTag": "Beta",
7243
- "name": "appSettingsSectionTitle",
7401
+ "name": "appSettingsTogglesHeading",
7244
7402
  "propertyTypeTokenRange": {
7245
7403
  "startIndex": 1,
7246
- "endIndex": 2
7404
+ "endIndex": 3
7247
7405
  },
7248
7406
  "isStatic": false,
7249
7407
  "isProtected": false,
@@ -7936,7 +8094,7 @@
7936
8094
  {
7937
8095
  "kind": "Property",
7938
8096
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#costSessionHistory:member",
7939
- "docComment": "/**\n * Persisted finalized cost sessions shown on the Cost tab build history list.\n */\n",
8097
+ "docComment": "/**\n * Persisted finalized cost sessions shown on the Usage tab build history list.\n */\n",
7940
8098
  "excerptTokens": [
7941
8099
  {
7942
8100
  "kind": "Content",
@@ -7971,7 +8129,7 @@
7971
8129
  {
7972
8130
  "kind": "Property",
7973
8131
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#cumulativeCostUsd:member",
7974
- "docComment": "/**\n * Saved build history plus the in-flight session — shown on the Cost tab summary.\n */\n",
8132
+ "docComment": "/**\n * Lifetime USD across every project in the history scope.\n */\n",
7975
8133
  "excerptTokens": [
7976
8134
  {
7977
8135
  "kind": "Content",
@@ -7998,6 +8156,37 @@
7998
8156
  "isProtected": false,
7999
8157
  "isAbstract": false
8000
8158
  },
8159
+ {
8160
+ "kind": "Property",
8161
+ "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#cumulativeUsage:member",
8162
+ "docComment": "/**\n * Lifetime usage across every project in the history scope — cost and all four token buckets. What the Usage tab's lifetime section renders.\n *\n * Rows ONLY — deliberately not rows + live session. Each row holds a project's lifetime usage and the active project's row is kept current on every transcript change, so adding the live total would count this project's spend twice. That double-count is what made the figure grow on every refresh: a page-hide banked a row while the restored session still carried the same spend.\n */\n",
8163
+ "excerptTokens": [
8164
+ {
8165
+ "kind": "Content",
8166
+ "text": "get cumulativeUsage(): "
8167
+ },
8168
+ {
8169
+ "kind": "Reference",
8170
+ "text": "AggregateUsage",
8171
+ "canonicalReference": "@genesislcap/foundation-ai!AggregateUsage:interface"
8172
+ },
8173
+ {
8174
+ "kind": "Content",
8175
+ "text": ";"
8176
+ }
8177
+ ],
8178
+ "isReadonly": true,
8179
+ "isOptional": false,
8180
+ "releaseTag": "Beta",
8181
+ "name": "cumulativeUsage",
8182
+ "propertyTypeTokenRange": {
8183
+ "startIndex": 1,
8184
+ "endIndex": 2
8185
+ },
8186
+ "isStatic": false,
8187
+ "isProtected": false,
8188
+ "isAbstract": false
8189
+ },
8001
8190
  {
8002
8191
  "kind": "Property",
8003
8192
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#debugRedux:member",
@@ -8293,7 +8482,7 @@
8293
8482
  {
8294
8483
  "kind": "Method",
8295
8484
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#finalizeCostSession:member(1)",
8296
- "docComment": "/**\n * Snapshot the running session into persisted build history (`localStorage`). No-op unless `chatConfig.costHistory.enabled` is `true`.\n */\n",
8485
+ "docComment": "/**\n * Write this session's usage into persisted build history (`localStorage`) as a single row keyed by the session key, replacing any existing row for that key.\n *\n * **Idempotent** — safe to call per turn, on tab close, and on a title change alike. The name is historical: it does NOT end the session or reset the running totals. Resetting them is what used to double-count spend, since the row was banked while the persisted transcript still carried the same usage, so a reload restored it and the Usage tab counted both.\n *\n * No-op unless `chatConfig.costHistory.enabled` is `true`, when the live session has no usage yet, or when the session has no key to upsert against. Gating on the *live* figures (not the banked total) means a reload that restores nothing rewrites nothing.\n */\n",
8297
8486
  "excerptTokens": [
8298
8487
  {
8299
8488
  "kind": "Content",
@@ -8909,7 +9098,7 @@
8909
9098
  {
8910
9099
  "kind": "Property",
8911
9100
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#liveCostSessionTitle:member",
8912
- "docComment": "/**\n * Label shown on the Cost tab for the in-flight session (app title or first user phrase).\n */\n",
9101
+ "docComment": "/**\n * Label shown on the Usage tab for the in-flight session (app title or first user phrase).\n */\n",
8913
9102
  "excerptTokens": [
8914
9103
  {
8915
9104
  "kind": "Content",
@@ -9010,6 +9199,36 @@
9010
9199
  "isProtected": false,
9011
9200
  "isAbstract": false
9012
9201
  },
9202
+ {
9203
+ "kind": "Property",
9204
+ "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#liveUsageIsProjectLifetime:member",
9205
+ "docComment": "/**\n * Whether the live session figures amount to this project's whole history, which is true exactly when the transcript is restored on load. Drives the Usage tab's live labels (\"Project cost\" vs \"Session cost\") so they state the scope rather than imply one.\n *\n * Note this is NOT what makes the *rows* lifetime — those bank their pre-transcript spend (see `CostSessionRecord.banked`) and are lifetime either way.\n */\n",
9206
+ "excerptTokens": [
9207
+ {
9208
+ "kind": "Content",
9209
+ "text": "get liveUsageIsProjectLifetime(): "
9210
+ },
9211
+ {
9212
+ "kind": "Content",
9213
+ "text": "boolean"
9214
+ },
9215
+ {
9216
+ "kind": "Content",
9217
+ "text": ";"
9218
+ }
9219
+ ],
9220
+ "isReadonly": true,
9221
+ "isOptional": false,
9222
+ "releaseTag": "Beta",
9223
+ "name": "liveUsageIsProjectLifetime",
9224
+ "propertyTypeTokenRange": {
9225
+ "startIndex": 1,
9226
+ "endIndex": 2
9227
+ },
9228
+ "isStatic": false,
9229
+ "isProtected": false,
9230
+ "isAbstract": false
9231
+ },
9013
9232
  {
9014
9233
  "kind": "Property",
9015
9234
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#messages:member",
@@ -10022,7 +10241,7 @@
10022
10241
  {
10023
10242
  "kind": "Property",
10024
10243
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#sessionCostUsd:member",
10025
- "docComment": "/**\n * Aggregated USD cost across every chat turn in this session.\n */\n",
10244
+ "docComment": "/**\n * Aggregated USD cost across every chat turn in this session.\n *\n * Read-only (unlike previously): it is a projection of `sessionUsage`, and a host assigning it would have set a figure the next transcript change overwrites.\n */\n",
10026
10245
  "excerptTokens": [
10027
10246
  {
10028
10247
  "kind": "Content",
@@ -10034,10 +10253,10 @@
10034
10253
  },
10035
10254
  {
10036
10255
  "kind": "Content",
10037
- "text": ";\n\nset sessionCostUsd(value: number);"
10256
+ "text": ";"
10038
10257
  }
10039
10258
  ],
10040
- "isReadonly": false,
10259
+ "isReadonly": true,
10041
10260
  "isOptional": false,
10042
10261
  "releaseTag": "Beta",
10043
10262
  "name": "sessionCostUsd",
@@ -10206,7 +10425,7 @@
10206
10425
  {
10207
10426
  "kind": "Property",
10208
10427
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#sessionTokensConsumed:member",
10209
- "docComment": "/**\n * Cumulative input + output tokens across every chat turn in this session.\n */\n",
10428
+ "docComment": "/**\n * Total tokens across every chat turn in this session — all four buckets added up. Read-only; the per-bucket split is on `sessionUsage`.\n */\n",
10210
10429
  "excerptTokens": [
10211
10430
  {
10212
10431
  "kind": "Content",
@@ -10218,10 +10437,10 @@
10218
10437
  },
10219
10438
  {
10220
10439
  "kind": "Content",
10221
- "text": ";\n\nset sessionTokensConsumed(value: number);"
10440
+ "text": ";"
10222
10441
  }
10223
10442
  ],
10224
- "isReadonly": false,
10443
+ "isReadonly": true,
10225
10444
  "isOptional": false,
10226
10445
  "releaseTag": "Beta",
10227
10446
  "name": "sessionTokensConsumed",
@@ -10233,6 +10452,46 @@
10233
10452
  "isProtected": false,
10234
10453
  "isAbstract": false
10235
10454
  },
10455
+ {
10456
+ "kind": "Property",
10457
+ "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#sessionUsage:member",
10458
+ "docComment": "/**\n * Cost plus the four token buckets for this session — derived from the transcript on every change, so it includes sub-agent turns and spend banked by a compaction.\n */\n",
10459
+ "excerptTokens": [
10460
+ {
10461
+ "kind": "Content",
10462
+ "text": "get sessionUsage(): "
10463
+ },
10464
+ {
10465
+ "kind": "Reference",
10466
+ "text": "AggregateUsage",
10467
+ "canonicalReference": "@genesislcap/foundation-ai!AggregateUsage:interface"
10468
+ },
10469
+ {
10470
+ "kind": "Content",
10471
+ "text": ";\n\nset sessionUsage(value: "
10472
+ },
10473
+ {
10474
+ "kind": "Reference",
10475
+ "text": "AggregateUsage",
10476
+ "canonicalReference": "@genesislcap/foundation-ai!AggregateUsage:interface"
10477
+ },
10478
+ {
10479
+ "kind": "Content",
10480
+ "text": ");"
10481
+ }
10482
+ ],
10483
+ "isReadonly": false,
10484
+ "isOptional": false,
10485
+ "releaseTag": "Beta",
10486
+ "name": "sessionUsage",
10487
+ "propertyTypeTokenRange": {
10488
+ "startIndex": 1,
10489
+ "endIndex": 2
10490
+ },
10491
+ "isStatic": false,
10492
+ "isProtected": false,
10493
+ "isAbstract": false
10494
+ },
10236
10495
  {
10237
10496
  "kind": "Method",
10238
10497
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#setAgent:member(1)",
@@ -10766,10 +11025,40 @@
10766
11025
  "isProtected": false,
10767
11026
  "isAbstract": false
10768
11027
  },
11028
+ {
11029
+ "kind": "Property",
11030
+ "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#settingsCostLifetimeVisible:member",
11031
+ "docComment": "/**\n * Whether the lifetime-usage section has anything to say.\n *\n * Requires build history: with it off there are no rows, so `cumulativeUsage` falls back to the live session and the section would restate the block directly below it under a \"lifetime\" heading it hasn't earned.\n */\n",
11032
+ "excerptTokens": [
11033
+ {
11034
+ "kind": "Content",
11035
+ "text": "get settingsCostLifetimeVisible(): "
11036
+ },
11037
+ {
11038
+ "kind": "Content",
11039
+ "text": "boolean"
11040
+ },
11041
+ {
11042
+ "kind": "Content",
11043
+ "text": ";"
11044
+ }
11045
+ ],
11046
+ "isReadonly": true,
11047
+ "isOptional": false,
11048
+ "releaseTag": "Beta",
11049
+ "name": "settingsCostLifetimeVisible",
11050
+ "propertyTypeTokenRange": {
11051
+ "startIndex": 1,
11052
+ "endIndex": 2
11053
+ },
11054
+ "isStatic": false,
11055
+ "isProtected": false,
11056
+ "isAbstract": false
11057
+ },
10769
11058
  {
10770
11059
  "kind": "Property",
10771
11060
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#settingsCostSummaryVisible:member",
10772
- "docComment": "/**\n * Whether the built-in Cost tab summary block has anything to show.\n */\n",
11061
+ "docComment": "/**\n * Whether the built-in Usage tab summary block has anything to show.\n */\n",
10773
11062
  "excerptTokens": [
10774
11063
  {
10775
11064
  "kind": "Content",
@@ -10799,7 +11088,7 @@
10799
11088
  {
10800
11089
  "kind": "Property",
10801
11090
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#settingsCostTabVisible:member",
10802
- "docComment": "/**\n * Whether the Cost tab should appear in the settings modal.\n */\n",
11091
+ "docComment": "/**\n * Whether the Usage tab should appear in the settings modal.\n */\n",
10803
11092
  "excerptTokens": [
10804
11093
  {
10805
11094
  "kind": "Content",
@@ -10986,7 +11275,7 @@
10986
11275
  {
10987
11276
  "kind": "Property",
10988
11277
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#settingsSessionTokensVisible:member",
10989
- "docComment": "/**\n * Whether session token usage should render on the Cost tab.\n */\n",
11278
+ "docComment": "/**\n * Whether session token usage should render on the Usage tab.\n */\n",
10990
11279
  "excerptTokens": [
10991
11280
  {
10992
11281
  "kind": "Content",
@@ -11444,6 +11733,41 @@
11444
11733
  "isProtected": false,
11445
11734
  "isAbstract": false
11446
11735
  },
11736
+ {
11737
+ "kind": "Property",
11738
+ "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#sortedCostSessionHistory:member",
11739
+ "docComment": "/**\n * Build history for display: most recently worked on first.\n *\n * The stored order is insertion order (see `upsertRecord`), which leaves a project returned to sitting wherever it was first seen — so ordering is applied here, on read, where it also covers rows a host provider supplied.\n */\n",
11740
+ "excerptTokens": [
11741
+ {
11742
+ "kind": "Content",
11743
+ "text": "get sortedCostSessionHistory(): "
11744
+ },
11745
+ {
11746
+ "kind": "Reference",
11747
+ "text": "CostSessionRecord",
11748
+ "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord:interface"
11749
+ },
11750
+ {
11751
+ "kind": "Content",
11752
+ "text": "[]"
11753
+ },
11754
+ {
11755
+ "kind": "Content",
11756
+ "text": ";"
11757
+ }
11758
+ ],
11759
+ "isReadonly": true,
11760
+ "isOptional": false,
11761
+ "releaseTag": "Beta",
11762
+ "name": "sortedCostSessionHistory",
11763
+ "propertyTypeTokenRange": {
11764
+ "startIndex": 1,
11765
+ "endIndex": 3
11766
+ },
11767
+ "isStatic": false,
11768
+ "isProtected": false,
11769
+ "isAbstract": false
11770
+ },
11447
11771
  {
11448
11772
  "kind": "Property",
11449
11773
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#state:member",
@@ -11907,6 +12231,41 @@
11907
12231
  "isAbstract": false,
11908
12232
  "name": "triggerFileInput"
11909
12233
  },
12234
+ {
12235
+ "kind": "Property",
12236
+ "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#uniqueProviderModels:member",
12237
+ "docComment": "/**\n * Distinct models the registry currently resolves to — the live session's model chips.\n *\n * `providerStatuses` carries one entry per registry SLOT, so a vendor configured across several tiers that happen to resolve to the same model reports it once per tier, and the chips rendered it once per tier too. Which tier a model came from is not what these chips are for.\n *\n * Deduped on the label actually displayed, not on `status.model`: a slot whose provider reports no model falls back to the slot's own name, and those are distinct per slot, so keying on the label keeps them from collapsing into one another.\n */\n",
12238
+ "excerptTokens": [
12239
+ {
12240
+ "kind": "Content",
12241
+ "text": "get uniqueProviderModels(): "
12242
+ },
12243
+ {
12244
+ "kind": "Reference",
12245
+ "text": "CostSessionModelEntry",
12246
+ "canonicalReference": "@genesislcap/ai-assistant!CostSessionModelEntry:interface"
12247
+ },
12248
+ {
12249
+ "kind": "Content",
12250
+ "text": "[]"
12251
+ },
12252
+ {
12253
+ "kind": "Content",
12254
+ "text": ";"
12255
+ }
12256
+ ],
12257
+ "isReadonly": true,
12258
+ "isOptional": false,
12259
+ "releaseTag": "Beta",
12260
+ "name": "uniqueProviderModels",
12261
+ "propertyTypeTokenRange": {
12262
+ "startIndex": 1,
12263
+ "endIndex": 3
12264
+ },
12265
+ "isStatic": false,
12266
+ "isProtected": false,
12267
+ "isAbstract": false
12268
+ },
11910
12269
  {
11911
12270
  "kind": "Property",
11912
12271
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#userIcon:member",
@@ -15177,6 +15536,65 @@
15177
15536
  ],
15178
15537
  "name": "load"
15179
15538
  },
15539
+ {
15540
+ "kind": "MethodSignature",
15541
+ "canonicalReference": "@genesislcap/ai-assistant!SessionPersistenceProvider#loadCostHistory:member(1)",
15542
+ "docComment": "/**\n * Scoped cost/build history — the per-project usage rows behind the Usage tab.\n *\n * ‼️ **Keyed by SCOPE, not `sessionKey`**, unlike every other method on this interface. A row holds one project's lifetime usage and the list spans projects, so keying it per session would defeat the model. The scope comes from `chatConfig.costHistory.scope`, falling back to the element `id`, then `'default'`.\n *\n * Optional: when a provider omits these, the assistant falls back to `localStorage`, so hosts that don't implement them are unaffected. Implementing them moves the ledger to the host's own backend, which is what stops it being stranded in one browser.\n *\n * Read/written **independently of the `enabled` toggle** (as with preferences and diagnostics): usage accounting is not conversation content, so a user turning off chat retention should not lose their cost ledger. Best-effort — a failed write must never affect the chat.\n *\n * `undefined` from `loadCostHistory` means \"nothing stored\", the same as `[]`.\n */\n",
15543
+ "excerptTokens": [
15544
+ {
15545
+ "kind": "Content",
15546
+ "text": "loadCostHistory?(scope: "
15547
+ },
15548
+ {
15549
+ "kind": "Content",
15550
+ "text": "string"
15551
+ },
15552
+ {
15553
+ "kind": "Content",
15554
+ "text": "): "
15555
+ },
15556
+ {
15557
+ "kind": "Reference",
15558
+ "text": "Promise",
15559
+ "canonicalReference": "!Promise:interface"
15560
+ },
15561
+ {
15562
+ "kind": "Content",
15563
+ "text": "<"
15564
+ },
15565
+ {
15566
+ "kind": "Reference",
15567
+ "text": "CostSessionRecord",
15568
+ "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord:interface"
15569
+ },
15570
+ {
15571
+ "kind": "Content",
15572
+ "text": "[] | undefined>"
15573
+ },
15574
+ {
15575
+ "kind": "Content",
15576
+ "text": ";"
15577
+ }
15578
+ ],
15579
+ "isOptional": true,
15580
+ "returnTypeTokenRange": {
15581
+ "startIndex": 3,
15582
+ "endIndex": 7
15583
+ },
15584
+ "releaseTag": "Public",
15585
+ "overloadIndex": 1,
15586
+ "parameters": [
15587
+ {
15588
+ "parameterName": "scope",
15589
+ "parameterTypeTokenRange": {
15590
+ "startIndex": 1,
15591
+ "endIndex": 2
15592
+ },
15593
+ "isOptional": false
15594
+ }
15595
+ ],
15596
+ "name": "loadCostHistory"
15597
+ },
15180
15598
  {
15181
15599
  "kind": "MethodSignature",
15182
15600
  "canonicalReference": "@genesislcap/ai-assistant!SessionPersistenceProvider#loadDiagnostics:member(1)",
@@ -15362,6 +15780,77 @@
15362
15780
  ],
15363
15781
  "name": "save"
15364
15782
  },
15783
+ {
15784
+ "kind": "MethodSignature",
15785
+ "canonicalReference": "@genesislcap/ai-assistant!SessionPersistenceProvider#saveCostHistory:member(1)",
15786
+ "docComment": "/**\n * Replace the stored row list for `scope`. See {@link SessionPersistenceProvider.loadCostHistory}.\n */\n",
15787
+ "excerptTokens": [
15788
+ {
15789
+ "kind": "Content",
15790
+ "text": "saveCostHistory?(scope: "
15791
+ },
15792
+ {
15793
+ "kind": "Content",
15794
+ "text": "string"
15795
+ },
15796
+ {
15797
+ "kind": "Content",
15798
+ "text": ", records: "
15799
+ },
15800
+ {
15801
+ "kind": "Reference",
15802
+ "text": "CostSessionRecord",
15803
+ "canonicalReference": "@genesislcap/ai-assistant!CostSessionRecord:interface"
15804
+ },
15805
+ {
15806
+ "kind": "Content",
15807
+ "text": "[]"
15808
+ },
15809
+ {
15810
+ "kind": "Content",
15811
+ "text": "): "
15812
+ },
15813
+ {
15814
+ "kind": "Reference",
15815
+ "text": "Promise",
15816
+ "canonicalReference": "!Promise:interface"
15817
+ },
15818
+ {
15819
+ "kind": "Content",
15820
+ "text": "<void>"
15821
+ },
15822
+ {
15823
+ "kind": "Content",
15824
+ "text": ";"
15825
+ }
15826
+ ],
15827
+ "isOptional": true,
15828
+ "returnTypeTokenRange": {
15829
+ "startIndex": 6,
15830
+ "endIndex": 8
15831
+ },
15832
+ "releaseTag": "Public",
15833
+ "overloadIndex": 1,
15834
+ "parameters": [
15835
+ {
15836
+ "parameterName": "scope",
15837
+ "parameterTypeTokenRange": {
15838
+ "startIndex": 1,
15839
+ "endIndex": 2
15840
+ },
15841
+ "isOptional": false
15842
+ },
15843
+ {
15844
+ "parameterName": "records",
15845
+ "parameterTypeTokenRange": {
15846
+ "startIndex": 3,
15847
+ "endIndex": 5
15848
+ },
15849
+ "isOptional": false
15850
+ }
15851
+ ],
15852
+ "name": "saveCostHistory"
15853
+ },
15365
15854
  {
15366
15855
  "kind": "PropertySignature",
15367
15856
  "canonicalReference": "@genesislcap/ai-assistant!SessionPersistenceProvider#saveDebounceMs:member",