@artooi/ag-ui-web-component 0.20.0 → 0.21.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.
- package/CHANGELOG.md +135 -1
- package/README.md +286 -20
- package/dist/ag-ui-web-component.bundle.js +407 -382
- package/dist/ag-ui-web-component.bundle.js.map +4 -4
- package/dist/core/ag_ui_chat.d.ts +82 -1
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/core/create_http_agent.d.ts +9 -0
- package/dist/core/create_http_agent.d.ts.map +1 -1
- package/dist/core/remote_conversation_store.d.ts +8 -1
- package/dist/core/remote_conversation_store.d.ts.map +1 -1
- package/dist/core/run_index.d.ts +8 -1
- package/dist/core/run_index.d.ts.map +1 -1
- package/dist/core/transcribe_audio.d.ts +7 -0
- package/dist/core/transcribe_audio.d.ts.map +1 -1
- package/dist/core/upload_attachment.d.ts +9 -0
- package/dist/core/upload_attachment.d.ts.map +1 -1
- package/dist/core/utils.d.ts +12 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/dom/animations.d.ts +51 -11
- package/dist/dom/animations.d.ts.map +1 -1
- package/dist/dom/dom_driver.d.ts +12 -7
- package/dist/dom/dom_driver.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +766 -430
- package/dist/index.js.map +3 -3
- package/dist/ui/styles.d.ts +1 -1
- package/dist/ui/styles.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/ag_ui_chat.ts +292 -31
- package/src/core/create_http_agent.ts +14 -3
- package/src/core/remote_conversation_store.ts +25 -6
- package/src/core/run_index.ts +27 -5
- package/src/core/transcribe_audio.ts +20 -5
- package/src/core/upload_attachment.ts +13 -0
- package/src/core/utils.ts +18 -0
- package/src/dom/animations.ts +175 -31
- package/src/dom/dom_driver.ts +18 -12
- package/src/index.ts +2 -0
- package/src/ui/styles.ts +377 -352
- package/src/version.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -134,11 +134,29 @@ function setNativeChecked(el, checked) {
|
|
|
134
134
|
|
|
135
135
|
// src/dom/animations.ts
|
|
136
136
|
var ACCENT = "#4f46e5";
|
|
137
|
+
var ACCENT_HALO = "rgba(79, 70, 229, 0.4)";
|
|
138
|
+
var ACCENT_PROPERTY = "--ag-ui-accent";
|
|
137
139
|
function delay(ms) {
|
|
138
140
|
return new Promise((resolve) => {
|
|
139
141
|
setTimeout(resolve, ms);
|
|
140
142
|
});
|
|
141
143
|
}
|
|
144
|
+
function prefersReducedMotion() {
|
|
145
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
146
|
+
}
|
|
147
|
+
function motionDelay(ms) {
|
|
148
|
+
if (ms <= 0 || prefersReducedMotion()) {
|
|
149
|
+
return Promise.resolve();
|
|
150
|
+
}
|
|
151
|
+
return delay(ms);
|
|
152
|
+
}
|
|
153
|
+
function accentColor(el, fallback) {
|
|
154
|
+
const themed = window.getComputedStyle(el).getPropertyValue(ACCENT_PROPERTY).trim();
|
|
155
|
+
return themed === "" ? fallback : themed;
|
|
156
|
+
}
|
|
157
|
+
function ringShadow(el) {
|
|
158
|
+
return `0 0 0 3px ${accentColor(el, ACCENT_HALO)}`;
|
|
159
|
+
}
|
|
142
160
|
async function typeInto(el, value, options = {}) {
|
|
143
161
|
const charDelayMs = options.charDelayMs ?? 35;
|
|
144
162
|
setNativeValue(el, "");
|
|
@@ -156,33 +174,75 @@ async function highlightThenClick(el, options = {}) {
|
|
|
156
174
|
const highlightMs = options.highlightMs ?? 280;
|
|
157
175
|
const previousOutline = el.style.outline;
|
|
158
176
|
const previousOffset = el.style.outlineOffset;
|
|
159
|
-
el.style.outline = `2px solid ${ACCENT}`;
|
|
177
|
+
el.style.outline = `2px solid ${accentColor(el, ACCENT)}`;
|
|
160
178
|
el.style.outlineOffset = "2px";
|
|
161
179
|
await delay(highlightMs);
|
|
162
180
|
el.style.outline = previousOutline;
|
|
163
181
|
el.style.outlineOffset = previousOffset;
|
|
164
182
|
el.click();
|
|
165
183
|
}
|
|
166
|
-
|
|
167
|
-
|
|
184
|
+
var SCROLL_SETTLE_MS = 600;
|
|
185
|
+
var SCROLL_START_MS = 100;
|
|
186
|
+
function scrollIntoCenterView(el, options = {}) {
|
|
187
|
+
const reduced = prefersReducedMotion();
|
|
188
|
+
el.scrollIntoView({
|
|
189
|
+
block: "center",
|
|
190
|
+
inline: "nearest",
|
|
191
|
+
behavior: reduced ? "auto" : "smooth"
|
|
192
|
+
});
|
|
193
|
+
if (reduced) {
|
|
194
|
+
return Promise.resolve();
|
|
195
|
+
}
|
|
196
|
+
return new Promise((resolve) => {
|
|
197
|
+
let timer;
|
|
198
|
+
const settle = () => {
|
|
199
|
+
clearTimeout(timer);
|
|
200
|
+
document.removeEventListener("scroll", started, true);
|
|
201
|
+
document.removeEventListener("scrollend", settle, true);
|
|
202
|
+
resolve();
|
|
203
|
+
};
|
|
204
|
+
const started = () => {
|
|
205
|
+
document.removeEventListener("scroll", started, true);
|
|
206
|
+
clearTimeout(timer);
|
|
207
|
+
timer = setTimeout(settle, options.settleMs ?? SCROLL_SETTLE_MS);
|
|
208
|
+
};
|
|
209
|
+
timer = setTimeout(settle, SCROLL_START_MS);
|
|
210
|
+
document.addEventListener("scroll", started, true);
|
|
211
|
+
document.addEventListener("scrollend", settle, true);
|
|
212
|
+
});
|
|
168
213
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
214
|
+
var FLASH_MS = 1200;
|
|
215
|
+
var FLASH_FADE_RATIO = 1 / 3;
|
|
216
|
+
async function flashRing(el, options, focusByDefault) {
|
|
217
|
+
if (options.focus ?? focusByDefault) {
|
|
218
|
+
el.focus({ preventScroll: true });
|
|
219
|
+
}
|
|
220
|
+
const flashMs = options.flashMs ?? FLASH_MS;
|
|
221
|
+
if (flashMs <= 0) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const previousOutline = el.style.outline;
|
|
225
|
+
const previousOffset = el.style.outlineOffset;
|
|
226
|
+
const previousTransition = el.style.transition;
|
|
227
|
+
const color = options.color ?? accentColor(el, ACCENT);
|
|
228
|
+
el.style.outline = `3px solid ${color}`;
|
|
229
|
+
el.style.outlineOffset = "2px";
|
|
230
|
+
const fadeMs = prefersReducedMotion() ? 0 : Math.round(flashMs * FLASH_FADE_RATIO);
|
|
231
|
+
await delay(flashMs - fadeMs);
|
|
232
|
+
if (fadeMs > 0) {
|
|
233
|
+
el.style.transition = `outline-color ${fadeMs}ms ease-out`;
|
|
234
|
+
el.style.outline = "3px solid transparent";
|
|
235
|
+
await delay(fadeMs);
|
|
236
|
+
}
|
|
237
|
+
el.style.outline = previousOutline;
|
|
238
|
+
el.style.outlineOffset = previousOffset;
|
|
239
|
+
el.style.transition = previousTransition;
|
|
176
240
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
241
|
+
function flash(el, options = {}) {
|
|
242
|
+
return flashRing(el, options, false);
|
|
180
243
|
}
|
|
181
|
-
function
|
|
182
|
-
|
|
183
|
-
return Promise.resolve();
|
|
184
|
-
}
|
|
185
|
-
return delay(ms);
|
|
244
|
+
function focusWithFlash(el, options = {}) {
|
|
245
|
+
return flashRing(el, options, true);
|
|
186
246
|
}
|
|
187
247
|
async function pressThenClick(el, options = {}) {
|
|
188
248
|
const pressMs = options.pressMs ?? 140;
|
|
@@ -191,7 +251,7 @@ async function pressThenClick(el, options = {}) {
|
|
|
191
251
|
const previousShadow = el.style.boxShadow;
|
|
192
252
|
el.style.transition = "transform 80ms ease";
|
|
193
253
|
el.style.transform = "scale(0.96)";
|
|
194
|
-
el.style.boxShadow =
|
|
254
|
+
el.style.boxShadow = ringShadow(el);
|
|
195
255
|
await motionDelay(pressMs);
|
|
196
256
|
el.style.transform = previousTransform;
|
|
197
257
|
el.style.transition = previousTransition;
|
|
@@ -214,7 +274,7 @@ async function selectOption(el, value, options = {}) {
|
|
|
214
274
|
const highlightMs = options.highlightMs ?? 220;
|
|
215
275
|
const previousOutline = el.style.outline;
|
|
216
276
|
const previousOffset = el.style.outlineOffset;
|
|
217
|
-
el.style.outline = `2px solid ${ACCENT}`;
|
|
277
|
+
el.style.outline = `2px solid ${accentColor(el, ACCENT)}`;
|
|
218
278
|
el.style.outlineOffset = "2px";
|
|
219
279
|
await motionDelay(highlightMs);
|
|
220
280
|
setNativeValue(el, option.value);
|
|
@@ -226,7 +286,7 @@ async function selectOption(el, value, options = {}) {
|
|
|
226
286
|
async function toggleControl(el, checked, options = {}) {
|
|
227
287
|
const flashMs = options.flashMs ?? 200;
|
|
228
288
|
const previousShadow = el.style.boxShadow;
|
|
229
|
-
el.style.boxShadow =
|
|
289
|
+
el.style.boxShadow = ringShadow(el);
|
|
230
290
|
await motionDelay(flashMs);
|
|
231
291
|
setNativeChecked(el, checked);
|
|
232
292
|
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4401,151 +4461,186 @@ var SkillsMenu = class {
|
|
|
4401
4461
|
|
|
4402
4462
|
// src/ui/styles.ts
|
|
4403
4463
|
var STYLES = `
|
|
4464
|
+
/* \u2500\u2500 Token defaults \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4465
|
+
Every public --ag-ui-* token is read here into a private --_* alias, and
|
|
4466
|
+
only the alias is used by the rules below.
|
|
4467
|
+
|
|
4468
|
+
The indirection is what makes ancestor theming work. Declaring the public
|
|
4469
|
+
name on :host would set it *on the host element*, and a value on an element
|
|
4470
|
+
always beats one inherited from an ancestor \u2014 so a page that put the tokens
|
|
4471
|
+
on a wrapper would see no effect at all, which is the one thing the API is
|
|
4472
|
+
documented to support. Reading the public name with the default as a var()
|
|
4473
|
+
fallback leaves it undeclared on the element, so an ancestor's value is
|
|
4474
|
+
inherited normally while a value aimed at the element still wins over it.
|
|
4475
|
+
|
|
4476
|
+
Two invariants hold this together:
|
|
4477
|
+
1. No rule outside this file's :host blocks may reference a public name
|
|
4478
|
+
directly. A public name read outside these blocks resolves to nothing and
|
|
4479
|
+
silently drops its declaration rather than erroring, so the miss shows up
|
|
4480
|
+
as a missing colour, not a failure.
|
|
4481
|
+
2. Every --_* alias in use is declared here. Aliases inherit like any custom
|
|
4482
|
+
property, so an undeclared one would pick up a same-named property from
|
|
4483
|
+
the host page; declaring it on :host shields the shadow tree from that. */
|
|
4404
4484
|
:host {
|
|
4405
4485
|
/* Colors */
|
|
4406
|
-
--ag-ui-bg
|
|
4407
|
-
--ag-ui-fg
|
|
4408
|
-
--ag-ui-accent
|
|
4409
|
-
--ag-ui-user-bg
|
|
4410
|
-
--ag-ui-user-fg
|
|
4411
|
-
--ag-ui-assistant-bg
|
|
4412
|
-
--ag-ui-hover
|
|
4413
|
-
--
|
|
4414
|
-
--
|
|
4415
|
-
--ag-ui-tool-fg
|
|
4416
|
-
--ag-ui-header-bg
|
|
4417
|
-
--ag-ui-header-fg
|
|
4418
|
-
--ag-ui-border
|
|
4419
|
-
--ag-ui-radius
|
|
4486
|
+
--_bg: var(--ag-ui-bg, #ffffff);
|
|
4487
|
+
--_fg: var(--ag-ui-fg, #1a1a2e);
|
|
4488
|
+
--_accent: var(--ag-ui-accent, #4f46e5);
|
|
4489
|
+
--_user-bg: var(--ag-ui-user-bg, #4f46e5);
|
|
4490
|
+
--_user-fg: var(--ag-ui-user-fg, #ffffff);
|
|
4491
|
+
--_assistant-bg: var(--ag-ui-assistant-bg, #f1f1f6);
|
|
4492
|
+
--_hover: var(--ag-ui-hover, #e7e7ee);
|
|
4493
|
+
--_input-bg: var(--ag-ui-input-bg, var(--_bg));
|
|
4494
|
+
--_tool-bg: var(--ag-ui-tool-bg, var(--_assistant-bg));
|
|
4495
|
+
--_tool-fg: var(--ag-ui-tool-fg, var(--_accent));
|
|
4496
|
+
--_header-bg: var(--ag-ui-header-bg, var(--_accent));
|
|
4497
|
+
--_header-fg: var(--ag-ui-header-fg, #ffffff);
|
|
4498
|
+
--_border: var(--ag-ui-border, #e2e2ec);
|
|
4499
|
+
--_radius: var(--ag-ui-radius, 12px);
|
|
4500
|
+
|
|
4501
|
+
/* Body text and raised chrome. Both are referenced by the code-block copy
|
|
4502
|
+
button; neither had a default before, so the declarations reading them
|
|
4503
|
+
were dropped and the button fell back to the inherited colour over a
|
|
4504
|
+
transparent box. The defaults below restate exactly that, so this is a
|
|
4505
|
+
rename with no repaint \u2014 see the note on .code-copy. */
|
|
4506
|
+
--_text: var(--ag-ui-text, var(--_fg));
|
|
4507
|
+
--_surface: var(--ag-ui-surface, transparent);
|
|
4420
4508
|
|
|
4421
4509
|
/* Status accents for tool-call cards. */
|
|
4422
|
-
--ag-ui-success
|
|
4423
|
-
--ag-ui-danger
|
|
4424
|
-
--ag-ui-muted
|
|
4510
|
+
--_success: var(--ag-ui-success, #15803d);
|
|
4511
|
+
--_danger: var(--ag-ui-danger, #b91c1c);
|
|
4512
|
+
--_muted: var(--ag-ui-muted, #6b7280);
|
|
4425
4513
|
|
|
4426
4514
|
/* Tool-call status icon glyphs (override to re-theme) + spinner speed.
|
|
4427
4515
|
The pending state is the animated ring; the settled states use these. */
|
|
4428
|
-
--ag-ui-tool-icon-done
|
|
4429
|
-
--ag-ui-tool-icon-error
|
|
4430
|
-
--ag-ui-tool-icon-declined
|
|
4431
|
-
--ag-ui-tool-spin-duration
|
|
4516
|
+
--_tool-icon-done: var(--ag-ui-tool-icon-done, "\u2713");
|
|
4517
|
+
--_tool-icon-error: var(--ag-ui-tool-icon-error, "\u2715");
|
|
4518
|
+
--_tool-icon-declined: var(--ag-ui-tool-icon-declined, "\u2298");
|
|
4519
|
+
--_tool-spin-duration: var(--ag-ui-tool-spin-duration, 0.7s);
|
|
4432
4520
|
|
|
4433
4521
|
/* Answer well (opt-in via data-answer-well) \u2014 boxes a whole assistant turn. */
|
|
4434
|
-
--ag-ui-well-bg
|
|
4435
|
-
--
|
|
4522
|
+
--_well-bg: var(--ag-ui-well-bg, transparent);
|
|
4523
|
+
--_well-border: var(--ag-ui-well-border, var(--_border));
|
|
4436
4524
|
|
|
4437
4525
|
/* Surface \u2014 set --ag-ui-shadow: none for a flush, embedded panel. */
|
|
4438
|
-
--ag-ui-shadow
|
|
4439
|
-
--ag-ui-font
|
|
4440
|
-
--ag-ui-font-size
|
|
4441
|
-
--ag-ui-code-font
|
|
4526
|
+
--_shadow: var(--ag-ui-shadow, 0 12px 32px rgba(20, 20, 50, 0.18));
|
|
4527
|
+
--_font: var(--ag-ui-font, inherit);
|
|
4528
|
+
--_font-size: var(--ag-ui-font-size, 14px);
|
|
4529
|
+
--_code-font: var(--ag-ui-code-font, ui-monospace, "SF Mono", Menlo, monospace);
|
|
4530
|
+
|
|
4531
|
+
/* Header / launcher icon box. */
|
|
4532
|
+
--_icon-size: var(--ag-ui-icon-size, 22px);
|
|
4533
|
+
--_icon-radius: var(--ag-ui-icon-radius, 4px);
|
|
4442
4534
|
|
|
4443
4535
|
/* Spacing \u2014 the density preset overrides these. */
|
|
4444
|
-
--ag-ui-space
|
|
4445
|
-
--ag-ui-pad
|
|
4446
|
-
--ag-ui-msg-pad
|
|
4447
|
-
--ag-ui-msg-radius
|
|
4536
|
+
--_space: var(--ag-ui-space, 10px);
|
|
4537
|
+
--_pad: var(--ag-ui-pad, 16px);
|
|
4538
|
+
--_msg-pad: var(--ag-ui-msg-pad, 8px 12px);
|
|
4539
|
+
--_msg-radius: var(--ag-ui-msg-radius, 14px);
|
|
4448
4540
|
|
|
4449
4541
|
/* Layout \u2014 override from outside to dock the widget anywhere.
|
|
4450
4542
|
Set --ag-ui-position: static (and place this element in your own
|
|
4451
4543
|
grid/flex layout) to embed it in the page flow instead of floating. */
|
|
4452
|
-
--ag-ui-position
|
|
4453
|
-
--ag-ui-z-index
|
|
4454
|
-
--ag-ui-width
|
|
4455
|
-
--ag-ui-height
|
|
4456
|
-
--ag-ui-inset
|
|
4457
|
-
--ag-ui-max-width
|
|
4458
|
-
--ag-ui-max-height
|
|
4544
|
+
--_position: var(--ag-ui-position, fixed);
|
|
4545
|
+
--_z-index: var(--ag-ui-z-index, 2147483000);
|
|
4546
|
+
--_width: var(--ag-ui-width, 380px);
|
|
4547
|
+
--_height: var(--ag-ui-height, 560px);
|
|
4548
|
+
--_inset: var(--ag-ui-inset, auto 24px 24px auto);
|
|
4549
|
+
--_max-width: var(--ag-ui-max-width, calc(100vw - 48px));
|
|
4550
|
+
--_max-height: var(--ag-ui-max-height, calc(100vh - 48px));
|
|
4459
4551
|
/* Reading-column width for placement="page" (full-bleed, centred content). */
|
|
4460
|
-
--ag-ui-content-max-width
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4552
|
+
--_content-max-width: var(--ag-ui-content-max-width, 820px);
|
|
4553
|
+
/* Slim rail the sidebar placement collapses to. Only that placement reads
|
|
4554
|
+
it, but it is declared here so invariant 2 holds for every alias. */
|
|
4555
|
+
--_rail-width: var(--ag-ui-rail-width, 52px);
|
|
4556
|
+
|
|
4557
|
+
position: var(--_position);
|
|
4558
|
+
inset: var(--_inset);
|
|
4559
|
+
z-index: var(--_z-index);
|
|
4560
|
+
width: var(--_width);
|
|
4561
|
+
max-width: var(--_max-width);
|
|
4562
|
+
height: var(--_height);
|
|
4563
|
+
max-height: var(--_max-height);
|
|
4469
4564
|
display: flex;
|
|
4470
|
-
font-family: var(--
|
|
4471
|
-
font-size: var(--
|
|
4472
|
-
color: var(--
|
|
4565
|
+
font-family: var(--_font);
|
|
4566
|
+
font-size: var(--_font-size);
|
|
4567
|
+
color: var(--_fg);
|
|
4473
4568
|
}
|
|
4474
4569
|
|
|
4475
4570
|
/* \u2500\u2500 Themes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
4476
4571
|
Themes only re-set the colour variables; layout/spacing are unaffected.
|
|
4477
4572
|
theme="auto" follows the OS via prefers-color-scheme. */
|
|
4478
4573
|
:host([theme="dark"]) {
|
|
4479
|
-
--ag-ui-bg
|
|
4480
|
-
--ag-ui-fg
|
|
4481
|
-
--ag-ui-assistant-bg
|
|
4482
|
-
--ag-ui-hover
|
|
4483
|
-
--ag-ui-header-bg
|
|
4484
|
-
--ag-ui-header-fg
|
|
4485
|
-
--ag-ui-border
|
|
4486
|
-
--ag-ui-muted
|
|
4487
|
-
--ag-ui-shadow
|
|
4574
|
+
--_bg: var(--ag-ui-bg, #15151f);
|
|
4575
|
+
--_fg: var(--ag-ui-fg, #e8e8f2);
|
|
4576
|
+
--_assistant-bg: var(--ag-ui-assistant-bg, #25253a);
|
|
4577
|
+
--_hover: var(--ag-ui-hover, #303049);
|
|
4578
|
+
--_header-bg: var(--ag-ui-header-bg, #1f1f30);
|
|
4579
|
+
--_header-fg: var(--ag-ui-header-fg, #e8e8f2);
|
|
4580
|
+
--_border: var(--ag-ui-border, #33334a);
|
|
4581
|
+
--_muted: var(--ag-ui-muted, #9aa0b4);
|
|
4582
|
+
--_shadow: var(--ag-ui-shadow, 0 12px 32px rgba(0, 0, 0, 0.5));
|
|
4488
4583
|
}
|
|
4489
4584
|
|
|
4490
4585
|
@media (prefers-color-scheme: dark) {
|
|
4491
4586
|
:host([theme="auto"]) {
|
|
4492
|
-
--ag-ui-bg
|
|
4493
|
-
--ag-ui-fg
|
|
4494
|
-
--ag-ui-assistant-bg
|
|
4495
|
-
--ag-ui-hover
|
|
4496
|
-
--ag-ui-header-bg
|
|
4497
|
-
--ag-ui-header-fg
|
|
4498
|
-
--ag-ui-border
|
|
4499
|
-
--ag-ui-muted
|
|
4500
|
-
--ag-ui-shadow
|
|
4587
|
+
--_bg: var(--ag-ui-bg, #15151f);
|
|
4588
|
+
--_fg: var(--ag-ui-fg, #e8e8f2);
|
|
4589
|
+
--_assistant-bg: var(--ag-ui-assistant-bg, #25253a);
|
|
4590
|
+
--_hover: var(--ag-ui-hover, #303049);
|
|
4591
|
+
--_header-bg: var(--ag-ui-header-bg, #1f1f30);
|
|
4592
|
+
--_header-fg: var(--ag-ui-header-fg, #e8e8f2);
|
|
4593
|
+
--_border: var(--ag-ui-border, #33334a);
|
|
4594
|
+
--_muted: var(--ag-ui-muted, #9aa0b4);
|
|
4595
|
+
--_shadow: var(--ag-ui-shadow, 0 12px 32px rgba(0, 0, 0, 0.5));
|
|
4501
4596
|
}
|
|
4502
4597
|
}
|
|
4503
4598
|
|
|
4504
4599
|
/* A terminal-flavoured "code" theme: dark, monospace, green accent. */
|
|
4505
4600
|
:host([theme="code"]) {
|
|
4506
|
-
--ag-ui-bg
|
|
4507
|
-
--ag-ui-fg
|
|
4508
|
-
--ag-ui-accent
|
|
4509
|
-
--ag-ui-user-bg
|
|
4510
|
-
--ag-ui-assistant-bg
|
|
4511
|
-
--ag-ui-hover
|
|
4512
|
-
--ag-ui-header-bg
|
|
4513
|
-
--ag-ui-header-fg
|
|
4514
|
-
--ag-ui-border
|
|
4515
|
-
--ag-ui-muted
|
|
4516
|
-
--ag-ui-font
|
|
4517
|
-
--ag-ui-shadow
|
|
4601
|
+
--_bg: var(--ag-ui-bg, #0d1117);
|
|
4602
|
+
--_fg: var(--ag-ui-fg, #c9d1d9);
|
|
4603
|
+
--_accent: var(--ag-ui-accent, #3fb950);
|
|
4604
|
+
--_user-bg: var(--ag-ui-user-bg, #238636);
|
|
4605
|
+
--_assistant-bg: var(--ag-ui-assistant-bg, #161b22);
|
|
4606
|
+
--_hover: var(--ag-ui-hover, #21262d);
|
|
4607
|
+
--_header-bg: var(--ag-ui-header-bg, #010409);
|
|
4608
|
+
--_header-fg: var(--ag-ui-header-fg, #c9d1d9);
|
|
4609
|
+
--_border: var(--ag-ui-border, #30363d);
|
|
4610
|
+
--_muted: var(--ag-ui-muted, #8b949e);
|
|
4611
|
+
--_font: var(--ag-ui-font, var(--_code-font));
|
|
4612
|
+
--_shadow: var(--ag-ui-shadow, 0 12px 32px rgba(0, 0, 0, 0.6));
|
|
4518
4613
|
}
|
|
4519
4614
|
|
|
4520
4615
|
/* \u2500\u2500 Density \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
4521
4616
|
:host([density="compact"]) {
|
|
4522
|
-
--ag-ui-font-size
|
|
4523
|
-
--ag-ui-space
|
|
4524
|
-
--ag-ui-pad
|
|
4525
|
-
--ag-ui-msg-pad
|
|
4526
|
-
--ag-ui-msg-radius
|
|
4617
|
+
--_font-size: var(--ag-ui-font-size, 13px);
|
|
4618
|
+
--_space: var(--ag-ui-space, 6px);
|
|
4619
|
+
--_pad: var(--ag-ui-pad, 10px);
|
|
4620
|
+
--_msg-pad: var(--ag-ui-msg-pad, 5px 9px);
|
|
4621
|
+
--_msg-radius: var(--ag-ui-msg-radius, 10px);
|
|
4527
4622
|
}
|
|
4528
4623
|
|
|
4529
4624
|
/* \u2500\u2500 Placement presets \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
4530
4625
|
:host([placement="bottom-left"]) {
|
|
4531
|
-
--ag-ui-inset
|
|
4626
|
+
--_inset: var(--ag-ui-inset, auto auto 24px 24px);
|
|
4532
4627
|
}
|
|
4533
4628
|
|
|
4534
4629
|
:host([placement="side"]) {
|
|
4535
|
-
--ag-ui-inset
|
|
4536
|
-
--ag-ui-width
|
|
4537
|
-
--ag-ui-height
|
|
4538
|
-
--ag-ui-max-height
|
|
4539
|
-
--ag-ui-radius
|
|
4630
|
+
--_inset: var(--ag-ui-inset, 0 0 0 auto);
|
|
4631
|
+
--_width: var(--ag-ui-width, 420px);
|
|
4632
|
+
--_height: var(--ag-ui-height, 100vh);
|
|
4633
|
+
--_max-height: var(--ag-ui-max-height, 100vh);
|
|
4634
|
+
--_radius: var(--ag-ui-radius, 0);
|
|
4540
4635
|
}
|
|
4541
4636
|
|
|
4542
4637
|
:host([placement="full"]) {
|
|
4543
|
-
--ag-ui-inset
|
|
4544
|
-
--ag-ui-width
|
|
4545
|
-
--ag-ui-height
|
|
4546
|
-
--ag-ui-max-width
|
|
4547
|
-
--ag-ui-max-height
|
|
4548
|
-
--ag-ui-radius
|
|
4638
|
+
--_inset: var(--ag-ui-inset, 0);
|
|
4639
|
+
--_width: var(--ag-ui-width, 100vw);
|
|
4640
|
+
--_height: var(--ag-ui-height, 100vh);
|
|
4641
|
+
--_max-width: var(--ag-ui-max-width, 100vw);
|
|
4642
|
+
--_max-height: var(--ag-ui-max-height, 100vh);
|
|
4643
|
+
--_radius: var(--ag-ui-radius, 0);
|
|
4549
4644
|
}
|
|
4550
4645
|
|
|
4551
4646
|
/* Page: full-bleed background with a centred reading column. Unlike
|
|
@@ -4554,85 +4649,20 @@ var STYLES = `
|
|
|
4554
4649
|
padding on the scroll area + composer (no per-row wrapper), so user pills
|
|
4555
4650
|
still right-align and the assistant well spans the column. */
|
|
4556
4651
|
:host([placement="page"]) {
|
|
4557
|
-
--ag-ui-inset
|
|
4558
|
-
--ag-ui-width
|
|
4559
|
-
--ag-ui-height
|
|
4560
|
-
--ag-ui-max-width
|
|
4561
|
-
--ag-ui-max-height
|
|
4562
|
-
--ag-ui-radius
|
|
4652
|
+
--_inset: var(--ag-ui-inset, 0);
|
|
4653
|
+
--_width: var(--ag-ui-width, 100vw);
|
|
4654
|
+
--_height: var(--ag-ui-height, 100vh);
|
|
4655
|
+
--_max-width: var(--ag-ui-max-width, 100vw);
|
|
4656
|
+
--_max-height: var(--ag-ui-max-height, 100vh);
|
|
4657
|
+
--_radius: var(--ag-ui-radius, 0);
|
|
4563
4658
|
}
|
|
4564
4659
|
|
|
4565
4660
|
:host([placement="page"]) .messages {
|
|
4566
|
-
padding-inline: max(var(--
|
|
4661
|
+
padding-inline: max(var(--_pad), calc((100% - var(--_content-max-width)) / 2));
|
|
4567
4662
|
}
|
|
4568
4663
|
|
|
4569
|
-
:host([placement="page"])
|
|
4570
|
-
|
|
4571
|
-
nothing to drag. */
|
|
4572
|
-
.resize-handle {
|
|
4573
|
-
position: absolute;
|
|
4574
|
-
z-index: 2;
|
|
4575
|
-
background: transparent;
|
|
4576
|
-
touch-action: none;
|
|
4577
|
-
}
|
|
4578
|
-
|
|
4579
|
-
.resize-handle:focus-visible {
|
|
4580
|
-
outline: 2px solid var(--ag-ui-accent);
|
|
4581
|
-
outline-offset: -2px;
|
|
4582
|
-
}
|
|
4583
|
-
|
|
4584
|
-
/* The grip sits at the corner the panel grows toward. Which corner that is
|
|
4585
|
-
depends on the host's layout, not on placement, so the element measures it
|
|
4586
|
-
and stamps data-resize-anchor with the edges that stay put.
|
|
4587
|
-
|
|
4588
|
-
Default (bottom-right pinned, the floating case) puts the grip top-left. */
|
|
4589
|
-
.resize-handle {
|
|
4590
|
-
top: 0;
|
|
4591
|
-
left: 0;
|
|
4592
|
-
width: 14px;
|
|
4593
|
-
height: 14px;
|
|
4594
|
-
cursor: nwse-resize;
|
|
4595
|
-
}
|
|
4596
|
-
|
|
4597
|
-
:host([data-resize-anchor~="left"]) .resize-handle {
|
|
4598
|
-
left: auto;
|
|
4599
|
-
right: 0;
|
|
4600
|
-
}
|
|
4601
|
-
|
|
4602
|
-
:host([data-resize-anchor~="top"]) .resize-handle {
|
|
4603
|
-
top: auto;
|
|
4604
|
-
bottom: 0;
|
|
4605
|
-
}
|
|
4606
|
-
|
|
4607
|
-
/* One axis flipped means the drag runs along the other diagonal. */
|
|
4608
|
-
:host([data-resize-anchor="top-right"]) .resize-handle,
|
|
4609
|
-
:host([data-resize-anchor="bottom-left"]) .resize-handle {
|
|
4610
|
-
cursor: nesw-resize;
|
|
4611
|
-
}
|
|
4612
|
-
|
|
4613
|
-
/* Docked: the placement owns the height, so only the inner edge is the user's. */
|
|
4614
|
-
:host([placement="sidebar"]) .resize-handle,
|
|
4615
|
-
:host([placement="side"]) .resize-handle {
|
|
4616
|
-
top: 0;
|
|
4617
|
-
bottom: auto;
|
|
4618
|
-
width: 8px;
|
|
4619
|
-
height: 100%;
|
|
4620
|
-
cursor: ew-resize;
|
|
4621
|
-
}
|
|
4622
|
-
|
|
4623
|
-
/* Full-bleed: nothing to drag. */
|
|
4624
|
-
:host([placement="full"]) .resize-handle,
|
|
4625
|
-
:host([placement="page"]) .resize-handle {
|
|
4626
|
-
display: none;
|
|
4627
|
-
}
|
|
4628
|
-
|
|
4629
|
-
.resize-handle[data-dragging] {
|
|
4630
|
-
background: var(--ag-ui-accent);
|
|
4631
|
-
opacity: 0.35;
|
|
4632
|
-
}
|
|
4633
|
-
|
|
4634
|
-
.input-row {
|
|
4635
|
-
padding-inline: max(12px, calc((100% - var(--ag-ui-content-max-width)) / 2));
|
|
4664
|
+
:host([placement="page"]) .input-row {
|
|
4665
|
+
padding-inline: max(12px, calc((100% - var(--_content-max-width)) / 2));
|
|
4636
4666
|
}
|
|
4637
4667
|
|
|
4638
4668
|
/* The rows between the message list and the composer (skill chips, the
|
|
@@ -4641,12 +4671,12 @@ var STYLES = `
|
|
|
4641
4671
|
margin-based, so each gets its own inline axis nudged by the same gutter. */
|
|
4642
4672
|
:host([placement="page"]) .skill-chips,
|
|
4643
4673
|
:host([placement="page"]) .attachment-tray {
|
|
4644
|
-
padding-inline: max(12px, calc((100% - var(--
|
|
4674
|
+
padding-inline: max(12px, calc((100% - var(--_content-max-width)) / 2));
|
|
4645
4675
|
}
|
|
4646
4676
|
|
|
4647
4677
|
:host([placement="page"]) .skill-palette,
|
|
4648
4678
|
:host([placement="page"]) .skill-hint {
|
|
4649
|
-
margin-inline: max(12px, calc((100% - var(--
|
|
4679
|
+
margin-inline: max(12px, calc((100% - var(--_content-max-width)) / 2));
|
|
4650
4680
|
}
|
|
4651
4681
|
|
|
4652
4682
|
/* In the reading column the assistant well uses the full width; the user
|
|
@@ -4661,17 +4691,16 @@ var STYLES = `
|
|
|
4661
4691
|
--ag-ui-position: static (and place this element in your own layout) for a
|
|
4662
4692
|
host-managed push instead. */
|
|
4663
4693
|
:host([placement="sidebar"]) {
|
|
4664
|
-
--ag-ui-inset
|
|
4665
|
-
--ag-ui-width
|
|
4666
|
-
--ag-ui-height
|
|
4667
|
-
--ag-ui-max-height
|
|
4668
|
-
--ag-ui-radius
|
|
4669
|
-
--ag-ui-rail-width: 52px;
|
|
4694
|
+
--_inset: var(--ag-ui-inset, 0 0 0 auto);
|
|
4695
|
+
--_width: var(--ag-ui-width, 420px);
|
|
4696
|
+
--_height: var(--ag-ui-height, 100vh);
|
|
4697
|
+
--_max-height: var(--ag-ui-max-height, 100vh);
|
|
4698
|
+
--_radius: var(--ag-ui-radius, 0);
|
|
4670
4699
|
transition: width 0.28s ease;
|
|
4671
4700
|
}
|
|
4672
4701
|
|
|
4673
4702
|
:host([placement="sidebar"][data-side="left"]) {
|
|
4674
|
-
--ag-ui-inset
|
|
4703
|
+
--_inset: var(--ag-ui-inset, 0 auto 0 0);
|
|
4675
4704
|
}
|
|
4676
4705
|
|
|
4677
4706
|
:host([placement="sidebar"]) .chat {
|
|
@@ -4682,7 +4711,7 @@ var STYLES = `
|
|
|
4682
4711
|
reveal the rail. Higher specificity than the generic collapse rules, so it
|
|
4683
4712
|
wins regardless of source order. */
|
|
4684
4713
|
:host([placement="sidebar"][collapsed]) {
|
|
4685
|
-
width: var(--
|
|
4714
|
+
width: var(--_rail-width);
|
|
4686
4715
|
height: 100vh;
|
|
4687
4716
|
max-height: 100vh;
|
|
4688
4717
|
bottom: 0;
|
|
@@ -4707,9 +4736,9 @@ var STYLES = `
|
|
|
4707
4736
|
align-items: flex-start;
|
|
4708
4737
|
justify-content: center;
|
|
4709
4738
|
padding-top: 16px;
|
|
4710
|
-
border: 1px solid var(--
|
|
4711
|
-
background: var(--
|
|
4712
|
-
color: var(--
|
|
4739
|
+
border: 1px solid var(--_border);
|
|
4740
|
+
background: var(--_header-bg);
|
|
4741
|
+
color: var(--_header-fg);
|
|
4713
4742
|
cursor: pointer;
|
|
4714
4743
|
}
|
|
4715
4744
|
|
|
@@ -4723,13 +4752,13 @@ var STYLES = `
|
|
|
4723
4752
|
/* Embedded: drop the floating chrome and the high z-index stacking context so
|
|
4724
4753
|
the widget lives in the host's own layout (fixes overlay/z-index clashes). */
|
|
4725
4754
|
:host([placement="embedded"]) {
|
|
4726
|
-
--ag-ui-position
|
|
4727
|
-
--ag-ui-width
|
|
4728
|
-
--ag-ui-height
|
|
4729
|
-
--ag-ui-max-width
|
|
4730
|
-
--ag-ui-max-height
|
|
4731
|
-
--ag-ui-shadow
|
|
4732
|
-
--ag-ui-z-index
|
|
4755
|
+
--_position: var(--ag-ui-position, static);
|
|
4756
|
+
--_width: var(--ag-ui-width, 100%);
|
|
4757
|
+
--_height: var(--ag-ui-height, 100%);
|
|
4758
|
+
--_max-width: var(--ag-ui-max-width, 100%);
|
|
4759
|
+
--_max-height: var(--ag-ui-max-height, 100%);
|
|
4760
|
+
--_shadow: var(--ag-ui-shadow, none);
|
|
4761
|
+
--_z-index: var(--ag-ui-z-index, auto);
|
|
4733
4762
|
}
|
|
4734
4763
|
|
|
4735
4764
|
.chat {
|
|
@@ -4738,10 +4767,10 @@ var STYLES = `
|
|
|
4738
4767
|
flex-direction: column;
|
|
4739
4768
|
flex: 1;
|
|
4740
4769
|
min-height: 0;
|
|
4741
|
-
background: var(--
|
|
4742
|
-
border: 1px solid var(--
|
|
4743
|
-
border-radius: var(--
|
|
4744
|
-
box-shadow: var(--
|
|
4770
|
+
background: var(--_bg);
|
|
4771
|
+
border: 1px solid var(--_border);
|
|
4772
|
+
border-radius: var(--_radius);
|
|
4773
|
+
box-shadow: var(--_shadow);
|
|
4745
4774
|
overflow: hidden;
|
|
4746
4775
|
}
|
|
4747
4776
|
|
|
@@ -4751,9 +4780,9 @@ var STYLES = `
|
|
|
4751
4780
|
justify-content: space-between;
|
|
4752
4781
|
gap: 8px;
|
|
4753
4782
|
padding: 10px 14px;
|
|
4754
|
-
border-bottom: 1px solid var(--
|
|
4755
|
-
background: var(--
|
|
4756
|
-
color: var(--
|
|
4783
|
+
border-bottom: 1px solid var(--_border);
|
|
4784
|
+
background: var(--_header-bg);
|
|
4785
|
+
color: var(--_header-fg);
|
|
4757
4786
|
}
|
|
4758
4787
|
|
|
4759
4788
|
.header-title {
|
|
@@ -4772,8 +4801,8 @@ var STYLES = `
|
|
|
4772
4801
|
align-items: center;
|
|
4773
4802
|
justify-content: center;
|
|
4774
4803
|
flex: none;
|
|
4775
|
-
width: var(--
|
|
4776
|
-
height: var(--
|
|
4804
|
+
width: var(--_icon-size);
|
|
4805
|
+
height: var(--_icon-size);
|
|
4777
4806
|
line-height: 1;
|
|
4778
4807
|
}
|
|
4779
4808
|
|
|
@@ -4781,7 +4810,7 @@ var STYLES = `
|
|
|
4781
4810
|
width: 100%;
|
|
4782
4811
|
height: 100%;
|
|
4783
4812
|
object-fit: contain;
|
|
4784
|
-
border-radius: var(--
|
|
4813
|
+
border-radius: var(--_icon-radius);
|
|
4785
4814
|
}
|
|
4786
4815
|
|
|
4787
4816
|
.header-controls {
|
|
@@ -4833,10 +4862,10 @@ var STYLES = `
|
|
|
4833
4862
|
.messages {
|
|
4834
4863
|
flex: 1;
|
|
4835
4864
|
overflow-y: auto;
|
|
4836
|
-
padding: var(--
|
|
4865
|
+
padding: var(--_pad);
|
|
4837
4866
|
display: flex;
|
|
4838
4867
|
flex-direction: column;
|
|
4839
|
-
gap: var(--
|
|
4868
|
+
gap: var(--_space);
|
|
4840
4869
|
}
|
|
4841
4870
|
|
|
4842
4871
|
/* Empty-state region (slot): centred while it's the only thing in the
|
|
@@ -4844,7 +4873,7 @@ var STYLES = `
|
|
|
4844
4873
|
.empty {
|
|
4845
4874
|
margin: auto;
|
|
4846
4875
|
text-align: center;
|
|
4847
|
-
color: var(--
|
|
4876
|
+
color: var(--_muted);
|
|
4848
4877
|
}
|
|
4849
4878
|
|
|
4850
4879
|
.empty[hidden] {
|
|
@@ -4860,22 +4889,22 @@ var STYLES = `
|
|
|
4860
4889
|
.answer {
|
|
4861
4890
|
display: flex;
|
|
4862
4891
|
flex-direction: column;
|
|
4863
|
-
gap: var(--
|
|
4892
|
+
gap: var(--_space);
|
|
4864
4893
|
align-self: stretch;
|
|
4865
4894
|
min-width: 0;
|
|
4866
4895
|
}
|
|
4867
4896
|
|
|
4868
4897
|
:host([data-answer-well]) .answer {
|
|
4869
|
-
padding: var(--
|
|
4870
|
-
background: var(--
|
|
4871
|
-
border: 1px solid var(--
|
|
4872
|
-
border-radius: var(--
|
|
4898
|
+
padding: var(--_pad);
|
|
4899
|
+
background: var(--_well-bg);
|
|
4900
|
+
border: 1px solid var(--_well-border);
|
|
4901
|
+
border-radius: var(--_radius);
|
|
4873
4902
|
}
|
|
4874
4903
|
|
|
4875
4904
|
.message {
|
|
4876
4905
|
max-width: 80%;
|
|
4877
|
-
padding: var(--
|
|
4878
|
-
border-radius: var(--
|
|
4906
|
+
padding: var(--_msg-pad);
|
|
4907
|
+
border-radius: var(--_msg-radius);
|
|
4879
4908
|
line-height: 1.4;
|
|
4880
4909
|
white-space: pre-wrap;
|
|
4881
4910
|
word-break: break-word;
|
|
@@ -4913,14 +4942,14 @@ var STYLES = `
|
|
|
4913
4942
|
|
|
4914
4943
|
.message--user {
|
|
4915
4944
|
align-self: flex-end;
|
|
4916
|
-
background: var(--
|
|
4917
|
-
color: var(--
|
|
4945
|
+
background: var(--_user-bg);
|
|
4946
|
+
color: var(--_user-fg);
|
|
4918
4947
|
border-bottom-right-radius: 4px;
|
|
4919
4948
|
}
|
|
4920
4949
|
|
|
4921
4950
|
.message--assistant {
|
|
4922
4951
|
align-self: flex-start;
|
|
4923
|
-
background: var(--
|
|
4952
|
+
background: var(--_assistant-bg);
|
|
4924
4953
|
border-bottom-left-radius: 4px;
|
|
4925
4954
|
/* Assistant bubbles hold rendered markdown/HTML, so collapse the source
|
|
4926
4955
|
whitespace the renderer leaves between block tags. */
|
|
@@ -4950,7 +4979,7 @@ var STYLES = `
|
|
|
4950
4979
|
}
|
|
4951
4980
|
|
|
4952
4981
|
.message--assistant a {
|
|
4953
|
-
color: var(--
|
|
4982
|
+
color: var(--_accent);
|
|
4954
4983
|
text-decoration: underline;
|
|
4955
4984
|
}
|
|
4956
4985
|
|
|
@@ -4965,8 +4994,8 @@ var STYLES = `
|
|
|
4965
4994
|
.message--assistant pre {
|
|
4966
4995
|
padding: 8px 10px;
|
|
4967
4996
|
overflow: auto;
|
|
4968
|
-
background: var(--
|
|
4969
|
-
border: 1px solid var(--
|
|
4997
|
+
background: var(--_bg);
|
|
4998
|
+
border: 1px solid var(--_border);
|
|
4970
4999
|
border-radius: 6px;
|
|
4971
5000
|
}
|
|
4972
5001
|
|
|
@@ -4982,6 +5011,13 @@ var STYLES = `
|
|
|
4982
5011
|
position: relative;
|
|
4983
5012
|
}
|
|
4984
5013
|
|
|
5014
|
+
/* This button is the only reader of --ag-ui-surface and --ag-ui-text, and
|
|
5015
|
+
neither had a default until the alias layer gave them one. Both references
|
|
5016
|
+
used to resolve to nothing, dropping the declaration: the background fell
|
|
5017
|
+
back to the initial transparent, and the hover/copied colour to the
|
|
5018
|
+
inherited body colour. The defaults chosen upstream (transparent, and the
|
|
5019
|
+
body foreground) reproduce that, so the rename repaints nothing. A raised
|
|
5020
|
+
surface behind the button is a separate design question. */
|
|
4985
5021
|
.code-copy {
|
|
4986
5022
|
position: absolute;
|
|
4987
5023
|
top: 4px;
|
|
@@ -4990,9 +5026,9 @@ var STYLES = `
|
|
|
4990
5026
|
font: inherit;
|
|
4991
5027
|
font-size: 0.75em;
|
|
4992
5028
|
line-height: 1.6;
|
|
4993
|
-
color: var(--
|
|
4994
|
-
background: var(--
|
|
4995
|
-
border: 1px solid var(--
|
|
5029
|
+
color: var(--_muted);
|
|
5030
|
+
background: var(--_surface);
|
|
5031
|
+
border: 1px solid var(--_border);
|
|
4996
5032
|
border-radius: 4px;
|
|
4997
5033
|
cursor: pointer;
|
|
4998
5034
|
opacity: 0;
|
|
@@ -5007,24 +5043,24 @@ var STYLES = `
|
|
|
5007
5043
|
}
|
|
5008
5044
|
|
|
5009
5045
|
.code-copy:hover {
|
|
5010
|
-
color: var(--
|
|
5011
|
-
background: var(--
|
|
5046
|
+
color: var(--_text);
|
|
5047
|
+
background: var(--_hover);
|
|
5012
5048
|
}
|
|
5013
5049
|
|
|
5014
5050
|
.code-copy[data-state="copied"] {
|
|
5015
5051
|
opacity: 1;
|
|
5016
|
-
color: var(--
|
|
5052
|
+
color: var(--_text);
|
|
5017
5053
|
}
|
|
5018
5054
|
|
|
5019
5055
|
.code-copy[data-state="failed"] {
|
|
5020
5056
|
opacity: 1;
|
|
5021
|
-
color: var(--
|
|
5057
|
+
color: var(--_danger, var(--_text));
|
|
5022
5058
|
}
|
|
5023
5059
|
|
|
5024
5060
|
.message--assistant blockquote {
|
|
5025
5061
|
padding-left: 10px;
|
|
5026
|
-
border-left: 3px solid var(--
|
|
5027
|
-
color: var(--
|
|
5062
|
+
border-left: 3px solid var(--_border);
|
|
5063
|
+
color: var(--_muted);
|
|
5028
5064
|
}
|
|
5029
5065
|
|
|
5030
5066
|
/* Markdown tables. table/thead/tbody/tr/th/td are all in
|
|
@@ -5045,13 +5081,13 @@ var STYLES = `
|
|
|
5045
5081
|
.message--assistant th,
|
|
5046
5082
|
.message--assistant td {
|
|
5047
5083
|
padding: 6px 10px;
|
|
5048
|
-
border: 1px solid var(--
|
|
5084
|
+
border: 1px solid var(--_border);
|
|
5049
5085
|
text-align: left;
|
|
5050
5086
|
vertical-align: top;
|
|
5051
5087
|
}
|
|
5052
5088
|
|
|
5053
5089
|
.message--assistant th {
|
|
5054
|
-
background: var(--
|
|
5090
|
+
background: var(--_hover);
|
|
5055
5091
|
font-weight: 600;
|
|
5056
5092
|
}
|
|
5057
5093
|
|
|
@@ -5061,7 +5097,7 @@ var STYLES = `
|
|
|
5061
5097
|
gap: 4px;
|
|
5062
5098
|
align-items: center;
|
|
5063
5099
|
padding: 12px 14px;
|
|
5064
|
-
background: var(--
|
|
5100
|
+
background: var(--_assistant-bg);
|
|
5065
5101
|
border-radius: 14px;
|
|
5066
5102
|
border-bottom-left-radius: 4px;
|
|
5067
5103
|
}
|
|
@@ -5070,7 +5106,7 @@ var STYLES = `
|
|
|
5070
5106
|
width: 6px;
|
|
5071
5107
|
height: 6px;
|
|
5072
5108
|
border-radius: 50%;
|
|
5073
|
-
background: var(--
|
|
5109
|
+
background: var(--_muted);
|
|
5074
5110
|
animation: ag-ui-pending 1.2s infinite ease-in-out both;
|
|
5075
5111
|
}
|
|
5076
5112
|
|
|
@@ -5103,7 +5139,7 @@ var STYLES = `
|
|
|
5103
5139
|
flex-direction: column;
|
|
5104
5140
|
gap: 4px;
|
|
5105
5141
|
font-size: 12px;
|
|
5106
|
-
color: var(--
|
|
5142
|
+
color: var(--_muted);
|
|
5107
5143
|
}
|
|
5108
5144
|
|
|
5109
5145
|
.thoughts-toggle {
|
|
@@ -5114,7 +5150,7 @@ var STYLES = `
|
|
|
5114
5150
|
font: inherit;
|
|
5115
5151
|
font-size: 12px;
|
|
5116
5152
|
font-weight: 600;
|
|
5117
|
-
color: var(--
|
|
5153
|
+
color: var(--_muted);
|
|
5118
5154
|
cursor: pointer;
|
|
5119
5155
|
}
|
|
5120
5156
|
|
|
@@ -5139,7 +5175,7 @@ var STYLES = `
|
|
|
5139
5175
|
.thoughts-body {
|
|
5140
5176
|
margin: 0;
|
|
5141
5177
|
padding: 4px 0 4px 10px;
|
|
5142
|
-
border-left: 2px solid var(--
|
|
5178
|
+
border-left: 2px solid var(--_border);
|
|
5143
5179
|
max-height: 220px;
|
|
5144
5180
|
overflow: auto;
|
|
5145
5181
|
white-space: pre-wrap;
|
|
@@ -5168,9 +5204,9 @@ var STYLES = `
|
|
|
5168
5204
|
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
5169
5205
|
padding: 8px 10px;
|
|
5170
5206
|
border-radius: 8px;
|
|
5171
|
-
background: var(--
|
|
5172
|
-
border: 1px solid var(--
|
|
5173
|
-
color: var(--
|
|
5207
|
+
background: var(--_tool-bg);
|
|
5208
|
+
border: 1px solid var(--_border);
|
|
5209
|
+
color: var(--_tool-fg);
|
|
5174
5210
|
}
|
|
5175
5211
|
|
|
5176
5212
|
.tool-call-head {
|
|
@@ -5203,10 +5239,10 @@ var STYLES = `
|
|
|
5203
5239
|
|
|
5204
5240
|
/* Pending: a real spinning ring. Speed is tunable; reduced motion stops it. */
|
|
5205
5241
|
.tool-call[data-status="pending"] .tool-call-icon {
|
|
5206
|
-
border: 2px solid var(--
|
|
5242
|
+
border: 2px solid var(--_muted);
|
|
5207
5243
|
border-top-color: transparent;
|
|
5208
5244
|
border-radius: 50%;
|
|
5209
|
-
animation: ag-ui-tool-spin var(--
|
|
5245
|
+
animation: ag-ui-tool-spin var(--_tool-spin-duration) linear infinite;
|
|
5210
5246
|
}
|
|
5211
5247
|
|
|
5212
5248
|
@keyframes ag-ui-tool-spin {
|
|
@@ -5215,18 +5251,18 @@ var STYLES = `
|
|
|
5215
5251
|
|
|
5216
5252
|
/* Settled: a themeable glyph coloured by outcome. */
|
|
5217
5253
|
.tool-call[data-status="done"] .tool-call-icon::before {
|
|
5218
|
-
content: var(--
|
|
5219
|
-
color: var(--
|
|
5254
|
+
content: var(--_tool-icon-done);
|
|
5255
|
+
color: var(--_success);
|
|
5220
5256
|
}
|
|
5221
5257
|
|
|
5222
5258
|
.tool-call[data-status="error"] .tool-call-icon::before {
|
|
5223
|
-
content: var(--
|
|
5224
|
-
color: var(--
|
|
5259
|
+
content: var(--_tool-icon-error);
|
|
5260
|
+
color: var(--_danger);
|
|
5225
5261
|
}
|
|
5226
5262
|
|
|
5227
5263
|
.tool-call[data-status="declined"] .tool-call-icon::before {
|
|
5228
|
-
content: var(--
|
|
5229
|
-
color: var(--
|
|
5264
|
+
content: var(--_tool-icon-declined);
|
|
5265
|
+
color: var(--_muted);
|
|
5230
5266
|
}
|
|
5231
5267
|
|
|
5232
5268
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -5252,19 +5288,19 @@ var STYLES = `
|
|
|
5252
5288
|
font-size: 11px;
|
|
5253
5289
|
font-weight: 600;
|
|
5254
5290
|
background: rgba(127, 127, 127, 0.16);
|
|
5255
|
-
color: var(--
|
|
5291
|
+
color: var(--_muted);
|
|
5256
5292
|
}
|
|
5257
5293
|
|
|
5258
5294
|
.tool-call[data-status="done"] .tool-call-status {
|
|
5259
|
-
color: var(--
|
|
5295
|
+
color: var(--_success);
|
|
5260
5296
|
}
|
|
5261
5297
|
|
|
5262
5298
|
.tool-call[data-status="error"] .tool-call-status {
|
|
5263
|
-
color: var(--
|
|
5299
|
+
color: var(--_danger);
|
|
5264
5300
|
}
|
|
5265
5301
|
|
|
5266
5302
|
.tool-call[data-status="declined"] .tool-call-status {
|
|
5267
|
-
color: var(--
|
|
5303
|
+
color: var(--_muted);
|
|
5268
5304
|
}
|
|
5269
5305
|
|
|
5270
5306
|
.tool-call-body {
|
|
@@ -5286,7 +5322,7 @@ var STYLES = `
|
|
|
5286
5322
|
font-weight: 700;
|
|
5287
5323
|
letter-spacing: 0.06em;
|
|
5288
5324
|
text-transform: uppercase;
|
|
5289
|
-
color: var(--
|
|
5325
|
+
color: var(--_muted);
|
|
5290
5326
|
}
|
|
5291
5327
|
|
|
5292
5328
|
/* The record of a human decision on a gated call. An approved call used to
|
|
@@ -5294,7 +5330,7 @@ var STYLES = `
|
|
|
5294
5330
|
.skill-item-token {
|
|
5295
5331
|
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
5296
5332
|
font-size: 0.92em;
|
|
5297
|
-
color: var(--
|
|
5333
|
+
color: var(--_accent);
|
|
5298
5334
|
margin-right: 6px;
|
|
5299
5335
|
}
|
|
5300
5336
|
|
|
@@ -5302,7 +5338,7 @@ var STYLES = `
|
|
|
5302
5338
|
flex: none;
|
|
5303
5339
|
font-size: 11px;
|
|
5304
5340
|
font-style: italic;
|
|
5305
|
-
color: var(--
|
|
5341
|
+
color: var(--_muted);
|
|
5306
5342
|
}
|
|
5307
5343
|
|
|
5308
5344
|
.tool-call-args,
|
|
@@ -5311,12 +5347,12 @@ var STYLES = `
|
|
|
5311
5347
|
padding: 6px 8px;
|
|
5312
5348
|
max-height: 160px;
|
|
5313
5349
|
overflow: auto;
|
|
5314
|
-
background: var(--
|
|
5315
|
-
border: 1px solid var(--
|
|
5350
|
+
background: var(--_bg);
|
|
5351
|
+
border: 1px solid var(--_border);
|
|
5316
5352
|
border-radius: 6px;
|
|
5317
5353
|
white-space: pre-wrap;
|
|
5318
5354
|
word-break: break-word;
|
|
5319
|
-
color: var(--
|
|
5355
|
+
color: var(--_fg);
|
|
5320
5356
|
}
|
|
5321
5357
|
|
|
5322
5358
|
/* Display modes are pure visibility over one DOM shape, selected from the host
|
|
@@ -5363,7 +5399,7 @@ var STYLES = `
|
|
|
5363
5399
|
background: none;
|
|
5364
5400
|
font: inherit;
|
|
5365
5401
|
font-weight: 600;
|
|
5366
|
-
color: var(--
|
|
5402
|
+
color: var(--_accent);
|
|
5367
5403
|
cursor: pointer;
|
|
5368
5404
|
}
|
|
5369
5405
|
|
|
@@ -5386,13 +5422,12 @@ var STYLES = `
|
|
|
5386
5422
|
}
|
|
5387
5423
|
|
|
5388
5424
|
.resize-handle:focus-visible {
|
|
5389
|
-
outline: 2px solid var(--
|
|
5425
|
+
outline: 2px solid var(--_accent);
|
|
5390
5426
|
outline-offset: -2px;
|
|
5391
5427
|
}
|
|
5392
5428
|
|
|
5393
5429
|
/* The grip sits on the corner opposite the panel's anchor, because a resize
|
|
5394
|
-
measures from whichever edge is not moving.
|
|
5395
|
-
so switching placement moves the grip immediately.
|
|
5430
|
+
measures from whichever edge is not moving.
|
|
5396
5431
|
|
|
5397
5432
|
Default is floating: pinned bottom-right, so the grip is top-left. */
|
|
5398
5433
|
.resize-handle {
|
|
@@ -5403,7 +5438,9 @@ var STYLES = `
|
|
|
5403
5438
|
cursor: nwse-resize;
|
|
5404
5439
|
}
|
|
5405
5440
|
|
|
5406
|
-
/*
|
|
5441
|
+
/* Placement is only the opening guess, and these two rules are all it is good
|
|
5442
|
+
for. Embedded sits in normal flow, pinned top-left, so it grows bottom-right;
|
|
5443
|
+
bottom-left is pinned there, so its free corner is top-right. */
|
|
5407
5444
|
:host([placement="embedded"]) .resize-handle {
|
|
5408
5445
|
top: auto;
|
|
5409
5446
|
left: auto;
|
|
@@ -5412,16 +5449,64 @@ var STYLES = `
|
|
|
5412
5449
|
cursor: nwse-resize;
|
|
5413
5450
|
}
|
|
5414
5451
|
|
|
5415
|
-
/* Pinned bottom-left, so the free corner is top-right. */
|
|
5416
5452
|
:host([placement="bottom-left"]) .resize-handle {
|
|
5417
5453
|
left: auto;
|
|
5418
5454
|
right: 0;
|
|
5419
5455
|
cursor: nesw-resize;
|
|
5420
5456
|
}
|
|
5421
5457
|
|
|
5422
|
-
/*
|
|
5458
|
+
/* Then the measurement corrects it. Which edges are held still belongs to the
|
|
5459
|
+
host's layout rather than to placement -- a floating panel a host right-aligns
|
|
5460
|
+
is anchored bottom-left, not bottom-right -- so the element measures the edges
|
|
5461
|
+
that stay put and stamps them here as "<y>-<x>". Equal specificity to the
|
|
5462
|
+
rules above, so source order is what lets the measured value win.
|
|
5463
|
+
|
|
5464
|
+
These must not be written as [data-resize-anchor~="left"]: the stamped value
|
|
5465
|
+
is one hyphenated token, and ~= matches whitespace-separated words, so such a
|
|
5466
|
+
selector cannot ever match. It did not, which left the grip drawn at the
|
|
5467
|
+
corner that moves while the cursor pointed along the right diagonal.
|
|
5468
|
+
|
|
5469
|
+
Each rule also sets both sides of its axis rather than only the side it
|
|
5470
|
+
moves. One that flipped a single way could not undo a placement guess that
|
|
5471
|
+
had flipped the other, which put the grip on the anchored corner for an
|
|
5472
|
+
embedded panel its host right-aligns. */
|
|
5473
|
+
:host([data-resize-anchor$="-left"]) .resize-handle {
|
|
5474
|
+
left: auto;
|
|
5475
|
+
right: 0;
|
|
5476
|
+
}
|
|
5477
|
+
|
|
5478
|
+
:host([data-resize-anchor$="-right"]) .resize-handle {
|
|
5479
|
+
left: 0;
|
|
5480
|
+
right: auto;
|
|
5481
|
+
}
|
|
5482
|
+
|
|
5483
|
+
:host([data-resize-anchor^="top-"]) .resize-handle {
|
|
5484
|
+
top: auto;
|
|
5485
|
+
bottom: 0;
|
|
5486
|
+
}
|
|
5487
|
+
|
|
5488
|
+
:host([data-resize-anchor^="bottom-"]) .resize-handle {
|
|
5489
|
+
top: 0;
|
|
5490
|
+
bottom: auto;
|
|
5491
|
+
}
|
|
5492
|
+
|
|
5493
|
+
/* One axis flipped means the drag runs along the other diagonal. */
|
|
5494
|
+
:host([data-resize-anchor="top-left"]) .resize-handle,
|
|
5495
|
+
:host([data-resize-anchor="bottom-right"]) .resize-handle {
|
|
5496
|
+
cursor: nwse-resize;
|
|
5497
|
+
}
|
|
5498
|
+
|
|
5499
|
+
:host([data-resize-anchor="top-right"]) .resize-handle,
|
|
5500
|
+
:host([data-resize-anchor="bottom-left"]) .resize-handle {
|
|
5501
|
+
cursor: nesw-resize;
|
|
5502
|
+
}
|
|
5503
|
+
|
|
5504
|
+
/* Docked: the placement owns the height, so only the inner edge is the user's --
|
|
5505
|
+
an edge, not a corner, so this outranks the measured anchor by coming after. */
|
|
5423
5506
|
:host([placement="sidebar"]) .resize-handle,
|
|
5424
5507
|
:host([placement="side"]) .resize-handle {
|
|
5508
|
+
top: 0;
|
|
5509
|
+
bottom: auto;
|
|
5425
5510
|
width: 8px;
|
|
5426
5511
|
height: 100%;
|
|
5427
5512
|
cursor: ew-resize;
|
|
@@ -5440,7 +5525,7 @@ var STYLES = `
|
|
|
5440
5525
|
}
|
|
5441
5526
|
|
|
5442
5527
|
.resize-handle[data-dragging] {
|
|
5443
|
-
background: var(--
|
|
5528
|
+
background: var(--_accent);
|
|
5444
5529
|
opacity: 0.35;
|
|
5445
5530
|
}
|
|
5446
5531
|
|
|
@@ -5448,14 +5533,14 @@ var STYLES = `
|
|
|
5448
5533
|
display: flex;
|
|
5449
5534
|
gap: 8px;
|
|
5450
5535
|
padding: 12px;
|
|
5451
|
-
border-top: 1px solid var(--
|
|
5536
|
+
border-top: 1px solid var(--_border);
|
|
5452
5537
|
}
|
|
5453
5538
|
|
|
5454
5539
|
.input {
|
|
5455
5540
|
flex: 1;
|
|
5456
5541
|
resize: none;
|
|
5457
|
-
background: var(--
|
|
5458
|
-
border: 1px solid var(--
|
|
5542
|
+
background: var(--_input-bg);
|
|
5543
|
+
border: 1px solid var(--_border);
|
|
5459
5544
|
border-radius: 8px;
|
|
5460
5545
|
padding: 8px 10px;
|
|
5461
5546
|
font: inherit;
|
|
@@ -5464,14 +5549,14 @@ var STYLES = `
|
|
|
5464
5549
|
}
|
|
5465
5550
|
|
|
5466
5551
|
.input:focus {
|
|
5467
|
-
border-color: var(--
|
|
5552
|
+
border-color: var(--_accent);
|
|
5468
5553
|
}
|
|
5469
5554
|
|
|
5470
5555
|
.send {
|
|
5471
5556
|
border: none;
|
|
5472
5557
|
border-radius: 8px;
|
|
5473
5558
|
padding: 0 16px;
|
|
5474
|
-
background: var(--
|
|
5559
|
+
background: var(--_accent);
|
|
5475
5560
|
color: #ffffff;
|
|
5476
5561
|
font: inherit;
|
|
5477
5562
|
font-weight: 600;
|
|
@@ -5485,23 +5570,23 @@ var STYLES = `
|
|
|
5485
5570
|
|
|
5486
5571
|
/* The composer button doubles as the Stop control while a run is in flight. */
|
|
5487
5572
|
.send[data-state="running"] {
|
|
5488
|
-
background: var(--
|
|
5573
|
+
background: var(--_muted);
|
|
5489
5574
|
}
|
|
5490
5575
|
|
|
5491
5576
|
/* \u2500\u2500 File attachments \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
5492
5577
|
/* The \u{1F4CE} picker button sits left of the input; hidden until data-attachments-url. */
|
|
5493
5578
|
.attach-btn {
|
|
5494
|
-
border: 1px solid var(--
|
|
5579
|
+
border: 1px solid var(--_border);
|
|
5495
5580
|
border-radius: 8px;
|
|
5496
5581
|
padding: 0 10px;
|
|
5497
|
-
background: var(--
|
|
5582
|
+
background: var(--_input-bg);
|
|
5498
5583
|
color: inherit;
|
|
5499
5584
|
font: inherit;
|
|
5500
5585
|
cursor: pointer;
|
|
5501
5586
|
}
|
|
5502
5587
|
|
|
5503
5588
|
.attach-btn:hover {
|
|
5504
|
-
border-color: var(--
|
|
5589
|
+
border-color: var(--_accent);
|
|
5505
5590
|
}
|
|
5506
5591
|
|
|
5507
5592
|
.attach-input {
|
|
@@ -5514,17 +5599,17 @@ var STYLES = `
|
|
|
5514
5599
|
}
|
|
5515
5600
|
|
|
5516
5601
|
.voice-btn {
|
|
5517
|
-
border: 1px solid var(--
|
|
5602
|
+
border: 1px solid var(--_border);
|
|
5518
5603
|
border-radius: 8px;
|
|
5519
5604
|
padding: 0 10px;
|
|
5520
|
-
background: var(--
|
|
5605
|
+
background: var(--_input-bg);
|
|
5521
5606
|
color: inherit;
|
|
5522
5607
|
font: inherit;
|
|
5523
5608
|
cursor: pointer;
|
|
5524
5609
|
}
|
|
5525
5610
|
|
|
5526
5611
|
.voice-btn:hover {
|
|
5527
|
-
border-color: var(--
|
|
5612
|
+
border-color: var(--_accent);
|
|
5528
5613
|
}
|
|
5529
5614
|
|
|
5530
5615
|
.voice-btn:disabled {
|
|
@@ -5534,8 +5619,8 @@ var STYLES = `
|
|
|
5534
5619
|
|
|
5535
5620
|
/* Recording: a red tint + a gentle pulse so it's clearly "live". */
|
|
5536
5621
|
.voice-btn[data-state="recording"] {
|
|
5537
|
-
border-color: var(--
|
|
5538
|
-
background: var(--
|
|
5622
|
+
border-color: var(--_danger);
|
|
5623
|
+
background: var(--_danger);
|
|
5539
5624
|
color: #ffffff;
|
|
5540
5625
|
animation: ag-ui-voice-pulse 1.2s ease-in-out infinite;
|
|
5541
5626
|
}
|
|
@@ -5578,10 +5663,10 @@ var STYLES = `
|
|
|
5578
5663
|
max-width: 100%;
|
|
5579
5664
|
margin: 2px 0;
|
|
5580
5665
|
padding: 3px 10px;
|
|
5581
|
-
border: 1px dashed var(--
|
|
5666
|
+
border: 1px dashed var(--_border);
|
|
5582
5667
|
border-radius: 999px;
|
|
5583
5668
|
background: transparent;
|
|
5584
|
-
color: var(--
|
|
5669
|
+
color: var(--_muted);
|
|
5585
5670
|
font-size: 0.8em;
|
|
5586
5671
|
line-height: 1.4;
|
|
5587
5672
|
}
|
|
@@ -5602,16 +5687,16 @@ var STYLES = `
|
|
|
5602
5687
|
gap: 6px;
|
|
5603
5688
|
max-width: 100%;
|
|
5604
5689
|
padding: 4px 8px;
|
|
5605
|
-
border: 1px solid var(--
|
|
5690
|
+
border: 1px solid var(--_border);
|
|
5606
5691
|
border-radius: 999px;
|
|
5607
|
-
background: var(--
|
|
5692
|
+
background: var(--_assistant-bg);
|
|
5608
5693
|
font-size: 0.85em;
|
|
5609
5694
|
position: relative;
|
|
5610
5695
|
}
|
|
5611
5696
|
|
|
5612
5697
|
.attachment-chip--error {
|
|
5613
|
-
border-color: var(--
|
|
5614
|
-
color: var(--
|
|
5698
|
+
border-color: var(--_danger);
|
|
5699
|
+
color: var(--_danger);
|
|
5615
5700
|
}
|
|
5616
5701
|
|
|
5617
5702
|
.attachment-chip-name {
|
|
@@ -5622,12 +5707,12 @@ var STYLES = `
|
|
|
5622
5707
|
}
|
|
5623
5708
|
|
|
5624
5709
|
.attachment-chip-size {
|
|
5625
|
-
color: var(--
|
|
5710
|
+
color: var(--_muted);
|
|
5626
5711
|
white-space: nowrap;
|
|
5627
5712
|
}
|
|
5628
5713
|
|
|
5629
5714
|
.attachment-chip--error .attachment-chip-size {
|
|
5630
|
-
color: var(--
|
|
5715
|
+
color: var(--_danger);
|
|
5631
5716
|
}
|
|
5632
5717
|
|
|
5633
5718
|
/* The progress bar fills as the file uploads. */
|
|
@@ -5635,13 +5720,13 @@ var STYLES = `
|
|
|
5635
5720
|
flex-basis: 100%;
|
|
5636
5721
|
height: 3px;
|
|
5637
5722
|
border-radius: 2px;
|
|
5638
|
-
background: var(--
|
|
5723
|
+
background: var(--_border);
|
|
5639
5724
|
overflow: hidden;
|
|
5640
5725
|
}
|
|
5641
5726
|
|
|
5642
5727
|
.attachment-chip-bar-fill {
|
|
5643
5728
|
height: 100%;
|
|
5644
|
-
background: var(--
|
|
5729
|
+
background: var(--_accent);
|
|
5645
5730
|
transition: width 0.15s ease;
|
|
5646
5731
|
}
|
|
5647
5732
|
|
|
@@ -5663,14 +5748,14 @@ var STYLES = `
|
|
|
5663
5748
|
|
|
5664
5749
|
/* A subtle outline while a file is dragged over the shell. */
|
|
5665
5750
|
.chat--dragover {
|
|
5666
|
-
outline: 2px dashed var(--
|
|
5751
|
+
outline: 2px dashed var(--_accent);
|
|
5667
5752
|
outline-offset: -4px;
|
|
5668
5753
|
}
|
|
5669
5754
|
|
|
5670
5755
|
/* Muted "\u23F9 Stopped" line after a cancelled run \u2014 a note, not an error bubble. */
|
|
5671
5756
|
.stopped-note {
|
|
5672
5757
|
align-self: flex-start;
|
|
5673
|
-
color: var(--
|
|
5758
|
+
color: var(--_muted);
|
|
5674
5759
|
font-size: 12px;
|
|
5675
5760
|
padding: 2px 4px;
|
|
5676
5761
|
}
|
|
@@ -5683,14 +5768,14 @@ var STYLES = `
|
|
|
5683
5768
|
flex-direction: column;
|
|
5684
5769
|
gap: 8px;
|
|
5685
5770
|
padding: 12px;
|
|
5686
|
-
background: var(--
|
|
5687
|
-
border: 1px solid var(--
|
|
5771
|
+
background: var(--_bg);
|
|
5772
|
+
border: 1px solid var(--_accent);
|
|
5688
5773
|
border-radius: 10px;
|
|
5689
5774
|
}
|
|
5690
5775
|
|
|
5691
5776
|
.confirm[data-resolved] {
|
|
5692
5777
|
opacity: 0.7;
|
|
5693
|
-
border-color: var(--
|
|
5778
|
+
border-color: var(--_border);
|
|
5694
5779
|
}
|
|
5695
5780
|
|
|
5696
5781
|
.confirm-body {
|
|
@@ -5704,7 +5789,7 @@ var STYLES = `
|
|
|
5704
5789
|
overflow: auto;
|
|
5705
5790
|
font-size: 12px;
|
|
5706
5791
|
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
5707
|
-
background: var(--
|
|
5792
|
+
background: var(--_assistant-bg);
|
|
5708
5793
|
border-radius: 8px;
|
|
5709
5794
|
white-space: pre-wrap;
|
|
5710
5795
|
word-break: break-word;
|
|
@@ -5717,14 +5802,14 @@ var STYLES = `
|
|
|
5717
5802
|
}
|
|
5718
5803
|
|
|
5719
5804
|
.confirm-btn {
|
|
5720
|
-
border: 1px solid var(--
|
|
5805
|
+
border: 1px solid var(--_border);
|
|
5721
5806
|
border-radius: 8px;
|
|
5722
5807
|
padding: 8px 14px;
|
|
5723
5808
|
font: inherit;
|
|
5724
5809
|
font-weight: 600;
|
|
5725
5810
|
cursor: pointer;
|
|
5726
|
-
background: var(--
|
|
5727
|
-
color: var(--
|
|
5811
|
+
background: var(--_bg);
|
|
5812
|
+
color: var(--_fg);
|
|
5728
5813
|
}
|
|
5729
5814
|
|
|
5730
5815
|
.confirm-btn:disabled {
|
|
@@ -5733,8 +5818,8 @@ var STYLES = `
|
|
|
5733
5818
|
}
|
|
5734
5819
|
|
|
5735
5820
|
.confirm-btn--confirm {
|
|
5736
|
-
border-color: var(--
|
|
5737
|
-
background: var(--
|
|
5821
|
+
border-color: var(--_accent);
|
|
5822
|
+
background: var(--_accent);
|
|
5738
5823
|
color: #ffffff;
|
|
5739
5824
|
}
|
|
5740
5825
|
|
|
@@ -5746,14 +5831,14 @@ var STYLES = `
|
|
|
5746
5831
|
flex-direction: column;
|
|
5747
5832
|
gap: 8px;
|
|
5748
5833
|
padding: 12px;
|
|
5749
|
-
background: var(--
|
|
5750
|
-
border: 1px solid var(--
|
|
5834
|
+
background: var(--_bg);
|
|
5835
|
+
border: 1px solid var(--_accent);
|
|
5751
5836
|
border-radius: 10px;
|
|
5752
5837
|
}
|
|
5753
5838
|
|
|
5754
5839
|
.approval[data-resolved] {
|
|
5755
5840
|
opacity: 0.7;
|
|
5756
|
-
border-color: var(--
|
|
5841
|
+
border-color: var(--_border);
|
|
5757
5842
|
}
|
|
5758
5843
|
|
|
5759
5844
|
.approval-body {
|
|
@@ -5767,14 +5852,14 @@ var STYLES = `
|
|
|
5767
5852
|
}
|
|
5768
5853
|
|
|
5769
5854
|
.approval-btn {
|
|
5770
|
-
border: 1px solid var(--
|
|
5855
|
+
border: 1px solid var(--_border);
|
|
5771
5856
|
border-radius: 8px;
|
|
5772
5857
|
padding: 8px 14px;
|
|
5773
5858
|
font: inherit;
|
|
5774
5859
|
font-weight: 600;
|
|
5775
5860
|
cursor: pointer;
|
|
5776
|
-
background: var(--
|
|
5777
|
-
color: var(--
|
|
5861
|
+
background: var(--_bg);
|
|
5862
|
+
color: var(--_fg);
|
|
5778
5863
|
}
|
|
5779
5864
|
|
|
5780
5865
|
.approval-btn:disabled {
|
|
@@ -5783,8 +5868,8 @@ var STYLES = `
|
|
|
5783
5868
|
}
|
|
5784
5869
|
|
|
5785
5870
|
.approval-btn--approve {
|
|
5786
|
-
border-color: var(--
|
|
5787
|
-
background: var(--
|
|
5871
|
+
border-color: var(--_accent);
|
|
5872
|
+
background: var(--_accent);
|
|
5788
5873
|
color: #ffffff;
|
|
5789
5874
|
}
|
|
5790
5875
|
|
|
@@ -5796,14 +5881,14 @@ var STYLES = `
|
|
|
5796
5881
|
flex-direction: column;
|
|
5797
5882
|
gap: 8px;
|
|
5798
5883
|
padding: 12px;
|
|
5799
|
-
background: var(--
|
|
5800
|
-
border: 1px solid var(--
|
|
5884
|
+
background: var(--_bg);
|
|
5885
|
+
border: 1px solid var(--_accent);
|
|
5801
5886
|
border-radius: 10px;
|
|
5802
5887
|
}
|
|
5803
5888
|
|
|
5804
5889
|
.question[data-resolved] {
|
|
5805
5890
|
opacity: 0.7;
|
|
5806
|
-
border-color: var(--
|
|
5891
|
+
border-color: var(--_border);
|
|
5807
5892
|
}
|
|
5808
5893
|
|
|
5809
5894
|
.question-body {
|
|
@@ -5828,9 +5913,9 @@ var STYLES = `
|
|
|
5828
5913
|
width: 100%;
|
|
5829
5914
|
padding: 8px 10px;
|
|
5830
5915
|
font: inherit;
|
|
5831
|
-
color: var(--
|
|
5832
|
-
background: var(--
|
|
5833
|
-
border: 1px solid var(--
|
|
5916
|
+
color: var(--_fg);
|
|
5917
|
+
background: var(--_bg);
|
|
5918
|
+
border: 1px solid var(--_border);
|
|
5834
5919
|
border-radius: 8px;
|
|
5835
5920
|
}
|
|
5836
5921
|
|
|
@@ -5844,13 +5929,13 @@ var STYLES = `
|
|
|
5844
5929
|
}
|
|
5845
5930
|
|
|
5846
5931
|
.question-btn {
|
|
5847
|
-
border: 1px solid var(--
|
|
5932
|
+
border: 1px solid var(--_accent);
|
|
5848
5933
|
border-radius: 8px;
|
|
5849
5934
|
padding: 8px 14px;
|
|
5850
5935
|
font: inherit;
|
|
5851
5936
|
font-weight: 600;
|
|
5852
5937
|
cursor: pointer;
|
|
5853
|
-
background: var(--
|
|
5938
|
+
background: var(--_accent);
|
|
5854
5939
|
color: #ffffff;
|
|
5855
5940
|
}
|
|
5856
5941
|
|
|
@@ -5868,18 +5953,18 @@ var STYLES = `
|
|
|
5868
5953
|
}
|
|
5869
5954
|
|
|
5870
5955
|
.skill-chip {
|
|
5871
|
-
border: 1px solid var(--
|
|
5956
|
+
border: 1px solid var(--_border);
|
|
5872
5957
|
border-radius: 999px;
|
|
5873
5958
|
padding: 4px 12px;
|
|
5874
5959
|
font: inherit;
|
|
5875
5960
|
font-size: 0.9em;
|
|
5876
5961
|
cursor: pointer;
|
|
5877
|
-
background: var(--
|
|
5878
|
-
color: var(--
|
|
5962
|
+
background: var(--_assistant-bg);
|
|
5963
|
+
color: var(--_fg);
|
|
5879
5964
|
}
|
|
5880
5965
|
|
|
5881
5966
|
.skill-chip:hover {
|
|
5882
|
-
border-color: var(--
|
|
5967
|
+
border-color: var(--_accent);
|
|
5883
5968
|
}
|
|
5884
5969
|
|
|
5885
5970
|
.skill-palette {
|
|
@@ -5888,8 +5973,8 @@ var STYLES = `
|
|
|
5888
5973
|
flex-direction: column;
|
|
5889
5974
|
max-height: 220px;
|
|
5890
5975
|
overflow: auto;
|
|
5891
|
-
background: var(--
|
|
5892
|
-
border: 1px solid var(--
|
|
5976
|
+
background: var(--_bg);
|
|
5977
|
+
border: 1px solid var(--_border);
|
|
5893
5978
|
border-radius: 8px;
|
|
5894
5979
|
box-shadow: 0 8px 24px rgba(20, 20, 50, 0.16);
|
|
5895
5980
|
}
|
|
@@ -5905,11 +5990,11 @@ var STYLES = `
|
|
|
5905
5990
|
font: inherit;
|
|
5906
5991
|
text-align: left;
|
|
5907
5992
|
cursor: pointer;
|
|
5908
|
-
color: var(--
|
|
5993
|
+
color: var(--_fg);
|
|
5909
5994
|
}
|
|
5910
5995
|
|
|
5911
5996
|
.skill-item[aria-selected="true"] {
|
|
5912
|
-
background: var(--
|
|
5997
|
+
background: var(--_assistant-bg);
|
|
5913
5998
|
}
|
|
5914
5999
|
|
|
5915
6000
|
.skill-item-title {
|
|
@@ -5918,7 +6003,7 @@ var STYLES = `
|
|
|
5918
6003
|
|
|
5919
6004
|
.skill-item-desc {
|
|
5920
6005
|
font-size: 0.85em;
|
|
5921
|
-
color: var(--
|
|
6006
|
+
color: var(--_muted);
|
|
5922
6007
|
}
|
|
5923
6008
|
|
|
5924
6009
|
/* The hint sits directly above the composer's top border, so a zero bottom
|
|
@@ -5927,7 +6012,7 @@ var STYLES = `
|
|
|
5927
6012
|
margin: 8px 12px;
|
|
5928
6013
|
font-size: 0.85em;
|
|
5929
6014
|
line-height: 1.4;
|
|
5930
|
-
color: var(--
|
|
6015
|
+
color: var(--_danger);
|
|
5931
6016
|
}
|
|
5932
6017
|
|
|
5933
6018
|
/* Chat-history drawer \u2014 a slide-over within the chat panel. */
|
|
@@ -5951,9 +6036,9 @@ var STYLES = `
|
|
|
5951
6036
|
flex-direction: column;
|
|
5952
6037
|
gap: 0.25rem;
|
|
5953
6038
|
padding: 0.5rem;
|
|
5954
|
-
border: 1px solid var(--
|
|
6039
|
+
border: 1px solid var(--_border);
|
|
5955
6040
|
border-radius: 0.5rem;
|
|
5956
|
-
background: var(--
|
|
6041
|
+
background: var(--_assistant-bg);
|
|
5957
6042
|
box-shadow: 0 6px 24px rgb(0 0 0 / 12%);
|
|
5958
6043
|
max-height: 60%;
|
|
5959
6044
|
overflow-y: auto;
|
|
@@ -5984,7 +6069,7 @@ var STYLES = `
|
|
|
5984
6069
|
}
|
|
5985
6070
|
|
|
5986
6071
|
.checkpoint-row:hover {
|
|
5987
|
-
background: var(--
|
|
6072
|
+
background: var(--_hover);
|
|
5988
6073
|
}
|
|
5989
6074
|
|
|
5990
6075
|
.checkpoint-label {
|
|
@@ -5999,7 +6084,7 @@ var STYLES = `
|
|
|
5999
6084
|
font-size: 0.6875rem;
|
|
6000
6085
|
padding: 0 0.375rem;
|
|
6001
6086
|
border-radius: 999px;
|
|
6002
|
-
background: var(--
|
|
6087
|
+
background: var(--_hover);
|
|
6003
6088
|
opacity: 0.8;
|
|
6004
6089
|
}
|
|
6005
6090
|
|
|
@@ -6008,14 +6093,14 @@ var STYLES = `
|
|
|
6008
6093
|
font-size: 0.75rem;
|
|
6009
6094
|
cursor: pointer;
|
|
6010
6095
|
padding: 0.125rem 0.5rem;
|
|
6011
|
-
border: 1px solid var(--
|
|
6096
|
+
border: 1px solid var(--_border);
|
|
6012
6097
|
border-radius: 0.375rem;
|
|
6013
6098
|
background: transparent;
|
|
6014
6099
|
color: inherit;
|
|
6015
6100
|
}
|
|
6016
6101
|
|
|
6017
6102
|
.checkpoint-action:hover {
|
|
6018
|
-
background: var(--
|
|
6103
|
+
background: var(--_hover);
|
|
6019
6104
|
}
|
|
6020
6105
|
|
|
6021
6106
|
.drawer-backdrop {
|
|
@@ -6030,9 +6115,9 @@ var STYLES = `
|
|
|
6030
6115
|
flex-direction: column;
|
|
6031
6116
|
width: min(300px, 85%);
|
|
6032
6117
|
height: 100%;
|
|
6033
|
-
background: var(--
|
|
6034
|
-
border-right: 1px solid var(--
|
|
6035
|
-
box-shadow: var(--
|
|
6118
|
+
background: var(--_bg);
|
|
6119
|
+
border-right: 1px solid var(--_border);
|
|
6120
|
+
box-shadow: var(--_shadow);
|
|
6036
6121
|
overflow: hidden;
|
|
6037
6122
|
}
|
|
6038
6123
|
|
|
@@ -6040,9 +6125,9 @@ var STYLES = `
|
|
|
6040
6125
|
display: flex;
|
|
6041
6126
|
align-items: center;
|
|
6042
6127
|
justify-content: space-between;
|
|
6043
|
-
gap: var(--
|
|
6044
|
-
padding: var(--
|
|
6045
|
-
border-bottom: 1px solid var(--
|
|
6128
|
+
gap: var(--_space);
|
|
6129
|
+
padding: var(--_pad);
|
|
6130
|
+
border-bottom: 1px solid var(--_border);
|
|
6046
6131
|
}
|
|
6047
6132
|
|
|
6048
6133
|
.drawer-title {
|
|
@@ -6050,10 +6135,10 @@ var STYLES = `
|
|
|
6050
6135
|
}
|
|
6051
6136
|
|
|
6052
6137
|
.drawer-new {
|
|
6053
|
-
border: 1px solid var(--
|
|
6054
|
-
border-radius: var(--
|
|
6055
|
-
background: var(--
|
|
6056
|
-
color: var(--
|
|
6138
|
+
border: 1px solid var(--_border);
|
|
6139
|
+
border-radius: var(--_radius);
|
|
6140
|
+
background: var(--_bg);
|
|
6141
|
+
color: var(--_accent);
|
|
6057
6142
|
padding: 4px 10px;
|
|
6058
6143
|
font: inherit;
|
|
6059
6144
|
font-size: 0.85em;
|
|
@@ -6067,19 +6152,19 @@ var STYLES = `
|
|
|
6067
6152
|
}
|
|
6068
6153
|
|
|
6069
6154
|
.drawer-empty {
|
|
6070
|
-
padding: var(--
|
|
6155
|
+
padding: var(--_pad);
|
|
6071
6156
|
font-size: 0.9em;
|
|
6072
|
-
color: var(--
|
|
6157
|
+
color: var(--_muted);
|
|
6073
6158
|
}
|
|
6074
6159
|
|
|
6075
6160
|
.drawer-row {
|
|
6076
6161
|
display: flex;
|
|
6077
6162
|
align-items: stretch;
|
|
6078
|
-
border-bottom: 1px solid var(--
|
|
6163
|
+
border-bottom: 1px solid var(--_border);
|
|
6079
6164
|
}
|
|
6080
6165
|
|
|
6081
6166
|
.drawer-row--active {
|
|
6082
|
-
background: var(--
|
|
6167
|
+
background: var(--_assistant-bg);
|
|
6083
6168
|
}
|
|
6084
6169
|
|
|
6085
6170
|
.drawer-row-select {
|
|
@@ -6106,12 +6191,12 @@ var STYLES = `
|
|
|
6106
6191
|
|
|
6107
6192
|
.drawer-row-time {
|
|
6108
6193
|
font-size: 0.72em;
|
|
6109
|
-
color: var(--
|
|
6194
|
+
color: var(--_muted);
|
|
6110
6195
|
}
|
|
6111
6196
|
|
|
6112
6197
|
.drawer-row-preview {
|
|
6113
6198
|
font-size: 0.8em;
|
|
6114
|
-
color: var(--
|
|
6199
|
+
color: var(--_muted);
|
|
6115
6200
|
overflow: hidden;
|
|
6116
6201
|
white-space: nowrap;
|
|
6117
6202
|
text-overflow: ellipsis;
|
|
@@ -6128,7 +6213,7 @@ var STYLES = `
|
|
|
6128
6213
|
.drawer-row-delete {
|
|
6129
6214
|
border: none;
|
|
6130
6215
|
background: none;
|
|
6131
|
-
color: var(--
|
|
6216
|
+
color: var(--_muted);
|
|
6132
6217
|
font-size: 0.9em;
|
|
6133
6218
|
padding: 4px;
|
|
6134
6219
|
cursor: pointer;
|
|
@@ -6139,10 +6224,10 @@ var STYLES = `
|
|
|
6139
6224
|
min-width: 0;
|
|
6140
6225
|
margin: 6px 10px;
|
|
6141
6226
|
padding: 4px 8px;
|
|
6142
|
-
border: 1px solid var(--
|
|
6227
|
+
border: 1px solid var(--_accent);
|
|
6143
6228
|
border-radius: 6px;
|
|
6144
|
-
background: var(--
|
|
6145
|
-
color: var(--
|
|
6229
|
+
background: var(--_input-bg);
|
|
6230
|
+
color: var(--_fg);
|
|
6146
6231
|
font: inherit;
|
|
6147
6232
|
}
|
|
6148
6233
|
|
|
@@ -6155,13 +6240,13 @@ var STYLES = `
|
|
|
6155
6240
|
}
|
|
6156
6241
|
|
|
6157
6242
|
.drawer-confirm-label {
|
|
6158
|
-
color: var(--
|
|
6243
|
+
color: var(--_danger);
|
|
6159
6244
|
}
|
|
6160
6245
|
|
|
6161
6246
|
.drawer-confirm-yes {
|
|
6162
6247
|
border: none;
|
|
6163
6248
|
border-radius: 6px;
|
|
6164
|
-
background: var(--
|
|
6249
|
+
background: var(--_danger);
|
|
6165
6250
|
color: #ffffff;
|
|
6166
6251
|
padding: 3px 10px;
|
|
6167
6252
|
font: inherit;
|
|
@@ -6169,7 +6254,7 @@ var STYLES = `
|
|
|
6169
6254
|
}
|
|
6170
6255
|
|
|
6171
6256
|
.drawer-confirm-no {
|
|
6172
|
-
border: 1px solid var(--
|
|
6257
|
+
border: 1px solid var(--_border);
|
|
6173
6258
|
border-radius: 6px;
|
|
6174
6259
|
background: none;
|
|
6175
6260
|
color: inherit;
|
|
@@ -7232,6 +7317,13 @@ function truncate(text2, limit) {
|
|
|
7232
7317
|
|
|
7233
7318
|
// src/core/create_http_agent.ts
|
|
7234
7319
|
import { HttpAgent } from "@ag-ui/client";
|
|
7320
|
+
|
|
7321
|
+
// src/core/utils.ts
|
|
7322
|
+
function withCredentials(init, credentials) {
|
|
7323
|
+
return credentials === void 0 ? init : { ...init, credentials };
|
|
7324
|
+
}
|
|
7325
|
+
|
|
7326
|
+
// src/core/create_http_agent.ts
|
|
7235
7327
|
function createHttpAgent(options) {
|
|
7236
7328
|
return new HttpAgent({
|
|
7237
7329
|
url: options.endpoint,
|
|
@@ -7242,17 +7334,18 @@ function createHttpAgent(options) {
|
|
|
7242
7334
|
// "Illegal invocation" in browsers. Wrap it so `fetch` is always called as
|
|
7243
7335
|
// a free function with the correct receiver. The wrapper also overlays
|
|
7244
7336
|
// `getHeaders()` per request, so header rotation (CSRF, short-lived JWT)
|
|
7245
|
-
// reaches the stream even though the agent instance is cached
|
|
7337
|
+
// reaches the stream even though the agent instance is cached, and applies
|
|
7338
|
+
// the configured cookie policy — the agent's own config has no seam for it.
|
|
7246
7339
|
fetch: (url, init) => {
|
|
7247
7340
|
const fresh = options.getHeaders?.();
|
|
7248
7341
|
if (fresh === void 0) {
|
|
7249
|
-
return fetch(url, init);
|
|
7342
|
+
return fetch(url, withCredentials(init, options.credentials));
|
|
7250
7343
|
}
|
|
7251
7344
|
const headers = new Headers(init?.headers);
|
|
7252
7345
|
for (const [name, value] of Object.entries(fresh)) {
|
|
7253
7346
|
headers.set(name, value);
|
|
7254
7347
|
}
|
|
7255
|
-
return fetch(url, { ...init, headers });
|
|
7348
|
+
return fetch(url, withCredentials({ ...init, headers }, options.credentials));
|
|
7256
7349
|
},
|
|
7257
7350
|
// Spread conditionally: under `exactOptionalPropertyTypes` an explicit
|
|
7258
7351
|
// `undefined` is not assignable to these optional config fields.
|
|
@@ -7266,12 +7359,14 @@ var RemoteConversationStore = class {
|
|
|
7266
7359
|
#url;
|
|
7267
7360
|
#headers;
|
|
7268
7361
|
#local;
|
|
7362
|
+
#credentials;
|
|
7269
7363
|
#dropped = /* @__PURE__ */ new Set();
|
|
7270
7364
|
#renamed = /* @__PURE__ */ new Map();
|
|
7271
|
-
constructor(url, headers = () => ({}), local = new SessionStorageStore()) {
|
|
7365
|
+
constructor(url, headers = () => ({}), local = new SessionStorageStore(), credentials = () => void 0) {
|
|
7272
7366
|
this.#url = url.endsWith("/") ? url : `${url}/`;
|
|
7273
7367
|
this.#headers = headers;
|
|
7274
7368
|
this.#local = local;
|
|
7369
|
+
this.#credentials = credentials;
|
|
7275
7370
|
}
|
|
7276
7371
|
threadId() {
|
|
7277
7372
|
return this.#local.threadId();
|
|
@@ -7349,7 +7444,7 @@ var RemoteConversationStore = class {
|
|
|
7349
7444
|
/** GET that resolves to the `Response`, or `null` on a network error. */
|
|
7350
7445
|
async #get(url) {
|
|
7351
7446
|
try {
|
|
7352
|
-
return await fetch(url, { headers: this.#headers() });
|
|
7447
|
+
return await fetch(url, withCredentials({ headers: this.#headers() }, this.#credentials()));
|
|
7353
7448
|
} catch {
|
|
7354
7449
|
return null;
|
|
7355
7450
|
}
|
|
@@ -7358,11 +7453,17 @@ var RemoteConversationStore = class {
|
|
|
7358
7453
|
async #mutate(threadId, method, body) {
|
|
7359
7454
|
const headers = this.#headers();
|
|
7360
7455
|
try {
|
|
7361
|
-
await fetch(
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7456
|
+
await fetch(
|
|
7457
|
+
`${this.#url}${encodeURIComponent(threadId)}/`,
|
|
7458
|
+
withCredentials(
|
|
7459
|
+
{
|
|
7460
|
+
method,
|
|
7461
|
+
headers: body === void 0 ? headers : { ...headers, "content-type": "application/json" },
|
|
7462
|
+
body: body === void 0 ? null : JSON.stringify(body)
|
|
7463
|
+
},
|
|
7464
|
+
this.#credentials()
|
|
7465
|
+
)
|
|
7466
|
+
);
|
|
7366
7467
|
} catch {
|
|
7367
7468
|
}
|
|
7368
7469
|
}
|
|
@@ -7372,9 +7473,11 @@ var RemoteConversationStore = class {
|
|
|
7372
7473
|
var RunIndex = class {
|
|
7373
7474
|
#url;
|
|
7374
7475
|
#headers;
|
|
7375
|
-
|
|
7476
|
+
#credentials;
|
|
7477
|
+
constructor(url, headers = () => ({}), credentials = () => void 0) {
|
|
7376
7478
|
this.#url = url.endsWith("/") ? url : `${url}/`;
|
|
7377
7479
|
this.#headers = headers;
|
|
7480
|
+
this.#credentials = credentials;
|
|
7378
7481
|
}
|
|
7379
7482
|
/**
|
|
7380
7483
|
* The user's runs, or `[]` when the endpoint is unreachable or answers with
|
|
@@ -7384,10 +7487,16 @@ var RunIndex = class {
|
|
|
7384
7487
|
*/
|
|
7385
7488
|
async list() {
|
|
7386
7489
|
try {
|
|
7387
|
-
const response = await fetch(
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7490
|
+
const response = await fetch(
|
|
7491
|
+
this.#url,
|
|
7492
|
+
withCredentials(
|
|
7493
|
+
{
|
|
7494
|
+
method: "GET",
|
|
7495
|
+
headers: { Accept: "application/json", ...this.#headers() }
|
|
7496
|
+
},
|
|
7497
|
+
this.#credentials()
|
|
7498
|
+
)
|
|
7499
|
+
);
|
|
7391
7500
|
if (!response.ok) {
|
|
7392
7501
|
return [];
|
|
7393
7502
|
}
|
|
@@ -7426,11 +7535,17 @@ var RunIndex = class {
|
|
|
7426
7535
|
async function transcribeAudio(audio, options) {
|
|
7427
7536
|
const form = new FormData();
|
|
7428
7537
|
form.append("audio", audio, "recording.webm");
|
|
7429
|
-
const response = await fetch(
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7538
|
+
const response = await fetch(
|
|
7539
|
+
options.url,
|
|
7540
|
+
withCredentials(
|
|
7541
|
+
{
|
|
7542
|
+
method: "POST",
|
|
7543
|
+
headers: { ...options.headers ?? {} },
|
|
7544
|
+
body: form
|
|
7545
|
+
},
|
|
7546
|
+
options.credentials
|
|
7547
|
+
)
|
|
7548
|
+
);
|
|
7434
7549
|
if (!response.ok) {
|
|
7435
7550
|
throw new Error(await errorMessage(response));
|
|
7436
7551
|
}
|
|
@@ -7458,6 +7573,7 @@ function uploadAttachment(file, options) {
|
|
|
7458
7573
|
form.append("file", file);
|
|
7459
7574
|
const xhr = new XMLHttpRequest();
|
|
7460
7575
|
xhr.open("POST", options.url);
|
|
7576
|
+
xhr.withCredentials = options.credentials === "include";
|
|
7461
7577
|
for (const [key, value] of Object.entries(options.headers ?? {})) {
|
|
7462
7578
|
xhr.setRequestHeader(key, value);
|
|
7463
7579
|
}
|
|
@@ -7531,14 +7647,42 @@ var CONNECT_TIME_ATTRIBUTES = [
|
|
|
7531
7647
|
"data-strings",
|
|
7532
7648
|
"data-icon-url"
|
|
7533
7649
|
];
|
|
7650
|
+
var CREDENTIALS_MODES = ["omit", "same-origin", "include"];
|
|
7651
|
+
function isCredentialsMode(value) {
|
|
7652
|
+
return CREDENTIALS_MODES.includes(value);
|
|
7653
|
+
}
|
|
7534
7654
|
var COLLAPSED_KEY = "ag-ui-chat:collapsed";
|
|
7535
7655
|
var SIZE_KEY = "ag-ui-chat:size";
|
|
7536
7656
|
var THEME_KEY = "ag-ui-chat:theme";
|
|
7537
7657
|
var AgUiChat = class extends HTMLElement {
|
|
7538
7658
|
/** Agent factory; override to inject a custom or fake agent (tests). */
|
|
7539
7659
|
agentFactory = createHttpAgent;
|
|
7540
|
-
/**
|
|
7660
|
+
/**
|
|
7661
|
+
* Static extra HTTP headers, sent with **every** request this element makes —
|
|
7662
|
+
* the agent run, the thread index and its messages, the tool and skill
|
|
7663
|
+
* catalogs, the run index, uploads and transcription.
|
|
7664
|
+
*
|
|
7665
|
+
* Right for values fixed for the element's lifetime. A credential that
|
|
7666
|
+
* rotates (a short-lived JWT, a re-issued CSRF token) belongs in
|
|
7667
|
+
* {@link getHeaders} instead: this is read at request time, but only a
|
|
7668
|
+
* re-assignment updates it, so a token captured here is pinned until the host
|
|
7669
|
+
* remembers to assign again.
|
|
7670
|
+
*/
|
|
7541
7671
|
headers = {};
|
|
7672
|
+
/**
|
|
7673
|
+
* Live header source, consulted immediately before every request — the way to
|
|
7674
|
+
* supply rotating credentials.
|
|
7675
|
+
*
|
|
7676
|
+
* Set it to a function and each request calls it afresh: a token refreshed by
|
|
7677
|
+
* the host between two requests reaches the second one, with nothing to
|
|
7678
|
+
* re-assign and nothing to keep in sync.
|
|
7679
|
+
*
|
|
7680
|
+
* Composes with {@link headers} rather than replacing it: the two are merged
|
|
7681
|
+
* per key with `getHeaders()` winning, so a static `X-Client` and a rotating
|
|
7682
|
+
* `Authorization` can be configured independently and neither silently drops
|
|
7683
|
+
* the other.
|
|
7684
|
+
*/
|
|
7685
|
+
getHeaders = null;
|
|
7542
7686
|
/**
|
|
7543
7687
|
* Permit `<img>` in rendered assistant markdown. **Off by default**: a
|
|
7544
7688
|
* model-controlled image URL is fetched with no user interaction, which
|
|
@@ -7825,7 +7969,11 @@ var AgUiChat = class extends HTMLElement {
|
|
|
7825
7969
|
return null;
|
|
7826
7970
|
}
|
|
7827
7971
|
if (this.#runIndex === null) {
|
|
7828
|
-
this.#runIndex = new RunIndex(
|
|
7972
|
+
this.#runIndex = new RunIndex(
|
|
7973
|
+
url,
|
|
7974
|
+
() => this.#requestHeaders(),
|
|
7975
|
+
() => this.#requestCredentials()
|
|
7976
|
+
);
|
|
7829
7977
|
}
|
|
7830
7978
|
return this.#runIndex;
|
|
7831
7979
|
}
|
|
@@ -7857,8 +8005,9 @@ var AgUiChat = class extends HTMLElement {
|
|
|
7857
8005
|
const endpoint = verb === "resume" ? index.resumeUrl(runId) : index.forkUrl(runId);
|
|
7858
8006
|
const agent = this.agentFactory({
|
|
7859
8007
|
endpoint,
|
|
7860
|
-
headers: this
|
|
7861
|
-
getHeaders: () => this
|
|
8008
|
+
headers: this.#requestHeaders(),
|
|
8009
|
+
getHeaders: () => this.#requestHeaders(),
|
|
8010
|
+
...this.#credentialsOption(),
|
|
7862
8011
|
threadId: this.#threadId,
|
|
7863
8012
|
// The seed the endpoints assume: nothing. The snapshot is the history.
|
|
7864
8013
|
initialMessages: []
|
|
@@ -7881,10 +8030,19 @@ var AgUiChat = class extends HTMLElement {
|
|
|
7881
8030
|
}
|
|
7882
8031
|
/** Attributes the element reacts to after it has been connected. */
|
|
7883
8032
|
static get observedAttributes() {
|
|
7884
|
-
return ["title-text", "placement", ...CONNECT_TIME_ATTRIBUTES];
|
|
8033
|
+
return ["title-text", "placement", "credentials", ...CONNECT_TIME_ATTRIBUTES];
|
|
7885
8034
|
}
|
|
7886
8035
|
attributeChangedCallback(name, previous, value) {
|
|
8036
|
+
if (name === "credentials") {
|
|
8037
|
+
if (value !== null && !isCredentialsMode(value)) {
|
|
8038
|
+
console.error(
|
|
8039
|
+
`<ag-ui-chat>: credentials="${value}" is not a fetch credentials mode (${CREDENTIALS_MODES.join(" / ")}) \u2014 it is being ignored, so requests use the browser default and cross-origin cookies will not be sent.`
|
|
8040
|
+
);
|
|
8041
|
+
}
|
|
8042
|
+
return;
|
|
8043
|
+
}
|
|
7887
8044
|
if (name === "placement") {
|
|
8045
|
+
this.#releaseOwnedAxes();
|
|
7888
8046
|
requestAnimationFrame(() => this.#syncResizeAnchor());
|
|
7889
8047
|
return;
|
|
7890
8048
|
}
|
|
@@ -8073,6 +8231,72 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8073
8231
|
set endpoint(value) {
|
|
8074
8232
|
this.setAttribute("endpoint", value);
|
|
8075
8233
|
}
|
|
8234
|
+
/**
|
|
8235
|
+
* Cookie policy for **every** request this element makes, as `fetch`'s own
|
|
8236
|
+
* `credentials` mode (`"omit"` / `"same-origin"` / `"include"`). Mirrored to
|
|
8237
|
+
* the `credentials` attribute, so markup embeds can set it without script.
|
|
8238
|
+
*
|
|
8239
|
+
* `null` (the default) leaves the browser's default of `same-origin` in
|
|
8240
|
+
* place. That default sends **no cookies at all** when the endpoints live on
|
|
8241
|
+
* a different origin from the page — app.example.com calling
|
|
8242
|
+
* api.example.com is cross-origin — and the request goes out anonymously
|
|
8243
|
+
* rather than failing, so the symptom is a 401 from a server that looks
|
|
8244
|
+
* correctly configured. A cookie-authenticated cross-origin deployment wants
|
|
8245
|
+
* `"include"`, plus `Access-Control-Allow-Credentials: true` and a concrete
|
|
8246
|
+
* (non-wildcard) `Access-Control-Allow-Origin` on the server.
|
|
8247
|
+
*
|
|
8248
|
+
* Read per request, so a late assignment applies to everything after it.
|
|
8249
|
+
* `"omit"` cannot be honoured by the built-in **upload** transport, which is
|
|
8250
|
+
* an `XMLHttpRequest` and only has a two-state cookie switch; every other
|
|
8251
|
+
* endpoint honours all three modes.
|
|
8252
|
+
*/
|
|
8253
|
+
get credentials() {
|
|
8254
|
+
const attr = this.getAttribute("credentials");
|
|
8255
|
+
return attr !== null && isCredentialsMode(attr) ? attr : null;
|
|
8256
|
+
}
|
|
8257
|
+
set credentials(value) {
|
|
8258
|
+
if (value === null) {
|
|
8259
|
+
this.removeAttribute("credentials");
|
|
8260
|
+
return;
|
|
8261
|
+
}
|
|
8262
|
+
if (!isCredentialsMode(value)) {
|
|
8263
|
+
throw new TypeError(
|
|
8264
|
+
`<ag-ui-chat>: credentials must be one of ${CREDENTIALS_MODES.map((mode) => `"${mode}"`).join(", ")} (got ${JSON.stringify(value)}).`
|
|
8265
|
+
);
|
|
8266
|
+
}
|
|
8267
|
+
this.setAttribute("credentials", value);
|
|
8268
|
+
}
|
|
8269
|
+
/**
|
|
8270
|
+
* The headers for the request about to go out: the static {@link headers}
|
|
8271
|
+
* with {@link getHeaders}'s live values overlaid, per key.
|
|
8272
|
+
*
|
|
8273
|
+
* Every request site goes through here, so "how this element authenticates"
|
|
8274
|
+
* is one answer rather than one per endpoint.
|
|
8275
|
+
*/
|
|
8276
|
+
#requestHeaders() {
|
|
8277
|
+
return { ...this.headers, ...this.getHeaders?.() };
|
|
8278
|
+
}
|
|
8279
|
+
/** The configured cookie policy as `fetch` spells it; `undefined` when unset. */
|
|
8280
|
+
#requestCredentials() {
|
|
8281
|
+
return this.credentials ?? void 0;
|
|
8282
|
+
}
|
|
8283
|
+
/**
|
|
8284
|
+
* The `credentials` entry for an {@link AgentFactory} call, or nothing at all.
|
|
8285
|
+
*
|
|
8286
|
+
* Spread rather than assigned: `exactOptionalPropertyTypes` rejects an
|
|
8287
|
+
* explicit `credentials: undefined`, and a factory should see the field
|
|
8288
|
+
* absent — not present-and-empty — when no policy is configured. The agent
|
|
8289
|
+
* reads it when it is built (first send, thread switch, continuation), by
|
|
8290
|
+
* which time any host configuration has landed.
|
|
8291
|
+
*/
|
|
8292
|
+
#credentialsOption() {
|
|
8293
|
+
const credentials = this.#requestCredentials();
|
|
8294
|
+
return credentials === void 0 ? {} : { credentials };
|
|
8295
|
+
}
|
|
8296
|
+
/** The `fetch` init for the element's own plain GETs (catalogs). */
|
|
8297
|
+
#fetchInit() {
|
|
8298
|
+
return withCredentials({ headers: this.#requestHeaders() }, this.#requestCredentials());
|
|
8299
|
+
}
|
|
8076
8300
|
/**
|
|
8077
8301
|
* How much detail tool-call cards show, from the `data-tool-display`
|
|
8078
8302
|
* attribute (`minimal` / `inline` / `compact` / `full`). Defaults to `full`.
|
|
@@ -8110,7 +8334,6 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8110
8334
|
}
|
|
8111
8335
|
this.#syncRail();
|
|
8112
8336
|
this.#initSkills();
|
|
8113
|
-
void this.#fetchToolCatalog();
|
|
8114
8337
|
if (this.#storageNs !== "" && this.conversationStore instanceof SessionStorageStore) {
|
|
8115
8338
|
this.conversationStore = new SessionStorageStore(this.#storageNs);
|
|
8116
8339
|
}
|
|
@@ -8118,9 +8341,62 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8118
8341
|
this.#wireAttachments();
|
|
8119
8342
|
this.#wireVoice();
|
|
8120
8343
|
this.#threadId = this.conversationStore.threadId();
|
|
8344
|
+
queueMicrotask(() => this.#startup());
|
|
8121
8345
|
void this.#rehydrate();
|
|
8122
8346
|
this.#connected = true;
|
|
8123
8347
|
}
|
|
8348
|
+
/**
|
|
8349
|
+
* The catalog requests the element issues on startup: the tool labels
|
|
8350
|
+
* (`data-tools-url`) and the backend skills (`data-skills-url`).
|
|
8351
|
+
*
|
|
8352
|
+
* Deliberately one microtask behind `connectedCallback`. A host that
|
|
8353
|
+
* configures the element through a framework ref necessarily does so *after*
|
|
8354
|
+
* inserting the node — React attaches refs and runs layout effects in the
|
|
8355
|
+
* same commit as the insertion, but strictly afterwards — so a request issued
|
|
8356
|
+
* from `connectedCallback` itself goes out before `headers`,
|
|
8357
|
+
* {@link getHeaders} or {@link credentials} exist, and comes back 401 in a
|
|
8358
|
+
* way that reads as a server fault rather than a mis-timed assignment. A
|
|
8359
|
+
* microtask lands after that commit and still before paint.
|
|
8360
|
+
*
|
|
8361
|
+
* Two things it is **not**. It is not a fix for configuration that arrives
|
|
8362
|
+
* later than the commit (a passive `useEffect`, an awaited token fetch):
|
|
8363
|
+
* configure before insertion (`createElement` → configure → `append`) or call
|
|
8364
|
+
* {@link reload} once configured, because a longer timer would hide that race
|
|
8365
|
+
* rather than close it. And it deliberately excludes the *history* replay,
|
|
8366
|
+
* which stays in `connectedCallback`: the replay renders into the transcript,
|
|
8367
|
+
* so deferring it lets a `sendMessage()` issued in the same task land first
|
|
8368
|
+
* and the replay then duplicate it. The thread history is therefore the one
|
|
8369
|
+
* request that can still go out before a ref is attached — {@link reload}
|
|
8370
|
+
* covers it.
|
|
8371
|
+
*/
|
|
8372
|
+
#startup() {
|
|
8373
|
+
if (!this.#connected) {
|
|
8374
|
+
return;
|
|
8375
|
+
}
|
|
8376
|
+
void this.#fetchToolCatalog();
|
|
8377
|
+
void this.#fetchSkills();
|
|
8378
|
+
}
|
|
8379
|
+
/**
|
|
8380
|
+
* Re-run everything the element loads on startup — the tool-label catalog,
|
|
8381
|
+
* the backend skill catalog and the thread's history — with the transport
|
|
8382
|
+
* configuration as it stands now.
|
|
8383
|
+
*
|
|
8384
|
+
* This is the answer for a host that can only configure the element after the
|
|
8385
|
+
* fact (a token fetched in a passive effect, an async auth handshake): the
|
|
8386
|
+
* startup requests already went out with whatever was set then, and this says
|
|
8387
|
+
* "try again, properly authenticated" without removing and re-inserting the
|
|
8388
|
+
* node.
|
|
8389
|
+
*
|
|
8390
|
+
* A reload, not a merge — the in-flight run is cancelled and the transcript
|
|
8391
|
+
* is rebuilt from the persisted history, so anything streamed since is
|
|
8392
|
+
* dropped. Call it once, when configuration lands; not between turns.
|
|
8393
|
+
*/
|
|
8394
|
+
async reload() {
|
|
8395
|
+
this.#cancelRun();
|
|
8396
|
+
this.#resetState();
|
|
8397
|
+
this.#setRunning(false);
|
|
8398
|
+
await Promise.all([this.#fetchToolCatalog(), this.#fetchSkills(), this.#rehydrate()]);
|
|
8399
|
+
}
|
|
8124
8400
|
/**
|
|
8125
8401
|
* Tear down live resources when the element leaves the DOM (a removed node, a
|
|
8126
8402
|
* client-side route swap): cancel the in-flight run so its SSE stream closes,
|
|
@@ -8202,7 +8478,13 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8202
8478
|
if (url === null) {
|
|
8203
8479
|
return null;
|
|
8204
8480
|
}
|
|
8205
|
-
return (file, onProgress, signal) => uploadAttachment(file, {
|
|
8481
|
+
return (file, onProgress, signal) => uploadAttachment(file, {
|
|
8482
|
+
url,
|
|
8483
|
+
headers: this.#requestHeaders(),
|
|
8484
|
+
...this.#credentialsOption(),
|
|
8485
|
+
onProgress,
|
|
8486
|
+
signal
|
|
8487
|
+
});
|
|
8206
8488
|
}
|
|
8207
8489
|
/**
|
|
8208
8490
|
* Reveal the composer's 🎤 mic button when transcription is possible — either
|
|
@@ -8229,7 +8511,11 @@ var AgUiChat = class extends HTMLElement {
|
|
|
8229
8511
|
if (url === null) {
|
|
8230
8512
|
return null;
|
|
8231
8513
|
}
|
|
8232
|
-
return (audio) => transcribeAudio(audio, {
|
|
8514
|
+
return (audio) => transcribeAudio(audio, {
|
|
8515
|
+
url,
|
|
8516
|
+
headers: this.#requestHeaders(),
|
|
8517
|
+
...this.#credentialsOption()
|
|
8518
|
+
});
|
|
8233
8519
|
}
|
|
8234
8520
|
/** Drop a voice transcript into the composer (appended to any typed text). */
|
|
8235
8521
|
#insertVoiceText(text2) {
|
|
@@ -8304,8 +8590,9 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
8304
8590
|
if (url !== null) {
|
|
8305
8591
|
this.conversationStore = new RemoteConversationStore(
|
|
8306
8592
|
url,
|
|
8307
|
-
() => this
|
|
8308
|
-
this.conversationStore
|
|
8593
|
+
() => this.#requestHeaders(),
|
|
8594
|
+
this.conversationStore,
|
|
8595
|
+
() => this.#requestCredentials()
|
|
8309
8596
|
);
|
|
8310
8597
|
}
|
|
8311
8598
|
}
|
|
@@ -8316,7 +8603,7 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
8316
8603
|
return;
|
|
8317
8604
|
}
|
|
8318
8605
|
try {
|
|
8319
|
-
const response = await fetch(url,
|
|
8606
|
+
const response = await fetch(url, this.#fetchInit());
|
|
8320
8607
|
this.#toolCatalog = parseToolCatalog(await response.json());
|
|
8321
8608
|
} catch {
|
|
8322
8609
|
}
|
|
@@ -8329,13 +8616,16 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
8329
8616
|
this.#clientSkills = skills;
|
|
8330
8617
|
this.#recomputeSkills();
|
|
8331
8618
|
}
|
|
8332
|
-
/**
|
|
8619
|
+
/**
|
|
8620
|
+
* Wire the skill surfaces: opt-in flags and the embedded catalog. The backend
|
|
8621
|
+
* catalog is fetched from `#startup`, a microtask later, so it carries the
|
|
8622
|
+
* host's transport configuration.
|
|
8623
|
+
*/
|
|
8333
8624
|
#initSkills() {
|
|
8334
8625
|
this.#skillsMenu.enableChips(this.#flag("data-prompt-chips"));
|
|
8335
8626
|
this.#skillsMenu.enableSlash(this.#flag("data-slash-commands"));
|
|
8336
8627
|
this.#embedSkills = this.#readEmbeddedSkills();
|
|
8337
8628
|
this.#recomputeSkills();
|
|
8338
|
-
void this.#fetchSkills();
|
|
8339
8629
|
}
|
|
8340
8630
|
/** Parse the inline `data-skills` JSON catalog (empty when absent/malformed). */
|
|
8341
8631
|
#readEmbeddedSkills() {
|
|
@@ -8356,7 +8646,7 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
8356
8646
|
return;
|
|
8357
8647
|
}
|
|
8358
8648
|
try {
|
|
8359
|
-
const response = await fetch(url,
|
|
8649
|
+
const response = await fetch(url, this.#fetchInit());
|
|
8360
8650
|
this.#backendSkills = parseSkills(await response.json());
|
|
8361
8651
|
this.#recomputeSkills();
|
|
8362
8652
|
} catch {
|
|
@@ -8531,21 +8821,45 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
8531
8821
|
this.style.setProperty(name, value);
|
|
8532
8822
|
}
|
|
8533
8823
|
/**
|
|
8534
|
-
* Write a dragged size onto the host
|
|
8824
|
+
* Write a dragged size onto the host, on the axes this placement leaves free.
|
|
8535
8825
|
*
|
|
8536
|
-
*
|
|
8537
|
-
*
|
|
8538
|
-
*
|
|
8539
|
-
*
|
|
8826
|
+
* ⚠ Writing the custom property rather than inline `width` / `height` does
|
|
8827
|
+
* **not** by itself leave placement in charge — an inline custom property
|
|
8828
|
+
* still outranks a `:host([placement=…])` rule setting the same property, so
|
|
8829
|
+
* a height dragged while floating capped a docked sidebar that had asked for
|
|
8830
|
+
* `100vh`. The cascade cannot arbitrate this; the axis check has to.
|
|
8831
|
+
*
|
|
8832
|
+
* So the rule is explicit: a placement owns the axes it fixes, and a
|
|
8833
|
+
* persisted size is only ever applied to the ones it does not.
|
|
8540
8834
|
*/
|
|
8541
8835
|
#applySize(size) {
|
|
8836
|
+
const axis = this.#resizeAxis();
|
|
8837
|
+
if (axis === "none") {
|
|
8838
|
+
return;
|
|
8839
|
+
}
|
|
8542
8840
|
if (size.width !== void 0) {
|
|
8543
8841
|
this.style.setProperty("--ag-ui-width", `${size.width}px`);
|
|
8544
8842
|
}
|
|
8545
|
-
if (size.height !== void 0) {
|
|
8843
|
+
if (size.height !== void 0 && axis === "both") {
|
|
8546
8844
|
this.style.setProperty("--ag-ui-height", `${size.height}px`);
|
|
8547
8845
|
}
|
|
8548
8846
|
}
|
|
8847
|
+
/**
|
|
8848
|
+
* Drop any dragged size the new placement has taken ownership of.
|
|
8849
|
+
*
|
|
8850
|
+
* Without this a size survives the switch as an inline property and silently
|
|
8851
|
+
* overrides the placement it moved to — the panel keeps a floating height
|
|
8852
|
+
* while docked, and reads as a component that cannot do full height.
|
|
8853
|
+
*/
|
|
8854
|
+
#releaseOwnedAxes() {
|
|
8855
|
+
const axis = this.#resizeAxis();
|
|
8856
|
+
if (axis !== "both") {
|
|
8857
|
+
this.style.removeProperty("--ag-ui-height");
|
|
8858
|
+
}
|
|
8859
|
+
if (axis === "none") {
|
|
8860
|
+
this.style.removeProperty("--ag-ui-width");
|
|
8861
|
+
}
|
|
8862
|
+
}
|
|
8549
8863
|
/** Persist a dragged size per tab, alongside the collapsed/theme preferences. */
|
|
8550
8864
|
#persistSize(size) {
|
|
8551
8865
|
const stored = { ...this.#readSize(), ...size };
|
|
@@ -8585,6 +8899,32 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
8585
8899
|
const dark = this.getAttribute("theme") === "dark";
|
|
8586
8900
|
this.#themeToggle.textContent = dark ? "\u2600\uFE0F" : "\u{1F319}";
|
|
8587
8901
|
}
|
|
8902
|
+
/**
|
|
8903
|
+
* Open the thread-history drawer: the imperative route to the control that
|
|
8904
|
+
* renders as `::part(history-button)`.
|
|
8905
|
+
*
|
|
8906
|
+
* A host that hides `::part(header)` to render its own title bar hides the
|
|
8907
|
+
* history, new-chat and collapse buttons with it — and thread switching then
|
|
8908
|
+
* has no route at all, because those controls live inside the header. Each of
|
|
8909
|
+
* them has a method, so a host chrome can rebuild the set: this one,
|
|
8910
|
+
* {@link openCheckpoints}, {@link newChat}, {@link toggleCollapsed} and
|
|
8911
|
+
* {@link toggleTheme}.
|
|
8912
|
+
*/
|
|
8913
|
+
openThreads() {
|
|
8914
|
+
void this.#refreshDrawer();
|
|
8915
|
+
this.#drawer.open();
|
|
8916
|
+
}
|
|
8917
|
+
/**
|
|
8918
|
+
* Open the checkpoints panel (the `::part(checkpoints-button)` route).
|
|
8919
|
+
*
|
|
8920
|
+
* It lists the runs the `data-runs-url` server reports as continuable;
|
|
8921
|
+
* without that attribute the built-in button is never rendered and this opens
|
|
8922
|
+
* an empty panel.
|
|
8923
|
+
*/
|
|
8924
|
+
openCheckpoints() {
|
|
8925
|
+
void this.#refreshCheckpoints();
|
|
8926
|
+
this.#checkpoints.open();
|
|
8927
|
+
}
|
|
8588
8928
|
/**
|
|
8589
8929
|
* Start a fresh conversation: forget the persisted history, drop the
|
|
8590
8930
|
* in-memory run state, clear the transcript, and mint a new thread id.
|
|
@@ -8855,15 +9195,9 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
8855
9195
|
controls.className = "header-controls";
|
|
8856
9196
|
controls.setAttribute("part", "header-controls");
|
|
8857
9197
|
const history = this.#headerButton("history", this.#strings.chatHistory, "\u2630");
|
|
8858
|
-
history.addEventListener("click", () =>
|
|
8859
|
-
void this.#refreshDrawer();
|
|
8860
|
-
this.#drawer.open();
|
|
8861
|
-
});
|
|
9198
|
+
history.addEventListener("click", () => this.openThreads());
|
|
8862
9199
|
const checkpoints = this.#headerButton("checkpoints", this.#strings.checkpoints, "\u2B6F");
|
|
8863
|
-
checkpoints.addEventListener("click", () =>
|
|
8864
|
-
void this.#refreshCheckpoints();
|
|
8865
|
-
this.#checkpoints.open();
|
|
8866
|
-
});
|
|
9200
|
+
checkpoints.addEventListener("click", () => this.openCheckpoints());
|
|
8867
9201
|
const newChat = this.#headerButton("new", this.#strings.newChat, "\u271A");
|
|
8868
9202
|
newChat.addEventListener("click", () => this.newChat());
|
|
8869
9203
|
const collapse = this.#headerButton("collapse", this.#strings.collapse, "\u2014");
|
|
@@ -9164,11 +9498,12 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
9164
9498
|
if (this.#client === null) {
|
|
9165
9499
|
const agent = this.agentFactory({
|
|
9166
9500
|
endpoint: this.endpoint,
|
|
9167
|
-
headers: this
|
|
9501
|
+
headers: this.#requestHeaders(),
|
|
9168
9502
|
// Live getter: the client is built once and cached, but a rotated
|
|
9169
9503
|
// token must still reach every request — the factory's fetch wrapper
|
|
9170
9504
|
// re-reads this on each call.
|
|
9171
|
-
getHeaders: () => this
|
|
9505
|
+
getHeaders: () => this.#requestHeaders(),
|
|
9506
|
+
...this.#credentialsOption(),
|
|
9172
9507
|
threadId: this.#threadId,
|
|
9173
9508
|
initialMessages: this.#initialMessages,
|
|
9174
9509
|
initialState: this.#sharedState
|
|
@@ -9538,24 +9873,24 @@ function defineAgUiChat() {
|
|
|
9538
9873
|
|
|
9539
9874
|
// src/dom/dom_driver.ts
|
|
9540
9875
|
async function fillField(el, value, options = {}) {
|
|
9541
|
-
scrollIntoCenterView(el);
|
|
9542
|
-
await focusWithFlash(el, { flashMs: options.flashMs ?? 0 });
|
|
9876
|
+
await scrollIntoCenterView(el);
|
|
9877
|
+
await focusWithFlash(el, { ...options, flashMs: options.flashMs ?? 0 });
|
|
9543
9878
|
await typeInto(el, value, options);
|
|
9544
9879
|
}
|
|
9545
9880
|
async function clickElement(el, options = {}) {
|
|
9546
|
-
scrollIntoCenterView(el);
|
|
9881
|
+
await scrollIntoCenterView(el);
|
|
9547
9882
|
await highlightThenClick(el, options);
|
|
9548
9883
|
}
|
|
9549
9884
|
async function pressButton(el, options = {}) {
|
|
9550
|
-
scrollIntoCenterView(el);
|
|
9885
|
+
await scrollIntoCenterView(el);
|
|
9551
9886
|
await pressThenClick(el, options);
|
|
9552
9887
|
}
|
|
9553
9888
|
async function selectControl(el, value, options = {}) {
|
|
9554
|
-
scrollIntoCenterView(el);
|
|
9889
|
+
await scrollIntoCenterView(el);
|
|
9555
9890
|
await selectOption(el, value, options);
|
|
9556
9891
|
}
|
|
9557
9892
|
async function toggleCheckbox(el, checked, options = {}) {
|
|
9558
|
-
scrollIntoCenterView(el);
|
|
9893
|
+
await scrollIntoCenterView(el);
|
|
9559
9894
|
await toggleControl(el, checked, options);
|
|
9560
9895
|
}
|
|
9561
9896
|
function setControlValue(el, value) {
|
|
@@ -9569,7 +9904,7 @@ function setControlValue(el, value) {
|
|
|
9569
9904
|
}
|
|
9570
9905
|
|
|
9571
9906
|
// src/version.ts
|
|
9572
|
-
var VERSION = "0.
|
|
9907
|
+
var VERSION = "0.21.0";
|
|
9573
9908
|
export {
|
|
9574
9909
|
ATTACHMENT_EVENT,
|
|
9575
9910
|
AgUiChat,
|
|
@@ -9607,6 +9942,7 @@ export {
|
|
|
9607
9942
|
createStateHookTools,
|
|
9608
9943
|
defineAgUiChat,
|
|
9609
9944
|
fillField,
|
|
9945
|
+
flash,
|
|
9610
9946
|
focusWithFlash,
|
|
9611
9947
|
highlightThenClick,
|
|
9612
9948
|
isDestructive,
|