@genesislcap/ai-assistant 14.482.0 → 14.482.1-GENC-1336.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.
@@ -1,5 +1,4 @@
1
1
  export * from './main.template';
2
- export * from '../styles';
3
2
  export * from './main';
4
3
  export * from './main.types';
5
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/main/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/main/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.styles.d.ts","sourceRoot":"","sources":["../../../src/main/main.styles.ts"],"names":[],"mappings":"AAgpBA,eAAO,MAAM,MAAM,iDAGlB,CAAC"}
1
+ {"version":3,"file":"main.styles.d.ts","sourceRoot":"","sources":["../../../src/main/main.styles.ts"],"names":[],"mappings":"AA2pBA,eAAO,MAAM,MAAM,iDAGlB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.template.d.ts","sourceRoot":"","sources":["../../../src/main/main.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,OAAO,EAAuC,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAuNpD,gBAAgB;AAChB,eAAO,MAAM,6BAA6B,GACxC,oBAAoB,MAAM,KACzB,YAAY,CAAC,qBAAqB,CA+ZpC,CAAC"}
1
+ {"version":3,"file":"main.template.d.ts","sourceRoot":"","sources":["../../../src/main/main.template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,OAAO,EAAuC,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC;AAsOpD,gBAAgB;AAChB,eAAO,MAAM,6BAA6B,GACxC,oBAAoB,MAAM,KACzB,YAAY,CAAC,qBAAqB,CAwapC,CAAC"}
@@ -1,4 +1,3 @@
1
1
  export * from './main.template';
2
- export * from '../styles';
3
2
  export * from './main';
4
3
  export * from './main.types';
@@ -81,9 +81,20 @@ const baseStyles = css `
81
81
  min-height: 0;
82
82
  overflow-y: auto;
83
83
  padding: 10px;
84
+ }
85
+
86
+ /* Caps and centres the conversation column inside the (full-width) scroll
87
+ container, so the scrollbar stays at the panel edge while the messages sit
88
+ in a readable-width column. Exposed as part="messages-content" so a host
89
+ can widen it (::part(messages-content) { max-width: none }) or neutralise
90
+ the wrapper entirely (::part(messages-content) { display: contents }). */
91
+ .messages-content {
84
92
  display: flex;
85
93
  flex-direction: column;
86
94
  gap: 10px;
95
+ width: 100%;
96
+ max-width: 1000px;
97
+ margin-inline: auto;
87
98
  }
88
99
 
89
100
  @keyframes slide-in-right {
@@ -230,7 +241,7 @@ const baseStyles = css `
230
241
  }
231
242
 
232
243
  .message {
233
- padding: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 3px);
244
+ padding: calc(var(--design-unit) * 2.5px) calc(var(--design-unit) * 3.5px);
234
245
  max-width: 80%;
235
246
  min-width: 70px;
236
247
  font-family: var(--body-font);
@@ -111,6 +111,20 @@ const senderLabelFor = (m) => m.category === 'narration' ? 'Working' : senderLab
111
111
  * `m.interaction` first; non-interaction messages never consult this.
112
112
  */
113
113
  const interactionPresentation = (m) => { var _a, _b; return (_b = (_a = m.interaction) === null || _a === void 0 ? void 0 : _a.presentation) !== null && _b !== void 0 ? _b : 'label'; };
114
+ /**
115
+ * Space-separated `part` names for a message bubble, so a host can style bubbles
116
+ * from its own stylesheet via `::part()`. Every bubble gets `message` plus its
117
+ * type (`message-user`, `message-ai`, `message-ai-thinking`, `message-ai-function`,
118
+ * `message-interaction`). Interaction bubbles additionally carry a
119
+ * presentation-specific part (`message-interaction-label` / `-bare` / `-bubble`)
120
+ * so a host can target, say, only the bubble-framed widgets.
121
+ */
122
+ const messageParts = (m) => {
123
+ const type = messageType(m);
124
+ return type === 'interaction'
125
+ ? `message message-interaction message-interaction-${interactionPresentation(m)}`
126
+ : `message message-${type}`;
127
+ };
114
128
  // ─── Sub-agent trace fragments ────────────────────────────────────────────────
115
129
  const subAgentAssistantTemplate = html `
116
130
  <div class="sub-agent-message sub-agent-assistant">${(m) => m.content}</div>
@@ -238,6 +252,7 @@ ${(tc) => { var _a; return (((_a = tc.foldPath) === null || _a === void 0 ? void
238
252
  </div>
239
253
  <div
240
254
  class="message ${(m) => messageType(m)} ${(m) => classNames(['narration', m.category === 'narration'])}"
255
+ part="${(m) => messageParts(m)}"
241
256
  >
242
257
  ${when(
243
258
  // A 'bare' interaction owns its full presentation — suppress the
@@ -385,28 +400,33 @@ ${(tc) => { var _a; return (((_a = tc.foldPath) === null || _a === void 0 ? void
385
400
  </div>
386
401
 
387
402
  <div class="messages" part="messages" ${ref('messagesEl')}>
388
- ${repeat((x) => x.visibleMessages, messageRowTemplate)}
389
- ${repeat((x) => x.activeInteractionRow, messageRowTemplate)}
390
- ${when((x) => x.liveSubAgentTrace.length > 0 && x.showToolCalls, liveSubAgentTraceTemplate)}
391
- ${when((x) => {
403
+ <div class="messages-content" part="messages-content">
404
+ ${repeat((x) => x.visibleMessages, messageRowTemplate)}
405
+ ${repeat((x) => x.activeInteractionRow, messageRowTemplate)}
406
+ ${when((x) => x.liveSubAgentTrace.length > 0 && x.showToolCalls, liveSubAgentTraceTemplate)}
407
+ ${when((x) => {
392
408
  var _a;
393
409
  return x.showLoadingIndicator &&
394
410
  (((_a = x.chatConfig.ui) === null || _a === void 0 ? void 0 : _a.animations) == null ||
395
411
  LOADING_STYLE_ANIMATIONS.some((s) => x.enabledAnimations.includes(s)));
396
412
  }, html `
397
- <div class="message-row ai" part="thinking">
398
- <div class="avatar">
399
- ${(x) => x.imageSrc
413
+ <div class="message-row ai" part="thinking">
414
+ <div class="avatar">
415
+ ${(x) => x.imageSrc
400
416
  ? html `
401
- <img src="${() => x.imageSrc}" alt="Assistant" class="avatar-img" />
402
- `
417
+ <img src="${() => x.imageSrc}" alt="Assistant" class="avatar-img" />
418
+ `
403
419
  : html `
404
- <span class="avatar-icon" :innerHTML="${() => x.assistantIconSafe}"></span>
405
- `}
420
+ <span
421
+ class="avatar-icon"
422
+ :innerHTML="${() => x.assistantIconSafe}"
423
+ ></span>
424
+ `}
425
+ </div>
426
+ ${(x) => selectThinkingTemplate(x)}
406
427
  </div>
407
- ${(x) => selectThinkingTemplate(x)}
408
- </div>
409
- `)}
428
+ `)}
429
+ </div>
410
430
  </div>
