@genesislcap/ai-assistant 14.438.1 → 14.439.1-GENC-1250.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4021,6 +4021,36 @@
4021
4021
  "isProtected": false,
4022
4022
  "isAbstract": false
4023
4023
  },
4024
+ {
4025
+ "kind": "Property",
4026
+ "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#activeModel:member",
4027
+ "docComment": "/**\n * Active model id resolved from the AIProvider, if exposed.\n */\n",
4028
+ "excerptTokens": [
4029
+ {
4030
+ "kind": "Content",
4031
+ "text": "get activeModel(): "
4032
+ },
4033
+ {
4034
+ "kind": "Content",
4035
+ "text": "string | undefined"
4036
+ },
4037
+ {
4038
+ "kind": "Content",
4039
+ "text": ";\n\nset activeModel(value: string | undefined);"
4040
+ }
4041
+ ],
4042
+ "isReadonly": false,
4043
+ "isOptional": false,
4044
+ "releaseTag": "Beta",
4045
+ "name": "activeModel",
4046
+ "propertyTypeTokenRange": {
4047
+ "startIndex": 1,
4048
+ "endIndex": 2
4049
+ },
4050
+ "isStatic": false,
4051
+ "isProtected": false,
4052
+ "isAbstract": false
4053
+ },
4024
4054
  {
4025
4055
  "kind": "Property",
4026
4056
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#agentPicker:member",
@@ -4900,7 +4930,7 @@
4900
4930
  },
4901
4931
  {
4902
4932
  "kind": "Content",
4903
- "text": "[];\n activeFoldStack: string[];\n activeDebugSnapshot: unknown;\n turnSnapshots: readonly import(\"../components/chat-driver/chat-driver\")."
4933
+ "text": "[];\n activeFoldStack: string[];\n context: {\n model: string;\n contextTokens: number;\n contextLimit: number;\n contextUsagePercent: number;\n sessionCostUsd: number;\n };\n activeDebugSnapshot: unknown;\n turnSnapshots: readonly import(\"../components/chat-driver/chat-driver\")."
4904
4934
  },
4905
4935
  {
4906
4936
  "kind": "Reference",
@@ -5802,6 +5832,36 @@
5802
5832
  "isAbstract": false,
5803
5833
  "name": "removeAttachmentError"
5804
5834
  },
