@genesislcap/ai-assistant 15.10.3 → 15.10.5
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 +68 -1
- package/dist/ai-assistant.d.ts +34 -22
- package/dist/chat-driver.cjs +27 -12
- package/dist/chat-driver.cjs.map +2 -2
- package/dist/chat-driver.mjs +27 -12
- package/dist/chat-driver.mjs.map +2 -2
- package/dist/custom-elements.json +30 -6
- package/dist/dts/components/chat-driver/chat-driver.d.ts +14 -4
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
- package/dist/dts/main/main.d.ts +20 -18
- package/dist/dts/main/main.d.ts.map +1 -1
- package/dist/dts/utils/condense-history.d.ts +29 -5
- package/dist/dts/utils/condense-history.d.ts.map +1 -1
- package/dist/esm/components/chat-driver/chat-driver.js +35 -4
- package/dist/esm/components/chat-driver/chat-driver.test.js +62 -0
- package/dist/esm/main/blocked-state.test.js +44 -0
- package/dist/esm/main/main.js +36 -17
- package/dist/esm/utils/condense-history.js +53 -23
- package/dist/esm/utils/condense-history.test.js +49 -4
- package/package.json +17 -17
- package/src/components/chat-driver/chat-driver.test.ts +107 -0
- package/src/components/chat-driver/chat-driver.ts +50 -8
- package/src/main/blocked-state.test.ts +59 -0
- package/src/main/main.ts +37 -18
- package/src/utils/condense-history.test.ts +65 -3
- package/src/utils/condense-history.ts +74 -25
|
@@ -5256,6 +5256,73 @@
|
|
|
5256
5256
|
"isAbstract": false,
|
|
5257
5257
|
"name": "markAsSubAgent"
|
|
5258
5258
|
},
|
|
5259
|
+
{
|
|
5260
|
+
"kind": "Method",
|
|
5261
|
+
"canonicalReference": "@genesislcap/ai-assistant!ChatDriver#reportBudgetExhausted:member(1)",
|
|
5262
|
+
"docComment": "",
|
|
5263
|
+
"excerptTokens": [
|
|
5264
|
+
{
|
|
5265
|
+
"kind": "Content",
|
|
5266
|
+
"text": "reportBudgetExhausted(e: "
|
|
5267
|
+
},
|
|
5268
|
+
{
|
|
5269
|
+
"kind": "Reference",
|
|
5270
|
+
"text": "BudgetExhaustedError",
|
|
5271
|
+
"canonicalReference": "@genesislcap/foundation-ai!BudgetExhaustedError:class"
|
|
5272
|
+
},
|
|
5273
|
+
{
|
|
5274
|
+
"kind": "Content",
|
|
5275
|
+
"text": ", pendingUserMessage?: "
|
|
5276
|
+
},
|
|
5277
|
+
{
|
|
5278
|
+
"kind": "Reference",
|
|
5279
|
+
"text": "ChatMessage",
|
|
5280
|
+
"canonicalReference": "@genesislcap/foundation-ai!ChatMessage:interface"
|
|
5281
|
+
},
|
|
5282
|
+
{
|
|
5283
|
+
"kind": "Content",
|
|
5284
|
+
"text": "): "
|
|
5285
|
+
},
|
|
5286
|
+
{
|
|
5287
|
+
"kind": "Reference",
|
|
5288
|
+
"text": "ChatDriverResult",
|
|
5289
|
+
"canonicalReference": "@genesislcap/foundation-ai!ChatDriverResult:type"
|
|
5290
|
+
},
|
|
5291
|
+
{
|
|
5292
|
+
"kind": "Content",
|
|
5293
|
+
"text": ";"
|
|
5294
|
+
}
|
|
5295
|
+
],
|
|
5296
|
+
"isStatic": false,
|
|
5297
|
+
"returnTypeTokenRange": {
|
|
5298
|
+
"startIndex": 5,
|
|
5299
|
+
"endIndex": 6
|
|
5300
|
+
},
|
|
5301
|
+
"releaseTag": "Beta",
|
|
5302
|
+
"isProtected": false,
|
|
5303
|
+
"overloadIndex": 1,
|
|
5304
|
+
"parameters": [
|
|
5305
|
+
{
|
|
5306
|
+
"parameterName": "e",
|
|
5307
|
+
"parameterTypeTokenRange": {
|
|
5308
|
+
"startIndex": 1,
|
|
5309
|
+
"endIndex": 2
|
|
5310
|
+
},
|
|
5311
|
+
"isOptional": false
|
|
5312
|
+
},
|
|
5313
|
+
{
|
|
5314
|
+
"parameterName": "pendingUserMessage",
|
|
5315
|
+
"parameterTypeTokenRange": {
|
|
5316
|
+
"startIndex": 3,
|
|
5317
|
+
"endIndex": 4
|
|
5318
|
+
},
|
|
5319
|
+
"isOptional": true
|
|
5320
|
+
}
|
|
5321
|
+
],
|
|
5322
|
+
"isOptional": false,
|
|
5323
|
+
"isAbstract": false,
|
|
5324
|
+
"name": "reportBudgetExhausted"
|
|
5325
|
+
},
|
|
5259
5326
|
{
|
|
5260
5327
|
"kind": "Method",
|
|
5261
5328
|
"canonicalReference": "@genesislcap/ai-assistant!ChatDriver#requestInteraction:member(1)",
|
|
@@ -5692,7 +5759,7 @@
|
|
|
5692
5759
|
{
|
|
5693
5760
|
"kind": "PropertySignature",
|
|
5694
5761
|
"canonicalReference": "@genesislcap/ai-assistant!ChatDriverConfig#budgetExhaustedMessage:member",
|
|
5695
|
-
"docComment": "/**\n * Transcript copy appended when the AI-spend budget wall is hit (GENC-1464).
|
|
5762
|
+
"docComment": "/**\n * Transcript copy appended when the AI-spend budget wall is hit (GENC-1464), used VERBATIM — set it only to own the copy entirely (white-labelling). When unset, the driver composes the bubble per wall: the neutral `DEFAULT_BUDGET_EXHAUSTED_MESSAGE`, upgraded with \"switch to another AI provider\" advice only when the 402's `otherVendorAvailable` positively says another metered vendor still has headroom — the same rule the blocked banner applies, so the two surfaces can no longer contradict each other.\n *\n * The assistant element already lets a host override the blocked **banner** via `setBlocked(true, reason)`; without this the transcript **bubble** stayed on the default, so a white-labelled host got its own copy in the banner and the shipped default directly below it. Passing the same effective copy here keeps the two surfaces saying one thing.\n *\n * Deliberately a driver-config field rather than something read off a chat config: `ChatDriver` has no `chatConfig` and is used standalone (see `chat-driver-node`), so threading one in would be a much larger and less reversible change.\n */\n",
|
|
5696
5763
|
"excerptTokens": [
|
|
5697
5764
|
{
|
|
5698
5765
|
"kind": "Content",
|
package/dist/ai-assistant.d.ts
CHANGED
|
@@ -1492,8 +1492,12 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
|
|
|
1492
1492
|
private readonly sessionKey;
|
|
1493
1493
|
/** Injected activity bus; defaults to a no-op off-browser (Node/tests/headless). */
|
|
1494
1494
|
private readonly activityBus;
|
|
1495
|
-
/**
|
|
1496
|
-
|
|
1495
|
+
/**
|
|
1496
|
+
* Host override for the budget-wall transcript copy, used verbatim — see
|
|
1497
|
+
* `ChatDriverConfig.budgetExhaustedMessage`. `undefined` means no override,
|
|
1498
|
+
* and the bubble is composed per wall by {@link ChatDriver.budgetExhaustedBubble}.
|
|
1499
|
+
*/
|
|
1500
|
+
private readonly budgetExhaustedMessageOverride?;
|
|
1497
1501
|
/**
|
|
1498
1502
|
* Set the moment a budget wall is observed anywhere in this turn — this
|
|
1499
1503
|
* driver's own 402, or a sub-agent's (which surfaces here only as a
|
|
@@ -1597,6 +1601,7 @@ export declare class ChatDriver extends EventTarget implements AiDriver {
|
|
|
1597
1601
|
*
|
|
1598
1602
|
* @internal
|
|
1599
1603
|
*/
|
|
1604
|
+
private budgetExhaustedBubble;
|
|
1600
1605
|
reportBudgetExhausted(e: BudgetExhaustedError, pendingUserMessage?: ChatMessage): ChatDriverResult;
|
|
1601
1606
|
/** The typed failure reason on a loop result, or `undefined` for a clean turn / handoff. */
|
|
1602
1607
|
private static failureReasonOf;
|
|
@@ -1914,8 +1919,13 @@ export declare interface ChatDriverConfig {
|
|
|
1914
1919
|
*/
|
|
1915
1920
|
activityBus?: ActivityBus;
|
|
1916
1921
|
/**
|
|
1917
|
-
* Transcript copy appended when the AI-spend budget wall is hit (GENC-1464)
|
|
1918
|
-
*
|
|
1922
|
+
* Transcript copy appended when the AI-spend budget wall is hit (GENC-1464),
|
|
1923
|
+
* used VERBATIM — set it only to own the copy entirely (white-labelling).
|
|
1924
|
+
* When unset, the driver composes the bubble per wall: the neutral
|
|
1925
|
+
* `DEFAULT_BUDGET_EXHAUSTED_MESSAGE`, upgraded with "switch to another AI
|
|
1926
|
+
* provider" advice only when the 402's `otherVendorAvailable` positively says
|
|
1927
|
+
* another metered vendor still has headroom — the same rule the blocked
|
|
1928
|
+
* banner applies, so the two surfaces can no longer contradict each other.
|
|
1919
1929
|
*
|
|
1920
1930
|
* The assistant element already lets a host override the blocked **banner**
|
|
1921
1931
|
* via `setBlocked(true, reason)`; without this the transcript **bubble** stayed
|
|
@@ -2859,24 +2869,26 @@ export declare class FoundationAiAssistant extends GenesisElement {
|
|
|
2859
2869
|
*/
|
|
2860
2870
|
get effectiveBlockedReason(): string;
|
|
2861
2871
|
/**
|
|
2862
|
-
* Copy the driver writes into the TRANSCRIPT when a turn hits the budget wall
|
|
2863
|
-
*
|
|
2864
|
-
*
|
|
2865
|
-
*
|
|
2866
|
-
*
|
|
2867
|
-
*
|
|
2868
|
-
*
|
|
2869
|
-
*
|
|
2870
|
-
*
|
|
2871
|
-
*
|
|
2872
|
-
*
|
|
2873
|
-
*
|
|
2874
|
-
*
|
|
2875
|
-
*
|
|
2876
|
-
*
|
|
2877
|
-
*
|
|
2878
|
-
*
|
|
2879
|
-
*
|
|
2872
|
+
* Copy the driver writes into the TRANSCRIPT when a turn hits the budget wall,
|
|
2873
|
+
* or `undefined` to let the driver compose it per wall.
|
|
2874
|
+
*
|
|
2875
|
+
* A set `blockedReason` still wins — a white-labelled host must not read its
|
|
2876
|
+
* own explanation in the banner and shipped copy directly below it, and the
|
|
2877
|
+
* vendor-agnostic latch's `formatBlockedReason(budget)` form stays advice-free
|
|
2878
|
+
* exactly as before.
|
|
2879
|
+
*
|
|
2880
|
+
* `undefined` (the usual case) is NOT the old `DEFAULT_BUDGET_EXHAUSTED_MESSAGE`
|
|
2881
|
+
* fallback: it hands composition to the driver, which builds the bubble from
|
|
2882
|
+
* EACH wall's own 402 — naming the exhausted vendor and advising a switch only
|
|
2883
|
+
* when that refusal's `otherVendorAvailable` positively vouched for headroom
|
|
2884
|
+
* elsewhere. That is immune to the staleness this getter used to guard against
|
|
2885
|
+
* by freezing the copy: construction-time advice could outlive its truth
|
|
2886
|
+
* (`getOrCreateDriver` re-runs on an agents swap and would have baked the
|
|
2887
|
+
* sentence into every later bubble), but per-wall advice is derived from the
|
|
2888
|
+
* refusal it annotates and dies with the turn. Forcing the default here was
|
|
2889
|
+
* also what made the driver's composed bubble unreachable in every real
|
|
2890
|
+
* mount — the banner advised switching while the bubble under it never did
|
|
2891
|
+
* (the GENC-1464 tester finding, root cause).
|
|
2880
2892
|
*/
|
|
2881
2893
|
private get transcriptBudgetExhaustedMessage();
|
|
2882
2894
|
/**
|
package/dist/chat-driver.cjs
CHANGED
|
@@ -3091,10 +3091,11 @@ function triggerReason(trigger) {
|
|
|
3091
3091
|
return "superseded";
|
|
3092
3092
|
}
|
|
3093
3093
|
}
|
|
3094
|
-
function condenseStub(target, tool, trigger, origLen) {
|
|
3094
|
+
function condenseStub(target, tool, trigger, origLen, restorable) {
|
|
3095
3095
|
const what = target === "args" ? "args" : "result";
|
|
3096
3096
|
const key = trigger.kind === "superseded" ? ` ${trigger.by}` : "";
|
|
3097
|
-
|
|
3097
|
+
const restore = restorable ? "; re-call to restore" : "";
|
|
3098
|
+
return `[${tool}${key} \u2014 ${what} elided, ~${origLen} chars (${triggerReason(trigger)})${restore}]`;
|
|
3098
3099
|
}
|
|
3099
3100
|
function triggerLabel(trigger) {
|
|
3100
3101
|
switch (trigger.kind) {
|
|
@@ -3151,9 +3152,14 @@ function applyCondensation(history, policies, ctx, onCondensed) {
|
|
|
3151
3152
|
return latestByKey.get(trig.by) !== toolCallId;
|
|
3152
3153
|
}
|
|
3153
3154
|
};
|
|
3154
|
-
const firstFired = (toolCallId, entry) =>
|
|
3155
|
-
|
|
3156
|
-
|
|
3155
|
+
const firstFired = (toolCallId, entry) => {
|
|
3156
|
+
if (entry.firedTrigger) return entry.firedTrigger;
|
|
3157
|
+
const fired = triggersOf(entry).find(
|
|
3158
|
+
(t) => (marksDiscontinuity(t.kind) || withinBatch(entry)) && triggerFires(toolCallId, entry, t)
|
|
3159
|
+
);
|
|
3160
|
+
if (fired) entry.firedTrigger = fired;
|
|
3161
|
+
return fired;
|
|
3162
|
+
};
|
|
3157
3163
|
return history.map((msg) => {
|
|
3158
3164
|
if (msg.toolCalls?.length) {
|
|
3159
3165
|
let changed = false;
|
|
@@ -3166,8 +3172,8 @@ function applyCondensation(history, policies, ctx, onCondensed) {
|
|
|
3166
3172
|
if (origLen < CONDENSE_MIN_CHARS) return tc;
|
|
3167
3173
|
changed = true;
|
|
3168
3174
|
const result = entry.policy.args;
|
|
3169
|
-
const args =
|
|
3170
|
-
[CONDENSED_ARGS_KEY]: result === "pointer" ? condenseStub("args", tc.name, fired, origLen) : result.replaceWith
|
|
3175
|
+
const args = {
|
|
3176
|
+
[CONDENSED_ARGS_KEY]: result === "drop" || result === "pointer" ? condenseStub("args", tc.name, fired, origLen, result === "pointer") : result.replaceWith
|
|
3171
3177
|
};
|
|
3172
3178
|
if (!entry.reportedArgs) {
|
|
3173
3179
|
entry.reportedArgs = true;
|
|
@@ -3193,7 +3199,7 @@ function applyCondensation(history, policies, ctx, onCondensed) {
|
|
|
3193
3199
|
if (entry && fired && origLen >= CONDENSE_MIN_CHARS) {
|
|
3194
3200
|
const tool = nameById.get(msg.toolResult.toolCallId) ?? msg.toolResult.toolCallId;
|
|
3195
3201
|
const result = entry.policy.response;
|
|
3196
|
-
const content = result === "drop"
|
|
3202
|
+
const content = result === "drop" || result === "pointer" ? condenseStub("response", tool, fired, origLen, result === "pointer") : result.replaceWith;
|
|
3197
3203
|
if (!entry.reportedResponse) {
|
|
3198
3204
|
entry.reportedResponse = true;
|
|
3199
3205
|
onCondensed({
|
|
@@ -3567,13 +3573,13 @@ var ChatDriver = class _ChatDriver extends EventTarget {
|
|
|
3567
3573
|
maxTurnSnapshots = DEFAULT_MAX_TURN_SNAPSHOTS,
|
|
3568
3574
|
sessionKey = "",
|
|
3569
3575
|
activityBus = NOOP_ACTIVITY_BUS,
|
|
3570
|
-
budgetExhaustedMessage
|
|
3576
|
+
budgetExhaustedMessage
|
|
3571
3577
|
} = config;
|
|
3572
3578
|
this.maxToolIterations = maxToolIterations;
|
|
3573
3579
|
this.condenseBatchCalls = condenseBatchCalls;
|
|
3574
3580
|
this.sessionKey = sessionKey;
|
|
3575
3581
|
this.activityBus = activityBus;
|
|
3576
|
-
this.
|
|
3582
|
+
this.budgetExhaustedMessageOverride = budgetExhaustedMessage;
|
|
3577
3583
|
if (typeof toolHandlers === "function") {
|
|
3578
3584
|
this.toolHandlersFactory = toolHandlers;
|
|
3579
3585
|
this.toolHandlers = {};
|
|
@@ -3710,6 +3716,12 @@ var ChatDriver = class _ChatDriver extends EventTarget {
|
|
|
3710
3716
|
*
|
|
3711
3717
|
* @internal
|
|
3712
3718
|
*/
|
|
3719
|
+
budgetExhaustedBubble(wall) {
|
|
3720
|
+
if (this.budgetExhaustedMessageOverride != null) return this.budgetExhaustedMessageOverride;
|
|
3721
|
+
if (wall?.otherVendorAvailable !== true) return DEFAULT_BUDGET_EXHAUSTED_MESSAGE;
|
|
3722
|
+
const subject = wall?.vendorLabel ? `${wall.vendorLabel}'s AI usage limit` : "your AI usage limit";
|
|
3723
|
+
return `You've reached ${subject}. Switch to another AI provider in Settings to keep going, or contact your administrator to raise it.`;
|
|
3724
|
+
}
|
|
3713
3725
|
reportBudgetExhausted(e, pendingUserMessage) {
|
|
3714
3726
|
if (pendingUserMessage) this.appendToHistory(pendingUserMessage);
|
|
3715
3727
|
this.budgetExhaustedThisTurn = true;
|
|
@@ -3728,7 +3740,7 @@ var ChatDriver = class _ChatDriver extends EventTarget {
|
|
|
3728
3740
|
spentUsd: e.spentUsd,
|
|
3729
3741
|
isSubAgent: this.isSubAgent
|
|
3730
3742
|
});
|
|
3731
|
-
this.appendToHistory({ role: "assistant", content: this.
|
|
3743
|
+
this.appendToHistory({ role: "assistant", content: this.budgetExhaustedBubble(e) });
|
|
3732
3744
|
return this.turnDone("budget-exhausted", budgetDetailOf(e));
|
|
3733
3745
|
}
|
|
3734
3746
|
/** The typed failure reason on a loop result, or `undefined` for a clean turn / handoff. */
|
|
@@ -4857,7 +4869,10 @@ Output format (strict):
|
|
|
4857
4869
|
if (this.isSubAgent) {
|
|
4858
4870
|
this.failSubAgent("budget_exhausted", this.budgetWallDetail);
|
|
4859
4871
|
} else {
|
|
4860
|
-
this.appendToHistory({
|
|
4872
|
+
this.appendToHistory({
|
|
4873
|
+
role: "assistant",
|
|
4874
|
+
content: this.budgetExhaustedBubble(this.budgetWallDetail)
|
|
4875
|
+
});
|
|
4861
4876
|
}
|
|
4862
4877
|
return this.turnDone("budget-exhausted", this.budgetWallDetail);
|
|
4863
4878
|
}
|