411
431
 
412
432
  ${when((x) => !x.composerHiddenByConfig && (x.attachments.length > 0 || x.attachmentErrors.length > 0), html `
@@ -1 +1 @@
1
- {"root":["../src/index.ts","../src/channel/ai-activity-bus.ts","../src/channel/ai-activity-channel.ts","../src/components/flowing-waves-indicator.ts","../src/components/halo-overlay.ts","../src/components/plasma-orb-indicator.ts","../src/components/waves-indicator.ts","../src/components/activity-halo/activity-halo.ts","../src/components/agent-picker/agent-picker.constants.ts","../src/components/agent-picker/agent-picker.styles.ts","../src/components/agent-picker/agent-picker.template.ts","../src/components/agent-picker/agent-picker.ts","../src/components/agent-picker/index.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/align-event-globals.ts","../src/components/chat-driver/chat-driver.test.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.test.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/components/settings-modal/index.ts","../src/components/settings-modal/settings-modal.styles.ts","../src/components/settings-modal/settings-modal.template.ts","../src/config/config.ts","../src/config/define-stateful-agent.test.ts","../src/config/define-stateful-agent.ts","../src/config/fallback-agents.ts","../src/config/index.ts","../src/config/validate-providers.test.ts","../src/config/validate-providers.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/provider/ai-provider-switcher.ts","../src/provider/assistant-app-settings.ts","../src/state/ai-assistant-slice.ts","../src/state/debug-event-log.test.ts","../src/state/debug-event-log.ts","../src/state/driver-registry.test.ts","../src/state/driver-registry.ts","../src/state/session-store.ts","../src/styles/ai-colours.ts","../src/styles/index.ts","../src/styles/styles.ts","../src/suggestions/chat-suggestions.ts","../src/tags/index.ts","../src/types/ai-chat-widget.ts","../src/utils/animated-panel-toggle.ts","../src/utils/animation-exclusivity.test.ts","../src/utils/animation-exclusivity.ts","../src/utils/collect-session-models.test.ts","../src/utils/collect-session-models.ts","../src/utils/condense-history.test.ts","../src/utils/condense-history.ts","../src/utils/cost-session-history.test.ts","../src/utils/cost-session-history.ts","../src/utils/derive-cost-session-title.test.ts","../src/utils/derive-cost-session-title.ts","../src/utils/flatten-sub-agent-messages.test.ts","../src/utils/flatten-sub-agent-messages.ts","../src/utils/history-transform.ts","../src/utils/index.ts","../src/utils/logger.ts","../src/utils/message-partition.test.ts","../src/utils/message-partition.ts","../src/utils/resolve-cost-history-config.test.ts","../src/utils/resolve-cost-history-config.ts","../src/utils/strip-agent-handlers.test.ts","../src/utils/strip-agent-handlers.ts","../src/utils/sum-costs.test.ts","../src/utils/sum-costs.ts","../src/utils/sum-tokens.test.ts","../src/utils/sum-tokens.ts","../src/utils/tool-fold.ts"],"version":"5.9.2"}
1
+ {"root":["../src/index.ts","../src/channel/ai-activity-bus.ts","../src/channel/ai-activity-channel.ts","../src/components/flowing-waves-indicator.ts","../src/components/halo-overlay.ts","../src/components/plasma-orb-indicator.ts","../src/components/waves-indicator.ts","../src/components/activity-halo/activity-halo.ts","../src/components/agent-picker/agent-picker.constants.ts","../src/components/agent-picker/agent-picker.styles.ts","../src/components/agent-picker/agent-picker.template.ts","../src/components/agent-picker/agent-picker.ts","../src/components/agent-picker/index.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/align-event-globals.ts","../src/components/chat-driver/chat-driver.test.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.test.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/components/settings-modal/index.ts","../src/components/settings-modal/settings-modal.styles.ts","../src/components/settings-modal/settings-modal.template.ts","../src/config/config.ts","../src/config/define-stateful-agent.test.ts","../src/config/define-stateful-agent.ts","../src/config/fallback-agents.ts","../src/config/index.ts","../src/config/validate-providers.test.ts","../src/config/validate-providers.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/provider/ai-provider-switcher.ts","../src/provider/assistant-app-settings.ts","../src/state/ai-assistant-slice.ts","../src/state/debug-event-log.test.ts","../src/state/debug-event-log.ts","../src/state/driver-registry.test.ts","../src/state/driver-registry.ts","../src/state/session-store.ts","../src/styles/ai-colours.ts","../src/suggestions/chat-suggestions.ts","../src/tags/index.ts","../src/types/ai-chat-widget.ts","../src/utils/animated-panel-toggle.ts","../src/utils/animation-exclusivity.test.ts","../src/utils/animation-exclusivity.ts","../src/utils/collect-session-models.test.ts","../src/utils/collect-session-models.ts","../src/utils/condense-history.test.ts","../src/utils/condense-history.ts","../src/utils/cost-session-history.test.ts","../src/utils/cost-session-history.ts","../src/utils/derive-cost-session-title.test.ts","../src/utils/derive-cost-session-title.ts","../src/utils/flatten-sub-agent-messages.test.ts","../src/utils/flatten-sub-agent-messages.ts","../src/utils/history-transform.ts","../src/utils/index.ts","../src/utils/logger.ts","../src/utils/message-partition.test.ts","../src/utils/message-partition.ts","../src/utils/resolve-cost-history-config.test.ts","../src/utils/resolve-cost-history-config.ts","../src/utils/strip-agent-handlers.test.ts","../src/utils/strip-agent-handlers.ts","../src/utils/sum-costs.test.ts","../src/utils/sum-costs.ts","../src/utils/sum-tokens.test.ts","../src/utils/sum-tokens.ts","../src/utils/tool-fold.ts"],"version":"5.9.2"}
@@ -0,0 +1,131 @@
1
+ # Styling & Theming
2
+
3
+ ## Overview
4
+
5
+ The assistant renders in a shadow root, so its internal classes are not reachable
6
+ from an app stylesheet. Customization is exposed through three deliberate,
7
+ stable surfaces:
8
+
9
+ 1. **Design-system tokens** — the widget reads standard tokens (`--neutral-layer-*`,
10
+ `--accent-fill-rest`, `--design-unit`, `--control-corner-radius`, `--body-font`,
11
+ the `--type-ramp-*` ramp, …). These inherit through the shadow boundary, so
12
+ theming the host design system themes the assistant with no widget-specific work.
13
+ 2. **`--ai-*` custom properties** — a small set of assistant-specific variables,
14
+ each with a built-in fallback, for the parts of the UI that have no natural
15
+ design-system token.
16
+ 3. **CSS Shadow Parts (`::part()`)** — named hooks on internal elements for
17
+ arbitrary restyling from an app stylesheet.
18
+
19
+ Prefer tokens where one exists (they inherit and can be set inline); reach for
20
+ `::part()` when you need to change something a token doesn't cover.
21
+
22
+ ---
23
+
24
+ ## `--ai-*` custom properties
25
+
26
+ | Property | Default | Applies to |
27
+ | --- | --- | --- |
28
+ | `--ai-message-shadow` | `0 2px 8px rgb(0 0 0 / 15%)` | Assistant message bubble shadow |
29
+ | `--ai-thinking-color` | `#7c3aed` | Thinking/reasoning bubble and its avatar ring |
30
+ | `--ai-function-color` | `#86efac` | Tool-call bubble text and border |
31
+
32
+ Set them on the host element (or any ancestor — they inherit):
33
+
34
+ ```css
35
+ foundation-ai-assistant {
36
+ --ai-thinking-color: #2563eb;
37
+ --ai-message-shadow: none;
38
+ }
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Shadow parts
44
+
45
+ Parts on the conversation area (the outer frame exposes many more — e.g.
46
+ `chat-header`, `input-row`, `input`, `send-button`):
47
+
48
+ | Part | Element |
49
+ | --- | --- |
50
+ | `chat-wrapper` | Outer frame (header + messages + composer) |
51
+ | `messages` | Scroll container (full width; owns the scrollbar) |
52
+ | `messages-content` | Width-capped, centred column that holds every message |
53
+ | `message` | Every message bubble |
54
+ | `message-<type>` | A bubble of one kind: `message-user`, `message-ai`, `message-ai-thinking`, `message-ai-function`, `message-interaction` |
55
+ | `message-interaction-<presentation>` | An interaction bubble in one presentation: `message-interaction-label`, `message-interaction-bare`, `message-interaction-bubble` |
56
+ | `thinking` | The loading-indicator row |
57
+
58
+ Target them from an app stylesheet with `::part()`:
59
+
60
+ ```css
61
+ /* Constrain every bubble to a width range */
62
+ foundation-ai-assistant::part(message) {
63
+ min-width: 200px;
64
+ max-width: 640px;
65
+ }
66
+
67
+ /* Restyle just one kind of bubble */
68
+ foundation-ai-assistant::part(message-user) {
69
+ border-radius: 18px;
70
+ }
71
+
72
+ /* Only interaction widgets, and only when framed as a bubble */
73
+ foundation-ai-assistant::part(message-interaction-bubble) {
74
+ min-width: 320px;
75
+ }
76
+
77
+ /* Change the padding inside bubbles */
78
+ foundation-ai-assistant::part(message) {
79
+ padding: 12px 16px;
80
+ }
81
+ ```
82
+
83
+ ### The conversation column (`messages-content`)
84
+
85
+ Messages sit in a column capped at `1000px` and centred inside the full-width
86
+ scroll container, so the scrollbar stays at the panel edge while the text keeps
87
+ a readable width. Adjust or remove the cap via the part:
88
+
89
+ ```css
90
+ /* Widen (or narrow) the column */
91
+ foundation-ai-assistant::part(messages-content) { max-width: 1400px; }
92
+
93
+ /* Remove the cap — messages fill the full width */
94
+ foundation-ai-assistant::part(messages-content) { max-width: none; }
95
+
96
+ /* Neutralise the wrapper entirely (as if the div weren't there) */
97
+ foundation-ai-assistant::part(messages-content) { display: contents; }
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Responsive sizing
103
+
104
+ A `min-width` only ever affects *short* messages — long ones are already wider —
105
+ so it can push a bubble past a narrow container. The assistant can be rendered at
106
+ any width (docked panel, popout, inline), so size overrides against the *element's*
107
+ width, not the viewport.
108
+
109
+ `@media` queries the viewport, which does not track the assistant's width, so it is
110
+ the wrong tool. Use a **container query** instead. `::part()` rules can be wrapped
111
+ in `@container` from the host stylesheet; the reliable pattern is to make your own
112
+ wrapper a container:
113
+
114
+ ```css
115
+ .ai-slot {
116
+ container-type: inline-size;
117
+ }
118
+
119
+ /* A comfortable minimum on wide layouts… */
120
+ foundation-ai-assistant::part(message) {
121
+ min-width: 220px;
122
+ }
123
+
124
+ /* …dropped when the assistant itself is narrow, so bubbles never overflow. */
125
+ @container (max-width: 420px) {
126
+ foundation-ai-assistant::part(message) {
127
+ min-width: 0;
128
+ }
129
+ }
130
+ ```
131
+
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.482.0",
4
+ "version": "14.482.1-GENC-1336.1",
5
5
  "license": "SEE LICENSE IN license.txt",
6
6
  "main": "dist/esm/index.js",
7
7
  "types": "dist/ai-assistant.d.ts",
@@ -64,25 +64,25 @@
64
64
  }
65
65
  },
