@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
@@ -6,11 +6,6 @@ import {
6
6
  AI_COLOUR_VIOLET,
7
7
  } from '../styles/ai-colours';
8
8
 
9
- const HALO_DEFAULT_SPEED = 1.5;
10
- const HALO_DEFAULT_BORDER_SIZE = 3;
11
- const HALO_DEFAULT_GLOW_OPACITY = 0.35;
12
- const HALO_DEFAULT_GLOW_SPREAD = 70;
13
-
14
9
  /**
15
10
  * Animated halo overlay — rotating conic-gradient border with an inward glow.
16
11
  *
@@ -51,7 +46,7 @@ const HALO_DEFAULT_GLOW_SPREAD = 70;
51
46
  position: absolute;
52
47
  inset: 0;
53
48
  border-radius: inherit;
54
- padding: var(--halo-border-size, 3px);
49
+ padding: 3px;
55
50
  background: repeating-conic-gradient(
56
51
  from var(--halo-angle, 0deg),
57
52
  ${AI_COLOUR_AMBER},
@@ -84,47 +79,14 @@ const HALO_DEFAULT_GLOW_SPREAD = 70;
84
79
  ${AI_COLOUR_VIOLET},
85
80
  ${AI_COLOUR_AMBER}
86
81
  );
87
- opacity: var(--halo-glow-opacity, 0.35);
88
- -webkit-mask-image: radial-gradient(
89
- ellipse at center,
90
- transparent var(--halo-glow-spread, 70%),
91
- black 100%
92
- );
93
- mask-image: radial-gradient(
94
- ellipse at center,
95
- transparent var(--halo-glow-spread, 70%),
96
- black 100%
97
- );
82
+ opacity: 0.35;
83
+ -webkit-mask-image: radial-gradient(ellipse at center, transparent 70%, black 100%);
84
+ mask-image: radial-gradient(ellipse at center, transparent 70%, black 100%);
98
85
  }
99
86
  `,
100
87
  })
101
88
  export class AiHaloOverlay extends GenesisElement {
102
89
  @attr({ mode: 'boolean' }) active: boolean = false;
103
- /** Rotation speed in degrees per frame. Default: 1.5 (≈ 4 s per full revolution at 60 fps). */
104
- @attr({ converter: { fromView: Number, toView: String } }) speed: number = HALO_DEFAULT_SPEED;
105
- /** Rotation direction. Default: 'cw' (clockwise). */
106
- @attr direction: 'cw' | 'ccw' = 'cw';
107
- /** Border thickness in px. Default: 3. */
108
- @attr({ attribute: 'border-size', converter: { fromView: Number, toView: String } })
109
- borderSize: number = HALO_DEFAULT_BORDER_SIZE;
110
- /** Glow layer opacity (0–1). Default: 0.35. */
111
- @attr({ attribute: 'glow-opacity', converter: { fromView: Number, toView: String } })
112
- glowOpacity: number = HALO_DEFAULT_GLOW_OPACITY;
113
- /** Transparent stop of the radial glow mask as a percentage (0–100). Higher = less spread. Default: 70. */
114
- @attr({ attribute: 'glow-spread', converter: { fromView: Number, toView: String } })
115
- glowSpread: number = HALO_DEFAULT_GLOW_SPREAD;
116
-
117
- borderSizeChanged() {
118
- this.style.setProperty('--halo-border-size', `${this.borderSize}px`);
119
- }
120
-
121
- glowOpacityChanged() {
122
- this.style.setProperty('--halo-glow-opacity', String(this.glowOpacity));
123
- }
124
-
125
- glowSpreadChanged() {
126
- this.style.setProperty('--halo-glow-spread', `${this.glowSpread}%`);
127
- }
128
90
 
129
91
  // TODO: The rAF loop is fine for demos but has two drawbacks vs a pure CSS @property animation:
130
92
  // 1. It runs on the main thread, so heavy JS work can cause the animation to stutter.
