@genesislcap/ai-assistant 14.421.1 → 14.422.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 +60 -0
- package/dist/dts/components/chat-driver/chat-driver.d.ts +33 -0
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts.map +1 -1
- package/dist/dts/config/config.d.ts +20 -0
- package/dist/dts/config/config.d.ts.map +1 -1
- package/dist/dts/main/main.d.ts +6 -0
- package/dist/dts/main/main.d.ts.map +1 -1
- package/dist/dts/main/main.styles.d.ts.map +1 -1
- package/dist/dts/main/main.template.d.ts +16 -0
- package/dist/dts/main/main.template.d.ts.map +1 -1
- package/dist/dts/state/ai-assistant-slice.d.ts +6 -0
- package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
- package/dist/dts/state/session-store.d.ts +2 -0
- package/dist/dts/state/session-store.d.ts.map +1 -1
- package/dist/dts/utils/history-transform.d.ts +13 -0
- package/dist/dts/utils/history-transform.d.ts.map +1 -0
- package/dist/esm/components/chat-driver/chat-driver.js +127 -16
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +8 -20
- package/dist/esm/config/config.js +18 -1
- package/dist/esm/main/main.js +43 -11
- package/dist/esm/main/main.styles.js +62 -0
- package/dist/esm/main/main.template.js +122 -71
- package/dist/esm/state/ai-assistant-slice.js +8 -0
- package/dist/esm/utils/history-transform.js +35 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/sub_agent.md +149 -211
- package/package.json +16 -16
- package/src/components/chat-driver/chat-driver.ts +169 -15
- package/src/components/orchestrating-driver/orchestrating-driver.ts +10 -22
- package/src/config/config.ts +24 -0
- package/src/main/main.styles.ts +62 -0
- package/src/main/main.template.ts +189 -117
- package/src/main/main.ts +43 -9
- package/src/state/ai-assistant-slice.ts +12 -0
- package/src/utils/history-transform.ts +40 -0
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
2
|
import { MalformedFunctionCallError } from '@genesislcap/foundation-ai';
|
|
3
|
+
import { applyHistoryCap } from '../../utils/history-transform';
|
|
3
4
|
import { logger } from '../../utils/logger';
|
|
4
5
|
import { TOOL_FOLD_SYMBOL } from '../../utils/tool-fold';
|
|
5
6
|
const DEFAULT_MAX_TOOL_ITERATIONS = 50;
|
|
6
7
|
const DEFAULT_MAX_FOLD_OPERATIONS = 5;
|
|
7
8
|
const DEFAULT_MAX_UNKNOWN_TOOL_CALLS = 5;
|
|
8
9
|
const MAX_MALFORMED_RETRIES = 2;
|
|
10
|
+
const MAX_EMPTY_RESPONSE_RETRIES = 3;
|
|
9
11
|
const SUGGESTIONS_HISTORY_WINDOW = 8;
|
|
10
12
|
/** Name reserved for the cross-agent handoff tool — injected by OrchestratingDriver. */
|
|
11
13
|
export const REQUEST_CONTINUATION_TOOL = 'request_continuation';
|
|
@@ -35,6 +37,8 @@ export class ChatDriver extends EventTarget {
|
|
|
35
37
|
this.consecutiveFoldOps = 0;
|
|
36
38
|
/** Consecutive unknown-tool calls without a real tool call. Reset on real tool execution. */
|
|
37
39
|
this.consecutiveUnknownToolCalls = 0;
|
|
40
|
+
/** Sub-agents declared on the active agent config, keyed by name. */
|
|
41
|
+
this.subAgentsMap = new Map();
|
|
38
42
|
this.toolHandlers = toolHandlers;
|
|
39
43
|
this.toolDefinitions = toolDefinitions;
|
|
40
44
|
this.systemPrompt = systemPrompt;
|
|
@@ -46,16 +50,24 @@ export class ChatDriver extends EventTarget {
|
|
|
46
50
|
* each specialist turn so the shared driver runs with the right tools and prompt.
|
|
47
51
|
*/
|
|
48
52
|
applyAgent(config) {
|
|
49
|
-
var _a, _b;
|
|
53
|
+
var _a, _b, _c;
|
|
50
54
|
this.systemPrompt = config.systemPrompt;
|
|
51
55
|
this.toolDefinitions = (_a = config.toolDefinitions) !== null && _a !== void 0 ? _a : [];
|
|
52
56
|
this.toolHandlers = (_b = config.toolHandlers) !== null && _b !== void 0 ? _b : {};
|
|
53
57
|
this.primerHistory = config.primerHistory;
|
|
54
58
|
this.activeAgentName = config.name;
|
|
59
|
+
this.subAgentsMap = new Map(((_c = config.subAgents) !== null && _c !== void 0 ? _c : []).map((s) => [s.name, s]));
|
|
55
60
|
// Reset fold state when agent changes — each specialist starts fresh
|
|
56
61
|
this.foldStack = [];
|
|
57
62
|
this.consecutiveFoldOps = 0;
|
|
58
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns the early-stop result set by `completeSubAgent`, if any.
|
|
66
|
+
* Called by a parent `ChatDriver` after running this instance as a sub-agent.
|
|
67
|
+
*/
|
|
68
|
+
getSubAgentCompletion() {
|
|
69
|
+
return this.subAgentCompletion;
|
|
70
|
+
}
|
|
59
71
|
/**
|
|
60
72
|
* Optional transform applied to conversation history immediately before each LLM request.
|
|
61
73
|
* Cleared when `undefined`. Does not alter stored history.
|
|
@@ -212,6 +224,7 @@ export class ChatDriver extends EventTarget {
|
|
|
212
224
|
return { reason: 'done' };
|
|
213
225
|
}
|
|
214
226
|
this.busy = true;
|
|
227
|
+
this.subAgentCompletion = undefined;
|
|
215
228
|
this.appendToHistory({ role: 'user', content: userInput, attachments });
|
|
216
229
|
try {
|
|
217
230
|
return yield this.runToolLoop(userInput, attachments);
|
|
@@ -226,6 +239,89 @@ export class ChatDriver extends EventTarget {
|
|
|
226
239
|
}
|
|
227
240
|
});
|
|
228
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* Builds the context object passed to every tool handler call.
|
|
244
|
+
* Centralised here so fold shortcut dispatch and the main tool loop use the
|
|
245
|
+
* same context without duplication.
|
|
246
|
+
*
|
|
247
|
+
* @param traceCapture - Optional per-invocation slot. When provided, the trace
|
|
248
|
+
* from any sub-agent call is written here rather than to shared instance state,
|
|
249
|
+
* so parallel tool calls each capture their own trace independently.
|
|
250
|
+
*/
|
|
251
|
+
buildHandlerContext(traceCapture) {
|
|
252
|
+
return Object.assign(Object.assign({ requestInteraction: (componentName, data) => this.requestInteraction(componentName, data) }, (this.subAgentsMap.size > 0 && {
|
|
253
|
+
requestSubAgent: (name, options) => this.invokeSubAgent(name, options).then(({ result, trace }) => {
|
|
254
|
+
if (traceCapture)
|
|
255
|
+
traceCapture.trace = trace;
|
|
256
|
+
return result;
|
|
257
|
+
}),
|
|
258
|
+
})), { completeSubAgent: (result) => {
|
|
259
|
+
var _a;
|
|
260
|
+
if (this.subAgentCompletion) {
|
|
261
|
+
logger.warn(`ChatDriver(${(_a = this.activeAgentName) !== null && _a !== void 0 ? _a : 'unknown'}): completeSubAgent called more than once — ignoring`);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
this.subAgentCompletion = { result };
|
|
265
|
+
} });
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Creates a child `ChatDriver` for the named sub-agent, runs it to completion,
|
|
269
|
+
* and returns its structured result (or final text fallback) together with the
|
|
270
|
+
* full child conversation trace. Callers receive both values so each parallel
|
|
271
|
+
* invocation can capture its own trace without touching shared instance state.
|
|
272
|
+
*/
|
|
273
|
+
invokeSubAgent(name, options) {
|
|
274
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
275
|
+
var _a, _b, _c;
|
|
276
|
+
const subConfig = this.subAgentsMap.get(name);
|
|
277
|
+
if (!subConfig) {
|
|
278
|
+
const available = [...this.subAgentsMap.keys()].join(', ') || '(none)';
|
|
279
|
+
throw new Error(`Sub-agent "${name}" not found on agent "${this.activeAgentName}". Available: ${available}`);
|
|
280
|
+
}
|
|
281
|
+
const { task, historyCap, context } = options !== null && options !== void 0 ? options : {};
|
|
282
|
+
// Exclude the current in-flight assistant message (the one with tool calls that
|
|
283
|
+
// triggered this invocation) — it has unresolved tool calls that would confuse
|
|
284
|
+
// the sub-agent into thinking it needs to handle tools it doesn't own.
|
|
285
|
+
const lastMsg = this.history[this.history.length - 1];
|
|
286
|
+
const baseHistory = (lastMsg === null || lastMsg === void 0 ? void 0 : lastMsg.role) === 'assistant' && ((_a = lastMsg.toolCalls) === null || _a === void 0 ? void 0 : _a.length)
|
|
287
|
+
? this.history.slice(0, -1)
|
|
288
|
+
: this.history;
|
|
289
|
+
const snapshotHistory = historyCap != null ? applyHistoryCap(baseHistory, historyCap) : [...baseHistory];
|
|
290
|
+
const contextMessages = context
|
|
291
|
+
? [{ role: 'user', content: `[Sub-agent context]: ${JSON.stringify(context)}` }]
|
|
292
|
+
: [];
|
|
293
|
+
const effectivePrimer = [
|
|
294
|
+
...snapshotHistory,
|
|
295
|
+
...contextMessages,
|
|
296
|
+
...((_b = subConfig.primerHistory) !== null && _b !== void 0 ? _b : []),
|
|
297
|
+
];
|
|
298
|
+
const child = new ChatDriver(this.aiProvider);
|
|
299
|
+
child.applyAgent(Object.assign(Object.assign({}, subConfig), { primerHistory: effectivePrimer }));
|
|
300
|
+
const forwardTrace = (e) => {
|
|
301
|
+
this.dispatchEvent(new CustomEvent('sub-agent-history-updated', {
|
|
302
|
+
detail: { agentName: subConfig.name, history: e.detail },
|
|
303
|
+
}));
|
|
304
|
+
};
|
|
305
|
+
child.addEventListener('history-updated', forwardTrace);
|
|
306
|
+
this.dispatchEvent(new CustomEvent('sub-agent-start', { detail: { name } }));
|
|
307
|
+
try {
|
|
308
|
+
yield child.sendMessage(task !== null && task !== void 0 ? task : '');
|
|
309
|
+
}
|
|
310
|
+
finally {
|
|
311
|
+
child.removeEventListener('history-updated', forwardTrace);
|
|
312
|
+
this.dispatchEvent(new CustomEvent('sub-agent-stop', { detail: { name } }));
|
|
313
|
+
}
|
|
314
|
+
const trace = child.getHistory();
|
|
315
|
+
const completion = child.getSubAgentCompletion();
|
|
316
|
+
if (completion) {
|
|
317
|
+
return { result: completion.result, trace };
|
|
318
|
+
}
|
|
319
|
+
const finalMsg = [...trace]
|
|
320
|
+
.reverse()
|
|
321
|
+
.find((m) => { var _a, _b; return m.role === 'assistant' && !((_a = m.toolCalls) === null || _a === void 0 ? void 0 : _a.length) && ((_b = m.content) === null || _b === void 0 ? void 0 : _b.trim()); });
|
|
322
|
+
return { result: ((_c = finalMsg === null || finalMsg === void 0 ? void 0 : finalMsg.content) !== null && _c !== void 0 ? _c : ''), trace };
|
|
323
|
+
});
|
|
324
|
+
}
|
|
229
325
|
/**
|
|
230
326
|
* Continue the tool loop from current history without appending a new user message.
|
|
231
327
|
* Used by OrchestratingDriver after an agent handoff.
|
|
@@ -239,6 +335,7 @@ export class ChatDriver extends EventTarget {
|
|
|
239
335
|
return { reason: 'done' };
|
|
240
336
|
}
|
|
241
337
|
this.busy = true;
|
|
338
|
+
this.subAgentCompletion = undefined;
|
|
242
339
|
try {
|
|
243
340
|
return yield this.runToolLoop('', undefined, transientPrimer);
|
|
244
341
|
}
|
|
@@ -327,9 +424,7 @@ export class ChatDriver extends EventTarget {
|
|
|
327
424
|
const innerArgs = typeof args[key] === 'object' && args[key] !== null
|
|
328
425
|
? args[key]
|
|
329
426
|
: {};
|
|
330
|
-
return innerHandler(innerArgs,
|
|
331
|
-
requestInteraction: (c, d) => this.requestInteraction(c, d),
|
|
332
|
-
}).then((r) => (typeof r === 'string' ? r : JSON.stringify(r)));
|
|
427
|
+
return innerHandler(innerArgs, this.buildHandlerContext()).then((r) => typeof r === 'string' ? r : JSON.stringify(r));
|
|
333
428
|
}
|
|
334
429
|
}
|
|
335
430
|
// Normal two-step open
|
|
@@ -395,7 +490,12 @@ export class ChatDriver extends EventTarget {
|
|
|
395
490
|
let currentAttachments = attachments;
|
|
396
491
|
let iterations = 0;
|
|
397
492
|
let malformedAttempts = 0;
|
|
398
|
-
|
|
493
|
+
let emptyResponseAttempts = 0;
|
|
494
|
+
// True only for the very first LLM call. Used to exclude the pending user message
|
|
495
|
+
// from history (it is passed separately as currentInput). Must not be derived from
|
|
496
|
+
// `iterations` because fold operations decrement iterations, which would incorrectly
|
|
497
|
+
// re-trigger the slice on subsequent calls after a fold open/close.
|
|
498
|
+
let firstLlmCall = !!currentInput;
|
|
399
499
|
while (iterations < this.maxToolIterations) {
|
|
400
500
|
iterations += 1;
|
|
401
501
|
const foldSuffix = this.buildFoldSystemPromptSuffix();
|
|
@@ -403,14 +503,17 @@ export class ChatDriver extends EventTarget {
|
|
|
403
503
|
? `${this.systemPrompt}${foldSuffix}`
|
|
404
504
|
: foldSuffix || undefined;
|
|
405
505
|
const primer = [...((_a = this.primerHistory) !== null && _a !== void 0 ? _a : []), ...(transientPrimer !== null && transientPrimer !== void 0 ? transientPrimer : [])];
|
|
406
|
-
const baseHistory =
|
|
506
|
+
const baseHistory = firstLlmCall ? this.history.slice(0, -1) : this.history;
|
|
507
|
+
firstLlmCall = false;
|
|
407
508
|
const historyForProvider = this.providerHistoryTransform
|
|
408
509
|
? this.providerHistoryTransform([...baseHistory])
|
|
409
510
|
: baseHistory;
|
|
410
511
|
const historyForCall = [...primer, ...historyForProvider];
|
|
411
512
|
const systemPrompt = malformedAttempts > 0
|
|
412
513
|
? `${baseSystemPrompt !== null && baseSystemPrompt !== void 0 ? baseSystemPrompt : ''}\n\nIMPORTANT: Use only the structured function-call API to invoke tools. Do not write Python code or use Python-style syntax to call tools.`
|
|
413
|
-
:
|
|
514
|
+
: emptyResponseAttempts > 0
|
|
515
|
+
? `${baseSystemPrompt !== null && baseSystemPrompt !== void 0 ? baseSystemPrompt : ''}\n\nIMPORTANT: You must respond to the user's message. Call the appropriate tool or provide a text response — do not return an empty response.`
|
|
516
|
+
: baseSystemPrompt;
|
|
414
517
|
const options = {
|
|
415
518
|
systemPrompt,
|
|
416
519
|
// Strip fold-only properties (foldEvent, foldPath) before sending to provider
|
|
@@ -443,9 +546,9 @@ export class ChatDriver extends EventTarget {
|
|
|
443
546
|
const isThinkingStep = response.content && ((_b = response.toolCalls) === null || _b === void 0 ? void 0 : _b.length);
|
|
444
547
|
const isEmptyResponse = !((_c = response.content) === null || _c === void 0 ? void 0 : _c.trim()) && !((_d = response.toolCalls) === null || _d === void 0 ? void 0 : _d.length);
|
|
445
548
|
if (isEmptyResponse) {
|
|
446
|
-
|
|
447
|
-
if (
|
|
448
|
-
logger.warn(`ChatDriver: empty model response, retrying (${
|
|
549
|
+
emptyResponseAttempts += 1;
|
|
550
|
+
if (emptyResponseAttempts < MAX_EMPTY_RESPONSE_RETRIES) {
|
|
551
|
+
logger.warn(`ChatDriver: empty model response, retrying (${emptyResponseAttempts}/${MAX_EMPTY_RESPONSE_RETRIES})`);
|
|
449
552
|
iterations -= 1;
|
|
450
553
|
continue;
|
|
451
554
|
}
|
|
@@ -542,11 +645,14 @@ export class ChatDriver extends EventTarget {
|
|
|
542
645
|
}
|
|
543
646
|
// Real tool execution
|
|
544
647
|
try {
|
|
545
|
-
const
|
|
546
|
-
|
|
547
|
-
});
|
|
648
|
+
const traceCapture = {};
|
|
649
|
+
const result = yield handler(tc.args, this.buildHandlerContext(traceCapture));
|
|
548
650
|
const content = typeof result === 'string' ? result : JSON.stringify(result);
|
|
549
|
-
executedById.set(tc.id, {
|
|
651
|
+
executedById.set(tc.id, {
|
|
652
|
+
toolCallId: tc.id,
|
|
653
|
+
content,
|
|
654
|
+
subAgentTrace: traceCapture.trace,
|
|
655
|
+
});
|
|
550
656
|
anyRealToolExecuted = true;
|
|
551
657
|
}
|
|
552
658
|
catch (e) {
|
|
@@ -594,7 +700,7 @@ export class ChatDriver extends EventTarget {
|
|
|
594
700
|
const tcMsg = this.history[tcMsgIdx];
|
|
595
701
|
const availableToolNames = Object.keys(this.toolHandlers);
|
|
596
702
|
const annotatedCalls = tcMsg.toolCalls.map((tc) => {
|
|
597
|
-
var _a, _b, _c, _d;
|
|
703
|
+
var _a, _b, _c, _d, _e;
|
|
598
704
|
const isFoldOpen = !!this.getFold(tc.name) ||
|
|
599
705
|
(
|
|
600
706
|
// Was a fold facade at time of the call (now the tool set has changed)
|
|
@@ -608,7 +714,7 @@ export class ChatDriver extends EventTarget {
|
|
|
608
714
|
? 'close'
|
|
609
715
|
: undefined,
|
|
610
716
|
// Use the fold path that was active at the START of this iteration (before any opens/closes)
|
|
611
|
-
foldPath: !isFoldOpen && !isFoldClose && foldPath.length > 0 ? foldPath : undefined, unknown: isUnknown || undefined, availableTools: isUnknown ? availableToolNames : undefined });
|
|
717
|
+
foldPath: !isFoldOpen && !isFoldClose && foldPath.length > 0 ? foldPath : undefined, unknown: isUnknown || undefined, availableTools: isUnknown ? availableToolNames : undefined, subAgentTrace: (_e = executedById.get(tc.id)) === null || _e === void 0 ? void 0 : _e.subAgentTrace });
|
|
612
718
|
});
|
|
613
719
|
this.history[tcMsgIdx] = Object.assign(Object.assign({}, tcMsg), { toolCalls: annotatedCalls });
|
|
614
720
|
this.dispatchEvent(new CustomEvent('history-updated', {
|
|
@@ -628,6 +734,11 @@ export class ChatDriver extends EventTarget {
|
|
|
628
734
|
const { summary, remaining_task: remainingTask } = firstContinuation.args;
|
|
629
735
|
return { reason: 'agent-handoff', summary, remainingTask };
|
|
630
736
|
}
|
|
737
|
+
// Sub-agent early exit — checked here so the exit point mirrors the
|
|
738
|
+
// system-call pattern above. Set by completeSubAgent() in a tool handler.
|
|
739
|
+
if (this.subAgentCompletion) {
|
|
740
|
+
return { reason: 'done' };
|
|
741
|
+
}
|
|
631
742
|
currentInput = '';
|
|
632
743
|
}
|
|
633
744
|
if (iterations >= this.maxToolIterations) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
|
+
import { transformHistoryForAgent } from '../../utils/history-transform';
|
|
2
3
|
import { logger } from '../../utils/logger';
|
|
3
4
|
import { ChatDriver, REQUEST_CONTINUATION_TOOL } from '../chat-driver/chat-driver';
|
|
4
5
|
const DEFAULT_MAX_HANDOFFS = 3;
|
|
@@ -35,25 +36,6 @@ function buildFallbackSystemPrompt(fallback, specialists) {
|
|
|
35
36
|
}
|
|
36
37
|
return `You are a helpful assistant. You cannot directly help with the user's request, but the following specialists are available:\n\n${agentList}\n\nPolitely let the user know what you can help with and invite them to rephrase their request.`;
|
|
37
38
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Prepares history for the LLM only: masks tool call args and results from other
|
|
40
|
-
* agents so the active specialist is not confused by tools it does not have.
|
|
41
|
-
* Canonical history in `ChatDriver` stays unmasked for UI and logging.
|
|
42
|
-
*/
|
|
43
|
-
function transformHistoryForAgent(history, agentName) {
|
|
44
|
-
return history.map((msg) => {
|
|
45
|
-
var _a;
|
|
46
|
-
if (!msg.agentName || msg.agentName === agentName)
|
|
47
|
-
return msg;
|
|
48
|
-
if ((_a = msg.toolCalls) === null || _a === void 0 ? void 0 : _a.length) {
|
|
49
|
-
return Object.assign(Object.assign({}, msg), { toolCalls: msg.toolCalls.map((tc) => (Object.assign(Object.assign({}, tc), { args: {} }))) });
|
|
50
|
-
}
|
|
51
|
-
if (msg.toolResult) {
|
|
52
|
-
return Object.assign(Object.assign({}, msg), { toolResult: Object.assign(Object.assign({}, msg.toolResult), { content: "[other agent's tool result omitted]" }) });
|
|
53
|
-
}
|
|
54
|
-
return msg;
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
39
|
/**
|
|
58
40
|
* Orchestrates multiple specialist agents. Sits between `FoundationAiAssistant`
|
|
59
41
|
* and `ChatDriver`, classifying each user message and routing it to the right
|
|
@@ -80,10 +62,16 @@ export class OrchestratingDriver extends EventTarget {
|
|
|
80
62
|
this.fallback = rawFallback
|
|
81
63
|
? Object.assign(Object.assign({}, rawFallback), { systemPrompt: buildFallbackSystemPrompt(rawFallback, this.specialists) }) : undefined;
|
|
82
64
|
this.chatDriver = new ChatDriver(aiProvider, {}, [], undefined, undefined, options.maxToolIterations, options.maxFoldOperations);
|
|
83
|
-
// Proxy
|
|
65
|
+
// Proxy events from the shared driver
|
|
84
66
|
this.chatDriver.addEventListener('history-updated', (e) => {
|
|
85
67
|
this.dispatchEvent(new CustomEvent('history-updated', { detail: e.detail }));
|
|
86
68
|
});
|
|
69
|
+
this.chatDriver.addEventListener('sub-agent-history-updated', (e) => {
|
|
70
|
+
this.dispatchEvent(new CustomEvent('sub-agent-history-updated', { detail: e.detail }));
|
|
71
|
+
});
|
|
72
|
+
this.chatDriver.addEventListener('sub-agent-stop', (e) => {
|
|
73
|
+
this.dispatchEvent(new CustomEvent('sub-agent-stop', { detail: e.detail }));
|
|
74
|
+
});
|
|
87
75
|
}
|
|
88
76
|
resolveInteraction(interactionId, result) {
|
|
89
77
|
this.chatDriver.resolveInteraction(interactionId, result);
|
|
@@ -1 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Identity helper that infers the narrowest possible type for an agent config,
|
|
3
|
+
* preserving string literal types (including `name`) without requiring `as const`.
|
|
4
|
+
*
|
|
5
|
+
* Use this when you need `typeof myAgent` to carry the literal `name` type —
|
|
6
|
+
* for example, when wiring `ChatToolHandlers<typeof myAgent>`.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const myAgent = defineAgent({ name: 'my_agent', ... });
|
|
10
|
+
* type Handlers = ChatToolHandlers<typeof myAgent>;
|
|
11
|
+
* // requestSubAgent name param is now typed as 'my_agent'
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @beta
|
|
15
|
+
*/
|
|
16
|
+
export function defineAgent(config) {
|
|
17
|
+
return config;
|
|
18
|
+
}
|
package/dist/esm/main/main.js
CHANGED
|
@@ -51,6 +51,12 @@ const MODEL_CONTEXT_LIMITS = {
|
|
|
51
51
|
};
|
|
52
52
|
// Register supporting components when the main component module is imported.
|
|
53
53
|
avoidTreeShaking(AiChatMarkdown, AiChatInteractionWrapper, AiHaloOverlay, AiChatBubble, AiActivityHalo, ChatSuggestions);
|
|
54
|
+
/** Recursively strips `toolHandlers` from an agent and all its sub-agents. */
|
|
55
|
+
function stripHandlers(agent) {
|
|
56
|
+
const { toolHandlers: _, subAgents } = agent, rest = __rest(agent, ["toolHandlers", "subAgents"]);
|
|
57
|
+
return (subAgents === null || subAgents === void 0 ? void 0 : subAgents.length)
|
|
58
|
+
? Object.assign(Object.assign({}, rest), { subAgents: subAgents.map(stripHandlers) }) : rest;
|
|
59
|
+
}
|
|
54
60
|
/**
|
|
55
61
|
* Foundation AI Assistant component.
|
|
56
62
|
*
|
|
@@ -112,17 +118,12 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
112
118
|
return (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.activeAgent;
|
|
113
119
|
}
|
|
114
120
|
set activeAgent(value) {
|
|
115
|
-
var _a
|
|
116
|
-
// Strip toolHandlers before storing — functions are non-serializable
|
|
117
|
-
// serializable-state middleware will warn. toolHandlers are never read
|
|
118
|
-
// the store; they are always sourced from this.agents when the driver
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setActiveAgent(serializable);
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
(_b = this._sessionRef) === null || _b === void 0 ? void 0 : _b.actions.aiAssistant.setActiveAgent(undefined);
|
|
125
|
-
}
|
|
121
|
+
var _a;
|
|
122
|
+
// Strip toolHandlers recursively before storing — functions are non-serializable
|
|
123
|
+
// and Redux serializable-state middleware will warn. toolHandlers are never read
|
|
124
|
+
// back from the store; they are always sourced from this.agents when the driver
|
|
125
|
+
// is built.
|
|
126
|
+
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setActiveAgent(value ? stripHandlers(value) : undefined);
|
|
126
127
|
}
|
|
127
128
|
get suggestionsState() {
|
|
128
129
|
var _a, _b;
|
|
@@ -168,6 +169,22 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
168
169
|
var _a;
|
|
169
170
|
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setEnabledAnimations(value);
|
|
170
171
|
}
|
|
172
|
+
get liveSubAgentTrace() {
|
|
173
|
+
var _a, _b;
|
|
174
|
+
return (_b = (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.liveSubAgentTrace) !== null && _b !== void 0 ? _b : [];
|
|
175
|
+
}
|
|
176
|
+
set liveSubAgentTrace(value) {
|
|
177
|
+
var _a;
|
|
178
|
+
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setLiveSubAgentTrace(value);
|
|
179
|
+
}
|
|
180
|
+
get liveSubAgentName() {
|
|
181
|
+
var _a, _b;
|
|
182
|
+
return (_b = (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.liveSubAgentName) !== null && _b !== void 0 ? _b : null;
|
|
183
|
+
}
|
|
184
|
+
set liveSubAgentName(value) {
|
|
185
|
+
var _a;
|
|
186
|
+
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setLiveSubAgentName(value);
|
|
187
|
+
}
|
|
171
188
|
/** Most recent prompt token count from the AI provider, if available. */
|
|
172
189
|
get contextTokens() {
|
|
173
190
|
var _a;
|
|
@@ -355,8 +372,23 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
355
372
|
this.messages = [...e.detail];
|
|
356
373
|
};
|
|
357
374
|
driver.addEventListener('history-updated', onHistoryUpdated);
|
|
375
|
+
const onSubAgentHistoryUpdated = (e) => {
|
|
376
|
+
const { agentName, history } = e.detail;
|
|
377
|
+
this.liveSubAgentName = agentName;
|
|
378
|
+
// structuredClone so Immer freezes an independent copy, not the child
|
|
379
|
+
// driver's own history array (which is still being mutated by the tool loop).
|
|
380
|
+
this.liveSubAgentTrace = structuredClone(history);
|
|
381
|
+
};
|
|
382
|
+
const onSubAgentStop = () => {
|
|
383
|
+
this.liveSubAgentTrace = [];
|
|
384
|
+
this.liveSubAgentName = null;
|
|
385
|
+
};
|
|
386
|
+
driver.addEventListener('sub-agent-history-updated', onSubAgentHistoryUpdated);
|
|
387
|
+
driver.addEventListener('sub-agent-stop', onSubAgentStop);
|
|
358
388
|
const cleanups = [
|
|
359
389
|
() => driver.removeEventListener('history-updated', onHistoryUpdated),
|
|
390
|
+
() => driver.removeEventListener('sub-agent-history-updated', onSubAgentHistoryUpdated),
|
|
391
|
+
() => driver.removeEventListener('sub-agent-stop', onSubAgentStop),
|
|
360
392
|
];
|
|
361
393
|
if (driver instanceof OrchestratingDriver) {
|
|
362
394
|
const onOrchStart = () => {
|
|
@@ -445,6 +445,68 @@ export const styles = css `
|
|
|
445
445
|
padding-left: 8px;
|
|
446
446
|
}
|
|
447
447
|
|
|
448
|
+
.live-sub-agent-trace {
|
|
449
|
+
animation: slide-in-left 0.25s ease-out;
|
|
450
|
+
border-left: 2px solid var(--neutral-stroke-rest);
|
|
451
|
+
padding: 4px 8px;
|
|
452
|
+
margin: 4px 0;
|
|
453
|
+
opacity: 80%;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.live-sub-agent-name {
|
|
457
|
+
font-family: monospace;
|
|
458
|
+
font-size: 0.8em;
|
|
459
|
+
opacity: 70%;
|
|
460
|
+
font-style: italic;
|
|
461
|
+
display: block;
|
|
462
|
+
margin-bottom: 2px;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.sub-agent-trace {
|
|
466
|
+
margin-top: 6px;
|
|
467
|
+
border-left: 2px solid var(--neutral-stroke-rest);
|
|
468
|
+
padding-left: 8px;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.sub-agent-trace-summary {
|
|
472
|
+
font-family: monospace;
|
|
473
|
+
font-size: 0.85em;
|
|
474
|
+
opacity: 70%;
|
|
475
|
+
cursor: pointer;
|
|
476
|
+
user-select: none;
|
|
477
|
+
padding: 2px 0;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
.sub-agent-trace-summary:hover {
|
|
481
|
+
opacity: 100%;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.sub-agent-message {
|
|
485
|
+
font-family: monospace;
|
|
486
|
+
font-size: 0.85em;
|
|
487
|
+
margin-top: 4px;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.sub-agent-assistant {
|
|
491
|
+
opacity: 85%;
|
|
492
|
+
white-space: pre-wrap;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.sub-agent-tool-call {
|
|
496
|
+
opacity: 60%;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.sub-agent-tool-name::before {
|
|
500
|
+
content: '⚙ ';
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.sub-agent-tool-result {
|
|
504
|
+
opacity: 50%;
|
|
505
|
+
border-left: 1px solid var(--neutral-stroke-rest);
|
|
506
|
+
padding-left: 6px;
|
|
507
|
+
white-space: pre-wrap;
|
|
508
|
+
}
|
|
509
|
+
|
|
448
510
|
.input-row {
|
|
449
511
|
display: flex;
|
|
450
512
|
gap: calc(var(--design-unit) * 2px);
|