@genesislcap/ai-assistant 14.409.0-FUI-2495.2 → 14.409.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.
Files changed (64) hide show
  1. package/dist/ai-assistant.api.json +1110 -2791
  2. package/dist/ai-assistant.d.ts +45 -267
  3. package/dist/dts/channel/ai-activity-channel.d.ts +0 -1
  4. package/dist/dts/channel/ai-activity-channel.d.ts.map +1 -1
  5. package/dist/dts/components/chat-driver/chat-driver.d.ts +7 -25
  6. package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
  7. package/dist/dts/components/halo-overlay.d.ts +1 -13
  8. package/dist/dts/components/halo-overlay.d.ts.map +1 -1
  9. package/dist/dts/config/config.d.ts +15 -43
  10. package/dist/dts/config/config.d.ts.map +1 -1
  11. package/dist/dts/config/index.d.ts +0 -1
  12. package/dist/dts/config/index.d.ts.map +1 -1
  13. package/dist/dts/index.d.ts +0 -4
  14. package/dist/dts/index.d.ts.map +1 -1
  15. package/dist/dts/main/main.d.ts +7 -16
  16. package/dist/dts/main/main.d.ts.map +1 -1
  17. package/dist/dts/main/main.styles.d.ts.map +1 -1
  18. package/dist/dts/main/main.template.d.ts.map +1 -1
  19. package/dist/esm/components/chat-driver/chat-driver.js +31 -86
  20. package/dist/esm/components/halo-overlay.js +7 -53
  21. package/dist/esm/config/index.js +0 -1
  22. package/dist/esm/index.js +0 -4
  23. package/dist/esm/main/main.js +45 -103
  24. package/dist/esm/main/main.styles.js +4 -145
  25. package/dist/esm/main/main.template.js +61 -97
  26. package/dist/tsconfig.tsbuildinfo +1 -1
  27. package/package.json +15 -15
  28. package/src/channel/ai-activity-channel.ts +0 -1
  29. package/src/components/chat-driver/chat-driver.ts +35 -116
  30. package/src/components/halo-overlay.ts +7 -45
  31. package/src/config/config.ts +15 -45
  32. package/src/config/index.ts +0 -1
  33. package/src/index.ts +0 -4
  34. package/src/main/main.styles.ts +4 -145
  35. package/src/main/main.template.ts +78 -116
  36. package/src/main/main.ts +50 -105
  37. package/dist/dts/components/ai-driver/ai-driver.d.ts +0 -38
  38. package/dist/dts/components/ai-driver/ai-driver.d.ts.map +0 -1
  39. package/dist/dts/components/ai-driver/index.d.ts +0 -2
  40. package/dist/dts/components/ai-driver/index.d.ts.map +0 -1
  41. package/dist/dts/components/orchestrating-driver/index.d.ts +0 -2
  42. package/dist/dts/components/orchestrating-driver/index.d.ts.map +0 -1
  43. package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts +0 -36
  44. package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts.map +0 -1
  45. package/dist/dts/components/popout-manager/index.d.ts +0 -2
  46. package/dist/dts/components/popout-manager/index.d.ts.map +0 -1
  47. package/dist/dts/components/popout-manager/popout-manager.d.ts +0 -74
  48. package/dist/dts/components/popout-manager/popout-manager.d.ts.map +0 -1
  49. package/dist/dts/config/fallback-agents.d.ts +0 -20
  50. package/dist/dts/config/fallback-agents.d.ts.map +0 -1
  51. package/dist/esm/components/ai-driver/ai-driver.js +0 -1
  52. package/dist/esm/components/ai-driver/index.js +0 -1
  53. package/dist/esm/components/orchestrating-driver/index.js +0 -1
  54. package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +0 -229
  55. package/dist/esm/components/popout-manager/index.js +0 -1
  56. package/dist/esm/components/popout-manager/popout-manager.js +0 -119
  57. package/dist/esm/config/fallback-agents.js +0 -26
  58. package/src/components/ai-driver/ai-driver.ts +0 -42
  59. package/src/components/ai-driver/index.ts +0 -1
  60. package/src/components/orchestrating-driver/index.ts +0 -1
  61. package/src/components/orchestrating-driver/orchestrating-driver.ts +0 -300
  62. package/src/components/popout-manager/index.ts +0 -1
  63. package/src/components/popout-manager/popout-manager.ts +0 -144
  64. package/src/config/fallback-agents.ts +0 -29
@@ -3,9 +3,6 @@ import { ANIMATION_DEFS } from './main.types';
3
3
  const animationItemRenderer = (option) => html `
4
4
  <span part="option-label" title="${() => option.tooltip}">${() => option.label}</span>
5
5
  `;