@@ -132,6 +94,8 @@ export class AiHaloOverlay extends GenesisElement {
132
94
  // Once @property inside Shadow DOM has solid cross-browser support, consider switching back
133
95
  // to a CSS @keyframes approach and removing connectedCallback/disconnectedCallback/tick().
134
96
 
97
+ // 1.5° per frame @ 60 fps ≈ 4 s per full revolution
98
+ private static readonly DEG_PER_FRAME = 1.5;
135
99
  private static readonly FULL_ROTATION_DEG = 360;
136
100
 
137
101
  private angle = 0;
@@ -150,9 +114,7 @@ export class AiHaloOverlay extends GenesisElement {
150
114
  }
151
115
 
152
116
  private tick() {
153
- const step = this.direction === 'ccw' ? -this.speed : this.speed;
154
- this.angle =
155
- (this.angle + step + AiHaloOverlay.FULL_ROTATION_DEG) % AiHaloOverlay.FULL_ROTATION_DEG;
117
+ this.angle = (this.angle + AiHaloOverlay.DEG_PER_FRAME) % AiHaloOverlay.FULL_ROTATION_DEG;
156
118
  this.style.setProperty('--halo-angle', `${this.angle}deg`);
157
119
  this.animFrame = requestAnimationFrame(() => this.tick());
158
120
  }
@@ -1,10 +1,24 @@
1
1
  import type { ChatMessage, ChatToolDefinition, ChatToolHandlers } from '@genesislcap/foundation-ai';
2
2
 
3
- interface BaseAgentConfig {
3
+ /**
4
+ * Configuration for a single specialist agent.
5
+ *
6
+ * When multiple agents are provided to `FoundationAiAssistant`, an orchestrating layer
7
+ * will route each user message to the appropriate specialist based on intent. When only
8
+ * one agent is configured, routing is skipped.
9
+ *
10
+ * @beta
11
+ */
12
+ export interface AgentConfig {
4
13
  /**
5
14
  * Display name shown in the chat header when this agent is active.
6
15
  */
7
16
  name: string;
17
+ /**
18
+ * Plain-language description of what this agent handles.
19
+ * Used by the classifier to auto-generate its routing prompt.
20
+ */
21
+ description: string;
8
22
  /**
9
23
  * System prompt injected into every conversation turn for this agent.
10
24
  */
@@ -23,47 +37,3 @@ interface BaseAgentConfig {
23
37
  */
24
38
  primerHistory?: ChatMessage[];
25
39
  }
26
-
27
- /**
28
- * Configuration for a specialist agent.
29
- *
30
- * Specialist agents are offered to the classifier for intent routing. The
31
- * `description` is used to auto-generate the classifier prompt — no manual
32
- * routing prompt authoring required.
33
- *
34
- * @beta
35
- */
36
- export interface SpecialistAgentConfig extends BaseAgentConfig {
37
- /**
38
- * Plain-language description of what this agent handles.
39
- * Used by the classifier to auto-generate its routing prompt.
40
- */
41
- description: string;
42
- fallback?: never;
43
- }
44
-
45
- /**
46
- * Configuration for a fallback agent.
47
- *
48
- * Invoked when the classifier returns no match. Excluded from the classifier
49
- * prompt. Only one fallback is permitted per agents array.
50
- *
51
- * @beta
52
- */
53
- export interface FallbackAgentConfig extends BaseAgentConfig {
54
- /**
55
- * Marks this agent as the fallback for unrecognised requests.
56
- */
57
- fallback: true;
58
- description?: never;
59
- }
60
-
61
- /**
62
- * Configuration for an agent passed to `FoundationAiAssistant`.
63
- *
64
- * Either a specialist (requires `description`) or a fallback (requires
65
- * `fallback: true`). Passing both or neither is a compile error.
66
- *
67
- * @beta
68
- */
69
- export type AgentConfig = SpecialistAgentConfig | FallbackAgentConfig;
@@ -1,2 +1 @@
1
1
  export * from './config';
2
- export * from './fallback-agents';
package/src/index.ts CHANGED
@@ -1,12 +1,8 @@
1
1
  export * from './main/main';
2
2
  export * from './main/main.types';
3
3
  export * from './main/main.template';
4
- export * from './components/ai-driver';
5
4
  export * from './components/chat-driver';
6
- export * from './components/orchestrating-driver';
7
- export * from './components/popout-manager';
8
5
  export * from './channel/ai-activity-channel';
9
6
  export * from './channel/ai-activity-bus';
10
7
  export * from './config/config';
11
- export * from './config/fallback-agents';
12
8
  export type { AiChatWidget } from './types/ai-chat-widget';
@@ -17,7 +17,6 @@ export const styles = css`
17
17
  }
18
18
 
19
19
  .chat-wrapper {
20
- container-type: inline-size;
21
20
  position: relative;
22
21
  display: flex;
23
22
  flex-direction: column;
@@ -63,140 +62,22 @@ export const styles = css`
63
62
  font-size: 1.2em;
64
63
  }
65
64
 
66
- @keyframes settings-slide-in {
67
- from {
68
- opacity: 0%;
69
- transform: translateY(-6px);
70
- }
71
-
72
- to {
73
- opacity: 100%;
74
- transform: translateY(0);
75
- }
76
- }
77
-
78
- @keyframes settings-slide-out {
79
- from {
80
- opacity: 100%;
81
- transform: translateY(0);
82
- }
83
-
84
- to {
85
- opacity: 0%;
86
- transform: translateY(-6px);
87
- }
88
- }
89
-
90
65
  .settings-panel {
91
- animation: settings-slide-in 0.2s ease-out;
92
- display: grid;
93
- grid-template-columns: 1fr;
94
- gap: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 4px);
66
+ display: flex;
67
+ flex-wrap: wrap;
68
+ align-items: center;
69
+ gap: calc(var(--design-unit) * 4px);
95
70
  padding: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 3px);
96
71
  border-bottom: 1px solid var(--neutral-stroke-rest);
97
72
  background-color: var(--neutral-layer-2);
98
73
  }