66
66
  "devDependencies": {
67
- "@genesislcap/foundation-testing": "14.482.0",
68
- "@genesislcap/genx": "14.482.0",
69
- "@genesislcap/rollup-builder": "14.482.0",
70
- "@genesislcap/ts-builder": "14.482.0",
71
- "@genesislcap/uvu-playwright-builder": "14.482.0",
72
- "@genesislcap/vite-builder": "14.482.0",
73
- "@genesislcap/webpack-builder": "14.482.0",
67
+ "@genesislcap/foundation-testing": "14.482.1-GENC-1336.1",
68
+ "@genesislcap/genx": "14.482.1-GENC-1336.1",
69
+ "@genesislcap/rollup-builder": "14.482.1-GENC-1336.1",
70
+ "@genesislcap/ts-builder": "14.482.1-GENC-1336.1",
71
+ "@genesislcap/uvu-playwright-builder": "14.482.1-GENC-1336.1",
72
+ "@genesislcap/vite-builder": "14.482.1-GENC-1336.1",
73
+ "@genesislcap/webpack-builder": "14.482.1-GENC-1336.1",
74
74
  "@types/dompurify": "^3.0.5",
75
75
  "@types/marked": "^5.0.2"
76
76
  },
77
77
  "dependencies": {
78
- "@genesislcap/foundation-ai": "14.482.0",
79
- "@genesislcap/foundation-logger": "14.482.0",
80
- "@genesislcap/foundation-notifications": "14.482.0",
81
- "@genesislcap/foundation-redux": "14.482.0",
82
- "@genesislcap/foundation-ui": "14.482.0",
83
- "@genesislcap/foundation-utils": "14.482.0",
84
- "@genesislcap/rapid-design-system": "14.482.0",
85
- "@genesislcap/web-core": "14.482.0",
78
+ "@genesislcap/foundation-ai": "14.482.1-GENC-1336.1",
79
+ "@genesislcap/foundation-logger": "14.482.1-GENC-1336.1",
80
+ "@genesislcap/foundation-notifications": "14.482.1-GENC-1336.1",
81
+ "@genesislcap/foundation-redux": "14.482.1-GENC-1336.1",
82
+ "@genesislcap/foundation-ui": "14.482.1-GENC-1336.1",
83
+ "@genesislcap/foundation-utils": "14.482.1-GENC-1336.1",
84
+ "@genesislcap/rapid-design-system": "14.482.1-GENC-1336.1",
85
+ "@genesislcap/web-core": "14.482.1-GENC-1336.1",
86
86
  "dompurify": "^3.3.1",
87
87
  "marked": "^17.0.3"
88
88
  },
