@genesislcap/ai-assistant 14.403.0-ai-assistant.1
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 +4 -0
- package/dist/ai-assistant.api.json +4028 -0
- package/dist/ai-assistant.d.ts +396 -0
- package/dist/dts/channel/ai-activity-channel.d.ts +32 -0
- package/dist/dts/channel/ai-activity-channel.d.ts.map +1 -0
- package/dist/dts/components/activity-halo/activity-halo.d.ts +31 -0
- package/dist/dts/components/activity-halo/activity-halo.d.ts.map +1 -0
- package/dist/dts/components/chat-bubble/chat-bubble.d.ts +52 -0
- package/dist/dts/components/chat-bubble/chat-bubble.d.ts.map +1 -0
- package/dist/dts/components/chat-bubble/chat-bubble.styles.d.ts +2 -0
- package/dist/dts/components/chat-bubble/chat-bubble.styles.d.ts.map +1 -0
- package/dist/dts/components/chat-bubble/chat-bubble.template.d.ts +4 -0
- package/dist/dts/components/chat-bubble/chat-bubble.template.d.ts.map +1 -0
- package/dist/dts/components/chat-bubble/index.d.ts +2 -0
- package/dist/dts/components/chat-bubble/index.d.ts.map +1 -0
- package/dist/dts/components/chat-driver/chat-driver.d.ts +49 -0
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -0
- package/dist/dts/components/chat-driver/index.d.ts +2 -0
- package/dist/dts/components/chat-driver/index.d.ts.map +1 -0
- package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.d.ts +19 -0
- package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.d.ts.map +1 -0
- package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.d.ts +2 -0
- package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.d.ts.map +1 -0
- package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.template.d.ts +3 -0
- package/dist/dts/components/chat-interaction-wrapper/chat-interaction-wrapper.template.d.ts.map +1 -0
- package/dist/dts/components/chat-interaction-wrapper/index.d.ts +4 -0
- package/dist/dts/components/chat-interaction-wrapper/index.d.ts.map +1 -0
- package/dist/dts/components/chat-markdown/chat-markdown.d.ts +6 -0
- package/dist/dts/components/chat-markdown/chat-markdown.d.ts.map +1 -0
- package/dist/dts/components/chat-markdown/index.d.ts +2 -0
- package/dist/dts/components/chat-markdown/index.d.ts.map +1 -0
- package/dist/dts/components/halo-overlay.d.ts +25 -0
- package/dist/dts/components/halo-overlay.d.ts.map +1 -0
- package/dist/dts/config/config.d.ts +51 -0
- package/dist/dts/config/config.d.ts.map +1 -0
- package/dist/dts/config/configure.d.ts +1 -0
- package/dist/dts/config/configure.d.ts.map +1 -0
- package/dist/dts/config/index.d.ts +2 -0
- package/dist/dts/config/index.d.ts.map +1 -0
- package/dist/dts/index.d.ts +10 -0
- package/dist/dts/index.d.ts.map +1 -0
- package/dist/dts/main/index.d.ts +5 -0
- package/dist/dts/main/index.d.ts.map +1 -0
- package/dist/dts/main/main.d.ts +103 -0
- package/dist/dts/main/main.d.ts.map +1 -0
- package/dist/dts/main/main.styles.d.ts +2 -0
- package/dist/dts/main/main.styles.d.ts.map +1 -0
- package/dist/dts/main/main.template.d.ts +4 -0
- package/dist/dts/main/main.template.d.ts.map +1 -0
- package/dist/dts/main/main.types.d.ts +54 -0
- package/dist/dts/main/main.types.d.ts.map +1 -0
- package/dist/dts/styles/index.d.ts +2 -0
- package/dist/dts/styles/index.d.ts.map +1 -0
- package/dist/dts/styles/styles.d.ts +5 -0
- package/dist/dts/styles/styles.d.ts.map +1 -0
- package/dist/dts/tags/index.d.ts +1 -0
- package/dist/dts/tags/index.d.ts.map +1 -0
- package/dist/dts/types/ai-chat-widget.d.ts +12 -0
- package/dist/dts/types/ai-chat-widget.d.ts.map +1 -0
- package/dist/dts/utils/index.d.ts +2 -0
- package/dist/dts/utils/index.d.ts.map +1 -0
- package/dist/dts/utils/logger.d.ts +2 -0
- package/dist/dts/utils/logger.d.ts.map +1 -0
- package/dist/esm/channel/ai-activity-channel.js +2 -0
- package/dist/esm/components/activity-halo/activity-halo.js +119 -0
- package/dist/esm/components/chat-bubble/chat-bubble.js +381 -0
- package/dist/esm/components/chat-bubble/chat-bubble.styles.js +193 -0
- package/dist/esm/components/chat-bubble/chat-bubble.template.js +50 -0
- package/dist/esm/components/chat-bubble/index.js +1 -0
- package/dist/esm/components/chat-driver/chat-driver.js +209 -0
- package/dist/esm/components/chat-driver/index.js +1 -0
- package/dist/esm/components/chat-interaction-wrapper/chat-interaction-wrapper.js +90 -0
- package/dist/esm/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.js +6 -0
- package/dist/esm/components/chat-interaction-wrapper/chat-interaction-wrapper.template.js +4 -0
- package/dist/esm/components/chat-interaction-wrapper/index.js +3 -0
- package/dist/esm/components/chat-markdown/chat-markdown.js +95 -0
- package/dist/esm/components/chat-markdown/index.js +1 -0
- package/dist/esm/components/halo-overlay.js +118 -0
- package/dist/esm/config/config.js +16 -0
- package/dist/esm/config/configure.js +0 -0
- package/dist/esm/config/index.js +1 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/main/index.js +4 -0
- package/dist/esm/main/main.js +491 -0
- package/dist/esm/main/main.styles.js +356 -0
- package/dist/esm/main/main.template.js +272 -0
- package/dist/esm/main/main.types.js +22 -0
- package/dist/esm/styles/index.js +1 -0
- package/dist/esm/styles/styles.js +237 -0
- package/dist/esm/tags/index.js +0 -0
- package/dist/esm/types/ai-chat-widget.js +1 -0
- package/dist/esm/utils/index.js +1 -0
- package/dist/esm/utils/logger.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/tsdoc-metadata.json +11 -0
- package/docs/.gitattributes +2 -0
- package/docs/api/ai-assistant.ai_activity_channel_name.md +11 -0
- package/docs/api/ai-assistant.aiactivityevents.md +24 -0
- package/docs/api/ai-assistant.aiactivityhalo.channelname.md +16 -0
- package/docs/api/ai-assistant.aiactivityhalo.connectedcallback.md +18 -0
- package/docs/api/ai-assistant.aiactivityhalo.disconnectedcallback.md +18 -0
- package/docs/api/ai-assistant.aiactivityhalo.haloactive.md +14 -0
- package/docs/api/ai-assistant.aiactivityhalo.md +176 -0
- package/docs/api/ai-assistant.aiactivityhalo.minshowtime.md +16 -0
- package/docs/api/ai-assistant.aiactivityhalo.tools.md +16 -0
- package/docs/api/ai-assistant.aiassistantanimation.md +18 -0
- package/docs/api/ai-assistant.aiassistantanimationdef.label.md +16 -0
- package/docs/api/ai-assistant.aiassistantanimationdef.md +80 -0
- package/docs/api/ai-assistant.aiassistantanimationdef.tooltip.md +16 -0
- package/docs/api/ai-assistant.aiassistantconfig.chatconfig.md +16 -0
- package/docs/api/ai-assistant.aiassistantconfig.debugstatefactory.md +16 -0
- package/docs/api/ai-assistant.aiassistantconfig.headertitle.md +16 -0
- package/docs/api/ai-assistant.aiassistantconfig.md +157 -0
- package/docs/api/ai-assistant.aiassistantconfig.systemprompt.md +16 -0
- package/docs/api/ai-assistant.aiassistantconfig.tooldefinitions.md +16 -0
- package/docs/api/ai-assistant.aiassistantconfig.toolhandlers.md +16 -0
- package/docs/api/ai-assistant.aiassistantserializedstate.enabledanimations.md +14 -0
- package/docs/api/ai-assistant.aiassistantserializedstate.md +118 -0
- package/docs/api/ai-assistant.aiassistantserializedstate.messages.md +14 -0
- package/docs/api/ai-assistant.aiassistantserializedstate.showthinkingsteps.md +14 -0
- package/docs/api/ai-assistant.aiassistantserializedstate.showtoolcalls.md +14 -0
- package/docs/api/ai-assistant.aiassistantstate.md +16 -0
- package/docs/api/ai-assistant.aichatbubble.bubbleleft.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.bubbletop.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.channelname.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.connectedcallback.md +15 -0
- package/docs/api/ai-assistant.aichatbubble.designsystemprefix.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.dialogcontent.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.dialogcontentchanged.md +64 -0
- package/docs/api/ai-assistant.aichatbubble.dialogheight.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.dialogleft.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.dialogopen.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.dialogopenchanged.md +64 -0
- package/docs/api/ai-assistant.aichatbubble.dialogtop.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.dialogwidth.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.disconnectedcallback.md +15 -0
- package/docs/api/ai-assistant.aichatbubble.hovered.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.imagesrc.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.md +396 -0
- package/docs/api/ai-assistant.aichatbubble.onbubblemousedown.md +50 -0
- package/docs/api/ai-assistant.aichatbubble.onclosedialog.md +15 -0
- package/docs/api/ai-assistant.aichatbubble.ondialogheadermousedown.md +53 -0
- package/docs/api/ai-assistant.aichatbubble.onpopout.md +15 -0
- package/docs/api/ai-assistant.aichatbubble.title.md +11 -0
- package/docs/api/ai-assistant.aichatbubble.tooltipstyle.md +11 -0
- package/docs/api/ai-assistant.aichatwidget.data.md +14 -0
- package/docs/api/ai-assistant.aichatwidget.md +80 -0
- package/docs/api/ai-assistant.aichatwidget.resolved.md +16 -0
- package/docs/api/ai-assistant.animation_defs.md +25 -0
- package/docs/api/ai-assistant.chatdriver._constructor_.md +99 -0
- package/docs/api/ai-assistant.chatdriver.gethistory.md +18 -0
- package/docs/api/ai-assistant.chatdriver.isbusy.md +18 -0
- package/docs/api/ai-assistant.chatdriver.loadhistory.md +55 -0
- package/docs/api/ai-assistant.chatdriver.md +158 -0
- package/docs/api/ai-assistant.chatdriver.requestinteraction.md +73 -0
- package/docs/api/ai-assistant.chatdriver.resolveinteraction.md +69 -0
- package/docs/api/ai-assistant.chatdriver.sendmessage.md +69 -0
- package/docs/api/ai-assistant.chathistoryupdatedevent.md +16 -0
- package/docs/api/ai-assistant.defaultaiassistantconfig.md +16 -0
- package/docs/api/ai-assistant.foundationaiassistant.aiprovider.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.applystate.md +55 -0
- package/docs/api/ai-assistant.foundationaiassistant.attachmenterrors.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.attachments.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.channelname.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.chatconfig.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.connectedcallback.md +18 -0
- package/docs/api/ai-assistant.foundationaiassistant.debugstatefactory.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.designsystemprefix.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.disconnectedcallback.md +18 -0
- package/docs/api/ai-assistant.foundationaiassistant.downloadhistory.md +18 -0
- package/docs/api/ai-assistant.foundationaiassistant.enabledanimations.md +16 -0
- package/docs/api/ai-assistant.foundationaiassistant.handlefileselect.md +53 -0
- package/docs/api/ai-assistant.foundationaiassistant.handleinteractioncompleted.md +53 -0
- package/docs/api/ai-assistant.foundationaiassistant.handlepopout.md +20 -0
- package/docs/api/ai-assistant.foundationaiassistant.handlesendclick.md +18 -0
- package/docs/api/ai-assistant.foundationaiassistant.hasactivependinginteraction.md +16 -0
- package/docs/api/ai-assistant.foundationaiassistant.headertitle.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.imagesrc.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.inputvalue.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.md +826 -0
- package/docs/api/ai-assistant.foundationaiassistant.messages.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.messageschanged.md +18 -0
- package/docs/api/ai-assistant.foundationaiassistant.onchatheadermousedown.md +53 -0
- package/docs/api/ai-assistant.foundationaiassistant.placeholder.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.popoutmode.md +16 -0
- package/docs/api/ai-assistant.foundationaiassistant.removeattachment.md +53 -0
- package/docs/api/ai-assistant.foundationaiassistant.removeattachmenterror.md +53 -0
- package/docs/api/ai-assistant.foundationaiassistant.setenabledanimations.md +53 -0
- package/docs/api/ai-assistant.foundationaiassistant.settingsopen.md +16 -0
- package/docs/api/ai-assistant.foundationaiassistant.showhalo.md +16 -0
- package/docs/api/ai-assistant.foundationaiassistant.showhalochanged.md +18 -0
- package/docs/api/ai-assistant.foundationaiassistant.showloadingindicator.md +16 -0
- package/docs/api/ai-assistant.foundationaiassistant.showloadingindicatorchanged.md +18 -0
- package/docs/api/ai-assistant.foundationaiassistant.showthinkingsteps.md +16 -0
- package/docs/api/ai-assistant.foundationaiassistant.showtoolcalls.md +16 -0
- package/docs/api/ai-assistant.foundationaiassistant.state.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.statechanged.md +18 -0
- package/docs/api/ai-assistant.foundationaiassistant.systemprompt.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.togglesettings.md +18 -0
- package/docs/api/ai-assistant.foundationaiassistant.toggleshowthinkingsteps.md +18 -0
- package/docs/api/ai-assistant.foundationaiassistant.toggleshowtoolcalls.md +18 -0
- package/docs/api/ai-assistant.foundationaiassistant.tooldefinitions.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.toolhandlers.md +14 -0
- package/docs/api/ai-assistant.foundationaiassistant.triggerfileinput.md +18 -0
- package/docs/api/ai-assistant.foundationaiassistant.visiblemessages.md +16 -0
- package/docs/api/ai-assistant.foundationaiassistanttemplate.md +50 -0
- package/docs/api/ai-assistant.md +262 -0
- package/docs/api/ai-assistant.popoutmode.md +16 -0
- package/docs/api/index.md +30 -0
- package/docs/api-report.md.api.md +280 -0
- package/license.txt +46 -0
- package/package.json +92 -0
- package/src/channel/ai-activity-channel.ts +30 -0
- package/src/components/activity-halo/activity-halo.ts +113 -0
- package/src/components/chat-bubble/chat-bubble.styles.ts +194 -0
- package/src/components/chat-bubble/chat-bubble.template.ts +63 -0
- package/src/components/chat-bubble/chat-bubble.ts +389 -0
- package/src/components/chat-bubble/index.ts +1 -0
- package/src/components/chat-driver/chat-driver.ts +254 -0
- package/src/components/chat-driver/index.ts +1 -0
- package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.ts +7 -0
- package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.template.ts +6 -0
- package/src/components/chat-interaction-wrapper/chat-interaction-wrapper.ts +89 -0
- package/src/components/chat-interaction-wrapper/index.ts +3 -0
- package/src/components/chat-markdown/chat-markdown.ts +87 -0
- package/src/components/chat-markdown/index.ts +1 -0
- package/src/components/halo-overlay.ts +115 -0
- package/src/config/config.ts +59 -0
- package/src/config/configure.ts +0 -0
- package/src/config/index.ts +1 -0
- package/src/index.ts +9 -0
- package/src/main/index.ts +4 -0
- package/src/main/main.styles.ts +357 -0
- package/src/main/main.template.ts +364 -0
- package/src/main/main.ts +474 -0
- package/src/main/main.types.ts +58 -0
- package/src/styles/index.ts +1 -0
- package/src/styles/styles.ts +238 -0
- package/src/tags/index.ts +0 -0
- package/src/types/ai-chat-widget.ts +11 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/logger.ts +3 -0
- package/temp/api-report.md.api.md +280 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { MalformedFunctionCallError } from '@genesislcap/foundation-ai';
|
|
3
|
+
import { logger } from '../../utils/logger';
|
|
4
|
+
const MAX_TOOL_ITERATIONS = 10;
|
|
5
|
+
const MAX_MALFORMED_RETRIES = 2;
|
|
6
|
+
/**
|
|
7
|
+
* Plain TS class that drives a multi-turn chat conversation, including the tool-call loop.
|
|
8
|
+
* Owned by `FoundationAiAssistant` — created in `connectedCallback`, torn down in `disconnectedCallback`.
|
|
9
|
+
*
|
|
10
|
+
* Dispatches `'history-updated'` events on itself so the owning element can observe changes.
|
|
11
|
+
*
|
|
12
|
+
* @beta
|
|
13
|
+
*/
|
|
14
|
+
export class ChatDriver extends EventTarget {
|
|
15
|
+
constructor(aiProvider, toolHandlers = {}, toolDefinitions = [], systemPrompt) {
|
|
16
|
+
super();
|
|
17
|
+
this.aiProvider = aiProvider;
|
|
18
|
+
this.toolHandlers = toolHandlers;
|
|
19
|
+
this.toolDefinitions = toolDefinitions;
|
|
20
|
+
this.systemPrompt = systemPrompt;
|
|
21
|
+
this.history = [];
|
|
22
|
+
this.busy = false;
|
|
23
|
+
this.pendingInteractions = new Map();
|
|
24
|
+
}
|
|
25
|
+
getHistory() {
|
|
26
|
+
return this.history;
|
|
27
|
+
}
|
|
28
|
+
isBusy() {
|
|
29
|
+
return this.busy;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Request a custom UI interaction. Emits a new message with the interaction.
|
|
33
|
+
* Tool handlers can call this to pause execution until the user completes the UI interaction.
|
|
34
|
+
*
|
|
35
|
+
* @param componentName - The custom element name to render.
|
|
36
|
+
* @param data - Data to pass to the component.
|
|
37
|
+
*/
|
|
38
|
+
requestInteraction(componentName, data) {
|
|
39
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
40
|
+
const interactionId = crypto.randomUUID();
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
this.pendingInteractions.set(interactionId, { resolve, reject });
|
|
43
|
+
this.appendToHistory({
|
|
44
|
+
role: 'assistant',
|
|
45
|
+
content: '',
|
|
46
|
+
interaction: { interactionId, componentName, data },
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolve a pending interaction. The wrapper component calls this on completion.
|
|
53
|
+
* Marks the interaction message as resolved so it renders read-only on re-render.
|
|
54
|
+
*/
|
|
55
|
+
resolveInteraction(interactionId, result) {
|
|
56
|
+
const interaction = this.pendingInteractions.get(interactionId);
|
|
57
|
+
if (interaction) {
|
|
58
|
+
// Mark the message as resolved before resolving the promise so the next
|
|
59
|
+
// history-updated event carries the updated flag.
|
|
60
|
+
const msg = this.history.find((m) => { var _a; return ((_a = m.interaction) === null || _a === void 0 ? void 0 : _a.interactionId) === interactionId; });
|
|
61
|
+
if (msg === null || msg === void 0 ? void 0 : msg.interaction) {
|
|
62
|
+
msg.interaction.resolved = true;
|
|
63
|
+
this.dispatchEvent(new CustomEvent('history-updated', {
|
|
64
|
+
detail: this.history,
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
interaction.resolve(result);
|
|
68
|
+
this.pendingInteractions.delete(interactionId);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
logger.warn(`Interaction with ID ${interactionId} not found.`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Seeds the driver with a prior conversation history so a new component instance
|
|
76
|
+
* can continue an existing conversation. Call this before the first user message.
|
|
77
|
+
*/
|
|
78
|
+
loadHistory(messages) {
|
|
79
|
+
this.history = [...messages];
|
|
80
|
+
}
|
|
81
|
+
sendMessage(userInput, attachments) {
|
|
82
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
83
|
+
if (this.busy || (!userInput.trim() && !(attachments === null || attachments === void 0 ? void 0 : attachments.length)))
|
|
84
|
+
return;
|
|
85
|
+
if (!this.aiProvider.chat) {
|
|
86
|
+
logger.warn('ChatDriver: AIProvider does not implement chat()');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
this.busy = true;
|
|
90
|
+
this.appendToHistory({ role: 'user', content: userInput, attachments });
|
|
91
|
+
try {
|
|
92
|
+
yield this.runToolLoop(userInput, attachments);
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
logger.error('ChatDriver error:', e);
|
|
96
|
+
this.appendToHistory({ role: 'assistant', content: 'Sorry, something went wrong.' });
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
this.busy = false;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
runToolLoop(userInput, attachments) {
|
|
104
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
105
|
+
var _a, _b, _c, _d, _e;
|
|
106
|
+
const baseOptions = {
|
|
107
|
+
systemPrompt: this.systemPrompt,
|
|
108
|
+
tools: this.toolDefinitions.length ? this.toolDefinitions : undefined,
|
|
109
|
+
};
|
|
110
|
+
// History has the user message at the end — pass everything before it as history,
|
|
111
|
+
// and the user input as the userMessage argument.
|
|
112
|
+
let currentInput = userInput;
|
|
113
|
+
let currentAttachments = attachments;
|
|
114
|
+
let iterations = 0;
|
|
115
|
+
let malformedAttempts = 0;
|
|
116
|
+
while (iterations < MAX_TOOL_ITERATIONS) {
|
|
117
|
+
iterations += 1;
|
|
118
|
+
// On the first iteration, the last item in history is the user message which is
|
|
119
|
+
// passed separately as currentInput — exclude it. On subsequent iterations, the
|
|
120
|
+
// full history (including tool results) should be sent and currentInput is empty.
|
|
121
|
+
const historyForCall = iterations === 1 ? this.history.slice(0, -1) : [...this.history];
|
|
122
|
+
// On malformed-call retries, augment the system prompt to steer the model
|
|
123
|
+
// away from generating Python-style batched function call syntax.
|
|
124
|
+
const systemPrompt = malformedAttempts > 0
|
|
125
|
+
? `${(_a = baseOptions.systemPrompt) !== null && _a !== void 0 ? _a : ''}\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.`
|
|
126
|
+
: baseOptions.systemPrompt;
|
|
127
|
+
const options = Object.assign(Object.assign({}, baseOptions), { systemPrompt, attachments: currentAttachments });
|
|
128
|
+
let response;
|
|
129
|
+
try {
|
|
130
|
+
// eslint-disable-next-line no-await-in-loop
|
|
131
|
+
response = yield this.aiProvider.chat(historyForCall, currentInput, options);
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
if (e instanceof MalformedFunctionCallError) {
|
|
135
|
+
malformedAttempts += 1;
|
|
136
|
+
if (malformedAttempts < MAX_MALFORMED_RETRIES) {
|
|
137
|
+
logger.warn(`ChatDriver: MALFORMED_FUNCTION_CALL, retrying (${malformedAttempts}/${MAX_MALFORMED_RETRIES})`);
|
|
138
|
+
iterations -= 1; // don't consume an iteration budget slot for a failed attempt
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
logger.error('ChatDriver: MALFORMED_FUNCTION_CALL, max retries reached');
|
|
142
|
+
this.appendToHistory({
|
|
143
|
+
role: 'assistant',
|
|
144
|
+
content: "I'm sorry, I wasn't able to complete that request. Please try rephrasing or breaking it into smaller steps.",
|
|
145
|
+
});
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
throw e;
|
|
149
|
+
}
|
|
150
|
+
currentAttachments = undefined; // attachments only sent on first call
|
|
151
|
+
const isThinkingStep = response.content && ((_b = response.toolCalls) === null || _b === void 0 ? void 0 : _b.length);
|
|
152
|
+
const isEmptyResponse = !((_c = response.content) === null || _c === void 0 ? void 0 : _c.trim()) && !((_d = response.toolCalls) === null || _d === void 0 ? void 0 : _d.length);
|
|
153
|
+
if (isEmptyResponse) {
|
|
154
|
+
// Do nothing, discard empty/whitespace-only responses
|
|
155
|
+
}
|
|
156
|
+
else if (isThinkingStep) {
|
|
157
|
+
// Separate thinking message and tool call message
|
|
158
|
+
this.appendToHistory(Object.assign(Object.assign({}, response), { toolCalls: undefined, thinking: true }));
|
|
159
|
+
this.appendToHistory(Object.assign(Object.assign({}, response), { content: '' }));
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
this.appendToHistory(response);
|
|
163
|
+
}
|
|
164
|
+
if (!((_e = response.toolCalls) === null || _e === void 0 ? void 0 : _e.length)) {
|
|
165
|
+
// Terminal text response — done
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
// Execute all tool calls for this iteration concurrently, then append results in order
|
|
169
|
+
// eslint-disable-next-line no-await-in-loop
|
|
170
|
+
const toolResults = yield Promise.all(response.toolCalls.map((tc) => __awaiter(this, void 0, void 0, function* () {
|
|
171
|
+
const handler = this.toolHandlers[tc.name];
|
|
172
|
+
if (!handler) {
|
|
173
|
+
logger.warn(`ChatDriver: no handler registered for tool "${tc.name}"`);
|
|
174
|
+
return { toolCallId: tc.id, content: `Unknown tool: ${tc.name}` };
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
const result = yield handler(tc.args, {
|
|
178
|
+
requestInteraction: (componentName, data) => this.requestInteraction(componentName, data),
|
|
179
|
+
});
|
|
180
|
+
const content = typeof result === 'string' ? result : JSON.stringify(result);
|
|
181
|
+
return { toolCallId: tc.id, content };
|
|
182
|
+
}
|
|
183
|
+
catch (e) {
|
|
184
|
+
logger.error(`ChatDriver tool "${tc.name}" failed:`, e);
|
|
185
|
+
return { toolCallId: tc.id, content: `Tool error: ${e.message}` };
|
|
186
|
+
}
|
|
187
|
+
})));
|
|
188
|
+
for (const result of toolResults) {
|
|
189
|
+
this.appendToHistory({
|
|
190
|
+
role: 'tool',
|
|
191
|
+
content: '',
|
|
192
|
+
toolResult: result,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
// Next iteration sends an empty string — the tool results are in history
|
|
196
|
+
currentInput = '';
|
|
197
|
+
}
|
|
198
|
+
if (iterations >= MAX_TOOL_ITERATIONS) {
|
|
199
|
+
logger.warn('ChatDriver: reached max tool iterations, stopping');
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
appendToHistory(message) {
|
|
204
|
+
this.history = [...this.history, message];
|
|
205
|
+
this.dispatchEvent(new CustomEvent('history-updated', {
|
|
206
|
+
detail: this.history,
|
|
207
|
+
}));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './chat-driver';
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { customElement, GenesisElement, observable } from '@genesislcap/web-core';
|
|
3
|
+
import { logger } from '../../utils/logger';
|
|
4
|
+
import { AiChatInteractionWrapperStyles } from './chat-interaction-wrapper.styles';
|
|
5
|
+
import { AiChatInteractionWrapperTemplate } from './chat-interaction-wrapper.template';
|
|
6
|
+
let AiChatInteractionWrapper = class AiChatInteractionWrapper extends GenesisElement {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(...arguments);
|
|
9
|
+
this.componentName = '';
|
|
10
|
+
this.interactionId = '';
|
|
11
|
+
/** When true, the interaction has already been resolved. Forwarded to the rendered component. */
|
|
12
|
+
this.resolved = false;
|
|
13
|
+
}
|
|
14
|
+
connectedCallback() {
|
|
15
|
+
super.connectedCallback();
|
|
16
|
+
this.renderComponent();
|
|
17
|
+
}
|
|
18
|
+
componentNameChanged() {
|
|
19
|
+
this.renderComponent();
|
|
20
|
+
}
|
|
21
|
+
resolvedChanged() {
|
|
22
|
+
var _a;
|
|
23
|
+
// TODO: switch to FAST ref() or slotted children directives instead of querying the container
|
|
24
|
+
// imperatively — this would allow property bindings to flow naturally through the template.
|
|
25
|
+
const container = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.container');
|
|
26
|
+
const element = container === null || container === void 0 ? void 0 : container.firstElementChild;
|
|
27
|
+
if (element) {
|
|
28
|
+
element.resolved = this.resolved;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
renderComponent() {
|
|
32
|
+
var _a;
|
|
33
|
+
const container = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.container');
|
|
34
|
+
if (!container || !this.componentName)
|
|
35
|
+
return;
|
|
36
|
+
// Clear children without using innerHTML
|
|
37
|
+
container.replaceChildren();
|
|
38
|
+
if (!customElements.get(this.componentName)) {
|
|
39
|
+
logger.warn(`Interactive component "\${this.componentName}" is not registered in the customElements registry.`);
|
|
40
|
+
const errorDiv = document.createElement('div');
|
|
41
|
+
errorDiv.textContent = `Error: Component "\${this.componentName}" is not available in this application.`;
|
|
42
|
+
container.appendChild(errorDiv);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const element = document.createElement(this.componentName);
|
|
47
|
+
// Pass data and resolved state to the component
|
|
48
|
+
if (this.data) {
|
|
49
|
+
element.data = this.data;
|
|
50
|
+
}
|
|
51
|
+
element.resolved = this.resolved;
|
|
52
|
+
// Handle completion from the inner component.
|
|
53
|
+
// Guard against re-emission if the interaction was already resolved
|
|
54
|
+
// (e.g. auto-resolve components fire on connectedCallback when rendering history).
|
|
55
|
+
element.addEventListener('interaction-completed', (e) => {
|
|
56
|
+
e.stopPropagation();
|
|
57
|
+
if (this.resolved)
|
|
58
|
+
return;
|
|
59
|
+
this.$emit('interaction-completed', Object.assign({ interactionId: this.interactionId }, e.detail));
|
|
60
|
+
});
|
|
61
|
+
container.appendChild(element);
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
logger.error(`Failed to create interactive component: \${this.componentName}`, e);
|
|
65
|
+
const errorDiv = document.createElement('div');
|
|
66
|
+
errorDiv.textContent = `Error: Could not load component \${this.componentName}`;
|
|
67
|
+
container.appendChild(errorDiv);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
__decorate([
|
|
72
|
+
observable
|
|
73
|
+
], AiChatInteractionWrapper.prototype, "componentName", void 0);
|
|
74
|
+
__decorate([
|
|
75
|
+
observable
|
|
76
|
+
], AiChatInteractionWrapper.prototype, "data", void 0);
|
|
77
|
+
__decorate([
|
|
78
|
+
observable
|
|
79
|
+
], AiChatInteractionWrapper.prototype, "interactionId", void 0);
|
|
80
|
+
__decorate([
|
|
81
|
+
observable
|
|
82
|
+
], AiChatInteractionWrapper.prototype, "resolved", void 0);
|
|
83
|
+
AiChatInteractionWrapper = __decorate([
|
|
84
|
+
customElement({
|
|
85
|
+
name: 'ai-chat-interaction-wrapper',
|
|
86
|
+
template: AiChatInteractionWrapperTemplate,
|
|
87
|
+
styles: AiChatInteractionWrapperStyles,
|
|
88
|
+
})
|
|
89
|
+
], AiChatInteractionWrapper);
|
|
90
|
+
export { AiChatInteractionWrapper };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { css, customElement, GenesisElement, html, observable } from '@genesislcap/web-core';
|
|
3
|
+
import DOMPurify from 'dompurify';
|
|
4
|
+
import { marked } from 'marked';
|
|
5
|
+
const styles = css `
|
|
6
|
+
:host {
|
|
7
|
+
display: block;
|
|
8
|
+
font-size: var(--type-ramp-base-font-size);
|
|
9
|
+
line-height: var(--type-ramp-base-line-height);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
p {
|
|
13
|
+
margin: 0 0 calc(var(--design-unit, 4) * 2px);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
p:last-child {
|
|
17
|
+
margin-bottom: 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
ul,
|
|
21
|
+
ol {
|
|
22
|
+
margin: 0 0 calc(var(--design-unit, 4) * 2px);
|
|
23
|
+
padding-left: calc(var(--design-unit, 4) * 5px);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
code {
|
|
27
|
+
background-color: var(--neutral-fill-rest);
|
|
28
|
+
padding: 2px 4px;
|
|
29
|
+
border-radius: calc(var(--design-unit, 4) * 0.5px);
|
|
30
|
+
font-family: monospace;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
pre {
|
|
34
|
+
background-color: var(--neutral-fill-rest);
|
|
35
|
+
padding: calc(var(--design-unit, 4) * 2px);
|
|
36
|
+
border-radius: calc(var(--design-unit, 4) * 1px);
|
|
37
|
+
overflow-x: auto;
|
|
38
|
+
border: 1px solid var(--neutral-stroke-rest);
|
|
39
|
+
margin: calc(var(--design-unit, 4) * 2px) 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
pre code {
|
|
43
|
+
background-color: transparent;
|
|
44
|
+
padding: 0;
|
|
45
|
+
border-radius: 0;
|
|
46
|
+
border: none;
|
|
47
|
+
font-family: inherit;
|
|
48
|
+
color: inherit;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
table {
|
|
52
|
+
display: block;
|
|
53
|
+
overflow-x: auto;
|
|
54
|
+
border-collapse: collapse;
|
|
55
|
+
max-width: 100%;
|
|
56
|
+
margin: calc(var(--design-unit, 4) * 2px) 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
th,
|
|
60
|
+
td {
|
|
61
|
+
border: 1px solid var(--neutral-stroke-rest);
|
|
62
|
+
padding: calc(var(--design-unit, 4) * 1px) calc(var(--design-unit, 4) * 2.5px);
|
|
63
|
+
white-space: nowrap;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
th {
|
|
67
|
+
background-color: var(--neutral-fill-stealth-rest);
|
|
68
|
+
font-weight: 600;
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
let AiChatMarkdown = class AiChatMarkdown extends GenesisElement {
|
|
72
|
+
constructor() {
|
|
73
|
+
super(...arguments);
|
|
74
|
+
this.content = '';
|
|
75
|
+
}
|
|
76
|
+
renderMarkdown() {
|
|
77
|
+
if (!this.content)
|
|
78
|
+
return '';
|
|
79
|
+
const rawHtml = marked.parse(this.content);
|
|
80
|
+
return DOMPurify.sanitize(rawHtml);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
__decorate([
|
|
84
|
+
observable
|
|
85
|
+
], AiChatMarkdown.prototype, "content", void 0);
|
|
86
|
+
AiChatMarkdown = __decorate([
|
|
87
|
+
customElement({
|
|
88
|
+
name: 'ai-chat-markdown',
|
|
89
|
+
template: html `
|
|
90
|
+
<div :innerHTML="${(x) => x.renderMarkdown()}"></div>
|
|
91
|
+
`,
|
|
92
|
+
styles,
|
|
93
|
+
})
|
|
94
|
+
], AiChatMarkdown);
|
|
95
|
+
export { AiChatMarkdown };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './chat-markdown';
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
var AiHaloOverlay_1;
|
|
2
|
+
import { __decorate } from "tslib";
|
|
3
|
+
import { attr, css, customElement, GenesisElement, html } from '@genesislcap/web-core';
|
|
4
|
+
/**
|
|
5
|
+
* Animated halo overlay — rotating conic-gradient border with an inward glow.
|
|
6
|
+
*
|
|
7
|
+
* Drop inside any `position: relative; overflow: hidden` container and toggle
|
|
8
|
+
* the `active` attribute to show/hide the effect.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```html
|
|
12
|
+
* <ai-halo-overlay ?active="${(x) => x.isLoading}"></ai-halo-overlay>
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* @beta
|
|
16
|
+
*/
|
|
17
|
+
let AiHaloOverlay = AiHaloOverlay_1 = class AiHaloOverlay extends GenesisElement {
|
|
18
|
+
constructor() {
|
|
19
|
+
super(...arguments);
|
|
20
|
+
this.active = false;
|
|
21
|
+
this.angle = 0;
|
|
22
|
+
}
|
|
23
|
+
connectedCallback() {
|
|
24
|
+
super.connectedCallback();
|
|
25
|
+
this.tick();
|
|
26
|
+
}
|
|
27
|
+
disconnectedCallback() {
|
|
28
|
+
super.disconnectedCallback();
|
|
29
|
+
if (this.animFrame !== undefined) {
|
|
30
|
+
cancelAnimationFrame(this.animFrame);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
tick() {
|
|
34
|
+
this.angle = (this.angle + AiHaloOverlay_1.DEG_PER_FRAME) % AiHaloOverlay_1.FULL_ROTATION_DEG;
|
|
35
|
+
this.style.setProperty('--halo-angle', `${this.angle}deg`);
|
|
36
|
+
this.animFrame = requestAnimationFrame(() => this.tick());
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
// TODO: The rAF loop is fine for demos but has two drawbacks vs a pure CSS @property animation:
|
|
40
|
+
// 1. It runs on the main thread, so heavy JS work can cause the animation to stutter.
|
|
41
|
+
// 2. The loop ticks even when `active` is false (idle cost is negligible but non-zero).
|
|
42
|
+
// Once @property inside Shadow DOM has solid cross-browser support, consider switching back
|
|
43
|
+
// to a CSS @keyframes approach and removing connectedCallback/disconnectedCallback/tick().
|
|
44
|
+
// 1.5° per frame @ 60 fps ≈ 4 s per full revolution
|
|
45
|
+
AiHaloOverlay.DEG_PER_FRAME = 1.5;
|
|
46
|
+
AiHaloOverlay.FULL_ROTATION_DEG = 360;
|
|
47
|
+
__decorate([
|
|
48
|
+
attr({ mode: 'boolean' })
|
|
49
|
+
], AiHaloOverlay.prototype, "active", void 0);
|
|
50
|
+
AiHaloOverlay = AiHaloOverlay_1 = __decorate([
|
|
51
|
+
customElement({
|
|
52
|
+
name: 'ai-halo-overlay',
|
|
53
|
+
template: html `
|
|
54
|
+
<slot></slot>
|
|
55
|
+
`,
|
|
56
|
+
styles: css `
|
|
57
|
+
:host {
|
|
58
|
+
display: block;
|
|
59
|
+
position: absolute;
|
|
60
|
+
inset: 0;
|
|
61
|
+
border-radius: inherit;
|
|
62
|
+
pointer-events: none;
|
|
63
|
+
z-index: 1000;
|
|
64
|
+
opacity: 0;
|
|
65
|
+
transition: opacity 0.4s ease;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
:host([active]) {
|
|
69
|
+
opacity: 1;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Rotating solid border */
|
|
73
|
+
:host::before {
|
|
74
|
+
content: '';
|
|
75
|
+
position: absolute;
|
|
76
|
+
inset: 0;
|
|
77
|
+
border-radius: inherit;
|
|
78
|
+
padding: 3px;
|
|
79
|
+
background: repeating-conic-gradient(
|
|
80
|
+
from var(--halo-angle, 0deg),
|
|
81
|
+
#feb60a,
|
|
82
|
+
#ff0062,
|
|
83
|
+
#00dbf9,
|
|
84
|
+
#da00f7,
|
|
85
|
+
#feb60a
|
|
86
|
+
);
|
|
87
|
+
-webkit-mask:
|
|
88
|
+
linear-gradient(#000 0 0) content-box,
|
|
89
|
+
linear-gradient(#000 0 0);
|
|
90
|
+
mask:
|
|
91
|
+
linear-gradient(#000 0 0) content-box,
|
|
92
|
+
linear-gradient(#000 0 0);
|
|
93
|
+
-webkit-mask-composite: destination-out;
|
|
94
|
+
mask-composite: exclude;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Inward glow — radial mask makes centre transparent, edges coloured */
|
|
98
|
+
:host::after {
|
|
99
|
+
content: '';
|
|
100
|
+
position: absolute;
|
|
101
|
+
inset: 0;
|
|
102
|
+
border-radius: inherit;
|
|
103
|
+
background: repeating-conic-gradient(
|
|
104
|
+
from var(--halo-angle, 0deg),
|
|
105
|
+
#feb60a,
|
|
106
|
+
#ff0062,
|
|
107
|
+
#00dbf9,
|
|
108
|
+
#da00f7,
|
|
109
|
+
#feb60a
|
|
110
|
+
);
|
|
111
|
+
opacity: 0.35;
|
|
112
|
+
-webkit-mask-image: radial-gradient(ellipse at center, transparent 70%, black 100%);
|
|
113
|
+
mask-image: radial-gradient(ellipse at center, transparent 70%, black 100%);
|
|
114
|
+
}
|
|
115
|
+
`,
|
|
116
|
+
})
|
|
117
|
+
], AiHaloOverlay);
|
|
118
|
+
export { AiHaloOverlay };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DI } from '@genesislcap/web-core';
|
|
2
|
+
/**
|
|
3
|
+
* Default AiAssistantConfig DI implementation.
|
|
4
|
+
*
|
|
5
|
+
* @beta
|
|
6
|
+
*/
|
|
7
|
+
export const defaultAiAssistantConfig = {
|
|
8
|
+
name: 'foundation-ai-assistant',
|
|
9
|
+
chatConfig: {},
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* AiAssistantConfig DI key.
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export const AiAssistantConfig = DI.createInterface((x) => x.instance(defaultAiAssistantConfig));
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './config';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './main/main';
|
|
2
|
+
export * from './main/main.types';
|
|
3
|
+
export * from './main/main.template';
|
|
4
|
+
export * from './components/chat-bubble';
|
|
5
|
+
export * from './components/chat-driver';
|
|
6
|
+
export * from './components/activity-halo/activity-halo';
|
|
7
|
+
export * from './channel/ai-activity-channel';
|
|
8
|
+
export * from './config/config';
|