99
74
 
100
- .settings-panel.closing {
101
- animation: settings-slide-out 0.2s ease-in forwards;
102
- }
103
-
104
- rapid-multiselect::part(root) {
105
- min-width: 80px;
106
- width: 300%;
107
- }
108
-
109
- rapid-multiselect::part(control),
110
- .settings-panel > [part='download-button'] {
111
- width: fit-content;
112
- }
113
-
114
- .settings-panel > [part='toggle-tool-calls'] {
115
- grid-column: 1;
116
- grid-row: 1;
117
- }
118
-
119
- .settings-panel > [part='toggle-thinking'] {
120
- grid-column: 2;
121
- grid-row: 1;
122
- }
123
-
124
- .settings-panel > [part='toggle-agent-switch'] {
125
- grid-column: 1;
126
- grid-row: 2;
127
- }
128
-
129
- .settings-panel > [part='download-button'] {
130
- grid-column: 2;
131
- grid-row: 2;
132
- }
133
-
134
75
  .settings-animations {
135
76
  display: flex;
136
77
  align-items: center;
137
78
  gap: calc(var(--design-unit) * 2px);
138
79
  }
139
80
 
140
- .settings-panel > .settings-animations {
141
- grid-column: 1/2;
142
- grid-row: 3;
143
- }
144
-
145
- @container (min-width: 400px) {
146
- .settings-panel {
147
- grid-template-columns: auto 1fr;
148
- align-items: start;
149
- }
150
-
151
- .settings-panel > [part='toggle-tool-calls'] {
152
- grid-column: 1;
153
- grid-row: 1;
154
- }
155
-
156
- .settings-panel > [part='toggle-thinking'] {
157
- grid-column: 1;
158
- grid-row: 2;
159
- }
160
-
161
- .settings-panel > [part='toggle-agent-switch'] {
162
- grid-column: 1;
163
- grid-row: 3;
164
- }
165
-
166
- .settings-panel > [part='download-button'],
167
- .settings-panel > .settings-animations {
168
- grid-column: 2;
169
- justify-self: end;
170
- }
171
-
172
- .settings-panel > [part='download-button'] {
173
- grid-row: 1;
174
- }
175
-
176
- .settings-panel > .settings-animations {
177
- grid-row: 2;
178
- }
179
- }
180
-
181
- @container (min-width: 750px) {
182
- .settings-panel {
183
- display: flex;
184
- flex-wrap: nowrap;
185
- align-items: center;
186
- gap: calc(var(--design-unit) * 4px);
187
- }
188
-
189
- .settings-panel > [part='download-button'],
190
- .settings-panel > .settings-animations {
191
- justify-self: unset;
192
- margin-left: auto;
193
- }
194
-
195
- .settings-panel > [part='download-button'] ~ .settings-animations {
196
- margin-left: 0;
197
- }
198
- }
199
-
200
81
  .messages {
201
82
  flex: 1;
202
83
  overflow-y: auto;
@@ -242,28 +123,6 @@ export const styles = css`
242
123
  }
243
124
  }
244
125
 
245
- .agent-switch-indicator {
246
- display: flex;
247
- align-items: center;
248
- gap: 8px;
249
- margin: 8px 0;
250
- color: var(--neutral-foreground-hint, var(--neutral-foreground-rest));
251
- opacity: 60%;
252
- font-size: 0.75em;
253
- }
254
-
255
- .agent-switch-indicator::before,
256
- .agent-switch-indicator::after {
257
- content: '';
258
- flex: 1;
259
- height: 1px;
260
- background: currentColor;
261
- }
262
-
263
- .agent-switch-label {
264
- white-space: nowrap;
265
- }
266
-
267
126
  .message-row {
268
127
  display: flex;
269
128
  align-items: flex-start;
@@ -7,10 +7,6 @@ const animationItemRenderer = (option: any): ViewTemplate => html`
7
7
  <span part="option-label" title="${() => option.tooltip}">${() => option.label}</span>
8
8
  `;
9
9
 
10
- const HALO_SPEED_DEFAULT = 1.5;
11
- const HALO_SPEED_ORCHESTRATING = 0.4;
12
- const HALO_BORDER_SIZE_DEFAULT = 3;
13
-
14
10
  const animationOptions = Object.entries(ANIMATION_DEFS).map(([value, def]) => ({
15
11
  value,
16
12
  label: def.label,
@@ -38,8 +34,6 @@ const genesisIconTemplate = html`
38
34
  */
39
35
  const messageType = (m: ChatMessage): string => {
40
36
  switch (true) {
41
- case m.role === 'system-event':
42
- return 'agent-switch';
43
37
  case m.role === 'user':
44
38
  return 'user';
45
39
  case !!m.thinking:
@@ -74,13 +68,13 @@ export const FoundationAiAssistantTemplate = (
74
68
  return html<FoundationAiAssistant>`
75
69
  <div class="chat-wrapper" part="chat-wrapper">
76
70
  ${when(
77
- (x) => !!x.chatConfig.ui?.acceptedFiles,
71
+ (x) => !!x.chatConfig.acceptedFiles,
78
72
  html<FoundationAiAssistant>`
79
73
  <input
80
74
  class="file-input"
81
75
  type="file"
82
76
  multiple
83
- accept=${(x) => x.chatConfig.ui?.acceptedFiles}
77
+ accept=${(x) => x.chatConfig.acceptedFiles}
84
78
  @change=${(x, c) => x.handleFileSelect(c.event)}
85
79
  />
86
80
  `,
@@ -88,21 +82,23 @@ export const FoundationAiAssistantTemplate = (
88
82
  ${when(
89
83
  (x) =>
90
84
  !!x.popoutMode ||
91
- x.chatConfig.ui?.showToolCalls != null ||
92
- x.chatConfig.ui?.showThinkingSteps != null ||
93
- x.chatConfig.ui?.showAgentSwitchIndicator != null ||
94
- x.chatConfig.ui?.allowDebugDownload === true ||
95
- x.chatConfig.ui?.animations != null,
85
+ x.chatConfig.showToolCalls != null ||
86
+ x.chatConfig.showThinkingSteps != null ||
87
+ x.chatConfig.allowDebugDownload === true ||
88
+ x.chatConfig.animations != null,
96
89
  html<FoundationAiAssistant>`
97
90
  <div
98
- class="chat-header ${(x) => (x.popoutMode !== 'collapse' ? 'draggable' : '')}"
91
+ class="chat-header ${(x) => (x.popoutMode === 'expand' ? 'draggable' : '')}"
99
92
  part="chat-header"
100
93
  @mousedown="${(x, c) => x.onChatHeaderMouseDown(c.event as MouseEvent)}"
101
94
  >
102
95
  ${when(
103
- (x) => !!x.headerTitle,
96
+ (x) => !!(x.headerTitle ?? x.agents?.[0]?.name),
104
97
  html<FoundationAiAssistant>`
105
- <span class="chat-title" part="chat-title">${(x) => x.headerTitle}</span>
98
+ <!-- TODO: multi-agent orchestration — bind to active agent name rather than always agents[0] -->
99
+ <span class="chat-title" part="chat-title">
100
+ ${(x) => x.headerTitle ?? x.agents?.[0]?.name}
101
+ </span>
106
102
  `,
107
103
  )}
108
104
  <div class="header-actions" part="header-actions">
@@ -122,11 +118,10 @@ export const FoundationAiAssistantTemplate = (
122
118
  )}
123
119
  ${when(
124
120
  (x) =>
125
- x.chatConfig.ui?.showToolCalls != null ||
126
- x.chatConfig.ui?.showThinkingSteps != null ||
127
- x.chatConfig.ui?.showAgentSwitchIndicator != null ||
128
- x.chatConfig.ui?.allowDebugDownload === true ||
129
- x.chatConfig.ui?.animations != null,
121
+ x.chatConfig.showToolCalls != null ||
122
+ x.chatConfig.showThinkingSteps != null ||
123
+ x.chatConfig.allowDebugDownload === true ||
124
+ x.chatConfig.animations != null,
130
125
  html<FoundationAiAssistant>`
131
126
  <${buttonTag}
132
127
  class="settings-button"
@@ -144,7 +139,7 @@ export const FoundationAiAssistantTemplate = (
144
139
  html<FoundationAiAssistant>`
145
140
  <div class="settings-panel" part="settings-panel">
146
141
  ${when(
147
- (x) => x.chatConfig.ui?.showToolCalls != null,
142
+ (x) => x.chatConfig.showToolCalls != null,
148
143
  html<FoundationAiAssistant>`
149
144
  <${switchTag}
150
145
  part="toggle-tool-calls"
@@ -154,7 +149,7 @@ export const FoundationAiAssistantTemplate = (
154
149
  `,
155
150
  )}
156
151
  ${when(
157
- (x) => x.chatConfig.ui?.showThinkingSteps != null,
152
+ (x) => x.chatConfig.showThinkingSteps != null,
158
153
  html<FoundationAiAssistant>`
159
154
  <${switchTag}
160
155
  part="toggle-thinking"
@@ -164,27 +159,17 @@ export const FoundationAiAssistantTemplate = (
164
159
  `,
165
160
  )}
166
161
  ${when(
167
- (x) => x.chatConfig.ui?.showAgentSwitchIndicator != null,
168
- html<FoundationAiAssistant>`
169
- <${switchTag}
170
- part="toggle-agent-switch"
171
- :checked=${(x) => x.showAgentSwitchIndicator}
172
- @change=${(x) => x.toggleShowAgentSwitchIndicator()}
173
- >Agents</${switchTag}>
174
- `,
175
- )}
176
- ${when(
177
- (x) => x.chatConfig.ui?.allowDebugDownload === true,
162
+ (x) => x.chatConfig.allowDebugDownload === true,
178
163
  html<FoundationAiAssistant>`
179
164
  <${buttonTag}
180
165
  part="download-button"
181
166
  appearance="stealth"
182
- @click=${(x) => x.downloadDebugLog()}
183
- >Download agent log</${buttonTag}>
167
+ @click=${(x) => x.downloadHistory()}
168
+ >Download debug state</${buttonTag}>
184
169
  `,
185
170
  )}
186
171
  ${when(
187
- (x) => x.chatConfig.ui?.animations?.userConfigurable === true,
172
+ (x) => x.chatConfig.animations?.userConfigurable === true,
188
173
  html<FoundationAiAssistant>`
189
174
  <div class="settings-animations">
190
175
  <span class="settings-label">Animations</span>
@@ -212,91 +197,71 @@ export const FoundationAiAssistantTemplate = (
212
197
  ${repeat(
213
198
  (x) => x.visibleMessages,
214
199
  html<ChatMessage, FoundationAiAssistant>`
215
- ${when(
216
- (m) => m.role === 'system-event',
217
- html<ChatMessage, FoundationAiAssistant>`
218
- <div class="agent-switch-indicator" part="agent-switch-indicator">
219
- <span class="agent-switch-label">${(m) => m.content}</span>
220
- </div>
221
- `,
222
- )}
223
- ${when(
224
- (m) => m.role !== 'system-event',
225
- html<ChatMessage, FoundationAiAssistant>`
226
- <div class="message-row ${(m) => messageType(m)}">
200
+ <div class="message-row ${(m) => messageType(m)}">
201
+ ${when(
202
+ (m) => m.role !== 'user',
203
+ html<ChatMessage, FoundationAiAssistant>`
204
+ <div class="avatar ${(m) => messageType(m)}">
205
+ ${when(
206
+ (m, c) => !!(c.parent as FoundationAiAssistant).imageSrc,
207
+ html<ChatMessage, FoundationAiAssistant>`
208
+ <img
209
+ src="${(m, c) => (c.parent as FoundationAiAssistant).imageSrc}"
210
+ alt="Assistant"
211
+ class="avatar-img"
212
+ />
213
+ `,
214
+ )}
215
+ ${when(
216
+ (m, c) => !(c.parent as FoundationAiAssistant).imageSrc,
217
+ genesisIconTemplate,
218
+ )}
219
+ </div>
220
+ `,
221
+ )}
222
+ <div class="message ${(m) => messageType(m)}">
223
+ <div class="sender">${(m) => senderLabel[messageType(m)]}</div>
224
+ <div class="content">
227
225
  ${when(
228
- (m) => m.role !== 'user',
226
+ (m) => m.content,
229
227
  html<ChatMessage, FoundationAiAssistant>`
230
- <div class="avatar ${(m) => messageType(m)}">
231
- ${when(
232
- (m, c) => !!(c.parent as FoundationAiAssistant).imageSrc,
233
- html<ChatMessage, FoundationAiAssistant>`
234
- <img
235
- src="${(m, c) => (c.parent as FoundationAiAssistant).imageSrc}"
236
- alt="Assistant"
237
- class="avatar-img"
238
- />
239
- `,
240
- )}
241
- ${when(
242
- (m, c) => !(c.parent as FoundationAiAssistant).imageSrc,
243
- genesisIconTemplate,
244
- )}
245
- </div>
228
+ <ai-chat-markdown :content="${(m) => m.content}"></ai-chat-markdown>
246
229
  `,
247
230
  )}
248
- <div class="message ${(m) => messageType(m)}">
249
- <div class="sender">
250
- ${(m, c) =>
251
- messageType(m) === 'ai-function' &&
252
- m.agentName &&
253
- (c.parent as FoundationAiAssistant).showAgentSwitchIndicator
254
- ? `Tool Call · ${m.agentName}`
255
- : senderLabel[messageType(m)]}
256
- </div>
257
- <div class="content">
258
- ${when(
259
- (m) => m.content,
260
- html<ChatMessage, FoundationAiAssistant>`
261
- <ai-chat-markdown :content="${(m) => m.content}"></ai-chat-markdown>
262
- `,
263
- )}
264
- ${when(
265
- (m) => m.toolCalls,
266
- html<ChatMessage, FoundationAiAssistant>`
267
- ${repeat(
268
- (m) => m.toolCalls ?? [],
269
- html<ChatToolCall>`
270
- <pre class="payload"><strong>${(tc) => tc.name}</strong>(${(tc) =>
271
- JSON.stringify(tc.args, null, 2)})</pre>
272
- `,
273
- )}
274
- `,
275
- )}
276
- ${when(
277
- (m) => m.interaction,
278
- html<ChatMessage, FoundationAiAssistant>`
279
- <ai-chat-interaction-wrapper
280
- :componentName=${(m) => m.interaction!.componentName}
281
- :data=${(m) => m.interaction!.data}
282
- :interactionId=${(m) => m.interaction!.interactionId}
283
- :resolved=${(m) => !!m.interaction!.resolved}
284
- @interaction-completed=${(m, c) =>
285
- c.parent.handleInteractionCompleted(c.event)}
286
- ></ai-chat-interaction-wrapper>
231
+ ${when(
232
+ (m) => m.toolCalls,
233
+ html<ChatMessage, FoundationAiAssistant>`
234
+ ${repeat(
235
+ (m) => m.toolCalls ?? [],
236
+ html<ChatToolCall>`
237
+ <pre class="payload"><strong>${(tc) => tc.name}</strong>(${(tc) =>
238
+ JSON.stringify(tc.args, null, 2)})</pre>
287
239
  `,
288
240
  )}
289
- </div>
290
- </div>
241
+ `,
242
+ )}
243
+ ${when(
244
+ (m) => m.interaction,
245
+ html<ChatMessage, FoundationAiAssistant>`
246
+ <ai-chat-interaction-wrapper
247
+ :componentName=${(m) => m.interaction!.componentName}
248
+ :data=${(m) => m.interaction!.data}
249
+ :interactionId=${(m) => m.interaction!.interactionId}
250
+ :resolved=${(m) => !!m.interaction!.resolved}
251
+ @interaction-completed=${(m, c) =>
252
+ c.parent.handleInteractionCompleted(c.event)}
253
+ ></ai-chat-interaction-wrapper>
254
+ `,
255
+ )}
291
256
  </div>
292
- `,
293
- )}
257
+ </div>
258
+ </div>
294
259
  `,
295
260
  )}
296
261
  ${when(
297
262
  (x) =>
298
263
  x.showLoadingIndicator &&
299
- (x.chatConfig.ui?.animations == null || x.enabledAnimations.includes('loading')),
264
+ (x.chatConfig.animations == null || x.enabledAnimations.includes('loading')),
300
265
  html<FoundationAiAssistant>`
301
266
  <div class="message-row ai" part="thinking">
302
267
  <div class="avatar">
@@ -359,13 +324,13 @@ export const FoundationAiAssistantTemplate = (
359
324
 
360
325
  <div class="input-row" part="input-row">
361
326
  ${when(
362
- (x) => !!x.chatConfig.ui?.acceptedFiles,
327
+ (x) => !!x.chatConfig.acceptedFiles,
363
328
  html<FoundationAiAssistant>`
364
329
  <${buttonTag}
365
330
  class="attach-button"
366
331
  part="attach-button"
367
332
  appearance="stealth"
368
- title=${(x) => `Attach file (${x.chatConfig.ui?.acceptedFiles})`}
333
+ title=${(x) => `Attach file (${x.chatConfig.acceptedFiles})`}
369
334
  ?disabled=${(x) => x.state === 'loading'}
370
335
  @click=${(x) => x.triggerFileInput()}
371
336
  ><${iconTag} name="paperclip"></${iconTag}></${buttonTag}>
@@ -399,10 +364,7 @@ export const FoundationAiAssistantTemplate = (
399
364
  </div>
400
365
  <ai-halo-overlay
401
366
  part="halo-overlay"
402
- ?active=${(x) => x.showHalo !== 'no' && x.enabledAnimations.includes('halo')}
403
- :speed="${(x) => (x.showHalo === 'orchestrating' ? HALO_SPEED_ORCHESTRATING : HALO_SPEED_DEFAULT)}"
404
- direction="${(x) => (x.showHalo === 'orchestrating' ? 'ccw' : 'cw')}"
405
- :borderSize="${(x) => (x.showHalo === 'orchestrating' ? 2 : HALO_BORDER_SIZE_DEFAULT)}"
367
+ ?active=${(x) => x.showHalo && x.enabledAnimations.includes('halo')}
406
368
  ></ai-halo-overlay>
407
369
  </div>
408
370
  `;