6
- const HALO_SPEED_DEFAULT = 1.5;
7
- const HALO_SPEED_ORCHESTRATING = 0.4;
8
- const HALO_BORDER_SIZE_DEFAULT = 3;
9
6
  const animationOptions = Object.entries(ANIMATION_DEFS).map(([value, def]) => ({
10
7
  value,
11
8
  label: def.label,
@@ -31,8 +28,6 @@ const genesisIconTemplate = html `
31
28
  */
32
29
  const messageType = (m) => {
33
30
  switch (true) {
34
- case m.role === 'system-event':
35
- return 'agent-switch';
36
31
  case m.role === 'user':
37
32
  return 'user';
38
33
  case !!m.thinking:
@@ -61,31 +56,30 @@ export const FoundationAiAssistantTemplate = (designSystemPrefix) => {
61
56
  const iconTag = `${designSystemPrefix}-icon`;
62
57
  return html `
63
58
  <div class="chat-wrapper" part="chat-wrapper">
64
- ${when((x) => { var _a; return !!((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.acceptedFiles); }, html `
59
+ ${when((x) => !!x.chatConfig.acceptedFiles, html `
65
60
  <input
66
61
  class="file-input"
67
62
  type="file"
68
63
  multiple
69
- accept=${(x) => { var _a; return (_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.acceptedFiles; }}
64
+ accept=${(x) => x.chatConfig.acceptedFiles}
70
65
  @change=${(x, c) => x.handleFileSelect(c.event)}
71
66
  />
72
67
  `)}
73
- ${when((x) => {
74
- var _a, _b, _c, _d, _e;
75
- return !!x.popoutMode ||
76
- ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.showToolCalls) != null ||
77
- ((_b = x.chatConfig.ui) === null || _b === void 0 ? void 0 : _b.showThinkingSteps) != null ||
78
- ((_c = x.chatConfig.ui) === null || _c === void 0 ? void 0 : _c.showAgentSwitchIndicator) != null ||
79
- ((_d = x.chatConfig.ui) === null || _d === void 0 ? void 0 : _d.allowDebugDownload) === true ||
80
- ((_e = x.chatConfig.ui) === null || _e === void 0 ? void 0 : _e.animations) != null;
81
- }, html `
68
+ ${when((x) => !!x.popoutMode ||
69
+ x.chatConfig.showToolCalls != null ||
70
+ x.chatConfig.showThinkingSteps != null ||
71
+ x.chatConfig.allowDebugDownload === true ||
72
+ x.chatConfig.animations != null, html `
82
73
  <div
83
- class="chat-header ${(x) => (x.popoutMode !== 'collapse' ? 'draggable' : '')}"
74
+ class="chat-header ${(x) => (x.popoutMode === 'expand' ? 'draggable' : '')}"
84
75
  part="chat-header"
85
76
  @mousedown="${(x, c) => x.onChatHeaderMouseDown(c.event)}"
86
77
  >
87
- ${when((x) => !!x.headerTitle, html `
88
- <span class="chat-title" part="chat-title">${(x) => x.headerTitle}</span>
78
+ ${when((x) => { var _a, _b, _c; return !!((_a = x.headerTitle) !== null && _a !== void 0 ? _a : (_c = (_b = x.agents) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.name); }, html `
79
+ <!-- TODO: multi-agent orchestration — bind to active agent name rather than always agents[0] -->
80
+ <span class="chat-title" part="chat-title">
81
+ ${(x) => { var _a, _b, _c; return (_a = x.headerTitle) !== null && _a !== void 0 ? _a : (_c = (_b = x.agents) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.name; }}
82
+ </span>
89
83
  `)}
90
84
  <div class="header-actions" part="header-actions">
91
85
  <slot name="header-actions-extra"></slot>
@@ -99,14 +93,10 @@ export const FoundationAiAssistantTemplate = (designSystemPrefix) => {
99
93
  @click=${(x) => x.handlePopout()}
100
94
  ><${iconTag} name="${(x) => (x.popoutMode === 'expand' ? 'external-link-alt' : 'compress-alt')}"></${iconTag}></${buttonTag}>
101
95
  `)}
102
- ${when((x) => {
103
- var _a, _b, _c, _d, _e;
104
- return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.showToolCalls) != null ||
105
- ((_b = x.chatConfig.ui) === null || _b === void 0 ? void 0 : _b.showThinkingSteps) != null ||
106
- ((_c = x.chatConfig.ui) === null || _c === void 0 ? void 0 : _c.showAgentSwitchIndicator) != null ||
107
- ((_d = x.chatConfig.ui) === null || _d === void 0 ? void 0 : _d.allowDebugDownload) === true ||
108
- ((_e = x.chatConfig.ui) === null || _e === void 0 ? void 0 : _e.animations) != null;
109
- }, html `
96
+ ${when((x) => x.chatConfig.showToolCalls != null ||
97
+ x.chatConfig.showThinkingSteps != null ||
98
+ x.chatConfig.allowDebugDownload === true ||
99
+ x.chatConfig.animations != null, html `
110
100
  <${buttonTag}
111
101
  class="settings-button"
112
102
  part="settings-button"
@@ -119,35 +109,28 @@ export const FoundationAiAssistantTemplate = (designSystemPrefix) => {
119
109
  </div>
120
110
  ${when((x) => x.settingsOpen, html `
121
111
  <div class="settings-panel" part="settings-panel">
122
- ${when((x) => { var _a; return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.showToolCalls) != null; }, html `
112
+ ${when((x) => x.chatConfig.showToolCalls != null, html `
123
113
  <${switchTag}
124
114
  part="toggle-tool-calls"
125
115
  :checked=${(x) => x.showToolCalls}
126
116
  @change=${(x) => x.toggleShowToolCalls()}
127
117
  >Tool calls</${switchTag}>
128
118
  `)}
129
- ${when((x) => { var _a; return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.showThinkingSteps) != null; }, html `
119
+ ${when((x) => x.chatConfig.showThinkingSteps != null, html `
130
120
  <${switchTag}
131
121
  part="toggle-thinking"
132
122
  :checked=${(x) => x.showThinkingSteps}
133
123
  @change=${(x) => x.toggleShowThinkingSteps()}
134
124
  >Thinking</${switchTag}>
135
125
  `)}
136
- ${when((x) => { var _a; return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.showAgentSwitchIndicator) != null; }, html `
137
- <${switchTag}
138
- part="toggle-agent-switch"
139
- :checked=${(x) => x.showAgentSwitchIndicator}
140
- @change=${(x) => x.toggleShowAgentSwitchIndicator()}
141
- >Agents</${switchTag}>
142
- `)}
143
- ${when((x) => { var _a; return ((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.allowDebugDownload) === true; }, html `
126
+ ${when((x) => x.chatConfig.allowDebugDownload === true, html `
144
127
  <${buttonTag}
145
128
  part="download-button"
146
129
  appearance="stealth"
147
- @click=${(x) => x.downloadDebugLog()}
148
- >Download agent log</${buttonTag}>
130
+ @click=${(x) => x.downloadHistory()}
131
+ >Download debug state</${buttonTag}>
149
132
  `)}
150
- ${when((x) => { var _a, _b; return ((_b = (_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.animations) === null || _b === void 0 ? void 0 : _b.userConfigurable) === true; }, html `
133
+ ${when((x) => { var _a; return ((_a = x.chatConfig.animations) === null || _a === void 0 ? void 0 : _a.userConfigurable) === true; }, html `
151
134
  <div class="settings-animations">
152
135
  <span class="settings-label">Animations</span>
153
136
  <${multiselectTag}
@@ -168,61 +151,45 @@ export const FoundationAiAssistantTemplate = (designSystemPrefix) => {
168
151
  <div class="messages" part="messages">
169
152
 
170
153
  ${repeat((x) => x.visibleMessages, html `
171
- ${when((m) => m.role === 'system-event', html `
172
- <div class="agent-switch-indicator" part="agent-switch-indicator">
173
- <span class="agent-switch-label">${(m) => m.content}</span>
174
- </div>
175
- `)}
176
- ${when((m) => m.role !== 'system-event', html `
177
- <div class="message-row ${(m) => messageType(m)}">
178
- ${when((m) => m.role !== 'user', html `
179
- <div class="avatar ${(m) => messageType(m)}">
180
- ${when((m, c) => !!c.parent.imageSrc, html `
181
- <img
182
- src="${(m, c) => c.parent.imageSrc}"
183
- alt="Assistant"
184
- class="avatar-img"
185
- />
186
- `)}
187
- ${when((m, c) => !c.parent.imageSrc, genesisIconTemplate)}
188
- </div>
154
+ <div class="message-row ${(m) => messageType(m)}">
155
+ ${when((m) => m.role !== 'user', html `
156
+ <div class="avatar ${(m) => messageType(m)}">
157
+ ${when((m, c) => !!c.parent.imageSrc, html `
158
+ <img
159
+ src="${(m, c) => c.parent.imageSrc}"
160
+ alt="Assistant"
161
+ class="avatar-img"
162
+ />
163
+ `)}
164
+ ${when((m, c) => !c.parent.imageSrc, genesisIconTemplate)}
165
+ </div>
166
+ `)}
167
+ <div class="message ${(m) => messageType(m)}">
168
+ <div class="sender">${(m) => senderLabel[messageType(m)]}</div>
169
+ <div class="content">
170
+ ${when((m) => m.content, html `
171
+ <ai-chat-markdown :content="${(m) => m.content}"></ai-chat-markdown>
189
172
  `)}
190
- <div class="message ${(m) => messageType(m)}">
191
- <div class="sender">
192
- ${(m, c) => messageType(m) === 'ai-function' &&
193
- m.agentName &&
194
- c.parent.showAgentSwitchIndicator
195
- ? `Tool Call · ${m.agentName}`
196
- : senderLabel[messageType(m)]}
197
- </div>
198
- <div class="content">
199
- ${when((m) => m.content, html `
200
- <ai-chat-markdown :content="${(m) => m.content}"></ai-chat-markdown>
201
- `)}
202
- ${when((m) => m.toolCalls, html `
203
- ${repeat((m) => { var _a; return (_a = m.toolCalls) !== null && _a !== void 0 ? _a : []; }, html `
204
- <pre class="payload"><strong>${(tc) => tc.name}</strong>(${(tc) => JSON.stringify(tc.args, null, 2)})</pre>
205
- `)}
173
+ ${when((m) => m.toolCalls, html `
174
+ ${repeat((m) => { var _a; return (_a = m.toolCalls) !== null && _a !== void 0 ? _a : []; }, html `
175
+ <pre class="payload"><strong>${(tc) => tc.name}</strong>(${(tc) => JSON.stringify(tc.args, null, 2)})</pre>
206
176
  `)}
207
- ${when((m) => m.interaction, html `
208
- <ai-chat-interaction-wrapper
209
- :componentName=${(m) => m.interaction.componentName}
210
- :data=${(m) => m.interaction.data}
211
- :interactionId=${(m) => m.interaction.interactionId}
212
- :resolved=${(m) => !!m.interaction.resolved}
213
- @interaction-completed=${(m, c) => c.parent.handleInteractionCompleted(c.event)}
214
- ></ai-chat-interaction-wrapper>
215
- `)}
216
- </div>
217
- </div>
177
+ `)}
178
+ ${when((m) => m.interaction, html `
179
+ <ai-chat-interaction-wrapper
180
+ :componentName=${(m) => m.interaction.componentName}
181
+ :data=${(m) => m.interaction.data}
182
+ :interactionId=${(m) => m.interaction.interactionId}
183
+ :resolved=${(m) => !!m.interaction.resolved}
184
+ @interaction-completed=${(m, c) => c.parent.handleInteractionCompleted(c.event)}
185
+ ></ai-chat-interaction-wrapper>
186
+ `)}
218
187
  </div>
219
- `)}
188
+ </div>
189
+ </div>
220
190
  `)}
221
- ${when((x) => {
222
- var _a;
223
- return x.showLoadingIndicator &&
224
- (((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.animations) == null || x.enabledAnimations.includes('loading'));
225
- }, html `
191
+ ${when((x) => x.showLoadingIndicator &&
192
+ (x.chatConfig.animations == null || x.enabledAnimations.includes('loading')), html `
226
193
  <div class="message-row ai" part="thinking">
227
194
  <div class="avatar">
228
195
  ${when((x) => !!x.imageSrc, html `
@@ -270,12 +237,12 @@ export const FoundationAiAssistantTemplate = (designSystemPrefix) => {
270
237
  `)}
271
238
 
272
239
  <div class="input-row" part="input-row">
273
- ${when((x) => { var _a; return !!((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.acceptedFiles); }, html `
240
+ ${when((x) => !!x.chatConfig.acceptedFiles, html `
274
241
  <${buttonTag}
275
242
  class="attach-button"
276
243
  part="attach-button"
277
244
  appearance="stealth"
278
- title=${(x) => { var _a; return `Attach file (${(_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.acceptedFiles})`; }}
245
+ title=${(x) => `Attach file (${x.chatConfig.acceptedFiles})`}
279
246
  ?disabled=${(x) => x.state === 'loading'}
280
247
  @click=${(x) => x.triggerFileInput()}
281
248
  ><${iconTag} name="paperclip"></${iconTag}></${buttonTag}>
@@ -306,10 +273,7 @@ export const FoundationAiAssistantTemplate = (designSystemPrefix) => {
306
273
  </div>
307
274
  <ai-halo-overlay
308
275
  part="halo-overlay"
309
- ?active=${(x) => x.showHalo !== 'no' && x.enabledAnimations.includes('halo')}
310
- :speed="${(x) => (x.showHalo === 'orchestrating' ? HALO_SPEED_ORCHESTRATING : HALO_SPEED_DEFAULT)}"
311
- direction="${(x) => (x.showHalo === 'orchestrating' ? 'ccw' : 'cw')}"
312
- :borderSize="${(x) => (x.showHalo === 'orchestrating' ? 2 : HALO_BORDER_SIZE_DEFAULT)}"
276
+ ?active=${(x) => x.showHalo && x.enabledAnimations.includes('halo')}
313
277
  ></ai-halo-overlay>
314
278
  </div>
315
279
  `;
@@ -1 +1 @@
1
- {"root":["../src/index.ts","../src/channel/ai-activity-bus.ts","../src/channel/ai-activity-channel.ts","../src/components/halo-overlay.ts","../src/components/activity-halo/activity-halo.ts","../src/components/ai-driver/ai-driver.ts","../src/components/ai-driver/index.ts","../src/components/chat-bubble/chat-bubble.styles.ts","../src/components/chat-bubble/chat-bubble.template.ts","../src/components/chat-bubble/chat-bubble.ts","../src/components/chat-bubble/index.ts","../src/components/chat-driver/chat-driver.ts","../src/components/chat-driver/index.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.template.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.ts","../src/components/chat-interaction-wrapper/index.ts","../src/components/chat-markdown/chat-markdown.ts","../src/components/chat-markdown/index.ts","../src/components/orchestrating-driver/index.ts","../src/components/orchestrating-driver/orchestrating-driver.ts","../src/components/popout-manager/index.ts","../src/components/popout-manager/popout-manager.ts","../src/config/config.ts","../src/config/fallback-agents.ts","../src/config/index.ts","../src/main/index.ts","../src/main/main.styles.ts","../src/main/main.template.ts","../src/main/main.ts","../src/main/main.types.ts","../src/styles/ai-colours.ts","../src/styles/index.ts","../src/styles/styles.ts","../src/tags/index.ts","../src/types/ai-chat-widget.ts","../src/utils/index.ts","../src/utils/logger.ts"],"version":"5.9.2"}
1
+ {"root":["../src/index.ts","../src/channel/ai-activity-bus.ts","../src/channel/ai-activity-channel.ts","../src/components/halo-overlay.ts","../src/components/activity-halo/activity-halo.ts","../src/components/chat-bubble/chat-bubble.styles.ts","../src/components/chat-bubble/chat-bubble.template.ts","../src/components/chat-bubble/chat-bubble.ts","../src/components/chat-bubble/index.ts","../src/components/chat-driver/chat-driver.ts","../src/components/chat-driver/index.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.template.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.ts","../src/components/chat-interaction-wrapper/index.ts","../src/components/chat-markdown/chat-markdown.ts","../src/components/chat-markdown/index.ts","../src/config/config.ts","../src/config/index.ts","../src/main/index.ts","../src/main/main.styles.ts","../src/main/main.template.ts","../src/main/main.ts","../src/main/main.types.ts","../src/styles/ai-colours.ts","../src/styles/index.ts","../src/styles/styles.ts","../src/tags/index.ts","../src/types/ai-chat-widget.ts","../src/utils/index.ts","../src/utils/logger.ts"],"version":"5.9.2"}
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.409.0-FUI-2495.2",
4
+ "version": "14.409.1",
5
5
  "license": "SEE LICENSE IN license.txt",
6
6
  "main": "dist/esm/index.js",
7
7
  "types": "dist/ai-assistant.d.ts",
@@ -59,23 +59,23 @@
59
59
  }
60
60
  },
61
61
  "devDependencies": {
62
- "@genesislcap/foundation-testing": "14.409.0-FUI-2495.2",
63
- "@genesislcap/genx": "14.409.0-FUI-2495.2",
64
- "@genesislcap/rollup-builder": "14.409.0-FUI-2495.2",
65
- "@genesislcap/ts-builder": "14.409.0-FUI-2495.2",
66
- "@genesislcap/uvu-playwright-builder": "14.409.0-FUI-2495.2",
67
- "@genesislcap/vite-builder": "14.409.0-FUI-2495.2",
68
- "@genesislcap/webpack-builder": "14.409.0-FUI-2495.2",
62
+ "@genesislcap/foundation-testing": "14.409.1",
63
+ "@genesislcap/genx": "14.409.1",
64
+ "@genesislcap/rollup-builder": "14.409.1",
65
+ "@genesislcap/ts-builder": "14.409.1",
66
+ "@genesislcap/uvu-playwright-builder": "14.409.1",
67
+ "@genesislcap/vite-builder": "14.409.1",
68
+ "@genesislcap/webpack-builder": "14.409.1",
69
69
  "@types/dompurify": "^3.0.5",
70
70
  "@types/marked": "^5.0.2"
71
71
  },
72
72
  "dependencies": {
73
- "@genesislcap/foundation-ai": "14.409.0-FUI-2495.2",
74
- "@genesislcap/foundation-logger": "14.409.0-FUI-2495.2",
75
- "@genesislcap/foundation-ui": "14.409.0-FUI-2495.2",
76
- "@genesislcap/foundation-utils": "14.409.0-FUI-2495.2",
77
- "@genesislcap/rapid-design-system": "14.409.0-FUI-2495.2",
78
- "@genesislcap/web-core": "14.409.0-FUI-2495.2",
73
+ "@genesislcap/foundation-ai": "14.409.1",
74
+ "@genesislcap/foundation-logger": "14.409.1",
75
+ "@genesislcap/foundation-ui": "14.409.1",
76
+ "@genesislcap/foundation-utils": "14.409.1",
77
+ "@genesislcap/rapid-design-system": "14.409.1",
78
+ "@genesislcap/web-core": "14.409.1",
79
79
  "dompurify": "^3.3.1",
80
80
  "marked": "^17.0.3"
81
81
  },
@@ -87,5 +87,5 @@
87
87
  "publishConfig": {
88
88
  "access": "public"
89
89
  },
90
- "gitHead": "1fcaf08e9b7559024b25dc6ccc27e3bc62f1512b"
90
+ "gitHead": "a23531e1359a6381e7d4fd81e98bd8d2e9981560"
91
91
  }
@@ -11,7 +11,6 @@ export interface AiAssistantSerializedState {
11
11
  messages: ChatMessage[];
12
12
  showToolCalls: boolean;
13
13
  showThinkingSteps: boolean;
14
- showAgentSwitchIndicator: boolean;
15
14
  enabledAnimations: AiAssistantAnimation[];
16
15
  }
17
16
 
@@ -1,23 +1,17 @@
1
1
  import type {
2
2
  AIProvider,
3
3
  ChatAttachment,
4
- ChatDriverResult,
5
4
  ChatMessage,
6
5
  ChatRequestOptions,
7
6
  ChatToolDefinition,
8
7
  ChatToolHandlers,
9
8
  } from '@genesislcap/foundation-ai';
10
9
  import { MalformedFunctionCallError } from '@genesislcap/foundation-ai';
11
- import type { AgentConfig } from '../../config/config';
12
10
  import { logger } from '../../utils/logger';
13
- import type { AiDriver } from '../ai-driver/ai-driver';
14
11
 
15
12
  const DEFAULT_MAX_TOOL_ITERATIONS = 50;
16
13
  const MAX_MALFORMED_RETRIES = 2;
17
14
 
18
- /** Name reserved for the cross-agent handoff tool — injected by OrchestratingDriver. */
19
- export const REQUEST_CONTINUATION_TOOL = 'request_continuation';
20
-
21
15
  /**
22
16
  * Event emitted when the chat history is updated (new message appended).
23
17
  *
@@ -33,7 +27,7 @@ export type ChatHistoryUpdatedEvent = CustomEvent<ReadonlyArray<ChatMessage>>;
33
27
  *
34
28
  * @beta
35
29
  */
36
- export class ChatDriver extends EventTarget implements AiDriver {
30
+ export class ChatDriver extends EventTarget {
37
31
  private history: ChatMessage[] = [];
38
32
  private busy = false;
39
33
  private pendingInteractions = new Map<
@@ -41,47 +35,26 @@ export class ChatDriver extends EventTarget implements AiDriver {
41
35
  { resolve: (value: any) => void; reject: (reason?: any) => void }
42
36
  >();
43
37
 
44
- private systemPrompt?: string;
45
- private toolDefinitions: ChatToolDefinition[];
46
- private toolHandlers: ChatToolHandlers;
47
- private primerHistory?: ChatMessage[];
48
- private activeAgentName?: string;
49
-
50
38
  constructor(
51
39
  private readonly aiProvider: AIProvider,
52
- toolHandlers: ChatToolHandlers = {},
53
- toolDefinitions: ChatToolDefinition[] = [],
54
- systemPrompt?: string,
55
- primerHistory?: ChatMessage[],
40
+ private readonly toolHandlers: ChatToolHandlers = {},
41
+ private readonly toolDefinitions: ChatToolDefinition[] = [],
42
+ private readonly systemPrompt?: string,
43
+ private readonly primerHistory?: ChatMessage[],
56
44
  private readonly maxToolIterations: number = DEFAULT_MAX_TOOL_ITERATIONS,
57
45
  ) {
58
46
  super();
59
- this.toolHandlers = toolHandlers;
60
- this.toolDefinitions = toolDefinitions;
61
- this.systemPrompt = systemPrompt;
62
- this.primerHistory = primerHistory;
63
- }
64
-
65
- /**
66
- * Swap in a new agent's configuration. Called by OrchestratingDriver before
67
- * each specialist turn so the shared driver runs with the right tools and prompt.
68
- */
69
- applyAgent(config: AgentConfig): void {
70
- this.systemPrompt = config.systemPrompt;
71
- this.toolDefinitions = config.toolDefinitions ?? [];
72
- this.toolHandlers = config.toolHandlers ?? {};
73
- this.primerHistory = config.primerHistory;
74
- this.activeAgentName = config.name;
47
+ if (!systemPrompt) {
48
+ logger.error(
49
+ 'ChatDriver: no systemPrompt provided. The assistant will have no instructions — set the systemPrompt property on foundation-ai-assistant.',
50
+ );
51
+ }
75
52
  }
76
53
 
77
54
  getHistory(): ReadonlyArray<ChatMessage> {
78
55
  return this.history;
79
56
  }
80
57
 
81
- getRawHistory(): readonly ChatMessage[] {
82
- return this.history;
83
- }
84
-
85
58
  isBusy(): boolean {
86
59
  return this.busy;
87
60
  }
@@ -136,95 +109,55 @@ export class ChatDriver extends EventTarget implements AiDriver {
136
109
  */
137
110
  public loadHistory(messages: ChatMessage[]): void {
138
111
  this.history = [...messages];
139
- this.dispatchEvent(
140
- new CustomEvent<ReadonlyArray<ChatMessage>>('history-updated', {
141
- detail: this.history,
142
- }),
143
- );
144
112
  }
145
113
 
146
- async sendMessage(userInput: string, attachments?: ChatAttachment[]): Promise<ChatDriverResult> {
147
- if (this.busy || (!userInput.trim() && !attachments?.length)) return { reason: 'done' };
114
+ async sendMessage(userInput: string, attachments?: ChatAttachment[]): Promise<void> {
115
+ if (this.busy || (!userInput.trim() && !attachments?.length)) return;
148
116
  if (!this.aiProvider.chat) {
149
117
  logger.warn('ChatDriver: AIProvider does not implement chat()');
150
- return { reason: 'done' };
118
+ return;
151
119
  }
152
120
 
153
121
  this.busy = true;
154
122
  this.appendToHistory({ role: 'user', content: userInput, attachments });
155
123
 
156
124
  try {
157
- return await this.runToolLoop(userInput, attachments);
158
- } catch (e) {
159
- logger.error('ChatDriver error:', e);
160
- this.appendToHistory({ role: 'assistant', content: 'Sorry, something went wrong.' });
161
- return { reason: 'done' };
162
- } finally {
163
- this.busy = false;
164
- }
165
- }
166
-
167
- /**
168
- * Continue the tool loop from current history without appending a new user message.
169
- * Used by OrchestratingDriver after an agent handoff — the handoff context is
170
- * already in history; `transientPrimer` is injected as an invisible one-shot
171
- * message for this call only.
172
- */
173
- async continueFromHistory(transientPrimer?: ChatMessage[]): Promise<ChatDriverResult> {
174
- if (this.busy) return { reason: 'done' };
175
- if (!this.aiProvider.chat) {
176
- logger.warn('ChatDriver: AIProvider does not implement chat()');
177
- return { reason: 'done' };
178
- }
179
-
180
- this.busy = true;
181
- try {
182
- return await this.runToolLoop('', undefined, transientPrimer);
125
+ await this.runToolLoop(userInput, attachments);
183
126
  } catch (e) {
184
127
  logger.error('ChatDriver error:', e);
185
128
  this.appendToHistory({ role: 'assistant', content: 'Sorry, something went wrong.' });
186
- return { reason: 'done' };
187
129
  } finally {
188
130
  this.busy = false;
189
131
  }
190
132
  }
191
133
 
192
- private async runToolLoop(
193
- userInput: string,
194
- attachments?: ChatAttachment[],
195
- transientPrimer?: ChatMessage[],
196
- ): Promise<ChatDriverResult> {
197
- if (!this.systemPrompt) {
198
- logger.warn(
199
- 'ChatDriver: no systemPrompt set. The assistant will have no instructions — provide a systemPrompt via agents config or the foundation-ai-assistant property.',
200
- );
201
- }
134
+ private async runToolLoop(userInput: string, attachments?: ChatAttachment[]): Promise<void> {
202
135
  const baseOptions: ChatRequestOptions = {
203
136
  systemPrompt: this.systemPrompt,
204
137
  tools: this.toolDefinitions.length ? this.toolDefinitions : undefined,
205
138
  };
206
139
 
140
+ // History has the user message at the end — pass everything before it as history,
141
+ // and the user input as the userMessage argument.
207
142
  let currentInput = userInput;
208
143
  let currentAttachments: ChatAttachment[] | undefined = attachments;
209
144
  let iterations = 0;
210
145
  let malformedAttempts = 0;
211
- // continueFromHistory callers pass empty input — start at iteration 1 so
212
- // the first LLM call sees the full history (no slice-off-last logic).
213
- const startIteration = currentInput ? 1 : 0;
214
146
 
215
147
  while (iterations < this.maxToolIterations) {
216
148
  iterations += 1;
217
149
 
218
- // On the first iteration of a normal sendMessage call, the last item in
219
- // history is the user message passed separately — exclude it from history.
220
- // On continueFromHistory calls (startIteration=0) or subsequent iterations,
221
- // the full history is sent and currentInput is empty.
222
- const primer = [...(this.primerHistory ?? []), ...(transientPrimer ?? [])];
150
+ // On the first iteration, the last item in history is the user message which is
151
+ // passed separately as currentInput — exclude it. On subsequent iterations, the
152
+ // full history (including tool results) should be sent and currentInput is empty.
153
+ // primerHistory (if provided) is prepended to every call but never stored in
154
+ // this.history and never shown in the UI.
155
+ const primer = this.primerHistory ?? [];
223
156
  const historyForCall =
224
- iterations === startIteration
225
- ? [...primer, ...this.history.slice(0, -1)]
226
- : [...primer, ...this.history];
157
+ iterations === 1 ? [...primer, ...this.history.slice(0, -1)] : [...primer, ...this.history];
227
158
 
159
+ // On malformed-call retries, augment the system prompt to steer the model
160
+ // away from generating Python-style batched function call syntax.
228
161
  const systemPrompt =
229
162
  malformedAttempts > 0
230
163
  ? `${baseOptions.systemPrompt ?? ''}\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.`
@@ -247,7 +180,7 @@ export class ChatDriver extends EventTarget implements AiDriver {
247
180
  logger.warn(
248
181
  `ChatDriver: MALFORMED_FUNCTION_CALL, retrying (${malformedAttempts}/${MAX_MALFORMED_RETRIES})`,
249
182
  );
250
- iterations -= 1;
183
+ iterations -= 1; // don't consume an iteration budget slot for a failed attempt
251
184
  continue;
252
185
  }
253
186
  logger.error('ChatDriver: MALFORMED_FUNCTION_CALL, max retries reached');
@@ -256,19 +189,20 @@ export class ChatDriver extends EventTarget implements AiDriver {
256
189
  content:
257
190
  "I'm sorry, I wasn't able to complete that request. Please try rephrasing or breaking it into smaller steps.",
258
191
  });
259
- return { reason: 'done' };
192
+ return;
260
193
  }
261
194
  throw e;
262
195
  }
263
196
 
264
- currentAttachments = undefined;
197
+ currentAttachments = undefined; // attachments only sent on first call
265
198
 
266
199
  const isThinkingStep = response.content && response.toolCalls?.length;
267
200
  const isEmptyResponse = !response.content?.trim() && !response.toolCalls?.length;
268
201
 
269
202
  if (isEmptyResponse) {
270
- // Discard empty/whitespace-only responses
203
+ // Do nothing, discard empty/whitespace-only responses
271
204
  } else if (isThinkingStep) {
205
+ // Separate thinking message and tool call message
272
206
  this.appendToHistory({ ...response, toolCalls: undefined, thinking: true });
273
207
  this.appendToHistory({ ...response, content: '' });
274
208
  } else {
@@ -276,22 +210,11 @@ export class ChatDriver extends EventTarget implements AiDriver {
276
210
  }
277
211
 
278
212
  if (!response.toolCalls?.length) {
213
+ // Terminal text response — done
279
214
  break;
280
215
  }
281
216
 
282
- // Check for request_continuation before executing tool calls it is a
283
- // system tool intercepted by OrchestratingDriver, not a real handler.
284
- const continuationCall = response.toolCalls.find(
285
- (tc) => tc.name === REQUEST_CONTINUATION_TOOL,
286
- );
287
- if (continuationCall) {
288
- const { summary, remaining_task: remainingTask } = continuationCall.args as {
289
- summary: string;
290
- remaining_task: string;
291
- };
292
- return { reason: 'agent-handoff', summary, remainingTask };
293
- }
294
-
217
+ // Execute all tool calls for this iteration concurrently, then append results in order
295
218
  // eslint-disable-next-line no-await-in-loop
296
219
  const toolResults = await Promise.all(
297
220
  response.toolCalls.map(async (tc) => {
@@ -322,21 +245,17 @@ export class ChatDriver extends EventTarget implements AiDriver {
322
245
  });
323
246
  }
324
247
 
248
+ // Next iteration sends an empty string — the tool results are in history
325
249
  currentInput = '';
326
250
  }
327
251
 
328
252
  if (iterations >= this.maxToolIterations) {
329
253
  logger.warn('ChatDriver: reached max tool iterations, stopping');
330
254
  }
331
-
332
- return { reason: 'done' };
333
255
  }
334
256
 
335
257
  private appendToHistory(message: ChatMessage): void {
336
- const tagged: ChatMessage = this.activeAgentName
337
- ? { ...message, agentName: this.activeAgentName }
338
- : message;
339
- this.history = [...this.history, tagged];
258
+ this.history = [...this.history, message];
340
259
  this.dispatchEvent(
341
260
  new CustomEvent<ReadonlyArray<ChatMessage>>('history-updated', {
342
261
  detail: this.history,