@artooi/ag-ui-web-component 0.17.0 → 0.18.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 +46 -1
- package/README.md +11 -3
- package/dist/ag-ui-web-component.bundle.js +92 -46
- package/dist/ag-ui-web-component.bundle.js.map +4 -4
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/index.js +209 -53
- package/dist/index.js.map +4 -4
- package/dist/ui/attach_copy_buttons.d.ts +19 -0
- package/dist/ui/attach_copy_buttons.d.ts.map +1 -0
- package/dist/ui/checkpoint_menu.d.ts.map +1 -1
- package/dist/ui/styles.d.ts +1 -1
- package/dist/ui/styles.d.ts.map +1 -1
- package/dist/ui/ui_strings.d.ts +6 -0
- package/dist/ui/ui_strings.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/ag_ui_chat.ts +24 -2
- package/src/ui/attach_copy_buttons.ts +82 -0
- package/src/ui/checkpoint_menu.ts +57 -6
- package/src/ui/styles.ts +46 -0
- package/src/ui/ui_strings.ts +9 -0
- package/src/version.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ag_ui_chat.d.ts","sourceRoot":"","sources":["../../src/core/ag_ui_chat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAsB,IAAI,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAKL,YAAY,EASb,MAAM,iBAAiB,CAAC;AAGzB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,KAAK,UAAU,EAAsB,MAAM,kCAAkC,CAAC;AAGvF,OAAO,EAAyB,KAAK,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAC9F,OAAO,EAAwB,KAAK,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC1E,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAE9E,OAAO,EAAoB,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"ag_ui_chat.d.ts","sourceRoot":"","sources":["../../src/core/ag_ui_chat.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -450,6 +450,9 @@ var DEFAULT_UI_STRINGS = {
|
|
|
450
450
|
collapse: "Collapse",
|
|
451
451
|
expand: "Expand",
|
|
452
452
|
toggleTheme: "Toggle theme",
|
|
453
|
+
copyCode: "Copy",
|
|
454
|
+
copied: "Copied",
|
|
455
|
+
copyFailed: "Copy failed",
|
|
453
456
|
checkpoints: "Continue a run",
|
|
454
457
|
noCheckpoints: "Nothing to continue yet.",
|
|
455
458
|
resumeRun: "Resume",
|
|
@@ -531,12 +534,12 @@ function mergeUiStrings(overrides) {
|
|
|
531
534
|
|
|
532
535
|
// src/ui/approval_card.ts
|
|
533
536
|
function actionButton(modifier, label) {
|
|
534
|
-
const
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
return
|
|
537
|
+
const button2 = document.createElement("button");
|
|
538
|
+
button2.type = "button";
|
|
539
|
+
button2.className = `approval-btn approval-btn--${modifier}`;
|
|
540
|
+
button2.setAttribute("part", `approval-button approval-${modifier}`);
|
|
541
|
+
button2.textContent = label;
|
|
542
|
+
return button2;
|
|
540
543
|
}
|
|
541
544
|
function requestApproval(host, request, options = {}) {
|
|
542
545
|
const strings = options.strings ?? DEFAULT_UI_STRINGS;
|
|
@@ -583,6 +586,55 @@ function requestApproval(host, request, options = {}) {
|
|
|
583
586
|
});
|
|
584
587
|
}
|
|
585
588
|
|
|
589
|
+
// src/ui/attach_copy_buttons.ts
|
|
590
|
+
var CONFIRM_MS = 1500;
|
|
591
|
+
function attachCopyButtons(root, strings) {
|
|
592
|
+
for (const pre of Array.from(root.querySelectorAll("pre"))) {
|
|
593
|
+
const code = pre.querySelector("code");
|
|
594
|
+
if (code === null || pre.querySelector(".code-copy") !== null) {
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
pre.classList.add("has-copy");
|
|
598
|
+
pre.append(button(code, strings));
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
function button(code, strings) {
|
|
602
|
+
const text2 = code.textContent;
|
|
603
|
+
const copy = document.createElement("button");
|
|
604
|
+
copy.type = "button";
|
|
605
|
+
copy.className = "code-copy";
|
|
606
|
+
copy.setAttribute("part", "code-copy");
|
|
607
|
+
copy.textContent = strings.copyCode;
|
|
608
|
+
copy.title = strings.copyCode;
|
|
609
|
+
copy.setAttribute("aria-label", strings.copyCode);
|
|
610
|
+
copy.addEventListener("click", () => {
|
|
611
|
+
void writeText(text2).then((ok) => {
|
|
612
|
+
confirm(copy, ok ? strings.copied : strings.copyFailed, strings);
|
|
613
|
+
});
|
|
614
|
+
});
|
|
615
|
+
return copy;
|
|
616
|
+
}
|
|
617
|
+
async function writeText(text2) {
|
|
618
|
+
const clipboard = navigator.clipboard;
|
|
619
|
+
if (clipboard === void 0) {
|
|
620
|
+
return false;
|
|
621
|
+
}
|
|
622
|
+
try {
|
|
623
|
+
await clipboard.writeText(text2);
|
|
624
|
+
return true;
|
|
625
|
+
} catch {
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
function confirm(copy, message, strings) {
|
|
630
|
+
copy.textContent = message;
|
|
631
|
+
copy.dataset["state"] = message === strings.copied ? "copied" : "failed";
|
|
632
|
+
setTimeout(() => {
|
|
633
|
+
copy.textContent = strings.copyCode;
|
|
634
|
+
delete copy.dataset["state"];
|
|
635
|
+
}, CONFIRM_MS);
|
|
636
|
+
}
|
|
637
|
+
|
|
586
638
|
// src/ui/attachment_chips.ts
|
|
587
639
|
function renderAttachmentChips(refs) {
|
|
588
640
|
const list = document.createElement("div");
|
|
@@ -885,6 +937,8 @@ var CheckpointMenu = class {
|
|
|
885
937
|
#onPick;
|
|
886
938
|
#list;
|
|
887
939
|
#heading;
|
|
940
|
+
/** What had focus before the panel opened, restored on close. */
|
|
941
|
+
#lastFocused = null;
|
|
888
942
|
#strings;
|
|
889
943
|
#runs = [];
|
|
890
944
|
constructor(onPick, strings = DEFAULT_UI_STRINGS) {
|
|
@@ -895,6 +949,7 @@ var CheckpointMenu = class {
|
|
|
895
949
|
this.element.setAttribute("part", "checkpoints");
|
|
896
950
|
this.element.setAttribute("role", "dialog");
|
|
897
951
|
this.element.setAttribute("aria-label", strings.checkpoints);
|
|
952
|
+
this.element.tabIndex = -1;
|
|
898
953
|
this.element.hidden = true;
|
|
899
954
|
const header = document.createElement("div");
|
|
900
955
|
header.className = "checkpoints-header";
|
|
@@ -908,12 +963,7 @@ var CheckpointMenu = class {
|
|
|
908
963
|
this.#list.className = "checkpoints-list";
|
|
909
964
|
this.#list.setAttribute("part", "checkpoints-list");
|
|
910
965
|
this.element.append(header, this.#list);
|
|
911
|
-
this.element.addEventListener("keydown", (event) =>
|
|
912
|
-
if (event.key === "Escape") {
|
|
913
|
-
event.stopPropagation();
|
|
914
|
-
this.close();
|
|
915
|
-
}
|
|
916
|
-
});
|
|
966
|
+
this.element.addEventListener("keydown", (event) => this.#onKeydown(event));
|
|
917
967
|
}
|
|
918
968
|
/** Replace the rows. The host passes only `continuable` runs. */
|
|
919
969
|
setRuns(runs) {
|
|
@@ -928,10 +978,52 @@ var CheckpointMenu = class {
|
|
|
928
978
|
this.#render();
|
|
929
979
|
}
|
|
930
980
|
open() {
|
|
981
|
+
if (this.open_) {
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
this.#lastFocused = this.#activeElement();
|
|
931
985
|
this.element.hidden = false;
|
|
986
|
+
(this.#focusables()[0] ?? this.element).focus();
|
|
932
987
|
}
|
|
933
988
|
close() {
|
|
989
|
+
if (!this.open_) {
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
934
992
|
this.element.hidden = true;
|
|
993
|
+
this.#lastFocused?.focus();
|
|
994
|
+
this.#lastFocused = null;
|
|
995
|
+
}
|
|
996
|
+
/** The focused element within this panel's root (shadow-aware). */
|
|
997
|
+
#activeElement() {
|
|
998
|
+
return this.element.getRootNode().activeElement;
|
|
999
|
+
}
|
|
1000
|
+
/** The panel's tabbable controls, in document order. */
|
|
1001
|
+
#focusables() {
|
|
1002
|
+
return Array.from(this.element.querySelectorAll("button, [tabindex]")).filter(
|
|
1003
|
+
(el) => !el.hidden
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
/** Escape closes; Tab is trapped so focus cannot wander behind the dialog. */
|
|
1007
|
+
#onKeydown(event) {
|
|
1008
|
+
if (event.key === "Escape") {
|
|
1009
|
+
event.stopPropagation();
|
|
1010
|
+
this.close();
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
if (event.key !== "Tab") {
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
const focusables = this.#focusables();
|
|
1017
|
+
const first = focusables[0];
|
|
1018
|
+
const last = focusables[focusables.length - 1];
|
|
1019
|
+
const active = this.#activeElement();
|
|
1020
|
+
if (event.shiftKey && active === first) {
|
|
1021
|
+
event.preventDefault();
|
|
1022
|
+
last?.focus();
|
|
1023
|
+
} else if (!event.shiftKey && active === last) {
|
|
1024
|
+
event.preventDefault();
|
|
1025
|
+
first?.focus();
|
|
1026
|
+
}
|
|
935
1027
|
}
|
|
936
1028
|
get open_() {
|
|
937
1029
|
return !this.element.hidden;
|
|
@@ -975,27 +1067,27 @@ var CheckpointMenu = class {
|
|
|
975
1067
|
return row;
|
|
976
1068
|
}
|
|
977
1069
|
#action(runId, verb, label) {
|
|
978
|
-
const
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1070
|
+
const button2 = document.createElement("button");
|
|
1071
|
+
button2.type = "button";
|
|
1072
|
+
button2.className = `checkpoint-action checkpoint-${verb}`;
|
|
1073
|
+
button2.setAttribute("part", `checkpoint-action checkpoint-${verb}`);
|
|
1074
|
+
button2.textContent = label;
|
|
1075
|
+
button2.addEventListener("click", () => {
|
|
984
1076
|
this.close();
|
|
985
1077
|
this.#onPick(runId, verb);
|
|
986
1078
|
});
|
|
987
|
-
return
|
|
1079
|
+
return button2;
|
|
988
1080
|
}
|
|
989
1081
|
};
|
|
990
1082
|
|
|
991
1083
|
// src/ui/confirmation_card.ts
|
|
992
1084
|
function actionButton2(modifier, label) {
|
|
993
|
-
const
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
return
|
|
1085
|
+
const button2 = document.createElement("button");
|
|
1086
|
+
button2.type = "button";
|
|
1087
|
+
button2.className = `confirm-btn confirm-btn--${modifier}`;
|
|
1088
|
+
button2.setAttribute("part", `confirm-button confirm-${modifier}`);
|
|
1089
|
+
button2.textContent = label;
|
|
1090
|
+
return button2;
|
|
999
1091
|
}
|
|
1000
1092
|
function requestConfirmation(host, request, options = {}) {
|
|
1001
1093
|
const strings = options.strings ?? DEFAULT_UI_STRINGS;
|
|
@@ -1018,7 +1110,7 @@ function requestConfirmation(host, request, options = {}) {
|
|
|
1018
1110
|
actions.className = "confirm-actions";
|
|
1019
1111
|
actions.setAttribute("part", "confirm-actions");
|
|
1020
1112
|
const cancel = actionButton2("cancel", strings.cancel);
|
|
1021
|
-
const
|
|
1113
|
+
const confirm2 = actionButton2("confirm", strings.confirm);
|
|
1022
1114
|
let settled = false;
|
|
1023
1115
|
const close = (accepted) => {
|
|
1024
1116
|
if (settled) {
|
|
@@ -1026,21 +1118,21 @@ function requestConfirmation(host, request, options = {}) {
|
|
|
1026
1118
|
}
|
|
1027
1119
|
settled = true;
|
|
1028
1120
|
cancel.disabled = true;
|
|
1029
|
-
|
|
1121
|
+
confirm2.disabled = true;
|
|
1030
1122
|
card.setAttribute("data-resolved", accepted ? "confirmed" : "declined");
|
|
1031
1123
|
resolve(accepted);
|
|
1032
1124
|
};
|
|
1033
1125
|
cancel.addEventListener("click", () => close(false));
|
|
1034
|
-
|
|
1126
|
+
confirm2.addEventListener("click", () => close(true));
|
|
1035
1127
|
options.signal?.addEventListener("abort", () => close(false), { once: true });
|
|
1036
|
-
actions.append(cancel,
|
|
1128
|
+
actions.append(cancel, confirm2);
|
|
1037
1129
|
card.append(body, args, actions);
|
|
1038
1130
|
host.appendChild(card);
|
|
1039
1131
|
if (options.signal?.aborted === true) {
|
|
1040
1132
|
close(false);
|
|
1041
1133
|
return;
|
|
1042
1134
|
}
|
|
1043
|
-
|
|
1135
|
+
confirm2.focus();
|
|
1044
1136
|
});
|
|
1045
1137
|
}
|
|
1046
1138
|
|
|
@@ -4193,13 +4285,13 @@ var SkillsMenu = class {
|
|
|
4193
4285
|
const chipSkills = this.#chipsEnabled ? this.#skills.filter((skill) => skill.chip === true) : [];
|
|
4194
4286
|
this.chips.hidden = chipSkills.length === 0;
|
|
4195
4287
|
for (const skill of chipSkills) {
|
|
4196
|
-
const
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
this.chips.appendChild(
|
|
4288
|
+
const button2 = document.createElement("button");
|
|
4289
|
+
button2.type = "button";
|
|
4290
|
+
button2.className = "skill-chip";
|
|
4291
|
+
button2.setAttribute("part", "skill-chip");
|
|
4292
|
+
button2.textContent = skill.title;
|
|
4293
|
+
button2.addEventListener("click", () => this.#pick(skill));
|
|
4294
|
+
this.chips.appendChild(button2);
|
|
4203
4295
|
}
|
|
4204
4296
|
}
|
|
4205
4297
|
#renderPalette() {
|
|
@@ -4740,6 +4832,52 @@ var STYLES = `
|
|
|
4740
4832
|
padding: 0;
|
|
4741
4833
|
}
|
|
4742
4834
|
|
|
4835
|
+
/* The copy button sits inside the block, so it scrolls with wide code rather
|
|
4836
|
+
than floating over the bubble. Positioning is on the pre; the button only
|
|
4837
|
+
appears once one has been attached. */
|
|
4838
|
+
.message--assistant pre.has-copy {
|
|
4839
|
+
position: relative;
|
|
4840
|
+
}
|
|
4841
|
+
|
|
4842
|
+
.code-copy {
|
|
4843
|
+
position: absolute;
|
|
4844
|
+
top: 4px;
|
|
4845
|
+
right: 4px;
|
|
4846
|
+
padding: 2px 8px;
|
|
4847
|
+
font: inherit;
|
|
4848
|
+
font-size: 0.75em;
|
|
4849
|
+
line-height: 1.6;
|
|
4850
|
+
color: var(--ag-ui-muted);
|
|
4851
|
+
background: var(--ag-ui-surface);
|
|
4852
|
+
border: 1px solid var(--ag-ui-border);
|
|
4853
|
+
border-radius: 4px;
|
|
4854
|
+
cursor: pointer;
|
|
4855
|
+
opacity: 0;
|
|
4856
|
+
transition: opacity 0.12s ease;
|
|
4857
|
+
}
|
|
4858
|
+
|
|
4859
|
+
/* Revealed on hover or keyboard focus. Focus matters as much as hover here:
|
|
4860
|
+
hidden-until-hover is invisible to a keyboard user otherwise. */
|
|
4861
|
+
.message--assistant pre.has-copy:hover .code-copy,
|
|
4862
|
+
.code-copy:focus-visible {
|
|
4863
|
+
opacity: 1;
|
|
4864
|
+
}
|
|
4865
|
+
|
|
4866
|
+
.code-copy:hover {
|
|
4867
|
+
color: var(--ag-ui-text);
|
|
4868
|
+
background: var(--ag-ui-hover);
|
|
4869
|
+
}
|
|
4870
|
+
|
|
4871
|
+
.code-copy[data-state="copied"] {
|
|
4872
|
+
opacity: 1;
|
|
4873
|
+
color: var(--ag-ui-text);
|
|
4874
|
+
}
|
|
4875
|
+
|
|
4876
|
+
.code-copy[data-state="failed"] {
|
|
4877
|
+
opacity: 1;
|
|
4878
|
+
color: var(--ag-ui-danger, var(--ag-ui-text));
|
|
4879
|
+
}
|
|
4880
|
+
|
|
4743
4881
|
.message--assistant blockquote {
|
|
4744
4882
|
padding-left: 10px;
|
|
4745
4883
|
border-left: 3px solid var(--ag-ui-border);
|
|
@@ -6053,9 +6191,9 @@ var ThreadDrawer = class {
|
|
|
6053
6191
|
}
|
|
6054
6192
|
/** Swap a row for an inline "Delete? [Delete] [Cancel]" confirm. */
|
|
6055
6193
|
#confirmDelete(row, meta) {
|
|
6056
|
-
const
|
|
6057
|
-
|
|
6058
|
-
|
|
6194
|
+
const confirm2 = document.createElement("div");
|
|
6195
|
+
confirm2.className = "drawer-confirm";
|
|
6196
|
+
confirm2.setAttribute("part", "drawer-confirm");
|
|
6059
6197
|
const label = document.createElement("span");
|
|
6060
6198
|
label.className = "drawer-confirm-label";
|
|
6061
6199
|
label.setAttribute("part", "drawer-confirm-label");
|
|
@@ -6072,8 +6210,8 @@ var ThreadDrawer = class {
|
|
|
6072
6210
|
no.setAttribute("part", "drawer-confirm-no");
|
|
6073
6211
|
no.textContent = this.#strings.cancel;
|
|
6074
6212
|
no.addEventListener("click", () => this.#renderList());
|
|
6075
|
-
|
|
6076
|
-
row.replaceChildren(
|
|
6213
|
+
confirm2.append(label, yes, no);
|
|
6214
|
+
row.replaceChildren(confirm2);
|
|
6077
6215
|
}
|
|
6078
6216
|
};
|
|
6079
6217
|
|
|
@@ -7647,6 +7785,22 @@ var AgUiChat = class extends HTMLElement {
|
|
|
7647
7785
|
this.#attachTray?.dispose();
|
|
7648
7786
|
this.#voice?.dispose();
|
|
7649
7787
|
}
|
|
7788
|
+
/**
|
|
7789
|
+
* Read an opt-in flag attribute the way HTML reads a boolean attribute.
|
|
7790
|
+
*
|
|
7791
|
+
* Present means on — bare (`data-prompt-chips`), empty
|
|
7792
|
+
* (`data-prompt-chips=""`) or any value except the literal `"false"`. These
|
|
7793
|
+
* were compared against the string `"true"`, so writing the attribute bare —
|
|
7794
|
+
* the spelling every native boolean attribute uses, and the one a reader
|
|
7795
|
+
* reaches for first — silently *disabled* the feature it names, with nothing
|
|
7796
|
+
* to indicate why the chips never appeared.
|
|
7797
|
+
*
|
|
7798
|
+
* `="false"` still turns it off, so an explicit opt-out keeps working.
|
|
7799
|
+
*/
|
|
7800
|
+
#flag(name) {
|
|
7801
|
+
const value = this.getAttribute(name);
|
|
7802
|
+
return value !== null && value !== "false";
|
|
7803
|
+
}
|
|
7650
7804
|
/** Parse the inline `data-strings` JSON overrides (empty when absent/malformed). */
|
|
7651
7805
|
#readStringOverrides() {
|
|
7652
7806
|
const raw = this.getAttribute("data-strings");
|
|
@@ -7827,8 +7981,8 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
7827
7981
|
}
|
|
7828
7982
|
/** Wire the skill surfaces: opt-in flags, embedded catalog, optional fetch. */
|
|
7829
7983
|
#initSkills() {
|
|
7830
|
-
this.#skillsMenu.enableChips(this
|
|
7831
|
-
this.#skillsMenu.enableSlash(this
|
|
7984
|
+
this.#skillsMenu.enableChips(this.#flag("data-prompt-chips"));
|
|
7985
|
+
this.#skillsMenu.enableSlash(this.#flag("data-slash-commands"));
|
|
7832
7986
|
this.#embedSkills = this.#readEmbeddedSkills();
|
|
7833
7987
|
this.#recomputeSkills();
|
|
7834
7988
|
void this.#fetchSkills();
|
|
@@ -8169,6 +8323,7 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
8169
8323
|
bubble.setAttribute("part", `message message-${role}`);
|
|
8170
8324
|
if (role === MESSAGE_ROLE.ASSISTANT) {
|
|
8171
8325
|
bubble.innerHTML = renderMarkdown(content, { allowImages: this.allowImages });
|
|
8326
|
+
attachCopyButtons(bubble, this.#strings);
|
|
8172
8327
|
this.#ensureGroup().appendChild(bubble);
|
|
8173
8328
|
} else {
|
|
8174
8329
|
this.#currentGroup = null;
|
|
@@ -8325,14 +8480,14 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
8325
8480
|
}
|
|
8326
8481
|
/** Build a header control button (icon glyph + localized title/aria). */
|
|
8327
8482
|
#headerButton(modifier, label, glyph) {
|
|
8328
|
-
const
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
return
|
|
8483
|
+
const button2 = document.createElement("button");
|
|
8484
|
+
button2.type = "button";
|
|
8485
|
+
button2.className = `header-btn header-btn--${modifier}`;
|
|
8486
|
+
button2.setAttribute("part", `header-button ${modifier}-button`);
|
|
8487
|
+
button2.title = label;
|
|
8488
|
+
button2.setAttribute("aria-label", label);
|
|
8489
|
+
button2.textContent = glyph;
|
|
8490
|
+
return button2;
|
|
8336
8491
|
}
|
|
8337
8492
|
/**
|
|
8338
8493
|
* An icon holder wrapping a `<slot>` so a host can project custom markup; with
|
|
@@ -8676,6 +8831,7 @@ Use the read_attachment tool with an id to read a file's contents.`
|
|
|
8676
8831
|
if (this.#streamDeltas <= 1) {
|
|
8677
8832
|
this.#revealWords(bubble);
|
|
8678
8833
|
}
|
|
8834
|
+
attachCopyButtons(bubble, this.#strings);
|
|
8679
8835
|
this.#streamingBubble = null;
|
|
8680
8836
|
},
|
|
8681
8837
|
onToolCall: (call) => {
|
|
@@ -8903,7 +9059,7 @@ function setControlValue(el, value) {
|
|
|
8903
9059
|
}
|
|
8904
9060
|
|
|
8905
9061
|
// src/version.ts
|
|
8906
|
-
var VERSION = "0.
|
|
9062
|
+
var VERSION = "0.18.0";
|
|
8907
9063
|
export {
|
|
8908
9064
|
ATTACHMENT_EVENT,
|
|
8909
9065
|
AgUiChat,
|