@artooi/ag-ui-web-component 0.44.0 → 0.46.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 (187) hide show
  1. package/CHANGELOG.md +182 -1
  2. package/README.md +245 -32
  3. package/dist/ag-ui-web-component.bundle.js +3696 -2798
  4. package/dist/ag-ui-web-component.bundle.js.map +4 -4
  5. package/dist/constants.d.ts +4 -1
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/core/ag_ui_chat.d.ts +28 -8
  8. package/dist/core/ag_ui_chat.d.ts.map +1 -1
  9. package/dist/core/read_flag.d.ts +11 -0
  10. package/dist/core/read_flag.d.ts.map +1 -0
  11. package/dist/core/read_json_attribute.d.ts +15 -0
  12. package/dist/core/read_json_attribute.d.ts.map +1 -0
  13. package/dist/index.js +5084 -3481
  14. package/dist/index.js.map +4 -4
  15. package/dist/tools/tool_catalog.d.ts +5 -0
  16. package/dist/tools/tool_catalog.d.ts.map +1 -1
  17. package/dist/tools/tool_dispatch.d.ts.map +1 -1
  18. package/dist/ui/charts/chart_styles.d.ts +2 -0
  19. package/dist/ui/charts/chart_styles.d.ts.map +1 -0
  20. package/dist/ui/composer/attachment_styles.d.ts +2 -0
  21. package/dist/ui/composer/attachment_styles.d.ts.map +1 -0
  22. package/dist/ui/composer/build_composer.d.ts +30 -0
  23. package/dist/ui/composer/build_composer.d.ts.map +1 -0
  24. package/dist/ui/composer/composer_styles.d.ts +2 -0
  25. package/dist/ui/composer/composer_styles.d.ts.map +1 -0
  26. package/dist/ui/composer/skill_styles.d.ts +2 -0
  27. package/dist/ui/composer/skill_styles.d.ts.map +1 -0
  28. package/dist/ui/history/history_styles.d.ts +2 -0
  29. package/dist/ui/history/history_styles.d.ts.map +1 -0
  30. package/dist/ui/interrupts/approval_styles.d.ts +2 -0
  31. package/dist/ui/interrupts/approval_styles.d.ts.map +1 -0
  32. package/dist/ui/interrupts/confirmation_styles.d.ts +2 -0
  33. package/dist/ui/interrupts/confirmation_styles.d.ts.map +1 -0
  34. package/dist/ui/interrupts/question_styles.d.ts +2 -0
  35. package/dist/ui/interrupts/question_styles.d.ts.map +1 -0
  36. package/dist/ui/placement/collapse_styles.d.ts +2 -0
  37. package/dist/ui/placement/collapse_styles.d.ts.map +1 -0
  38. package/dist/ui/placement/embedded_styles.d.ts +2 -0
  39. package/dist/ui/placement/embedded_styles.d.ts.map +1 -0
  40. package/dist/ui/placement/launcher_styles.d.ts +2 -0
  41. package/dist/ui/placement/launcher_styles.d.ts.map +1 -0
  42. package/dist/ui/placement/page_styles.d.ts +2 -0
  43. package/dist/ui/placement/page_styles.d.ts.map +1 -0
  44. package/dist/ui/placement/panel_placement.d.ts.map +1 -1
  45. package/dist/ui/placement/preset_styles.d.ts +2 -0
  46. package/dist/ui/placement/preset_styles.d.ts.map +1 -0
  47. package/dist/ui/placement/resize_styles.d.ts +2 -0
  48. package/dist/ui/placement/resize_styles.d.ts.map +1 -0
  49. package/dist/ui/placement/sidebar_styles.d.ts +2 -0
  50. package/dist/ui/placement/sidebar_styles.d.ts.map +1 -0
  51. package/dist/ui/placement/small_viewport_styles.d.ts +2 -0
  52. package/dist/ui/placement/small_viewport_styles.d.ts.map +1 -0
  53. package/dist/ui/placement/surface_for.d.ts +74 -0
  54. package/dist/ui/placement/surface_for.d.ts.map +1 -0
  55. package/dist/ui/progress/run_notice_styles.d.ts +2 -0
  56. package/dist/ui/progress/run_notice_styles.d.ts.map +1 -0
  57. package/dist/ui/progress/thoughts_styles.d.ts +2 -0
  58. package/dist/ui/progress/thoughts_styles.d.ts.map +1 -0
  59. package/dist/ui/progress/tool_call_card.d.ts +8 -0
  60. package/dist/ui/progress/tool_call_card.d.ts.map +1 -1
  61. package/dist/ui/progress/tool_group_styles.d.ts +2 -0
  62. package/dist/ui/progress/tool_group_styles.d.ts.map +1 -0
  63. package/dist/ui/progress/tool_step_group.d.ts +47 -0
  64. package/dist/ui/progress/tool_step_group.d.ts.map +1 -0
  65. package/dist/ui/progress/tool_step_styles.d.ts +2 -0
  66. package/dist/ui/progress/tool_step_styles.d.ts.map +1 -0
  67. package/dist/ui/shell/adopt_styles.d.ts +9 -4
  68. package/dist/ui/shell/adopt_styles.d.ts.map +1 -1
  69. package/dist/ui/shell/build_header.d.ts +40 -0
  70. package/dist/ui/shell/build_header.d.ts.map +1 -0
  71. package/dist/ui/shell/build_launcher.d.ts +20 -0
  72. package/dist/ui/shell/build_launcher.d.ts.map +1 -0
  73. package/dist/ui/shell/frame_styles.d.ts +2 -0
  74. package/dist/ui/shell/frame_styles.d.ts.map +1 -0
  75. package/dist/ui/shell/theme_styles.d.ts +2 -0
  76. package/dist/ui/shell/theme_styles.d.ts.map +1 -0
  77. package/dist/ui/shell/token_styles.d.ts +2 -0
  78. package/dist/ui/shell/token_styles.d.ts.map +1 -0
  79. package/dist/ui/styles.d.ts +1 -1
  80. package/dist/ui/styles.d.ts.map +1 -1
  81. package/dist/ui/themes/classic_styles.d.ts +2 -0
  82. package/dist/ui/themes/classic_styles.d.ts.map +1 -0
  83. package/dist/ui/themes/classic_tokens.d.ts +2 -0
  84. package/dist/ui/themes/classic_tokens.d.ts.map +1 -0
  85. package/dist/ui/themes/code_tokens.d.ts +2 -0
  86. package/dist/ui/themes/code_tokens.d.ts.map +1 -0
  87. package/dist/ui/themes/ledger_styles.d.ts +2 -0
  88. package/dist/ui/themes/ledger_styles.d.ts.map +1 -0
  89. package/dist/ui/themes/ledger_tokens.d.ts +2 -0
  90. package/dist/ui/themes/ledger_tokens.d.ts.map +1 -0
  91. package/dist/ui/themes/modern_styles.d.ts +2 -0
  92. package/dist/ui/themes/modern_styles.d.ts.map +1 -0
  93. package/dist/ui/themes/quiet_styles.d.ts +2 -0
  94. package/dist/ui/themes/quiet_styles.d.ts.map +1 -0
  95. package/dist/ui/themes/scheme_styles.d.ts +2 -0
  96. package/dist/ui/themes/scheme_styles.d.ts.map +1 -0
  97. package/dist/ui/themes/soft_styles.d.ts +2 -0
  98. package/dist/ui/themes/soft_styles.d.ts.map +1 -0
  99. package/dist/ui/themes/soft_tokens.d.ts +2 -0
  100. package/dist/ui/themes/soft_tokens.d.ts.map +1 -0
  101. package/dist/ui/themes/theme_hosts.d.ts +15 -0
  102. package/dist/ui/themes/theme_hosts.d.ts.map +1 -0
  103. package/dist/ui/transcript/attachment_chip_styles.d.ts +2 -0
  104. package/dist/ui/transcript/attachment_chip_styles.d.ts.map +1 -0
  105. package/dist/ui/transcript/build_transcript.d.ts +21 -0
  106. package/dist/ui/transcript/build_transcript.d.ts.map +1 -0
  107. package/dist/ui/transcript/greeting_styles.d.ts +2 -0
  108. package/dist/ui/transcript/greeting_styles.d.ts.map +1 -0
  109. package/dist/ui/transcript/groups_tool_steps.d.ts +13 -0
  110. package/dist/ui/transcript/groups_tool_steps.d.ts.map +1 -0
  111. package/dist/ui/transcript/message_action_styles.d.ts +2 -0
  112. package/dist/ui/transcript/message_action_styles.d.ts.map +1 -0
  113. package/dist/ui/transcript/message_styles.d.ts +2 -0
  114. package/dist/ui/transcript/message_styles.d.ts.map +1 -0
  115. package/dist/ui/transcript/transcript.d.ts +16 -1
  116. package/dist/ui/transcript/transcript.d.ts.map +1 -1
  117. package/dist/ui/transcript/transcript_styles.d.ts +2 -0
  118. package/dist/ui/transcript/transcript_styles.d.ts.map +1 -0
  119. package/dist/ui/ui_strings.d.ts +18 -0
  120. package/dist/ui/ui_strings.d.ts.map +1 -1
  121. package/package.json +2 -2
  122. package/src/constants.ts +4 -1
  123. package/src/core/ag_ui_chat.ts +164 -299
  124. package/src/core/read_flag.ts +13 -0
  125. package/src/core/read_json_attribute.ts +30 -0
  126. package/src/tools/tool_catalog.ts +23 -10
  127. package/src/tools/tool_dispatch.ts +26 -11
  128. package/src/ui/charts/chart_block.ts +9 -9
  129. package/src/ui/charts/chart_styles.ts +63 -0
  130. package/src/ui/composer/attachment_styles.ts +71 -0
  131. package/src/ui/composer/build_composer.ts +112 -0
  132. package/src/ui/composer/composer_styles.ts +174 -0
  133. package/src/ui/composer/skill_styles.ts +120 -0
  134. package/src/ui/history/history_styles.ts +484 -0
  135. package/src/ui/interrupts/approval_styles.ts +52 -0
  136. package/src/ui/interrupts/confirmation_styles.ts +114 -0
  137. package/src/ui/interrupts/question_styles.ts +73 -0
  138. package/src/ui/placement/collapse_styles.ts +137 -0
  139. package/src/ui/placement/embedded_styles.ts +14 -0
  140. package/src/ui/placement/launcher_styles.ts +189 -0
  141. package/src/ui/placement/page_styles.ts +47 -0
  142. package/src/ui/placement/panel_placement.ts +3 -12
  143. package/src/ui/placement/preset_styles.ts +33 -0
  144. package/src/ui/placement/resize_styles.ts +186 -0
  145. package/src/ui/placement/sidebar_styles.ts +88 -0
  146. package/src/ui/placement/small_viewport_styles.ts +56 -0
  147. package/src/ui/placement/surface_for.ts +135 -0
  148. package/src/ui/progress/run_notice_styles.ts +52 -0
  149. package/src/ui/progress/thoughts_styles.ts +65 -0
  150. package/src/ui/progress/tool_call_card.ts +11 -0
  151. package/src/ui/progress/tool_group_styles.ts +232 -0
  152. package/src/ui/progress/tool_step_group.ts +269 -0
  153. package/src/ui/progress/tool_step_styles.ts +472 -0
  154. package/src/ui/shell/adopt_styles.ts +11 -5
  155. package/src/ui/shell/build_header.ts +108 -0
  156. package/src/ui/shell/build_launcher.ts +50 -0
  157. package/src/ui/shell/frame_styles.ts +119 -0
  158. package/src/ui/shell/theme_styles.ts +11 -0
  159. package/src/ui/shell/token_styles.ts +406 -0
  160. package/src/ui/styles.ts +104 -3774
  161. package/src/ui/themes/classic_styles.ts +32 -0
  162. package/src/ui/themes/classic_tokens.ts +50 -0
  163. package/src/ui/themes/code_tokens.ts +21 -0
  164. package/src/ui/themes/ledger_styles.ts +168 -0
  165. package/src/ui/themes/ledger_tokens.ts +32 -0
  166. package/src/ui/themes/modern_styles.ts +80 -0
  167. package/src/ui/themes/quiet_styles.ts +115 -0
  168. package/src/ui/themes/scheme_styles.ts +17 -0
  169. package/src/ui/themes/soft_styles.ts +148 -0
  170. package/src/ui/themes/soft_tokens.ts +28 -0
  171. package/src/ui/themes/theme_hosts.ts +14 -0
  172. package/src/ui/transcript/attachment_chip_styles.ts +116 -0
  173. package/src/ui/transcript/build_transcript.ts +67 -0
  174. package/src/ui/transcript/greeting_styles.ts +171 -0
  175. package/src/ui/transcript/groups_tool_steps.ts +16 -0
  176. package/src/ui/transcript/message_action_styles.ts +155 -0
  177. package/src/ui/transcript/message_styles.ts +262 -0
  178. package/src/ui/transcript/transcript.ts +109 -3
  179. package/src/ui/transcript/transcript_styles.ts +140 -0
  180. package/src/ui/ui_strings.ts +31 -0
  181. package/src/version.ts +1 -1
  182. package/dist/ui/placement/is_collapsible_placement.d.ts +0 -18
  183. package/dist/ui/placement/is_collapsible_placement.d.ts.map +0 -1
  184. package/dist/ui/placement/is_draggable_placement.d.ts +0 -9
  185. package/dist/ui/placement/is_draggable_placement.d.ts.map +0 -1
  186. package/src/ui/placement/is_collapsible_placement.ts +0 -19
  187. package/src/ui/placement/is_draggable_placement.ts +0 -23
