@artooi/ag-ui-web-component 0.46.0 → 0.47.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 +87 -1
- package/README.md +130 -19
- package/dist/ag-ui-web-component.bundle.js +99 -94
- package/dist/ag-ui-web-component.bundle.js.map +4 -4
- package/dist/constants.d.ts +10 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/core/ag_ui_chat.d.ts +38 -0
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/core/chat_registry.d.ts +23 -0
- package/dist/core/chat_registry.d.ts.map +1 -0
- package/dist/core/events/run_finished_detail.d.ts +6 -0
- package/dist/core/events/run_finished_detail.d.ts.map +1 -1
- package/dist/core/events/thread_detail.d.ts +27 -0
- package/dist/core/events/thread_detail.d.ts.map +1 -0
- package/dist/core/run_handlers.d.ts +6 -1
- package/dist/core/run_handlers.d.ts.map +1 -1
- package/dist/dom/animations.d.ts +21 -6
- package/dist/dom/animations.d.ts.map +1 -1
- package/dist/dom/highlight_overlay.d.ts +7 -1
- package/dist/dom/highlight_overlay.d.ts.map +1 -1
- package/dist/dom/ring_color.d.ts +14 -0
- package/dist/dom/ring_color.d.ts.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +249 -54
- package/dist/index.js.map +4 -4
- package/dist/ui/history/conversation_history.d.ts +10 -1
- package/dist/ui/history/conversation_history.d.ts.map +1 -1
- package/dist/ui/placement/panel_placement.d.ts +6 -0
- package/dist/ui/placement/panel_placement.d.ts.map +1 -1
- package/dist/ui/placement/small_viewport_styles.d.ts.map +1 -1
- package/dist/ui/progress/tool_call_card.d.ts.map +1 -1
- package/dist/ui/progress/tool_step_group.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +11 -0
- package/src/core/ag_ui_chat.ts +108 -5
- package/src/core/chat_registry.ts +53 -0
- package/src/core/events/run_finished_detail.ts +6 -0
- package/src/core/events/thread_detail.ts +26 -0
- package/src/core/run_handlers.ts +9 -4
- package/src/dom/animations.ts +30 -31
- package/src/dom/highlight_overlay.ts +9 -5
- package/src/dom/ring_color.ts +85 -0
- package/src/index.ts +3 -0
- package/src/ui/history/conversation_history.ts +28 -4
- package/src/ui/placement/embedded_styles.ts +2 -2
- package/src/ui/placement/panel_placement.ts +34 -9
- package/src/ui/placement/preset_styles.ts +1 -1
- package/src/ui/placement/sidebar_styles.ts +1 -1
- package/src/ui/placement/small_viewport_styles.ts +5 -0
- package/src/ui/progress/tool_call_card.ts +18 -8
- package/src/ui/progress/tool_step_group.ts +3 -0
- package/src/ui/shell/token_styles.ts +2 -2
- package/src/version.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ var UNREAD_EVENT = "ag-ui-unread";
|
|
|
6
6
|
var STATE_EVENT = "ag-ui-state";
|
|
7
7
|
var ATTACHMENT_EVENT = "ag-ui-attachments";
|
|
8
8
|
var RUN_FINISHED_EVENT = "ag-ui-run-finished";
|
|
9
|
+
var THREAD_EVENT = "ag-ui-thread";
|
|
9
10
|
var CUSTOM_AGENT_EVENT = "ag-ui-custom";
|
|
10
11
|
var INVALIDATE_EVENT = "ag-ui-invalidate";
|
|
11
12
|
var FEEDBACK_EVENT = "ag-ui-feedback";
|
|
@@ -354,8 +355,79 @@ var ClientToolRegistry = class {
|
|
|
354
355
|
}
|
|
355
356
|
};
|
|
356
357
|
|
|
358
|
+
// src/core/chat_registry.ts
|
|
359
|
+
var CONNECTED_CHATS = /* @__PURE__ */ new Set();
|
|
360
|
+
var ChatRegistration = class {
|
|
361
|
+
#chat;
|
|
362
|
+
constructor(chat) {
|
|
363
|
+
this.#chat = chat;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Join, as the most recently connected chat. An element moved in the DOM
|
|
367
|
+
* left on disconnect before it reconnected, so it rejoins at the end and no
|
|
368
|
+
* entry needs removing first.
|
|
369
|
+
*/
|
|
370
|
+
join() {
|
|
371
|
+
CONNECTED_CHATS.add(this.#chat);
|
|
372
|
+
}
|
|
373
|
+
/** Leave. The previous chat, if one is still connected, becomes the latest. */
|
|
374
|
+
leave() {
|
|
375
|
+
CONNECTED_CHATS.delete(this.#chat);
|
|
376
|
+
}
|
|
377
|
+
/** The most recently connected chat still in the document, or `null`. */
|
|
378
|
+
static latest() {
|
|
379
|
+
let latest = null;
|
|
380
|
+
for (const chat of CONNECTED_CHATS) {
|
|
381
|
+
latest = chat;
|
|
382
|
+
}
|
|
383
|
+
return latest;
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// src/dom/ring_color.ts
|
|
388
|
+
var RING_TOKEN = "--ag-ui-highlight-ring-color";
|
|
389
|
+
var ACCENT_TOKEN = "--ag-ui-accent";
|
|
390
|
+
var CHAT_ACCENT = "--_accent";
|
|
391
|
+
var PACKAGE_ACCENT = "#4f46e5";
|
|
392
|
+
function ringColor(target, chat) {
|
|
393
|
+
const onTarget = readToken(target, RING_TOKEN);
|
|
394
|
+
if (onTarget !== "") {
|
|
395
|
+
return onTarget;
|
|
396
|
+
}
|
|
397
|
+
const owner = chat ?? ChatRegistration.latest();
|
|
398
|
+
const onChat = owner === null ? "" : resolveOn(owner, RING_TOKEN);
|
|
399
|
+
if (onChat !== "") {
|
|
400
|
+
return onChat;
|
|
401
|
+
}
|
|
402
|
+
const accent = readToken(target, ACCENT_TOKEN);
|
|
403
|
+
if (accent !== "") {
|
|
404
|
+
return accent;
|
|
405
|
+
}
|
|
406
|
+
const chatAccent = owner === null ? "" : resolveOn(owner, CHAT_ACCENT);
|
|
407
|
+
return chatAccent === "" ? PACKAGE_ACCENT : chatAccent;
|
|
408
|
+
}
|
|
409
|
+
function readToken(el2, name) {
|
|
410
|
+
return window.getComputedStyle(el2).getPropertyValue(name).trim();
|
|
411
|
+
}
|
|
412
|
+
function resolveOn(chat, name) {
|
|
413
|
+
const value = readToken(chat, name);
|
|
414
|
+
const root = chat.shadowRoot;
|
|
415
|
+
if (value === "" || root === null) {
|
|
416
|
+
return value;
|
|
417
|
+
}
|
|
418
|
+
const probe = document.createElement("span");
|
|
419
|
+
probe.hidden = true;
|
|
420
|
+
probe.style.color = value;
|
|
421
|
+
if (probe.style.color === "") {
|
|
422
|
+
return "";
|
|
423
|
+
}
|
|
424
|
+
root.appendChild(probe);
|
|
425
|
+
const resolved = window.getComputedStyle(probe).color;
|
|
426
|
+
probe.remove();
|
|
427
|
+
return resolved;
|
|
428
|
+
}
|
|
429
|
+
|
|
357
430
|
// src/dom/highlight_overlay.ts
|
|
358
|
-
var ACCENT = "#4f46e5";
|
|
359
431
|
function tokenOn(target, name, fallback) {
|
|
360
432
|
const value = window.getComputedStyle(target).getPropertyValue(name).trim();
|
|
361
433
|
return value === "" ? fallback : value;
|
|
@@ -440,7 +512,7 @@ function safeColor(value) {
|
|
|
440
512
|
return CSS.supports("color", value) ? value : null;
|
|
441
513
|
}
|
|
442
514
|
function ringPaint(target, options) {
|
|
443
|
-
const color = safeColor(options.color) ??
|
|
515
|
+
const color = safeColor(options.color) ?? ringColor(target, options.chat);
|
|
444
516
|
if (options.gradient !== true) {
|
|
445
517
|
return `border-color: ${color}`;
|
|
446
518
|
}
|
|
@@ -504,9 +576,6 @@ function setNativeChecked(el2, checked) {
|
|
|
504
576
|
}
|
|
505
577
|
|
|
506
578
|
// src/dom/animations.ts
|
|
507
|
-
var ACCENT2 = "#4f46e5";
|
|
508
|
-
var ACCENT_HALO = "rgba(79, 70, 229, 0.4)";
|
|
509
|
-
var ACCENT_PROPERTY = "--ag-ui-accent";
|
|
510
579
|
function delay(ms) {
|
|
511
580
|
return new Promise((resolve) => {
|
|
512
581
|
setTimeout(resolve, ms);
|
|
@@ -521,12 +590,8 @@ function motionDelay(ms) {
|
|
|
521
590
|
}
|
|
522
591
|
return delay(ms);
|
|
523
592
|
}
|
|
524
|
-
function
|
|
525
|
-
|
|
526
|
-
return themed === "" ? fallback : themed;
|
|
527
|
-
}
|
|
528
|
-
function ringShadow(el2) {
|
|
529
|
-
return `0 0 0 3px ${accentColor(el2, ACCENT_HALO)}`;
|
|
593
|
+
function ringShadow(el2, chat) {
|
|
594
|
+
return `0 0 0 3px color-mix(in srgb, ${ringColor(el2, chat)} 40%, transparent)`;
|
|
530
595
|
}
|
|
531
596
|
async function typeInto(el2, value, options = {}) {
|
|
532
597
|
const charDelayMs = options.charDelayMs ?? 35;
|
|
@@ -545,7 +610,7 @@ async function highlightThenClick(el2, options = {}) {
|
|
|
545
610
|
const highlightMs = options.highlightMs ?? 280;
|
|
546
611
|
const previousOutline = el2.style.outline;
|
|
547
612
|
const previousOffset = el2.style.outlineOffset;
|
|
548
|
-
el2.style.outline = `2px solid ${
|
|
613
|
+
el2.style.outline = `2px solid ${ringColor(el2, options.chat)}`;
|
|
549
614
|
el2.style.outlineOffset = "2px";
|
|
550
615
|
await delay(highlightMs);
|
|
551
616
|
el2.style.outline = previousOutline;
|
|
@@ -597,7 +662,8 @@ async function flashRing(el2, options, focusByDefault) {
|
|
|
597
662
|
scrim: options.scrim === true,
|
|
598
663
|
gradient: options.gradient === true,
|
|
599
664
|
...options.color === void 0 ? {} : { color: options.color },
|
|
600
|
-
...options.ringPadding === void 0 ? {} : { padding: options.ringPadding }
|
|
665
|
+
...options.ringPadding === void 0 ? {} : { padding: options.ringPadding },
|
|
666
|
+
...options.chat === void 0 ? {} : { chat: options.chat }
|
|
601
667
|
});
|
|
602
668
|
await delay(flashMs);
|
|
603
669
|
dismiss();
|
|
@@ -606,7 +672,7 @@ async function flashRing(el2, options, focusByDefault) {
|
|
|
606
672
|
const previousOutline = el2.style.outline;
|
|
607
673
|
const previousOffset = el2.style.outlineOffset;
|
|
608
674
|
const previousTransition = el2.style.transition;
|
|
609
|
-
const color = options.color ??
|
|
675
|
+
const color = options.color ?? ringColor(el2, options.chat);
|
|
610
676
|
el2.style.outline = `3px solid ${color}`;
|
|
611
677
|
el2.style.outlineOffset = "2px";
|
|
612
678
|
const fadeMs = prefersReducedMotion() ? 0 : Math.round(flashMs * FLASH_FADE_RATIO);
|
|
@@ -633,7 +699,7 @@ async function pressThenClick(el2, options = {}) {
|
|
|
633
699
|
const previousShadow = el2.style.boxShadow;
|
|
634
700
|
el2.style.transition = "transform 80ms ease";
|
|
635
701
|
el2.style.transform = "scale(0.96)";
|
|
636
|
-
el2.style.boxShadow = ringShadow(el2);
|
|
702
|
+
el2.style.boxShadow = ringShadow(el2, options.chat);
|
|
637
703
|
await motionDelay(pressMs);
|
|
638
704
|
el2.style.transform = previousTransform;
|
|
639
705
|
el2.style.transition = previousTransition;
|
|
@@ -656,7 +722,7 @@ async function selectOption(el2, value, options = {}) {
|
|
|
656
722
|
const highlightMs = options.highlightMs ?? 220;
|
|
657
723
|
const previousOutline = el2.style.outline;
|
|
658
724
|
const previousOffset = el2.style.outlineOffset;
|
|
659
|
-
el2.style.outline = `2px solid ${
|
|
725
|
+
el2.style.outline = `2px solid ${ringColor(el2, options.chat)}`;
|
|
660
726
|
el2.style.outlineOffset = "2px";
|
|
661
727
|
await motionDelay(highlightMs);
|
|
662
728
|
setNativeValue(el2, option.value);
|
|
@@ -668,7 +734,7 @@ async function selectOption(el2, value, options = {}) {
|
|
|
668
734
|
async function toggleControl(el2, checked, options = {}) {
|
|
669
735
|
const flashMs = options.flashMs ?? 200;
|
|
670
736
|
const previousShadow = el2.style.boxShadow;
|
|
671
|
-
el2.style.boxShadow = ringShadow(el2);
|
|
737
|
+
el2.style.boxShadow = ringShadow(el2, options.chat);
|
|
672
738
|
await motionDelay(flashMs);
|
|
673
739
|
setNativeChecked(el2, checked);
|
|
674
740
|
el2.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4422,7 +4488,7 @@ var ConversationHistory = class {
|
|
|
4422
4488
|
this.#host.conversationStore().setActiveThread(threadId);
|
|
4423
4489
|
this.#threadId = threadId;
|
|
4424
4490
|
this.#host.setRunning(false);
|
|
4425
|
-
await this.rehydrate();
|
|
4491
|
+
await this.rehydrate("switch");
|
|
4426
4492
|
}
|
|
4427
4493
|
/** Rename a thread, then reload the list that shows its title. */
|
|
4428
4494
|
renameThread(threadId, title) {
|
|
@@ -4440,6 +4506,7 @@ var ConversationHistory = class {
|
|
|
4440
4506
|
this.#host.resetState();
|
|
4441
4507
|
this.adoptActiveThread();
|
|
4442
4508
|
this.#host.setRunning(false);
|
|
4509
|
+
this.#host.threadChanged(this.#threadId, "delete");
|
|
4443
4510
|
}
|
|
4444
4511
|
void this.refreshDrawer();
|
|
4445
4512
|
}
|
|
@@ -4616,8 +4683,11 @@ var ConversationHistory = class {
|
|
|
4616
4683
|
* for the run it would have resumed -- unless what replaced it is a restore
|
|
4617
4684
|
* of the same conversation, still current, which answers for that run
|
|
4618
4685
|
* instead; see `#forgetStopped`.
|
|
4686
|
+
*
|
|
4687
|
+
* `reason` is what the thread event this restore ends with reports as why
|
|
4688
|
+
* the conversation changed. A restore that is stopped reports nothing.
|
|
4619
4689
|
*/
|
|
4620
|
-
async rehydrate() {
|
|
4690
|
+
async rehydrate(reason) {
|
|
4621
4691
|
this.#generation += 1;
|
|
4622
4692
|
const generation = this.#generation;
|
|
4623
4693
|
const threadId = this.#threadId;
|
|
@@ -4667,11 +4737,17 @@ var ConversationHistory = class {
|
|
|
4667
4737
|
}
|
|
4668
4738
|
}
|
|
4669
4739
|
}
|
|
4740
|
+
if (checkpoint === null) {
|
|
4741
|
+
this.#noticeIfRunUnfinished(messages);
|
|
4742
|
+
}
|
|
4743
|
+
this.#host.threadChanged(threadId, reason);
|
|
4670
4744
|
if (checkpoint !== null) {
|
|
4745
|
+
if (!this.#restoring(generation)) {
|
|
4746
|
+
this.#forgetStopped(store, threadId, checkpoint);
|
|
4747
|
+
return;
|
|
4748
|
+
}
|
|
4671
4749
|
await this.#resumeFrom(checkpoint, generation);
|
|
4672
|
-
return;
|
|
4673
4750
|
}
|
|
4674
|
-
this.#noticeIfRunUnfinished(messages);
|
|
4675
4751
|
} finally {
|
|
4676
4752
|
hold.release();
|
|
4677
4753
|
if (this.#loading === waiting) {
|
|
@@ -5652,6 +5728,8 @@ function surfaceFor(placement) {
|
|
|
5652
5728
|
|
|
5653
5729
|
// src/ui/placement/panel_placement.ts
|
|
5654
5730
|
var SIZE_KEY = "ag-ui-chat:size";
|
|
5731
|
+
var DRAG_WIDTH = "--_drag-width";
|
|
5732
|
+
var DRAG_HEIGHT = "--_drag-height";
|
|
5655
5733
|
var LAUNCHER_KEY = "ag-ui-chat:launcher";
|
|
5656
5734
|
function asPoint(value) {
|
|
5657
5735
|
if (typeof value !== "object" || value === null) {
|
|
@@ -5735,6 +5813,17 @@ var PanelPlacement = class {
|
|
|
5735
5813
|
restoreSize() {
|
|
5736
5814
|
this.#applySize(this.#readSize());
|
|
5737
5815
|
}
|
|
5816
|
+
/**
|
|
5817
|
+
* Drop the dragged size and its stored copy, so the placement's own size and
|
|
5818
|
+
* the host's tokens apply again. For a host entering a sized state of its
|
|
5819
|
+
* own, which a user's drag would otherwise outrank.
|
|
5820
|
+
*/
|
|
5821
|
+
resetSize() {
|
|
5822
|
+
this.#host.element.style.removeProperty(DRAG_WIDTH);
|
|
5823
|
+
this.#host.element.style.removeProperty(DRAG_HEIGHT);
|
|
5824
|
+
this.#host.clearPreference(SIZE_KEY);
|
|
5825
|
+
this.syncResizeAnchor();
|
|
5826
|
+
}
|
|
5738
5827
|
/**
|
|
5739
5828
|
* A zero-sized box carrying the host's viewport insets as padding, so they
|
|
5740
5829
|
* can be read back as used pixel lengths. See the `.viewport-probe` rule for
|
|
@@ -5923,12 +6012,12 @@ var PanelPlacement = class {
|
|
|
5923
6012
|
*/
|
|
5924
6013
|
#measureAnchor() {
|
|
5925
6014
|
const before = this.#host.element.getBoundingClientRect();
|
|
5926
|
-
const width = this.#host.element.style.getPropertyValue(
|
|
5927
|
-
const height = this.#host.element.style.getPropertyValue(
|
|
6015
|
+
const width = this.#host.element.style.getPropertyValue(DRAG_WIDTH);
|
|
6016
|
+
const height = this.#host.element.style.getPropertyValue(DRAG_HEIGHT);
|
|
5928
6017
|
const shrunk = this.#probeAnchor(before, -1);
|
|
5929
6018
|
const grown = shrunk.x === null || shrunk.y === null ? this.#probeAnchor(before, 1) : shrunk;
|
|
5930
|
-
this.#restoreProperty(
|
|
5931
|
-
this.#restoreProperty(
|
|
6019
|
+
this.#restoreProperty(DRAG_WIDTH, width);
|
|
6020
|
+
this.#restoreProperty(DRAG_HEIGHT, height);
|
|
5932
6021
|
return {
|
|
5933
6022
|
// Neither direction moved it: the axis cannot be resized at all, so the
|
|
5934
6023
|
// floating default is the best answer available and is the one the
|
|
@@ -5974,7 +6063,7 @@ var PanelPlacement = class {
|
|
|
5974
6063
|
/**
|
|
5975
6064
|
* Write a dragged size onto the host, on the axes this placement leaves free.
|
|
5976
6065
|
*
|
|
5977
|
-
* Writing
|
|
6066
|
+
* Writing a custom property rather than inline `width` / `height` does not
|
|
5978
6067
|
* by itself leave placement in charge: an inline custom property still
|
|
5979
6068
|
* outranks a `:host([placement=…])` rule setting the same property, so a
|
|
5980
6069
|
* height dragged while floating would cap a docked sidebar asking for
|
|
@@ -5988,10 +6077,10 @@ var PanelPlacement = class {
|
|
|
5988
6077
|
return;
|
|
5989
6078
|
}
|
|
5990
6079
|
if (size.width !== void 0) {
|
|
5991
|
-
this.#host.element.style.setProperty(
|
|
6080
|
+
this.#host.element.style.setProperty(DRAG_WIDTH, `${size.width}px`);
|
|
5992
6081
|
}
|
|
5993
6082
|
if (size.height !== void 0 && axis === "both") {
|
|
5994
|
-
this.#host.element.style.setProperty(
|
|
6083
|
+
this.#host.element.style.setProperty(DRAG_HEIGHT, `${size.height}px`);
|
|
5995
6084
|
}
|
|
5996
6085
|
}
|
|
5997
6086
|
/**
|
|
@@ -6004,10 +6093,10 @@ var PanelPlacement = class {
|
|
|
6004
6093
|
releaseOwnedAxes() {
|
|
6005
6094
|
const axis = this.#resizeAxis();
|
|
6006
6095
|
if (axis !== "both") {
|
|
6007
|
-
this.#host.element.style.removeProperty(
|
|
6096
|
+
this.#host.element.style.removeProperty(DRAG_HEIGHT);
|
|
6008
6097
|
}
|
|
6009
6098
|
if (axis === "none") {
|
|
6010
|
-
this.#host.element.style.removeProperty(
|
|
6099
|
+
this.#host.element.style.removeProperty(DRAG_WIDTH);
|
|
6011
6100
|
}
|
|
6012
6101
|
}
|
|
6013
6102
|
/**
|
|
@@ -6910,9 +6999,7 @@ var ToolCallCard = class {
|
|
|
6910
6999
|
this.#formatPayload = options.formatPayload ?? null;
|
|
6911
7000
|
this.element = document.createElement("div");
|
|
6912
7001
|
this.element.className = "tool-call";
|
|
6913
|
-
this.element.setAttribute("part", "tool-card");
|
|
6914
7002
|
this.element.setAttribute("data-tool-name", name);
|
|
6915
|
-
this.element.setAttribute("data-status", TOOL_CALL_STATUS.PENDING);
|
|
6916
7003
|
this.element.setAttribute("data-expanded", "false");
|
|
6917
7004
|
const head = document.createElement("div");
|
|
6918
7005
|
head.className = "tool-call-head";
|
|
@@ -6927,8 +7014,7 @@ var ToolCallCard = class {
|
|
|
6927
7014
|
label.textContent = summary ?? name;
|
|
6928
7015
|
this.#status = document.createElement("span");
|
|
6929
7016
|
this.#status.className = "tool-call-status";
|
|
6930
|
-
this.#
|
|
6931
|
-
this.#status.textContent = statusLabels(strings)[TOOL_CALL_STATUS.PENDING];
|
|
7017
|
+
this.#setStatus(TOOL_CALL_STATUS.PENDING);
|
|
6932
7018
|
this.#decision = document.createElement("span");
|
|
6933
7019
|
this.#decision.className = "tool-call-decision";
|
|
6934
7020
|
this.#decision.setAttribute("part", "tool-card-decision");
|
|
@@ -6976,8 +7062,7 @@ var ToolCallCard = class {
|
|
|
6976
7062
|
if (this.#settled) {
|
|
6977
7063
|
return;
|
|
6978
7064
|
}
|
|
6979
|
-
this
|
|
6980
|
-
this.#status.textContent = statusLabels(this.#strings)[status];
|
|
7065
|
+
this.#setStatus(status);
|
|
6981
7066
|
}
|
|
6982
7067
|
/**
|
|
6983
7068
|
* Say whether a prompt is open on this call, a question it asked or a
|
|
@@ -7012,8 +7097,7 @@ var ToolCallCard = class {
|
|
|
7012
7097
|
return;
|
|
7013
7098
|
}
|
|
7014
7099
|
this.#settled = true;
|
|
7015
|
-
this
|
|
7016
|
-
this.#status.textContent = statusLabels(this.#strings)[status];
|
|
7100
|
+
this.#setStatus(status);
|
|
7017
7101
|
this.#resultLabel.textContent = resultLabels(this.#strings)[status];
|
|
7018
7102
|
this.#renderPayload(
|
|
7019
7103
|
this.#resultBody,
|
|
@@ -7022,6 +7106,20 @@ var ToolCallCard = class {
|
|
|
7022
7106
|
);
|
|
7023
7107
|
this.#resultSection.hidden = false;
|
|
7024
7108
|
}
|
|
7109
|
+
/**
|
|
7110
|
+
* Write the status everywhere it is read from, in one place so they cannot
|
|
7111
|
+
* disagree: `data-status` for the shadow CSS, the pill's text, and the part
|
|
7112
|
+
* lists. `::part()` takes no attribute selector, so the card and its pill also
|
|
7113
|
+
* name the status as a part (`tool-card-error`, `tool-card-status-error`), the
|
|
7114
|
+
* modifier convention a run notice uses, and a host styles failures alone.
|
|
7115
|
+
* Setting the whole list replaces the previous modifier.
|
|
7116
|
+
*/
|
|
7117
|
+
#setStatus(status) {
|
|
7118
|
+
this.element.setAttribute("data-status", status);
|
|
7119
|
+
this.element.setAttribute("part", `tool-card tool-card-${status}`);
|
|
7120
|
+
this.#status.setAttribute("part", `tool-card-status tool-card-status-${status}`);
|
|
7121
|
+
this.#status.textContent = statusLabels(this.#strings)[status];
|
|
7122
|
+
}
|
|
7025
7123
|
/**
|
|
7026
7124
|
* Fill one body region, offering it to the host formatter first.
|
|
7027
7125
|
*
|
|
@@ -8373,8 +8471,8 @@ var EMBEDDED_STYLES = `
|
|
|
8373
8471
|
the widget lives in the host's own layout (fixes overlay/z-index clashes). */
|
|
8374
8472
|
:host([placement="embedded"]) {
|
|
8375
8473
|
--_position: var(--ag-ui-position, static);
|
|
8376
|
-
--_width: var(--ag-ui-width, 100%);
|
|
8377
|
-
--_height: var(--ag-ui-height, 100%);
|
|
8474
|
+
--_width: var(--_drag-width, var(--ag-ui-width, 100%));
|
|
8475
|
+
--_height: var(--_drag-height, var(--ag-ui-height, 100%));
|
|
8378
8476
|
--_max-width: var(--ag-ui-max-width, 100%);
|
|
8379
8477
|
--_max-height: var(--ag-ui-max-height, 100%);
|
|
8380
8478
|
--_shadow: var(--ag-ui-shadow, none);
|
|
@@ -8632,7 +8730,7 @@ var PRESET_STYLES = `
|
|
|
8632
8730
|
|
|
8633
8731
|
:host([placement="side"]) {
|
|
8634
8732
|
--_inset: var(--ag-ui-inset, calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) var(--_viewport-inset-right) var(--_viewport-inset-bottom) auto);
|
|
8635
|
-
--_width: var(--ag-ui-width, 420px);
|
|
8733
|
+
--_width: var(--_drag-width, var(--ag-ui-width, 420px));
|
|
8636
8734
|
--_height: var(--ag-ui-height, var(--_viewport-height));
|
|
8637
8735
|
--_max-height: var(--ag-ui-max-height, var(--_viewport-height));
|
|
8638
8736
|
--_panel-radius: var(--ag-ui-panel-radius, 0);
|
|
@@ -8848,7 +8946,7 @@ var SIDEBAR_STYLES = `
|
|
|
8848
8946
|
host-managed push instead. */
|
|
8849
8947
|
:host([placement="sidebar"]) {
|
|
8850
8948
|
--_inset: var(--ag-ui-inset, calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) var(--_viewport-inset-right) var(--_viewport-inset-bottom) auto);
|
|
8851
|
-
--_width: var(--ag-ui-width, 420px);
|
|
8949
|
+
--_width: var(--_drag-width, var(--ag-ui-width, 420px));
|
|
8852
8950
|
--_height: var(--ag-ui-height, var(--_viewport-height));
|
|
8853
8951
|
--_max-height: var(--ag-ui-max-height, var(--_viewport-height));
|
|
8854
8952
|
--_panel-radius: var(--ag-ui-panel-radius, 0);
|
|
@@ -8947,6 +9045,11 @@ var SMALL_VIEWPORT_STYLES = `
|
|
|
8947
9045
|
fine-pointered and small, and conflating the two gets both wrong. What the
|
|
8948
9046
|
pointer decides is which controls make sense, further down.
|
|
8949
9047
|
|
|
9048
|
+
The size the user dragged is deliberately not read here. The desktop
|
|
9049
|
+
placements read it before the host token, and this block restates the sizes
|
|
9050
|
+
without it, so a persisted or freshly dragged size cannot change the shape
|
|
9051
|
+
of a phone, and a window narrowed after a drag goes full-bleed.
|
|
9052
|
+
|
|
8950
9053
|
Two placements are left alone. "page" is already this shape. "embedded" sits
|
|
8951
9054
|
in a box the host sized and placed, and taking that over would break the app
|
|
8952
9055
|
shell it was embedded into -- the host is the only party that knows whether
|
|
@@ -10227,8 +10330,8 @@ var TOKEN_STYLES = `
|
|
|
10227
10330
|
grid/flex layout) to embed it in the page flow instead of floating. */
|
|
10228
10331
|
--_position: var(--ag-ui-position, fixed);
|
|
10229
10332
|
--_z-index: var(--ag-ui-z-index, 2147483000);
|
|
10230
|
-
--_width: var(--ag-ui-width, 380px);
|
|
10231
|
-
--_height: var(--ag-ui-height, 560px);
|
|
10333
|
+
--_width: var(--_drag-width, var(--ag-ui-width, 380px));
|
|
10334
|
+
--_height: var(--_drag-height, var(--ag-ui-height, 560px));
|
|
10232
10335
|
/* The gutter a resting floating panel keeps between itself and the edge of
|
|
10233
10336
|
the box the host left free. One number, because the inset below spends it
|
|
10234
10337
|
and the cap beneath has to know it was spent. */
|
|
@@ -16292,6 +16395,7 @@ var ToolStepGroup = class {
|
|
|
16292
16395
|
state = "error";
|
|
16293
16396
|
}
|
|
16294
16397
|
this.element.setAttribute("data-state", state);
|
|
16398
|
+
this.element.setAttribute("part", `tool-group tool-group-${state}`);
|
|
16295
16399
|
this.element.setAttribute("data-count", String(total));
|
|
16296
16400
|
const only = total === 1 ? steps[0] : void 0;
|
|
16297
16401
|
if (only !== void 0) {
|
|
@@ -17998,8 +18102,13 @@ var RunHandlers = class {
|
|
|
17998
18102
|
* A handler table for one AG-UI client. Every table built for the current
|
|
17999
18103
|
* conversation draws into the same transcript and shares its bookkeeping, so
|
|
18000
18104
|
* a continuation run reports into the interaction the user is looking at.
|
|
18105
|
+
*
|
|
18106
|
+
* `threadId` is the thread the client was built for, named on the
|
|
18107
|
+
* run-finished detail. Taken here rather than read when the run settles,
|
|
18108
|
+
* because a stopped run settles after the reset that stopped it, when the
|
|
18109
|
+
* thread on screen is already the next one.
|
|
18001
18110
|
*/
|
|
18002
|
-
forClient() {
|
|
18111
|
+
forClient(threadId) {
|
|
18003
18112
|
const ledger = this.#ledger;
|
|
18004
18113
|
const attached = () => ledger === this.#ledger;
|
|
18005
18114
|
const { onSettled, ...drawing } = this.#tableFor(ledger);
|
|
@@ -18009,7 +18118,7 @@ var RunHandlers = class {
|
|
|
18009
18118
|
if (attached()) {
|
|
18010
18119
|
onSettled();
|
|
18011
18120
|
}
|
|
18012
|
-
this.#dispatchRunFinished(ledger);
|
|
18121
|
+
this.#dispatchRunFinished(ledger, threadId);
|
|
18013
18122
|
}
|
|
18014
18123
|
};
|
|
18015
18124
|
}
|
|
@@ -18162,7 +18271,7 @@ var RunHandlers = class {
|
|
|
18162
18271
|
* server is a fact about the run, and a name can appear on both sides across a
|
|
18163
18272
|
* conversation.
|
|
18164
18273
|
*/
|
|
18165
|
-
#dispatchRunFinished(ledger) {
|
|
18274
|
+
#dispatchRunFinished(ledger, threadId) {
|
|
18166
18275
|
const tools = ledger.tools.map(({ id, name }) => ({
|
|
18167
18276
|
name,
|
|
18168
18277
|
side: ledger.serverSettled.has(id) ? "server" : "client"
|
|
@@ -18173,7 +18282,7 @@ var RunHandlers = class {
|
|
|
18173
18282
|
ledger.invalidated.clear();
|
|
18174
18283
|
this.#host.element.dispatchEvent(
|
|
18175
18284
|
new CustomEvent(RUN_FINISHED_EVENT, {
|
|
18176
|
-
detail: { tools, invalidated },
|
|
18285
|
+
detail: { threadId, tools, invalidated },
|
|
18177
18286
|
bubbles: true,
|
|
18178
18287
|
composed: true
|
|
18179
18288
|
})
|
|
@@ -18992,6 +19101,11 @@ var AgUiChat = class extends HTMLElement {
|
|
|
18992
19101
|
* then a host's {@link sendMessage} waits for it rather than refusing.
|
|
18993
19102
|
*/
|
|
18994
19103
|
#restoreHold = null;
|
|
19104
|
+
/**
|
|
19105
|
+
* The thread the latest {@link THREAD_EVENT} reported, which the next one
|
|
19106
|
+
* names as the thread it replaced; `null` before the first.
|
|
19107
|
+
*/
|
|
19108
|
+
#shownThread = null;
|
|
18995
19109
|
/** The decision a run is suspended on, which a Stop abandons. */
|
|
18996
19110
|
#decision = new PendingDecision();
|
|
18997
19111
|
/**
|
|
@@ -19023,6 +19137,8 @@ var AgUiChat = class extends HTMLElement {
|
|
|
19023
19137
|
allowImages: () => this.allowImages,
|
|
19024
19138
|
follow: () => this.#transcript.follow()
|
|
19025
19139
|
});
|
|
19140
|
+
// This chat's place among the connected ones, which a free highlight ring reads.
|
|
19141
|
+
#chatRegistration = new ChatRegistration(this);
|
|
19026
19142
|
/**
|
|
19027
19143
|
* Which storage keys are this element's: the namespace it claims, the keys
|
|
19028
19144
|
* its layout preferences live under, and the built-in store scoped to them.
|
|
@@ -19270,7 +19386,8 @@ var AgUiChat = class extends HTMLElement {
|
|
|
19270
19386
|
},
|
|
19271
19387
|
cancelRun: () => this.#cancelRun(),
|
|
19272
19388
|
resetState: () => this.#resetState(),
|
|
19273
|
-
setRunning: (running) => this.#setRunning(running)
|
|
19389
|
+
setRunning: (running) => this.#setRunning(running),
|
|
19390
|
+
threadChanged: (threadId, reason) => this.#dispatchThread(threadId, reason)
|
|
19274
19391
|
});
|
|
19275
19392
|
}
|
|
19276
19393
|
/** Attributes the element reacts to after it has been connected. */
|
|
@@ -19583,6 +19700,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
19583
19700
|
}
|
|
19584
19701
|
this.#connectedBefore = true;
|
|
19585
19702
|
this.#storage.claim();
|
|
19703
|
+
this.#chatRegistration.join();
|
|
19586
19704
|
this.#placement.restoreSize();
|
|
19587
19705
|
requestAnimationFrame(() => {
|
|
19588
19706
|
this.#placement.restoreLauncherPosition();
|
|
@@ -19620,7 +19738,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
19620
19738
|
this.#voice.wire();
|
|
19621
19739
|
this.#history.adoptActiveThread();
|
|
19622
19740
|
queueMicrotask(() => this.#startup());
|
|
19623
|
-
void this.#history.rehydrate();
|
|
19741
|
+
void this.#history.rehydrate(changed && held !== "" ? "rescope" : "restore");
|
|
19624
19742
|
if (changed) {
|
|
19625
19743
|
void this.#history.refreshDrawer();
|
|
19626
19744
|
}
|
|
@@ -19673,7 +19791,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
19673
19791
|
await Promise.all([
|
|
19674
19792
|
this.#tools.fetchCatalog(),
|
|
19675
19793
|
this.#skills.fetch(),
|
|
19676
|
-
this.#history.rehydrate()
|
|
19794
|
+
this.#history.rehydrate("restore")
|
|
19677
19795
|
]);
|
|
19678
19796
|
}
|
|
19679
19797
|
/**
|
|
@@ -19689,6 +19807,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
19689
19807
|
window.visualViewport?.removeEventListener("resize", this.#onViewportResize);
|
|
19690
19808
|
window.visualViewport?.removeEventListener("scroll", this.#onViewportResize);
|
|
19691
19809
|
this.#storage.release();
|
|
19810
|
+
this.#chatRegistration.leave();
|
|
19692
19811
|
this.#cancelRun();
|
|
19693
19812
|
this.#excerpts.detachPageOffer();
|
|
19694
19813
|
this.#attachments.tray?.dispose();
|
|
@@ -19836,6 +19955,26 @@ var AgUiChat = class extends HTMLElement {
|
|
|
19836
19955
|
get unread() {
|
|
19837
19956
|
return this.#unread;
|
|
19838
19957
|
}
|
|
19958
|
+
/**
|
|
19959
|
+
* The thread on screen; `null` before the element first connects.
|
|
19960
|
+
*
|
|
19961
|
+
* Only reads. `conversationStore.threadId()` mints and stores a thread when
|
|
19962
|
+
* the store points at none, so a host asking which conversation is showing
|
|
19963
|
+
* could start one; this never does. {@link THREAD_EVENT} says when it changes.
|
|
19964
|
+
*/
|
|
19965
|
+
get threadId() {
|
|
19966
|
+
const threadId = this.#history.threadId;
|
|
19967
|
+
return threadId === "" ? null : threadId;
|
|
19968
|
+
}
|
|
19969
|
+
/**
|
|
19970
|
+
* Whether an interaction is in flight: the composer's own state, the one that
|
|
19971
|
+
* shows Stop. It spans every tool round, a retry and a checkpoint
|
|
19972
|
+
* continuation as well as a send, which {@link SUBMIT_EVENT} alone does not.
|
|
19973
|
+
* Reflected as `data-running` on the element, for a host's CSS.
|
|
19974
|
+
*/
|
|
19975
|
+
get running() {
|
|
19976
|
+
return this.#running;
|
|
19977
|
+
}
|
|
19839
19978
|
/**
|
|
19840
19979
|
* Whether to mount collapsed.
|
|
19841
19980
|
*
|
|
@@ -19886,6 +20025,13 @@ var AgUiChat = class extends HTMLElement {
|
|
|
19886
20025
|
moveTo(corner, options = {}) {
|
|
19887
20026
|
return this.#placement.moveTo(corner, options);
|
|
19888
20027
|
}
|
|
20028
|
+
/**
|
|
20029
|
+
* Drop a size the user dragged, and its stored copy, so the placement's
|
|
20030
|
+
* default and the host's `--ag-ui-width` / `--ag-ui-height` apply again.
|
|
20031
|
+
*/
|
|
20032
|
+
resetSize() {
|
|
20033
|
+
this.#placement.resetSize();
|
|
20034
|
+
}
|
|
19889
20035
|
/** Flip the collapsed state. Bound to the built-in header toggle. */
|
|
19890
20036
|
toggleCollapsed() {
|
|
19891
20037
|
this.setCollapsed(!this.collapsed);
|
|
@@ -19955,7 +20101,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
19955
20101
|
this.#voice.dispose();
|
|
19956
20102
|
this.#voice.wire();
|
|
19957
20103
|
this.#history.adoptActiveThread();
|
|
19958
|
-
void this.#history.rehydrate();
|
|
20104
|
+
void this.#history.rehydrate("rescope");
|
|
19959
20105
|
void this.#history.refreshDrawer();
|
|
19960
20106
|
}
|
|
19961
20107
|
/**
|
|
@@ -20016,6 +20162,34 @@ var AgUiChat = class extends HTMLElement {
|
|
|
20016
20162
|
closeCheckpoints() {
|
|
20017
20163
|
this.#checkpoints.close();
|
|
20018
20164
|
}
|
|
20165
|
+
/**
|
|
20166
|
+
* Put a stored thread on screen, as picking it in the conversation list does,
|
|
20167
|
+
* for a host that lists conversations in its own chrome.
|
|
20168
|
+
*
|
|
20169
|
+
* Resolves once the thread has been replayed, when {@link THREAD_EVENT} has
|
|
20170
|
+
* fired. **A run in flight is cancelled**, as the list and {@link newChat} do;
|
|
20171
|
+
* a host that would rather wait reads {@link running} first. The thread
|
|
20172
|
+
* already on screen is left alone, and so is everything before the element
|
|
20173
|
+
* connects, since until then it has no store to read the thread from.
|
|
20174
|
+
*/
|
|
20175
|
+
async switchThread(threadId) {
|
|
20176
|
+
if (!this.#connected) {
|
|
20177
|
+
return;
|
|
20178
|
+
}
|
|
20179
|
+
await this.#history.switchThread(threadId);
|
|
20180
|
+
}
|
|
20181
|
+
/**
|
|
20182
|
+
* Delete a stored thread, as the conversation list's delete does. Deleting the
|
|
20183
|
+
* thread on screen cancels its run and puts a fresh thread in its place, and
|
|
20184
|
+
* {@link THREAD_EVENT} reports it; deleting another leaves the screen alone.
|
|
20185
|
+
* Does nothing before the element connects.
|
|
20186
|
+
*/
|
|
20187
|
+
deleteThread(threadId) {
|
|
20188
|
+
if (!this.#connected) {
|
|
20189
|
+
return;
|
|
20190
|
+
}
|
|
20191
|
+
this.#history.deleteThread(threadId);
|
|
20192
|
+
}
|
|
20019
20193
|
/**
|
|
20020
20194
|
* Open the checkpoints panel, or close it if it is already open — what the
|
|
20021
20195
|
* built-in ⭯ button does, because a control that opens a panel is read as the
|
|
@@ -20048,6 +20222,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
20048
20222
|
this.#history.startThread();
|
|
20049
20223
|
this.#setRunning(false);
|
|
20050
20224
|
this.#setUnread(0);
|
|
20225
|
+
this.#dispatchThread(this.#history.threadId, "new");
|
|
20051
20226
|
if (!this.collapsed) {
|
|
20052
20227
|
this.#input.focus({ preventScroll: true });
|
|
20053
20228
|
}
|
|
@@ -20240,6 +20415,8 @@ var AgUiChat = class extends HTMLElement {
|
|
|
20240
20415
|
},
|
|
20241
20416
|
onFilesPicked: () => this.#attachments.onFilesPicked()
|
|
20242
20417
|
});
|
|
20418
|
+
const aboveComposer = document.createElement("slot");
|
|
20419
|
+
aboveComposer.name = "above-composer";
|
|
20243
20420
|
const footer = document.createElement("slot");
|
|
20244
20421
|
footer.name = "footer";
|
|
20245
20422
|
this.#messagesWrap.className = "messages-wrap";
|
|
@@ -20252,6 +20429,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
20252
20429
|
this.#composerHint,
|
|
20253
20430
|
this.#queuedRow,
|
|
20254
20431
|
this.#attachSlot,
|
|
20432
|
+
aboveComposer,
|
|
20255
20433
|
inputRow,
|
|
20256
20434
|
footer,
|
|
20257
20435
|
this.#drawer.element,
|
|
@@ -20419,6 +20597,21 @@ var AgUiChat = class extends HTMLElement {
|
|
|
20419
20597
|
this.#sending = null;
|
|
20420
20598
|
this.#history.stopContinuation();
|
|
20421
20599
|
}
|
|
20600
|
+
/**
|
|
20601
|
+
* Say the conversation on screen changed: {@link THREAD_EVENT}.
|
|
20602
|
+
*
|
|
20603
|
+
* The thread it replaced is the one last reported, rather than the one the
|
|
20604
|
+
* element last pointed at: a switch superseded before it replayed never drew
|
|
20605
|
+
* its thread, so naming it as the previous one left a host's own list
|
|
20606
|
+
* marking a thread that was never shown and still marking the one that was.
|
|
20607
|
+
*/
|
|
20608
|
+
#dispatchThread(threadId, reason) {
|
|
20609
|
+
const detail = { threadId, previousThreadId: this.#shownThread, reason };
|
|
20610
|
+
this.#shownThread = threadId;
|
|
20611
|
+
this.dispatchEvent(
|
|
20612
|
+
new CustomEvent(THREAD_EVENT, { detail, bubbles: true, composed: true })
|
|
20613
|
+
);
|
|
20614
|
+
}
|
|
20422
20615
|
/**
|
|
20423
20616
|
* Swap the composer button between Send (idle) and Stop (running).
|
|
20424
20617
|
*
|
|
@@ -20436,6 +20629,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
20436
20629
|
this.#send.title = label;
|
|
20437
20630
|
this.#send.setAttribute("aria-label", label);
|
|
20438
20631
|
this.#send.dataset["state"] = running ? "running" : "idle";
|
|
20632
|
+
this.toggleAttribute("data-running", running);
|
|
20439
20633
|
if (settled) {
|
|
20440
20634
|
this.#flushQueued();
|
|
20441
20635
|
}
|
|
@@ -20724,7 +20918,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
20724
20918
|
});
|
|
20725
20919
|
return new AgUiClient({
|
|
20726
20920
|
agent,
|
|
20727
|
-
handlers: this.#runHandlers.forClient(),
|
|
20921
|
+
handlers: this.#runHandlers.forClient(threadId),
|
|
20728
20922
|
getTools: () => this.#tools.advertise(),
|
|
20729
20923
|
getContext: () => this.#dispatch.buildContext(),
|
|
20730
20924
|
executeTool: (call) => this.#dispatch.execute(call),
|
|
@@ -20918,7 +21112,7 @@ function setControlValue(el2, value) {
|
|
|
20918
21112
|
}
|
|
20919
21113
|
|
|
20920
21114
|
// src/version.ts
|
|
20921
|
-
var VERSION = "0.
|
|
21115
|
+
var VERSION = "0.47.0";
|
|
20922
21116
|
export {
|
|
20923
21117
|
ATTACHMENT_EVENT,
|
|
20924
21118
|
AgUiChat,
|
|
@@ -20951,6 +21145,7 @@ export {
|
|
|
20951
21145
|
SUBMIT_EVENT,
|
|
20952
21146
|
SUGGESTIONS_ACTIVITY_TYPE,
|
|
20953
21147
|
SessionStorageStore,
|
|
21148
|
+
THREAD_EVENT,
|
|
20954
21149
|
TOGGLE_EVENT,
|
|
20955
21150
|
TOOL_CALL_STATUS,
|
|
20956
21151
|
TOOL_DISPLAY,
|