@@ -94,5 +94,5 @@
94
94
  "publishConfig": {
95
95
  "access": "public"
96
96
  },
97
- "gitHead": "176fdab04821da415454fcdbc124f7fabac07aa7"
97
+ "gitHead": "226fa34f7ccc429157141416f11971ee7b64c63e"
98
98
  }
package/src/main/index.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export * from './main.template';
2
- export * from '../styles';
3
2
  export * from './main';
4
3
  export * from './main.types';
@@ -87,9 +87,20 @@ const baseStyles = css`
87
87
  min-height: 0;
88
88
  overflow-y: auto;
89
89
  padding: 10px;
90
+ }
91
+
92
+ /* Caps and centres the conversation column inside the (full-width) scroll
93
+ container, so the scrollbar stays at the panel edge while the messages sit
94
+ in a readable-width column. Exposed as part="messages-content" so a host
95
+ can widen it (::part(messages-content) { max-width: none }) or neutralise
96
+ the wrapper entirely (::part(messages-content) { display: contents }). */
97
+ .messages-content {
90
98
  display: flex;
91
99
  flex-direction: column;
92
100
  gap: 10px;
101
+ width: 100%;
102
+ max-width: 1000px;
103
+ margin-inline: auto;
93
104
  }
94
105
 
95
106
  @keyframes slide-in-right {
@@ -236,7 +247,7 @@ const baseStyles = css`
236
247
  }
