@cianfrani/ai-ui 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +144 -0
  3. package/dist/ai-ui.js +3218 -0
  4. package/dist/types/index.d.ts +7 -0
  5. package/dist/types/lib/has-slot-controller.d.ts +21 -0
  6. package/dist/types/lib/tool-tone.d.ts +2 -0
  7. package/dist/types/native-styles.d.ts +5 -0
  8. package/dist/types/semantic/ai-conversation.d.ts +28 -0
  9. package/dist/types/semantic/ai-event.d.ts +91 -0
  10. package/dist/types/semantic/ai-message.d.ts +45 -0
  11. package/dist/types/semantic/ai-thinking.d.ts +41 -0
  12. package/dist/types/semantic/ai-tool-call.d.ts +59 -0
  13. package/dist/types/semantic/ai-tool-result.d.ts +44 -0
  14. package/dist/types/semantic/index.d.ts +6 -0
  15. package/dist/types/visual/avatar.d.ts +34 -0
  16. package/dist/types/visual/badge.d.ts +32 -0
  17. package/dist/types/visual/divider.d.ts +26 -0
  18. package/dist/types/visual/icon.d.ts +24 -0
  19. package/dist/types/visual/index.d.ts +9 -0
  20. package/dist/types/visual/markdown.d.ts +52 -0
  21. package/dist/types/visual/stack.d.ts +32 -0
  22. package/dist/types/visual/status.d.ts +33 -0
  23. package/dist/types/visual/surface.d.ts +34 -0
  24. package/dist/types/visual/text.d.ts +37 -0
  25. package/package.json +67 -0
  26. package/src/custom-elements.json +3741 -0
  27. package/src/index.ts +8 -0
  28. package/src/lib/has-slot-controller.ts +61 -0
  29. package/src/lib/tool-tone.ts +18 -0
  30. package/src/native-styles.ts +29 -0
  31. package/src/semantic/ai-conversation.ts +84 -0
  32. package/src/semantic/ai-event.ts +452 -0
  33. package/src/semantic/ai-message.ts +235 -0
  34. package/src/semantic/ai-thinking.ts +190 -0
  35. package/src/semantic/ai-tool-call.ts +513 -0
  36. package/src/semantic/ai-tool-result.ts +239 -0
  37. package/src/semantic/index.ts +6 -0
  38. package/src/visual/avatar.ts +163 -0
  39. package/src/visual/badge.ts +141 -0
  40. package/src/visual/divider.ts +97 -0
  41. package/src/visual/icon.ts +97 -0
  42. package/src/visual/index.ts +9 -0
  43. package/src/visual/markdown.ts +888 -0
  44. package/src/visual/stack.ts +115 -0
  45. package/src/visual/status.ts +170 -0
  46. package/src/visual/surface.ts +150 -0
  47. package/src/visual/text.ts +141 -0
