@genesislcap/ai-assistant 14.436.0-FUI-2489.2 → 14.437.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/api-extractor.json +9 -9
- package/dist/ai-assistant.api.json +73 -47
- package/dist/ai-assistant.d.ts +26 -21
- package/dist/dts/components/chat-driver/chat-driver.d.ts +6 -3
- 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/components/popout-manager/popout-manager.d.ts.map +1 -1
- package/dist/dts/main/main.d.ts +4 -4
- package/dist/dts/main/main.d.ts.map +1 -1
- package/dist/dts/state/ai-assistant-slice.d.ts +12 -10
- package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
- package/dist/dts/state/session-store.d.ts +2 -2
- package/dist/dts/suggestions/chat-suggestions.d.ts.map +1 -1
- package/dist/dts/tags/index.d.ts +0 -1
- package/dist/dts/tags/index.d.ts.map +1 -1
- package/dist/esm/components/chat-driver/chat-driver.js +25 -9
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +12 -6
- package/dist/esm/components/popout-manager/popout-manager.js +0 -1
- package/dist/esm/main/main.js +29 -8
- package/dist/esm/state/ai-assistant-slice.js +5 -5
- package/dist/esm/suggestions/chat-suggestions.js +2 -1
- package/dist/esm/tags/index.js +0 -1
- package/package.json +16 -16
- package/src/components/chat-driver/chat-driver.ts +49 -14
- package/src/components/orchestrating-driver/orchestrating-driver.ts +16 -6
- package/src/components/popout-manager/popout-manager.ts +0 -1
- package/src/main/main.ts +29 -8
- package/src/state/ai-assistant-slice.ts +15 -15
- package/src/suggestions/chat-suggestions.ts +2 -9
- package/src/tags/index.ts +0 -1
- package/tsconfig.json +3 -1
|
@@ -90,6 +90,12 @@ export class OrchestratingDriver extends EventTarget {
|
|
|
90
90
|
this.chatDriver.addEventListener('sub-agent-stop', (e) => {
|
|
91
91
|
this.dispatchEvent(new CustomEvent('sub-agent-stop', { detail: e.detail }));
|
|
92
92
|
});
|
|
93
|
+
this.chatDriver.addEventListener('interaction-start', (e) => {
|
|
94
|
+
this.dispatchEvent(new CustomEvent('interaction-start', { detail: e.detail }));
|
|
95
|
+
});
|
|
96
|
+
this.chatDriver.addEventListener('interaction-stop', (e) => {
|
|
97
|
+
this.dispatchEvent(new CustomEvent('interaction-stop', { detail: e.detail }));
|
|
98
|
+
});
|
|
93
99
|
}
|
|
94
100
|
resolveInteraction(interactionId, result) {
|
|
95
101
|
this.chatDriver.resolveInteraction(interactionId, result);
|
|
@@ -150,18 +156,18 @@ export class OrchestratingDriver extends EventTarget {
|
|
|
150
156
|
let handoffSummary = '';
|
|
151
157
|
let remainingTask = '';
|
|
152
158
|
while (true) {
|
|
153
|
-
//
|
|
159
|
+
// eslint-disable-next-line no-await-in-loop
|
|
154
160
|
yield this.applyAgent(currentAgent);
|
|
155
161
|
let result;
|
|
156
162
|
if (isHandoff) {
|
|
157
163
|
const contextPrimer = handoffSummary
|
|
158
164
|
? [{ role: 'user', content: `[Context from previous agent]: ${handoffSummary}` }]
|
|
159
165
|
: [];
|
|
160
|
-
//
|
|
166
|
+
// eslint-disable-next-line no-await-in-loop
|
|
161
167
|
result = yield this.chatDriver.continueFromHistory(contextPrimer);
|
|
162
168
|
}
|
|
163
169
|
else {
|
|
164
|
-
//
|
|
170
|
+
// eslint-disable-next-line no-await-in-loop
|
|
165
171
|
result = yield this.chatDriver.sendMessage(input, attachments);
|
|
166
172
|
}
|
|
167
173
|
// Release check: a stateful agent called `releaseAgent` from a terminal
|
|
@@ -169,7 +175,7 @@ export class OrchestratingDriver extends EventTarget {
|
|
|
169
175
|
// classifier-mode. The LLM has already emitted its final wrap-up message
|
|
170
176
|
// by the time we get here — release is purely a teardown.
|
|
171
177
|
if (this.chatDriver.getAgentReleaseRequested()) {
|
|
172
|
-
//
|
|
178
|
+
// eslint-disable-next-line no-await-in-loop
|
|
173
179
|
yield this.releaseActiveAgent();
|
|
174
180
|
break;
|
|
175
181
|
}
|
|
@@ -188,7 +194,7 @@ export class OrchestratingDriver extends EventTarget {
|
|
|
188
194
|
isHandoff = true;
|
|
189
195
|
const updatedHistory = this.chatDriver.getHistory();
|
|
190
196
|
this.dispatchEvent(new CustomEvent('orchestrating-start'));
|
|
191
|
-
//
|
|
197
|
+
// eslint-disable-next-line no-await-in-loop
|
|
192
198
|
currentAgent = yield this.classify(remainingTask, updatedHistory);
|
|
193
199
|
}
|
|
194
200
|
return { reason: 'done' };
|
|
@@ -386,7 +392,7 @@ export class OrchestratingDriver extends EventTarget {
|
|
|
386
392
|
systemPrompt: classifierPrompt,
|
|
387
393
|
tools: [routingTool],
|
|
388
394
|
};
|
|
389
|
-
//
|
|
395
|
+
// eslint-disable-next-line no-await-in-loop
|
|
390
396
|
const response = yield this.aiProvider.chat([], input, options);
|
|
391
397
|
const tc = (_b = response.toolCalls) === null || _b === void 0 ? void 0 : _b[0];
|
|
392
398
|
const index = (tc === null || tc === void 0 ? void 0 : tc.name) === 'select_agent' ? tc.args.agent_index : -1;
|
|
@@ -35,7 +35,6 @@ let FoundationAiPopoutManager = class FoundationAiPopoutManager extends GenesisE
|
|
|
35
35
|
}
|
|
36
36
|
connectedCallback() {
|
|
37
37
|
super.connectedCallback();
|
|
38
|
-
// oxlint-disable-next-line typescript-eslint(no-this-alias) -- module-level singleton, not a local alias
|
|
39
38
|
_aiPopoutManager = this;
|
|
40
39
|
const bubble = this.querySelector('foundation-ai-chat-bubble');
|
|
41
40
|
const assistantEl = bubble === null || bubble === void 0 ? void 0 : bubble.querySelector('[slot="dialog-content"]');
|
package/dist/esm/main/main.js
CHANGED
|
@@ -300,22 +300,22 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
300
300
|
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setLiveSubAgentName(value);
|
|
301
301
|
}
|
|
302
302
|
/**
|
|
303
|
-
* In-flight per-call chat-input overrides pushed by `requestSubAgent`
|
|
304
|
-
*
|
|
303
|
+
* In-flight per-call chat-input overrides pushed by `requestSubAgent` or
|
|
304
|
+
* `requestInteraction` calls. Empty means no override is active.
|
|
305
305
|
*/
|
|
306
|
-
get
|
|
306
|
+
get inputOverrides() {
|
|
307
307
|
var _a, _b;
|
|
308
|
-
return (_b = (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.
|
|
308
|
+
return (_b = (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.inputOverrides) !== null && _b !== void 0 ? _b : [];
|
|
309
309
|
}
|
|
310
310
|
/**
|
|
311
311
|
* Resolves the effective chat-input behaviour while the assistant is
|
|
312
|
-
* executing.
|
|
312
|
+
* executing. Per-call overrides take precedence over the agent-level
|
|
313
313
|
* config; among overrides the most restrictive wins (`'hidden'` >
|
|
314
314
|
* `'disabled'`). Falls back to the active agent's config, then `'disabled'`.
|
|
315
315
|
*/
|
|
316
316
|
get effectiveChatInputDuringExecution() {
|
|
317
317
|
var _a, _b;
|
|
318
|
-
const overrides = this.
|
|
318
|
+
const overrides = this.inputOverrides;
|
|
319
319
|
if (overrides.some((o) => o.mode === 'hidden'))
|
|
320
320
|
return 'hidden';
|
|
321
321
|
if (overrides.some((o) => o.mode === 'disabled'))
|
|
@@ -570,7 +570,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
570
570
|
const { invocationId, chatInputDuringExecution } = e.detail;
|
|
571
571
|
if (!chatInputDuringExecution)
|
|
572
572
|
return;
|
|
573
|
-
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.
|
|
573
|
+
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.addInputOverride({
|
|
574
574
|
id: invocationId,
|
|
575
575
|
mode: chatInputDuringExecution,
|
|
576
576
|
});
|
|
@@ -581,17 +581,38 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
581
581
|
this.liveSubAgentName = null;
|
|
582
582
|
const { invocationId } = e.detail;
|
|
583
583
|
if (invocationId) {
|
|
584
|
-
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.
|
|
584
|
+
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.removeInputOverride({ id: invocationId });
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
const onInteractionStart = (e) => {
|
|
588
|
+
var _a;
|
|
589
|
+
const { interactionId, chatInputDuringExecution } = e.detail;
|
|
590
|
+
if (!chatInputDuringExecution)
|
|
591
|
+
return;
|
|
592
|
+
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.addInputOverride({
|
|
593
|
+
id: interactionId,
|
|
594
|
+
mode: chatInputDuringExecution,
|
|
595
|
+
});
|
|
596
|
+
};
|
|
597
|
+
const onInteractionStop = (e) => {
|
|
598
|
+
var _a;
|
|
599
|
+
const { interactionId } = e.detail;
|
|
600
|
+
if (interactionId) {
|
|
601
|
+
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.removeInputOverride({ id: interactionId });
|
|
585
602
|
}
|
|
586
603
|
};
|
|
587
604
|
driver.addEventListener('sub-agent-history-updated', onSubAgentHistoryUpdated);
|
|
588
605
|
driver.addEventListener('sub-agent-start', onSubAgentStart);
|
|
589
606
|
driver.addEventListener('sub-agent-stop', onSubAgentStop);
|
|
607
|
+
driver.addEventListener('interaction-start', onInteractionStart);
|
|
608
|
+
driver.addEventListener('interaction-stop', onInteractionStop);
|
|
590
609
|
const cleanups = [
|
|
591
610
|
() => driver.removeEventListener('history-updated', onHistoryUpdated),
|
|
592
611
|
() => driver.removeEventListener('sub-agent-history-updated', onSubAgentHistoryUpdated),
|
|
593
612
|
() => driver.removeEventListener('sub-agent-start', onSubAgentStart),
|
|
594
613
|
() => driver.removeEventListener('sub-agent-stop', onSubAgentStop),
|
|
614
|
+
() => driver.removeEventListener('interaction-start', onInteractionStart),
|
|
615
|
+
() => driver.removeEventListener('interaction-stop', onInteractionStop),
|
|
595
616
|
];
|
|
596
617
|
if (driver instanceof OrchestratingDriver) {
|
|
597
618
|
// Restore any pinned agent from the session store onto the freshly built
|
|
@@ -15,7 +15,7 @@ export const defaultSessionState = {
|
|
|
15
15
|
inputValue: '',
|
|
16
16
|
liveSubAgentTrace: [],
|
|
17
17
|
liveSubAgentName: null,
|
|
18
|
-
|
|
18
|
+
inputOverrides: [],
|
|
19
19
|
};
|
|
20
20
|
export const aiAssistantSlice = createSlice({
|
|
21
21
|
name: 'aiAssistant',
|
|
@@ -66,11 +66,11 @@ export const aiAssistantSlice = createSlice({
|
|
|
66
66
|
setLiveSubAgentName(state, action) {
|
|
67
67
|
state.liveSubAgentName = action.payload;
|
|
68
68
|
},
|
|
69
|
-
|
|
70
|
-
state.
|
|
69
|
+
addInputOverride(state, action) {
|
|
70
|
+
state.inputOverrides.push(action.payload);
|
|
71
71
|
},
|
|
72
|
-
|
|
73
|
-
state.
|
|
72
|
+
removeInputOverride(state, action) {
|
|
73
|
+
state.inputOverrides = state.inputOverrides.filter((o) => o.id !== action.payload.id);
|
|
74
74
|
},
|
|
75
75
|
},
|
|
76
76
|
selectors: {},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
-
import { customElement,
|
|
2
|
+
import { customElement, observable, html, css, repeat, when } from '@genesislcap/web-core';
|
|
3
|
+
import { GenesisElement } from '@genesislcap/web-core';
|
|
3
4
|
const PILL_ANIMATION_STAGGER_MS = 70;
|
|
4
5
|
const template = html `
|
|
5
6
|
${when((x) => x.state.status === 'loading', html `
|
package/dist/esm/tags/index.js
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genesislcap/ai-assistant",
|
|
3
3
|
"description": "Genesis AI Assistant micro-frontend",
|
|
4
|
-
"version": "14.
|
|
4
|
+
"version": "14.437.0",
|
|
5
5
|
"license": "SEE LICENSE IN license.txt",
|
|
6
6
|
"main": "dist/esm/index.js",
|
|
7
7
|
"types": "dist/ai-assistant.d.ts",
|
|
@@ -64,24 +64,24 @@
|
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@genesislcap/foundation-testing": "14.
|
|
68
|
-
"@genesislcap/genx": "14.
|
|
69
|
-
"@genesislcap/rollup-builder": "14.
|
|
70
|
-
"@genesislcap/ts-builder": "14.
|
|
71
|
-
"@genesislcap/uvu-playwright-builder": "14.
|
|
72
|
-
"@genesislcap/vite-builder": "14.
|
|
73
|
-
"@genesislcap/webpack-builder": "14.
|
|
67
|
+
"@genesislcap/foundation-testing": "14.437.0",
|
|
68
|
+
"@genesislcap/genx": "14.437.0",
|
|
69
|
+
"@genesislcap/rollup-builder": "14.437.0",
|
|
70
|
+
"@genesislcap/ts-builder": "14.437.0",
|
|
71
|
+
"@genesislcap/uvu-playwright-builder": "14.437.0",
|
|
72
|
+
"@genesislcap/vite-builder": "14.437.0",
|
|
73
|
+
"@genesislcap/webpack-builder": "14.437.0",
|
|
74
74
|
"@types/dompurify": "^3.0.5",
|
|
75
75
|
"@types/marked": "^5.0.2"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@genesislcap/foundation-ai": "14.
|
|
79
|
-
"@genesislcap/foundation-logger": "14.
|
|
80
|
-
"@genesislcap/foundation-redux": "14.
|
|
81
|
-
"@genesislcap/foundation-ui": "14.
|
|
82
|
-
"@genesislcap/foundation-utils": "14.
|
|
83
|
-
"@genesislcap/rapid-design-system": "14.
|
|
84
|
-
"@genesislcap/web-core": "14.
|
|
78
|
+
"@genesislcap/foundation-ai": "14.437.0",
|
|
79
|
+
"@genesislcap/foundation-logger": "14.437.0",
|
|
80
|
+
"@genesislcap/foundation-redux": "14.437.0",
|
|
81
|
+
"@genesislcap/foundation-ui": "14.437.0",
|
|
82
|
+
"@genesislcap/foundation-utils": "14.437.0",
|
|
83
|
+
"@genesislcap/rapid-design-system": "14.437.0",
|
|
84
|
+
"@genesislcap/web-core": "14.437.0",
|
|
85
85
|
"dompurify": "^3.3.1",
|
|
86
86
|
"marked": "^17.0.3"
|
|
87
87
|
},
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"publishConfig": {
|
|
94
94
|
"access": "public"
|
|
95
95
|
},
|
|
96
|
-
"gitHead": "
|
|
96
|
+
"gitHead": "c30c777f0ab5e45f4e931a9cc1200ac85bcace35"
|
|
97
97
|
}
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
ChatToolCall,
|
|
8
8
|
ChatToolDefinition,
|
|
9
9
|
ChatToolHandlers,
|
|
10
|
+
InteractionRequestOptions,
|
|
10
11
|
SubAgentRequestOptions,
|
|
11
12
|
} from '@genesislcap/foundation-ai';
|
|
12
13
|
import { MalformedFunctionCallError } from '@genesislcap/foundation-ai';
|
|
@@ -89,7 +90,12 @@ export class ChatDriver extends EventTarget implements AiDriver {
|
|
|
89
90
|
private busy = false;
|
|
90
91
|
private pendingInteractions = new Map<
|
|
91
92
|
string,
|
|
92
|
-
{
|
|
93
|
+
{
|
|
94
|
+
resolve: (value: any) => void;
|
|
95
|
+
reject: (reason?: any) => void;
|
|
96
|
+
/** Present when the call requested a chat-input override. */
|
|
97
|
+
overrideId?: string;
|
|
98
|
+
}
|
|
93
99
|
>();
|
|
94
100
|
|
|
95
101
|
private systemPrompt?: SystemPromptInput;
|
|
@@ -117,7 +123,11 @@ export class ChatDriver extends EventTarget implements AiDriver {
|
|
|
117
123
|
* widget renders in — and resolves through — the parent (ultimately the
|
|
118
124
|
* root) driver, where the main UI is listening.
|
|
119
125
|
*/
|
|
120
|
-
private hostInteractionRequester?: <T>(
|
|
126
|
+
private hostInteractionRequester?: <T>(
|
|
127
|
+
componentName: string,
|
|
128
|
+
data: any,
|
|
129
|
+
options?: InteractionRequestOptions,
|
|
130
|
+
) => Promise<T>;
|
|
121
131
|
/**
|
|
122
132
|
* When set (e.g. by OrchestratingDriver), applied only to the conversation slice
|
|
123
133
|
* sent to the model — stored `history` stays unchanged for UI and logging.
|
|
@@ -385,7 +395,7 @@ export class ChatDriver extends EventTarget implements AiDriver {
|
|
|
385
395
|
* naturally: a grandchild → child → root.
|
|
386
396
|
*/
|
|
387
397
|
public setHostInteractionRequester(
|
|
388
|
-
fn: <T>(componentName: string, data: any) => Promise<T>,
|
|
398
|
+
fn: <T>(componentName: string, data: any, options?: InteractionRequestOptions) => Promise<T>,
|
|
389
399
|
): void {
|
|
390
400
|
this.hostInteractionRequester = fn;
|
|
391
401
|
}
|
|
@@ -403,10 +413,17 @@ export class ChatDriver extends EventTarget implements AiDriver {
|
|
|
403
413
|
*
|
|
404
414
|
* @param componentName - The custom element name to render.
|
|
405
415
|
* @param data - Data to pass to the component.
|
|
416
|
+
* @param options - Optional per-call overrides, including
|
|
417
|
+
* `chatInputDuringExecution` to hide or disable the main chat input while
|
|
418
|
+
* the widget is awaiting user input. Reverts when the interaction resolves.
|
|
406
419
|
*/
|
|
407
|
-
public async requestInteraction<T>(
|
|
420
|
+
public async requestInteraction<T>(
|
|
421
|
+
componentName: string,
|
|
422
|
+
data: any,
|
|
423
|
+
options?: InteractionRequestOptions,
|
|
424
|
+
): Promise<T> {
|
|
408
425
|
if (this.hostInteractionRequester) {
|
|
409
|
-
return this.hostInteractionRequester<T>(componentName, data);
|
|
426
|
+
return this.hostInteractionRequester<T>(componentName, data, options);
|
|
410
427
|
}
|
|
411
428
|
if (this.pendingInteractions.size > 0) {
|
|
412
429
|
throw new Error(
|
|
@@ -416,8 +433,20 @@ export class ChatDriver extends EventTarget implements AiDriver {
|
|
|
416
433
|
);
|
|
417
434
|
}
|
|
418
435
|
const interactionId = crypto.randomUUID();
|
|
436
|
+
const chatInputDuringExecution = options?.chatInputDuringExecution;
|
|
419
437
|
return new Promise((resolve, reject) => {
|
|
420
|
-
this.pendingInteractions.set(interactionId, {
|
|
438
|
+
this.pendingInteractions.set(interactionId, {
|
|
439
|
+
resolve,
|
|
440
|
+
reject,
|
|
441
|
+
overrideId: chatInputDuringExecution ? interactionId : undefined,
|
|
442
|
+
});
|
|
443
|
+
if (chatInputDuringExecution) {
|
|
444
|
+
this.dispatchEvent(
|
|
445
|
+
new CustomEvent('interaction-start', {
|
|
446
|
+
detail: { interactionId, chatInputDuringExecution },
|
|
447
|
+
}),
|
|
448
|
+
);
|
|
449
|
+
}
|
|
421
450
|
this.appendToHistory({
|
|
422
451
|
role: 'assistant',
|
|
423
452
|
content: '',
|
|
@@ -445,6 +474,9 @@ export class ChatDriver extends EventTarget implements AiDriver {
|
|
|
445
474
|
}),
|
|
446
475
|
);
|
|
447
476
|
}
|
|
477
|
+
if (interaction.overrideId) {
|
|
478
|
+
this.dispatchEvent(new CustomEvent('interaction-stop', { detail: { interactionId } }));
|
|
479
|
+
}
|
|
448
480
|
interaction.resolve(result);
|
|
449
481
|
this.pendingInteractions.delete(interactionId);
|
|
450
482
|
} else {
|
|
@@ -499,8 +531,11 @@ export class ChatDriver extends EventTarget implements AiDriver {
|
|
|
499
531
|
*/
|
|
500
532
|
private buildHandlerContext(traceCapture?: { trace?: ChatMessage[] }) {
|
|
501
533
|
return {
|
|
502
|
-
requestInteraction: <T>(
|
|
503
|
-
|
|
534
|
+
requestInteraction: <T>(
|
|
535
|
+
componentName: string,
|
|
536
|
+
data: any,
|
|
537
|
+
options?: InteractionRequestOptions,
|
|
538
|
+
): Promise<T> => this.requestInteraction(componentName, data, options),
|
|
504
539
|
...(this.subAgentsMap.size > 0 && {
|
|
505
540
|
requestSubAgent: <T = never>(
|
|
506
541
|
name: string,
|
|
@@ -581,8 +616,8 @@ export class ChatDriver extends EventTarget implements AiDriver {
|
|
|
581
616
|
// pending map the main UI is wired to. Recurses naturally for nested
|
|
582
617
|
// sub-agents.
|
|
583
618
|
child.setHostInteractionRequester(
|
|
584
|
-
<R>(componentName: string, data: any): Promise<R> =>
|
|
585
|
-
this.requestInteraction<R>(componentName, data),
|
|
619
|
+
<R>(componentName: string, data: any, opts?: InteractionRequestOptions): Promise<R> =>
|
|
620
|
+
this.requestInteraction<R>(componentName, data, opts),
|
|
586
621
|
);
|
|
587
622
|
|
|
588
623
|
const forwardTrace = (e: Event) => {
|
|
@@ -839,13 +874,13 @@ export class ChatDriver extends EventTarget implements AiDriver {
|
|
|
839
874
|
// Sequential await is required — each iteration must see fresh values
|
|
840
875
|
// before constructing the LLM request.
|
|
841
876
|
if (this.toolDefinitionsFactory) {
|
|
842
|
-
//
|
|
877
|
+
// eslint-disable-next-line no-await-in-loop
|
|
843
878
|
this.toolDefinitions = await this.toolDefinitionsFactory(promptCtx);
|
|
844
879
|
}
|
|
845
880
|
|
|
846
881
|
const resolvedSystemPrompt =
|
|
847
882
|
typeof this.systemPrompt === 'function'
|
|
848
|
-
? //
|
|
883
|
+
? // eslint-disable-next-line no-await-in-loop
|
|
849
884
|
await this.systemPrompt(promptCtx)
|
|
850
885
|
: this.systemPrompt;
|
|
851
886
|
|
|
@@ -891,7 +926,7 @@ export class ChatDriver extends EventTarget implements AiDriver {
|
|
|
891
926
|
|
|
892
927
|
let response: ChatMessage;
|
|
893
928
|
try {
|
|
894
|
-
//
|
|
929
|
+
// eslint-disable-next-line no-await-in-loop
|
|
895
930
|
response = await this.aiProvider.chat!(historyForCall, userInputForCall, options);
|
|
896
931
|
} catch (e) {
|
|
897
932
|
if (e instanceof MalformedFunctionCallError) {
|
|
@@ -961,7 +996,7 @@ export class ChatDriver extends EventTarget implements AiDriver {
|
|
|
961
996
|
let hitUnknownToolLimit = false;
|
|
962
997
|
|
|
963
998
|
if (toolCalls.length > 0) {
|
|
964
|
-
//
|
|
999
|
+
// eslint-disable-next-line no-await-in-loop
|
|
965
1000
|
await Promise.all(
|
|
966
1001
|
toolCalls.map(async (tc) => {
|
|
967
1002
|
// Check for fold facade
|
|
@@ -156,6 +156,16 @@ export class OrchestratingDriver extends EventTarget implements AiDriver {
|
|
|
156
156
|
this.chatDriver.addEventListener('sub-agent-stop', (e: Event) => {
|
|
157
157
|
this.dispatchEvent(new CustomEvent('sub-agent-stop', { detail: (e as CustomEvent).detail }));
|
|
158
158
|
});
|
|
159
|
+
this.chatDriver.addEventListener('interaction-start', (e: Event) => {
|
|
160
|
+
this.dispatchEvent(
|
|
161
|
+
new CustomEvent('interaction-start', { detail: (e as CustomEvent).detail }),
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
this.chatDriver.addEventListener('interaction-stop', (e: Event) => {
|
|
165
|
+
this.dispatchEvent(
|
|
166
|
+
new CustomEvent('interaction-stop', { detail: (e as CustomEvent).detail }),
|
|
167
|
+
);
|
|
168
|
+
});
|
|
159
169
|
}
|
|
160
170
|
|
|
161
171
|
resolveInteraction(interactionId: string, result: unknown): void {
|
|
@@ -230,7 +240,7 @@ export class OrchestratingDriver extends EventTarget implements AiDriver {
|
|
|
230
240
|
let remainingTask = '';
|
|
231
241
|
|
|
232
242
|
while (true) {
|
|
233
|
-
//
|
|
243
|
+
// eslint-disable-next-line no-await-in-loop
|
|
234
244
|
await this.applyAgent(currentAgent);
|
|
235
245
|
|
|
236
246
|
let result: ChatDriverResult;
|
|
@@ -238,10 +248,10 @@ export class OrchestratingDriver extends EventTarget implements AiDriver {
|
|
|
238
248
|
const contextPrimer: ChatMessage[] = handoffSummary
|
|
239
249
|
? [{ role: 'user', content: `[Context from previous agent]: ${handoffSummary}` }]
|
|
240
250
|
: [];
|
|
241
|
-
//
|
|
251
|
+
// eslint-disable-next-line no-await-in-loop
|
|
242
252
|
result = await this.chatDriver.continueFromHistory(contextPrimer);
|
|
243
253
|
} else {
|
|
244
|
-
//
|
|
254
|
+
// eslint-disable-next-line no-await-in-loop
|
|
245
255
|
result = await this.chatDriver.sendMessage(input, attachments);
|
|
246
256
|
}
|
|
247
257
|
|
|
@@ -250,7 +260,7 @@ export class OrchestratingDriver extends EventTarget implements AiDriver {
|
|
|
250
260
|
// classifier-mode. The LLM has already emitted its final wrap-up message
|
|
251
261
|
// by the time we get here — release is purely a teardown.
|
|
252
262
|
if (this.chatDriver.getAgentReleaseRequested()) {
|
|
253
|
-
//
|
|
263
|
+
// eslint-disable-next-line no-await-in-loop
|
|
254
264
|
await this.releaseActiveAgent();
|
|
255
265
|
break;
|
|
256
266
|
}
|
|
@@ -275,7 +285,7 @@ export class OrchestratingDriver extends EventTarget implements AiDriver {
|
|
|
275
285
|
|
|
276
286
|
const updatedHistory = this.chatDriver.getHistory() as ChatMessage[];
|
|
277
287
|
this.dispatchEvent(new CustomEvent('orchestrating-start'));
|
|
278
|
-
//
|
|
288
|
+
// eslint-disable-next-line no-await-in-loop
|
|
279
289
|
currentAgent = await this.classify(remainingTask, updatedHistory);
|
|
280
290
|
}
|
|
281
291
|
|
|
@@ -483,7 +493,7 @@ export class OrchestratingDriver extends EventTarget implements AiDriver {
|
|
|
483
493
|
systemPrompt: classifierPrompt,
|
|
484
494
|
tools: [routingTool],
|
|
485
495
|
};
|
|
486
|
-
//
|
|
496
|
+
// eslint-disable-next-line no-await-in-loop
|
|
487
497
|
const response = await this.aiProvider.chat!([], input, options);
|
|
488
498
|
const tc = response.toolCalls?.[0];
|
|
489
499
|
const index = tc?.name === 'select_agent' ? (tc.args.agent_index as number) : -1;
|
|
@@ -64,7 +64,6 @@ export class FoundationAiPopoutManager extends GenesisElement {
|
|
|
64
64
|
|
|
65
65
|
connectedCallback() {
|
|
66
66
|
super.connectedCallback();
|
|
67
|
-
// oxlint-disable-next-line typescript-eslint(no-this-alias) -- module-level singleton, not a local alias
|
|
68
67
|
_aiPopoutManager = this;
|
|
69
68
|
|
|
70
69
|
const bubble = this.querySelector('foundation-ai-chat-bubble');
|
package/src/main/main.ts
CHANGED
|
@@ -333,22 +333,22 @@ export class FoundationAiAssistant extends GenesisElement {
|
|
|
333
333
|
}
|
|
334
334
|
|
|
335
335
|
/**
|
|
336
|
-
* In-flight per-call chat-input overrides pushed by `requestSubAgent`
|
|
337
|
-
*
|
|
336
|
+
* In-flight per-call chat-input overrides pushed by `requestSubAgent` or
|
|
337
|
+
* `requestInteraction` calls. Empty means no override is active.
|
|
338
338
|
*/
|
|
339
|
-
get
|
|
340
|
-
return this._sessionRef?.store.aiAssistant.
|
|
339
|
+
get inputOverrides() {
|
|
340
|
+
return this._sessionRef?.store.aiAssistant.inputOverrides ?? [];
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
/**
|
|
344
344
|
* Resolves the effective chat-input behaviour while the assistant is
|
|
345
|
-
* executing.
|
|
345
|
+
* executing. Per-call overrides take precedence over the agent-level
|
|
346
346
|
* config; among overrides the most restrictive wins (`'hidden'` >
|
|
347
347
|
* `'disabled'`). Falls back to the active agent's config, then `'disabled'`.
|
|
348
348
|
*/
|
|
349
349
|
@volatile
|
|
350
350
|
get effectiveChatInputDuringExecution(): ChatInputDuringExecutionMode {
|
|
351
|
-
const overrides = this.
|
|
351
|
+
const overrides = this.inputOverrides;
|
|
352
352
|
if (overrides.some((o) => o.mode === 'hidden')) return 'hidden';
|
|
353
353
|
if (overrides.some((o) => o.mode === 'disabled')) return 'disabled';
|
|
354
354
|
return this.activeAgent?.chatInputDuringExecution ?? 'disabled';
|
|
@@ -656,7 +656,7 @@ export class FoundationAiAssistant extends GenesisElement {
|
|
|
656
656
|
chatInputDuringExecution?: ChatInputDuringExecutionMode;
|
|
657
657
|
};
|
|
658
658
|
if (!chatInputDuringExecution) return;
|
|
659
|
-
this._sessionRef?.actions.aiAssistant.
|
|
659
|
+
this._sessionRef?.actions.aiAssistant.addInputOverride({
|
|
660
660
|
id: invocationId,
|
|
661
661
|
mode: chatInputDuringExecution,
|
|
662
662
|
});
|
|
@@ -666,18 +666,39 @@ export class FoundationAiAssistant extends GenesisElement {
|
|
|
666
666
|
this.liveSubAgentName = null;
|
|
667
667
|
const { invocationId } = (e as CustomEvent).detail as { invocationId?: string };
|
|
668
668
|
if (invocationId) {
|
|
669
|
-
this._sessionRef?.actions.aiAssistant.
|
|
669
|
+
this._sessionRef?.actions.aiAssistant.removeInputOverride({ id: invocationId });
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
const onInteractionStart = (e: Event) => {
|
|
673
|
+
const { interactionId, chatInputDuringExecution } = (e as CustomEvent).detail as {
|
|
674
|
+
interactionId: string;
|
|
675
|
+
chatInputDuringExecution?: ChatInputDuringExecutionMode;
|
|
676
|
+
};
|
|
677
|
+
if (!chatInputDuringExecution) return;
|
|
678
|
+
this._sessionRef?.actions.aiAssistant.addInputOverride({
|
|
679
|
+
id: interactionId,
|
|
680
|
+
mode: chatInputDuringExecution,
|
|
681
|
+
});
|
|
682
|
+
};
|
|
683
|
+
const onInteractionStop = (e: Event) => {
|
|
684
|
+
const { interactionId } = (e as CustomEvent).detail as { interactionId?: string };
|
|
685
|
+
if (interactionId) {
|
|
686
|
+
this._sessionRef?.actions.aiAssistant.removeInputOverride({ id: interactionId });
|
|
670
687
|
}
|
|
671
688
|
};
|
|
672
689
|
driver.addEventListener('sub-agent-history-updated', onSubAgentHistoryUpdated);
|
|
673
690
|
driver.addEventListener('sub-agent-start', onSubAgentStart);
|
|
674
691
|
driver.addEventListener('sub-agent-stop', onSubAgentStop);
|
|
692
|
+
driver.addEventListener('interaction-start', onInteractionStart);
|
|
693
|
+
driver.addEventListener('interaction-stop', onInteractionStop);
|
|
675
694
|
|
|
676
695
|
const cleanups: (() => void)[] = [
|
|
677
696
|
() => driver.removeEventListener('history-updated', onHistoryUpdated),
|
|
678
697
|
() => driver.removeEventListener('sub-agent-history-updated', onSubAgentHistoryUpdated),
|
|
679
698
|
() => driver.removeEventListener('sub-agent-start', onSubAgentStart),
|
|
680
699
|
() => driver.removeEventListener('sub-agent-stop', onSubAgentStop),
|
|
700
|
+
() => driver.removeEventListener('interaction-start', onInteractionStart),
|
|
701
|
+
() => driver.removeEventListener('interaction-stop', onInteractionStop),
|
|
681
702
|
];
|
|
682
703
|
|
|
683
704
|
if (driver instanceof OrchestratingDriver) {
|
|
@@ -6,13 +6,14 @@ import type { AiAssistantAnimation, AiAssistantState, SuggestionsState } from '.
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* A single in-flight per-call chat-input override pushed by a `requestSubAgent`
|
|
9
|
-
*
|
|
10
|
-
* pop-in/pop-out and so a listener that connects
|
|
11
|
-
* effective mode without having seen the start
|
|
9
|
+
* or `requestInteraction` call. Tracked as an array (not a counter) so the
|
|
10
|
+
* slice can survive pop-in/pop-out and so a listener that connects
|
|
11
|
+
* mid-execution can compute the effective mode without having seen the start
|
|
12
|
+
* event.
|
|
12
13
|
*
|
|
13
14
|
* @internal
|
|
14
15
|
*/
|
|
15
|
-
export interface
|
|
16
|
+
export interface InputOverride {
|
|
16
17
|
/** Unique per-invocation id, paired with the start/stop events. */
|
|
17
18
|
id: string;
|
|
18
19
|
/** The mode requested for this invocation. */
|
|
@@ -54,11 +55,12 @@ export interface AiAssistantSessionState {
|
|
|
54
55
|
/** Name of the currently-executing sub-agent, or null when idle. */
|
|
55
56
|
liveSubAgentName: string | null;
|
|
56
57
|
/**
|
|
57
|
-
* In-flight per-call chat-input overrides pushed by `requestSubAgent`
|
|
58
|
-
* The most restrictive entry (`'hidden'` >
|
|
59
|
-
* means the agent-level
|
|
58
|
+
* In-flight per-call chat-input overrides pushed by `requestSubAgent` or
|
|
59
|
+
* `requestInteraction` calls. The most restrictive entry (`'hidden'` >
|
|
60
|
+
* `'disabled'`) wins; an empty list means the agent-level
|
|
61
|
+
* `chatInputDuringExecution` applies.
|
|
60
62
|
*/
|
|
61
|
-
|
|
63
|
+
inputOverrides: InputOverride[];
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
export const defaultSessionState: AiAssistantSessionState = {
|
|
@@ -77,7 +79,7 @@ export const defaultSessionState: AiAssistantSessionState = {
|
|
|
77
79
|
inputValue: '',
|
|
78
80
|
liveSubAgentTrace: [],
|
|
79
81
|
liveSubAgentName: null,
|
|
80
|
-
|
|
82
|
+
inputOverrides: [],
|
|
81
83
|
};
|
|
82
84
|
|
|
83
85
|
export const aiAssistantSlice = createSlice({
|
|
@@ -129,13 +131,11 @@ export const aiAssistantSlice = createSlice({
|
|
|
129
131
|
setLiveSubAgentName(state, action: PayloadAction<string | null>) {
|
|
130
132
|
state.liveSubAgentName = action.payload;
|
|
131
133
|
},
|
|
132
|
-
|
|
133
|
-
state.
|
|
134
|
+
addInputOverride(state, action: PayloadAction<InputOverride>) {
|
|
135
|
+
state.inputOverrides.push(action.payload);
|
|
134
136
|
},
|
|
135
|
-
|
|
136
|
-
state.
|
|
137
|
-
(o) => o.id !== action.payload.id,
|
|
138
|
-
);
|
|
137
|
+
removeInputOverride(state, action: PayloadAction<{ id: string }>) {
|
|
138
|
+
state.inputOverrides = state.inputOverrides.filter((o) => o.id !== action.payload.id);
|
|
139
139
|
},
|
|
140
140
|
},
|
|
141
141
|
selectors: {},
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
GenesisElement,
|
|
4
|
-
observable,
|
|
5
|
-
html,
|
|
6
|
-
css,
|
|
7
|
-
repeat,
|
|
8
|
-
when,
|
|
9
|
-
} from '@genesislcap/web-core';
|
|
1
|
+
import { customElement, observable, html, css, repeat, when } from '@genesislcap/web-core';
|
|
2
|
+
import { GenesisElement } from '@genesislcap/web-core';
|
|
10
3
|
import type { SuggestionsState } from '../main/main.types';
|
|
11
4
|
|
|
12
5
|
type LoadedState = { status: 'loaded'; suggestions: string[] };
|
package/src/tags/index.ts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|