@genesislcap/ai-assistant 15.3.3-alpha-4899ddd.0 → 15.3.4
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 +5 -391
- package/dist/ai-assistant.d.ts +6 -603
- package/dist/chat-driver.cjs +26 -285
- package/dist/chat-driver.cjs.map +3 -3
- package/dist/chat-driver.mjs +26 -285
- package/dist/chat-driver.mjs.map +3 -3
- package/dist/custom-elements.json +10 -236
- package/dist/dts/channel/ai-activity-channel.d.ts +1 -51
- package/dist/dts/channel/ai-activity-channel.d.ts.map +1 -1
- package/dist/dts/components/chat-driver/chat-driver.d.ts +1 -99
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
- package/dist/dts/components/chat-driver/chat-driver.test.d.ts.map +1 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts +0 -14
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts.map +1 -1
- package/dist/dts/main/main.d.ts +6 -384
- 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 +0 -53
- package/dist/dts/main/main.template.d.ts.map +1 -1
- package/dist/dts/state/ai-assistant-slice.d.ts +6 -143
- package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
- package/dist/dts/state/debug-event-log.d.ts +1 -6
- package/dist/dts/state/debug-event-log.d.ts.map +1 -1
- package/dist/dts/state/session-store.d.ts +0 -10
- package/dist/dts/state/session-store.d.ts.map +1 -1
- package/dist/esm/components/chat-driver/chat-driver.js +21 -263
- package/dist/esm/components/chat-driver/chat-driver.test.js +1 -464
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +4 -89
- package/dist/esm/main/main.js +16 -680
- package/dist/esm/main/main.styles.js +0 -47
- package/dist/esm/main/main.template.js +4 -121
- package/dist/esm/state/ai-assistant-slice.js +7 -128
- package/dist/esm/state/ai-assistant-slice.test.js +1 -138
- package/dist/esm/state/debug-event-log.js +2 -7
- package/dist/esm/state/debug-event-log.test.js +1 -49
- package/dist/esm/state/persistence/session-snapshot.test.js +0 -18
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/sub_agent.md +3 -20
- package/package.json +17 -17
- package/src/channel/ai-activity-channel.ts +2 -56
- package/src/components/chat-driver/chat-driver.test.ts +0 -549
- package/src/components/chat-driver/chat-driver.ts +14 -324
- package/src/components/orchestrating-driver/orchestrating-driver.ts +6 -101
- package/src/main/main.styles.ts +0 -47
- package/src/main/main.template.ts +4 -131
- package/src/main/main.ts +10 -680
- package/src/state/ai-assistant-slice.test.ts +0 -215
- package/src/state/ai-assistant-slice.ts +8 -181
- package/src/state/debug-event-log.test.ts +0 -63
- package/src/state/debug-event-log.ts +2 -7
- package/src/state/persistence/session-snapshot.test.ts +0 -22
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.budget.test.d.ts +0 -2
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.budget.test.d.ts.map +0 -1
- package/dist/dts/main/blocked-state.test.d.ts +0 -2
- package/dist/dts/main/blocked-state.test.d.ts.map +0 -1
- package/dist/dts/main/main.styles.test.d.ts +0 -2
- package/dist/dts/main/main.styles.test.d.ts.map +0 -1
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.budget.test.js +0 -312
- package/dist/esm/main/blocked-state.test.js +0 -913
- package/dist/esm/main/main.styles.test.js +0 -86
- package/docs/migration-GENC-1464.md +0 -562
- package/src/components/orchestrating-driver/orchestrating-driver.budget.test.ts +0 -438
- package/src/main/blocked-state.test.ts +0 -1243
- package/src/main/main.styles.test.ts +0 -103
package/dist/chat-driver.mjs
CHANGED
|
@@ -969,67 +969,6 @@ var GeminiProvider = class {
|
|
|
969
969
|
}
|
|
970
970
|
};
|
|
971
971
|
|
|
972
|
-
// ../../foundation-ai/dist/esm/transports/budget-exhausted-error.js
|
|
973
|
-
var BUDGET_EXCEEDED_CODE = "BUDGET_EXCEEDED";
|
|
974
|
-
var VENDOR_LABELS = Object.freeze({
|
|
975
|
-
anthropic: "Anthropic",
|
|
976
|
-
gemini: "Gemini",
|
|
977
|
-
openai: "OpenAI",
|
|
978
|
-
chrome: "Chrome"
|
|
979
|
-
});
|
|
980
|
-
var BUDGETED_VENDORS = Object.freeze([
|
|
981
|
-
"anthropic",
|
|
982
|
-
"gemini"
|
|
983
|
-
]);
|
|
984
|
-
var VENDOR_TYPE_BY_LABEL = new Map(Object.entries(VENDOR_LABELS).map(([type, label]) => [
|
|
985
|
-
label.toLowerCase(),
|
|
986
|
-
type
|
|
987
|
-
]));
|
|
988
|
-
function vendorTypeOfLabel(label) {
|
|
989
|
-
if (typeof label !== "string")
|
|
990
|
-
return void 0;
|
|
991
|
-
return VENDOR_TYPE_BY_LABEL.get(label.trim().toLowerCase());
|
|
992
|
-
}
|
|
993
|
-
var BUDGET_EXCEEDED_STATUS = 402;
|
|
994
|
-
var DEFAULT_BUDGET_EXHAUSTED_MESSAGE = "You've reached your AI usage limit. Contact your administrator to raise it.";
|
|
995
|
-
var BudgetExhaustedError = class extends Error {
|
|
996
|
-
constructor(vendorLabel, budgetUsd, spentUsd, detail, extra) {
|
|
997
|
-
super(`${vendorLabel} request refused: the AI usage budget is exhausted` + (budgetUsd != null ? ` (spent ${spentUsd != null ? `$${spentUsd}` : "an unknown amount"} of a $${budgetUsd} budget)` : "") + (detail ? `: ${detail}` : "") + ". Retrying will not clear this \u2014 the budget must be raised.");
|
|
998
|
-
this.vendorLabel = vendorLabel;
|
|
999
|
-
this.budgetUsd = budgetUsd;
|
|
1000
|
-
this.spentUsd = spentUsd;
|
|
1001
|
-
this.detail = detail;
|
|
1002
|
-
this.name = "BudgetExhaustedError";
|
|
1003
|
-
this.otherVendorAvailable = extra === null || extra === void 0 ? void 0 : extra.otherVendorAvailable;
|
|
1004
|
-
this.serverVendor = extra === null || extra === void 0 ? void 0 : extra.serverVendor;
|
|
1005
|
-
}
|
|
1006
|
-
};
|
|
1007
|
-
var isBudgetRejection = (status, code) => status === BUDGET_EXCEEDED_STATUS || code === BUDGET_EXCEEDED_CODE;
|
|
1008
|
-
var parseJsonOrUndefined = (text) => {
|
|
1009
|
-
try {
|
|
1010
|
-
return JSON.parse(text);
|
|
1011
|
-
} catch (_a) {
|
|
1012
|
-
return void 0;
|
|
1013
|
-
}
|
|
1014
|
-
};
|
|
1015
|
-
var codeOf = (payload) => {
|
|
1016
|
-
const code = payload === null || payload === void 0 ? void 0 : payload.code;
|
|
1017
|
-
return typeof code === "string" ? code : void 0;
|
|
1018
|
-
};
|
|
1019
|
-
var numberOrUndefined = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1020
|
-
var booleanOrUndefined = (value) => typeof value === "boolean" ? value : void 0;
|
|
1021
|
-
var stringOrUndefined = (value) => typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
1022
|
-
function budgetExhaustedFrom(vendorLabel, payload, fallbackDetail) {
|
|
1023
|
-
var _a, _b, _c, _d;
|
|
1024
|
-
const body = typeof payload === "object" && payload !== null ? payload : {};
|
|
1025
|
-
const details = typeof body.details === "object" && body.details !== null ? body.details : {};
|
|
1026
|
-
const detail = typeof body.error === "string" ? body.error : fallbackDetail;
|
|
1027
|
-
return new BudgetExhaustedError(vendorLabel, (_a = numberOrUndefined(body.budgetUsd)) !== null && _a !== void 0 ? _a : numberOrUndefined(details.budgetUsd), (_b = numberOrUndefined(body.spentUsd)) !== null && _b !== void 0 ? _b : numberOrUndefined(details.spentUsd), detail, {
|
|
1028
|
-
otherVendorAvailable: (_c = booleanOrUndefined(body.otherVendorAvailable)) !== null && _c !== void 0 ? _c : booleanOrUndefined(details.otherVendorAvailable),
|
|
1029
|
-
serverVendor: (_d = stringOrUndefined(body.vendor)) !== null && _d !== void 0 ? _d : stringOrUndefined(details.vendor)
|
|
1030
|
-
});
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
972
|
// ../../foundation-ai/dist/esm/types/config.types.js
|
|
1034
973
|
var SUPPORTED_GEMINI_MODEL_IDS = [
|
|
1035
974
|
"gemini-2.5-pro",
|
|
@@ -1184,19 +1123,15 @@ function postWithRetry(options) {
|
|
|
1184
1123
|
signal: combinedSignal,
|
|
1185
1124
|
credentials
|
|
1186
1125
|
});
|
|
1126
|
+
if (retryableStatuses.includes(response.status) && attempt < MAX_RETRIES) {
|
|
1127
|
+
logger.warn(`${vendorLabel}Transport: retryable status ${response.status}, retrying (attempt ${attempt + 1}/${MAX_RETRIES})`);
|
|
1128
|
+
clearTimeout(timeoutId);
|
|
1129
|
+
yield backoff(attempt);
|
|
1130
|
+
continue;
|
|
1131
|
+
}
|
|
1187
1132
|
if (!response.ok) {
|
|
1188
|
-
const
|
|
1189
|
-
|
|
1190
|
-
if (isBudgetRejection(response.status, codeOf(parsed))) {
|
|
1191
|
-
throw budgetExhaustedFrom(vendorLabel, parsed, errText || void 0);
|
|
1192
|
-
}
|
|
1193
|
-
if (retryableStatuses.includes(response.status) && attempt < MAX_RETRIES) {
|
|
1194
|
-
logger.warn(`${vendorLabel}Transport: retryable status ${response.status}, retrying (attempt ${attempt + 1}/${MAX_RETRIES})`);
|
|
1195
|
-
clearTimeout(timeoutId);
|
|
1196
|
-
yield backoff(attempt);
|
|
1197
|
-
continue;
|
|
1198
|
-
}
|
|
1199
|
-
throw new Error(`${vendorLabel} request error ${response.status}: ${errText}`);
|
|
1133
|
+
const err = yield response.text();
|
|
1134
|
+
throw new Error(`${vendorLabel} request error ${response.status}: ${err}`);
|
|
1200
1135
|
}
|
|
1201
1136
|
if (((_b = (_a = response.headers) === null || _a === void 0 ? void 0 : _a.get("content-type")) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes("application/x-ndjson")) && response.body) {
|
|
1202
1137
|
rearmStallTimer();
|
|
@@ -1206,9 +1141,6 @@ function postWithRetry(options) {
|
|
|
1206
1141
|
if (frame.code === "UPSTREAM_STALLED") {
|
|
1207
1142
|
throw new DOMException(`${vendorLabel} request stalled: ${(_c = frame.error) !== null && _c !== void 0 ? _c : "no upstream data"}`, "TimeoutError");
|
|
1208
1143
|
}
|
|
1209
|
-
if (isBudgetRejection(frame.status, frame.code)) {
|
|
1210
|
-
throw budgetExhaustedFrom(vendorLabel, frame);
|
|
1211
|
-
}
|
|
1212
1144
|
if (retryableStatuses.includes(frame.status) && attempt < MAX_RETRIES) {
|
|
1213
1145
|
logger.warn(`${vendorLabel}Transport: retryable status ${frame.status} (err frame), retrying (attempt ${attempt + 1}/${MAX_RETRIES})`);
|
|
1214
1146
|
clearTimeout(timeoutId);
|
|
@@ -1671,7 +1603,7 @@ ${att.content}` });
|
|
|
1671
1603
|
headers: requestHeaders,
|
|
1672
1604
|
body,
|
|
1673
1605
|
credentials,
|
|
1674
|
-
vendorLabel:
|
|
1606
|
+
vendorLabel: "Anthropic",
|
|
1675
1607
|
retryableStatuses: _AnthropicTransport.RETRYABLE_STATUSES,
|
|
1676
1608
|
timeout: this.timeout,
|
|
1677
1609
|
stallTimeout: this.stallTimeout,
|
|
@@ -2320,7 +2252,7 @@ ${att.content}`
|
|
|
2320
2252
|
headers,
|
|
2321
2253
|
body: payload,
|
|
2322
2254
|
credentials,
|
|
2323
|
-
vendorLabel:
|
|
2255
|
+
vendorLabel: "Gemini",
|
|
2324
2256
|
retryableStatuses: _GeminiTransport.RETRYABLE_STATUSES,
|
|
2325
2257
|
timeout: this.timeout,
|
|
2326
2258
|
stallTimeout: this.stallTimeout,
|
|
@@ -3022,19 +2954,6 @@ The above summarizes earlier parts of this conversation that were compacted. Con
|
|
|
3022
2954
|
var TOOL_FOLD_SYMBOL = Symbol("toolFold");
|
|
3023
2955
|
|
|
3024
2956
|
// src/components/chat-driver/chat-driver.ts
|
|
3025
|
-
var budgetDetailOf = (e) => {
|
|
3026
|
-
const vendor = vendorTypeOfLabel(e.vendorLabel) ?? vendorTypeOfLabel(e.serverVendor);
|
|
3027
|
-
if (e.budgetUsd == null && e.spentUsd == null && !vendor) return void 0;
|
|
3028
|
-
return {
|
|
3029
|
-
budgetUsd: e.budgetUsd,
|
|
3030
|
-
spentUsd: e.spentUsd,
|
|
3031
|
-
vendorLabel: e.vendorLabel,
|
|
3032
|
-
...vendor ? { vendor } : {},
|
|
3033
|
-
// Server-known truth the client cannot re-derive, so it rides all the way to
|
|
3034
|
-
// the banner rather than being re-guessed there from registry membership.
|
|
3035
|
-
...e.otherVendorAvailable != null ? { otherVendorAvailable: e.otherVendorAvailable } : {}
|
|
3036
|
-
};
|
|
3037
|
-
};
|
|
3038
2957
|
var DEFAULT_MAX_TOOL_ITERATIONS = 50;
|
|
3039
2958
|
var DEFAULT_MAX_FOLD_OPERATIONS = 5;
|
|
3040
2959
|
var DEFAULT_MAX_TURN_SNAPSHOTS = 400;
|
|
@@ -3217,22 +3136,6 @@ var ChatDriver = class _ChatDriver extends EventTarget {
|
|
|
3217
3136
|
* picked up on the next turn.
|
|
3218
3137
|
*/
|
|
3219
3138
|
this.resolvedStatusCache = /* @__PURE__ */ new Map();
|
|
3220
|
-
/**
|
|
3221
|
-
* Set the moment a budget wall is observed anywhere in this turn — this
|
|
3222
|
-
* driver's own 402, or a sub-agent's (which surfaces here only as a
|
|
3223
|
-
* `'budget_exhausted'` tool result). Read at the top of the tool loop to end
|
|
3224
|
-
* the turn before issuing another model call that would hit the same wall.
|
|
3225
|
-
* Reset per turn alongside the other per-turn counters.
|
|
3226
|
-
*/
|
|
3227
|
-
this.budgetExhaustedThisTurn = false;
|
|
3228
|
-
/**
|
|
3229
|
-
* Whether this turn's budget wall came from a SUB-AGENT rather than this
|
|
3230
|
-
* driver's own request. Decides whether `lastResolvedProvider` is a valid
|
|
3231
|
-
* attribution fallback: for an own wall it is the refusing vendor, for a
|
|
3232
|
-
* child's wall it is the parent's vendor — the one known NOT to have refused.
|
|
3233
|
-
* Reset per turn alongside `budgetWallDetail`.
|
|
3234
|
-
*/
|
|
3235
|
-
this.budgetWallViaSubAgent = false;
|
|
3236
3139
|
const {
|
|
3237
3140
|
toolHandlers = {},
|
|
3238
3141
|
toolDefinitions = [],
|
|
@@ -3242,13 +3145,11 @@ var ChatDriver = class _ChatDriver extends EventTarget {
|
|
|
3242
3145
|
maxFoldOperations = DEFAULT_MAX_FOLD_OPERATIONS,
|
|
3243
3146
|
maxTurnSnapshots = DEFAULT_MAX_TURN_SNAPSHOTS,
|
|
3244
3147
|
sessionKey = "",
|
|
3245
|
-
activityBus = NOOP_ACTIVITY_BUS
|
|
3246
|
-
budgetExhaustedMessage = DEFAULT_BUDGET_EXHAUSTED_MESSAGE
|
|
3148
|
+
activityBus = NOOP_ACTIVITY_BUS
|
|
3247
3149
|
} = config;
|
|
3248
3150
|
this.maxToolIterations = maxToolIterations;
|
|
3249
3151
|
this.sessionKey = sessionKey;
|
|
3250
3152
|
this.activityBus = activityBus;
|
|
3251
|
-
this.budgetExhaustedMessage = budgetExhaustedMessage;
|
|
3252
3153
|
if (typeof toolHandlers === "function") {
|
|
3253
3154
|
this.toolHandlersFactory = toolHandlers;
|
|
3254
3155
|
this.toolHandlers = {};
|
|
@@ -3355,56 +3256,8 @@ var ChatDriver = class _ChatDriver extends EventTarget {
|
|
|
3355
3256
|
* (rather than set to `undefined`) so a happy-path result stays byte-identical to
|
|
3356
3257
|
* the historical `{ reason: 'done' }`.
|
|
3357
3258
|
*/
|
|
3358
|
-
turnDone(failureReason
|
|
3359
|
-
|
|
3360
|
-
return budget ? { reason: "done", failureReason, budget } : { reason: "done", failureReason };
|
|
3361
|
-
}
|
|
3362
|
-
/**
|
|
3363
|
-
* Terminal budget outcome for a wall hit **outside** the tool loop — today,
|
|
3364
|
-
* `OrchestratingDriver`'s classification phase, which calls the provider
|
|
3365
|
-
* directly and so never enters `runToolLoop`.
|
|
3366
|
-
*
|
|
3367
|
-
* Does **not** publish `tool-loop-end`: no `tool-loop-start` was published for
|
|
3368
|
-
* the classify phase, and an unbalanced end would break start/end pairing for
|
|
3369
|
-
* subscribers that rely on it. The driver **return value** is what reports this
|
|
3370
|
-
* case — see `FoundationAiAssistant`'s latch, which reads both seams for
|
|
3371
|
-
* exactly this reason.
|
|
3372
|
-
*
|
|
3373
|
-
* The non-sub-agent tail of the in-loop `BudgetExhaustedError` branch lives
|
|
3374
|
-
* here so there is one copy of the log line, the debug-log entry, the
|
|
3375
|
-
* transcript bubble and the result shape rather than two that can drift.
|
|
3376
|
-
*
|
|
3377
|
-
* @param pendingUserMessage - a user message that has NOT yet been appended,
|
|
3378
|
-
* appended first so the answer does not end up replying to nothing. Only the
|
|
3379
|
-
* classification seam passes it: `OrchestratingDriver` dispatches the user's
|
|
3380
|
-
* text as an optimistic `history-updated` detail and leaves the real append
|
|
3381
|
-
* to `chatDriver.sendMessage`, which never runs when `classify()` throws — so
|
|
3382
|
-
* the bubble below would re-dispatch a history the user's own message was
|
|
3383
|
-
* never in, and it would vanish from the transcript on the next render. The
|
|
3384
|
-
* in-loop caller has already appended it and passes nothing.
|
|
3385
|
-
*
|
|
3386
|
-
* @internal
|
|
3387
|
-
*/
|
|
3388
|
-
reportBudgetExhausted(e, pendingUserMessage) {
|
|
3389
|
-
if (pendingUserMessage) this.appendToHistory(pendingUserMessage);
|
|
3390
|
-
this.budgetExhaustedThisTurn = true;
|
|
3391
|
-
logger2.error("ChatDriver: AI budget exhausted", e);
|
|
3392
|
-
recordTurnError(this.sessionKey, "budget-exhausted", {
|
|
3393
|
-
agent: this.activeAgentName,
|
|
3394
|
-
provider: this.lastResolvedProviderName,
|
|
3395
|
-
// The registry ALIAS (e.g. 'high') is what `provider` records; the vendor
|
|
3396
|
-
// is the thing a per-vendor budget is actually scoped to, and it was known
|
|
3397
|
-
// at both ends and discarded in the middle until now. Taken from the
|
|
3398
|
-
// refusing transport's label first — this method also serves the
|
|
3399
|
-
// classification seam, where `lastResolvedProvider` is the PREVIOUS turn's
|
|
3400
|
-
// vendor (or nothing), because classify runs against the registry default.
|
|
3401
|
-
vendor: vendorTypeOfLabel(e.vendorLabel) ?? vendorTypeOfLabel(e.serverVendor) ?? this.lastResolvedProvider,
|
|
3402
|
-
budgetUsd: e.budgetUsd,
|
|
3403
|
-
spentUsd: e.spentUsd,
|
|
3404
|
-
isSubAgent: this.isSubAgent
|
|
3405
|
-
});
|
|
3406
|
-
this.appendToHistory({ role: "assistant", content: this.budgetExhaustedMessage });
|
|
3407
|
-
return this.turnDone("budget-exhausted", budgetDetailOf(e));
|
|
3259
|
+
turnDone(failureReason) {
|
|
3260
|
+
return failureReason ? { reason: "done", failureReason } : { reason: "done" };
|
|
3408
3261
|
}
|
|
3409
3262
|
/** The typed failure reason on a loop result, or `undefined` for a clean turn / handoff. */
|
|
3410
3263
|
static failureReasonOf(result) {
|
|
@@ -3414,28 +3267,10 @@ var ChatDriver = class _ChatDriver extends EventTarget {
|
|
|
3414
3267
|
* Build the `tool-loop-end` event detail for a turn's result. A failure carries a
|
|
3415
3268
|
* `{ failureReason }` detail; a clean turn emits `undefined` — the historical shape,
|
|
3416
3269
|
* kept byte-identical so subscribers see exactly what they always have.
|
|
3417
|
-
*
|
|
3418
|
-
* A budget failure additionally carries `vendor` — the concrete vendor
|
|
3419
|
-
* (`'anthropic'`/`'gemini'`) the walled turn resolved to, which the driver knows
|
|
3420
|
-
* and used to discard. Optional and additive: a subscriber reading only
|
|
3421
|
-
* `failureReason` is unaffected, a non-budget failure still emits the historical
|
|
3422
|
-
* `{ failureReason }` with no `vendor` key, and the value is a plain string so
|
|
3423
|
-
* the detail stays structured-cloneable for the cross-tab hop. It is the field a
|
|
3424
|
-
* per-vendor budget model needs and the one that would be awkward to retrofit.
|
|
3425
3270
|
*/
|
|
3426
|
-
loopEndDetail(result) {
|
|
3271
|
+
static loopEndDetail(result) {
|
|
3427
3272
|
const failureReason = _ChatDriver.failureReasonOf(result);
|
|
3428
|
-
|
|
3429
|
-
if (failureReason !== "budget-exhausted") {
|
|
3430
|
-
return { failureReason };
|
|
3431
|
-
}
|
|
3432
|
-
const budget = result.reason === "done" ? result.budget : void 0;
|
|
3433
|
-
const vendor = budget?.vendor ?? (this.budgetWallViaSubAgent ? void 0 : this.lastResolvedProvider);
|
|
3434
|
-
return {
|
|
3435
|
-
failureReason,
|
|
3436
|
-
...vendor ? { vendor } : {},
|
|
3437
|
-
...budget ? { budget } : {}
|
|
3438
|
-
};
|
|
3273
|
+
return failureReason ? { failureReason } : void 0;
|
|
3439
3274
|
}
|
|
3440
3275
|
/**
|
|
3441
3276
|
* Swap in a new agent's configuration. Called by OrchestratingDriver before
|
|
@@ -3621,9 +3456,9 @@ var ChatDriver = class _ChatDriver extends EventTarget {
|
|
|
3621
3456
|
* under a separate session key, so recording here would orphan the event off
|
|
3622
3457
|
* the user-visible debug-log timeline.)
|
|
3623
3458
|
*/
|
|
3624
|
-
failSubAgent(reason
|
|
3459
|
+
failSubAgent(reason) {
|
|
3625
3460
|
if (!this.isSubAgent || this.subAgentFailure) return;
|
|
3626
|
-
this.subAgentFailure =
|
|
3461
|
+
this.subAgentFailure = { reason };
|
|
3627
3462
|
}
|
|
3628
3463
|
/**
|
|
3629
3464
|
* Returns true if `releaseAgent` was called during the most recent turn.
|
|
@@ -4068,9 +3903,6 @@ Output format (strict):
|
|
|
4068
3903
|
this.subAgentCompletion = void 0;
|
|
4069
3904
|
this.subAgentFailure = void 0;
|
|
4070
3905
|
this.agentReleaseRequested = false;
|
|
4071
|
-
this.budgetExhaustedThisTurn = false;
|
|
4072
|
-
this.budgetWallDetail = void 0;
|
|
4073
|
-
this.budgetWallViaSubAgent = false;
|
|
4074
3906
|
this.appendToHistory({ role: "user", content: userInput, attachments });
|
|
4075
3907
|
this.turnStartedAt = Date.now();
|
|
4076
3908
|
recordMetaEvent(this.sessionKey, "turn.start", {
|
|
@@ -4105,7 +3937,7 @@ Output format (strict):
|
|
|
4105
3937
|
});
|
|
4106
3938
|
this.busy = false;
|
|
4107
3939
|
this.endTurn();
|
|
4108
|
-
this.activityBus.publish("tool-loop-end",
|
|
3940
|
+
this.activityBus.publish("tool-loop-end", _ChatDriver.loopEndDetail(result));
|
|
4109
3941
|
}
|
|
4110
3942
|
}
|
|
4111
3943
|
/**
|
|
@@ -4296,14 +4128,8 @@ Output format (strict):
|
|
|
4296
4128
|
recordMetaEvent(this.sessionKey, "subagent.completed", { agent: name });
|
|
4297
4129
|
return { outcome: { ok: true, result: completion.result }, trace };
|
|
4298
4130
|
}
|
|
4299
|
-
const
|
|
4300
|
-
const reason = failure?.reason ?? "max_iterations";
|
|
4131
|
+
const reason = child.getSubAgentFailure()?.reason ?? "max_iterations";
|
|
4301
4132
|
recordMetaEvent(this.sessionKey, "subagent.failed", { agent: name, reason });
|
|
4302
|
-
if (reason === "budget_exhausted") {
|
|
4303
|
-
this.budgetExhaustedThisTurn = true;
|
|
4304
|
-
this.budgetWallViaSubAgent = true;
|
|
4305
|
-
this.budgetWallDetail ??= failure?.budget;
|
|
4306
|
-
}
|
|
4307
4133
|
return { outcome: { ok: false, reason }, trace };
|
|
4308
4134
|
}
|
|
4309
4135
|
/**
|
|
@@ -4316,9 +4142,6 @@ Output format (strict):
|
|
|
4316
4142
|
this.beginTurn();
|
|
4317
4143
|
this.subAgentCompletion = void 0;
|
|
4318
4144
|
this.subAgentFailure = void 0;
|
|
4319
|
-
this.budgetExhaustedThisTurn = false;
|
|
4320
|
-
this.budgetWallDetail = void 0;
|
|
4321
|
-
this.budgetWallViaSubAgent = false;
|
|
4322
4145
|
this.turnStartedAt = Date.now();
|
|
4323
4146
|
recordMetaEvent(this.sessionKey, "turn.start", {
|
|
4324
4147
|
phase: "continueFromHistory",
|
|
@@ -4352,7 +4175,7 @@ Output format (strict):
|
|
|
4352
4175
|
});
|
|
4353
4176
|
this.busy = false;
|
|
4354
4177
|
this.endTurn();
|
|
4355
|
-
this.activityBus.publish("tool-loop-end",
|
|
4178
|
+
this.activityBus.publish("tool-loop-end", _ChatDriver.loopEndDetail(result));
|
|
4356
4179
|
}
|
|
4357
4180
|
}
|
|
4358
4181
|
// ---------------------------------------------------------------------------
|
|
@@ -4506,31 +4329,6 @@ Output format (strict):
|
|
|
4506
4329
|
if (this.turnController.signal.aborted) {
|
|
4507
4330
|
return this.completeAbortedTurn();
|
|
4508
4331
|
}
|
|
4509
|
-
if (this.budgetExhaustedThisTurn) {
|
|
4510
|
-
logger2.error("ChatDriver: ending the turn \u2014 a sub-agent hit the AI budget wall");
|
|
4511
|
-
recordTurnError(this.sessionKey, "budget-exhausted", {
|
|
4512
|
-
agent: this.activeAgentName,
|
|
4513
|
-
provider: this.lastResolvedProviderName,
|
|
4514
|
-
// The CHILD's vendor when it knew one, and NOTHING otherwise. On this
|
|
4515
|
-
// path the wall is definitionally the child's, and on a mixed registry
|
|
4516
|
-
// `lastResolvedProvider` is this driver's own vendor — the one known
|
|
4517
|
-
// NOT to have refused. An unattributable child wall must degrade to
|
|
4518
|
-
// the vendor-agnostic block (which `latchBlockedFrom` handles
|
|
4519
|
-
// fail-safe), never to a vendor that is known to be wrong: naming the
|
|
4520
|
-
// parent's vendor here walled BOTH — the child's via its own
|
|
4521
|
-
// tool-loop-end, the parent's via this event — and derived `blocked`
|
|
4522
|
-
// over headroom that still existed.
|
|
4523
|
-
vendor: this.budgetWallDetail?.vendor,
|
|
4524
|
-
via: "sub-agent",
|
|
4525
|
-
isSubAgent: this.isSubAgent
|
|
4526
|
-
});
|
|
4527
|
-
if (this.isSubAgent) {
|
|
4528
|
-
this.failSubAgent("budget_exhausted", this.budgetWallDetail);
|
|
4529
|
-
} else {
|
|
4530
|
-
this.appendToHistory({ role: "assistant", content: this.budgetExhaustedMessage });
|
|
4531
|
-
}
|
|
4532
|
-
return this.turnDone("budget-exhausted", this.budgetWallDetail);
|
|
4533
|
-
}
|
|
4534
4332
|
const promptCtx = {
|
|
4535
4333
|
agentName: this.activeAgentName ?? "",
|
|
4536
4334
|
history: this.history,
|
|
@@ -4701,25 +4499,6 @@ ${tailBody}
|
|
|
4701
4499
|
}
|
|
4702
4500
|
return this.turnDone("response-truncated");
|
|
4703
4501
|
}
|
|
4704
|
-
if (e instanceof BudgetExhaustedError) {
|
|
4705
|
-
this.budgetExhaustedThisTurn = true;
|
|
4706
|
-
this.budgetWallDetail = budgetDetailOf(e);
|
|
4707
|
-
this.budgetWallViaSubAgent = false;
|
|
4708
|
-
if (this.isSubAgent) {
|
|
4709
|
-
logger2.error("ChatDriver: AI budget exhausted", e);
|
|
4710
|
-
recordTurnError(this.sessionKey, "budget-exhausted", {
|
|
4711
|
-
agent: this.activeAgentName,
|
|
4712
|
-
provider: this.lastResolvedProviderName,
|
|
4713
|
-
vendor: vendorTypeOfLabel(e.vendorLabel) ?? vendorTypeOfLabel(e.serverVendor) ?? this.lastResolvedProvider,
|
|
4714
|
-
budgetUsd: e.budgetUsd,
|
|
4715
|
-
spentUsd: e.spentUsd,
|
|
4716
|
-
isSubAgent: true
|
|
4717
|
-
});
|
|
4718
|
-
this.failSubAgent("budget_exhausted", this.budgetWallDetail);
|
|
4719
|
-
return this.turnDone("budget-exhausted", this.budgetWallDetail);
|
|
4720
|
-
}
|
|
4721
|
-
return this.reportBudgetExhausted(e);
|
|
4722
|
-
}
|
|
4723
4502
|
if (e instanceof DOMException && e.name === "TimeoutError") {
|
|
4724
4503
|
logger2.error("ChatDriver: request timed out", e);
|
|
4725
4504
|
recordTurnError(this.sessionKey, "exception", {
|
|
@@ -5195,17 +4974,6 @@ var OrchestratingDriver = class extends EventTarget {
|
|
|
5195
4974
|
* user stops. Reset at the start of each `sendMessage`.
|
|
5196
4975
|
*/
|
|
5197
4976
|
this.cancelled = false;
|
|
5198
|
-
/**
|
|
5199
|
-
* Whether the CURRENT turn's user message has reached the inner driver's
|
|
5200
|
-
* history. False through the pre-first-turn classify (where the only echo of
|
|
5201
|
-
* the message is an optimistic `history-updated` dispatch), true from the
|
|
5202
|
-
* moment `chatDriver.sendMessage` is entered — including through every later
|
|
5203
|
-
* handoff classify. Read by the budget-wall catch in `sendMessage` to decide
|
|
5204
|
-
* whether `reportBudgetExhausted` must append the message itself: appending
|
|
5205
|
-
* it when already appended duplicated it; not appending it when unappended
|
|
5206
|
-
* made it vanish. Reset at the top of each `runOrchestratedTurn`.
|
|
5207
|
-
*/
|
|
5208
|
-
this.userMessageAppended = false;
|
|
5209
4977
|
/**
|
|
5210
4978
|
* Sticky user pick from the picker (or the host's `setAgent` API). Only
|
|
5211
4979
|
* changes on explicit user action. Survives flow completion: when a stateful
|
|
@@ -5247,8 +5015,7 @@ var OrchestratingDriver = class extends EventTarget {
|
|
|
5247
5015
|
maxFoldOperations: options.maxFoldOperations,
|
|
5248
5016
|
maxTurnSnapshots: options.maxTurnSnapshots,
|
|
5249
5017
|
sessionKey: this.sessionKey,
|
|
5250
|
-
activityBus: options.activityBus
|
|
5251
|
-
budgetExhaustedMessage: options.budgetExhaustedMessage
|
|
5018
|
+
activityBus: options.activityBus
|
|
5252
5019
|
});
|
|
5253
5020
|
this.chatDriver.addEventListener("history-updated", (e) => {
|
|
5254
5021
|
this.dispatchEvent(new CustomEvent("history-updated", { detail: e.detail }));
|
|
@@ -5347,25 +5114,7 @@ var OrchestratingDriver = class extends EventTarget {
|
|
|
5347
5114
|
return this.chatDriver.getSuggestions(history, prompt2, count, agentInfo);
|
|
5348
5115
|
}
|
|
5349
5116
|
async sendMessage(input, attachments) {
|
|
5350
|
-
try {
|
|
5351
|
-
return await this.runOrchestratedTurn(input, attachments);
|
|
5352
|
-
} catch (e) {
|
|
5353
|
-
if (e instanceof BudgetExhaustedError) {
|
|
5354
|
-
return this.chatDriver.reportBudgetExhausted(
|
|
5355
|
-
e,
|
|
5356
|
-
this.userMessageAppended ? void 0 : {
|
|
5357
|
-
role: "user",
|
|
5358
|
-
content: input,
|
|
5359
|
-
...attachments ? { attachments } : {}
|
|
5360
|
-
}
|
|
5361
|
-
);
|
|
5362
|
-
}
|
|
5363
|
-
throw e;
|
|
5364
|
-
}
|
|
5365
|
-
}
|
|
5366
|
-
async runOrchestratedTurn(input, attachments) {
|
|
5367
5117
|
this.cancelled = false;
|
|
5368
|
-
this.userMessageAppended = false;
|
|
5369
5118
|
const history = this.chatDriver.getHistory();
|
|
5370
5119
|
this.dispatchEvent(
|
|
5371
5120
|
new CustomEvent("history-updated", {
|
|
@@ -5379,7 +5128,6 @@ var OrchestratingDriver = class extends EventTarget {
|
|
|
5379
5128
|
let handoffs = 0;
|
|
5380
5129
|
let handoffSummary = "";
|
|
5381
5130
|
let remainingTask = "";
|
|
5382
|
-
let lastResult;
|
|
5383
5131
|
while (true) {
|
|
5384
5132
|
if (this.cancelled) break;
|
|
5385
5133
|
await this.applyAgent(currentAgent);
|
|
@@ -5388,10 +5136,8 @@ var OrchestratingDriver = class extends EventTarget {
|
|
|
5388
5136
|
const contextPrimer = handoffSummary ? [{ role: "user", content: `[Context from previous agent]: ${handoffSummary}` }] : [];
|
|
5389
5137
|
result = await this.chatDriver.continueFromHistory(contextPrimer);
|
|
5390
5138
|
} else {
|
|
5391
|
-
this.userMessageAppended = true;
|
|
5392
5139
|
result = await this.chatDriver.sendMessage(input, attachments);
|
|
5393
5140
|
}
|
|
5394
|
-
lastResult = result;
|
|
5395
5141
|
if (this.chatDriver.getAgentReleaseRequested()) {
|
|
5396
5142
|
await this.releaseActiveAgent();
|
|
5397
5143
|
break;
|
|
@@ -5413,7 +5159,7 @@ var OrchestratingDriver = class extends EventTarget {
|
|
|
5413
5159
|
this.dispatchEvent(new CustomEvent("orchestrating-start"));
|
|
5414
5160
|
currentAgent = await this.classify(remainingTask, updatedHistory);
|
|
5415
5161
|
}
|
|
5416
|
-
return
|
|
5162
|
+
return { reason: "done" };
|
|
5417
5163
|
}
|
|
5418
5164
|
async continueFromHistory(transientPrimer) {
|
|
5419
5165
|
return this.chatDriver.continueFromHistory(transientPrimer);
|
|
@@ -5596,7 +5342,6 @@ ${recentMessages}` : ""}`;
|
|
|
5596
5342
|
}
|
|
5597
5343
|
}
|
|
5598
5344
|
};
|
|
5599
|
-
let routedNoMatch = false;
|
|
5600
5345
|
for (let attempt = 0; attempt <= this.classifierRetries; attempt += 1) {
|
|
5601
5346
|
try {
|
|
5602
5347
|
const options = {
|
|
@@ -5616,10 +5361,8 @@ ${recentMessages}` : ""}`;
|
|
|
5616
5361
|
if (index >= 0 && index < this.specialists.length) {
|
|
5617
5362
|
return this.specialists[index];
|
|
5618
5363
|
}
|
|
5619
|
-
routedNoMatch = true;
|
|
5620
5364
|
break;
|
|
5621
5365
|
} catch (e) {
|
|
5622
|
-
if (e instanceof BudgetExhaustedError) throw e;
|
|
5623
5366
|
logger2.warn(`OrchestratingDriver: classifier attempt ${attempt + 1} failed:`, e);
|
|
5624
5367
|
if (attempt === this.classifierRetries) {
|
|
5625
5368
|
logger2.error("OrchestratingDriver: classifier failed after all retries, using fallback");
|
|
@@ -5627,12 +5370,10 @@ ${recentMessages}` : ""}`;
|
|
|
5627
5370
|
}
|
|
5628
5371
|
}
|
|
5629
5372
|
if (this.fallback) return this.fallback;
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
);
|
|
5635
|
-
}
|
|
5373
|
+
const specialistNames = this.specialists.map((s) => s.name).join(", ");
|
|
5374
|
+
this.appendInlineMessage(
|
|
5375
|
+
`I'm not sure how to help with that. I can assist with: ${specialistNames}.`
|
|
5376
|
+
);
|
|
5636
5377
|
return this.specialists[0];
|
|
5637
5378
|
}
|
|
5638
5379
|
/**
|