5835
+ {
5836
+ "kind": "Property",
5837
+ "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#sessionCostUsd:member",
5838
+ "docComment": "/**\n * Aggregated USD cost across every chat turn in this session.\n */\n",
5839
+ "excerptTokens": [
5840
+ {
5841
+ "kind": "Content",
5842
+ "text": "get sessionCostUsd(): "
5843
+ },
5844
+ {
5845
+ "kind": "Content",
5846
+ "text": "number"
5847
+ },
5848
+ {
5849
+ "kind": "Content",
5850
+ "text": ";\n\nset sessionCostUsd(value: number);"
5851
+ }
5852
+ ],
5853
+ "isReadonly": false,
5854
+ "isOptional": false,
5855
+ "releaseTag": "Beta",
5856
+ "name": "sessionCostUsd",
5857
+ "propertyTypeTokenRange": {
5858
+ "startIndex": 1,
5859
+ "endIndex": 2
5860
+ },
5861
+ "isStatic": false,
5862
+ "isProtected": false,
5863
+ "isAbstract": false
5864
+ },
5805
5865
  {
5806
5866
  "kind": "Method",
5807
5867
  "canonicalReference": "@genesislcap/ai-assistant!FoundationAiAssistant#setAgent:member(1)",
@@ -935,6 +935,13 @@ export declare class FoundationAiAssistant extends GenesisElement {
935
935
  set messages(value: ChatMessage[]);
936
936
  get state(): AiAssistantState;
937
937
  set state(value: AiAssistantState);
938
+ /**
939
+ * Re-runs `agentsChanged` if the live `agents` array no longer matches the
940
+ * fingerprint of the currently installed driver. Used to apply swaps that
941
+ * landed during a turn (and were skipped by the `isBusy()` guard) once the
942
+ * driver returns to idle.
943
+ */
944
+ private applyDeferredAgentsSwap;
938
945
  /**
939
946
  * Focus the main chat input if the user is still engaged with the assistant.
940
947
  * Deferred to the next frame so any conditional re-render (e.g. unhiding the
@@ -996,6 +1003,12 @@ export declare class FoundationAiAssistant extends GenesisElement {
996
1003
  /** Context window size for the active model, if known. */
997
1004
  get contextLimit(): number | undefined;
998
1005
  set contextLimit(value: number | undefined);
1006
+ /** Aggregated USD cost across every chat turn in this session. */
1007
+ get sessionCostUsd(): number;
1008
+ set sessionCostUsd(value: number);
1009
+ /** Active model id resolved from the AIProvider, if exposed. */
1010
+ get activeModel(): string | undefined;
1011
+ set activeModel(value: string | undefined);
999
1012
  private _suggestionsGeneration;
1000
1013
  get inputValue(): string;
1001
1014
  set inputValue(value: string);
@@ -1211,6 +1224,13 @@ export declare class FoundationAiAssistant extends GenesisElement {
1211
1224
  activeSystemPrompt: string;
1212
1225
  activePrimerHistory: ChatMessage[];
1213
1226
  activeFoldStack: string[];
1227
+ context: {
1228
+ model: string;
1229
+ contextTokens: number;
1230
+ contextLimit: number;
1231
+ contextUsagePercent: number;
1232
+ sessionCostUsd: number;
1233
+ };
1214
1234
  activeDebugSnapshot: unknown;
1215
1235
  turnSnapshots: readonly TurnSnapshot[];
1216
1236
  debug: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"chat-driver.d.ts","sourceRoot":"","sources":["../../../../src/components/chat-driver/chat-driver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chat-driver.d.ts","sourceRoot":"","sources":["../../../../src/components/chat-driver/chat-driver.ts"],"names":[],"mappings":"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"}
@@ -49,6 +49,13 @@ export declare class FoundationAiAssistant extends GenesisElement {
49
49
  set messages(value: ChatMessage[]);
50
50
  get state(): AiAssistantState;
51
51
  set state(value: AiAssistantState);
52
+ /**
53
+ * Re-runs `agentsChanged` if the live `agents` array no longer matches the
54
+ * fingerprint of the currently installed driver. Used to apply swaps that
55
+ * landed during a turn (and were skipped by the `isBusy()` guard) once the
56
+ * driver returns to idle.
57
+ */
58
+ private applyDeferredAgentsSwap;
52
59
  /**
53
60
  * Focus the main chat input if the user is still engaged with the assistant.
54
61
  * Deferred to the next frame so any conditional re-render (e.g. unhiding the
@@ -110,6 +117,12 @@ export declare class FoundationAiAssistant extends GenesisElement {
110
117
  /** Context window size for the active model, if known. */
111
118
  get contextLimit(): number | undefined;
112
119
  set contextLimit(value: number | undefined);
120
+ /** Aggregated USD cost across every chat turn in this session. */
121
+ get sessionCostUsd(): number;
122
+ set sessionCostUsd(value: number);
123
+ /** Active model id resolved from the AIProvider, if exposed. */
124
+ get activeModel(): string | undefined;
125
+ set activeModel(value: string | undefined);
113
126
  private _suggestionsGeneration;
114
127
  get inputValue(): string;
115
128
  set inputValue(value: string);
@@ -325,6 +338,13 @@ export declare class FoundationAiAssistant extends GenesisElement {
325
338
  activeSystemPrompt: string;
326
339
  activePrimerHistory: ChatMessage[];
327
340
  activeFoldStack: string[];
341
+ context: {
342
+ model: string;
343
+ contextTokens: number;
344
+ contextLimit: number;
345
+ contextUsagePercent: number;
346
+ sessionCostUsd: number;
347
+ };
328
348
  activeDebugSnapshot: unknown;
329
349
  turnSnapshots: readonly import("../components/chat-driver/chat-driver").TurnSnapshot[];
330
350
  debug: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/main/main.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/main/main.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EACV,4BAA4B,EAC5B,WAAW,EACZ,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAGL,cAAc,EAIf,MAAM,uBAAuB,CAAC;AAW/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAgBpD,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,gBAAgB,EACjB,MAAM,cAAc,CAAC;AAgEtB;;;;;;;;;;;;;GAaG;AACH,qBAOa,qBAAsB,SAAQ,cAAc;IAC3C,UAAU,EAAG,UAAU,CAAC;IAExB,kBAAkB,EAAE,MAAM,CAAW;IACZ,WAAW,EAAE,MAAM,CAAuB;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC5C,WAAW,EAAE,MAAM,CAA0B;IACrD;;;;;OAKG;IACiC,UAAU,CAAC,EAAE,UAAU,CAAC;IAC5D;;;OAGG;IACS,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,UAAU,EAAE,UAAU,CAAM;IAExC;;;OAGG;IACH,IAAI,WAAW,IAAI,eAAe,CAEjC;IACW,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC;IAC9C,0EAA0E;IACrB,UAAU,UAAS;IAIxE,OAAO,CAAC,WAAW,CAAC,CAAqB;IAEzC,IAAI,QAAQ,IAAI,WAAW,EAAE,CAE5B;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,EAGhC;IAED,IAAI,KAAK,IAAI,gBAAgB,CAE5B;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,gBAAgB,EAehC;IAED;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IAM/B;;;;;;;;OAQG;IACH,OAAO,CAAC,uBAAuB;IAQ/B,IAAI,WAAW,IAAI,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,SAAS,CAE/D;IACD,IAAI,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,EAM7C;IAED,IAAI,gBAAgB,IAAI,gBAAgB,CAEvC;IACD,IAAI,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAE3C;IAED,iEAAiE;IACjE,IAAI,aAAa,IAAI,OAAO,CAE3B;IACD,IAAI,aAAa,CAAC,KAAK,EAAE,OAAO,EAE/B;IAED,qEAAqE;IACrE,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IACD,IAAI,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAEnC;IAED,8EAA8E;IAC9E,IAAI,wBAAwB,IAAI,OAAO,CAEtC;IACD,IAAI,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAE1C;IAED,oCAAoC;IACpC,IAAI,iBAAiB,IAAI,oBAAoB,EAAE,CAE9C;IACD,IAAI,iBAAiB,CAAC,KAAK,EAAE,oBAAoB,EAAE,EAElD;IAED;;;OAGG;IACH,IAAI,eAAe,IAAI,OAAO,CAE7B;IACD,IAAI,eAAe,CAAC,KAAK,EAAE,OAAO,EAEjC;IAED;;;;OAIG;IACH,IAAI,eAAe,IAAI,MAAM,GAAG,IAAI,CAEnC;IACD,IAAI,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAYvC;IAED,IAAI,iBAAiB,IAAI,WAAW,EAAE,CAErC;IACD,IAAI,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,EAEzC;IAED,IAAI,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEpC;IACD,IAAI,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAExC;IAED;;;OAGG;IACH,IAAI,cAAc,0DAEjB;IAED;;;;;OAKG;IACH,IACI,iCAAiC,IAAI,4BAA4B,CAKpE;IAED,yEAAyE;IACzE,IAAI,aAAa,IAAI,MAAM,GAAG,SAAS,CAEtC;IACD,IAAI,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAE1C;IAED,0DAA0D;IAC1D,IAAI,YAAY,IAAI,MAAM,GAAG,SAAS,CAErC;IACD,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAEzC;IAED,kEAAkE;IAClE,IAAI,cAAc,IAAI,MAAM,CAE3B;IACD,IAAI,cAAc,CAAC,KAAK,EAAE,MAAM,EAE/B;IAED,gEAAgE;IAChE,IAAI,WAAW,IAAI,MAAM,GAAG,SAAS,CAEpC;IACD,IAAI,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAExC;IAID,OAAO,CAAC,sBAAsB,CAAK;IAEnC,IAAI,UAAU,IAAI,MAAM,CAEvB;IACD,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,EAE3B;IACW,WAAW,EAAE,cAAc,EAAE,CAAM;IACnC,gBAAgB,EAAE,MAAM,EAAE,CAAM;IAC5C,+FAA+F;IACnF,oBAAoB,UAAS;IACzC,0CAA0C;IAC9B,YAAY,UAAS;IACjC,6IAA6I;IACjI,aAAa,UAAS;IAElC,OAAO,CAAC,MAAM,CAAC,CAAW;IAC1B,OAAO,CAAC,aAAa,CAAC,CAAa;IACnC,OAAO,CAAC,YAAY,CAA4C;IAChE,OAAO,CAAC,QAAQ,CAAC,CAAa;IAC9B,OAAO,CAAC,kBAAkB,CAAS;IACnC,yHAAyH;IACzH,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAClC,mHAAmH;IACnH,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,oEAAoE;IACpE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;;OAKG;IACS,SAAS,EAAE,OAAO,CAAQ;IACtC,OAAO,CAAC,wBAAwB,CAI9B;IACF,mGAAmG;IACnG,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,eAAe,CAAC,CAAa;IACrC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,0BAA0B,CAAM;IACxD;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAE3C;IACF;;;;;OAKG;IACH,OAAO,CAAC,yBAAyB,CAAC,CAAa;IAEnC,QAAQ,EAAE,IAAI,GAAG,eAAe,GAAG,OAAO,CAAQ;IAE9D,OAAO,CAAC,YAAY;IAapB,0FAA0F;IAC1F,IAAI,2BAA2B,IAAI,OAAO,CAIzC;IAED,eAAe;IAWf,OAAO,CAAC,kBAAkB;IAU1B;;;;;;;;;;OAUG;IACH,IACI,eAAe,IAAI,WAAW,EAAE,CA0BnC;IAED,aAAa,IAAI,IAAI;IAiCrB,mGAAmG;IACnG,OAAO,CAAC,YAAY;IAmBpB;;;;OAIG;IACH;;;;;;OAMG;IACH,OAAO,CAAC,6BAA6B;IAoBrC,OAAO,CAAC,YAAY;IA0CpB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IA8GlB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAKpB,iBAAiB;IA6FjB,oBAAoB;YA2BN,mBAAmB;IAUjC,iBAAiB;IAIjB,oBAAoB;IAWpB,OAAO,CAAC,iBAAiB;IAIzB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAiD5B,2BAA2B;IAQ3B,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAK;IACpD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAK;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAQ;IAE7C,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,gBAAgB;IAKxB,qDAAqD;IACrD,YAAY,IAAI,IAAI;IAQpB,4FAA4F;IAC5F,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAQ9B;IAEF,cAAc;IAId,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAQjC;IAEF,iBAAiB;IAIjB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO;IAWnE,gGAAgG;IAChG,IACI,kBAAkB,IAAI,OAAO,CAIhC;IAED,2FAA2F;IAC3F,IACI,eAAe,IAAI,MAAM,GAAG,SAAS,CAGxC;IAED;;;;;;;;;;;OAWG;IACH,IACI,SAAS,IAAI,OAAO,CAKvB;IAED,iDAAiD;IACjD,IACI,gBAAgB,IAAI,MAAM,CAc7B;IAED;;;;;;OAMG;IACH,IACI,iBAAiB,IAAI,MAAM,GAAG,SAAS,CAM1C;IAED;;;;OAIG;IACH,IACI,oBAAoB,IAAI,MAAM,CAGjC;IAED,mBAAmB;IAInB,uBAAuB;IAIvB,8BAA8B;IAI9B,oBAAoB,CAAC,UAAU,EAAE,oBAAoB,EAAE;IAIvD,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAqEX,gBAAgB;IAehB,gBAAgB,IAAI,IAAI;IAIxB,gBAAgB,CAAC,CAAC,EAAE,KAAK,GAAG,IAAI;IAIhC,gBAAgB,CAAC,UAAU,EAAE,cAAc,GAAG,IAAI;IAIlD,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAU5C,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,cAAc;YASR,iBAAiB;IAmC/B,eAAe;IAIf,qBAAqB,CAAC,UAAU,EAAE,MAAM;YAK1B,gBAAgB;YA4DhB,IAAI;IAwClB,qBAAqB,CAAC,CAAC,EAAE,UAAU;IAYnC,0BAA0B,CAAC,CAAC,EAAE,KAAK;CAQpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.styles.d.ts","sourceRoot":"","sources":["../../../src/main/main.styles.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,MAAM,iDAoqBlB,CAAC"}
1
+ {"version":3,"file":"main.styles.d.ts","sourceRoot":"","sources":["../../../src/main/main.styles.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,MAAM,iDA6rBlB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.template.d.ts","sourceRoot":"","sources":["../../../src/main/main.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAA2B,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAiIpD,gBAAgB;AAChB,eAAO,MAAM,6BAA6B,GACxC,oBAAoB,MAAM,KACzB,YAAY,CAAC,qBAAqB,CA0dpC,CAAC"}
1
+ {"version":3,"file":"main.template.d.ts","sourceRoot":"","sources":["../../../src/main/main.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,EAA2B,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAoIpD,gBAAgB;AAChB,eAAO,MAAM,6BAA6B,GACxC,oBAAoB,MAAM,KACzB,YAAY,CAAC,qBAAqB,CA+epC,CAAC"}
@@ -32,6 +32,10 @@ export interface AiAssistantSessionState {
32
32
  suggestionsState: SuggestionsState;
33
33
  contextTokens: number | undefined;
34
34
  contextLimit: number | undefined;
35
+ /** Aggregated USD cost across every chat turn in this session. */
36
+ sessionCostUsd: number;
37
+ /** Active model id (e.g. `claude-sonnet-4-6`), resolved on connect. */
38
+ activeModel: string | undefined;
35
39
  activeAgent: Omit<AgentConfig, 'toolHandlers'> | undefined;
36
40
  /**
37
41
  * Name of the agent the user has pinned via the picker. `null` means the
@@ -70,6 +74,8 @@ export declare const aiAssistantSlice: import("@reduxjs/toolkit").Slice<AiAssist
70
74
  setSuggestionsState(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<SuggestionsState>): void;
71
75
  setContextTokens(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<number | undefined>): void;
72
76
  setContextLimit(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<number | undefined>): void;
77
+ setSessionCostUsd(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<number>): void;
78
+ setActiveModel(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<string | undefined>): void;
73
79
  setActiveAgent(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<Omit<AgentConfig, "toolHandlers"> | undefined>): void;
74
80
  setPinnedAgentName(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<string | null>): void;
75
81
  setAgentPickerOpen(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<boolean>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"ai-assistant-slice.d.ts","sourceRoot":"","sources":["../../../src/state/ai-assistant-slice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE5F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEnG;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,mEAAmE;IACnE,EAAE,EAAE,MAAM,CAAC;IACX,8CAA8C;IAC9C,IAAI,EAAE,4BAA4B,CAAC;CACpC;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,wBAAwB,EAAE,OAAO,CAAC;IAClC,iBAAiB,EAAE,oBAAoB,EAAE,CAAC;IAC1C,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,SAAS,CAAC;IAC3D;;;;OAIG;IACH,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,iBAAiB,EAAE,WAAW,EAAE,CAAC;IACjC,oEAAoE;IACpE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;;;OAKG;IACH,cAAc,EAAE,aAAa,EAAE,CAAC;CACjC;AAED,eAAO,MAAM,mBAAmB,EAAE,uBAiBjC,CAAC;AAEF,eAAO,MAAM,gBAAgB;uFAIE,aAAa,CAAC,WAAW,EAAE,CAAC;oFAG/B,aAAa,CAAC,gBAAgB,CAAC;4FAGvB,aAAa,CAAC,OAAO,CAAC;gGAGlB,aAAa,CAAC,OAAO,CAAC;uGAGf,aAAa,CAAC,OAAO,CAAC;gGAG7B,aAAa,CAAC,oBAAoB,EAAE,CAAC;+FAGtC,aAAa,CAAC,gBAAgB,CAAC;4FAGlC,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC;2FAGlC,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC;0FAGlC,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,SAAS,CAAC;8FAGxD,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC;8FAG5B,aAAa,CAAC,OAAO,CAAC;yFAG3B,aAAa,CAAC,MAAM,CAAC;gGAGd,aAAa,CAAC,WAAW,EAAE,CAAC;+FAG7B,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC;4FAG/B,aAAa,CAAC,aAAa,CAAC;+FAGzB,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;oCAKlE,CAAC"}
1
+ {"version":3,"file":"ai-assistant-slice.d.ts","sourceRoot":"","sources":["../../../src/state/ai-assistant-slice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAE5F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEnG;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAa;IAC5B,mEAAmE;IACnE,EAAE,EAAE,MAAM,CAAC;IACX,8CAA8C;IAC9C,IAAI,EAAE,4BAA4B,CAAC;CACpC;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,wBAAwB,EAAE,OAAO,CAAC;IAClC,iBAAiB,EAAE,oBAAoB,EAAE,CAAC;IAC1C,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,kEAAkE;IAClE,cAAc,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,SAAS,CAAC;IAC3D;;;;OAIG;IACH,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;;OAIG;IACH,eAAe,EAAE,OAAO,CAAC;IACzB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,iBAAiB,EAAE,WAAW,EAAE,CAAC;IACjC,oEAAoE;IACpE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;;;OAKG;IACH,cAAc,EAAE,aAAa,EAAE,CAAC;CACjC;AAED,eAAO,MAAM,mBAAmB,EAAE,uBAmBjC,CAAC;AAEF,eAAO,MAAM,gBAAgB;uFAIE,aAAa,CAAC,WAAW,EAAE,CAAC;oFAG/B,aAAa,CAAC,gBAAgB,CAAC;4FAGvB,aAAa,CAAC,OAAO,CAAC;gGAGlB,aAAa,CAAC,OAAO,CAAC;uGAGf,aAAa,CAAC,OAAO,CAAC;gGAG7B,aAAa,CAAC,oBAAoB,EAAE,CAAC;+FAGtC,aAAa,CAAC,gBAAgB,CAAC;4FAGlC,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC;2FAGlC,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC;6FAG/B,aAAa,CAAC,MAAM,CAAC;0FAGxB,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC;0FAGjC,aAAa,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,SAAS,CAAC;8FAGxD,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC;8FAG5B,aAAa,CAAC,OAAO,CAAC;yFAG3B,aAAa,CAAC,MAAM,CAAC;gGAGd,aAAa,CAAC,WAAW,EAAE,CAAC;+FAG7B,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC;4FAG/B,aAAa,CAAC,aAAa,CAAC;+FAGzB,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;oCAKlE,CAAC"}
@@ -10,6 +10,8 @@ declare function makeStore(devTools: boolean | undefined): import("@genesislcap/
10
10
  setSuggestionsState(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<import("..").SuggestionsState>): void;
11
11
  setContextTokens(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<number | undefined>): void;
12
12
  setContextLimit(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<number | undefined>): void;
13
+ setSessionCostUsd(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<number>): void;
14
+ setActiveModel(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<string | undefined>): void;
13
15
  setActiveAgent(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<Omit<import("..").AgentConfig, "toolHandlers"> | undefined>): void;
14
16
  setPinnedAgentName(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<string | null>): void;
15
17
  setAgentPickerOpen(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<boolean>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../../src/state/session-store.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAC;AAE9B,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAIvD,iBAAS,SAAS,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;wCAM/C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAMnF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,YAAY,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,CAAC"}
1
+ {"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../../src/state/session-store.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAC;AAE9B,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAIvD,iBAAS,SAAS,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;wCAM/C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAMnF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,YAAY,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,CAAC"}
@@ -224,51 +224,73 @@ export class ChatDriver extends EventTarget {
224
224
  agentContext = `You are currently acting as the "${this.activeAgentName}" agent.`;
225
225
  toolContext = toolNames ? `You have access to the following tools: ${toolNames}.` : '';
226
226
  }
227
- let systemPrompt;
227
+ // System prompt is intentionally short: it sets the role only. Concrete
228
+ // instructions live in the user message *after* the transcript so the
229
+ // immediately-preceding context for the model is "here is data, now do X"
230
+ // rather than "here is a dialogue, continue it". This matters for Anthropic
231
+ // — without it, Claude reads the transcript as an in-progress conversation
232
+ // and produces a normal assistant turn instead of a list of suggestions.
233
+ const systemPrompt = 'You generate suggested prompts that a user could send to an AI assistant. ' +
234
+ 'You never continue the conversation or roleplay as the assistant.';
235
+ const capabilitiesBlock = agentContext || toolContext
236
+ ? `\n\n<capabilities>\n${[agentContext, toolContext].filter(Boolean).join('\n')}\n</capabilities>\nSuggestions must only cover what the agent is capable of. Do not suggest anything outside these capabilities.`
237
+ : '';
238
+ const guidanceBlock = prompt ? `\n\nAdditional guidance: "${prompt}"` : '';
239
+ let userMessage;
228
240
  if (history.length === 0) {
229
- systemPrompt = `You are generating short, simple starter prompts to show a user what an AI assistant can do. Generate exactly ${count} brief suggestions phrased as the user would write them. Keep them short and generic — do not invent specific names, IDs, or data (e.g. prefer "Search for a trade" over "Find all trades with Client A").`;
230
- if (agentContext || toolContext) {
231
- systemPrompt += " Base suggestions only on the agent's actual capabilities.";
232
- if (agentContext)
233
- systemPrompt += ` ${agentContext}`;
234
- if (toolContext)
235
- systemPrompt += ` ${toolContext}`;
236
- systemPrompt += ' Do not suggest anything outside these capabilities.';
237
- }
241
+ userMessage =
242
+ `Generate exactly ${count} brief starter prompts to show a user what an AI assistant can do. ` +
243
+ `Phrase each one as the user would write it. Keep them short and generic — do not invent specific names, IDs, or data (e.g. prefer "Search for a trade" over "Find all trades with Client A").` +
244
+ capabilitiesBlock +
245
+ guidanceBlock +
246
+ `\n\nOutput format (strict):\n` +
247
+ `- Exactly ${count} lines.\n` +
248
+ `- One suggestion per line.\n` +
249
+ `- No numbering, bullets, markdown, emojis, code blocks, or quotes around the suggestion.\n` +
250
+ `- No preamble, headings, summary, or commentary before or after the list.`;
238
251
  }
239
252
  else {
240
- systemPrompt = `You are generating suggested follow-up prompts that a user could send to an AI assistant. Generate exactly ${count} suggestions phrased as the user would write them — first-person requests or questions directed at the agent. The first ${Math.max(0, count - 1)} should be natural follow-ups to the last turn of conversation. Do not invent specific names, IDs, or data values that do not appear in the conversation history.`;
241
- if (agentContext || toolContext) {
242
- systemPrompt += ' Suggestions must only cover what the agent is capable of.';
243
- if (agentContext)
244
- systemPrompt += ` ${agentContext}`;
245
- if (toolContext)
246
- systemPrompt += ` ${toolContext}`;
247
- systemPrompt += ' Do not suggest anything outside these capabilities.';
248
- }
249
- }
250
- if (prompt) {
251
- systemPrompt += ` Additional guidance: "${prompt}"`;
253
+ const conversationContext = history
254
+ .filter((m) => {
255
+ var _a, _b;
256
+ return (m.role === 'user' || m.role === 'assistant') &&
257
+ !((_a = m.toolCalls) === null || _a === void 0 ? void 0 : _a.length) &&
258
+ !m.thinking &&
259
+ !!((_b = m.content) === null || _b === void 0 ? void 0 : _b.trim());
260
+ })
261
+ .slice(-SUGGESTIONS_HISTORY_WINDOW)
262
+ .map((m) => `${m.role === 'user' ? 'User' : 'Assistant'}: ${m.content}`)
263
+ .join('\n');
264
+ userMessage =
265
+ `<conversation_history>\n${conversationContext}\n</conversation_history>\n\n` +
266
+ `The conversation above has ended. Do not continue it or respond as the assistant. ` +
267
+ `Generate exactly ${count} follow-up prompts the *user* might send next, phrased in first person as the user would write them. ` +
268
+ `The first ${Math.max(0, count - 1)} should be natural follow-ups to the last turn. ` +
269
+ `Do not invent specific names, IDs, or data values that do not appear in <conversation_history>.` +
270
+ capabilitiesBlock +
271
+ guidanceBlock +
272
+ `\n\nOutput format (strict):\n` +
273
+ `- Exactly ${count} lines.\n` +
274
+ `- One suggestion per line.\n` +
275
+ `- No numbering, bullets, markdown, emojis, code blocks, or quotes around the suggestion.\n` +
276
+ `- No preamble, headings, summary, or commentary before or after the list.`;
252
277
  }
253
- systemPrompt +=
254
- ' Output only the suggestions one per line, no numbering, no bullets, no commentary, no preamble. Do not describe or explain the suggestions.';
255
- const conversationContext = history
256
- .filter((m) => {
257
- var _a, _b;
258
- return (m.role === 'user' || m.role === 'assistant') &&
259
- !((_a = m.toolCalls) === null || _a === void 0 ? void 0 : _a.length) &&
260
- !m.thinking &&
261
- !!((_b = m.content) === null || _b === void 0 ? void 0 : _b.trim());
262
- })
263
- .slice(-SUGGESTIONS_HISTORY_WINDOW)
264
- .map((m) => `${m.role === 'user' ? 'User' : 'Assistant'}: ${m.content}`)
265
- .join('\n');
266
- const message = conversationContext || 'The conversation has not started yet.';
267
- const text = yield this.aiProvider.prompt(message, { systemPrompt });
268
- return text
278
+ const text = yield this.aiProvider.prompt(userMessage, { systemPrompt });
279
+ // Lenient parsing as a defensive backstop: even with the strict prompt,
280
+ // models occasionally slip in numbering, bullets, or surrounding markdown.
281
+ return (text
269
282
  .split('\n')
270
283
  .map((s) => s.trim())
271
- .filter(Boolean);
284
+ // strip leading bullets/numbers ("- ", "* ", "• ", "1. ", "1) ")
285
+ .map((s) => s.replace(/^([-*•]|\d+[.)])\s+/, ''))
286
+ // strip surrounding bold/italic markers
287
+ .map((s) => s.replace(/^[*_]{1,3}|[*_]{1,3}$/g, '').trim())
288
+ // drop empty lines, separators, and obvious preamble lines
289
+ .filter((s) => s.length > 0)
290
+ .filter((s) => !/^[-=]{2,}$/.test(s))
291
+ .filter((s) => !/^here (are|is) /i.test(s))
292
+ .filter((s) => !s.endsWith(':'))
293
+ .slice(0, count));
272
294
  });
273
295
  }
274
296
  isBusy() {
@@ -60,13 +60,6 @@ const AGENT_PICKER_CLOSE_MS = 200;
60
60
  * the `settings-slide-out` keyframe duration in `main.styles.ts`.
61
61
  */
62
62
  const SETTINGS_CLOSE_MS = 200;
63
- const MODEL_CONTEXT_LIMITS = {
64
- 'gemini-2.5-flash': 1048576,
65
- 'gemini-2.5-flash-lite': 1048576,
66
- 'gpt-4o': 128000,
67
- 'gpt-4o-mini': 128000,
68
- 'gpt-4-turbo': 128000,
69
- };
70
63
  // Register supporting components when the main component module is imported.
71
64
  avoidTreeShaking(AiChatMarkdown, AiChatInteractionWrapper, AiHaloOverlay, AiChatBubble, AiActivityHalo, ChatSuggestions, AgentPicker);
72
65
  /**
@@ -183,8 +176,26 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
183
176
  // if they haven't moved on to something else on the page.
184
177
  if (prev === 'loading' && value !== 'loading') {
185
178
  this.maybeAutoFocusChatInput();
179
+ // Apply any agents swap deferred by the busy guard in `agentsChanged`.
180
+ // Host-side `agents` getters typically cache a stable reference between
181
+ // predicate changes, so FAST's property binding will not re-fire the
182
+ // setter on its own once the turn finishes — re-enter manually.
183
+ this.applyDeferredAgentsSwap();
186
184
  }
187
185
  }
186
+ /**
187
+ * Re-runs `agentsChanged` if the live `agents` array no longer matches the
188
+ * fingerprint of the currently installed driver. Used to apply swaps that
189
+ * landed during a turn (and were skipped by the `isBusy()` guard) once the
190
+ * driver returns to idle.
191
+ */
192
+ applyDeferredAgentsSwap() {
193
+ if (!this.driver)
194
+ return;
195
+ if (this.getAgentsKey(this.agents) === this._driverAgentsKey)
196
+ return;
197
+ this.agentsChanged();
198
+ }
188
199
  /**
189
200
  * Focus the main chat input if the user is still engaged with the assistant.
190
201
  * Deferred to the next frame so any conditional re-render (e.g. unhiding the
@@ -352,6 +363,24 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
352
363
  var _a;
353
364
  (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setContextLimit(value);
354
365
  }
366
+ /** Aggregated USD cost across every chat turn in this session. */
367
+ get sessionCostUsd() {
368
+ var _a, _b;
369
+ return (_b = (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.sessionCostUsd) !== null && _b !== void 0 ? _b : 0;
370
+ }
371
+ set sessionCostUsd(value) {
372
+ var _a;
373
+ (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setSessionCostUsd(value);
374
+ }
375
+ /** Active model id resolved from the AIProvider, if exposed. */
376
+ get activeModel() {
377
+ var _a;
378
+ return (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.activeModel;
379
+ }
380
+ set activeModel(value) {
381
+ var _a;
382
+ (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setActiveModel(value);
383
+ }
355
384
  get inputValue() {
356
385
  var _a, _b;
357
386
  return (_b = (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.inputValue) !== null && _b !== void 0 ? _b : '';
@@ -455,11 +484,11 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
455
484
  const newKey = this.getAgentsKey(this.agents);
456
485
  if (newKey === this._driverAgentsKey)
457
486
  return;
458
- this._driverAgentsKey = newKey;
459
- // Don't rebuild while the driver is busy it was created with the correct agents
460
- // and has live pending interactions. This prevents the collapse element (which
461
- // initially has no agents, then gets them assigned by its wrapper) from tearing
462
- // down a mid-flight driver and creating a fresh idle one.
487
+ // Don't rebuild while the driver is busy — pending interactions and the
488
+ // in-flight tool loop reference the captured agents array. The swap is
489
+ // re-attempted from the `state` setter on the loading→idle transition.
490
+ // `_driverAgentsKey` is updated only after the rebuild actually installs
491
+ // the new agents, so the deferred re-attempt still sees the mismatch.
463
492
  if (this.driver.isBusy())
464
493
  return;
465
494
  const history = (_c = (_b = (_a = this.driver).getRawHistory) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : [];
@@ -476,6 +505,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
476
505
  this.wireDriver();
477
506
  if (history.length)
478
507
  this.driver.loadHistory([...history]);
508
+ this._driverAgentsKey = newKey;
479
509
  }
480
510
  /** Returns a stable fingerprint for an agents array based on agent names and tool handler keys. */
481
511
  getAgentsKey(agents) {
@@ -794,12 +824,11 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
794
824
  var _a, _b;
795
825
  try {
796
826
  const status = yield ((_b = (_a = this.aiProvider).getStatus) === null || _b === void 0 ? void 0 : _b.call(_a));
797
- if (status === null || status === void 0 ? void 0 : status.model) {
798
- this.contextLimit = MODEL_CONTEXT_LIMITS[status.model];
799
- }
827
+ this.contextLimit = status === null || status === void 0 ? void 0 : status.contextLimit;
828
+ this.activeModel = status === null || status === void 0 ? void 0 : status.model;
800
829
  }
801
830
  catch (_c) {
802
- // Non-fatal — context limit display simply won't show
831
+ // Non-fatal — context limit / model display simply won't show
803
832
  }
804
833
  });
805
834
  }
@@ -849,6 +878,17 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
849
878
  break;
850
879
  }
851
880
  }
881
+ // Recompute aggregated session cost from per-message `cost` fields. Recomputing
882
+ // (rather than incrementing on append) keeps the total correct under any
883
+ // mutation of the message list — including future clear-chat / re-render flows.
884
+ let runningCost = 0;
885
+ for (const m of this.messages) {
886
+ if (m.cost != null)
887
+ runningCost += m.cost;
888
+ }
889
+ if (runningCost !== this.sessionCostUsd) {
890
+ this.sessionCostUsd = runningCost;
891
+ }
852
892
  // Publish halo-start whenever a new toolCalls message arrives.
853
893
  if (this.showHalo !== 'no' && ((_a = this.enabledAnimations) === null || _a === void 0 ? void 0 : _a.includes('halo'))) {
854
894
  const last = this.messages[this.messages.length - 1];
@@ -1060,6 +1100,9 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
1060
1100
  catch (e) {
1061
1101
  activeDebugSnapshot = `<getDebugSnapshot threw: ${e instanceof Error ? e.message : String(e)}>`;
1062
1102
  }
1103
+ const contextUsagePercent = this.contextTokens != null && this.contextLimit != null && this.contextLimit > 0
1104
+ ? Math.round((this.contextTokens / this.contextLimit) * 100)
1105
+ : undefined;
1063
1106
  return {
1064
1107
  messages: (_e = (_d = (_c = this.driver) === null || _c === void 0 ? void 0 : _c.getRawHistory) === null || _d === void 0 ? void 0 : _d.call(_c)) !== null && _e !== void 0 ? _e : this.messages,
1065
1108
  meta: {
@@ -1082,6 +1125,18 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
1082
1125
  : (_k = this.activeAgent) === null || _k === void 0 ? void 0 : _k.systemPrompt,
1083
1126
  activePrimerHistory: (_l = this.activeAgent) === null || _l === void 0 ? void 0 : _l.primerHistory,
1084
1127
  activeFoldStack: this.driver instanceof ChatDriver ? this.driver.getActiveFoldNames() : undefined,
1128
+ // Context window + cost snapshot. `sessionCostUsd` is the chat-scoped
1129
+ // total (per-message `cost` summed); the transport's lifetime cost is
1130
+ // not included here because it pools other call sites (suggestions,
1131
+ // criteria interpretation, etc.) and would be misleading next to the
1132
+ // chat-only token counts.
1133
+ context: {
1134
+ model: this.activeModel,
1135
+ contextTokens: this.contextTokens,
1136
+ contextLimit: this.contextLimit,
1137
+ contextUsagePercent,
1138
+ sessionCostUsd: this.sessionCostUsd,
1139
+ },
1085
1140
  // Snapshot captured fresh at log-export time — reflects state NOW, which
1086
1141
  // may have transitioned since the last LLM call.
1087
1142
  activeDebugSnapshot,
@@ -226,6 +226,31 @@ export const styles = css `
226
226
  width: 100%;
227
227
  }
228
228
 
229
+ .session-stat {
230
+ animation: settings-slide-in 0.2s ease-out;
231
+ padding: calc(var(--design-unit) * 1.5px) calc(var(--design-unit) * 3px);
232
+ border-bottom: 1px solid var(--neutral-stroke-rest);
233
+ background-color: var(--neutral-layer-2);
234
+ display: flex;
235
+ justify-content: space-between;
236
+ align-items: baseline;
237
+ gap: calc(var(--design-unit) * 2px);
238
+ }
239
+
240
+ .session-stat-label {
241
+ font-size: 0.85em;
242
+ font-weight: 600;
243
+ color: var(--neutral-foreground-rest);
244
+ white-space: nowrap;
245
+ }
246
+
247
+ .session-stat-value {
248
+ font-size: 0.8em;
249
+ color: var(--neutral-foreground-hint, var(--neutral-foreground-rest));
250
+ opacity: 80%;
251
+ font-family: var(--monospace-font, ui-monospace, monospace);
252
+ }
253
+
229
254
  .splash-wrapper {
230
255
  position: absolute;
231
256
  inset: 0;
@@ -33,6 +33,8 @@ const animationItemRenderer = (option) => html `
33
33
  const HALO_SPEED_DEFAULT = 1.5;
34
34
  const HALO_SPEED_ORCHESTRATING = 0.4;
35
35
  const HALO_BORDER_SIZE_DEFAULT = 3;
36
+ /** Decimal places shown for the running session cost (USD). 4 ≈ $0.0001 resolution. */
37
+ const SESSION_COST_DECIMALS = 4;
36
38
  const animationOptions = Object.entries(ANIMATION_DEFS).map(([value, def]) => ({
37
39
  value,
38
40
  label: def.label,
@@ -374,6 +376,20 @@ ${(tc) => { var _a; return (((_a = tc.foldPath) === null || _a === void 0 ? void
374
376
  ></${progressTag}>
375
377
  </div>
376
378
  `)}
379
+ ${when((x) => { var _a; return x.settingsOpen && ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.showActiveModel) !== false && x.activeModel != null; }, html `
380
+ <div class="session-stat" part="active-model">
381
+ <span class="session-stat-label">Model</span>
382
+ <span class="session-stat-value">${(x) => x.activeModel}</span>
383
+ </div>
384
+ `)}
385
+ ${when((x) => { var _a; return x.settingsOpen && ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.showSessionCost) !== false && x.sessionCostUsd > 0; }, html `
386
+ <div class="session-stat" part="session-cost">
387
+ <span class="session-stat-label">Session cost</span>
388
+ <span class="session-stat-value">
389
+ $${(x) => x.sessionCostUsd.toFixed(SESSION_COST_DECIMALS)}
390
+ </span>
391
+ </div>
392
+ `)}
377
393
 
378
394
  <div class="splash-wrapper" part="splash">
379
395
  <slot name="splash"></slot>
@@ -9,6 +9,8 @@ export const defaultSessionState = {
9
9
  suggestionsState: { status: 'idle' },
10
10
  contextTokens: undefined,
11
11
  contextLimit: undefined,
12
+ sessionCostUsd: 0,
13
+ activeModel: undefined,
12
14
  activeAgent: undefined,
13
15
  pinnedAgentName: null,
14
16
  agentPickerOpen: false,
@@ -48,6 +50,12 @@ export const aiAssistantSlice = createSlice({
48
50
  setContextLimit(state, action) {
49
51
  state.contextLimit = action.payload;
50
52
  },
53
+ setSessionCostUsd(state, action) {
54
+ state.sessionCostUsd = action.payload;
55
+ },
56
+ setActiveModel(state, action) {
57
+ state.activeModel = action.payload;
58
+ },
51
59
  setActiveAgent(state, action) {
52
60
  state.activeAgent = action.payload;
53
61
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@genesislcap/ai-assistant",
3
3
  "description": "Genesis AI Assistant micro-frontend",
4
- "version": "14.438.1",
4
+ "version": "14.439.1-GENC-1250.1",
5
5
  "license": "SEE LICENSE IN license.txt",
6
6
  "main": "dist/esm/index.js",
7
7
  "types": "dist/ai-assistant.d.ts",
@@ -64,24 +64,24 @@
64
64
  }
65
65
  },
66
66
  "devDependencies": {
67
- "@genesislcap/foundation-testing": "14.438.1",
68
- "@genesislcap/genx": "14.438.1",
69
- "@genesislcap/rollup-builder": "14.438.1",
70
- "@genesislcap/ts-builder": "14.438.1",
71
- "@genesislcap/uvu-playwright-builder": "14.438.1",
72
- "@genesislcap/vite-builder": "14.438.1",
73
- "@genesislcap/webpack-builder": "14.438.1",
67
+ "@genesislcap/foundation-testing": "14.439.1-GENC-1250.1",
68
+ "@genesislcap/genx": "14.439.1-GENC-1250.1",
69
+ "@genesislcap/rollup-builder": "14.439.1-GENC-1250.1",
70
+ "@genesislcap/ts-builder": "14.439.1-GENC-1250.1",
71
+ "@genesislcap/uvu-playwright-builder": "14.439.1-GENC-1250.1",
72
+ "@genesislcap/vite-builder": "14.439.1-GENC-1250.1",
73
+ "@genesislcap/webpack-builder": "14.439.1-GENC-1250.1",
74
74
  "@types/dompurify": "^3.0.5",
75
75
  "@types/marked": "^5.0.2"
76
76
  },
77
77
  "dependencies": {
78
- "@genesislcap/foundation-ai": "14.438.1",
79
- "@genesislcap/foundation-logger": "14.438.1",
80
- "@genesislcap/foundation-redux": "14.438.1",
81
- "@genesislcap/foundation-ui": "14.438.1",
82
- "@genesislcap/foundation-utils": "14.438.1",
83
- "@genesislcap/rapid-design-system": "14.438.1",
84
- "@genesislcap/web-core": "14.438.1",
78
+ "@genesislcap/foundation-ai": "14.439.1-GENC-1250.1",
79
+ "@genesislcap/foundation-logger": "14.439.1-GENC-1250.1",
80
+ "@genesislcap/foundation-redux": "14.439.1-GENC-1250.1",
81
+ "@genesislcap/foundation-ui": "14.439.1-GENC-1250.1",
82
+ "@genesislcap/foundation-utils": "14.439.1-GENC-1250.1",
83
+ "@genesislcap/rapid-design-system": "14.439.1-GENC-1250.1",
84
+ "@genesislcap/web-core": "14.439.1-GENC-1250.1",
85
85
  "dompurify": "^3.3.1",
86
86
  "marked": "^17.0.3"
87
87
  },
@@ -93,5 +93,5 @@
93
93
  "publishConfig": {
94
94
  "access": "public"
95
95
  },
96
- "gitHead": "65abdfa1a8d4d0ad873ed356dff62952dd2e2a92"
96
+ "gitHead": "4347686a257fc3d74548bba4cdbc570d1ea14914"
97
97
  }
@@ -392,49 +392,82 @@ export class ChatDriver extends EventTarget implements AiDriver {
392
392
  toolContext = toolNames ? `You have access to the following tools: ${toolNames}.` : '';
393
393
  }
394
394
 
395
- let systemPrompt: string;
395
+ // System prompt is intentionally short: it sets the role only. Concrete
396
+ // instructions live in the user message *after* the transcript so the
397
+ // immediately-preceding context for the model is "here is data, now do X"
398
+ // rather than "here is a dialogue, continue it". This matters for Anthropic
399
+ // — without it, Claude reads the transcript as an in-progress conversation
400
+ // and produces a normal assistant turn instead of a list of suggestions.
401
+ const systemPrompt =
402
+ 'You generate suggested prompts that a user could send to an AI assistant. ' +
403
+ 'You never continue the conversation or roleplay as the assistant.';
404
+
405
+ const capabilitiesBlock =
406
+ agentContext || toolContext
407
+ ? `\n\n<capabilities>\n${[agentContext, toolContext].filter(Boolean).join('\n')}\n</capabilities>\nSuggestions must only cover what the agent is capable of. Do not suggest anything outside these capabilities.`
408
+ : '';
409
+
410
+ const guidanceBlock = prompt ? `\n\nAdditional guidance: "${prompt}"` : '';
411
+
412
+ let userMessage: string;
396
413
  if (history.length === 0) {
397
- systemPrompt = `You are generating short, simple starter prompts to show a user what an AI assistant can do. Generate exactly ${count} brief suggestions phrased as the user would write them. Keep them short and generic — do not invent specific names, IDs, or data (e.g. prefer "Search for a trade" over "Find all trades with Client A").`;
398
- if (agentContext || toolContext) {
399
- systemPrompt += " Base suggestions only on the agent's actual capabilities.";
400
- if (agentContext) systemPrompt += ` ${agentContext}`;
401
- if (toolContext) systemPrompt += ` ${toolContext}`;
402
- systemPrompt += ' Do not suggest anything outside these capabilities.';
403
- }
414
+ userMessage =
415
+ `Generate exactly ${count} brief starter prompts to show a user what an AI assistant can do. ` +
416
+ `Phrase each one as the user would write it. Keep them short and generic — do not invent specific names, IDs, or data (e.g. prefer "Search for a trade" over "Find all trades with Client A").` +
417
+ capabilitiesBlock +
418
+ guidanceBlock +
419
+ `\n\nOutput format (strict):\n` +
420
+ `- Exactly ${count} lines.\n` +
421
+ `- One suggestion per line.\n` +
422
+ `- No numbering, bullets, markdown, emojis, code blocks, or quotes around the suggestion.\n` +
423
+ `- No preamble, headings, summary, or commentary before or after the list.`;
404
424
  } else {
405
- systemPrompt = `You are generating suggested follow-up prompts that a user could send to an AI assistant. Generate exactly ${count} suggestions phrased as the user would write them — first-person requests or questions directed at the agent. The first ${Math.max(0, count - 1)} should be natural follow-ups to the last turn of conversation. Do not invent specific names, IDs, or data values that do not appear in the conversation history.`;
406
- if (agentContext || toolContext) {
407
- systemPrompt += ' Suggestions must only cover what the agent is capable of.';
408
- if (agentContext) systemPrompt += ` ${agentContext}`;
409
- if (toolContext) systemPrompt += ` ${toolContext}`;
410
- systemPrompt += ' Do not suggest anything outside these capabilities.';
411
- }
412
- }
413
- if (prompt) {
414
- systemPrompt += ` Additional guidance: "${prompt}"`;
425
+ const conversationContext = history
426
+ .filter(
427
+ (m) =>
428
+ (m.role === 'user' || m.role === 'assistant') &&
429
+ !m.toolCalls?.length &&
430
+ !m.thinking &&
431
+ !!m.content?.trim(),
432
+ )
433
+ .slice(-SUGGESTIONS_HISTORY_WINDOW)
434
+ .map((m) => `${m.role === 'user' ? 'User' : 'Assistant'}: ${m.content}`)
435
+ .join('\n');
436
+
437
+ userMessage =
438
+ `<conversation_history>\n${conversationContext}\n</conversation_history>\n\n` +
439
+ `The conversation above has ended. Do not continue it or respond as the assistant. ` +
440
+ `Generate exactly ${count} follow-up prompts the *user* might send next, phrased in first person as the user would write them. ` +
441
+ `The first ${Math.max(0, count - 1)} should be natural follow-ups to the last turn. ` +
442
+ `Do not invent specific names, IDs, or data values that do not appear in <conversation_history>.` +
443
+ capabilitiesBlock +
444
+ guidanceBlock +
445
+ `\n\nOutput format (strict):\n` +
446
+ `- Exactly ${count} lines.\n` +
447
+ `- One suggestion per line.\n` +
448
+ `- No numbering, bullets, markdown, emojis, code blocks, or quotes around the suggestion.\n` +
449
+ `- No preamble, headings, summary, or commentary before or after the list.`;
415
450
  }
416
- systemPrompt +=
417
- ' Output only the suggestions — one per line, no numbering, no bullets, no commentary, no preamble. Do not describe or explain the suggestions.';
418
-
419
- const conversationContext = history
420
- .filter(
421
- (m) =>
422
- (m.role === 'user' || m.role === 'assistant') &&
423
- !m.toolCalls?.length &&
424
- !m.thinking &&
425
- !!m.content?.trim(),
426
- )
427
- .slice(-SUGGESTIONS_HISTORY_WINDOW)
428
- .map((m) => `${m.role === 'user' ? 'User' : 'Assistant'}: ${m.content}`)
429
- .join('\n');
430
-
431
- const message = conversationContext || 'The conversation has not started yet.';
432
-
433
- const text = await this.aiProvider.prompt!(message, { systemPrompt });
434
- return text
435
- .split('\n')
436
- .map((s) => s.trim())
437
- .filter(Boolean);
451
+
452
+ const text = await this.aiProvider.prompt!(userMessage, { systemPrompt });
453
+
454
+ // Lenient parsing as a defensive backstop: even with the strict prompt,
455
+ // models occasionally slip in numbering, bullets, or surrounding markdown.
456
+ return (
457
+ text
458
+ .split('\n')
459
+ .map((s) => s.trim())
460
+ // strip leading bullets/numbers ("- ", "* ", "• ", "1. ", "1) ")
461
+ .map((s) => s.replace(/^([-*•]|\d+[.)])\s+/, ''))
462
+ // strip surrounding bold/italic markers
463
+ .map((s) => s.replace(/^[*_]{1,3}|[*_]{1,3}$/g, '').trim())
464
+ // drop empty lines, separators, and obvious preamble lines
465
+ .filter((s) => s.length > 0)
466
+ .filter((s) => !/^[-=]{2,}$/.test(s))
467
+ .filter((s) => !/^here (are|is) /i.test(s))
468
+ .filter((s) => !s.endsWith(':'))
469
+ .slice(0, count)
470
+ );
438
471
  }
439
472
 
440
473
  isBusy(): boolean {
@@ -232,6 +232,31 @@ export const styles = css`
232
232
  width: 100%;
233
233
  }
234
234
 
235
+ .session-stat {
236
+ animation: settings-slide-in 0.2s ease-out;
237
+ padding: calc(var(--design-unit) * 1.5px) calc(var(--design-unit) * 3px);
238
+ border-bottom: 1px solid var(--neutral-stroke-rest);
239
+ background-color: var(--neutral-layer-2);
240
+ display: flex;
241
+ justify-content: space-between;
242
+ align-items: baseline;
243
+ gap: calc(var(--design-unit) * 2px);
244
+ }
245
+
246
+ .session-stat-label {
247
+ font-size: 0.85em;
248
+ font-weight: 600;
249
+ color: var(--neutral-foreground-rest);
250
+ white-space: nowrap;
251
+ }
252
+
253
+ .session-stat-value {
254
+ font-size: 0.8em;
255
+ color: var(--neutral-foreground-hint, var(--neutral-foreground-rest));
256
+ opacity: 80%;
257
+ font-family: var(--monospace-font, ui-monospace, monospace);
258
+ }
259
+
235
260
  .splash-wrapper {
236
261
  position: absolute;
237
262
  inset: 0;
@@ -39,6 +39,9 @@ const HALO_SPEED_DEFAULT = 1.5;
39
39
  const HALO_SPEED_ORCHESTRATING = 0.4;
40
40
  const HALO_BORDER_SIZE_DEFAULT = 3;
41
41
 
42
+ /** Decimal places shown for the running session cost (USD). 4 ≈ $0.0001 resolution. */
43
+ const SESSION_COST_DECIMALS = 4;
44
+
42
45
  const animationOptions = Object.entries(ANIMATION_DEFS).map(([value, def]) => ({
43
46
  value,
44
47
  label: def.label,
@@ -495,6 +498,27 @@ ${(tc) => (tc.foldPath?.length ? `${tc.foldPath.join(' › ')} › ` : '')}<stro
495
498
  </div>
496
499
  `,
497
500
  )}
501
+ ${when(
502
+ (x) =>
503
+ x.settingsOpen && x.chatConfig.ui?.showActiveModel !== false && x.activeModel != null,
504
+ html<FoundationAiAssistant>`
505
+ <div class="session-stat" part="active-model">
506
+ <span class="session-stat-label">Model</span>
507
+ <span class="session-stat-value">${(x) => x.activeModel}</span>
508
+ </div>
509
+ `,
510
+ )}
511
+ ${when(
512
+ (x) => x.settingsOpen && x.chatConfig.ui?.showSessionCost !== false && x.sessionCostUsd > 0,
513
+ html<FoundationAiAssistant>`
514
+ <div class="session-stat" part="session-cost">
515
+ <span class="session-stat-label">Session cost</span>
516
+ <span class="session-stat-value">
517
+ $${(x) => x.sessionCostUsd.toFixed(SESSION_COST_DECIMALS)}
518
+ </span>
519
+ </div>
520
+ `,
521
+ )}
498
522
 
499
523
  <div class="splash-wrapper" part="splash">
500
524
  <slot name="splash"></slot>
package/src/main/main.ts CHANGED
@@ -90,14 +90,6 @@ const AGENT_PICKER_CLOSE_MS = 200;
90
90
  */
91
91
  const SETTINGS_CLOSE_MS = 200;
92
92
 
93
- const MODEL_CONTEXT_LIMITS: Record<string, number> = {
94
- 'gemini-2.5-flash': 1_048_576,
95
- 'gemini-2.5-flash-lite': 1_048_576,
96
- 'gpt-4o': 128_000,
97
- 'gpt-4o-mini': 128_000,
98
- 'gpt-4-turbo': 128_000,
99
- };
100
-
101
93
  // Register supporting components when the main component module is imported.
102
94
  avoidTreeShaking(
103
95
  AiChatMarkdown,
@@ -218,9 +210,26 @@ export class FoundationAiAssistant extends GenesisElement {
218
210
  // if they haven't moved on to something else on the page.
219
211
  if (prev === 'loading' && value !== 'loading') {
220
212
  this.maybeAutoFocusChatInput();
213
+ // Apply any agents swap deferred by the busy guard in `agentsChanged`.
214
+ // Host-side `agents` getters typically cache a stable reference between
215
+ // predicate changes, so FAST's property binding will not re-fire the
216
+ // setter on its own once the turn finishes — re-enter manually.
217
+ this.applyDeferredAgentsSwap();
221
218
  }
222
219
  }
223
220
 
221
+ /**
222
+ * Re-runs `agentsChanged` if the live `agents` array no longer matches the
223
+ * fingerprint of the currently installed driver. Used to apply swaps that
224
+ * landed during a turn (and were skipped by the `isBusy()` guard) once the
225
+ * driver returns to idle.
226
+ */
227
+ private applyDeferredAgentsSwap(): void {
228
+ if (!this.driver) return;
229
+ if (this.getAgentsKey(this.agents) === this._driverAgentsKey) return;
230
+ this.agentsChanged();
231
+ }
232
+
224
233
  /**
225
234
  * Focus the main chat input if the user is still engaged with the assistant.
226
235
  * Deferred to the next frame so any conditional re-render (e.g. unhiding the
@@ -373,6 +382,22 @@ export class FoundationAiAssistant extends GenesisElement {
373
382
  this._sessionRef?.actions.aiAssistant.setContextLimit(value);
374
383
  }
375
384
 
385
+ /** Aggregated USD cost across every chat turn in this session. */
386
+ get sessionCostUsd(): number {
387
+ return this._sessionRef?.store.aiAssistant.sessionCostUsd ?? 0;
388
+ }
389
+ set sessionCostUsd(value: number) {
390
+ this._sessionRef?.actions.aiAssistant.setSessionCostUsd(value);
391
+ }
392
+
393
+ /** Active model id resolved from the AIProvider, if exposed. */
394
+ get activeModel(): string | undefined {
395
+ return this._sessionRef?.store.aiAssistant.activeModel;
396
+ }
397
+ set activeModel(value: string | undefined) {
398
+ this._sessionRef?.actions.aiAssistant.setActiveModel(value);
399
+ }
400
+
376
401
  // ---- Transient UI state (stays as @observable on the component) ----
377
402
 
378
403
  private _suggestionsGeneration = 0;
@@ -532,11 +557,11 @@ export class FoundationAiAssistant extends GenesisElement {
532
557
  // destroy pending interactions in the existing driver.
533
558
  const newKey = this.getAgentsKey(this.agents);
534
559
  if (newKey === this._driverAgentsKey) return;
535
- this._driverAgentsKey = newKey;
536
- // Don't rebuild while the driver is busy it was created with the correct agents
537
- // and has live pending interactions. This prevents the collapse element (which
538
- // initially has no agents, then gets them assigned by its wrapper) from tearing
539
- // down a mid-flight driver and creating a fresh idle one.
560
+ // Don't rebuild while the driver is busy — pending interactions and the
561
+ // in-flight tool loop reference the captured agents array. The swap is
562
+ // re-attempted from the `state` setter on the loading→idle transition.
563
+ // `_driverAgentsKey` is updated only after the rebuild actually installs
564
+ // the new agents, so the deferred re-attempt still sees the mismatch.
540
565
  if (this.driver.isBusy()) return;
541
566
  const history = this.driver.getRawHistory?.() ?? [];
542
567
  const oldDriver = this.driver;
@@ -551,6 +576,7 @@ export class FoundationAiAssistant extends GenesisElement {
551
576
  this.driver = getOrCreateDriver(key, () => this.createDriver());
552
577
  this.wireDriver();
553
578
  if (history.length) this.driver.loadHistory([...history]);
579
+ this._driverAgentsKey = newKey;
554
580
  }
555
581
 
556
582
  /** Returns a stable fingerprint for an agents array based on agent names and tool handler keys. */
@@ -894,11 +920,10 @@ export class FoundationAiAssistant extends GenesisElement {
894
920
  private async resolveContextLimit(): Promise<void> {
895
921
  try {
896
922
  const status = await this.aiProvider.getStatus?.();
897
- if (status?.model) {
898
- this.contextLimit = MODEL_CONTEXT_LIMITS[status.model];
899
- }
923
+ this.contextLimit = status?.contextLimit;
924
+ this.activeModel = status?.model;
900
925
  } catch {
901
- // Non-fatal — context limit display simply won't show
926
+ // Non-fatal — context limit / model display simply won't show
902
927
  }
903
928
  }
904
929
 
@@ -947,6 +972,16 @@ export class FoundationAiAssistant extends GenesisElement {
947
972
  break;
948
973
  }
949
974
  }
975
+ // Recompute aggregated session cost from per-message `cost` fields. Recomputing
976
+ // (rather than incrementing on append) keeps the total correct under any
977
+ // mutation of the message list — including future clear-chat / re-render flows.
978
+ let runningCost = 0;
979
+ for (const m of this.messages) {
980
+ if (m.cost != null) runningCost += m.cost;
981
+ }
982
+ if (runningCost !== this.sessionCostUsd) {
983
+ this.sessionCostUsd = runningCost;
984
+ }
950
985
  // Publish halo-start whenever a new toolCalls message arrives.
951
986
  if (this.showHalo !== 'no' && this.enabledAnimations?.includes('halo')) {
952
987
  const last = this.messages[this.messages.length - 1];
@@ -1185,6 +1220,10 @@ export class FoundationAiAssistant extends GenesisElement {
1185
1220
  } catch (e) {
1186
1221
  activeDebugSnapshot = `<getDebugSnapshot threw: ${e instanceof Error ? e.message : String(e)}>`;
1187
1222
  }
1223
+ const contextUsagePercent =
1224
+ this.contextTokens != null && this.contextLimit != null && this.contextLimit > 0
1225
+ ? Math.round((this.contextTokens / this.contextLimit) * 100)
1226
+ : undefined;
1188
1227
  return {
1189
1228
  messages: this.driver?.getRawHistory?.() ?? this.messages,
1190
1229
  meta: {
@@ -1213,6 +1252,18 @@ export class FoundationAiAssistant extends GenesisElement {
1213
1252
  activePrimerHistory: this.activeAgent?.primerHistory,
1214
1253
  activeFoldStack:
1215
1254
  this.driver instanceof ChatDriver ? this.driver.getActiveFoldNames() : undefined,
1255
+ // Context window + cost snapshot. `sessionCostUsd` is the chat-scoped
1256
+ // total (per-message `cost` summed); the transport's lifetime cost is
1257
+ // not included here because it pools other call sites (suggestions,
1258
+ // criteria interpretation, etc.) and would be misleading next to the
1259
+ // chat-only token counts.
1260
+ context: {
1261
+ model: this.activeModel,
1262
+ contextTokens: this.contextTokens,
1263
+ contextLimit: this.contextLimit,
1264
+ contextUsagePercent,
1265
+ sessionCostUsd: this.sessionCostUsd,
1266
+ },
1216
1267
  // Snapshot captured fresh at log-export time — reflects state NOW, which
1217
1268
  // may have transitioned since the last LLM call.
1218
1269
  activeDebugSnapshot,
@@ -35,6 +35,10 @@ export interface AiAssistantSessionState {
35
35
  suggestionsState: SuggestionsState;
36
36
  contextTokens: number | undefined;
37
37
  contextLimit: number | undefined;
38
+ /** Aggregated USD cost across every chat turn in this session. */
39
+ sessionCostUsd: number;
40
+ /** Active model id (e.g. `claude-sonnet-4-6`), resolved on connect. */
41
+ activeModel: string | undefined;
38
42
  activeAgent: Omit<AgentConfig, 'toolHandlers'> | undefined;
39
43
  /**
40
44
  * Name of the agent the user has pinned via the picker. `null` means the
@@ -73,6 +77,8 @@ export const defaultSessionState: AiAssistantSessionState = {
73
77
  suggestionsState: { status: 'idle' },
74
78
  contextTokens: undefined,
75
79
  contextLimit: undefined,
80
+ sessionCostUsd: 0,
81
+ activeModel: undefined,
76
82
  activeAgent: undefined,
77
83
  pinnedAgentName: null,
78
84
  agentPickerOpen: false,
@@ -113,6 +119,12 @@ export const aiAssistantSlice = createSlice({
113
119
  setContextLimit(state, action: PayloadAction<number | undefined>) {
114
120
  state.contextLimit = action.payload;
115
121
  },
122
+ setSessionCostUsd(state, action: PayloadAction<number>) {
123
+ state.sessionCostUsd = action.payload;
124
+ },
125
+ setActiveModel(state, action: PayloadAction<string | undefined>) {
126
+ state.activeModel = action.payload;
127
+ },
116
128
  setActiveAgent(state, action: PayloadAction<Omit<AgentConfig, 'toolHandlers'> | undefined>) {
117
129
  state.activeAgent = action.payload;
118
130
  },