@@ -0,0 +1,119 @@
1
+ // The panel itself and its header: title, icon holder and header controls.
2
+ export const FRAME_STYLES: string = `
3
+ .chat {
4
+ position: relative;
5
+ display: flex;
6
+ flex-direction: column;
7
+ flex: 1;
8
+ min-height: 0;
9
+ background: var(--_bg);
10
+ border: 1px solid var(--_border);
11
+ border-radius: var(--_panel-radius);
12
+ box-shadow: var(--_shadow);
13
+ overflow: hidden;
14
+ }
15
+
16
+ .header {
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: space-between;
20
+ gap: 8px;
21
+ padding: 10px 14px;
22
+ border-bottom: 1px solid var(--_border);
23
+ background: var(--_header-bg);
24
+ color: var(--_header-fg);
25
+ }
26
+
27
+ /* The header is the panel's title bar: on the placements that let the widget
28
+ be moved it drags the whole thing, matching the launcher's own drag. The
29
+ selector lists those placements rather than asking JS to stamp an attribute,
30
+ because a cursor that appears one frame late reads as a control that only
31
+ sometimes exists. touch-action keeps a finger drag here moving the panel
32
+ instead of scrolling the page behind it. */
33
+ :host(:not([placement])) .header,
34
+ :host([placement=""]) .header,
35
+ :host([placement="floating"]) .header,
36
+ :host([placement="bottom-left"]) .header {
37
+ cursor: move;
38
+ touch-action: none;
39
+ }
40
+
41
+ /* A host that turned the drag off keeps a header that says so. */
42
+ :host([data-launcher-drag="false"]) .header {
43
+ cursor: auto;
44
+ touch-action: auto;
45
+ }
46
+
47
+ /* :host is carried for the specificity, not the scope: the placement rules
48
+ above are a host selector plus a class plus an attribute, and a bare
49
+ .header[data-dragging] loses to them -- silently, because the drag still
50
+ works and only the cursor is wrong. */
51
+ :host .header[data-dragging] {
52
+ cursor: grabbing;
53
+ }
54
+
55
+ /* The cursor inherits, so a control a host slots into the header would show
56
+ the drag cursor over something the drag deliberately ignores. Named to
57
+ match the controls panel_drag steps aside for. */
58
+ .header ::slotted(:is(button, a, input, select, textarea)) {
59
+ cursor: pointer;
60
+ }
61
+
62
+ .header-title {
63
+ flex: 1;
64
+ min-width: 0;
65
+ font-weight: 600;
66
+ overflow: hidden;
67
+ text-overflow: ellipsis;
68
+ white-space: nowrap;
69
+ }
70
+
71
+ /* Header / launcher icon holder: a slot, with a data-icon-url <img>
72
+ fallback, sized via --ag-ui-icon-size. */
73
+ .icon-holder {
74
+ display: inline-flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ flex: none;
78
+ width: var(--_icon-size);
79
+ height: var(--_icon-size);
80
+ line-height: 1;
81
+ }
82
+
83
+ .icon-img {
84
+ width: 100%;
85
+ height: 100%;
86
+ object-fit: contain;
87
+ border-radius: var(--_icon-radius);
88
+ }
89
+
90
+ .header-controls {
91
+ display: flex;
92
+ gap: var(--_header-gap);
93
+ flex: none;
94
+ }
95
+
96
+ .header-btn {
97
+ display: inline-flex;
98
+ flex: 0 0 auto;
99
+ align-items: center;
100
+ justify-content: center;
101
+ box-sizing: border-box;
102
+ width: var(--_header-btn-size);
103
+ height: var(--_header-btn-size);
104
+ border: none;
105
+ background: transparent;
106
+ color: inherit;
107
+ font: inherit;
108
+ line-height: 1;
109
+ padding: 0;
110
+ border-radius: 6px;
111
+ cursor: pointer;
112
+ opacity: 0.85;
113
+ }
114
+
115
+ .header-btn:hover {
116
+ opacity: 1;
117
+ background: rgba(255, 255, 255, 0.18);
118
+ }
119
+ `;
@@ -0,0 +1,11 @@
1
+ // The density presets: token overrides only. The themes live in ui/themes.
2
+ export const THEME_STYLES: string = `
3
+ /* ── Density ────────────────────────────────────────────────────────────── */
4
+ :host([density="compact"]) {
5
+ --_font-size: var(--ag-ui-font-size, 13px);
6
+ --_space: var(--ag-ui-space, 6px);
7
+ --_pad: var(--ag-ui-pad, 10px);
8
+ --_msg-pad: var(--ag-ui-msg-pad, 5px 9px);
9
+ --_msg-radius: var(--ag-ui-msg-radius, 10px);
10
+ }
11
+ `;
@@ -0,0 +1,406 @@
1
+ // Every public --ag-ui-* token read into its private --_* alias on :host.
2
+ // This is where the token defaults are declared; see the block comment below.
3
+ export const TOKEN_STYLES: string = `
4
+ /* ── Token defaults ─────────────────────────────────────────────────────────
5
+ Every public --ag-ui-* token is read here into a private --_* alias, and
6
+ only the alias is used by the rules below.
7
+
8
+ The indirection is what makes ancestor theming work. Declaring the public
9
+ name on :host would set it on the host element, and a value on an element
10
+ always beats one inherited from an ancestor, so tokens put on a wrapper
11
+ would have no effect. Reading the public name with the default as a var()
12
+ fallback leaves it undeclared on the element, so an ancestor's value
13
+ inherits normally while one aimed at the element still wins.
14
+
15
+ Two invariants hold this together:
16
+ 1. No rule outside a :host block may reference a public name
17
+ directly. A public name read outside these blocks resolves to nothing and
18
+ silently drops its declaration rather than erroring, so the miss shows up
19
+ as a missing colour, not a failure.
20
+ 2. Every --_* alias in use is declared here. Aliases inherit like any custom
21
+ property, so an undeclared one would pick up a same-named property from
22
+ the host page; declaring it on :host shields the shadow tree from that. */
23
+ :host {
24
+ /* Colors. The default theme, Quiet: three seeds, and every other shade
25
+ mixed from them in oklch, so a host that sets only --ag-ui-accent (or
26
+ only the background and text) gets a whole widget rethemed. The seeds use
27
+ light-dark, so the scheme word on the theme attribute picks the half;
28
+ see scheme_styles in the themes directory. Every derived shade still
29
+ reads its own public token first, so each stays an override point. */
30
+ color-scheme: light;
31
+ --_bg: var(--ag-ui-bg, light-dark(#ffffff, #161618));
32
+ --_fg: var(--ag-ui-fg, light-dark(#1b1b1d, #ececee));
33
+ --_accent: var(--ag-ui-accent, light-dark(#232326, #f0f0f2));
34
+ --_ink-2: var(--ag-ui-ink-2, color-mix(in oklch, var(--_fg) 78%, var(--_bg)));
35
+ --_ink-3: var(--ag-ui-ink-3, color-mix(in oklch, var(--_fg) 64%, var(--_bg)));
36
+ --_line: var(--ag-ui-line, color-mix(in oklch, var(--_fg) 11%, var(--_bg)));
37
+ --_line-strong: var(--ag-ui-line-strong, color-mix(in oklch, var(--_fg) 20%, var(--_bg)));
38
+ --_wash: var(--ag-ui-wash, color-mix(in oklch, var(--_fg) 4.5%, var(--_bg)));
39
+ --_accent-ink: var(--ag-ui-accent-ink, color-mix(in oklch, var(--_accent) 82%, var(--_fg)));
40
+ --_ring: var(--ag-ui-ring, color-mix(in oklch, var(--_accent) 55%, transparent));
41
+ /* The user's turn is the accent at a whisper. With Quiet's graphite accent
42
+ that is a neutral wash; once a host sets a brand accent it becomes a tint
43
+ of the brand, which is the one thing Soft does that Quiet keeps. */
44
+ --_user-bg: var(--ag-ui-user-bg, color-mix(in oklch, var(--_accent) 12%, var(--_bg)));
45
+ --_user-fg: var(--ag-ui-user-fg, var(--_fg));
46
+ --_assistant-bg: var(--ag-ui-assistant-bg, transparent);
47
+ --_hover: var(--ag-ui-hover, color-mix(in oklch, var(--_fg) 6%, var(--_bg)));
48
+ --_input-bg: var(--ag-ui-input-bg, var(--_bg));
49
+ --_tool-bg: var(--ag-ui-tool-bg, transparent);
50
+ --_tool-fg: var(--ag-ui-tool-fg, var(--_ink-2));
51
+ --_header-bg: var(--ag-ui-header-bg, var(--_bg));
52
+ --_header-fg: var(--ag-ui-header-fg, var(--_fg));
53
+ --_border: var(--ag-ui-border, var(--_line));
54
+ --_radius: var(--ag-ui-radius, 12px);
55
+ /* The panel's own frame, which is the one corner a placement can put against
56
+ the edge of the viewport. The placements that do (page, sidebar, side, full,
57
+ and all but embedded on a small viewport) square this and leave --_radius alone, so
58
+ the answer well and the controls inside the panel stay as round as the
59
+ theme says: none of them meets that edge. */
60
+ /* What a theme sets for the frame; the effective value below is what a
61
+ placement squares, so the two never fight over one property. A host's
62
+ --ag-ui-radius still rounds the frame, as it did before themes gave the
63
+ frame a radius of its own; only the theme's own default differs. */
64
+ --_frame-radius: var(--ag-ui-frame-radius, var(--ag-ui-radius, 14px));
65
+ --_panel-radius: var(--ag-ui-panel-radius, var(--_frame-radius));
66
+
67
+ /* Body text and raised chrome, read only by the code-block copy button.
68
+ The defaults restate what it inherits, so a host that sets neither sees
69
+ no repaint — see the note on .code-copy. */
70
+ --_text: var(--ag-ui-text, var(--_fg));
71
+ --_surface: var(--ag-ui-surface, transparent);
72
+
73
+ /* Message action row: the control box and the mark inside it. The box has a
74
+ floor of 24px so it stays a reliable target at every density. */
75
+ --_action-size: var(--ag-ui-action-size, 28px);
76
+ /* The header's own controls. Sized rather than left to their contents: a row
77
+ of buttons each as wide as the glyph inside it comes out uneven, and uneven
78
+ buttons two pixels apart read as one smudge rather than five controls. */
79
+ --_header-btn-size: var(--ag-ui-header-btn-size, 30px);
80
+ --_header-gap: var(--ag-ui-header-gap, 4px);
81
+ --_action-icon-size: var(--ag-ui-action-icon-size, 15px);
82
+ --_tooltip-bg: var(--ag-ui-tooltip-bg, var(--_fg));
83
+ --_tooltip-fg: var(--ag-ui-tooltip-fg, var(--_bg));
84
+
85
+ /* Text and marks drawn on top of the accent and danger fills. Separate
86
+ tokens because they are not free: a host that themes the accent to a pale
87
+ colour has white-on-pale with no way to correct it, which is the one
88
+ theming change that makes a control unreadable rather than merely off. */
89
+ /* Picked from the accent's own luminance where relative colour syntax is
90
+ supported (the first block after this rule). Without it, this value: the
91
+ scheme's colour, which is the right side for each newer theme's own
92
+ accent in both schemes. Classic and code take white instead, in the
93
+ second block. */
94
+ --_on-accent: var(--ag-ui-on-accent, light-dark(#ffffff, #111111));
95
+ --_on-danger: var(--ag-ui-on-danger, #ffffff);
96
+
97
+ /* Resize grips: the corner squares and the edge strips between them. Wide
98
+ enough to hit without being wide enough to swallow a click on the content
99
+ underneath, and adjustable for a host with a coarser pointer. */
100
+ --_grip-corner: var(--ag-ui-grip-corner, 14px);
101
+ --_grip-edge: var(--ag-ui-grip-edge, 6px);
102
+ --_grip-edge-docked: var(--ag-ui-grip-edge-docked, 8px);
103
+ /* The mark drawn inside a grip, as opposed to the area it answers to. */
104
+ --_grip-mark-length: var(--ag-ui-grip-mark-length, 28px);
105
+ --_grip-mark-thickness: var(--ag-ui-grip-mark-thickness, 3px);
106
+
107
+ /* Status accents for tool-call cards. */
108
+ --_success: var(--ag-ui-success, light-dark(#15803d, #4ade80));
109
+ --_danger: var(--ag-ui-danger, light-dark(#b91c1c, #f87171));
110
+ --_muted: var(--ag-ui-muted, var(--_ink-3));
111
+
112
+ /* Tool-call status icon glyphs (override to re-theme) + spinner speed.
113
+ The pending state is the animated ring; the settled states use these. */
114
+ --_tool-icon-done: var(--ag-ui-tool-icon-done, "✓");
115
+ --_tool-icon-error: var(--ag-ui-tool-icon-error, "✕");
116
+ --_tool-icon-declined: var(--ag-ui-tool-icon-declined, "⊘");
117
+ --_tool-icon-interrupted: var(--ag-ui-tool-icon-interrupted, "◌");
118
+
119
+ /* Disclosure marks on every expandable row. Tokenised for the same reason
120
+ the status icons above are: a host re-theming one set and not the other
121
+ ends up with two vocabularies in one transcript. */
122
+ --_disclosure-collapsed: var(--ag-ui-disclosure-collapsed, "▸");
123
+ --_disclosure-expanded: var(--ag-ui-disclosure-expanded, "▾");
124
+ --_tool-spin-duration: var(--ag-ui-tool-spin-duration, 0.7s);
125
+
126
+ /* Answer well (opt-in via data-answer-well) — boxes a whole assistant turn. */
127
+ --_well-bg: var(--ag-ui-well-bg, transparent);
128
+ --_well-border: var(--ag-ui-well-border, var(--_border));
129
+ --_well-radius: var(--ag-ui-well-radius, var(--_radius));
130
+
131
+ /* Surface — set --ag-ui-shadow: none for a flush, embedded panel. */
132
+ --_frame-shadow: var(--ag-ui-frame-shadow, 0 1px 2px light-dark(rgb(0 0 0 / 0.05), rgb(255 255 255 / 0.04)), 0 12px 32px -16px light-dark(rgb(0 0 0 / 0.22), rgb(0 0 0 / 0.7)));
133
+ --_shadow: var(--ag-ui-shadow, var(--_frame-shadow));
134
+ --_font: var(--ag-ui-font, Inter, ui-sans-serif, system-ui, sans-serif);
135
+ --_serif: var(--ag-ui-serif, Charter, "Bitstream Charter", "Iowan Old Style", Georgia, serif);
136
+ --_font-size: var(--ag-ui-font-size, var(--_text-md));
137
+ /* The type scale. */
138
+ --_text-xs: var(--ag-ui-text-xs, 11.5px);
139
+ --_text-sm: var(--ag-ui-text-sm, 12.5px);
140
+ --_text-md: var(--ag-ui-text-md, 14px);
141
+ --_text-lg: var(--ag-ui-text-lg, 16px);
142
+ --_leading: var(--ag-ui-leading, 1.55);
143
+ --_code-font: var(--ag-ui-code-font, ui-monospace, "SF Mono", Menlo, monospace);
144
+
145
+ /* Header / launcher icon box. */
146
+ --_icon-size: var(--ag-ui-icon-size, 22px);
147
+ --_icon-radius: var(--ag-ui-icon-radius, 4px);
148
+
149
+ /* Composer — one bordered surface holding the field and its tool row. */
150
+ --_composer-radius: var(--ag-ui-composer-radius, 12px);
151
+ --_composer-max-height: var(--ag-ui-composer-max-height, 40vh);
152
+ --_tool-btn-size: var(--ag-ui-tool-btn-size, 30px);
153
+ --_send-size: var(--ag-ui-send-size, 30px);
154
+ --_glyph-size: var(--ag-ui-glyph-size, 18px);
155
+ --_glyph-stroke: var(--ag-ui-glyph-stroke, 1.75);
156
+
157
+ /* How wide a chart is allowed to get. A cap rather than a width: below it
158
+ the chart fills its column, and above it a wider panel is just a wider
159
+ panel. */
160
+ --_chart-max-width: var(--ag-ui-chart-max-width, 480px);
161
+ /* Chart series. Quiet draws in ink and keeps hues for the series past two. */
162
+ --_chart-1: var(--ag-ui-chart-1, var(--_fg));
163
+ --_chart-2: var(--ag-ui-chart-2, color-mix(in oklch, var(--_fg) 32%, var(--_bg)));
164
+ --_chart-3: var(--ag-ui-chart-3, #e0803c);
165
+ --_chart-4: var(--ag-ui-chart-4, #b563d8);
166
+ --_chart-5: var(--ag-ui-chart-5, #d84f6e);
167
+ --_chart-6: var(--ag-ui-chart-6, #3ba7c4);
168
+
169
+ /* Unread badge on the launcher. */
170
+ --_badge-bg: var(--ag-ui-badge-bg, var(--_danger));
171
+ --_badge-fg: var(--ag-ui-badge-fg, #ffffff);
172
+ --_badge-size: var(--ag-ui-badge-size, 18px);
173
+ --_badge-font-size: var(--ag-ui-badge-font-size, 11px);
174
+
175
+ /* The floating launcher a collapsed widget shrinks to. */
176
+ --_launcher-size: var(--ag-ui-launcher-size, 48px);
177
+ --_launcher-bg: var(--ag-ui-launcher-bg, var(--_bg));
178
+ --_launcher-fg: var(--ag-ui-launcher-fg, var(--_fg));
179
+ --_launcher-radius: var(--ag-ui-launcher-radius, 14px);
180
+ --_launcher-icon-size: var(--ag-ui-launcher-icon-size, 22px);
181
+ --_launcher-inset: var(--ag-ui-launcher-inset, auto 0 0 auto);
182
+
183
+ /* Motion. One duration and two curves drive every collapse, expand and
184
+ slide-over, so the widget accelerates and settles as one thing. The
185
+ default curve decelerates into place; the pop curve overshoots slightly,
186
+ for something arriving. */
187
+ --_motion: var(--ag-ui-motion, 0.28s);
188
+ --_ease: var(--ag-ui-ease, cubic-bezier(0.32, 0.72, 0, 1));
189
+ --_ease-pop: var(--ag-ui-ease-pop, cubic-bezier(0.34, 1.36, 0.64, 1));
190
+
191
+ /* Spacing — the density preset overrides these. */
192
+ --_space: var(--ag-ui-space, 10px);
193
+ --_pad: var(--ag-ui-pad, 16px);
194
+ --_msg-pad: var(--ag-ui-msg-pad, 8px 12px);
195
+ --_msg-radius: var(--ag-ui-msg-radius, 12px);
196
+
197
+ /* Edges of the viewport the host has already spent, and that a fixed
198
+ placement must therefore stay out of: a sticky nav bar, a docked toolbar,
199
+ a device's safe area. Four longhands rather than one shorthand because a
200
+ custom property is a token stream and CSS cannot index one -- the height
201
+ arithmetic below needs the vertical pair on its own.
202
+
203
+ Every fixed placement derives from these, and the heights subtract them in
204
+ one place. A host that reserved its chrome by restating --ag-ui-inset per
205
+ placement had to keep --ag-ui-height in step by hand, and forgetting it
206
+ overflowed the panel past the bottom of the screen with nothing to say so.
207
+
208
+ These take env(safe-area-inset-*) verbatim, which is what a full-bleed
209
+ placement wants on a device with a notch. */
210
+ --_viewport-inset-top: var(--ag-ui-viewport-inset-top, 0px);
211
+ --_viewport-inset-right: var(--ag-ui-viewport-inset-right, 0px);
212
+ --_viewport-inset-bottom: var(--ag-ui-viewport-inset-bottom, 0px);
213
+ --_viewport-inset-left: var(--ag-ui-viewport-inset-left, 0px);
214
+ /* What is left of the viewport once the host's chrome is taken out, on both
215
+ axes, so a placement never composes this itself and no host can subtract
216
+ an edge from the position and forget it in the height.
217
+
218
+ Settable in their own right, and that is not only convention: an on-screen
219
+ keyboard changes no viewport-percentage length -- not vh, not dvh, not svh
220
+ -- so a full-bleed panel on a phone has to be told the height rather than
221
+ deriving it. The value to publish there is the visual viewport's. */
222
+ --_viewport-height: var(
223
+ --ag-ui-viewport-height,
224
+ calc(
225
+ min(var(--_visual-viewport-inset-top) + var(--_visual-viewport-height), 100dvh - var(--_viewport-inset-bottom)) -
226
+ var(--_viewport-inset-top) - var(--_keyboard-inset-top)
227
+ )
228
+ );
229
+ /* That default is the host's box cut to the part of the screen the user can
230
+ see: from the top the panel starts at, the host's reserved top moved down
231
+ by the keyboard inset below, to whichever is further up, the bottom of the
232
+ visible area or the host's reserved bottom. Where nothing has measured, the
233
+ visible area is the layout viewport with no pan, and this is the host's
234
+ box exactly.
235
+
236
+ Cut rather than replaced. A measured height used as the whole answer kept
237
+ a bar the host reserved at the top in the position and out of the height,
238
+ so the panel ran that far past the bottom of the visible area, with its
239
+ composer behind the keyboard. */
240
+ /* The measured height of the part of the screen the user can actually see,
241
+ written by the element from the visual viewport and falling back to the
242
+ layout viewport where nothing has measured yet.
243
+
244
+ This is the on-screen keyboard, and it needs measuring because no CSS
245
+ length describes it: an on-screen keyboard has no effect on any
246
+ viewport-percentage unit, so 100vh, 100dvh and 100svh are all the same
247
+ number with the keyboard up as without it. A full-bleed panel sized from
248
+ any of them puts its composer behind the keyboard the user is typing into.
249
+
250
+ Separate from the token above so a host that states the usable height
251
+ outright still wins: the element writes this one inline, and an inline
252
+ value would otherwise outrank the host's own rule.
253
+
254
+ The fallback is dvh rather than vh because the browser's own bars do move
255
+ it, where a keyboard does not. iOS Safari resolves vh to the viewport with
256
+ its bars collapsed, so on a page that does not scroll them away a panel
257
+ sized from it ran under the address bar by the bars' height -- 40px on
258
+ the phone measured -- with a docked composer underneath. dvh is the
259
+ viewport with the bars as they are. */
260
+ --_visual-viewport-height: var(--ag-ui-visual-viewport-height, 100dvh);
261
+ /* How much of the layout viewport is hidden below the visible one, measured
262
+ and written by the element alongside the height above.
263
+
264
+ A shorter panel is not enough on its own for anything anchored to the
265
+ bottom. A floating widget is positioned against the layout viewport, so
266
+ with a keyboard up its bottom edge -- and the launcher that lives at that
267
+ corner -- sits behind the keyboard however tall the panel is. This is what
268
+ lifts it clear. */
269
+ /* Two tokens, for the same reason the height above has two: the element
270
+ writes the measurement inline, and a host that states its own value needs
271
+ a knob that outranks that write rather than one the next write replaces.
272
+ A host wanting no keyboard lift at all sets --ag-ui-keyboard-inset: 0px. */
273
+ --_keyboard-inset: var(--ag-ui-keyboard-inset, var(--_visual-viewport-inset-bottom));
274
+ --_visual-viewport-inset-bottom: var(--ag-ui-visual-viewport-inset-bottom, 0px);
275
+ /* How far a panel anchored at the top moves down for a keyboard, below the
276
+ top the host reserved. With the same two-token shape as the lift above;
277
+ 0px keeps the panel at the host's top.
278
+
279
+ To show the field being typed into, a browser pans the visible area down
280
+ the layout viewport, and a fixed element stays against the layout top, so
281
+ a panel that did not move showed only its lower part, from the pan down,
282
+ with its header off the screen and an empty band under it. It moves by
283
+ what the pan goes past the host's reserved top, not by the whole pan: the
284
+ pan scrolls a bar reserved there away with the rest of the page rather
285
+ than pushing it down, and adding the two put the panel a whole bar below
286
+ the visible area. A corner panel anchored at the bottom does not use this,
287
+ because the band below already accounts for the pan. */
288
+ --_keyboard-inset-top: var(--ag-ui-keyboard-inset-top, max(0px, var(--_visual-viewport-inset-top) - var(--_viewport-inset-top)));
289
+ /* How much of the layout viewport is hidden above the visible one: how far
290
+ the browser panned. Measured and written by the element with the two
291
+ above. */
292
+ --_visual-viewport-inset-top: var(--ag-ui-visual-viewport-inset-top, 0px);
293
+ --_viewport-width: var(
294
+ --ag-ui-viewport-width,
295
+ calc(100vw - var(--_viewport-inset-left) - var(--_viewport-inset-right))
296
+ );
297
+
298
+ /* Layout — override from outside to dock the widget anywhere.
299
+ Set --ag-ui-position: static (and place this element in your own
300
+ grid/flex layout) to embed it in the page flow instead of floating. */
301
+ --_position: var(--ag-ui-position, fixed);
302
+ --_z-index: var(--ag-ui-z-index, 2147483000);
303
+ --_width: var(--ag-ui-width, 380px);
304
+ --_height: var(--ag-ui-height, 560px);
305
+ /* The gutter a resting floating panel keeps between itself and the edge of
306
+ the box the host left free. One number, because the inset below spends it
307
+ and the cap beneath has to know it was spent. */
308
+ --_edge-gutter: var(--ag-ui-edge-gutter, 24px);
309
+ --_inset: var(
310
+ --ag-ui-inset,
311
+ auto calc(var(--_edge-gutter) + var(--_viewport-inset-right))
312
+ calc(var(--_edge-gutter) + var(--_viewport-inset-bottom) + var(--_keyboard-inset)) auto
313
+ );
314
+ /* The cap is what the host left free, less the *one* gutter the inset above
315
+ spends on the anchored edge -- not two, and not none.
316
+
317
+ Two was the first answer and it was felt on one axis only. The arithmetic
318
+ says why: the default panel is 560 tall against a cap of the viewport
319
+ minus 48, which on an 800px screen with a header reserved is 72px of
320
+ headroom, so the height reaches its cap almost immediately; the default
321
+ width is 380 against a cap near 1230, which is 850px nothing ever reaches.
322
+ Once the size is capped a grip cannot grow the panel, so a pull on the
323
+ anchored edge is written as position instead and the panel travels, and a
324
+ pull on the free edge stops a whole gutter short of an edge a drag can
325
+ reach.
326
+
327
+ None was the correction, and it overshot: the panel is anchored bottom-
328
+ right with a gutter already spent there, so a cap of the full usable
329
+ height puts the far edge exactly one gutter outside it. On an 800px screen
330
+ with nothing reserved that is a top of -24 -- the header, and every
331
+ control in it, off the top of the window. Reserve a 120px header and it
332
+ sits inside that instead, which is the one thing the reservation exists to
333
+ prevent.
334
+
335
+ One is the fixed point of both complaints. A resting panel grown to the
336
+ cap runs from the usable near edge to its gutter on the far one, so the
337
+ near edge is reachable by a resize exactly as it is by a drag, and neither
338
+ can put any part of the panel outside the box. */
339
+ --_max-width: var(--ag-ui-max-width, calc(var(--_viewport-width) - var(--_edge-gutter)));
340
+ --_max-height: var(--ag-ui-max-height, calc(var(--_viewport-height) - var(--_edge-gutter)));
341
+ /* Reading-column width for placement="page" (full-bleed, centred content). */
342
+ --_content-max-width: var(--ag-ui-content-max-width, 820px);
343
+ /* The greeting over an empty full-page conversation. The size scales with
344
+ the viewport between a phone and a desktop rather than stepping at a
345
+ breakpoint. */
346
+ --_greeting-font: var(--ag-ui-greeting-font, var(--_font));
347
+ --_greeting-size: var(--ag-ui-greeting-size, clamp(1.5rem, 4vw, 2.25rem));
348
+ /* Slim rail the sidebar placement collapses to. Only that placement reads
349
+ it, but it is declared here so every alias has a default in one place. */
350
+ --_rail-width: var(--ag-ui-rail-width, 52px);
351
+
352
+ position: var(--_position);
353
+ inset: var(--_inset);
354
+ z-index: var(--_z-index);
355
+ width: var(--_width);
356
+ max-width: var(--_max-width);
357
+ height: var(--_height);
358
+ max-height: var(--_max-height);
359
+ display: flex;
360
+ font-family: var(--_font);
361
+ font-size: var(--_font-size);
362
+ color: var(--_fg);
363
+
364
+ /* Surfaces a theme can tint; Quiet leaves them neutral. */
365
+ --_tint: var(--ag-ui-tint, var(--_wash));
366
+ --_tint-2: var(--ag-ui-tint-2, var(--_user-bg));
367
+
368
+ /* Status marks drawn as masks, so they take the colour of their state. */
369
+ --_ico-check: var(--ag-ui-ico-check, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E"));
370
+ --_ico-error: var(--ag-ui-ico-error, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round'%3E%3Ccircle cx='8' cy='8' r='6.2'/%3E%3Cpath d='M8 4.9v3.7M8 11.1v.1'/%3E%3C/svg%3E"));
371
+ --_ico-declined: var(--ag-ui-ico-declined, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round'%3E%3Ccircle cx='8' cy='8' r='6.2'/%3E%3Cpath d='M3.8 12.2l8.4-8.4'/%3E%3C/svg%3E"));
372
+ --_ico-chevron: var(--ag-ui-ico-chevron, url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5l4.5 4.5L6 12.5'/%3E%3C/svg%3E"));
373
+ }
374
+
375
+ /* The colour drawn on the accent, from the accent's own luminance: white on
376
+ an accent darker than WCAG relative luminance 0.179, black on a lighter
377
+ one. That is the crossover where the two give the same contrast, so the
378
+ pick is always the better of the two and never under 4.58:1. A threshold on
379
+ oklch lightness was tried first and missed: indigo 500 sits under the
380
+ threshold that works for greys and took white at 4.47:1. Each channel is
381
+ the same expression over the linear channels, so the result is pure black
382
+ or pure white. A host that sets a mid-tone brand accent in the dark scheme
383
+ would otherwise get the scheme's near-black on it. Relative colour syntax
384
+ with channel arithmetic is Chrome 119, Firefox 128 and Safari 18. Of the
385
+ browsers at or above this package's floor (Chrome 123, Firefox 120, Safari
386
+ 17.5), Firefox 120 to 127 lack it, and Safari 17.5 and 17.6 parse an older
387
+ draft that rejects this expression, so the test below asks for the exact
388
+ expression and those engines keep the fallback above. light-dark needs no
389
+ such test: the floor is set where every engine has it. */
390
+ @supports (color: color(from red srgb-linear clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1) 0 0)) {
391
+ :host {
392
+ --_on-accent: var(--ag-ui-on-accent, color(from var(--_accent) srgb-linear clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1) clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1) clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1)));
393
+ }
394
+ }
395
+
396
+ /* Without relative colour syntax, classic and code keep the white they drew
397
+ before the theme set, not the scheme's colour: their accents are dark in
398
+ both schemes. Only on that path, so where the pick can be computed it is.
399
+ The condition is the one above, negated, and must stay its exact twin. */
400
+ @supports not (color: color(from red srgb-linear clamp(0, (0.179 - (0.2126 * r + 0.7152 * g + 0.0722 * b)) * 100000, 1) 0 0)) {
401
+ :host([theme~="classic"]),
402
+ :host([theme~="code"]) {
403
+ --_on-accent: var(--ag-ui-on-accent, #ffffff);
404
+ }
405
+ }
406
+ `;