@genesislcap/ai-assistant 15.7.3-alpha-e7d4aa5.0 → 15.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-assistant.api.json +191 -1
- package/dist/ai-assistant.d.ts +155 -1
- package/dist/custom-elements.json +114 -2
- package/dist/dts/components/settings-modal/settings-modal.styles.d.ts.map +1 -1
- package/dist/dts/components/settings-modal/settings-modal.styles.test.d.ts +2 -0
- package/dist/dts/components/settings-modal/settings-modal.styles.test.d.ts.map +1 -0
- package/dist/dts/components/settings-modal/settings-modal.template.d.ts +22 -0
- package/dist/dts/components/settings-modal/settings-modal.template.d.ts.map +1 -1
- package/dist/dts/components/settings-modal/settings-modal.template.test.d.ts +2 -0
- package/dist/dts/components/settings-modal/settings-modal.template.test.d.ts.map +1 -0
- package/dist/dts/main/budget-meter.test.d.ts +2 -0
- package/dist/dts/main/budget-meter.test.d.ts.map +1 -0
- package/dist/dts/main/main.d.ts +113 -2
- package/dist/dts/main/main.d.ts.map +1 -1
- package/dist/dts/main/main.types.d.ts +25 -0
- package/dist/dts/main/main.types.d.ts.map +1 -1
- package/dist/dts/state/ai-assistant-slice.d.ts +47 -0
- package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
- package/dist/dts/state/session-store.d.ts +4 -0
- package/dist/dts/state/session-store.d.ts.map +1 -1
- package/dist/dts/utils/format-usd.d.ts +24 -0
- package/dist/dts/utils/format-usd.d.ts.map +1 -0
- package/dist/esm/components/settings-modal/settings-modal.styles.js +33 -3
- package/dist/esm/components/settings-modal/settings-modal.styles.test.js +80 -0
- package/dist/esm/components/settings-modal/settings-modal.template.js +64 -14
- package/dist/esm/components/settings-modal/settings-modal.template.test.js +91 -0
- package/dist/esm/main/budget-meter.test.js +317 -0
- package/dist/esm/main/main.js +189 -3
- package/dist/esm/state/ai-assistant-slice.js +38 -0
- package/dist/esm/utils/format-usd.js +23 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/migration-GENC-1464.md +63 -0
- package/docs/styling.md +23 -0
- package/package.json +17 -17
- package/src/components/settings-modal/settings-modal.styles.test.ts +94 -0
- package/src/components/settings-modal/settings-modal.styles.ts +33 -3
- package/src/components/settings-modal/settings-modal.template.test.ts +124 -0
- package/src/components/settings-modal/settings-modal.template.ts +82 -13
- package/src/main/budget-meter.test.ts +427 -0
- package/src/main/main.ts +198 -3
- package/src/main/main.types.ts +26 -0
- package/src/state/ai-assistant-slice.ts +74 -0
- package/src/utils/format-usd.ts +26 -0
package/src/main/main.types.ts
CHANGED
|
@@ -93,6 +93,32 @@ export const AiAssistantEvent = {
|
|
|
93
93
|
*/
|
|
94
94
|
export type AiAssistantEvent = (typeof AiAssistantEvent)[keyof typeof AiAssistantEvent];
|
|
95
95
|
|
|
96
|
+
/**
|
|
97
|
+
* One rendered row of the settings-modal budget meter (GENC-1464) — a vendor
|
|
98
|
+
* that currently has budget figures, pre-formatted so the template stays a pure
|
|
99
|
+
* binding layer (and so tests can pin the exact text a user reads).
|
|
100
|
+
*
|
|
101
|
+
* @beta
|
|
102
|
+
*/
|
|
103
|
+
export interface SettingsBudgetRow {
|
|
104
|
+
/** The vendor the row describes (an `AIProviderType` member). */
|
|
105
|
+
vendor: string;
|
|
106
|
+
/** Display name from `VENDOR_LABELS`, e.g. `Anthropic`. */
|
|
107
|
+
label: string;
|
|
108
|
+
/**
|
|
109
|
+
* The real figures — `$45.00 / $50.00 (90%)`. The percentage is NOT clamped:
|
|
110
|
+
* spend can genuinely overshoot the cap (the last allowed call may cross it),
|
|
111
|
+
* and the text tells the truth about it.
|
|
112
|
+
*/
|
|
113
|
+
figures: string;
|
|
114
|
+
/**
|
|
115
|
+
* The bar's value, clamped to `0..100` — a progress bar past its end renders
|
|
116
|
+
* nonsense, so only the bar clamps (mirroring the context-usage indicator's
|
|
117
|
+
* `Math.min(100, …)`).
|
|
118
|
+
*/
|
|
119
|
+
barValue: number;
|
|
120
|
+
}
|
|
121
|
+
|
|
96
122
|
/**
|
|
97
123
|
* State of the chat suggestions feature.
|
|
98
124
|
*
|
|
@@ -27,6 +27,23 @@ export interface InputOverride {
|
|
|
27
27
|
mode: ChatInputDuringExecutionMode;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* One vendor's AI-spend figures, as fed by the host from the budget endpoint
|
|
32
|
+
* (GENC-1464 — the settings-modal budget meter).
|
|
33
|
+
*
|
|
34
|
+
* Dollars, not a percentage: the meter's text shows the real figures (spend CAN
|
|
35
|
+
* exceed the cap — the last allowed call may overshoot it), and only the bar
|
|
36
|
+
* clamps. Storing a pre-computed percentage would destroy the overshoot.
|
|
37
|
+
*
|
|
38
|
+
* @beta
|
|
39
|
+
*/
|
|
40
|
+
export interface VendorBudgetFigures {
|
|
41
|
+
/** The vendor's budget cap in USD. Finite and `>= 0`. */
|
|
42
|
+
budgetUsd: number;
|
|
43
|
+
/** Metered spend against that cap in USD. Finite and `>= 0`; may exceed the cap. */
|
|
44
|
+
spentUsd: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
30
47
|
/**
|
|
31
48
|
* Shape of a single AI assistant session's serializable state.
|
|
32
49
|
*
|
|
@@ -182,6 +199,20 @@ export interface AiAssistantSessionState {
|
|
|
182
199
|
* copy composed from the vendor's display name.
|
|
183
200
|
*/
|
|
184
201
|
blockedVendorReasons: Partial<Record<AIProviderType, string>>;
|
|
202
|
+
/**
|
|
203
|
+
* Per-vendor AI-spend figures for the settings-modal budget meter (GENC-1464),
|
|
204
|
+
* fed by the host via the element's `setVendorBudget`. A vendor with no entry
|
|
205
|
+
* renders no meter row — which is also how "unlimited" is expressed: the host
|
|
206
|
+
* simply never feeds a vendor the server marks unlimited.
|
|
207
|
+
*
|
|
208
|
+
* NOT persisted to the session snapshot, deliberately. The server is
|
|
209
|
+
* authoritative for spend and the host re-feeds on boot (and after each turn),
|
|
210
|
+
* so a persisted copy could only ever show stale dollars across a reload —
|
|
211
|
+
* wrong money is worse than a beat of no meter. The snapshot assembler
|
|
212
|
+
* (`session-snapshot.ts`) builds from an explicit field list, so absence is
|
|
213
|
+
* structural, not an accident of serialization.
|
|
214
|
+
*/
|
|
215
|
+
vendorBudgets: Partial<Record<AIProviderType, VendorBudgetFigures>>;
|
|
185
216
|
/** Draft text in the input box — preserved across pop-in/pop-out cycles. */
|
|
186
217
|
inputValue: string;
|
|
187
218
|
/** Live trace from a currently-executing sub-agent. Cleared on sub-agent-stop. */
|
|
@@ -249,6 +280,7 @@ export function createDefaultSessionState(): AiAssistantSessionState {
|
|
|
249
280
|
blockedVendors: [],
|
|
250
281
|
sweptVendors: [],
|
|
251
282
|
blockedVendorReasons: {},
|
|
283
|
+
vendorBudgets: {},
|
|
252
284
|
inputValue: '',
|
|
253
285
|
liveSubAgentTrace: [],
|
|
254
286
|
liveSubAgentName: null,
|
|
@@ -427,6 +459,41 @@ export const aiAssistantSlice = createSlice({
|
|
|
427
459
|
delete state.blockedVendorReasons[vendor];
|
|
428
460
|
}
|
|
429
461
|
},
|
|
462
|
+
/**
|
|
463
|
+
* Store (or clear, with `null`) one vendor's budget figures for the meter.
|
|
464
|
+
*
|
|
465
|
+
* Validation lives at the element boundary (`setVendorBudget` on the
|
|
466
|
+
* element), not here — the reducer is the storage layer and trusts its one
|
|
467
|
+
* caller, exactly as `setVendorBlocked` above trusts its.
|
|
468
|
+
*
|
|
469
|
+
* Idempotent by VALUE, not just by effect: re-feeding the figures a vendor
|
|
470
|
+
* already holds leaves the stored object untouched. The documented feed
|
|
471
|
+
* re-runs after every turn, so without this every turn would publish a new
|
|
472
|
+
* store reference for the same dollars and re-render a meter that has not
|
|
473
|
+
* changed.
|
|
474
|
+
*/
|
|
475
|
+
setVendorBudget(
|
|
476
|
+
state,
|
|
477
|
+
action: PayloadAction<{ vendor: AIProviderType; figures: VendorBudgetFigures | null }>,
|
|
478
|
+
) {
|
|
479
|
+
const { vendor, figures } = action.payload;
|
|
480
|
+
if (figures === null) {
|
|
481
|
+
delete state.vendorBudgets[vendor];
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const existing = state.vendorBudgets[vendor];
|
|
485
|
+
if (
|
|
486
|
+
existing &&
|
|
487
|
+
existing.budgetUsd === figures.budgetUsd &&
|
|
488
|
+
existing.spentUsd === figures.spentUsd
|
|
489
|
+
) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
// A fresh object rather than the caller's: the store may freeze what it
|
|
493
|
+
// holds, and adopting the host's object would freeze state the host still
|
|
494
|
+
// owns (and let later host mutations bypass the store).
|
|
495
|
+
state.vendorBudgets[vendor] = { budgetUsd: figures.budgetUsd, spentUsd: figures.spentUsd };
|
|
496
|
+
},
|
|
430
497
|
setInputValue(state, action: PayloadAction<string>) {
|
|
431
498
|
state.inputValue = action.payload;
|
|
432
499
|
},
|
|
@@ -522,6 +589,13 @@ export const aiAssistantSlice = createSlice({
|
|
|
522
589
|
blockedVendors: state.blockedVendors,
|
|
523
590
|
sweptVendors: state.sweptVendors,
|
|
524
591
|
blockedVendorReasons: state.blockedVendorReasons,
|
|
592
|
+
// Category 2, beside the blocked latch: the budget figures are a fact
|
|
593
|
+
// about the USER'S DEPLOYMENT (what the server meters), not about this
|
|
594
|
+
// conversation — "Clear" refills no budget, so wiping them would blank
|
|
595
|
+
// the meter until the host's next re-feed while the dollars are
|
|
596
|
+
// unchanged. Opposite side from `contextTokens`, which IS conversation
|
|
597
|
+
// state (a new chat genuinely has an empty context window).
|
|
598
|
+
vendorBudgets: state.vendorBudgets,
|
|
525
599
|
} satisfies Partial<AiAssistantSessionState>;
|
|
526
600
|
Object.assign(state, createDefaultSessionState(), preservedAcrossReset);
|
|
527
601
|
},
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE place this package renders a USD amount as text.
|
|
3
|
+
*
|
|
4
|
+
* Extracted (GENC-1464 budget meter) from the ad-hoc `.toFixed(2)` call sites
|
|
5
|
+
* that had grown in `formatBlockedReason` and the settings modal's cost blocks,
|
|
6
|
+
* so the blocked banner, the session-cost figures and the budget meter cannot
|
|
7
|
+
* drift to different precisions. Two decimals always — money columns jitter
|
|
8
|
+
* when "$5.1" sits above "$5.10".
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Decimal places for every USD figure this package renders. */
|
|
14
|
+
export const USD_DECIMALS = 2;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The bare amount, no currency sign — `(12.3) => "12.30"`.
|
|
18
|
+
*
|
|
19
|
+
* Exists for the settings modal's cost blocks, where the `$` is a separately
|
|
20
|
+
* styled `<span class="prefix">` and folding it into the text would change the
|
|
21
|
+
* DOM those styles target.
|
|
22
|
+
*/
|
|
23
|
+
export const formatUsdAmount = (value: number): string => value.toFixed(USD_DECIMALS);
|
|
24
|
+
|
|
25
|
+
/** A signed USD figure — `(12.3) => "$12.30"`. */
|
|
26
|
+
export const formatUsd = (value: number): string => `$${formatUsdAmount(value)}`;
|