@genesislcap/ai-assistant 14.421.0 → 14.421.1-FUI-2511.2
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 +119 -12
- 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 +161 -11
- 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,5 +1,6 @@
|
|
|
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;
|
|
@@ -35,6 +36,8 @@ export class ChatDriver extends EventTarget {
|
|
|
35
36
|
this.consecutiveFoldOps = 0;
|
|
36
37
|
/** Consecutive unknown-tool calls without a real tool call. Reset on real tool execution. */
|
|
37
38
|
this.consecutiveUnknownToolCalls = 0;
|
|
39
|
+
/** Sub-agents declared on the active agent config, keyed by name. */
|
|
40
|
+
this.subAgentsMap = new Map();
|
|
38
41
|
this.toolHandlers = toolHandlers;
|
|
39
42
|
this.toolDefinitions = toolDefinitions;
|
|
40
43
|
this.systemPrompt = systemPrompt;
|
|
@@ -46,16 +49,24 @@ export class ChatDriver extends EventTarget {
|
|
|
46
49
|
* each specialist turn so the shared driver runs with the right tools and prompt.
|
|
47
50
|
*/
|
|
48
51
|
applyAgent(config) {
|
|
49
|
-
var _a, _b;
|
|
52
|
+
var _a, _b, _c;
|
|
50
53
|
this.systemPrompt = config.systemPrompt;
|
|
51
54
|
this.toolDefinitions = (_a = config.toolDefinitions) !== null && _a !== void 0 ? _a : [];
|
|
52
55
|
this.toolHandlers = (_b = config.toolHandlers) !== null && _b !== void 0 ? _b : {};
|
|
53
56
|
this.primerHistory = config.primerHistory;
|
|
54
57
|
this.activeAgentName = config.name;
|
|
58
|
+
this.subAgentsMap = new Map(((_c = config.subAgents) !== null && _c !== void 0 ? _c : []).map((s) => [s.name, s]));
|
|
55
59
|
// Reset fold state when agent changes — each specialist starts fresh
|
|
56
60
|
this.foldStack = [];
|
|
57
61
|
this.consecutiveFoldOps = 0;
|
|
58
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Returns the early-stop result set by `completeSubAgent`, if any.
|
|
65
|
+
* Called by a parent `ChatDriver` after running this instance as a sub-agent.
|
|
66
|
+
*/
|
|
67
|
+
getSubAgentCompletion() {
|
|
68
|
+
return this.subAgentCompletion;
|
|
69
|
+
}
|
|
59
70
|
/**
|
|
60
71
|
* Optional transform applied to conversation history immediately before each LLM request.
|
|
61
72
|
* Cleared when `undefined`. Does not alter stored history.
|
|
@@ -212,6 +223,7 @@ export class ChatDriver extends EventTarget {
|
|
|
212
223
|
return { reason: 'done' };
|
|
213
224
|
}
|
|
214
225
|
this.busy = true;
|
|
226
|
+
this.subAgentCompletion = undefined;
|
|
215
227
|
this.appendToHistory({ role: 'user', content: userInput, attachments });
|
|
216
228
|
try {
|
|
217
229
|
return yield this.runToolLoop(userInput, attachments);
|
|
@@ -226,6 +238,89 @@ export class ChatDriver extends EventTarget {
|
|
|
226
238
|
}
|
|
227
239
|
});
|
|
228
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Builds the context object passed to every tool handler call.
|
|
243
|
+
* Centralised here so fold shortcut dispatch and the main tool loop use the
|
|
244
|
+
* same context without duplication.
|
|
245
|
+
*
|
|
246
|
+
* @param traceCapture - Optional per-invocation slot. When provided, the trace
|
|
247
|
+
* from any sub-agent call is written here rather than to shared instance state,
|
|
248
|
+
* so parallel tool calls each capture their own trace independently.
|
|
249
|
+
*/
|
|
250
|
+
buildHandlerContext(traceCapture) {
|
|
251
|
+
return Object.assign(Object.assign({ requestInteraction: (componentName, data) => this.requestInteraction(componentName, data) }, (this.subAgentsMap.size > 0 && {
|
|
252
|
+
requestSubAgent: (name, options) => this.invokeSubAgent(name, options).then(({ result, trace }) => {
|
|
253
|
+
if (traceCapture)
|
|
254
|
+
traceCapture.trace = trace;
|
|
255
|
+
return result;
|
|
256
|
+
}),
|
|
257
|
+
})), { completeSubAgent: (result) => {
|
|
258
|
+
var _a;
|
|
259
|
+
if (this.subAgentCompletion) {
|
|
260
|
+
logger.warn(`ChatDriver(${(_a = this.activeAgentName) !== null && _a !== void 0 ? _a : 'unknown'}): completeSubAgent called more than once — ignoring`);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
this.subAgentCompletion = { result };
|
|
264
|
+
} });
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Creates a child `ChatDriver` for the named sub-agent, runs it to completion,
|
|
268
|
+
* and returns its structured result (or final text fallback) together with the
|
|
269
|
+
* full child conversation trace. Callers receive both values so each parallel
|
|
270
|
+
* invocation can capture its own trace without touching shared instance state.
|
|
271
|
+
*/
|
|
272
|
+
invokeSubAgent(name, options) {
|
|
273
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
274
|
+
var _a, _b, _c;
|
|
275
|
+
const subConfig = this.subAgentsMap.get(name);
|
|
276
|
+
if (!subConfig) {
|
|
277
|
+
const available = [...this.subAgentsMap.keys()].join(', ') || '(none)';
|
|
278
|
+
throw new Error(`Sub-agent "${name}" not found on agent "${this.activeAgentName}". Available: ${available}`);
|
|
279
|
+
}
|
|
280
|
+
const { task, historyCap, context } = options !== null && options !== void 0 ? options : {};
|
|
281
|
+
// Exclude the current in-flight assistant message (the one with tool calls that
|
|
282
|
+
// triggered this invocation) — it has unresolved tool calls that would confuse
|
|
283
|
+
// the sub-agent into thinking it needs to handle tools it doesn't own.
|
|
284
|
+
const lastMsg = this.history[this.history.length - 1];
|
|
285
|
+
const baseHistory = (lastMsg === null || lastMsg === void 0 ? void 0 : lastMsg.role) === 'assistant' && ((_a = lastMsg.toolCalls) === null || _a === void 0 ? void 0 : _a.length)
|
|
286
|
+
? this.history.slice(0, -1)
|
|
287
|
+
: this.history;
|
|
288
|
+
const snapshotHistory = historyCap != null ? applyHistoryCap(baseHistory, historyCap) : [...baseHistory];
|
|
289
|
+
const contextMessages = context
|
|
290
|
+
? [{ role: 'user', content: `[Sub-agent context]: ${JSON.stringify(context)}` }]
|
|
291
|
+
: [];
|
|
292
|
+
const effectivePrimer = [
|
|
293
|
+
...snapshotHistory,
|
|
294
|
+
...contextMessages,
|
|
295
|
+
...((_b = subConfig.primerHistory) !== null && _b !== void 0 ? _b : []),
|
|
296
|
+
];
|
|
297
|
+
const child = new ChatDriver(this.aiProvider);
|
|
298
|
+
child.applyAgent(Object.assign(Object.assign({}, subConfig), { primerHistory: effectivePrimer }));
|
|
299
|
+
const forwardTrace = (e) => {
|
|
300
|
+
this.dispatchEvent(new CustomEvent('sub-agent-history-updated', {
|
|
301
|
+
detail: { agentName: subConfig.name, history: e.detail },
|
|
302
|
+
}));
|
|
303
|
+
};
|
|
304
|
+
child.addEventListener('history-updated', forwardTrace);
|
|
305
|
+
this.dispatchEvent(new CustomEvent('sub-agent-start', { detail: { name } }));
|
|
306
|
+
try {
|
|
307
|
+
yield child.sendMessage(task !== null && task !== void 0 ? task : '');
|
|
308
|
+
}
|
|
309
|
+
finally {
|
|
310
|
+
child.removeEventListener('history-updated', forwardTrace);
|
|
311
|
+
this.dispatchEvent(new CustomEvent('sub-agent-stop', { detail: { name } }));
|
|
312
|
+
}
|
|
313
|
+
const trace = child.getHistory();
|
|
314
|
+
const completion = child.getSubAgentCompletion();
|
|
315
|
+
if (completion) {
|
|
316
|
+
return { result: completion.result, trace };
|
|
317
|
+
}
|
|
318
|
+
const finalMsg = [...trace]
|
|
319
|
+
.reverse()
|
|
320
|
+
.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()); });
|
|
321
|
+
return { result: ((_c = finalMsg === null || finalMsg === void 0 ? void 0 : finalMsg.content) !== null && _c !== void 0 ? _c : ''), trace };
|
|
322
|
+
});
|
|
323
|
+
}
|
|
229
324
|
/**
|
|
230
325
|
* Continue the tool loop from current history without appending a new user message.
|
|
231
326
|
* Used by OrchestratingDriver after an agent handoff.
|
|
@@ -239,6 +334,7 @@ export class ChatDriver extends EventTarget {
|
|
|
239
334
|
return { reason: 'done' };
|
|
240
335
|
}
|
|
241
336
|
this.busy = true;
|
|
337
|
+
this.subAgentCompletion = undefined;
|
|
242
338
|
try {
|
|
243
339
|
return yield this.runToolLoop('', undefined, transientPrimer);
|
|
244
340
|
}
|
|
@@ -327,9 +423,7 @@ export class ChatDriver extends EventTarget {
|
|
|
327
423
|
const innerArgs = typeof args[key] === 'object' && args[key] !== null
|
|
328
424
|
? args[key]
|
|
329
425
|
: {};
|
|
330
|
-
return innerHandler(innerArgs,
|
|
331
|
-
requestInteraction: (c, d) => this.requestInteraction(c, d),
|
|
332
|
-
}).then((r) => (typeof r === 'string' ? r : JSON.stringify(r)));
|
|
426
|
+
return innerHandler(innerArgs, this.buildHandlerContext()).then((r) => typeof r === 'string' ? r : JSON.stringify(r));
|
|
333
427
|
}
|
|
334
428
|
}
|
|
335
429
|
// Normal two-step open
|
|
@@ -395,7 +489,11 @@ export class ChatDriver extends EventTarget {
|
|
|
395
489
|
let currentAttachments = attachments;
|
|
396
490
|
let iterations = 0;
|
|
397
491
|
let malformedAttempts = 0;
|
|
398
|
-
|
|
492
|
+
// True only for the very first LLM call. Used to exclude the pending user message
|
|
493
|
+
// from history (it is passed separately as currentInput). Must not be derived from
|
|
494
|
+
// `iterations` because fold operations decrement iterations, which would incorrectly
|
|
495
|
+
// re-trigger the slice on subsequent calls after a fold open/close.
|
|
496
|
+
let firstLlmCall = !!currentInput;
|
|
399
497
|
while (iterations < this.maxToolIterations) {
|
|
400
498
|
iterations += 1;
|
|
401
499
|
const foldSuffix = this.buildFoldSystemPromptSuffix();
|
|
@@ -403,7 +501,8 @@ export class ChatDriver extends EventTarget {
|
|
|
403
501
|
? `${this.systemPrompt}${foldSuffix}`
|
|
404
502
|
: foldSuffix || undefined;
|
|
405
503
|
const primer = [...((_a = this.primerHistory) !== null && _a !== void 0 ? _a : []), ...(transientPrimer !== null && transientPrimer !== void 0 ? transientPrimer : [])];
|
|
406
|
-
const baseHistory =
|
|
504
|
+
const baseHistory = firstLlmCall ? this.history.slice(0, -1) : this.history;
|
|
505
|
+
firstLlmCall = false;
|
|
407
506
|
const historyForProvider = this.providerHistoryTransform
|
|
408
507
|
? this.providerHistoryTransform([...baseHistory])
|
|
409
508
|
: baseHistory;
|
|
@@ -542,11 +641,14 @@ export class ChatDriver extends EventTarget {
|
|
|
542
641
|
}
|
|
543
642
|
// Real tool execution
|
|
544
643
|
try {
|
|
545
|
-
const
|
|
546
|
-
|
|
547
|
-
});
|
|
644
|
+
const traceCapture = {};
|
|
645
|
+
const result = yield handler(tc.args, this.buildHandlerContext(traceCapture));
|
|
548
646
|
const content = typeof result === 'string' ? result : JSON.stringify(result);
|
|
549
|
-
executedById.set(tc.id, {
|
|
647
|
+
executedById.set(tc.id, {
|
|
648
|
+
toolCallId: tc.id,
|
|
649
|
+
content,
|
|
650
|
+
subAgentTrace: traceCapture.trace,
|
|
651
|
+
});
|
|
550
652
|
anyRealToolExecuted = true;
|
|
551
653
|
}
|
|
552
654
|
catch (e) {
|
|
@@ -594,7 +696,7 @@ export class ChatDriver extends EventTarget {
|
|
|
594
696
|
const tcMsg = this.history[tcMsgIdx];
|
|
595
697
|
const availableToolNames = Object.keys(this.toolHandlers);
|
|
596
698
|
const annotatedCalls = tcMsg.toolCalls.map((tc) => {
|
|
597
|
-
var _a, _b, _c, _d;
|
|
699
|
+
var _a, _b, _c, _d, _e;
|
|
598
700
|
const isFoldOpen = !!this.getFold(tc.name) ||
|
|
599
701
|
(
|
|
600
702
|
// Was a fold facade at time of the call (now the tool set has changed)
|
|
@@ -608,7 +710,7 @@ export class ChatDriver extends EventTarget {
|
|
|
608
710
|
? 'close'
|
|
609
711
|
: undefined,
|
|
610
712
|
// 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 });
|
|
713
|
+
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
714
|
});
|
|
613
715
|
this.history[tcMsgIdx] = Object.assign(Object.assign({}, tcMsg), { toolCalls: annotatedCalls });
|
|
614
716
|
this.dispatchEvent(new CustomEvent('history-updated', {
|
|
@@ -628,6 +730,11 @@ export class ChatDriver extends EventTarget {
|
|
|
628
730
|
const { summary, remaining_task: remainingTask } = firstContinuation.args;
|
|
629
731
|
return { reason: 'agent-handoff', summary, remainingTask };
|
|
630
732
|
}
|
|
733
|
+
// Sub-agent early exit — checked here so the exit point mirrors the
|
|
734
|
+
// system-call pattern above. Set by completeSubAgent() in a tool handler.
|
|
735
|
+
if (this.subAgentCompletion) {
|
|
736
|
+
return { reason: 'done' };
|
|
737
|
+
}
|
|
631
738
|
currentInput = '';
|
|
632
739
|
}
|
|
633
740
|
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);
|