237
248
 
238
249
  .message {
239
- padding: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 3px);
250
+ padding: calc(var(--design-unit) * 2.5px) calc(var(--design-unit) * 3.5px);
240
251
  max-width: 80%;
241
252
  min-width: 70px;
242
253
  font-family: var(--body-font);
@@ -130,6 +130,21 @@ const senderLabelFor = (m: ChatMessage): string =>
130
130
  const interactionPresentation = (m: ChatMessage): InteractionPresentation =>
131
131
  m.interaction?.presentation ?? 'label';
132
132
 
133
+ /**
134
+ * Space-separated `part` names for a message bubble, so a host can style bubbles
135
+ * from its own stylesheet via `::part()`. Every bubble gets `message` plus its
136
+ * type (`message-user`, `message-ai`, `message-ai-thinking`, `message-ai-function`,
137
+ * `message-interaction`). Interaction bubbles additionally carry a
138
+ * presentation-specific part (`message-interaction-label` / `-bare` / `-bubble`)
139
+ * so a host can target, say, only the bubble-framed widgets.
140
+ */
141
+ const messageParts = (m: ChatMessage): string => {
142
+ const type = messageType(m);
143
+ return type === 'interaction'
144
+ ? `message message-interaction message-interaction-${interactionPresentation(m)}`
145
+ : `message message-${type}`;
146
+ };
147
+
133
148
  // ─── Sub-agent trace fragments ────────────────────────────────────────────────
134
149
 
