@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.
- package/dist/ai-assistant.api.json +61 -1
- package/dist/ai-assistant.d.ts +20 -0
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
- package/dist/dts/main/main.d.ts +20 -0
- package/dist/dts/main/main.d.ts.map +1 -1
- package/dist/dts/main/main.styles.d.ts.map +1 -1
- package/dist/dts/main/main.template.d.ts.map +1 -1
- package/dist/dts/state/ai-assistant-slice.d.ts +6 -0
- package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
- package/dist/dts/state/session-store.d.ts +2 -0
- package/dist/dts/state/session-store.d.ts.map +1 -1
- package/dist/esm/components/chat-driver/chat-driver.js +61 -39
- package/dist/esm/main/main.js +71 -16
- package/dist/esm/main/main.styles.js +25 -0
- package/dist/esm/main/main.template.js +16 -0
- package/dist/esm/state/ai-assistant-slice.js +8 -0
- package/package.json +16 -16
- package/src/components/chat-driver/chat-driver.ts +73 -40
- package/src/main/main.styles.ts +25 -0
- package/src/main/main.template.ts +24 -0
- package/src/main/main.ts +68 -17
- package/src/state/ai-assistant-slice.ts +12 -0
|
@@ -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)",
|
package/dist/ai-assistant.d.ts
CHANGED
|
@@ -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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"}
|
package/dist/dts/main/main.d.ts
CHANGED
|
@@ -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":"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;
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/main/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.styles.d.ts","sourceRoot":"","sources":["../../../src/main/main.styles.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,MAAM,
|
|
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;
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
-
.
|
|
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() {
|
package/dist/esm/main/main.js
CHANGED
|
@@ -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
|
-
|
|
459
|
-
//
|
|
460
|
-
//
|
|
461
|
-
//
|
|
462
|
-
//
|
|
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
|
-
|
|
798
|
-
|
|
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.
|
|
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.
|
|
68
|
-
"@genesislcap/genx": "14.
|
|
69
|
-
"@genesislcap/rollup-builder": "14.
|
|
70
|
-
"@genesislcap/ts-builder": "14.
|
|
71
|
-
"@genesislcap/uvu-playwright-builder": "14.
|
|
72
|
-
"@genesislcap/vite-builder": "14.
|
|
73
|
-
"@genesislcap/webpack-builder": "14.
|
|
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.
|
|
79
|
-
"@genesislcap/foundation-logger": "14.
|
|
80
|
-
"@genesislcap/foundation-redux": "14.
|
|
81
|
-
"@genesislcap/foundation-ui": "14.
|
|
82
|
-
"@genesislcap/foundation-utils": "14.
|
|
83
|
-
"@genesislcap/rapid-design-system": "14.
|
|
84
|
-
"@genesislcap/web-core": "14.
|
|
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": "
|
|
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
|
-
|
|
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
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
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
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
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 {
|
package/src/main/main.styles.ts
CHANGED
|
@@ -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
|
-
|
|
536
|
-
//
|
|
537
|
-
//
|
|
538
|
-
//
|
|
539
|
-
//
|
|
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
|
-
|
|
898
|
-
|
|
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
|
},
|