package/dist/ai-ui.js ADDED
@@ -0,0 +1,3218 @@
1
+ var __legacyDecorateClassTS = function(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
4
+ r = Reflect.decorate(decorators, target, key, desc);
5
+ else
6
+ for (var i = decorators.length - 1;i >= 0; i--)
7
+ if (d = decorators[i])
8
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
9
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
10
+ };
11
+
12
+ // src/semantic/ai-conversation.ts
13
+ import { LitElement, css, html } from "lit";
14
+ import { customElement, property } from "lit/decorators.js";
15
+ class AiConversation extends LitElement {
16
+ constructor() {
17
+ super(...arguments);
18
+ this.density = "comfortable";
19
+ this.live = false;
20
+ this.label = "Conversation";
21
+ }
22
+ static styles = css`
23
+ :host {
24
+ box-sizing: border-box;
25
+ display: block;
26
+ margin: 0;
27
+ padding: 0;
28
+ }
29
+
30
+ *,
31
+ *::before,
32
+ *::after {
33
+ box-sizing: inherit;
34
+ }
35
+
36
+ .conversation {
37
+ display: flex;
38
+ flex-direction: column;
39
+ gap: var(--ai-conversation-gap, var(--ai-space-lg, 16px));
40
+ background: var(--ai-conversation-background, transparent);
41
+ color: var(--ai-conversation-color, var(--ai-color-text, inherit));
42
+ }
43
+
44
+ .conversation[data-density="compact"] {
45
+ gap: var(--ai-conversation-compact-gap, var(--ai-space-sm, 8px));
46
+ }
47
+
48
+ :host([live]) .conversation {
49
+ border-left: 2px solid var(--ai-conversation-live-border-color, transparent);
50
+ }
51
+ `;
52
+ get normalizedDensity() {
53
+ return this.density === "compact" ? "compact" : "comfortable";
54
+ }
55
+ render() {
56
+ const ariaLive = this.live ? "polite" : "off";
57
+ return html`
58
+ <section
59
+ class="conversation"
60
+ data-density=${this.normalizedDensity}
61
+ aria-label=${this.getAttribute("aria-label") ?? this.label}
62
+ aria-live=${ariaLive}
63
+ aria-relevant="additions text"
64
+ >
65
+ <slot></slot>
66
+ </section>
67
+ `;
68
+ }
69
+ }
70
+ __legacyDecorateClassTS([
71
+ property({ reflect: true })
72
+ ], AiConversation.prototype, "density", undefined);
73
+ __legacyDecorateClassTS([
74
+ property({ type: Boolean, reflect: true })
75
+ ], AiConversation.prototype, "live", undefined);
76
+ __legacyDecorateClassTS([
77
+ property({ reflect: true })
78
+ ], AiConversation.prototype, "label", undefined);
79
+ AiConversation = __legacyDecorateClassTS([
80
+ customElement("ai-conversation")
81
+ ], AiConversation);
82
+ // src/semantic/ai-message.ts
83
+ import { LitElement as LitElement2, css as css2, html as html2, nothing } from "lit";
84
+ import { customElement as customElement2, property as property2 } from "lit/decorators.js";
85
+ class AiMessage extends LitElement2 {
86
+ constructor() {
87
+ super(...arguments);
88
+ this.role = "assistant";
89
+ this.htmlFor = "";
90
+ this.status = "unknown";
91
+ this.timestamp = "";
92
+ this.label = "";
93
+ }
94
+ static styles = css2`
95
+ :host {
96
+ box-sizing: border-box;
97
+ display: block;
98
+ margin: 0;
99
+ padding: 0;
100
+ max-width: 100%;
101
+ min-width: 0;
102
+ }
103
+
104
+ *,
105
+ *::before,
106
+ *::after {
107
+ box-sizing: inherit;
108
+ }
109
+
110
+ .message {
111
+ display: flex;
112
+ flex-direction: column;
113
+ min-width: 0;
114
+ max-width: 100%;
115
+ background-color: var(--ai-message-background, transparent);
116
+ color: var(--ai-message-color, inherit);
117
+ border: var(--ai-message-border-width, 0) solid var(--ai-message-border-color, transparent);
118
+ border-radius: var(--ai-message-radius, 0);
119
+ }
120
+
121
+ .content {
122
+ display: flex;
123
+ flex-direction: column;
124
+ gap: var(--ai-message-gap, 3px);
125
+ min-width: 0;
126
+ max-width: 100%;
127
+ }
128
+
129
+ .content ::slotted(*) {
130
+ min-width: 0;
131
+ max-width: 100%;
132
+ }
133
+
134
+ ::slotted([slot="meta"]) {
135
+ color: var(--ai-message-meta-color, var(--text-muted, var(--ai-color-text-muted, #888)));
136
+ font-size: var(--font-size-caption, var(--ai-font-size-caption, 0.75rem));
137
+ line-height: var(--line-height-tight, var(--ai-line-height-tight, 1.1));
138
+ }
139
+
140
+ .meta-fallback {
141
+ color: var(--ai-message-meta-color, var(--text-muted, var(--ai-color-text-muted, #888)));
142
+ font-size: var(--font-size-caption, var(--ai-font-size-caption, 0.75rem));
143
+ line-height: var(--line-height-tight, var(--ai-line-height-tight, 1.1));
144
+ }
145
+
146
+ /* User bubble treatment. */
147
+ :host([role="user"]) .message {
148
+ align-items: flex-end;
149
+ gap: calc(var(--spacing-xs, 4px) / 2);
150
+ }
151
+
152
+ :host([role="user"]) .content {
153
+ width: auto;
154
+ max-width: var(--ai-message-user-max-width, min(90%, 640px));
155
+ padding: var(--spacing-sm, 8px) var(--spacing-md, 12px);
156
+ background: var(--ai-message-user-background, var(--accent, Highlight));
157
+ color: var(--ai-message-user-color, var(--text-on-accent, HighlightText));
158
+ border-radius: var(
159
+ --ai-message-radius,
160
+ var(--radius, 8px) var(--radius, 8px) 4px var(--radius, 8px)
161
+ );
162
+ box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
163
+ overflow-wrap: anywhere;
164
+ }
165
+
166
+ /* Assistant rail/header treatment. */
167
+ :host([role="assistant"]) .message {
168
+ align-items: stretch;
169
+ gap: 2px;
170
+ width: 100%;
171
+ }
172
+
173
+ .header {
174
+ display: none;
175
+ }
176
+
177
+ :host([role="assistant"]) .header {
178
+ display: inline-flex;
179
+ align-items: center;
180
+ gap: var(--spacing-sm, 8px);
181
+ padding-left: calc(var(--spacing-md, 12px) + 2px);
182
+ line-height: var(--line-height-tight, 1.1);
183
+ }
184
+
185
+ .actor-label {
186
+ color: var(--ai-message-assistant-label-color, var(--text-muted, #888));
187
+ font-size: var(--font-size-caption, 0.75rem);
188
+ font-weight: var(--font-weight-bold, 700);
189
+ letter-spacing: var(--tracking-overline, 0.08em);
190
+ line-height: var(--line-height-tight, 1.1);
191
+ text-transform: uppercase;
192
+ }
193
+
194
+ :host([role="assistant"]) .content {
195
+ display: flex;
196
+ flex-direction: column;
197
+ width: 100%;
198
+ max-width: 100%;
199
+ min-width: 0;
200
+ padding-left: calc(var(--spacing-md, 12px) + 2px);
201
+ border-left: 1px solid var(--ai-message-assistant-rail-color, rgba(255, 255, 255, 0.08));
202
+ background: transparent;
203
+ color: var(--ai-message-color, var(--text, inherit));
204
+ }
205
+
206
+ :host([role="tool"]) .message,
207
+ :host([role="system"]) .message {
208
+ gap: var(--ai-message-gap, 3px);
209
+ color: var(--ai-message-color, var(--text, inherit));
210
+ }
211
+
212
+ :host([role="tool"]) .content {
213
+ width: 100%;
214
+ }
215
+
216
+ :host([role="system"]) .content {
217
+ color: color-mix(in oklch, var(--text-muted, currentColor) 92%, transparent);
218
+ font-size: var(--font-size-meta, 0.8125rem);
219
+ }
220
+
221
+ @media (max-width: 420px) {
222
+ :host([role="assistant"]) .header,
223
+ :host([role="assistant"]) .content {
224
+ padding-left: calc(var(--spacing-sm, 8px) + 2px);
225
+ }
226
+ }
227
+ `;
228
+ get normalizedRole() {
229
+ if (this.role === "user" || this.role === "assistant" || this.role === "system" || this.role === "tool") {
230
+ return this.role;
231
+ }
232
+ return "system";
233
+ }
234
+ get actorLabel() {
235
+ return this.label || (this.normalizedRole === "assistant" ? "Assistant" : this.normalizedRole);
236
+ }
237
+ render() {
238
+ const role = this.normalizedRole;
239
+ return html2`
240
+ <article class="message" data-role=${role} aria-busy=${this.status === "running"}>
241
+ ${role === "assistant" ? html2`
242
+ <div class="header">
243
+ <slot name="avatar"></slot>
244
+ <slot name="actor"><span class="actor-label">${this.actorLabel}</span></slot>
245
+ <slot name="meta"></slot>
246
+ </div>
247
+ ` : nothing}
248
+ <div class="content">
249
+ <slot></slot>
250
+ </div>
251
+ ${role !== "assistant" ? html2`
252
+ <slot name="meta"></slot>
253
+ ` : nothing}
254
+ </article>
255
+ `;
256
+ }
257
+ }
258
+ __legacyDecorateClassTS([
259
+ property2({ reflect: true })
260
+ ], AiMessage.prototype, "role", undefined);
261
+ __legacyDecorateClassTS([
262
+ property2({ reflect: true, attribute: "for" })
263
+ ], AiMessage.prototype, "htmlFor", undefined);
264
+ __legacyDecorateClassTS([
265
+ property2({ reflect: true })
266
+ ], AiMessage.prototype, "status", undefined);
267
+ __legacyDecorateClassTS([
268
+ property2({ reflect: true })
269
+ ], AiMessage.prototype, "timestamp", undefined);
270
+ __legacyDecorateClassTS([
271
+ property2({ reflect: true })
272
+ ], AiMessage.prototype, "label", undefined);
273
+ AiMessage = __legacyDecorateClassTS([
274
+ customElement2("ai-message")
275
+ ], AiMessage);
276
+ // src/semantic/ai-tool-call.ts
277
+ import { LitElement as LitElement3, css as css3, html as html3, nothing as nothing2, svg } from "lit";
278
+ import { customElement as customElement3, property as property3 } from "lit/decorators.js";
279
+
280
+ // src/lib/tool-tone.ts
281
+ function getToolTone(name) {
282
+ const normalized = name.toLowerCase();
283
+ if (normalized.includes("read")) {
284
+ return "read";
285
+ }
286
+ if (normalized.includes("write")) {
287
+ return "write";
288
+ }
289
+ if (normalized.includes("edit")) {
290
+ return "edit";
291
+ }
292
+ if (normalized.includes("bash")) {
293
+ return "bash";
294
+ }
295
+ return "generic";
296
+ }
297
+
298
+ // src/lib/has-slot-controller.ts
299
+ class HasSlotController {
300
+ host;
301
+ slotNames = [];
302
+ constructor(host, ...slotNames) {
303
+ (this.host = host).addController(this);
304
+ this.slotNames = slotNames;
305
+ }
306
+ hasDefaultSlot() {
307
+ return [...this.host.childNodes].some((node) => {
308
+ if (node.nodeType === node.TEXT_NODE && node.textContent?.trim() !== "") {
309
+ return true;
310
+ }
311
+ if (node.nodeType === node.ELEMENT_NODE) {
312
+ const el = node;
313
+ if (!el.hasAttribute("slot")) {
314
+ return true;
315
+ }
316
+ }
317
+ return false;
318
+ });
319
+ }
320
+ hasNamedSlot(name) {
321
+ return this.host.querySelector(`:scope > [slot="${name}"]`) !== null;
322
+ }
323
+ test(slotName) {
324
+ return slotName === "[default]" ? this.hasDefaultSlot() : this.hasNamedSlot(slotName);
325
+ }
326
+ hostConnected() {
327
+ this.host.shadowRoot?.addEventListener("slotchange", this.handleSlotChange);
328
+ }
329
+ hostDisconnected() {
330
+ this.host.shadowRoot?.removeEventListener("slotchange", this.handleSlotChange);
331
+ }
332
+ handleSlotChange = (event) => {
333
+ const slot = event.target;
334
+ if (this.slotNames.includes("[default]") && !slot.name || slot.name && this.slotNames.includes(slot.name)) {
335
+ this.host.requestUpdate();
336
+ }
337
+ };
338
+ }
339
+
340
+ // src/semantic/ai-tool-call.ts
341
+ function renderGlyph(tone) {
342
+ switch (tone) {
343
+ case "read":
344
+ return svg`<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 1 2-2h12"></path><path d="M14 3v6h6"></path><path d="M8 13h8"></path><path d="M8 17h5"></path><path d="M14 3l6 6v10a2 2 0 0 1-2 2H6"></path></svg>`;
345
+ case "write":
346
+ return svg`<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 20h9"></path><path d="M16.5 3.5a2.1 2.1 0 1 1 3 3L7 19l-4 1 1-4Z"></path></svg>`;
347
+ case "edit":
348
+ return svg`<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 20h9"></path><path d="M4 13.5V20h6.5L19 11.5 12.5 5 4 13.5Z"></path></svg>`;
349
+ case "bash":
350
+ return svg`<svg viewBox="0 0 24 24" aria-hidden="true"><path d="m4 17 6-5-6-5"></path><path d="M12 19h8"></path></svg>`;
351
+ default:
352
+ return nothing2;
353
+ }
354
+ }
355
+
356
+ class AiToolCall extends LitElement3 {
357
+ constructor() {
358
+ super(...arguments);
359
+ this.id = "";
360
+ this.name = "";
361
+ this.label = "";
362
+ this.kind = "unknown";
363
+ this.effect = "unknown";
364
+ this.headline = "";
365
+ this.subline = "";
366
+ this.status = "unknown";
367
+ this.open = false;
368
+ }
369
+ static styles = css3`
370
+ *,
371
+ *::before,
372
+ *::after {
373
+ box-sizing: border-box;
374
+ }
375
+
376
+ :host {
377
+ display: block;
378
+ margin: 0;
379
+ padding: 0;
380
+ width: 100%;
381
+ max-width: 100%;
382
+ min-width: 0;
383
+ color: var(--ai-tool-call-color, var(--text, var(--ai-color-text, inherit)));
384
+ }
385
+
386
+ .row {
387
+ --accent: color-mix(
388
+ in oklch,
389
+ var(--ai-tool-call-status-color, var(--text-muted, var(--ai-color-text-muted, #888))) 82%,
390
+ var(--ai-tool-call-border-color, var(--border, var(--ai-color-border, #333)))
391
+ );
392
+ --surface-hover: color-mix(in oklch, var(--accent) 8%, transparent);
393
+ --surface-open: color-mix(in oklch, var(--accent) 5%, transparent);
394
+ display: block;
395
+ min-width: 0;
396
+ max-width: 100%;
397
+ background: var(--ai-tool-call-background, var(--background-color, transparent));
398
+ color: inherit;
399
+ }
400
+
401
+ .row[data-tone="read"] {
402
+ --accent: oklch(74% 0.12 190);
403
+ }
404
+ .row[data-tone="write"] {
405
+ --accent: oklch(78% 0.15 145);
406
+ }
407
+ .row[data-tone="edit"] {
408
+ --accent: oklch(76% 0.17 85);
409
+ }
410
+ .row[data-tone="bash"] {
411
+ --accent: oklch(68% 0.19 25);
412
+ }
413
+
414
+ .row[data-status="success"] {
415
+ --accent: var(
416
+ --ai-tool-call-success-color,
417
+ var(--success-color, var(--success, var(--ai-color-success, #16a34a)))
418
+ );
419
+ }
420
+
421
+ .row[data-status="running"],
422
+ .row[data-status="pending"] {
423
+ --accent: var(
424
+ --ai-tool-call-running-color,
425
+ var(--running-color, var(--accent, var(--ai-color-accent, Highlight)))
426
+ );
427
+ }
428
+
429
+ .row[data-status="error"] {
430
+ --accent: var(
431
+ --ai-tool-call-error-color,
432
+ var(--error-color, var(--error, var(--ai-color-error, #dc2626)))
433
+ );
434
+ --surface-hover: color-mix(in oklch, var(--accent) 10%, transparent);
435
+ --surface-open: color-mix(in oklch, var(--accent) 7%, transparent);
436
+ }
437
+
438
+ .row-header {
439
+ display: grid;
440
+ grid-template-columns: minmax(0, 1fr) auto;
441
+ align-items: center;
442
+ gap: calc(var(--spacing-xs, 4px) + 2px);
443
+ padding: 2px 4px;
444
+ background: var(
445
+ --ai-tool-call-summary-background,
446
+ var(--summary-background-color, transparent)
447
+ );
448
+ list-style: none;
449
+ }
450
+
451
+ .row-header[interactive] {
452
+ cursor: pointer;
453
+ transition: background 0.16s ease;
454
+ }
455
+
456
+ .row-header[interactive]:hover {
457
+ background: var(--surface-hover);
458
+ }
459
+
460
+ .row-header[interactive]:focus-visible {
461
+ outline: 2px solid var(--focus, Highlight);
462
+ outline-offset: 2px;
463
+ }
464
+
465
+ details[open] > .row-header {
466
+ background: var(--surface-open);
467
+ }
468
+
469
+ summary.row-header::marker,
470
+ summary.row-header::-webkit-details-marker {
471
+ display: none;
472
+ }
473
+
474
+ .header-content {
475
+ display: flex;
476
+ align-items: center;
477
+ gap: 6px;
478
+ min-width: 0;
479
+ }
480
+
481
+ .icon-frame {
482
+ display: inline-flex;
483
+ align-items: center;
484
+ justify-content: center;
485
+ width: 14px;
486
+ height: 14px;
487
+ flex-shrink: 0;
488
+ color: color-mix(in oklch, var(--accent) 62%, var(--text-muted, currentColor));
489
+ }
490
+
491
+ .icon-frame svg {
492
+ width: 12.5px;
493
+ height: 12.5px;
494
+ stroke: currentColor;
495
+ fill: none;
496
+ stroke-width: 1.8;
497
+ stroke-linecap: round;
498
+ stroke-linejoin: round;
499
+ }
500
+
501
+ .reasoning-dot {
502
+ width: 5px;
503
+ height: 5px;
504
+ border-radius: 999px;
505
+ background: currentColor;
506
+ opacity: 0.72;
507
+ }
508
+
509
+ .text-block {
510
+ display: grid;
511
+ gap: 1px;
512
+ min-width: 0;
513
+ padding-block: 1px;
514
+ }
515
+
516
+ .headline {
517
+ display: flex;
518
+ align-items: baseline;
519
+ gap: 6px;
520
+ flex-wrap: wrap;
521
+ min-width: 0;
522
+ }
523
+
524
+ .badge {
525
+ flex-shrink: 0;
526
+ font-size: var(--font-size-caption, 0.75rem);
527
+ font-weight: var(--font-weight-semibold, 600);
528
+ line-height: var(--line-height-tight, 1.1);
529
+ letter-spacing: var(--tracking-label, 0.04em);
530
+ color: color-mix(in oklch, var(--accent) 52%, var(--text-muted, currentColor));
531
+ }
532
+
533
+ .headline-text {
534
+ min-width: 0;
535
+ font-size: var(--font-size-meta, 0.8125rem);
536
+ line-height: var(--line-height-snug, 1.25);
537
+ color: color-mix(in oklch, var(--text, currentColor) 88%, var(--text-muted, currentColor));
538
+ overflow: hidden;
539
+ text-overflow: ellipsis;
540
+ white-space: normal;
541
+ display: -webkit-box;
542
+ -webkit-box-orient: vertical;
543
+ -webkit-line-clamp: 2;
544
+ }
545
+
546
+ .subline {
547
+ font-size: var(--font-size-caption, 0.75rem);
548
+ line-height: var(--line-height-snug, 1.25);
549
+ color: color-mix(in oklch, var(--text-muted, currentColor) 92%, transparent);
550
+ overflow: hidden;
551
+ text-overflow: ellipsis;
552
+ white-space: nowrap;
553
+ }
554
+
555
+ .row[data-tone="generic"] .badge {
556
+ color: color-mix(in oklch, var(--text-muted, currentColor) 92%, transparent);
557
+ }
558
+
559
+ .row[data-tone="generic"] .headline-text {
560
+ color: color-mix(in oklch, var(--text, currentColor) 78%, var(--text-muted, currentColor));
561
+ }
562
+
563
+ .row[data-tone="read"] .headline-text {
564
+ white-space: nowrap;
565
+ display: block;
566
+ -webkit-line-clamp: unset;
567
+ }
568
+
569
+ .chevron {
570
+ width: 8px;
571
+ height: 8px;
572
+ flex-shrink: 0;
573
+ color: color-mix(in oklch, var(--text-muted, currentColor) 88%, transparent);
574
+ transition: transform 0.16s ease;
575
+ }
576
+
577
+ details[open] .chevron {
578
+ transform: rotate(90deg);
579
+ }
580
+
581
+ .body {
582
+ padding: 1px 4px calc(var(--spacing-xs, 4px) + 1px) 24px;
583
+ }
584
+
585
+ .body::before {
586
+ content: "";
587
+ display: block;
588
+ height: 1px;
589
+ }
590
+
591
+ .body ::slotted(*) {
592
+ display: block;
593
+ min-width: 0;
594
+ }
595
+
596
+ .input-area {
597
+ padding: var(--ai-space-xs, 2px) 4px var(--ai-space-xs, 2px) 24px;
598
+ background: var(--ai-tool-call-input-background, var(--input-background-color, transparent));
599
+ }
600
+
601
+ .input-area ::slotted(*) {
602
+ display: block;
603
+ min-width: 0;
604
+ margin: 0;
605
+ max-width: 100%;
606
+ }
607
+ `;
608
+ hasSlot = new HasSlotController(this, "[default]", "input", "summary");
609
+ get tone() {
610
+ return getToolTone(this.name);
611
+ }
612
+ get badgeText() {
613
+ return this.label || this.name;
614
+ }
615
+ get headlineText() {
616
+ return this.headline || this.label || "";
617
+ }
618
+ get hasBodyContent() {
619
+ return this.hasSlot.test("[default]");
620
+ }
621
+ get hasInputContent() {
622
+ return this.hasSlot.test("input");
623
+ }
624
+ get hasSummaryContent() {
625
+ return this.hasSlot.test("summary");
626
+ }
627
+ get isExpandable() {
628
+ return this.hasBodyContent || this.hasInputContent;
629
+ }
630
+ get hasVisibleHeaderContent() {
631
+ return Boolean(this.badgeText || this.headlineText || this.subline);
632
+ }
633
+ show() {
634
+ this.open = true;
635
+ }
636
+ hide() {
637
+ this.open = false;
638
+ }
639
+ toggle(force) {
640
+ this.open = force ?? !this.open;
641
+ }
642
+ emitToggle(isOpen) {
643
+ this.dispatchEvent(new CustomEvent(isOpen ? "ai-show" : "ai-hide", {
644
+ detail: { source: "tool-call", open: isOpen, id: this.id, name: this.name },
645
+ bubbles: true,
646
+ composed: true
647
+ }));
648
+ }
649
+ handleToggle(e) {
650
+ const details = e.currentTarget;
651
+ const isOpen = details.open;
652
+ if (this.open !== isOpen) {
653
+ this.open = isOpen;
654
+ }
655
+ this.emitToggle(isOpen);
656
+ }
657
+ updated(changed) {
658
+ if (changed.has("open") && changed.get("open") !== undefined) {
659
+ const details = this.renderRoot.querySelector("details");
660
+ if (details && details.open !== this.open) {
661
+ details.open = this.open;
662
+ }
663
+ }
664
+ }
665
+ renderIcon() {
666
+ const tone = this.tone;
667
+ if (tone === "generic") {
668
+ return html3`
669
+ <span class="icon-frame" aria-hidden="true">
670
+ <span class="reasoning-dot"></span>
671
+ </span>
672
+ `;
673
+ }
674
+ return html3`<span class="icon-frame" aria-hidden="true">${renderGlyph(tone)}</span>`;
675
+ }
676
+ renderHeaderContent() {
677
+ return html3`
678
+ <span class="header-content">
679
+ ${this.renderIcon()}
680
+ <span class="text-block">
681
+ <span class="headline">
682
+ ${this.badgeText ? html3`<span class="badge">${this.badgeText}</span>` : nothing2}
683
+ ${this.headlineText && this.headlineText !== this.badgeText ? html3`<span class="headline-text">${this.headlineText}</span>` : nothing2}
684
+ </span>
685
+ ${this.subline ? html3`<span class="subline">${this.subline}</span>` : nothing2}
686
+ </span>
687
+ </span>
688
+ ${this.isExpandable ? html3`
689
+ <svg class="chevron" viewBox="0 0 10 10" aria-hidden="true">
690
+ <path
691
+ d="M3 2.2 6.8 5 3 7.8"
692
+ fill="none"
693
+ stroke="currentColor"
694
+ stroke-width="1.4"
695
+ stroke-linecap="round"
696
+ stroke-linejoin="round"
697
+ ></path>
698
+ </svg>
699
+ ` : nothing2}
700
+ `;
701
+ }
702
+ render() {
703
+ const tone = this.tone;
704
+ const status = this.status;
705
+ if (this.hasSummaryContent) {
706
+ return html3`
707
+ <div class="row" data-tone=${tone} data-status=${status}>
708
+ <slot name="summary"></slot>
709
+ ${this.isExpandable ? html3`
710
+ <div class="body">
711
+ ${this.hasInputContent ? html3`
712
+ <div class="input-area"><slot name="input"></slot></div>
713
+ ` : nothing2}
714
+ <slot></slot>
715
+ </div>
716
+ ` : nothing2}
717
+ </div>
718
+ `;
719
+ }
720
+ if (!this.isExpandable) {
721
+ if (!this.hasVisibleHeaderContent) {
722
+ return nothing2;
723
+ }
724
+ return html3`
725
+ <div class="row" data-tone=${tone} data-status=${status}>
726
+ <div class="row-header">${this.renderHeaderContent()}</div>
727
+ </div>
728
+ `;
729
+ }
730
+ return html3`
731
+ <details
732
+ class="row"
733
+ data-tone=${tone}
734
+ data-status=${status}
735
+ ?open=${this.open}
736
+ @toggle=${this.handleToggle}
737
+ >
738
+ <summary class="row-header" interactive>${this.renderHeaderContent()}</summary>
739
+ ${this.hasInputContent ? html3`
740
+ <div class="input-area"><slot name="input"></slot></div>
741
+ ` : nothing2}
742
+ <div class="body"><slot></slot></div>
743
+ </details>
744
+ `;
745
+ }
746
+ }
747
+ __legacyDecorateClassTS([
748
+ property3({ reflect: true })
749
+ ], AiToolCall.prototype, "id", undefined);
750
+ __legacyDecorateClassTS([
751
+ property3({ reflect: true })
752
+ ], AiToolCall.prototype, "name", undefined);
753
+ __legacyDecorateClassTS([
754
+ property3({ reflect: true })
755
+ ], AiToolCall.prototype, "label", undefined);
756
+ __legacyDecorateClassTS([
757
+ property3({ reflect: true })
758
+ ], AiToolCall.prototype, "kind", undefined);
759
+ __legacyDecorateClassTS([
760
+ property3({ reflect: true })
761
+ ], AiToolCall.prototype, "effect", undefined);
762
+ __legacyDecorateClassTS([
763
+ property3({ reflect: true })
764
+ ], AiToolCall.prototype, "headline", undefined);
765
+ __legacyDecorateClassTS([
766
+ property3({ reflect: true })
767
+ ], AiToolCall.prototype, "subline", undefined);
768
+ __legacyDecorateClassTS([
769
+ property3({ reflect: true })
770
+ ], AiToolCall.prototype, "status", undefined);
771
+ __legacyDecorateClassTS([
772
+ property3({ reflect: true, type: Boolean })
773
+ ], AiToolCall.prototype, "open", undefined);
774
+ AiToolCall = __legacyDecorateClassTS([
775
+ customElement3("ai-tool-call")
776
+ ], AiToolCall);
777
+ // src/semantic/ai-tool-result.ts
778
+ import { LitElement as LitElement4, css as css4, html as html4, nothing as nothing3 } from "lit";
779
+ import { customElement as customElement4, property as property4 } from "lit/decorators.js";
780
+ function isStructuredValue(value) {
781
+ return typeof value === "string" || Array.isArray(value) || Boolean(value) && typeof value === "object";
782
+ }
783
+ function extractFirstStructuredField(record, keys) {
784
+ for (const key of keys) {
785
+ const candidate = record[key];
786
+ if (!isStructuredValue(candidate)) {
787
+ continue;
788
+ }
789
+ const parts = extractStructuredText(candidate);
790
+ if (parts.length > 0) {
791
+ return parts;
792
+ }
793
+ }
794
+ }
795
+ function extractStructuredText(value) {
796
+ if (typeof value === "string") {
797
+ const trimmed = value.trim();
798
+ return trimmed ? [trimmed] : [];
799
+ }
800
+ if (Array.isArray(value)) {
801
+ return value.flatMap((item) => extractStructuredText(item));
802
+ }
803
+ if (value && typeof value === "object") {
804
+ const record = value;
805
+ const extracted = extractFirstStructuredField(record, [
806
+ "text",
807
+ "message",
808
+ "content",
809
+ "result",
810
+ "output",
811
+ "error"
812
+ ]);
813
+ return extracted ?? [JSON.stringify(value, undefined, 2)];
814
+ }
815
+ if (value === null || value === undefined) {
816
+ return [];
817
+ }
818
+ return [String(value)];
819
+ }
820
+ function normalizeToolOutput(content) {
821
+ const trimmed = content.trim();
822
+ if (!trimmed) {
823
+ return "";
824
+ }
825
+ try {
826
+ const parsed = JSON.parse(trimmed);
827
+ const lines = extractStructuredText(parsed).filter(Boolean);
828
+ if (lines.length > 0) {
829
+ return lines.join(`
830
+
831
+ `);
832
+ }
833
+ } catch {}
834
+ return trimmed;
835
+ }
836
+
837
+ class AiToolResult extends LitElement4 {
838
+ constructor() {
839
+ super(...arguments);
840
+ this.htmlFor = "";
841
+ this.name = "";
842
+ this.status = "unknown";
843
+ this.channel = "unknown";
844
+ this.contentType = "text/plain";
845
+ this.content = "";
846
+ this.truncated = false;
847
+ }
848
+ hasSlot = new HasSlotController(this, "[default]", "meta");
849
+ static styles = css4`
850
+ :host {
851
+ box-sizing: border-box;
852
+ display: block;
853
+ margin: 0;
854
+ padding: 0;
855
+ min-width: 0;
856
+ max-width: 100%;
857
+ background: var(--ai-tool-result-background, transparent);
858
+ color: var(--ai-tool-result-color, var(--text, var(--ai-color-text, inherit)));
859
+ }
860
+
861
+ *,
862
+ *::before,
863
+ *::after {
864
+ box-sizing: inherit;
865
+ }
866
+
867
+ .container {
868
+ display: flex;
869
+ flex-direction: column;
870
+ gap: var(--ai-space-sm, 8px);
871
+ min-width: 0;
872
+ max-width: 100%;
873
+ }
874
+
875
+ .meta {
876
+ display: flex;
877
+ align-items: center;
878
+ gap: var(--ai-space-xs, 4px);
879
+ color: var(--ai-tool-result-meta-color, var(--text-muted, var(--ai-color-text-muted, #888)));
880
+ font-size: var(--font-size-caption, var(--ai-font-size-xs, 0.75rem));
881
+ }
882
+
883
+ .content {
884
+ min-width: 0;
885
+ max-width: 100%;
886
+ color: var(--ai-tool-result-color, var(--text, var(--ai-color-text, inherit)));
887
+ }
888
+
889
+ pre {
890
+ margin: 0;
891
+ max-width: 100%;
892
+ max-height: var(--ai-tool-result-max-height, 240px);
893
+ overflow-x: auto;
894
+ overflow-y: auto;
895
+ -webkit-overflow-scrolling: touch;
896
+ color: var(
897
+ --ai-tool-result-code-color,
898
+ color-mix(in oklch, var(--text, currentColor) 82%, var(--text-muted, currentColor))
899
+ );
900
+ font-family: var(--ai-tool-result-code-font, var(--font-family-mono, monospace));
901
+ font-size: var(--font-size-caption, 0.75rem);
902
+ line-height: var(--line-height-body, 1.5);
903
+ white-space: pre-wrap;
904
+ word-break: break-word;
905
+ }
906
+
907
+ :host([channel="stderr"]) .content,
908
+ :host([status="error"]) .content {
909
+ color: var(--ai-tool-result-error-color, var(--error, var(--ai-color-error, #dc2626)));
910
+ }
911
+
912
+ :host([channel="log"]) .content {
913
+ color: var(--ai-tool-result-meta-color, var(--text-muted, var(--ai-color-text-muted, #888)));
914
+ }
915
+
916
+ .truncation-indicator::after {
917
+ content: " (truncated)";
918
+ color: var(--ai-tool-result-meta-color, var(--text-muted, var(--ai-color-text-muted, #888)));
919
+ font-style: italic;
920
+ }
921
+ `;
922
+ get hasDefaultContent() {
923
+ return this.hasSlot.test("[default]");
924
+ }
925
+ get hasMetaContent() {
926
+ return this.hasSlot.test("meta");
927
+ }
928
+ render() {
929
+ const body = normalizeToolOutput(this.content);
930
+ return html4`
931
+ <div class="container">
932
+ ${this.hasMetaContent ? html4`
933
+ <div class="meta"><slot name="meta"></slot></div>
934
+ ` : nothing3}
935
+ <div class="content ${this.truncated ? "truncation-indicator" : ""}">
936
+ ${this.hasDefaultContent ? html4`
937
+ <slot></slot>
938
+ ` : body ? html4`<pre>${body}</pre>` : nothing3}
939
+ </div>
940
+ </div>
941
+ `;
942
+ }
943
+ }
944
+ __legacyDecorateClassTS([
945
+ property4({ reflect: true, attribute: "for" })
946
+ ], AiToolResult.prototype, "htmlFor", undefined);
947
+ __legacyDecorateClassTS([
948
+ property4({ reflect: true })
949
+ ], AiToolResult.prototype, "name", undefined);
950
+ __legacyDecorateClassTS([
951
+ property4({ reflect: true })
952
+ ], AiToolResult.prototype, "status", undefined);
953
+ __legacyDecorateClassTS([
954
+ property4({ reflect: true })
955
+ ], AiToolResult.prototype, "channel", undefined);
956
+ __legacyDecorateClassTS([
957
+ property4({ reflect: true, attribute: "content-type" })
958
+ ], AiToolResult.prototype, "contentType", undefined);
959
+ __legacyDecorateClassTS([
960
+ property4({ type: String })
961
+ ], AiToolResult.prototype, "content", undefined);
962
+ __legacyDecorateClassTS([
963
+ property4({ reflect: true, type: Boolean })
964
+ ], AiToolResult.prototype, "truncated", undefined);
965
+ AiToolResult = __legacyDecorateClassTS([
966
+ customElement4("ai-tool-result")
967
+ ], AiToolResult);
968
+ // src/semantic/ai-thinking.ts
969
+ import { LitElement as LitElement5, css as css5, html as html5 } from "lit";
970
+ import { customElement as customElement5, property as property5 } from "lit/decorators.js";
971
+ function summarizeThinking(content) {
972
+ const normalized = content.replace(/\s+/g, " ").trim();
973
+ if (!normalized) {
974
+ return "Reasoning";
975
+ }
976
+ const sentence = normalized.match(/.*?[.!?](?:\s|$)/)?.[0]?.trim() ?? normalized;
977
+ if (sentence.length <= 88) {
978
+ return sentence;
979
+ }
980
+ return `${sentence.slice(0, 85).trimEnd()}…`;
981
+ }
982
+
983
+ class AiThinking extends LitElement5 {
984
+ constructor() {
985
+ super(...arguments);
986
+ this.content = "";
987
+ this.source = "unknown";
988
+ this.redacted = false;
989
+ this.open = false;
990
+ this.headline = "";
991
+ }
992
+ static styles = css5`
993
+ *,
994
+ *::before,
995
+ *::after {
996
+ box-sizing: border-box;
997
+ }
998
+
999
+ :host {
1000
+ display: block;
1001
+ margin: 0;
1002
+ padding: 0;
1003
+ width: 100%;
1004
+ max-width: 100%;
1005
+ min-width: 0;
1006
+ color: var(
1007
+ --ai-thinking-color,
1008
+ color-mix(in oklch, var(--text-muted, currentColor) 90%, transparent)
1009
+ );
1010
+ }
1011
+
1012
+ .thinking-content {
1013
+ color: var(
1014
+ --ai-thinking-color,
1015
+ color-mix(in oklch, var(--text-muted, currentColor) 90%, transparent)
1016
+ );
1017
+ font-size: var(--font-size-caption, 0.75rem);
1018
+ line-height: var(--line-height-body, 1.5);
1019
+ white-space: pre-wrap;
1020
+ word-break: break-word;
1021
+ max-height: var(--ai-thinking-max-height, 140px);
1022
+ overflow-x: auto;
1023
+ overflow-y: auto;
1024
+ -webkit-overflow-scrolling: touch;
1025
+ }
1026
+
1027
+ .redacted {
1028
+ display: flex;
1029
+ align-items: center;
1030
+ gap: 6px;
1031
+ padding: 2px 4px;
1032
+ color: var(--ai-thinking-muted-color, var(--text-muted, var(--ai-color-text-muted, #888)));
1033
+ font-size: var(--font-size-caption, 0.75rem);
1034
+ line-height: var(--line-height-snug, 1.25);
1035
+ font-style: italic;
1036
+ }
1037
+ `;
1038
+ show() {
1039
+ if (this.redacted) {
1040
+ return;
1041
+ }
1042
+ this.open = true;
1043
+ }
1044
+ hide() {
1045
+ if (this.redacted) {
1046
+ return;
1047
+ }
1048
+ this.open = false;
1049
+ }
1050
+ toggle(force) {
1051
+ if (this.redacted) {
1052
+ return;
1053
+ }
1054
+ this.open = force ?? !this.open;
1055
+ }
1056
+ handleShow() {
1057
+ if (this.redacted) {
1058
+ return;
1059
+ }
1060
+ this.open = true;
1061
+ this.dispatchEvent(new CustomEvent("ai-show", {
1062
+ detail: { source: "thinking", redacted: this.redacted },
1063
+ bubbles: true,
1064
+ composed: true
1065
+ }));
1066
+ }
1067
+ handleHide() {
1068
+ if (this.redacted) {
1069
+ return;
1070
+ }
1071
+ this.open = false;
1072
+ this.dispatchEvent(new CustomEvent("ai-hide", {
1073
+ detail: { source: "thinking", redacted: this.redacted },
1074
+ bubbles: true,
1075
+ composed: true
1076
+ }));
1077
+ }
1078
+ updated(changed) {
1079
+ if (changed.has("redacted") && this.redacted && this.open) {
1080
+ this.open = false;
1081
+ }
1082
+ }
1083
+ render() {
1084
+ if (this.redacted) {
1085
+ return html5`
1086
+ <div class="redacted">Reasoning redacted<slot name="meta"></slot></div>
1087
+ `;
1088
+ }
1089
+ const content = this.content.trim();
1090
+ if (!content) {
1091
+ return html5`
1092
+ <slot></slot>
1093
+ `;
1094
+ }
1095
+ return html5`
1096
+ <ai-tool-call
1097
+ name="Reasoning"
1098
+ .headline=${this.headline || summarizeThinking(content)}
1099
+ .open=${this.open}
1100
+ @ai-show=${this.handleShow}
1101
+ @ai-hide=${this.handleHide}
1102
+ >
1103
+ <div class="thinking-content">${content}</div>
1104
+ <slot name="meta"></slot>
1105
+ </ai-tool-call>
1106
+ `;
1107
+ }
1108
+ }
1109
+ __legacyDecorateClassTS([
1110
+ property5({ type: String })
1111
+ ], AiThinking.prototype, "content", undefined);
1112
+ __legacyDecorateClassTS([
1113
+ property5({ reflect: true })
1114
+ ], AiThinking.prototype, "source", undefined);
1115
+ __legacyDecorateClassTS([
1116
+ property5({ reflect: true, type: Boolean })
1117
+ ], AiThinking.prototype, "redacted", undefined);
1118
+ __legacyDecorateClassTS([
1119
+ property5({ reflect: true, type: Boolean })
1120
+ ], AiThinking.prototype, "open", undefined);
1121
+ __legacyDecorateClassTS([
1122
+ property5({ reflect: true })
1123
+ ], AiThinking.prototype, "headline", undefined);
1124
+ AiThinking = __legacyDecorateClassTS([
1125
+ customElement5("ai-thinking")
1126
+ ], AiThinking);
1127
+ // src/semantic/ai-event.ts
1128
+ import { LitElement as LitElement6, css as css6, html as html6 } from "lit";
1129
+ import { customElement as customElement6, property as property6, query } from "lit/decorators.js";
1130
+ var KIND_LABELS = {
1131
+ status: "Status",
1132
+ "model-change": "Model Change",
1133
+ checkpoint: "Checkpoint",
1134
+ note: "Note",
1135
+ system: "System",
1136
+ error: "Error",
1137
+ custom: "Event"
1138
+ };
1139
+ var SEVERITY_COLORS = {
1140
+ info: "var(--ai-event-info-color, var(--ai-event-info, var(--ai-color-info, #3b82f6)))",
1141
+ warning: "var(--ai-event-warning-color, var(--ai-event-warning, var(--ai-color-warning, #f59e0b)))",
1142
+ error: "var(--ai-event-error-color, var(--ai-event-error, var(--ai-color-error, #ef4444)))"
1143
+ };
1144
+
1145
+ class AiEvent extends LitElement6 {
1146
+ constructor() {
1147
+ super(...arguments);
1148
+ this.kind = "custom";
1149
+ this.severity = "info";
1150
+ this.source = "";
1151
+ this.htmlFor = "";
1152
+ this.open = false;
1153
+ }
1154
+ show() {
1155
+ this.open = true;
1156
+ }
1157
+ hide() {
1158
+ this.open = false;
1159
+ }
1160
+ toggle(force) {
1161
+ this.open = force !== undefined ? force : !this.open;
1162
+ }
1163
+ _prevOpen = false;
1164
+ updated() {
1165
+ if (this._details && this._details.open !== this.open) {
1166
+ this._details.open = this.open;
1167
+ }
1168
+ if (this._prevOpen !== this.open) {
1169
+ this._prevOpen = this.open;
1170
+ this.dispatchEvent(new CustomEvent(this.open ? "ai-show" : "ai-hide", {
1171
+ detail: { source: "event", kind: this.kind },
1172
+ bubbles: true,
1173
+ composed: true
1174
+ }));
1175
+ }
1176
+ }
1177
+ _onToggle() {
1178
+ const details = this._details;
1179
+ if (!details) {
1180
+ return;
1181
+ }
1182
+ this.open = details.open;
1183
+ }
1184
+ get _severityColor() {
1185
+ return SEVERITY_COLORS[this.severity] ?? SEVERITY_COLORS.info ?? "#888";
1186
+ }
1187
+ get _kindLabel() {
1188
+ return KIND_LABELS[this.kind] ?? KIND_LABELS.custom ?? "Custom";
1189
+ }
1190
+ render() {
1191
+ const accentColor = this._severityColor;
1192
+ return html6`
1193
+ <details
1194
+ .open=${this.open}
1195
+ @toggle=${this._onToggle}
1196
+ part="details"
1197
+ style="--_accent: ${accentColor}"
1198
+ >
1199
+ <summary part="summary">
1200
+ <span class="summary-text" part="summary-text">
1201
+ <slot name="summary">
1202
+ <span class="kind-label" part="kind-label">${this._kindLabel}</span>
1203
+ </slot>
1204
+ </span>
1205
+ <span class="summary-rule" aria-hidden="true"></span>
1206
+ <span class="summary-meta" part="meta">
1207
+ <slot name="meta"></slot>
1208
+ </span>
1209
+ <span class="chevron" part="marker" aria-hidden="true">
1210
+ <svg viewBox="0 0 10 10" focusable="false">
1211
+ <path d="M3.25 2.25 6.25 5 3.25 7.75"></path>
1212
+ </svg>
1213
+ </span>
1214
+ </summary>
1215
+
1216
+ <div class="content-shell" part="content-shell">
1217
+ <div class="content" part="content">
1218
+ <slot></slot>
1219
+ </div>
1220
+ </div>
1221
+ </details>
1222
+ `;
1223
+ }
1224
+ static styles = css6`
1225
+ :host {
1226
+ box-sizing: border-box;
1227
+ display: block;
1228
+ width: 100%;
1229
+ max-width: 100%;
1230
+ min-width: 0;
1231
+ margin: 0;
1232
+ padding: 0;
1233
+ color: var(--ai-event-color, var(--ai-event-text-color, var(--text-muted, #8d867a)));
1234
+ }
1235
+
1236
+ *,
1237
+ *::before,
1238
+ *::after {
1239
+ box-sizing: inherit;
1240
+ }
1241
+
1242
+ details {
1243
+ display: block;
1244
+ min-width: 0;
1245
+ max-width: 100%;
1246
+ margin: 0;
1247
+ background: var(--ai-event-background, var(--ai-event-background-color, transparent));
1248
+ border: var(--ai-event-border-width, 0) solid
1249
+ var(--ai-event-border-color, var(--ai-color-border, transparent));
1250
+ border-radius: var(--ai-event-radius, var(--ai-event-border-radius, 0));
1251
+ }
1252
+
1253
+ summary {
1254
+ display: grid;
1255
+ grid-template-columns: auto minmax(24px, 1fr) auto 12px;
1256
+ align-items: center;
1257
+ column-gap: 8px;
1258
+ min-width: 0;
1259
+ list-style: none;
1260
+ cursor: pointer;
1261
+ color: var(
1262
+ --ai-event-summary-color,
1263
+ color-mix(in oklch, var(--text-muted, currentColor) 82%, var(--text, currentColor))
1264
+ );
1265
+ padding: 3px 4px;
1266
+ border-radius: var(--radius-sm, 5px);
1267
+ background: transparent;
1268
+ user-select: none;
1269
+ transition:
1270
+ background 0.16s ease,
1271
+ color 0.16s ease;
1272
+ }
1273
+
1274
+ summary:hover {
1275
+ background: color-mix(in oklch, var(--_accent) 5%, transparent);
1276
+ color: color-mix(in oklch, var(--text, currentColor) 72%, var(--text-muted, currentColor));
1277
+ }
1278
+
1279
+ summary:focus-visible {
1280
+ outline: 2px solid var(--focus, var(--_accent));
1281
+ outline-offset: 2px;
1282
+ }
1283
+
1284
+ details[open] > summary {
1285
+ color: color-mix(in oklch, var(--text, currentColor) 76%, var(--text-muted, currentColor));
1286
+ }
1287
+
1288
+ summary::marker,
1289
+ summary::-webkit-details-marker {
1290
+ display: none;
1291
+ }
1292
+
1293
+ .summary-text {
1294
+ min-width: 0;
1295
+ overflow: hidden;
1296
+ text-overflow: ellipsis;
1297
+ white-space: nowrap;
1298
+ font-size: var(--font-size-caption, 0.75rem);
1299
+ font-weight: var(--font-weight-semibold, 600);
1300
+ letter-spacing: var(--tracking-label, 0.04em);
1301
+ line-height: var(--line-height-tight, 1.1);
1302
+ text-transform: uppercase;
1303
+ }
1304
+
1305
+ .summary-rule {
1306
+ min-width: 24px;
1307
+ height: 1px;
1308
+ background: var(
1309
+ --ai-event-rule-color,
1310
+ color-mix(in oklch, var(--text-muted, currentColor) 16%, transparent)
1311
+ );
1312
+ }
1313
+
1314
+ details[open] .summary-rule {
1315
+ background: var(
1316
+ --ai-event-open-rule-color,
1317
+ color-mix(in oklch, var(--text-muted, currentColor) 24%, transparent)
1318
+ );
1319
+ }
1320
+
1321
+ .kind-label {
1322
+ color: inherit;
1323
+ font-weight: inherit;
1324
+ }
1325
+
1326
+ .summary-meta {
1327
+ display: inline-flex;
1328
+ align-items: baseline;
1329
+ justify-content: flex-end;
1330
+ min-width: 0;
1331
+ max-width: min(46vw, 360px);
1332
+ color: var(
1333
+ --ai-event-meta-color,
1334
+ var(--ai-event-meta, color-mix(in oklch, var(--text-muted, currentColor) 76%, transparent))
1335
+ );
1336
+ font-size: var(--font-size-caption, 0.75rem);
1337
+ line-height: var(--line-height-tight, 1.1);
1338
+ white-space: nowrap;
1339
+ overflow: hidden;
1340
+ text-overflow: ellipsis;
1341
+ }
1342
+
1343
+ .chevron {
1344
+ display: inline-flex;
1345
+ align-items: center;
1346
+ justify-content: center;
1347
+ width: 12px;
1348
+ height: 16px;
1349
+ justify-self: end;
1350
+ color: color-mix(in oklch, var(--text-muted, currentColor) 88%, transparent);
1351
+ }
1352
+
1353
+ .chevron svg {
1354
+ width: 10px;
1355
+ height: 10px;
1356
+ stroke: currentColor;
1357
+ fill: none;
1358
+ stroke-width: 1.8;
1359
+ stroke-linecap: round;
1360
+ stroke-linejoin: round;
1361
+ transition: transform 0.16s ease;
1362
+ }
1363
+
1364
+ details[open] .chevron svg {
1365
+ transform: rotate(90deg);
1366
+ }
1367
+
1368
+ .content-shell {
1369
+ margin: 2px 0 1px;
1370
+ padding: 6px 4px 3px var(--ai-event-content-indent, clamp(20px, 7vw, 58px));
1371
+ }
1372
+
1373
+ .content {
1374
+ display: block;
1375
+ min-width: 0;
1376
+ max-width: 100%;
1377
+ color: var(
1378
+ --ai-event-content-color,
1379
+ color-mix(in oklch, var(--text, currentColor) 82%, var(--text-muted, currentColor))
1380
+ );
1381
+ font-size: var(--font-size-meta, 0.8125rem);
1382
+ line-height: var(--line-height-relaxed, 1.45);
1383
+ }
1384
+
1385
+ .content ::slotted(*) {
1386
+ max-width: 100%;
1387
+ }
1388
+
1389
+ .content ::slotted(:first-child) {
1390
+ margin-top: 0;
1391
+ }
1392
+
1393
+ .content ::slotted(:last-child) {
1394
+ margin-bottom: 0;
1395
+ }
1396
+
1397
+ .content ::slotted(pre) {
1398
+ overflow-x: auto;
1399
+ padding: 8px 10px;
1400
+ border-radius: var(--radius-sm, 5px);
1401
+ background: color-mix(in oklch, var(--text, currentColor) 5%, transparent);
1402
+ font-size: var(--font-size-caption, 0.75rem);
1403
+ line-height: var(--line-height-snug, 1.25);
1404
+ }
1405
+
1406
+ .content ::slotted(code) {
1407
+ border-radius: 4px;
1408
+ padding: 0.08em 0.35em;
1409
+ background: color-mix(in oklch, var(--text, currentColor) 7%, transparent);
1410
+ color: color-mix(in oklch, var(--text, currentColor) 88%, var(--_accent));
1411
+ font-size: 0.94em;
1412
+ }
1413
+
1414
+ :host([severity="warning"]) .summary-text {
1415
+ color: color-mix(in oklch, var(--_accent) 44%, var(--text, currentColor));
1416
+ }
1417
+
1418
+ :host([severity="warning"]) .summary-rule {
1419
+ background: color-mix(in oklch, var(--_accent) 24%, transparent);
1420
+ }
1421
+
1422
+ :host([severity="error"]) .summary-text {
1423
+ color: color-mix(in oklch, var(--_accent) 52%, var(--text, currentColor));
1424
+ }
1425
+
1426
+ :host([severity="error"]) .summary-rule {
1427
+ background: color-mix(in oklch, var(--_accent) 30%, transparent);
1428
+ }
1429
+
1430
+ :host([severity="error"]) summary:hover {
1431
+ background: color-mix(in oklch, var(--_accent) 9%, transparent);
1432
+ }
1433
+
1434
+ @media (max-width: 520px) {
1435
+ summary {
1436
+ grid-template-columns: auto minmax(16px, 1fr) 12px;
1437
+ padding-right: 4px;
1438
+ }
1439
+
1440
+ .summary-meta {
1441
+ grid-column: 1 / 3;
1442
+ grid-row: 2;
1443
+ justify-content: flex-start;
1444
+ max-width: 100%;
1445
+ margin-top: 1px;
1446
+ }
1447
+
1448
+ .chevron {
1449
+ grid-column: 3;
1450
+ grid-row: 1 / span 2;
1451
+ }
1452
+
1453
+ .content-shell {
1454
+ padding-left: 18px;
1455
+ }
1456
+ }
1457
+ `;
1458
+ }
1459
+ __legacyDecorateClassTS([
1460
+ property6({ reflect: true })
1461
+ ], AiEvent.prototype, "kind", undefined);
1462
+ __legacyDecorateClassTS([
1463
+ property6({ reflect: true })
1464
+ ], AiEvent.prototype, "severity", undefined);
1465
+ __legacyDecorateClassTS([
1466
+ property6({ reflect: true })
1467
+ ], AiEvent.prototype, "source", undefined);
1468
+ __legacyDecorateClassTS([
1469
+ property6({ reflect: true, attribute: "for" })
1470
+ ], AiEvent.prototype, "htmlFor", undefined);
1471
+ __legacyDecorateClassTS([
1472
+ property6({ reflect: true, type: Boolean })
1473
+ ], AiEvent.prototype, "open", undefined);
1474
+ __legacyDecorateClassTS([
1475
+ query("details")
1476
+ ], AiEvent.prototype, "_details", undefined);
1477
+ AiEvent = __legacyDecorateClassTS([
1478
+ customElement6("ai-event")
1479
+ ], AiEvent);
1480
+ // src/visual/stack.ts
1481
+ import { LitElement as LitElement7, css as css7, html as html7 } from "lit";
1482
+ import { customElement as customElement7, property as property7 } from "lit/decorators.js";
1483
+ var GAP_MAP = {
1484
+ none: "0",
1485
+ "2xs": "0.125rem",
1486
+ xs: "0.25rem",
1487
+ sm: "0.5rem",
1488
+ md: "0.75rem",
1489
+ lg: "1rem",
1490
+ xl: "1.5rem",
1491
+ "2xl": "2rem"
1492
+ };
1493
+ var JUSTIFY_MAP = {
1494
+ start: "flex-start",
1495
+ center: "center",
1496
+ end: "flex-end",
1497
+ between: "space-between",
1498
+ around: "space-around",
1499
+ evenly: "space-evenly"
1500
+ };
1501
+
1502
+ class AiStack extends LitElement7 {
1503
+ constructor() {
1504
+ super(...arguments);
1505
+ this.direction = "column";
1506
+ this.gap = "none";
1507
+ this.align = "stretch";
1508
+ this.justify = "start";
1509
+ this.wrap = false;
1510
+ this.inline = false;
1511
+ }
1512
+ static styles = css7`
1513
+ :host {
1514
+ box-sizing: border-box;
1515
+ display: flex;
1516
+ flex-direction: column;
1517
+ gap: var(--gap, 0);
1518
+ align-items: var(--align-items, stretch);
1519
+ justify-content: var(--justify-content, flex-start);
1520
+ margin: 0;
1521
+ padding: 0;
1522
+ }
1523
+
1524
+ :host([inline]) {
1525
+ display: inline-flex;
1526
+ }
1527
+
1528
+ :host([direction="row"]) {
1529
+ flex-direction: row;
1530
+ }
1531
+
1532
+ :host([wrap]) {
1533
+ flex-wrap: wrap;
1534
+ }
1535
+
1536
+ *,
1537
+ *::before,
1538
+ *::after {
1539
+ box-sizing: inherit;
1540
+ }
1541
+ `;
1542
+ render() {
1543
+ return html7`
1544
+ <slot></slot>
1545
+ `;
1546
+ }
1547
+ updated() {
1548
+ const gap = GAP_MAP[this.gap] ?? "0";
1549
+ this.style.setProperty("--gap", `var(--gap, ${gap})`);
1550
+ const alignItems = this.align;
1551
+ this.style.setProperty("--align-items", `var(--align-items, ${alignItems})`);
1552
+ const justifyContent = JUSTIFY_MAP[this.justify] ?? "flex-start";
1553
+ this.style.setProperty("--justify-content", `var(--justify-content, ${justifyContent})`);
1554
+ this.style.direction;
1555
+ this.style.gap = `var(--gap, ${gap})`;
1556
+ this.style.alignItems = `var(--align-items, ${alignItems})`;
1557
+ this.style.justifyContent = `var(--justify-content, ${justifyContent})`;
1558
+ }
1559
+ }
1560
+ __legacyDecorateClassTS([
1561
+ property7({ reflect: true })
1562
+ ], AiStack.prototype, "direction", undefined);
1563
+ __legacyDecorateClassTS([
1564
+ property7({ reflect: true })
1565
+ ], AiStack.prototype, "gap", undefined);
1566
+ __legacyDecorateClassTS([
1567
+ property7({ reflect: true })
1568
+ ], AiStack.prototype, "align", undefined);
1569
+ __legacyDecorateClassTS([
1570
+ property7({ reflect: true })
1571
+ ], AiStack.prototype, "justify", undefined);
1572
+ __legacyDecorateClassTS([
1573
+ property7({ reflect: true, type: Boolean })
1574
+ ], AiStack.prototype, "wrap", undefined);
1575
+ __legacyDecorateClassTS([
1576
+ property7({ reflect: true, type: Boolean })
1577
+ ], AiStack.prototype, "inline", undefined);
1578
+ AiStack = __legacyDecorateClassTS([
1579
+ customElement7("ai-stack")
1580
+ ], AiStack);
1581
+ // src/visual/surface.ts
1582
+ import { LitElement as LitElement8, css as css8, html as html8 } from "lit";
1583
+ import { customElement as customElement8, property as property8 } from "lit/decorators.js";
1584
+ var RADIUS_MAP = {
1585
+ none: "0",
1586
+ sm: "0.375rem",
1587
+ md: "0.625rem",
1588
+ lg: "0.875rem",
1589
+ pill: "999px"
1590
+ };
1591
+
1592
+ class AiSurface extends LitElement8 {
1593
+ constructor() {
1594
+ super(...arguments);
1595
+ this.variant = "flat";
1596
+ this.tone = "neutral";
1597
+ this.radius = "md";
1598
+ this.interactive = false;
1599
+ }
1600
+ static styles = css8`
1601
+ :host {
1602
+ box-sizing: border-box;
1603
+ display: block;
1604
+ margin: 0;
1605
+ padding: 0;
1606
+ border-radius: var(--border-radius, 0.625rem);
1607
+ background: var(--background-color, transparent);
1608
+ color: var(--text-color, inherit);
1609
+ }
1610
+
1611
+ :host([variant="outlined"]) {
1612
+ border: var(--border-width, 1px) solid
1613
+ var(--border-color, var(--ai-color-border, rgba(128, 128, 128, 0.2)));
1614
+ }
1615
+
1616
+ :host([variant="raised"]) {
1617
+ box-shadow: var(--shadow, 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.08));
1618
+ }
1619
+
1620
+ :host([variant="sunken"]) {
1621
+ box-shadow: var(--shadow, inset 0 1px 3px rgba(0, 0, 0, 0.12));
1622
+ }
1623
+
1624
+ :host([interactive]) {
1625
+ cursor: pointer;
1626
+ transition: background 0.15s ease;
1627
+ }
1628
+
1629
+ :host([interactive]:hover) {
1630
+ background: var(--hover-background-color, var(--background-color, rgba(128, 128, 128, 0.05)));
1631
+ }
1632
+
1633
+ :host([interactive]:focus-visible) {
1634
+ outline: var(--focus-ring, 2px solid var(--ai-color-accent, #4a90d9));
1635
+ outline-offset: 2px;
1636
+ }
1637
+
1638
+ *,
1639
+ *::before,
1640
+ *::after {
1641
+ box-sizing: inherit;
1642
+ }
1643
+ `;
1644
+ render() {
1645
+ return html8`
1646
+ <slot></slot>
1647
+ `;
1648
+ }
1649
+ updated() {
1650
+ const radius = RADIUS_MAP[this.radius] ?? "0.625rem";
1651
+ this.style.setProperty("--border-radius", `var(--border-radius, ${radius})`);
1652
+ const toneColors = this.getToneColors();
1653
+ this.style.setProperty("--background-color", `var(--background-color, ${toneColors.bg})`);
1654
+ this.style.setProperty("--text-color", `var(--text-color, ${toneColors.text})`);
1655
+ this.style.setProperty("--border-color", `var(--border-color, ${toneColors.border})`);
1656
+ }
1657
+ getToneColors() {
1658
+ switch (this.tone) {
1659
+ case "accent":
1660
+ return {
1661
+ bg: "rgba(74, 144, 217, 0.1)",
1662
+ text: "var(--ai-color-accent, #4a90d9)",
1663
+ border: "rgba(74, 144, 217, 0.3)"
1664
+ };
1665
+ case "success":
1666
+ return {
1667
+ bg: "rgba(46, 160, 67, 0.1)",
1668
+ text: "var(--ai-color-success, #2ea043)",
1669
+ border: "rgba(46, 160, 67, 0.3)"
1670
+ };
1671
+ case "warning":
1672
+ return {
1673
+ bg: "rgba(210, 153, 34, 0.1)",
1674
+ text: "var(--ai-color-warning, #d29922)",
1675
+ border: "rgba(210, 153, 34, 0.3)"
1676
+ };
1677
+ case "error":
1678
+ return {
1679
+ bg: "rgba(227, 62, 51, 0.1)",
1680
+ text: "var(--ai-color-error, #e33e33)",
1681
+ border: "rgba(227, 62, 51, 0.3)"
1682
+ };
1683
+ case "info":
1684
+ return {
1685
+ bg: "rgba(80, 160, 220, 0.1)",
1686
+ text: "var(--ai-color-info, #50a0dc)",
1687
+ border: "rgba(80, 160, 220, 0.3)"
1688
+ };
1689
+ default:
1690
+ return {
1691
+ bg: "transparent",
1692
+ text: "inherit",
1693
+ border: "var(--ai-color-border, rgba(128, 128, 128, 0.2))"
1694
+ };
1695
+ }
1696
+ }
1697
+ }
1698
+ __legacyDecorateClassTS([
1699
+ property8({ reflect: true })
1700
+ ], AiSurface.prototype, "variant", undefined);
1701
+ __legacyDecorateClassTS([
1702
+ property8({ reflect: true })
1703
+ ], AiSurface.prototype, "tone", undefined);
1704
+ __legacyDecorateClassTS([
1705
+ property8({ reflect: true })
1706
+ ], AiSurface.prototype, "radius", undefined);
1707
+ __legacyDecorateClassTS([
1708
+ property8({ reflect: true, type: Boolean })
1709
+ ], AiSurface.prototype, "interactive", undefined);
1710
+ AiSurface = __legacyDecorateClassTS([
1711
+ customElement8("ai-surface")
1712
+ ], AiSurface);
1713
+ // src/visual/text.ts
1714
+ import { LitElement as LitElement9, css as css9, html as html9 } from "lit";
1715
+ import { customElement as customElement9, property as property9 } from "lit/decorators.js";
1716
+ var SIZE_MAP = {
1717
+ caption: "0.75rem",
1718
+ meta: "0.8125rem",
1719
+ ui: "0.875rem",
1720
+ body: "1rem",
1721
+ title: "1.125rem",
1722
+ display: "1.375rem"
1723
+ };
1724
+ var WEIGHT_MAP = {
1725
+ normal: 400,
1726
+ medium: 500,
1727
+ semibold: 600,
1728
+ bold: 700
1729
+ };
1730
+
1731
+ class AiText extends LitElement9 {
1732
+ constructor() {
1733
+ super(...arguments);
1734
+ this.size = "body";
1735
+ this.weight = "normal";
1736
+ this.tone = "default";
1737
+ this.mono = false;
1738
+ this.truncate = false;
1739
+ this.inline = false;
1740
+ }
1741
+ static styles = css9`
1742
+ :host {
1743
+ box-sizing: border-box;
1744
+ display: block;
1745
+ margin: 0;
1746
+ padding: 0;
1747
+ font-size: var(--font-size, 1rem);
1748
+ font-weight: var(--font-weight, 400);
1749
+ line-height: var(--line-height, 1.5);
1750
+ letter-spacing: var(--letter-spacing, normal);
1751
+ color: var(--text-color, inherit);
1752
+ }
1753
+
1754
+ :host([inline]) {
1755
+ display: inline-flex;
1756
+ }
1757
+
1758
+ :host([mono]) {
1759
+ font-family: var(
1760
+ --font-family-mono,
1761
+ ui-monospace,
1762
+ "Cascadia Code",
1763
+ "Source Code Pro",
1764
+ Menlo,
1765
+ Consolas,
1766
+ "DejaVu Sans Mono",
1767
+ monospace
1768
+ );
1769
+ }
1770
+
1771
+ :host(:not([mono])) {
1772
+ font-family: var(--font-family, inherit);
1773
+ }
1774
+
1775
+ :host([truncate]) {
1776
+ text-overflow: ellipsis;
1777
+ overflow: hidden;
1778
+ white-space: nowrap;
1779
+ }
1780
+
1781
+ *,
1782
+ *::before,
1783
+ *::after {
1784
+ box-sizing: inherit;
1785
+ }
1786
+ `;
1787
+ render() {
1788
+ return html9`
1789
+ <slot></slot>
1790
+ `;
1791
+ }
1792
+ updated() {
1793
+ const size = SIZE_MAP[this.size] ?? "1rem";
1794
+ const weight = WEIGHT_MAP[this.weight] ?? 400;
1795
+ this.style.setProperty("--font-size", `var(--font-size, ${size})`);
1796
+ this.style.setProperty("--font-weight", `var(--font-weight, ${weight})`);
1797
+ const toneColor = this.getToneColor();
1798
+ this.style.setProperty("--text-color", `var(--text-color, ${toneColor})`);
1799
+ }
1800
+ getToneColor() {
1801
+ switch (this.tone) {
1802
+ case "muted":
1803
+ return "var(--ai-color-text-muted, rgba(128, 128, 128, 0.7))";
1804
+ case "accent":
1805
+ return "var(--ai-color-accent, #4a90d9)";
1806
+ case "success":
1807
+ return "var(--ai-color-success, #2ea043)";
1808
+ case "warning":
1809
+ return "var(--ai-color-warning, #d29922)";
1810
+ case "error":
1811
+ return "var(--ai-color-error, #e33e33)";
1812
+ default:
1813
+ return "inherit";
1814
+ }
1815
+ }
1816
+ }
1817
+ __legacyDecorateClassTS([
1818
+ property9({ reflect: true })
1819
+ ], AiText.prototype, "size", undefined);
1820
+ __legacyDecorateClassTS([
1821
+ property9({ reflect: true })
1822
+ ], AiText.prototype, "weight", undefined);
1823
+ __legacyDecorateClassTS([
1824
+ property9({ reflect: true })
1825
+ ], AiText.prototype, "tone", undefined);
1826
+ __legacyDecorateClassTS([
1827
+ property9({ reflect: true, type: Boolean })
1828
+ ], AiText.prototype, "mono", undefined);
1829
+ __legacyDecorateClassTS([
1830
+ property9({ reflect: true, type: Boolean })
1831
+ ], AiText.prototype, "truncate", undefined);
1832
+ __legacyDecorateClassTS([
1833
+ property9({ reflect: true, type: Boolean })
1834
+ ], AiText.prototype, "inline", undefined);
1835
+ AiText = __legacyDecorateClassTS([
1836
+ customElement9("ai-text")
1837
+ ], AiText);
1838
+ // src/visual/markdown.ts
1839
+ import { LitElement as LitElement10, css as css10, html as html10, nothing as nothing4 } from "lit";
1840
+ import { customElement as customElement10, property as property10 } from "lit/decorators.js";
1841
+ import { map } from "lit/directives/map.js";
1842
+ class AiMarkdown extends LitElement10 {
1843
+ constructor() {
1844
+ super(...arguments);
1845
+ this.content = "";
1846
+ this.tone = "assistant";
1847
+ this.trusted = false;
1848
+ }
1849
+ static styles = css10`
1850
+ *,
1851
+ *::before,
1852
+ *::after {
1853
+ box-sizing: border-box;
1854
+ }
1855
+
1856
+ :host {
1857
+ display: block;
1858
+ max-width: 100%;
1859
+ color: var(--ai-markdown-color, var(--text-block-color, var(--text, var(--ai-color-text))));
1860
+ white-space: normal;
1861
+ word-break: normal;
1862
+ overflow-wrap: anywhere;
1863
+ font-size: var(--font-size-body, var(--ai-font-size-body, 0.875rem));
1864
+ line-height: var(--line-height-loose, var(--ai-line-height, 1.6));
1865
+ }
1866
+
1867
+ .markdown {
1868
+ display: block;
1869
+ }
1870
+
1871
+ .markdown > * + * {
1872
+ margin-top: var(--ai-markdown-gap, var(--content-gap, 10px));
1873
+ }
1874
+
1875
+ p,
1876
+ ul,
1877
+ ol,
1878
+ pre,
1879
+ h1,
1880
+ h2,
1881
+ h3,
1882
+ blockquote {
1883
+ margin: 0;
1884
+ }
1885
+
1886
+ p,
1887
+ li {
1888
+ white-space: pre-wrap;
1889
+ }
1890
+
1891
+ h1,
1892
+ h2,
1893
+ h3 {
1894
+ line-height: var(--line-height-snug, 1.3);
1895
+ color: var(
1896
+ --ai-markdown-heading-color,
1897
+ var(--heading-color, var(--text, var(--ai-markdown-color, var(--ai-color-text))))
1898
+ );
1899
+ }
1900
+
1901
+ h1 {
1902
+ font-size: var(--font-size-title, 1.125rem);
1903
+ font-weight: var(--font-weight-bold, 700);
1904
+ }
1905
+
1906
+ h2 {
1907
+ font-size: var(--font-size-body, 1rem);
1908
+ font-weight: var(--font-weight-bold, 700);
1909
+ }
1910
+
1911
+ h3 {
1912
+ font-size: var(--font-size-ui, 0.875rem);
1913
+ font-weight: var(--font-weight-title, 600);
1914
+ }
1915
+
1916
+ ul,
1917
+ ol {
1918
+ padding-left: 1.1rem;
1919
+ }
1920
+
1921
+ li {
1922
+ margin: 0;
1923
+ }
1924
+
1925
+ li + li {
1926
+ margin-top: 4px;
1927
+ }
1928
+
1929
+ li > ul,
1930
+ li > ol {
1931
+ margin-top: 4px;
1932
+ margin-bottom: 0;
1933
+ }
1934
+
1935
+ blockquote {
1936
+ border-left: 3px solid
1937
+ var(
1938
+ --ai-markdown-border-color,
1939
+ var(--blockquote-border-color, var(--border, var(--ai-color-border, #333)))
1940
+ );
1941
+ padding-left: var(--spacing-sm, var(--ai-space-sm, 0.5rem));
1942
+ color: color-mix(
1943
+ in srgb,
1944
+ var(--text, var(--ai-markdown-color, var(--ai-color-text))) 80%,
1945
+ transparent
1946
+ );
1947
+ }
1948
+
1949
+ blockquote > * + * {
1950
+ margin-top: 6px;
1951
+ }
1952
+
1953
+ blockquote blockquote {
1954
+ margin-top: 6px;
1955
+ }
1956
+
1957
+ code {
1958
+ padding: 0.12rem 0.35rem;
1959
+ border-radius: 6px;
1960
+ background: var(
1961
+ --ai-markdown-code-background,
1962
+ var(--code-background-color, color-mix(in srgb, var(--text, currentColor) 8%, transparent))
1963
+ );
1964
+ color: var(
1965
+ --ai-markdown-code-color,
1966
+ var(--code-text-color, var(--text, var(--ai-color-text)))
1967
+ );
1968
+ font-family: var(--font-family-mono, var(--ai-font-family-mono, monospace));
1969
+ font-size: 0.92em;
1970
+ }
1971
+
1972
+ pre {
1973
+ max-width: 100%;
1974
+ overflow-x: auto;
1975
+ -webkit-overflow-scrolling: touch;
1976
+ padding: calc(var(--spacing-sm, var(--ai-space-sm, 0.5rem)) + 2px)
1977
+ var(--spacing-md, var(--ai-space-md, 0.75rem));
1978
+ border-radius: calc(var(--radius, var(--ai-radius, 8px)) + 2px);
1979
+ background: var(
1980
+ --ai-markdown-code-background,
1981
+ var(--code-background-color, color-mix(in srgb, var(--text, currentColor) 5%, transparent))
1982
+ );
1983
+ border: 1px solid
1984
+ var(
1985
+ --ai-markdown-border-color,
1986
+ var(--blockquote-border-color, var(--border, var(--ai-color-border, #333)))
1987
+ );
1988
+ }
1989
+
1990
+ pre code {
1991
+ padding: 0;
1992
+ border-radius: 0;
1993
+ background: transparent;
1994
+ color: inherit;
1995
+ font-size: 0.9em;
1996
+ }
1997
+
1998
+ strong {
1999
+ color: var(--text, var(--ai-markdown-color, var(--ai-color-text)));
2000
+ font-weight: var(--font-weight-title, 600);
2001
+ }
2002
+
2003
+ em {
2004
+ font-style: italic;
2005
+ }
2006
+
2007
+ a {
2008
+ color: var(
2009
+ --ai-markdown-link-color,
2010
+ var(--link-color, var(--accent, var(--ai-color-accent, #0066cc)))
2011
+ );
2012
+ text-decoration: underline;
2013
+ text-underline-offset: 2px;
2014
+ cursor: pointer;
2015
+ }
2016
+
2017
+ a:hover {
2018
+ opacity: 0.8;
2019
+ }
2020
+
2021
+ :host([tone="user"]) {
2022
+ color: var(--ai-markdown-color, var(--text-on-accent, HighlightText));
2023
+ line-height: var(--line-height-snug, 1.25);
2024
+ }
2025
+
2026
+ :host([tone="user"]) .markdown > * + * {
2027
+ margin-top: 4px;
2028
+ }
2029
+
2030
+ :host([tone="user"]) a {
2031
+ color: var(--ai-markdown-link-color, var(--text-on-accent, HighlightText));
2032
+ text-decoration: underline;
2033
+ text-underline-offset: 2px;
2034
+ }
2035
+
2036
+ :host([tone="user"]) blockquote {
2037
+ border-left-color: color-mix(in srgb, var(--text-on-accent, currentColor) 30%, transparent);
2038
+ color: var(--text-on-accent, currentColor);
2039
+ }
2040
+
2041
+ :host([tone="user"]) code,
2042
+ :host([tone="user"]) pre {
2043
+ background: var(
2044
+ --ai-markdown-code-background,
2045
+ color-mix(in srgb, var(--text, currentColor) 12%, transparent)
2046
+ );
2047
+ border-color: var(
2048
+ --ai-markdown-border-color,
2049
+ color-mix(in srgb, var(--text, currentColor) 15%, transparent)
2050
+ );
2051
+ color: var(--ai-markdown-code-color, var(--text, currentColor));
2052
+ }
2053
+
2054
+ :host([tone="user"]) th {
2055
+ background: color-mix(in srgb, var(--text, currentColor) 8%, transparent);
2056
+ }
2057
+
2058
+ :host([tone="user"]) th,
2059
+ :host([tone="user"]) td {
2060
+ border-color: var(
2061
+ --ai-markdown-border-color,
2062
+ color-mix(in srgb, var(--text, currentColor) 15%, transparent)
2063
+ );
2064
+ }
2065
+
2066
+ :host([tone="system"]),
2067
+ :host([tone="tool"]) {
2068
+ color: var(--ai-markdown-color, var(--text-muted, var(--ai-color-text-muted, #888)));
2069
+ font-size: var(--font-size-meta, var(--ai-font-size-meta, 0.8125rem));
2070
+ }
2071
+
2072
+ .table-wrapper {
2073
+ width: 100%;
2074
+ overflow-x: auto;
2075
+ -webkit-overflow-scrolling: touch;
2076
+ }
2077
+
2078
+ table {
2079
+ width: 100%;
2080
+ min-width: max-content;
2081
+ border-collapse: collapse;
2082
+ font-size: 0.92em;
2083
+ margin: 0;
2084
+ }
2085
+
2086
+ th,
2087
+ td {
2088
+ padding: var(--spacing-xs, var(--ai-space-xs, 0.25rem))
2089
+ var(--spacing-sm, var(--ai-space-sm, 0.5rem));
2090
+ border: 1px solid
2091
+ var(
2092
+ --ai-markdown-border-color,
2093
+ var(--table-border-color, var(--border, var(--ai-color-border, #333)))
2094
+ );
2095
+ text-align: left;
2096
+ }
2097
+
2098
+ th {
2099
+ background: color-mix(
2100
+ in srgb,
2101
+ var(--text, var(--ai-markdown-color, var(--ai-color-text))) 4%,
2102
+ transparent
2103
+ );
2104
+ font-weight: var(--font-weight-semibold, 600);
2105
+ color: var(--text, var(--ai-markdown-color, var(--ai-color-text)));
2106
+ }
2107
+
2108
+ td {
2109
+ background: transparent;
2110
+ }
2111
+
2112
+ tr:nth-child(even) td {
2113
+ background: color-mix(
2114
+ in srgb,
2115
+ var(--text, var(--ai-markdown-color, var(--ai-color-text))) 2%,
2116
+ transparent
2117
+ );
2118
+ }
2119
+ `;
2120
+ parseInlines(text) {
2121
+ const parts = [];
2122
+ const pattern = /(`[^`]+`|\*\*[^*]+\*\*|\[[^\]]+\]\([^)]+\)|\*[^*]+\*|_[^_]+_)/g;
2123
+ let lastIndex = 0;
2124
+ for (const match of text.matchAll(pattern)) {
2125
+ const token = match[0];
2126
+ const index = match.index ?? 0;
2127
+ if (index > lastIndex) {
2128
+ parts.push({ type: "text", value: text.slice(lastIndex, index) });
2129
+ }
2130
+ if (token.startsWith("`")) {
2131
+ parts.push({ type: "code", value: token.slice(1, -1) });
2132
+ } else if (token.startsWith("**")) {
2133
+ parts.push({ type: "strong", value: token.slice(2, -2) });
2134
+ } else if (token.startsWith("[")) {
2135
+ const linkMatch = token.match(/^\[(.+)\]\((.+)\)$/);
2136
+ if (linkMatch) {
2137
+ parts.push({
2138
+ type: "link",
2139
+ text: linkMatch[1] ?? "",
2140
+ href: linkMatch[2] ?? ""
2141
+ });
2142
+ } else {
2143
+ parts.push({ type: "text", value: token });
2144
+ }
2145
+ } else if (token.startsWith("_")) {
2146
+ parts.push({ type: "emphasis", value: token.slice(1, -1) });
2147
+ } else {
2148
+ parts.push({ type: "emphasis", value: token.slice(1, -1) });
2149
+ }
2150
+ lastIndex = index + token.length;
2151
+ }
2152
+ if (lastIndex < text.length) {
2153
+ parts.push({ type: "text", value: text.slice(lastIndex) });
2154
+ }
2155
+ return parts;
2156
+ }
2157
+ renderInline(text) {
2158
+ return map(this.parseInlines(text), (part) => {
2159
+ if (part.type === "code") {
2160
+ return html10`<code>${part.value}</code>`;
2161
+ }
2162
+ if (part.type === "strong") {
2163
+ return html10`<strong>${part.value}</strong>`;
2164
+ }
2165
+ if (part.type === "emphasis") {
2166
+ return html10`<em>${part.value}</em>`;
2167
+ }
2168
+ if (part.type === "link") {
2169
+ const isAllowed = /^https?:\/\//i.test(part.href) || !/^[a-zA-Z][a-zA-Z0-9+.-]*:/i.test(part.href);
2170
+ const safe = isAllowed ? part.href : "";
2171
+ return html10`<a
2172
+ href="${safe}"
2173
+ target="_blank"
2174
+ rel="noopener noreferrer"
2175
+ >${part.text}</a
2176
+ >`;
2177
+ }
2178
+ return part.value;
2179
+ });
2180
+ }
2181
+ parseTableRow(line) {
2182
+ const content = line.replace(/^\|/, "").replace(/\|$/, "");
2183
+ return content.split("|").map((cell) => cell.trim());
2184
+ }
2185
+ parseTableAligns(separator) {
2186
+ const cells = this.parseTableRow(separator);
2187
+ return cells.map((cell) => {
2188
+ const trimmed = cell.trim();
2189
+ const leftAlign = trimmed.startsWith(":");
2190
+ const rightAlign = trimmed.endsWith(":");
2191
+ if (leftAlign && rightAlign) {
2192
+ return "center";
2193
+ }
2194
+ if (rightAlign) {
2195
+ return "right";
2196
+ }
2197
+ return "left";
2198
+ });
2199
+ }
2200
+ isTableSeparator(line, columnCount) {
2201
+ const cells = this.parseTableRow(line);
2202
+ if (cells.length !== columnCount || cells.length === 0) {
2203
+ return false;
2204
+ }
2205
+ return cells.every((cell) => /^:?-{3,}:?$/.test(cell.trim()));
2206
+ }
2207
+ indentLevel(line) {
2208
+ let n = 0;
2209
+ for (const ch of line) {
2210
+ if (ch === " ") {
2211
+ n++;
2212
+ } else if (ch === "\t") {
2213
+ n += 2;
2214
+ } else {
2215
+ break;
2216
+ }
2217
+ }
2218
+ return n;
2219
+ }
2220
+ parseBlocks(source) {
2221
+ const lines = source.replace(/\r\n/g, `
2222
+ `).split(`
2223
+ `);
2224
+ const blocks = [];
2225
+ let i = 0;
2226
+ while (i < lines.length) {
2227
+ const trimmed = (lines[i] ?? "").trim();
2228
+ if (!trimmed) {
2229
+ i++;
2230
+ continue;
2231
+ }
2232
+ const codeBlock = this.parseCodeBlock(lines, i, trimmed);
2233
+ if (codeBlock) {
2234
+ blocks.push(codeBlock.block);
2235
+ i = codeBlock.nextIndex;
2236
+ continue;
2237
+ }
2238
+ const headingBlock = this.parseHeadingBlock(trimmed);
2239
+ if (headingBlock) {
2240
+ blocks.push(headingBlock);
2241
+ i++;
2242
+ continue;
2243
+ }
2244
+ const blockquoteBlock = this.parseBlockquoteBlock(lines, i, trimmed);
2245
+ if (blockquoteBlock) {
2246
+ blocks.push(blockquoteBlock.block);
2247
+ i = blockquoteBlock.nextIndex;
2248
+ continue;
2249
+ }
2250
+ const listBlock = this.parseListBlock(lines, i, trimmed);
2251
+ if (listBlock) {
2252
+ blocks.push(listBlock.block);
2253
+ i = listBlock.nextIndex;
2254
+ continue;
2255
+ }
2256
+ const tableBlock = this.parseTableBlock(lines, i, trimmed);
2257
+ if (tableBlock) {
2258
+ blocks.push(tableBlock.block);
2259
+ i = tableBlock.nextIndex;
2260
+ continue;
2261
+ }
2262
+ const paragraphBlock = this.parseParagraphBlock(lines, i);
2263
+ blocks.push(paragraphBlock.block);
2264
+ i = paragraphBlock.nextIndex;
2265
+ }
2266
+ return blocks;
2267
+ }
2268
+ parseCodeBlock(lines, startIndex, trimmed) {
2269
+ if (!trimmed.startsWith("```")) {
2270
+ return;
2271
+ }
2272
+ const language = trimmed.slice(3).trim();
2273
+ const codeLines = [];
2274
+ let i = startIndex + 1;
2275
+ while (i < lines.length && !(lines[i] ?? "").trim().startsWith("```")) {
2276
+ codeLines.push(lines[i] ?? "");
2277
+ i++;
2278
+ }
2279
+ if (i < lines.length) {
2280
+ i++;
2281
+ }
2282
+ return {
2283
+ block: { type: "code", code: codeLines.join(`
2284
+ `), language },
2285
+ nextIndex: i
2286
+ };
2287
+ }
2288
+ parseHeadingBlock(trimmed) {
2289
+ const heading = trimmed.match(/^(#{1,3})\s+(.+)$/);
2290
+ if (!heading?.[1] || !heading?.[2]) {
2291
+ return;
2292
+ }
2293
+ return {
2294
+ type: "heading",
2295
+ level: heading[1].length,
2296
+ text: heading[2].trim()
2297
+ };
2298
+ }
2299
+ parseBlockquoteBlock(lines, startIndex, trimmed) {
2300
+ if (!trimmed.startsWith(">")) {
2301
+ return;
2302
+ }
2303
+ const quoteLines = [];
2304
+ let i = startIndex;
2305
+ while (i < lines.length) {
2306
+ const line = lines[i] ?? "";
2307
+ const lineTrimmed = line.trim();
2308
+ if (!lineTrimmed) {
2309
+ let j = i + 1;
2310
+ while (j < lines.length && !(lines[j] ?? "").trim()) {
2311
+ j++;
2312
+ }
2313
+ if (j < lines.length && (lines[j] ?? "").trim().startsWith(">")) {
2314
+ quoteLines.push("");
2315
+ i = j;
2316
+ continue;
2317
+ }
2318
+ break;
2319
+ }
2320
+ if (!lineTrimmed.startsWith(">")) {
2321
+ break;
2322
+ }
2323
+ quoteLines.push(lineTrimmed.replace(/^>\s?/, ""));
2324
+ i++;
2325
+ }
2326
+ if (quoteLines.length === 0) {
2327
+ return;
2328
+ }
2329
+ const innerBlocks = this.parseBlocks(quoteLines.join(`
2330
+ `));
2331
+ return {
2332
+ block: { type: "blockquote", blocks: innerBlocks },
2333
+ nextIndex: i
2334
+ };
2335
+ }
2336
+ parseListBlock(lines, startIndex, trimmed) {
2337
+ if (/^[-*]\s+(.+)$/.test(trimmed)) {
2338
+ return this.collectList(lines, startIndex, "ul");
2339
+ }
2340
+ if (/^\d+\.\s+(.+)$/.test(trimmed)) {
2341
+ return this.collectList(lines, startIndex, "ol");
2342
+ }
2343
+ return;
2344
+ }
2345
+ skipBlankLines(lines, from) {
2346
+ let j = from;
2347
+ while (j < lines.length && !(lines[j] ?? "").trim()) {
2348
+ j++;
2349
+ }
2350
+ return j;
2351
+ }
2352
+ parseNestedChildren(lines, startIndex, baseIndent) {
2353
+ const nestedLines = [];
2354
+ let i = startIndex;
2355
+ while (i < lines.length) {
2356
+ const nestedLine = lines[i] ?? "";
2357
+ const nestedTrimmed = nestedLine.trim();
2358
+ if (!nestedTrimmed) {
2359
+ const j = this.skipBlankLines(lines, i + 1);
2360
+ if (j < lines.length && this.indentLevel(lines[j] ?? "") > baseIndent) {
2361
+ nestedLines.push("");
2362
+ i = j;
2363
+ continue;
2364
+ }
2365
+ break;
2366
+ }
2367
+ if (this.indentLevel(nestedLine) <= baseIndent) {
2368
+ break;
2369
+ }
2370
+ nestedLines.push(nestedLine);
2371
+ i++;
2372
+ }
2373
+ if (nestedLines.length === 0) {
2374
+ return [];
2375
+ }
2376
+ const nonEmpty = nestedLines.filter((l) => l.trim());
2377
+ const minIndent = nonEmpty.length > 0 ? Math.min(...nonEmpty.map((l) => this.indentLevel(l))) : 0;
2378
+ const unindented = nestedLines.map((l) => l.trim() ? l.slice(minIndent) : l);
2379
+ return this.parseBlocks(unindented.join(`
2380
+ `));
2381
+ }
2382
+ collectList(lines, startIndex, type) {
2383
+ const baseIndent = this.indentLevel(lines[startIndex] ?? "");
2384
+ const listPattern = type === "ul" ? /^[-*]\s+(.+)$/ : /^\d+\.\s+(.+)$/;
2385
+ const items = [];
2386
+ let i = startIndex;
2387
+ while (i < lines.length) {
2388
+ const line = lines[i] ?? "";
2389
+ const trimmed = line.trim();
2390
+ const indent = this.indentLevel(line);
2391
+ if (!trimmed) {
2392
+ const j = this.skipBlankLines(lines, i + 1);
2393
+ if (j < lines.length && this.indentLevel(lines[j] ?? "") === baseIndent && listPattern.test((lines[j] ?? "").trim())) {
2394
+ i = j;
2395
+ continue;
2396
+ }
2397
+ break;
2398
+ }
2399
+ if (indent < baseIndent) {
2400
+ break;
2401
+ }
2402
+ if (indent === baseIndent) {
2403
+ const match = trimmed.match(listPattern);
2404
+ if (!match?.[1]) {
2405
+ break;
2406
+ }
2407
+ items.push({ text: match[1].trim(), children: [] });
2408
+ i++;
2409
+ continue;
2410
+ }
2411
+ const current = items[items.length - 1];
2412
+ if (!current) {
2413
+ break;
2414
+ }
2415
+ current.children = this.parseNestedChildren(lines, i, baseIndent);
2416
+ const consumed = this.countNestedLines(lines, i, baseIndent);
2417
+ i += consumed;
2418
+ }
2419
+ return { block: { type, items }, nextIndex: i };
2420
+ }
2421
+ countNestedLines(lines, startIndex, baseIndent) {
2422
+ let count = 0;
2423
+ let i = startIndex;
2424
+ while (i < lines.length) {
2425
+ const line = lines[i] ?? "";
2426
+ const trimmed = line.trim();
2427
+ if (!trimmed) {
2428
+ const j = this.skipBlankLines(lines, i + 1);
2429
+ if (j < lines.length && this.indentLevel(lines[j] ?? "") > baseIndent) {
2430
+ count += j - i;
2431
+ i = j;
2432
+ continue;
2433
+ }
2434
+ break;
2435
+ }
2436
+ if (this.indentLevel(line) <= baseIndent) {
2437
+ break;
2438
+ }
2439
+ count++;
2440
+ i++;
2441
+ }
2442
+ return count;
2443
+ }
2444
+ parseTableBlock(lines, startIndex, trimmed) {
2445
+ if (!this.startsTable(trimmed)) {
2446
+ return;
2447
+ }
2448
+ const headers = this.parseTableRow(trimmed);
2449
+ const separator = (lines[startIndex + 1] ?? "").trim();
2450
+ if (!separator.startsWith("|") || !this.isTableSeparator(separator, headers.length)) {
2451
+ return;
2452
+ }
2453
+ const aligns = this.parseTableAligns(separator);
2454
+ const rows = [];
2455
+ let i = startIndex + 2;
2456
+ while (i < lines.length) {
2457
+ const tableLine = (lines[i] ?? "").trim();
2458
+ if (!this.startsTable(tableLine)) {
2459
+ break;
2460
+ }
2461
+ rows.push(this.parseTableRow(tableLine));
2462
+ i++;
2463
+ }
2464
+ return {
2465
+ block: { type: "table", headers, rows, aligns },
2466
+ nextIndex: i
2467
+ };
2468
+ }
2469
+ parseParagraphBlock(lines, startIndex) {
2470
+ const paragraphLines = [];
2471
+ let i = startIndex;
2472
+ while (i < lines.length) {
2473
+ const nextTrimmed = (lines[i] ?? "").trim();
2474
+ if (!nextTrimmed || this.startsStructuredBlock(lines, i, nextTrimmed)) {
2475
+ break;
2476
+ }
2477
+ paragraphLines.push(nextTrimmed);
2478
+ i++;
2479
+ }
2480
+ return {
2481
+ block: {
2482
+ type: "paragraph",
2483
+ text: paragraphLines.join(" ")
2484
+ },
2485
+ nextIndex: i
2486
+ };
2487
+ }
2488
+ startsStructuredBlock(lines, index, trimmed) {
2489
+ return /^(#{1,3})\s+/.test(trimmed) || /^[-*]\s+/.test(trimmed) || /^\d+\.\s+/.test(trimmed) || trimmed.startsWith("```") || trimmed.startsWith(">") || this.isTableStart(lines, index, trimmed);
2490
+ }
2491
+ startsTable(trimmed) {
2492
+ return trimmed.startsWith("|") && trimmed.includes("|");
2493
+ }
2494
+ isTableStart(lines, index, trimmed) {
2495
+ if (!this.startsTable(trimmed)) {
2496
+ return false;
2497
+ }
2498
+ const headers = this.parseTableRow(trimmed);
2499
+ const separator = (lines[index + 1] ?? "").trim();
2500
+ return separator.startsWith("|") && this.isTableSeparator(separator, headers.length);
2501
+ }
2502
+ renderBlocks(blocks) {
2503
+ return map(blocks, (block) => this.renderBlock(block));
2504
+ }
2505
+ renderBlock(block) {
2506
+ if (block.type === "paragraph") {
2507
+ return html10`<p>${this.renderInline(block.text)}</p>`;
2508
+ }
2509
+ if (block.type === "heading") {
2510
+ if (block.level === 1) {
2511
+ return html10`<h1>${this.renderInline(block.text)}</h1>`;
2512
+ }
2513
+ if (block.level === 2) {
2514
+ return html10`<h2>${this.renderInline(block.text)}</h2>`;
2515
+ }
2516
+ return html10`<h3>${this.renderInline(block.text)}</h3>`;
2517
+ }
2518
+ if (block.type === "code") {
2519
+ return html10`<pre><code>${block.code}</code></pre>`;
2520
+ }
2521
+ if (block.type === "ul") {
2522
+ return html10`<ul
2523
+ >${map(block.items, (item) => html10`<li
2524
+ >${this.renderInline(item.text)}${item.children.length ? this.renderBlocks(item.children) : nothing4}</li
2525
+ >`)}</ul
2526
+ >`;
2527
+ }
2528
+ if (block.type === "ol") {
2529
+ return html10`<ol
2530
+ >${map(block.items, (item) => html10`<li
2531
+ >${this.renderInline(item.text)}${item.children.length ? this.renderBlocks(item.children) : nothing4}</li
2532
+ >`)}</ol
2533
+ >`;
2534
+ }
2535
+ if (block.type === "blockquote") {
2536
+ return html10`<blockquote>${this.renderBlocks(block.blocks)}</blockquote>`;
2537
+ }
2538
+ if (block.type === "table") {
2539
+ return html10`
2540
+ <div class="table-wrapper">
2541
+ <table>
2542
+ <thead>
2543
+ <tr>
2544
+ ${map(block.headers, (header, idx) => {
2545
+ const align = block.aligns[idx] ?? "left";
2546
+ return html10`<th style="text-align: ${align}"
2547
+ >${this.renderInline(header)}</th
2548
+ >`;
2549
+ })}
2550
+ </tr>
2551
+ </thead>
2552
+ <tbody>
2553
+ ${map(block.rows, (row) => html10`
2554
+ <tr>
2555
+ ${map(row, (cell, idx) => {
2556
+ const align = block.aligns[idx] ?? "left";
2557
+ return html10`<td style="text-align: ${align}"
2558
+ >${this.renderInline(cell)}</td
2559
+ >`;
2560
+ })}
2561
+ </tr>
2562
+ `)}
2563
+ </tbody>
2564
+ </table>
2565
+ </div>
2566
+ `;
2567
+ }
2568
+ return nothing4;
2569
+ }
2570
+ renderMarkdown(source) {
2571
+ const blocks = this.parseBlocks(source.trim());
2572
+ return html10`<div class="markdown">${this.renderBlocks(blocks)}</div>`;
2573
+ }
2574
+ render() {
2575
+ if (this.content) {
2576
+ return this.renderMarkdown(this.content);
2577
+ }
2578
+ return html10`
2579
+ <slot></slot>
2580
+ `;
2581
+ }
2582
+ }
2583
+ __legacyDecorateClassTS([
2584
+ property10({ type: String })
2585
+ ], AiMarkdown.prototype, "content", undefined);
2586
+ __legacyDecorateClassTS([
2587
+ property10({ reflect: true })
2588
+ ], AiMarkdown.prototype, "tone", undefined);
2589
+ __legacyDecorateClassTS([
2590
+ property10({ type: Boolean, reflect: true })
2591
+ ], AiMarkdown.prototype, "trusted", undefined);
2592
+ AiMarkdown = __legacyDecorateClassTS([
2593
+ customElement10("ai-markdown")
2594
+ ], AiMarkdown);
2595
+ // src/visual/badge.ts
2596
+ import { LitElement as LitElement11, css as css11, html as html11 } from "lit";
2597
+ import { customElement as customElement11, property as property11 } from "lit/decorators.js";
2598
+ class AiBadge extends LitElement11 {
2599
+ constructor() {
2600
+ super(...arguments);
2601
+ this.tone = "neutral";
2602
+ this.size = "md";
2603
+ this.dot = false;
2604
+ }
2605
+ static styles = css11`
2606
+ :host {
2607
+ box-sizing: border-box;
2608
+ display: inline-flex;
2609
+ align-items: center;
2610
+ gap: var(--inline-gap, 4px);
2611
+ margin: 0;
2612
+ padding: var(--_padding, 3px 8px);
2613
+ font-size: var(--font-size, 0.75rem);
2614
+ font-weight: var(--font-weight, 600);
2615
+ line-height: 1;
2616
+ color: var(--text-color, inherit);
2617
+ background: var(--background-color, rgba(128, 128, 128, 0.1));
2618
+ border: 1px solid var(--border-color, transparent);
2619
+ border-radius: var(--border-radius, 999px);
2620
+ white-space: nowrap;
2621
+ }
2622
+
2623
+ :host([size="sm"]) {
2624
+ --_padding: 2px 6px;
2625
+ }
2626
+
2627
+ :host([size="md"]) {
2628
+ --_padding: 3px 8px;
2629
+ }
2630
+
2631
+ .dot {
2632
+ width: 6px;
2633
+ height: 6px;
2634
+ border-radius: 50%;
2635
+ background: var(--dot-color, var(--text-color, inherit));
2636
+ flex-shrink: 0;
2637
+ }
2638
+
2639
+ *,
2640
+ *::before,
2641
+ *::after {
2642
+ box-sizing: inherit;
2643
+ }
2644
+ `;
2645
+ render() {
2646
+ return html11`
2647
+ ${this.dot ? html11`
2648
+ <span class="dot" part="dot"></span>
2649
+ ` : ""}
2650
+ <slot></slot>
2651
+ `;
2652
+ }
2653
+ updated() {
2654
+ const colors = this.getToneColors();
2655
+ this.style.setProperty("--background-color", `var(--background-color, ${colors.bg})`);
2656
+ this.style.setProperty("--text-color", `var(--text-color, ${colors.text})`);
2657
+ this.style.setProperty("--border-color", `var(--border-color, ${colors.border})`);
2658
+ this.style.setProperty("--dot-color", `var(--dot-color, ${colors.text})`);
2659
+ }
2660
+ getToneColors() {
2661
+ switch (this.tone) {
2662
+ case "accent":
2663
+ return {
2664
+ bg: "rgba(74, 144, 217, 0.12)",
2665
+ text: "var(--ai-color-accent, #4a90d9)",
2666
+ border: "rgba(74, 144, 217, 0.2)"
2667
+ };
2668
+ case "success":
2669
+ return {
2670
+ bg: "rgba(46, 160, 67, 0.12)",
2671
+ text: "var(--ai-color-success, #2ea043)",
2672
+ border: "rgba(46, 160, 67, 0.2)"
2673
+ };
2674
+ case "warning":
2675
+ return {
2676
+ bg: "rgba(210, 153, 34, 0.12)",
2677
+ text: "var(--ai-color-warning, #d29922)",
2678
+ border: "rgba(210, 153, 34, 0.2)"
2679
+ };
2680
+ case "error":
2681
+ return {
2682
+ bg: "rgba(227, 62, 51, 0.12)",
2683
+ text: "var(--ai-color-error, #e33e33)",
2684
+ border: "rgba(227, 62, 51, 0.2)"
2685
+ };
2686
+ case "info":
2687
+ return {
2688
+ bg: "rgba(80, 160, 220, 0.12)",
2689
+ text: "var(--ai-color-info, #50a0dc)",
2690
+ border: "rgba(80, 160, 220, 0.2)"
2691
+ };
2692
+ default:
2693
+ return {
2694
+ bg: "rgba(128, 128, 128, 0.1)",
2695
+ text: "inherit",
2696
+ border: "rgba(128, 128, 128, 0.15)"
2697
+ };
2698
+ }
2699
+ }
2700
+ }
2701
+ __legacyDecorateClassTS([
2702
+ property11({ reflect: true })
2703
+ ], AiBadge.prototype, "tone", undefined);
2704
+ __legacyDecorateClassTS([
2705
+ property11({ reflect: true })
2706
+ ], AiBadge.prototype, "size", undefined);
2707
+ __legacyDecorateClassTS([
2708
+ property11({ reflect: true, type: Boolean })
2709
+ ], AiBadge.prototype, "dot", undefined);
2710
+ AiBadge = __legacyDecorateClassTS([
2711
+ customElement11("ai-badge")
2712
+ ], AiBadge);
2713
+ // src/visual/status.ts
2714
+ import { LitElement as LitElement12, css as css12, html as html12 } from "lit";
2715
+ import { customElement as customElement12, property as property12 } from "lit/decorators.js";
2716
+ var SIZE_MAP2 = {
2717
+ xs: "6px",
2718
+ sm: "8px",
2719
+ md: "12px",
2720
+ lg: "16px"
2721
+ };
2722
+
2723
+ class AiStatus extends LitElement12 {
2724
+ constructor() {
2725
+ super(...arguments);
2726
+ this.state = "unknown";
2727
+ this.size = "md";
2728
+ this.variant = "dot";
2729
+ }
2730
+ static styles = css12`
2731
+ :host {
2732
+ box-sizing: border-box;
2733
+ display: inline-flex;
2734
+ align-items: center;
2735
+ justify-content: center;
2736
+ margin: 0;
2737
+ padding: 0;
2738
+ color: var(--color, var(--ai-color-text-muted, rgba(128, 128, 128, 0.7)));
2739
+ }
2740
+
2741
+ .dot {
2742
+ width: var(--size, 12px);
2743
+ height: var(--size, 12px);
2744
+ border-radius: 50%;
2745
+ background: var(--color, var(--ai-color-text-muted, rgba(128, 128, 128, 0.7)));
2746
+ flex-shrink: 0;
2747
+ }
2748
+
2749
+ :host([state="running"]) .dot {
2750
+ animation: pulse var(--pulse-duration, 1.5s) ease-in-out infinite;
2751
+ }
2752
+
2753
+ @keyframes pulse {
2754
+ 0%,
2755
+ 100% {
2756
+ transform: scale(1);
2757
+ opacity: 1;
2758
+ }
2759
+ 50% {
2760
+ transform: scale(1.2);
2761
+ opacity: 0.7;
2762
+ }
2763
+ }
2764
+
2765
+ .icon-wrapper {
2766
+ width: var(--size, 12px);
2767
+ height: var(--size, 12px);
2768
+ display: inline-flex;
2769
+ align-items: center;
2770
+ justify-content: center;
2771
+ }
2772
+
2773
+ .fallback-icon {
2774
+ width: 100%;
2775
+ height: 100%;
2776
+ }
2777
+
2778
+ *,
2779
+ *::before,
2780
+ *::after {
2781
+ box-sizing: inherit;
2782
+ }
2783
+ `;
2784
+ render() {
2785
+ if (this.variant === "icon") {
2786
+ return html12`
2787
+ <span class="icon-wrapper" part="icon">
2788
+ <slot>
2789
+ <svg class="fallback-icon" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
2790
+ ${this.getFallbackIconPath()}
2791
+ </svg>
2792
+ </slot>
2793
+ </span>
2794
+ `;
2795
+ }
2796
+ return html12`
2797
+ <span class="dot" part="dot"></span>
2798
+ `;
2799
+ }
2800
+ updated() {
2801
+ const size = SIZE_MAP2[this.size] ?? "12px";
2802
+ this.style.setProperty("--size", `var(--size, ${size})`);
2803
+ const stateColor = this.getStateColor();
2804
+ this.style.setProperty("--color", `var(--color, ${stateColor})`);
2805
+ }
2806
+ getStateColor() {
2807
+ switch (this.state) {
2808
+ case "idle":
2809
+ return "var(--idle-color, var(--ai-color-text-muted, rgba(128, 128, 128, 0.4)))";
2810
+ case "running":
2811
+ return "var(--running-color, var(--ai-color-accent, #4a90d9))";
2812
+ case "success":
2813
+ return "var(--success-color, var(--ai-color-success, #2ea043))";
2814
+ case "error":
2815
+ return "var(--error-color, var(--ai-color-error, #e33e33))";
2816
+ case "cancelled":
2817
+ return "var(--cancelled-color, var(--ai-color-text-muted, rgba(128, 128, 128, 0.5)))";
2818
+ default:
2819
+ return "var(--ai-color-text-muted, rgba(128, 128, 128, 0.7))";
2820
+ }
2821
+ }
2822
+ getFallbackIconPath() {
2823
+ switch (this.state) {
2824
+ case "success":
2825
+ return html12`
2826
+ <path
2827
+ d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"
2828
+ />
2829
+ `.strings.join("");
2830
+ case "error":
2831
+ return html12`
2832
+ <path
2833
+ d="M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z"
2834
+ />
2835
+ `.strings.join("");
2836
+ case "running":
2837
+ return html12`
2838
+ <path
2839
+ d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm9-3.25v2.5h2.5a.75.75 0 010 1.5H9v2.5a.75.75 0 01-1.5 0v-2.5H5a.75.75 0 010-1.5h2.5v-2.5a.75.75 0 011.5 0z"
2840
+ />
2841
+ `.strings.join("");
2842
+ default:
2843
+ return html12`
2844
+ <circle cx="8" cy="8" r="4" />
2845
+ `.strings.join("");
2846
+ }
2847
+ }
2848
+ }
2849
+ __legacyDecorateClassTS([
2850
+ property12({ reflect: true })
2851
+ ], AiStatus.prototype, "state", undefined);
2852
+ __legacyDecorateClassTS([
2853
+ property12({ reflect: true })
2854
+ ], AiStatus.prototype, "size", undefined);
2855
+ __legacyDecorateClassTS([
2856
+ property12({ reflect: true })
2857
+ ], AiStatus.prototype, "variant", undefined);
2858
+ AiStatus = __legacyDecorateClassTS([
2859
+ customElement12("ai-status")
2860
+ ], AiStatus);
2861
+ // src/visual/avatar.ts
2862
+ import { LitElement as LitElement13, css as css13, html as html13 } from "lit";
2863
+ import { customElement as customElement13, property as property13 } from "lit/decorators.js";
2864
+ var SIZE_MAP3 = {
2865
+ sm: "1.5rem",
2866
+ md: "2rem",
2867
+ lg: "2.5rem"
2868
+ };
2869
+ var FONT_SIZE_MAP = {
2870
+ sm: "0.625rem",
2871
+ md: "0.75rem",
2872
+ lg: "0.875rem"
2873
+ };
2874
+
2875
+ class AiAvatar extends LitElement13 {
2876
+ constructor() {
2877
+ super(...arguments);
2878
+ this.src = "";
2879
+ this.name = "";
2880
+ this.size = "md";
2881
+ this.tone = "neutral";
2882
+ }
2883
+ static styles = css13`
2884
+ :host {
2885
+ box-sizing: border-box;
2886
+ display: inline-flex;
2887
+ align-items: center;
2888
+ justify-content: center;
2889
+ width: var(--size, 2rem);
2890
+ height: var(--size, 2rem);
2891
+ border-radius: var(--border-radius, 50%);
2892
+ background: var(--background-color, rgba(128, 128, 128, 0.15));
2893
+ color: var(--text-color, inherit);
2894
+ border: 1px solid var(--border-color, transparent);
2895
+ overflow: hidden;
2896
+ flex-shrink: 0;
2897
+ margin: 0;
2898
+ padding: 0;
2899
+ }
2900
+
2901
+ img {
2902
+ width: 100%;
2903
+ height: 100%;
2904
+ object-fit: cover;
2905
+ display: block;
2906
+ }
2907
+
2908
+ .initials {
2909
+ font-size: var(--font-size, 0.75rem);
2910
+ font-weight: var(--font-weight, 700);
2911
+ line-height: 1;
2912
+ text-transform: uppercase;
2913
+ letter-spacing: 0.02em;
2914
+ user-select: none;
2915
+ }
2916
+
2917
+ *,
2918
+ *::before,
2919
+ *::after {
2920
+ box-sizing: inherit;
2921
+ }
2922
+ `;
2923
+ render() {
2924
+ if (this.src) {
2925
+ return html13`<img src="${this.src}" alt="${this.name || ""}" part="image" />`;
2926
+ }
2927
+ const initials = this.getInitials();
2928
+ if (initials) {
2929
+ return html13`<span class="initials" part="initials">${initials}</span>`;
2930
+ }
2931
+ return html13`
2932
+ <slot></slot>
2933
+ `;
2934
+ }
2935
+ updated() {
2936
+ const size = SIZE_MAP3[this.size] ?? "2rem";
2937
+ const fontSize = FONT_SIZE_MAP[this.size] ?? "0.75rem";
2938
+ this.style.setProperty("--size", `var(--size, ${size})`);
2939
+ this.style.setProperty("--font-size", `var(--font-size, ${fontSize})`);
2940
+ const toneColors = this.getToneColors();
2941
+ this.style.setProperty("--background-color", `var(--background-color, ${toneColors.bg})`);
2942
+ this.style.setProperty("--text-color", `var(--text-color, ${toneColors.text})`);
2943
+ this.style.setProperty("--border-color", `var(--border-color, ${toneColors.border})`);
2944
+ }
2945
+ getInitials() {
2946
+ if (!this.name) {
2947
+ return "";
2948
+ }
2949
+ const words = this.name.trim().split(/\s+/);
2950
+ if (words.length >= 2) {
2951
+ const first = words[0]?.[0] ?? "";
2952
+ const last = words[words.length - 1]?.[0] ?? "";
2953
+ return (first + last).toUpperCase();
2954
+ }
2955
+ return (words[0]?.[0] ?? "").toUpperCase();
2956
+ }
2957
+ getToneColors() {
2958
+ switch (this.tone) {
2959
+ case "accent":
2960
+ return {
2961
+ bg: "rgba(74, 144, 217, 0.15)",
2962
+ text: "var(--ai-color-accent, #4a90d9)",
2963
+ border: "rgba(74, 144, 217, 0.25)"
2964
+ };
2965
+ case "user":
2966
+ return {
2967
+ bg: "rgba(74, 144, 217, 0.12)",
2968
+ text: "var(--ai-color-accent, #4a90d9)",
2969
+ border: "rgba(74, 144, 217, 0.2)"
2970
+ };
2971
+ case "assistant":
2972
+ return {
2973
+ bg: "rgba(128, 128, 128, 0.12)",
2974
+ text: "var(--ai-color-text-muted, rgba(128, 128, 128, 0.8))",
2975
+ border: "rgba(128, 128, 128, 0.2)"
2976
+ };
2977
+ case "agent":
2978
+ return {
2979
+ bg: "rgba(46, 160, 67, 0.12)",
2980
+ text: "var(--ai-color-success, #2ea043)",
2981
+ border: "rgba(46, 160, 67, 0.2)"
2982
+ };
2983
+ default:
2984
+ return {
2985
+ bg: "rgba(128, 128, 128, 0.15)",
2986
+ text: "inherit",
2987
+ border: "transparent"
2988
+ };
2989
+ }
2990
+ }
2991
+ }
2992
+ __legacyDecorateClassTS([
2993
+ property13({ reflect: true })
2994
+ ], AiAvatar.prototype, "src", undefined);
2995
+ __legacyDecorateClassTS([
2996
+ property13({ reflect: true })
2997
+ ], AiAvatar.prototype, "name", undefined);
2998
+ __legacyDecorateClassTS([
2999
+ property13({ reflect: true })
3000
+ ], AiAvatar.prototype, "size", undefined);
3001
+ __legacyDecorateClassTS([
3002
+ property13({ reflect: true })
3003
+ ], AiAvatar.prototype, "tone", undefined);
3004
+ AiAvatar = __legacyDecorateClassTS([
3005
+ customElement13("ai-avatar")
3006
+ ], AiAvatar);
3007
+ // src/visual/icon.ts
3008
+ import { LitElement as LitElement14, css as css14, html as html14 } from "lit";
3009
+ import { customElement as customElement14, property as property14 } from "lit/decorators.js";
3010
+ var SIZE_MAP4 = {
3011
+ xs: "12px",
3012
+ sm: "14px",
3013
+ md: "16px",
3014
+ lg: "20px"
3015
+ };
3016
+
3017
+ class AiIcon extends LitElement14 {
3018
+ constructor() {
3019
+ super(...arguments);
3020
+ this.size = "md";
3021
+ this.tone = "default";
3022
+ }
3023
+ static styles = css14`
3024
+ :host {
3025
+ box-sizing: border-box;
3026
+ display: inline-flex;
3027
+ align-items: center;
3028
+ justify-content: center;
3029
+ width: var(--size, 16px);
3030
+ height: var(--size, 16px);
3031
+ color: var(--color, inherit);
3032
+ margin: 0;
3033
+ padding: 0;
3034
+ }
3035
+
3036
+ ::slotted(*) {
3037
+ width: 100%;
3038
+ height: 100%;
3039
+ }
3040
+
3041
+ ::slotted(svg) {
3042
+ fill: currentColor;
3043
+ }
3044
+
3045
+ *,
3046
+ *::before,
3047
+ *::after {
3048
+ box-sizing: inherit;
3049
+ }
3050
+ `;
3051
+ render() {
3052
+ return html14`
3053
+ <slot></slot>
3054
+ `;
3055
+ }
3056
+ updated() {
3057
+ const size = SIZE_MAP4[this.size] ?? "16px";
3058
+ this.style.setProperty("--size", `var(--size, ${size})`);
3059
+ const toneColor = this.getToneColor();
3060
+ this.style.setProperty("--color", `var(--color, ${toneColor})`);
3061
+ }
3062
+ getToneColor() {
3063
+ switch (this.tone) {
3064
+ case "muted":
3065
+ return "var(--ai-color-text-muted, rgba(128, 128, 128, 0.7))";
3066
+ case "accent":
3067
+ return "var(--ai-color-accent, #4a90d9)";
3068
+ case "success":
3069
+ return "var(--ai-color-success, #2ea043)";
3070
+ case "warning":
3071
+ return "var(--ai-color-warning, #d29922)";
3072
+ case "error":
3073
+ return "var(--ai-color-error, #e33e33)";
3074
+ default:
3075
+ return "inherit";
3076
+ }
3077
+ }
3078
+ }
3079
+ __legacyDecorateClassTS([
3080
+ property14({ reflect: true })
3081
+ ], AiIcon.prototype, "size", undefined);
3082
+ __legacyDecorateClassTS([
3083
+ property14({ reflect: true })
3084
+ ], AiIcon.prototype, "tone", undefined);
3085
+ AiIcon = __legacyDecorateClassTS([
3086
+ customElement14("ai-icon")
3087
+ ], AiIcon);
3088
+ // src/visual/divider.ts
3089
+ import { LitElement as LitElement15, css as css15, html as html15 } from "lit";
3090
+ import { customElement as customElement15, property as property15 } from "lit/decorators.js";
3091
+ var TONE_OPACITY = {
3092
+ subtle: 0.08,
3093
+ default: 0.16,
3094
+ strong: 0.32
3095
+ };
3096
+
3097
+ class AiDivider extends LitElement15 {
3098
+ constructor() {
3099
+ super(...arguments);
3100
+ this.orientation = "horizontal";
3101
+ this.tone = "default";
3102
+ }
3103
+ static styles = css15`
3104
+ :host {
3105
+ box-sizing: border-box;
3106
+ display: flex;
3107
+ margin: 0;
3108
+ padding: 0;
3109
+ color: var(--text-color, inherit);
3110
+ }
3111
+
3112
+ :host([orientation="horizontal"]) {
3113
+ flex-direction: row;
3114
+ align-items: center;
3115
+ width: 100%;
3116
+ }
3117
+
3118
+ :host([orientation="vertical"]) {
3119
+ flex-direction: column;
3120
+ justify-content: center;
3121
+ height: 100%;
3122
+ align-self: stretch;
3123
+ }
3124
+
3125
+ .line {
3126
+ flex: 1;
3127
+ background: var(--line-color, rgba(128, 128, 128, 0.16));
3128
+ }
3129
+
3130
+ :host([orientation="horizontal"]) .line {
3131
+ height: var(--line-width, 1px);
3132
+ }
3133
+
3134
+ :host([orientation="vertical"]) .line {
3135
+ width: var(--line-width, 1px);
3136
+ }
3137
+
3138
+ ::slotted(*) {
3139
+ padding: 0 var(--label-gap, 0.5rem);
3140
+ white-space: nowrap;
3141
+ }
3142
+
3143
+ :host([orientation="vertical"]) ::slotted(*) {
3144
+ padding: var(--label-gap, 0.5rem) 0;
3145
+ }
3146
+
3147
+ *,
3148
+ *::before,
3149
+ *::after {
3150
+ box-sizing: inherit;
3151
+ }
3152
+ `;
3153
+ render() {
3154
+ return html15`
3155
+ <span class="line" part="line-before"></span>
3156
+ <slot></slot>
3157
+ <span class="line" part="line-after"></span>
3158
+ `;
3159
+ }
3160
+ updated() {
3161
+ const opacity = TONE_OPACITY[this.tone] ?? 0.16;
3162
+ this.style.setProperty("--line-color", `var(--line-color, rgba(128, 128, 128, ${opacity}))`);
3163
+ }
3164
+ }
3165
+ __legacyDecorateClassTS([
3166
+ property15({ reflect: true })
3167
+ ], AiDivider.prototype, "orientation", undefined);
3168
+ __legacyDecorateClassTS([
3169
+ property15({ reflect: true })
3170
+ ], AiDivider.prototype, "tone", undefined);
3171
+ AiDivider = __legacyDecorateClassTS([
3172
+ customElement15("ai-divider")
3173
+ ], AiDivider);
3174
+ // src/native-styles.ts
3175
+ import { css as css16 } from "lit";
3176
+ var nativeStyles = css16`
3177
+ pre {
3178
+ margin: 0;
3179
+ max-height: 240px;
3180
+ overflow: auto;
3181
+ font-family: var(--ai-font-family-mono, monospace);
3182
+ font-size: var(--ai-font-size-caption, 0.75rem);
3183
+ white-space: pre-wrap;
3184
+ }
3185
+
3186
+ a {
3187
+ color: var(--ai-color-accent, #0066cc);
3188
+ text-decoration: underline;
3189
+ }
3190
+
3191
+ time {
3192
+ font-size: inherit;
3193
+ }
3194
+
3195
+ button {
3196
+ cursor: pointer;
3197
+ }
3198
+ `;
3199
+ export {
3200
+ normalizeToolOutput,
3201
+ getToolTone,
3202
+ HasSlotController,
3203
+ AiToolResult,
3204
+ AiToolCall,
3205
+ AiThinking,
3206
+ AiText,
3207
+ AiSurface,
3208
+ AiStatus,
3209
+ AiStack,
3210
+ AiMessage,
3211
+ AiMarkdown,
3212
+ AiIcon,
3213
+ AiEvent,
3214
+ AiDivider,
3215
+ AiConversation,
3216
+ AiBadge,
3217
+ AiAvatar
3218
+ };