135
150
  const subAgentAssistantTemplate = html<ChatMessage>`
@@ -310,6 +325,7 @@ ${(tc) => (tc.foldPath?.length ? `${tc.foldPath.join(' › ')} › ` : '')}<stro
310
325
  <div
311
326
  class="message ${(m) => messageType(m)} ${(m) =>
312
327
  classNames(['narration', m.category === 'narration'])}"
328
+ part="${(m) => messageParts(m)}"
313
329
  >
314
330
  ${when(
315
331
  // A 'bare' interaction owns its full presentation — suppress the
@@ -496,30 +512,38 @@ ${(tc) => (tc.foldPath?.length ? `${tc.foldPath.join(' › ')} › ` : '')}<stro
496
512
  </div>
497
513
 
498
514
  <div class="messages" part="messages" ${ref('messagesEl')}>
499
- ${repeat((x) => x.visibleMessages, messageRowTemplate)}
500
- ${repeat((x) => x.activeInteractionRow, messageRowTemplate)}
501
- ${when((x) => x.liveSubAgentTrace.length > 0 && x.showToolCalls, liveSubAgentTraceTemplate)}
502
- ${when(
503
- (x) =>
504
- x.showLoadingIndicator &&
505
- (x.chatConfig.ui?.animations == null ||
506
- LOADING_STYLE_ANIMATIONS.some((s) => x.enabledAnimations.includes(s))),
507
- html<FoundationAiAssistant>`
508
- <div class="message-row ai" part="thinking">
509
- <div class="avatar">
510
- ${(x) =>
511
- x.imageSrc
512
- ? html<FoundationAiAssistant>`
513
- <img src="${() => x.imageSrc}" alt="Assistant" class="avatar-img" />
514
- `
515
- : html<FoundationAiAssistant>`
516
- <span class="avatar-icon" :innerHTML="${() => x.assistantIconSafe}"></span>
517
- `}
515
+ <div class="messages-content" part="messages-content">
516
+ ${repeat((x) => x.visibleMessages, messageRowTemplate)}
517
+ ${repeat((x) => x.activeInteractionRow, messageRowTemplate)}
518
+ ${when(
519
+ (x) => x.liveSubAgentTrace.length > 0 && x.showToolCalls,
520
+ liveSubAgentTraceTemplate,
521
+ )}
522
+ ${when(
523
+ (x) =>
524
+ x.showLoadingIndicator &&
525
+ (x.chatConfig.ui?.animations == null ||
526
+ LOADING_STYLE_ANIMATIONS.some((s) => x.enabledAnimations.includes(s))),
527
+ html<FoundationAiAssistant>`
528
+ <div class="message-row ai" part="thinking">
529
+ <div class="avatar">
530
+ ${(x) =>
531
+ x.imageSrc
532
+ ? html<FoundationAiAssistant>`
533
+ <img src="${() => x.imageSrc}" alt="Assistant" class="avatar-img" />
534
+ `
535
+ : html<FoundationAiAssistant>`
536
+ <span
537
+ class="avatar-icon"
538
+ :innerHTML="${() => x.assistantIconSafe}"
539
+ ></span>
540
+ `}
541
+ </div>
542
+ ${(x) => selectThinkingTemplate(x)}
518
543
  </div>
519
- ${(x) => selectThinkingTemplate(x)}
520
- </div>
521
- `,
522
- )}
544
+ `,
545
+ )}
546
+ </div>
523
547
  </div>
524
548
 
525
549
  ${when(
@@ -1,2 +0,0 @@
1
- export * from './styles';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/styles/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC"}
@@ -1,5 +0,0 @@
1
- /**
2
- * @beta
3
- */
4
- export declare const FoundationAiAssistantStyles: import("@microsoft/fast-element").ElementStyles;
5
- //# sourceMappingURL=styles.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/styles/styles.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,2BAA2B,iDAwOvC,CAAC"}
@@ -1 +0,0 @@
1
- export * from './styles';
@@ -1,237 +0,0 @@
1
- import { css } from '@genesislcap/web-core';
2
- /**
3
- * @beta
4
- */
5
- export const FoundationAiAssistantStyles = css `
6
- :host {
7
- display: flex;
8
- flex-direction: column;
9
- height: 100%;
10
- box-sizing: border-box;
11
- }
12
-
13
- .chat-wrapper {
14
- display: flex;
15
- flex-direction: column;
16
- height: 100%;
17
- overflow: hidden;
18
- background: var(--neutral-fill-layer-rest, var(--neutral-layer-1));
19
- border-radius: calc(var(--design-unit, 4) * 1px);
20
- border: 1px solid var(--neutral-stroke-rest);
21
- }
22
-
23
- .chat-header {
24
- display: flex;
25
- align-items: center;
26
- gap: calc(var(--design-unit, 4) * 3px);
27
- padding: calc(var(--design-unit, 4) * 1.5px) calc(var(--design-unit, 4) * 3px);
28
- border-bottom: 1px solid var(--neutral-stroke-rest);
29
- background: var(--neutral-fill-stealth-rest);
30
- font-size: var(--type-ramp-minus-1-font-size);
31
- color: var(--neutral-foreground-rest);
32
- }
33
-
34
- .chat-title {
35
- flex: 1;
36
- font-weight: 600;
37
- font-size: var(--type-ramp-base-font-size);
38
- overflow: hidden;
39
- text-overflow: ellipsis;
40
- white-space: nowrap;
41
- }
42
-
43
- .toggle-label {
44
- display: flex;
45
- align-items: center;
46
- gap: calc(var(--design-unit, 4) * 1px);
47
- cursor: pointer;
48
- user-select: none;
49
- }
50
-
51
- .toggle-label input[type='checkbox'] {
52
- cursor: pointer;
53
- accent-color: var(--accent-fill-rest);
54
- }
55
-
56
- .download-button {
57
- margin-left: auto;
58
- }
59
-
60
- .messages {
61
- flex: 1;
62
- overflow-y: auto;
63
- padding: calc(var(--design-unit, 4) * 3px);
64
- display: flex;
65
- flex-direction: column;
66
- gap: calc(var(--design-unit, 4) * 2px);
67
- }
68
-
69
- .message {
70
- padding: calc(var(--design-unit, 4) * 2px) calc(var(--design-unit, 4) * 3px);
71
- border-radius: calc(var(--design-unit, 4) * 2px);
72
- max-width: 80%;
73
- word-break: break-word;
74
- font-size: var(--type-ramp-base-font-size);
75
- line-height: var(--type-ramp-base-line-height);
76
- }
77
-
78
- .message--user {
79
- align-self: flex-end;
80
- background: var(--accent-fill-rest);
81
- color: var(--foreground-on-accent-rest);
82
- border-bottom-right-radius: calc(var(--design-unit, 4) * 0.5px);
83
- }
84
-
85
- .message--assistant {
86
- align-self: flex-start;
87
- background: var(--neutral-fill-rest);
88
- color: var(--neutral-foreground-rest);
89
- border-bottom-left-radius: calc(var(--design-unit, 4) * 0.5px);
90
- }
91
-
92
- .thinking-block {
93
- margin-bottom: calc(var(--design-unit, 4) * 1px);
94
- border: 1px solid var(--neutral-stroke-rest);
95
- border-radius: calc(var(--design-unit, 4) * 1px);
96
- overflow: hidden;
97
- }
98
-
99
- .thinking-summary {
100
- cursor: pointer;
101
- padding: calc(var(--design-unit, 4) * 1px) calc(var(--design-unit, 4) * 2px);
102
- font-size: var(--type-ramp-minus-1-font-size);
103
- color: var(--neutral-foreground-hint);
104
- user-select: none;
105
- list-style: none;
106
- }
107
-
108
- .thinking-summary::marker,
109
- .thinking-summary::-webkit-details-marker {
110
- display: none;
111
- }
112
-
113
- .thinking-summary::before {
114
- content: '▶ ';
115
- font-size: 0.6em;
116
- vertical-align: middle;
117
- }
118
-
119
- details[open] .thinking-summary::before {
120
- content: '▼ ';
121
- }
122
-
123
- .thinking-content {
124
- padding: calc(var(--design-unit, 4) * 2px);
125
- font-size: var(--type-ramp-minus-1-font-size);
126
- color: var(--neutral-foreground-hint);
127
- border-top: 1px solid var(--neutral-stroke-rest);
128
- }
129
-
130
- .tool-calls {
131
- font-size: var(--type-ramp-minus-1-font-size);
132
- color: var(--neutral-foreground-hint);
133
- font-family: monospace;
134
- }
135
-
136
- .message--tool {
137
- align-self: flex-start;
138
- background: var(--neutral-fill-stealth-rest);
139
- color: var(--neutral-foreground-hint);
140
- font-size: var(--type-ramp-minus-1-font-size);
141
- font-family: monospace;
142
- max-width: 100%;
143
- border-radius: calc(var(--design-unit, 4) * 1px);
144
- }
145
-
146
- .empty-state {
147
- flex: 1;
148
- display: flex;
149
- align-items: center;
150
- justify-content: center;
151
- color: var(--neutral-foreground-hint);
152
- font-size: var(--type-ramp-base-font-size);
153
- }
154
-
155
- .thinking {
156
- align-self: flex-start;
157
- padding: calc(var(--design-unit, 4) * 1px);
158
- }
159
-
160
- .file-input {
161
- display: none;
162
- }
163
-
164
- .attachment-chips {
165
- display: flex;
166
- flex-wrap: wrap;
167
- gap: calc(var(--design-unit, 4) * 1px);
168
- padding: calc(var(--design-unit, 4) * 1px) calc(var(--design-unit, 4) * 2px);
169
- border-top: 1px solid var(--neutral-stroke-rest);
170
- }
171
-
172
- .attachment-chip {
173
- display: inline-flex;
174
- align-items: center;
175
- gap: calc(var(--design-unit, 4) * 1px);
176
- padding: calc(var(--design-unit, 4) * 0.5px) calc(var(--design-unit, 4) * 1.5px);
177
- background: var(--neutral-fill-rest);
178
- border: 1px solid var(--neutral-stroke-rest);
179
- border-radius: calc(var(--design-unit, 4) * 4px);
180
- font-size: var(--type-ramp-minus-1-font-size);
181
- color: var(--neutral-foreground-rest);
182
- max-width: 200px;
183
- overflow: hidden;
184
- text-overflow: ellipsis;
185
- white-space: nowrap;
186
- }
187
-
188
- .attachment-chip-error {
189
- background: var(--error-fill-rest, #fde8e8);
190
- border-color: var(--error-stroke-rest, #f87171);
191
- color: var(--error-foreground-rest, #b91c1c);
192
- }
193
-
194
- .chip-remove {
195
- flex-shrink: 0;
196
- background: none;
197
- border: none;
198
- cursor: pointer;
199
- padding: 0;
200
- line-height: 1;
201
- color: inherit;
202
- opacity: 0.6;
203
- font-size: 0.9em;
204
- }
205
-
206
- .chip-remove:hover {
207
- opacity: 1;
208
- }
209
-
210
- .input-row {
211
- display: flex;
212
- gap: calc(var(--design-unit, 4) * 2px);
213
- padding: calc(var(--design-unit, 4) * 2px);
214
- border-top: 1px solid var(--neutral-stroke-rest);
215
- align-items: flex-end;
216
- }
217
-
218
- .attach-button {
219
- flex-shrink: 0;
220
- align-self: flex-end;
221
- }
222
-
223
- .chat-input {
224
- flex: 1;
225
- }
226
-
227
- .chat-input::part(control) {
228
- resize: none;
229
- min-height: calc(var(--base-height-multiplier, 10) * 1px + var(--design-unit, 4) * 4px);
230
- max-height: calc(var(--base-height-multiplier, 10) * 5px);
231
- }
232
-
233
- .send-button {
234
- flex-shrink: 0;
235
- align-self: flex-end;
236
- }
237
- `;
@@ -1 +0,0 @@
1
- export * from './styles';
@@ -1,238 +0,0 @@
1
- import { css } from '@genesislcap/web-core';
2
-
3
- /**
4
- * @beta
5
- */
6
- export const FoundationAiAssistantStyles = css`
7
- :host {
8
- display: flex;
9
- flex-direction: column;
10
- height: 100%;
11
- box-sizing: border-box;
12
- }
13
-
14
- .chat-wrapper {
15
- display: flex;
16
- flex-direction: column;
17
- height: 100%;
18
- overflow: hidden;
19
- background: var(--neutral-fill-layer-rest, var(--neutral-layer-1));
20
- border-radius: calc(var(--design-unit, 4) * 1px);
21
- border: 1px solid var(--neutral-stroke-rest);
22
- }
23
-
24
- .chat-header {
25
- display: flex;
26
- align-items: center;
27
- gap: calc(var(--design-unit, 4) * 3px);
28
- padding: calc(var(--design-unit, 4) * 1.5px) calc(var(--design-unit, 4) * 3px);
29
- border-bottom: 1px solid var(--neutral-stroke-rest);
30
- background: var(--neutral-fill-stealth-rest);
31
- font-size: var(--type-ramp-minus-1-font-size);
32
- color: var(--neutral-foreground-rest);
33
- }
34
-
35
- .chat-title {
36
- flex: 1;
37
- font-weight: 600;
38
- font-size: var(--type-ramp-base-font-size);
39
- overflow: hidden;
40
- text-overflow: ellipsis;
41
- white-space: nowrap;
42
- }
43
-
44
- .toggle-label {
45
- display: flex;
46
- align-items: center;
47
- gap: calc(var(--design-unit, 4) * 1px);
48
- cursor: pointer;
49
- user-select: none;
50
- }
51
-
52
- .toggle-label input[type='checkbox'] {
53
- cursor: pointer;
54
- accent-color: var(--accent-fill-rest);
55
- }
56
-
57
- .download-button {
58
- margin-left: auto;
59
- }
60
-
61
- .messages {
62
- flex: 1;
63
- overflow-y: auto;
64
- padding: calc(var(--design-unit, 4) * 3px);
65
- display: flex;
66
- flex-direction: column;
67
- gap: calc(var(--design-unit, 4) * 2px);
68
- }
69
-
70
- .message {
71
- padding: calc(var(--design-unit, 4) * 2px) calc(var(--design-unit, 4) * 3px);
72
- border-radius: calc(var(--design-unit, 4) * 2px);
73
- max-width: 80%;
74
- word-break: break-word;
75
- font-size: var(--type-ramp-base-font-size);
76
- line-height: var(--type-ramp-base-line-height);
77
- }
78
-
79
- .message--user {
80
- align-self: flex-end;
81
- background: var(--accent-fill-rest);
82
- color: var(--foreground-on-accent-rest);
83
- border-bottom-right-radius: calc(var(--design-unit, 4) * 0.5px);
84
- }
85
-
86
- .message--assistant {
87
- align-self: flex-start;
88
- background: var(--neutral-fill-rest);
89
- color: var(--neutral-foreground-rest);
90
- border-bottom-left-radius: calc(var(--design-unit, 4) * 0.5px);
91
- }
92
-
93
- .thinking-block {
94
- margin-bottom: calc(var(--design-unit, 4) * 1px);
95
- border: 1px solid var(--neutral-stroke-rest);
96
- border-radius: calc(var(--design-unit, 4) * 1px);
97
- overflow: hidden;
98
- }
99
-
100
- .thinking-summary {
101
- cursor: pointer;
102
- padding: calc(var(--design-unit, 4) * 1px) calc(var(--design-unit, 4) * 2px);
103
- font-size: var(--type-ramp-minus-1-font-size);
104
- color: var(--neutral-foreground-hint);
105
- user-select: none;
106
- list-style: none;
107
- }
108
-
109
- .thinking-summary::marker,
110
- .thinking-summary::-webkit-details-marker {
111
- display: none;
112
- }
113
-
114
- .thinking-summary::before {
115
- content: '▶ ';
116
- font-size: 0.6em;
117
- vertical-align: middle;
118
- }
119
-
120
- details[open] .thinking-summary::before {
121
- content: '▼ ';
122
- }
123
-
124
- .thinking-content {
125
- padding: calc(var(--design-unit, 4) * 2px);
126
- font-size: var(--type-ramp-minus-1-font-size);
127
- color: var(--neutral-foreground-hint);
128
- border-top: 1px solid var(--neutral-stroke-rest);
129
- }
130
-
131
- .tool-calls {
132
- font-size: var(--type-ramp-minus-1-font-size);
133
- color: var(--neutral-foreground-hint);
134
- font-family: monospace;
135
- }
136
-
137
- .message--tool {
138
- align-self: flex-start;
139
- background: var(--neutral-fill-stealth-rest);
140
- color: var(--neutral-foreground-hint);
141
- font-size: var(--type-ramp-minus-1-font-size);
142
- font-family: monospace;
143
- max-width: 100%;
144
- border-radius: calc(var(--design-unit, 4) * 1px);
145
- }
146
-
147
- .empty-state {
148
- flex: 1;
149
- display: flex;
150
- align-items: center;
151
- justify-content: center;
152
- color: var(--neutral-foreground-hint);
153
- font-size: var(--type-ramp-base-font-size);
154
- }
155
-
156
- .thinking {
157
- align-self: flex-start;
158
- padding: calc(var(--design-unit, 4) * 1px);
159
- }
160
-
161
- .file-input {
162
- display: none;
163
- }
164
-
165
- .attachment-chips {
166
- display: flex;
167
- flex-wrap: wrap;
168
- gap: calc(var(--design-unit, 4) * 1px);
169
- padding: calc(var(--design-unit, 4) * 1px) calc(var(--design-unit, 4) * 2px);
170
- border-top: 1px solid var(--neutral-stroke-rest);
171
- }
172
-
173
- .attachment-chip {
174
- display: inline-flex;
175
- align-items: center;
176
- gap: calc(var(--design-unit, 4) * 1px);
177
- padding: calc(var(--design-unit, 4) * 0.5px) calc(var(--design-unit, 4) * 1.5px);
178
- background: var(--neutral-fill-rest);
179
- border: 1px solid var(--neutral-stroke-rest);
180
- border-radius: calc(var(--design-unit, 4) * 4px);
181
- font-size: var(--type-ramp-minus-1-font-size);
182
- color: var(--neutral-foreground-rest);
183
- max-width: 200px;
184
- overflow: hidden;
185
- text-overflow: ellipsis;
186
- white-space: nowrap;
187
- }
188
-
189
- .attachment-chip-error {
190
- background: var(--error-fill-rest, #fde8e8);
191
- border-color: var(--error-stroke-rest, #f87171);
192
- color: var(--error-foreground-rest, #b91c1c);
193
- }
194
-
195
- .chip-remove {
196
- flex-shrink: 0;
197
- background: none;
198
- border: none;
199
- cursor: pointer;
200
- padding: 0;
201
- line-height: 1;
202
- color: inherit;
203
- opacity: 0.6;
204
- font-size: 0.9em;
205
- }
206
-
207
- .chip-remove:hover {
208
- opacity: 1;
209
- }
210
-
211
- .input-row {
212
- display: flex;
213
- gap: calc(var(--design-unit, 4) * 2px);
214
- padding: calc(var(--design-unit, 4) * 2px);
215
- border-top: 1px solid var(--neutral-stroke-rest);
216
- align-items: flex-end;
217
- }
218
-
219
- .attach-button {
220
- flex-shrink: 0;
221
- align-self: flex-end;
222
- }
223
-
224
- .chat-input {
225
- flex: 1;
226
- }
227
-
228
- .chat-input::part(control) {
229
- resize: none;
230
- min-height: calc(var(--base-height-multiplier, 10) * 1px + var(--design-unit, 4) * 4px);
231
- max-height: calc(var(--base-height-multiplier, 10) * 5px);
232
- }
233
-
234
- .send-button {
235
- flex-shrink: 0;
236
- align-self: flex-end;
237
- }
238
- `;