@genesislcap/ai-assistant 15.23.3 → 15.24.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 +419 -50
- package/dist/ai-assistant.d.ts +217 -683
- package/dist/chat-driver.cjs.map +1 -1
- package/dist/chat-driver.mjs.map +1 -1
- package/dist/custom-elements.json +310 -609
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts +16 -0
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts.map +1 -1
- package/dist/dts/components/settings-modal/index.d.ts +1 -0
- package/dist/dts/components/settings-modal/index.d.ts.map +1 -1
- package/dist/dts/components/settings-modal/settings-modal.d.ts +215 -0
- package/dist/dts/components/settings-modal/settings-modal.d.ts.map +1 -0
- package/dist/dts/components/settings-modal/settings-modal.template.d.ts.map +1 -1
- package/dist/dts/main/attachment-controller.d.ts +66 -0
- package/dist/dts/main/attachment-controller.d.ts.map +1 -0
- package/dist/dts/main/budget-controller.d.ts +368 -0
- package/dist/dts/main/budget-controller.d.ts.map +1 -0
- package/dist/dts/main/composer-menu-controller.d.ts +113 -0
- package/dist/dts/main/composer-menu-controller.d.ts.map +1 -0
- package/dist/dts/main/composer-resize-controller.d.ts +80 -0
- package/dist/dts/main/composer-resize-controller.d.ts.map +1 -0
- package/dist/dts/main/context-gate-controller.d.ts +197 -0
- package/dist/dts/main/context-gate-controller.d.ts.map +1 -0
- package/dist/dts/main/cost-ledger-controller.d.ts +228 -0
- package/dist/dts/main/cost-ledger-controller.d.ts.map +1 -0
- package/dist/dts/main/main.d.ts +201 -722
- 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/main/meta-snapshot.d.ts +50 -0
- package/dist/dts/main/meta-snapshot.d.ts.map +1 -0
- package/dist/dts/state/persistence/session-persister.d.ts.map +1 -1
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +18 -0
- package/dist/esm/components/settings-modal/index.js +1 -0
- package/dist/esm/components/settings-modal/settings-modal.js +436 -0
- package/dist/esm/components/settings-modal/settings-modal.template.js +15 -4
- package/dist/esm/main/attachment-controller.js +254 -0
- package/dist/esm/main/budget-controller.js +745 -0
- package/dist/esm/main/composer-menu-controller.js +234 -0
- package/dist/esm/main/composer-resize-controller.js +119 -0
- package/dist/esm/main/context-gate-controller.js +289 -0
- package/dist/esm/main/cost-ledger-controller.js +498 -0
- package/dist/esm/main/main.js +501 -2268
- package/dist/esm/main/meta-snapshot.js +108 -0
- package/dist/esm/state/persistence/session-persister.js +5 -4
- package/docs/migration-GENC-1580.md +209 -0
- package/package.json +16 -16
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import { type AIProviderRegistry, type AIProviderRegistryStatusEntry, type AIProviderType, type ChatConfig, type ChatDriverResult, type TurnFailureReason } from '@genesislcap/foundation-ai';
|
|
2
|
+
import type { VendorBudgetFigures } from '../state/ai-assistant-slice';
|
|
3
|
+
import type { SessionStoreReturn } from '../state/session-store';
|
|
4
|
+
import type { SettingsBudgetRow } from './main.types';
|
|
5
|
+
/**
|
|
6
|
+
* Banner copy built from the figures a 402 actually reported, or `undefined`
|
|
7
|
+
* when the proxy sent none.
|
|
8
|
+
*
|
|
9
|
+
* `undefined` is the meaningful return, not a fallback: paired with the
|
|
10
|
+
* slice's "a re-latch without a reason keeps the existing explanation" rule, it
|
|
11
|
+
* makes a figureless driver latch leave a host-supplied reason intact rather
|
|
12
|
+
* than blanking it back to the default at the exact moment the wall is hit.
|
|
13
|
+
*
|
|
14
|
+
* Exported for the unit test that pins the formatting; not part of the element
|
|
15
|
+
* API.
|
|
16
|
+
*
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatBlockedReason(budget?: Partial<Extract<ChatDriverResult, {
|
|
20
|
+
reason: 'done';
|
|
21
|
+
}>['budget']>, vendor?: AIProviderType): string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Whole-number percentage of a budget consumed, for the meter (GENC-1464).
|
|
24
|
+
*
|
|
25
|
+
* Deliberately unclamped — spend can genuinely overshoot the cap (the last
|
|
26
|
+
* allowed call may cross it), and the meter's TEXT shows the truth; only the
|
|
27
|
+
* bar clamps, at the render site. The one special case is a `$0` cap, which the
|
|
28
|
+
* platform treats as "no spend allowed" (not "unlimited"): it has no headroom
|
|
29
|
+
* by definition, so the meter reads full rather than dividing by zero.
|
|
30
|
+
*
|
|
31
|
+
* Exported for the unit test that pins the arithmetic; not element API.
|
|
32
|
+
*
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
export declare function budgetPercentOf(figures: VendorBudgetFigures): number;
|
|
36
|
+
/**
|
|
37
|
+
* What the controller needs from its host.
|
|
38
|
+
*
|
|
39
|
+
* `sessionRef` is a deliberate departure from the other controllers, which take
|
|
40
|
+
* one value callback per field. The budget surface is a projection of the redux
|
|
41
|
+
* slice: nine of its members are thin reads of `store.aiAssistant.*` and four are
|
|
42
|
+
* action dispatches, so threading a callback per field would be ten pieces of
|
|
43
|
+
* plumbing that still hard-code the slice shape in their signatures — coupling
|
|
44
|
+
* without isolation. It is also required rather than merely tidier:
|
|
45
|
+
* {@link BudgetController.latchFrom} writes through a session ref *captured at
|
|
46
|
+
* call time*, so a teardown race cannot land a wall in a new session's store, and
|
|
47
|
+
* a value callback cannot express that.
|
|
48
|
+
*/
|
|
49
|
+
export interface BudgetDeps {
|
|
50
|
+
/** The live session store. Observable on the element, so reads here stay tracked. */
|
|
51
|
+
sessionRef: () => SessionStoreReturn | undefined;
|
|
52
|
+
providerStatuses: () => AIProviderRegistryStatusEntry[];
|
|
53
|
+
/** Needed to tell a chat-capable provider from a status-only one — see `reachableVendors`. */
|
|
54
|
+
providerRegistry: () => AIProviderRegistry | undefined;
|
|
55
|
+
/** For `ui.showBudgetUsage` only. */
|
|
56
|
+
chatConfig: () => ChatConfig;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The AI-spend budget: which vendors are walled, whether that locks the composer,
|
|
60
|
+
* the banner copy that explains it, and the settings-modal meter (GENC-1464).
|
|
61
|
+
*
|
|
62
|
+
* Two invariants run through the whole file:
|
|
63
|
+
*
|
|
64
|
+
* - **Walls latch; locking derives.** A wall is one-way per vendor and nothing in
|
|
65
|
+
* here clears it, because nothing the user can do refills a budget. But
|
|
66
|
+
* {@link BudgetController.blocked} is *derived* from "is every reachable vendor
|
|
67
|
+
* walled", so a host swapping its registry to a vendor with headroom recovers
|
|
68
|
+
* the composer without un-latching anything.
|
|
69
|
+
* - **The banner may only name vendors the user could actually be routed to.**
|
|
70
|
+
* Hence {@link BudgetController.relevantBlockedVendors}, and hence the
|
|
71
|
+
* provenance mark the sweep writes.
|
|
72
|
+
*
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
export declare class BudgetController {
|
|
76
|
+
private readonly deps;
|
|
77
|
+
/**
|
|
78
|
+
* When budget figures last arrived — from the host's
|
|
79
|
+
* {@link BudgetController.setVendorBudget} or the wall latch's own feed — as
|
|
80
|
+
* epoch ms; `null` until the first feed.
|
|
81
|
+
*
|
|
82
|
+
* ELEMENT state, not slice state, on purpose: the reducer is idempotent by
|
|
83
|
+
* value (an unchanged re-feed must not re-render the meter rows), but "when
|
|
84
|
+
* was this fetched" must move on every feed, changed figures or not — a
|
|
85
|
+
* refresh that confirms the same dollars is still a refresh. Only the
|
|
86
|
+
* toolbar label observes this, so a stamp re-renders one span, not the rows.
|
|
87
|
+
*/
|
|
88
|
+
meterLastFedAt: number | null;
|
|
89
|
+
/**
|
|
90
|
+
* One warning per element for garbage fed to
|
|
91
|
+
* {@link BudgetController.setVendorBudget}. Once, not per call, because the
|
|
92
|
+
* documented feed re-runs after every turn — a host bug would otherwise repeat
|
|
93
|
+
* the same warning on every send for the life of the page.
|
|
94
|
+
*
|
|
95
|
+
* Not observable: nothing renders it.
|
|
96
|
+
*/
|
|
97
|
+
private warningIssued;
|
|
98
|
+
constructor(deps: BudgetDeps);
|
|
99
|
+
private get slice();
|
|
100
|
+
/**
|
|
101
|
+
* Whether the assistant is blocked by a backend condition and cannot send.
|
|
102
|
+
*
|
|
103
|
+
* Derived, not stored — see the class note. Unknown reachability (statuses not
|
|
104
|
+
* loaded yet, or providers that report no status) fails SAFE: any wall blocks
|
|
105
|
+
* everything, and that needs no clause of its own, because `every` on the empty
|
|
106
|
+
* set is vacuously true.
|
|
107
|
+
*/
|
|
108
|
+
get blocked(): boolean;
|
|
109
|
+
set blocked(value: boolean);
|
|
110
|
+
/**
|
|
111
|
+
* The distinct vendors the registry can currently reach, from the provider
|
|
112
|
+
* statuses the element loads on connect and refreshes on every
|
|
113
|
+
* observable-registry change.
|
|
114
|
+
*
|
|
115
|
+
* This is the answer to "which vendor would the next turn use" — a question
|
|
116
|
+
* that has **no** correct answer and deliberately gets no API. The provider is
|
|
117
|
+
* resolved per turn AND per agent: `activeProviderInput` may be an async
|
|
118
|
+
* function of the turn's context, an orchestrated turn picks its agent with an
|
|
119
|
+
* LLM `classify()` call, and sub-agents resolve their own providers. Any
|
|
120
|
+
* pre-turn "peek" would therefore be a guess that is wrong precisely on the
|
|
121
|
+
* multi-agent hosts per-vendor budgets exist for.
|
|
122
|
+
*
|
|
123
|
+
* Asking instead which vendors are REACHABLE is answerable, synchronous, and
|
|
124
|
+
* free — and it is enough: the composer must stay live while any reachable
|
|
125
|
+
* vendor has headroom, and must lock when none does. It also makes
|
|
126
|
+
* vendor-switch recovery a derivation rather than a mutation.
|
|
127
|
+
*/
|
|
128
|
+
get reachableVendors(): readonly AIProviderType[];
|
|
129
|
+
/** Vendors currently walled, in the order they were walled. */
|
|
130
|
+
get blockedVendors(): readonly AIProviderType[];
|
|
131
|
+
/** Whether this specific vendor's budget is walled, regardless of the others. */
|
|
132
|
+
isVendorBlocked(vendor: AIProviderType): boolean;
|
|
133
|
+
/** Whether this vendor's wall came from the sweep alone — see the slice's `sweptVendors`. */
|
|
134
|
+
private isVendorSwept;
|
|
135
|
+
/**
|
|
136
|
+
* Wall (or release) one vendor's budget, optionally with banner copy for it.
|
|
137
|
+
*
|
|
138
|
+
* `'none'` is rejected with a warning rather than accepted: it is the "no
|
|
139
|
+
* provider configured" sentinel, not a vendor. Latching it would put the raw
|
|
140
|
+
* sentinel in the banner ("none's AI usage limit is reached") and could never be
|
|
141
|
+
* undone by derivation, because `'none'` never appears in
|
|
142
|
+
* {@link BudgetController.reachableVendors} — so `blocked` could never become
|
|
143
|
+
* derivable from it either.
|
|
144
|
+
*/
|
|
145
|
+
setVendorBlocked(vendor: AIProviderType, blocked: boolean, reason?: string | null): void;
|
|
146
|
+
private warnOnce;
|
|
147
|
+
/**
|
|
148
|
+
* Feed (or clear) one vendor's AI-spend figures for the meter. Returns `false`
|
|
149
|
+
* — warning once, not per call — for a non-budgeted vendor or a figure that is
|
|
150
|
+
* not a finite number `>= 0`, and also for "no store yet", which is a lifecycle
|
|
151
|
+
* window rather than bad input and so is deliberately not warned about.
|
|
152
|
+
*
|
|
153
|
+
* The full host-facing contract, including the intended `GET /api/budget` feed,
|
|
154
|
+
* is on the element's `setVendorBudget`.
|
|
155
|
+
*/
|
|
156
|
+
setVendorBudget(vendor: string, figures: {
|
|
157
|
+
budgetUsd: number;
|
|
158
|
+
spentUsd: number;
|
|
159
|
+
} | null): boolean;
|
|
160
|
+
/** "Updated HH:MM:SS" for the meter toolbar, or `undefined` before any feed. */
|
|
161
|
+
get updatedLabel(): string | undefined;
|
|
162
|
+
/**
|
|
163
|
+
* The walled vendors the user can still be routed to — i.e.
|
|
164
|
+
* {@link BudgetController.blockedVendors} narrowed to the reachable set, which
|
|
165
|
+
* is the only set the banner may name.
|
|
166
|
+
*
|
|
167
|
+
* A wall the registry can no longer reach is not news: it cannot be hit, and
|
|
168
|
+
* naming it puts a vendor in front of the user that is not theirs. The concrete
|
|
169
|
+
* failure this exists to stop: a host ships Anthropic-only, Anthropic walls, the
|
|
170
|
+
* host swaps its registry to Gemini, Gemini walls — and the banner reads "AI
|
|
171
|
+
* usage limits are reached for Anthropic and Gemini" to a user who has never
|
|
172
|
+
* had an Anthropic key. The spurious second name also flips the copy onto the
|
|
173
|
+
* plural branch, so even the closing sentence is wrong.
|
|
174
|
+
*
|
|
175
|
+
* When nothing is reachable YET (the statuses are still loading — the exact
|
|
176
|
+
* window the pre-flight and the cross-tab bus latch into), the fallback keeps
|
|
177
|
+
* every wall for LOCKING (`blocked` still derives true) but names only the
|
|
178
|
+
* vendors walled by a REFUSAL, dropping the ones the `otherVendorAvailable`
|
|
179
|
+
* sweep added. A refusal is a fact about a vendor this user just used; a sweep
|
|
180
|
+
* entry is the proxy's headroom verdict about a vendor the host may not even
|
|
181
|
+
* ship — naming it here reproduced the exact failure above from the other
|
|
182
|
+
* direction ("Gemini's AI usage limit is reached" to an Anthropic-only user),
|
|
183
|
+
* and flipped the copy onto the plural branch with it. Self-corrects when the
|
|
184
|
+
* statuses land: from then on reachability, not provenance, decides.
|
|
185
|
+
*/
|
|
186
|
+
get relevantBlockedVendors(): readonly AIProviderType[];
|
|
187
|
+
/**
|
|
188
|
+
* Whether the blocked banner has anything to say — a vendor-agnostic block, or
|
|
189
|
+
* a partial wall that the NEXT send would actually hit.
|
|
190
|
+
*
|
|
191
|
+
* Partial exhaustion is announced only while the ACTIVE vendor (the registry
|
|
192
|
+
* default the next send resolves to) is among the walled ones. A user who has
|
|
193
|
+
* switched to a vendor with headroom has already acted on the advice —
|
|
194
|
+
* keeping the banner up past that point nagged about a vendor they just left
|
|
195
|
+
* (GENC-1464 tester feedback), while switching BACK to the walled vendor
|
|
196
|
+
* brings the banner straight back. Two conservative fallbacks keep it
|
|
197
|
+
* fail-informative: while the statuses are still loading the active vendor is
|
|
198
|
+
* unknowable, so any reachable-and-walled vendor still announces; and a
|
|
199
|
+
* vendor-agnostic block announces always, exactly as before.
|
|
200
|
+
*/
|
|
201
|
+
get bannerVisible(): boolean;
|
|
202
|
+
/**
|
|
203
|
+
* Whether a suggestions fetch would hit a wall.
|
|
204
|
+
*
|
|
205
|
+
* Unlike a chat turn, this one CAN be resolved exactly: both suggestion paths
|
|
206
|
+
* go to the registry **default** and never to a per-agent override
|
|
207
|
+
* (`ChatDriver.getSuggestions` calls `providerRegistry.default()`, and
|
|
208
|
+
* `OrchestratingDriver.getSuggestions` just delegates to it). So the vendor a
|
|
209
|
+
* suggestions call would use is knowable, and this is the one place in the
|
|
210
|
+
* feature where that is true.
|
|
211
|
+
*/
|
|
212
|
+
get suggestionsBlocked(): boolean;
|
|
213
|
+
/**
|
|
214
|
+
* The vendor the NEXT send resolves to — the registry default's provider, as
|
|
215
|
+
* reported through `providerStatuses`. `undefined` while the statuses are
|
|
216
|
+
* still loading (or when the default reports the `'none'` sentinel), which
|
|
217
|
+
* every consumer treats conservatively.
|
|
218
|
+
*/
|
|
219
|
+
private get activeVendor();
|
|
220
|
+
/** Host override for the banner copy, or `null` for the element's default. */
|
|
221
|
+
get blockedReason(): string | null;
|
|
222
|
+
set blockedReason(value: string | null);
|
|
223
|
+
/**
|
|
224
|
+
* Block or unblock the assistant, optionally with custom banner copy.
|
|
225
|
+
*
|
|
226
|
+
* Blocking writes the **vendor-agnostic** block — what a host with one budget
|
|
227
|
+
* pot means — and does not populate {@link BudgetController.blockedVendors}.
|
|
228
|
+
* Unblocking clears the per-vendor walls as well, so a host asserting "the wall
|
|
229
|
+
* is gone" after its own pre-flight cannot be silently overruled by a driver
|
|
230
|
+
* latch it never saw.
|
|
231
|
+
*/
|
|
232
|
+
setBlocked(blocked: boolean, reason?: string | null): void;
|
|
233
|
+
/**
|
|
234
|
+
* Latch the backend block off a turn outcome. The single decision point for
|
|
235
|
+
* both latch sites (the `tool-loop-end` bus subscription and `send()`'s
|
|
236
|
+
* return-value check), so the rule cannot diverge between them.
|
|
237
|
+
*
|
|
238
|
+
* Idempotent and one-way **per vendor**: it never unblocks, and it never
|
|
239
|
+
* re-writes an existing wall. That guard is load-bearing, not just an
|
|
240
|
+
* optimisation — the bus fires from the driver's `finally`, i.e. BEFORE
|
|
241
|
+
* `sendMessage()` resolves, so a host subscribed to `tool-loop-end` (what the
|
|
242
|
+
* migration guide's Option C recommends) sets its own detailed reason and the
|
|
243
|
+
* return-value latch would otherwise land a moment later and blank it.
|
|
244
|
+
*
|
|
245
|
+
* The guard being per-vendor rather than global is the whole difference. A
|
|
246
|
+
* single global "already blocked, do nothing" would swallow a second vendor's
|
|
247
|
+
* wall entirely.
|
|
248
|
+
*
|
|
249
|
+
* **Vendor attribution, in precedence order:**
|
|
250
|
+
*
|
|
251
|
+
* 1. `budget.vendorLabel` — stamped by the transport that was actually refused,
|
|
252
|
+
* so it is the only source that cannot be a guess. A label the element does
|
|
253
|
+
* not recognise leaves it unclaimed by any vendor.
|
|
254
|
+
* 2. `budget.vendor` — which the driver resolved from the label where it could,
|
|
255
|
+
* and otherwise from the proxy's own `vendor` field on the 402. It is
|
|
256
|
+
* therefore NOT simply `vendorLabel` normalised, and the two can disagree.
|
|
257
|
+
* 3. `vendorHint` — the bus detail's top-level vendor, i.e. the driver's
|
|
258
|
+
* best guess at the turn's vendor, which may be the previous turn's vendor
|
|
259
|
+
* or nothing at all.
|
|
260
|
+
*
|
|
261
|
+
* A wall that names no recognised vendor falls back to the vendor-agnostic
|
|
262
|
+
* block — fail-safe, and identical to the pre-per-vendor behaviour.
|
|
263
|
+
*
|
|
264
|
+
* **`otherVendorAvailable: false` is server-known truth and outranks every
|
|
265
|
+
* local guess.** Only the proxy knows whether anything else has headroom; this
|
|
266
|
+
* element can only observe which vendors the registry can reach. So when the
|
|
267
|
+
* proxy says no, every other *budgeted* vendor is walled in the same pass. That
|
|
268
|
+
* is what makes `blocked` derive true — locking the composer on the first wall
|
|
269
|
+
* rather than leaving it live against a vendor set the banner would otherwise
|
|
270
|
+
* have advised switching to.
|
|
271
|
+
*
|
|
272
|
+
* The sweep runs over `BUDGETED_VENDORS`, NOT
|
|
273
|
+
* {@link BudgetController.reachableVendors}: reachability is loaded
|
|
274
|
+
* asynchronously, so a reachability-scoped sweep dropped the verdict entirely
|
|
275
|
+
* when the wall beat the statuses home — making it effectively un-latch, since
|
|
276
|
+
* the single wall derived `blocked` only while nothing was reachable, and the
|
|
277
|
+
* composer came back to life against a budget the proxy had already said was
|
|
278
|
+
* gone. Sweeping the metered list instead makes the verdict independent of load
|
|
279
|
+
* order. Walling a vendor the registry cannot reach costs nothing: `blocked`
|
|
280
|
+
* only asks whether every REACHABLE vendor is walled, and the banner reads
|
|
281
|
+
* {@link BudgetController.relevantBlockedVendors}.
|
|
282
|
+
*
|
|
283
|
+
* One boundary remains on the sweep: it walls only vendors the proxy meters,
|
|
284
|
+
* because a vendor it does not meter has no budget there to exhaust, so "no
|
|
285
|
+
* other vendor has budget" is not a statement about it.
|
|
286
|
+
*
|
|
287
|
+
* The sweep runs last but sits OUTSIDE the per-vendor idempotence guard, and
|
|
288
|
+
* both halves of that matter. Last, so the vendor that actually refused this
|
|
289
|
+
* turn heads the wall order the multi-vendor banner reads. Outside the guard,
|
|
290
|
+
* because the verdict can arrive on a LATER 402 for a vendor that is already
|
|
291
|
+
* walled.
|
|
292
|
+
*
|
|
293
|
+
* @param reason - the turn's failure reason; anything but `'budget-exhausted'` is ignored.
|
|
294
|
+
* @param ref - the session store to write through, captured by the caller so a
|
|
295
|
+
* teardown race cannot land the wall in a new session's store.
|
|
296
|
+
* @param budget - what the 402 reported: figures when the proxy sent any, the
|
|
297
|
+
* refusing vendor, and its `otherVendorAvailable` verdict.
|
|
298
|
+
* @param vendorHint - the `tool-loop-end` detail's top-level vendor, used only
|
|
299
|
+
* when the budget payload names none.
|
|
300
|
+
*/
|
|
301
|
+
latchFrom(reason?: TurnFailureReason, ref?: SessionStoreReturn | undefined, budget?: Extract<ChatDriverResult, {
|
|
302
|
+
reason: 'done';
|
|
303
|
+
}>['budget'], vendorHint?: AIProviderType): void;
|
|
304
|
+
/**
|
|
305
|
+
* Copy shown in the blocked banner, in ascending specificity:
|
|
306
|
+
*
|
|
307
|
+
* 1. the host's `blockedReason` — a whole-banner override, unchanged;
|
|
308
|
+
* 2. copy composed from the walled vendors (their per-vendor reasons when set,
|
|
309
|
+
* else their figures);
|
|
310
|
+
* 3. the default budget-exhaustion message.
|
|
311
|
+
*
|
|
312
|
+
* The action clause is composed HERE, not stored at latch time, because whether
|
|
313
|
+
* "switch vendor" or "contact your administrator" is honest depends on whether
|
|
314
|
+
* another reachable vendor still has headroom — which changes when the registry
|
|
315
|
+
* changes, long after the wall was latched. Telling a user to switch to a vendor
|
|
316
|
+
* that is also exhausted is worse than saying nothing.
|
|
317
|
+
*
|
|
318
|
+
* **Per-vendor copy is composed however many vendors are walled**, which is what
|
|
319
|
+
* `setVendorBlocked`'s `reason` parameter promises. It used to be honoured only
|
|
320
|
+
* on the single-vendor branch, so a host that had carefully set copy for each of
|
|
321
|
+
* its vendors watched all of it vanish the moment a second one walled.
|
|
322
|
+
*/
|
|
323
|
+
get effectiveBlockedReason(): string;
|
|
324
|
+
/**
|
|
325
|
+
* Copy the driver writes into the TRANSCRIPT when a turn hits the budget wall,
|
|
326
|
+
* or `undefined` to let the driver compose it per wall.
|
|
327
|
+
*
|
|
328
|
+
* A set `blockedReason` still wins — a white-labelled host must not read its own
|
|
329
|
+
* explanation in the banner and shipped copy directly below it.
|
|
330
|
+
*
|
|
331
|
+
* `undefined` (the usual case) is NOT the old `DEFAULT_BUDGET_EXHAUSTED_MESSAGE`
|
|
332
|
+
* fallback: it hands composition to the driver, which builds the bubble from
|
|
333
|
+
* EACH wall's own 402 — naming the exhausted vendor and advising a switch only
|
|
334
|
+
* when that refusal's `otherVendorAvailable` positively vouched for headroom
|
|
335
|
+
* elsewhere. That is immune to the staleness this getter used to guard against
|
|
336
|
+
* by freezing the copy: construction-time advice could outlive its truth
|
|
337
|
+
* (`getOrCreateDriver` re-runs on an agents swap and would have baked the
|
|
338
|
+
* sentence into every later bubble), but per-wall advice is derived from the
|
|
339
|
+
* refusal it annotates and dies with the turn. Forcing the default here was also
|
|
340
|
+
* what made the driver's composed bubble unreachable in every real mount — the
|
|
341
|
+
* banner advised switching while the bubble under it never did (the GENC-1464
|
|
342
|
+
* tester finding, root cause).
|
|
343
|
+
*/
|
|
344
|
+
get transcriptMessage(): string | undefined;
|
|
345
|
+
/**
|
|
346
|
+
* Built-in per-vendor budget meter (GENC-1464) — the money sibling of the
|
|
347
|
+
* settings modal's context-usage gate, with the same shape: not configured off,
|
|
348
|
+
* and there is data to show. "Data" here is "at least one vendor has figures",
|
|
349
|
+
* so a host that feeds nothing (or only unlimited vendors) gets no meter and no
|
|
350
|
+
* empty container.
|
|
351
|
+
*
|
|
352
|
+
* Answered from the RAW slice state rather than from
|
|
353
|
+
* {@link BudgetController.settingsRows}, whose `.length` would format every row
|
|
354
|
+
* (a `formatUsd` pair and a `budgetPercentOf` each) only to ask whether any
|
|
355
|
+
* exist. This is read several times per render pass — the getter, the section
|
|
356
|
+
* gate, the template's `when` — so it stays as cheap as the context sibling's
|
|
357
|
+
* `!= null`.
|
|
358
|
+
*/
|
|
359
|
+
get settingsUsageVisible(): boolean;
|
|
360
|
+
/**
|
|
361
|
+
* The meter's rows — one per vendor that currently has figures, in
|
|
362
|
+
* `BUDGETED_VENDORS` order (the proxy's own metered list) so the rendering is
|
|
363
|
+
* stable however the host ordered its feed calls. Pre-formatted; see
|
|
364
|
+
* {@link SettingsBudgetRow} for why the text is unclamped while the bar is.
|
|
365
|
+
*/
|
|
366
|
+
get settingsRows(): readonly SettingsBudgetRow[];
|
|
367
|
+
}
|
|
368
|
+
//# sourceMappingURL=budget-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"budget-controller.d.ts","sourceRoot":"","sources":["../../../src/main/budget-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { MetaEventType } from '../state/debug-event-log';
|
|
2
|
+
/** A read/write pair for one piece of state the controller does not own. */
|
|
3
|
+
export interface Accessor<T> {
|
|
4
|
+
get(): T;
|
|
5
|
+
set(value: T): void;
|
|
6
|
+
}
|
|
7
|
+
/** What the controller needs from its host beyond the shadow root. */
|
|
8
|
+
export interface ComposerMenuDeps {
|
|
9
|
+
agentPickerOpen: Accessor<boolean>;
|
|
10
|
+
sessionMenuOpen: Accessor<boolean>;
|
|
11
|
+
/** Return focus here after Escape, rather than to a button that just vanished. */
|
|
12
|
+
focusInput: () => void;
|
|
13
|
+
/**
|
|
14
|
+
* Clear the session menu's two-step confirm prompts. Called on EVERY session-menu
|
|
15
|
+
* toggle, not just a user click on the ⋮ button — the menu must always reopen
|
|
16
|
+
* showing the menu rather than a leftover Clear-confirm, and it can be closed
|
|
17
|
+
* from four paths (the button, Escape, an outside click, opening the agent
|
|
18
|
+
* picker). Keeping it in the controller is what makes that hold on all four.
|
|
19
|
+
*/
|
|
20
|
+
resetSessionConfirmations: () => void;
|
|
21
|
+
logMeta: (type: MetaEventType, detail?: Record<string, unknown>) => void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The two composer menus — the agent picker and the session (⋮) menu: their
|
|
25
|
+
* mutually-exclusive open/close animation, their measured placement above the
|
|
26
|
+
* button that opened them, and the document-level listeners that dismiss them.
|
|
27
|
+
*
|
|
28
|
+
* Owns no observable state: both open flags live on the session store so the
|
|
29
|
+
* bubble and popout instances stay in sync, and reach this controller as
|
|
30
|
+
* {@link Accessor}s.
|
|
31
|
+
*
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
export declare class ComposerMenuController {
|
|
35
|
+
/**
|
|
36
|
+
* Typed `HTMLElement`, not the assistant: this controller needs the shadow root
|
|
37
|
+
* and nothing else, and the narrower type is what stops it reaching back into
|
|
38
|
+
* element API and recreating the god object with extra indirection.
|
|
39
|
+
*/
|
|
40
|
+
private readonly host;
|
|
41
|
+
private readonly deps;
|
|
42
|
+
private readonly agentPicker;
|
|
43
|
+
private readonly sessionMenu;
|
|
44
|
+
/** Live only while a menu is open — see {@link ComposerMenuController.syncDismissal}. */
|
|
45
|
+
private dismissPointer?;
|
|
46
|
+
private dismissKey?;
|
|
47
|
+
private dismissResize?;
|
|
48
|
+
constructor(
|
|
49
|
+
/**
|
|
50
|
+
* Typed `HTMLElement`, not the assistant: this controller needs the shadow root
|
|
51
|
+
* and nothing else, and the narrower type is what stops it reaching back into
|
|
52
|
+
* element API and recreating the god object with extra indirection.
|
|
53
|
+
*/
|
|
54
|
+
host: HTMLElement, deps: ComposerMenuDeps);
|
|
55
|
+
toggleAgentPicker(): void;
|
|
56
|
+
toggleSessionMenu(): void;
|
|
57
|
+
/** Close whichever menus are open, with their close animation. */
|
|
58
|
+
closeAll(): void;
|
|
59
|
+
/**
|
|
60
|
+
* Close both menus at once, with no close animation and no `panel.toggled`
|
|
61
|
+
* meta event — for a caller that is about to replace the view the menu sits in
|
|
62
|
+
* (Compact swaps the transcript for a progress indicator, Clear wipes it).
|
|
63
|
+
*
|
|
64
|
+
* Not {@link ComposerMenuController.closeAll}: animating a panel out over 200ms
|
|
65
|
+
* while the thing behind it is being replaced is the wrong effect, and routing
|
|
66
|
+
* through the toggles would log a spurious user-initiated panel toggle into the
|
|
67
|
+
* debug timeline. This matches what the direct flag assignment on the element did
|
|
68
|
+
* before — including leaving any in-flight close timer alone, which is safe
|
|
69
|
+
* because the toggle strips `closing` from the node it captured.
|
|
70
|
+
*/
|
|
71
|
+
closeImmediate(): void;
|
|
72
|
+
/** Re-place whichever menu is open. Cheap enough to run from a resize. */
|
|
73
|
+
repositionOpen(): void;
|
|
74
|
+
/**
|
|
75
|
+
* Attach or drop the dismissal listeners to match whether a menu is open.
|
|
76
|
+
* Called from the open/close setters, so the listeners exist only while there is
|
|
77
|
+
* something to dismiss.
|
|
78
|
+
*/
|
|
79
|
+
syncDismissal(): void;
|
|
80
|
+
/**
|
|
81
|
+
* Finalise in-flight close animations and drop every listener — call from
|
|
82
|
+
* `disconnectedCallback`.
|
|
83
|
+
*
|
|
84
|
+
* **Teardown runs LAST, and the order is load-bearing.** `finalize()` writes the
|
|
85
|
+
* flag through `setOpen`, which reaches the element setter and therefore
|
|
86
|
+
* {@link ComposerMenuController.syncDismissal} — so tearing down first let the
|
|
87
|
+
* sync re-arm the listeners on an element that is going away. Reachable, if
|
|
88
|
+
* narrowly: a panel's flag stays TRUE for the whole close animation, so
|
|
89
|
+
* switching from the session menu to the agent picker leaves both flags set for
|
|
90
|
+
* ~200ms, and a disconnect in that window finalised the closing menu while the
|
|
91
|
+
* picker was still open — `shouldListen` true, listeners re-attached, nothing
|
|
92
|
+
* left to remove them (PR #2503 review).
|
|
93
|
+
*/
|
|
94
|
+
dispose(): void;
|
|
95
|
+
private teardownDismissal;
|
|
96
|
+
/**
|
|
97
|
+
* Places an open composer menu directly above the control that opened it.
|
|
98
|
+
*
|
|
99
|
+
* CSS alone cannot: the menu is a child of `.composer` — which is what lets its
|
|
100
|
+
* width be capped against the composer rather than against a button — while its
|
|
101
|
+
* anchor is a button several levels down the bar, and no selector can read a
|
|
102
|
+
* sibling's offset. So the left edge is measured on open and written as a custom
|
|
103
|
+
* property.
|
|
104
|
+
*
|
|
105
|
+
* Clamped to the composer, so a menu opened from a control near the right edge of
|
|
106
|
+
* a narrow panel slides back inside instead of overhanging. The animation origin
|
|
107
|
+
* is written separately and keeps pointing at the button's centre even after such
|
|
108
|
+
* a shift — the menu still grows out of the thing that opened it, which is the
|
|
109
|
+
* whole point of anchoring it there.
|
|
110
|
+
*/
|
|
111
|
+
private position;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=composer-menu-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer-menu-controller.d.ts","sourceRoot":"","sources":["../../../src/main/composer-menu-controller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AA4B9D,4EAA4E;AAC5E,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,GAAG,IAAI,CAAC,CAAC;IACT,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;CACrB;AAED,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACnC,eAAe,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACnC,kFAAkF;IAClF,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB;;;;;;OAMG;IACH,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,OAAO,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAC1E;AAED;;;;;;;;;;GAUG;AACH,qBAAa,sBAAsB;IAU/B;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAfvB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsB;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsB;IAElD,yFAAyF;IACzF,OAAO,CAAC,cAAc,CAAC,CAAqB;IAC5C,OAAO,CAAC,UAAU,CAAC,CAA6B;IAChD,OAAO,CAAC,aAAa,CAAC,CAAa;;IAGjC;;;;OAIG;IACc,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,gBAAgB;IAkBzC,iBAAiB,IAAI,IAAI;IAkBzB,iBAAiB,IAAI,IAAI;IAmBzB,kEAAkE;IAClE,QAAQ,IAAI,IAAI;IAKhB;;;;;;;;;;;OAWG;IACH,cAAc,IAAI,IAAI;IAKtB,0EAA0E;IAC1E,cAAc,IAAI,IAAI;IAStB;;;;OAIG;IACH,aAAa,IAAI,IAAI;IA6BrB;;;;;;;;;;;;;OAaG;IACH,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,iBAAiB;IAezB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,QAAQ;CAgDjB"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** What the controller needs from its host, as callbacks so it holds no element reference. */
|
|
2
|
+
export interface ComposerResizeDeps {
|
|
3
|
+
/** `chatConfig.ui.resizableInput !== false` — read live, since a host can flip it. */
|
|
4
|
+
enabled: () => boolean;
|
|
5
|
+
/** The composer box, for its measured natural height on the first drag. */
|
|
6
|
+
inputEl: () => HTMLElement | undefined;
|
|
7
|
+
/** The message list, whose height is the headroom the composer may claim. */
|
|
8
|
+
messagesEl: () => HTMLElement | undefined;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Drag-to-resize for the composer: owns the chosen height and the transient
|
|
12
|
+
* geometry of one drag gesture.
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export declare class ComposerResizeController {
|
|
17
|
+
private readonly deps;
|
|
18
|
+
/**
|
|
19
|
+
* Explicit composer height in px once the user has dragged; `null` keeps the
|
|
20
|
+
* default auto-grow behaviour.
|
|
21
|
+
*
|
|
22
|
+
* Observable because {@link ComposerResizeController.heightStyle} is bound in
|
|
23
|
+
* the template — see the sibling scratch fields for why the rest are not.
|
|
24
|
+
*/
|
|
25
|
+
heightPx: number | null;
|
|
26
|
+
/**
|
|
27
|
+
* Pointer Y and height captured at the start of a drag.
|
|
28
|
+
*
|
|
29
|
+
* Deliberately NOT observable, and the same goes for the two bounds below.
|
|
30
|
+
* These are rewritten on every `pointermove`, and no binding reads them, so
|
|
31
|
+
* marking them would fire a notification per mouse-move for values nothing
|
|
32
|
+
* displays — while `heightPx`, which does drive the render, fires exactly one.
|
|
33
|
+
*/
|
|
34
|
+
private startY;
|
|
35
|
+
private startHeight;
|
|
36
|
+
/** Natural (un-dragged) height, measured on the first drag — the floor for shrinking. */
|
|
37
|
+
private naturalHeight;
|
|
38
|
+
/** Upper bound for the current drag, capped to the headroom above the composer. */
|
|
39
|
+
private maxHeight;
|
|
40
|
+
constructor(deps: ComposerResizeDeps);
|
|
41
|
+
/** Whether the composer shows a drag handle. On by default; hosts opt out via config. */
|
|
42
|
+
get resizable(): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Inline style for the composer: writes the chosen height into the
|
|
45
|
+
* `--composer-height` custom property (read by `.chat-input` and its control in
|
|
46
|
+
* `main.styles.ts`). Empty until the user drags, or when resizing is disabled,
|
|
47
|
+
* so the CSS default applies.
|
|
48
|
+
*
|
|
49
|
+
* `heightPx` is read into a local BEFORE the branch, and that is load-bearing.
|
|
50
|
+
* Written as `this.resizable && this.heightPx != null ? …`, the `&&`
|
|
51
|
+
* short-circuits past `heightPx` whenever resizing is off — so on a host that
|
|
52
|
+
* mounts with `resizableInput: false`, FAST never records a dependency on it.
|
|
53
|
+
* The template's binding for this getter (`style=${(x) => x.composerHeightStyle}`)
|
|
54
|
+
* carries no `:`/`&&`/`||`, so FAST classifies it non-volatile and collects
|
|
55
|
+
* dependencies exactly once per bind; the missing dependency is therefore never
|
|
56
|
+
* picked up, and a later `resizableInput: true` gives a handle that drags —
|
|
57
|
+
* `heightPx` updates — while the composer never visibly moves.
|
|
58
|
+
*
|
|
59
|
+
* Reading it unconditionally makes the dependency honest and costs nothing.
|
|
60
|
+
* `@volatile` would also fix it, by re-collecting on every evaluation, but it pays
|
|
61
|
+
* a full unsubscribe/resubscribe cycle each time to express something that is
|
|
62
|
+
* simply true: this getter always depends on both.
|
|
63
|
+
*/
|
|
64
|
+
get heightStyle(): string;
|
|
65
|
+
/**
|
|
66
|
+
* Begin a drag. Captures the pointer so move/up keep firing on the handle even
|
|
67
|
+
* when the cursor leaves its 7px band.
|
|
68
|
+
*/
|
|
69
|
+
onStart(e: PointerEvent): void;
|
|
70
|
+
/**
|
|
71
|
+
* Resize while dragging. Dragging up (clientY decreases) grows the composer; the
|
|
72
|
+
* result is clamped between the natural height and the available headroom. No-op
|
|
73
|
+
* unless a drag is active (the handle holds pointer capture), so plain
|
|
74
|
+
* hover-moves are ignored.
|
|
75
|
+
*/
|
|
76
|
+
onMove(e: PointerEvent): void;
|
|
77
|
+
/** End a drag and release the pointer capture. */
|
|
78
|
+
onEnd(e: PointerEvent): void;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=composer-resize-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer-resize-controller.d.ts","sourceRoot":"","sources":["../../../src/main/composer-resize-controller.ts"],"names":[],"mappings":"AAaA,8FAA8F;AAC9F,MAAM,WAAW,kBAAkB;IACjC,sFAAsF;IACtF,OAAO,EAAE,MAAM,OAAO,CAAC;IACvB,2EAA2E;IAC3E,OAAO,EAAE,MAAM,WAAW,GAAG,SAAS,CAAC;IACvC,6EAA6E;IAC7E,UAAU,EAAE,MAAM,WAAW,GAAG,SAAS,CAAC;CAC3C;AAED;;;;;GAKG;AACH,qBAAa,wBAAwB;IAyBvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAxBjC;;;;;;OAMG;IACS,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE3C;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,WAAW,CAAK;IACxB,yFAAyF;IACzF,OAAO,CAAC,aAAa,CAAK;IAC1B,mFAAmF;IACnF,OAAO,CAAC,SAAS,CAA0B;gBAEd,IAAI,EAAE,kBAAkB;IAErD,yFAAyF;IACzF,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,IAAI,WAAW,IAAI,MAAM,CAGxB;IAED;;;OAGG;IACH,OAAO,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI;IAoB9B;;;;;OAKG;IACH,MAAM,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI;IAS7B,kDAAkD;IAClD,KAAK,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI;CAI7B"}
|