@noodleseed/assistant 1.4.0 → 1.6.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/README.md +31 -8
- package/dist/{appearance-BLO7kFYB.d.cts → appearance-DowzFJjh.d.cts} +9 -0
- package/dist/{appearance-BLO7kFYB.d.ts → appearance-DowzFJjh.d.ts} +9 -0
- package/dist/{chunk-P34VLBIK.js → chunk-GTYYQNGT.js} +2 -2
- package/dist/chunk-GTYYQNGT.js.map +1 -0
- package/dist/{chunk-JIL4B5HD.js → chunk-ZKXOX67J.js} +463 -100
- package/dist/chunk-ZKXOX67J.js.map +1 -0
- package/dist/{client-nW-Zf4bU.d.ts → client-9kup0-ws.d.cts} +4 -1
- package/dist/{client-1uaN8-yl.d.cts → client-BRjZMXlk.d.ts} +4 -1
- package/dist/client.cjs +1 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +2 -2
- package/dist/client.d.ts +2 -2
- package/dist/client.js +1 -1
- package/dist/index.cjs +462 -99
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +53 -4
- package/dist/index.d.ts +53 -4
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +468 -99
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +6 -4
- package/dist/react.d.ts +6 -4
- package/dist/react.js +8 -2
- package/dist/react.js.map +1 -1
- package/dist/server.d.cts +1 -1
- package/dist/server.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-JIL4B5HD.js.map +0 -1
- package/dist/chunk-P34VLBIK.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -18331,12 +18331,12 @@ var common = {
|
|
|
18331
18331
|
baseFontSize: 15,
|
|
18332
18332
|
messageFontSize: 15,
|
|
18333
18333
|
lineHeight: 1.5,
|
|
18334
|
-
panelRadius:
|
|
18335
|
-
cardRadius:
|
|
18336
|
-
inputRadius:
|
|
18337
|
-
buttonRadius:
|
|
18334
|
+
panelRadius: 20,
|
|
18335
|
+
cardRadius: 14,
|
|
18336
|
+
inputRadius: 14,
|
|
18337
|
+
buttonRadius: 12,
|
|
18338
18338
|
launcherRadius: 999,
|
|
18339
|
-
spacing:
|
|
18339
|
+
spacing: 8,
|
|
18340
18340
|
backdropBlur: 18,
|
|
18341
18341
|
motionScale: 1
|
|
18342
18342
|
};
|
|
@@ -18394,7 +18394,7 @@ var DEFAULT_APPEARANCE = {
|
|
|
18394
18394
|
layout: {
|
|
18395
18395
|
mode: "floating",
|
|
18396
18396
|
position: "bottom-right",
|
|
18397
|
-
panelWidth:
|
|
18397
|
+
panelWidth: 520,
|
|
18398
18398
|
panelMinHeight: 540,
|
|
18399
18399
|
panelMaxHeight: 820,
|
|
18400
18400
|
edgeOffset: 20,
|
|
@@ -18421,7 +18421,16 @@ var DEFAULT_APPEARANCE = {
|
|
|
18421
18421
|
close: "Close assistant",
|
|
18422
18422
|
open: "Open assistant",
|
|
18423
18423
|
confirm: "Confirm",
|
|
18424
|
+
decline: "Don't proceed",
|
|
18424
18425
|
cancel: "Cancel",
|
|
18426
|
+
confirmationHeading: "Review and confirm",
|
|
18427
|
+
additionalDetails: "Additional details",
|
|
18428
|
+
redacted: "Hidden for security",
|
|
18429
|
+
completed: "Completed",
|
|
18430
|
+
stopped: "Stopped",
|
|
18431
|
+
copy: "Copy",
|
|
18432
|
+
newMessages: "New messages",
|
|
18433
|
+
reconnect: "Reconnect",
|
|
18425
18434
|
retry: "Try again",
|
|
18426
18435
|
unavailable: "The assistant is temporarily unavailable.",
|
|
18427
18436
|
sessionExpired: "Your assistant session expired. Reopen it to continue.",
|
|
@@ -18432,7 +18441,7 @@ var DEFAULT_APPEARANCE = {
|
|
|
18432
18441
|
},
|
|
18433
18442
|
presentation: {
|
|
18434
18443
|
panel: {
|
|
18435
|
-
surface: "
|
|
18444
|
+
surface: "solid",
|
|
18436
18445
|
elevation: "soft",
|
|
18437
18446
|
border: "subtle"
|
|
18438
18447
|
},
|
|
@@ -18603,7 +18612,7 @@ function toAssistantClientEvent(event) {
|
|
|
18603
18612
|
}
|
|
18604
18613
|
break;
|
|
18605
18614
|
case "tool_proposed":
|
|
18606
|
-
if (hasString(value, "id") && hasString(value, "tool") && hasOptionalJson(value.arguments) && hasOptionalString(value.expiresAt) && (value.requiresConfirmation === void 0 || value.requiresConfirmation === true) && hasOptionalTurnId(value)) {
|
|
18615
|
+
if (hasString(value, "id") && hasString(value, "tool") && hasOptionalString(value.title) && hasOptionalString(value.description) && hasOptionalJson(value.arguments) && (value.reviewSchema === void 0 || isRecord(value.reviewSchema)) && hasOptionalString(value.expiresAt) && (value.requiresConfirmation === void 0 || value.requiresConfirmation === true) && hasOptionalTurnId(value)) {
|
|
18607
18616
|
return event;
|
|
18608
18617
|
}
|
|
18609
18618
|
break;
|
|
@@ -19582,22 +19591,54 @@ function record2(value) {
|
|
|
19582
19591
|
function createInteractionCard(options) {
|
|
19583
19592
|
const card = document.createElement("section");
|
|
19584
19593
|
card.className = "tool-proposal";
|
|
19585
|
-
|
|
19586
|
-
|
|
19587
|
-
|
|
19594
|
+
card.setAttribute("aria-label", options.labels.heading);
|
|
19595
|
+
const eyebrow = document.createElement("span");
|
|
19596
|
+
eyebrow.className = "proposal-eyebrow";
|
|
19597
|
+
eyebrow.textContent = options.labels.heading;
|
|
19598
|
+
const title = document.createElement("h3");
|
|
19599
|
+
title.textContent = options.title ?? humanizeArgumentName(options.tool);
|
|
19600
|
+
card.append(eyebrow, title);
|
|
19601
|
+
if (options.description) {
|
|
19602
|
+
const description = document.createElement("p");
|
|
19603
|
+
description.className = "proposal-description";
|
|
19604
|
+
description.textContent = options.description;
|
|
19605
|
+
card.append(description);
|
|
19606
|
+
}
|
|
19588
19607
|
if (options.arguments && Object.keys(options.arguments).length > 0) {
|
|
19589
|
-
|
|
19608
|
+
const { action, ...businessArguments } = options.arguments;
|
|
19609
|
+
if (Object.keys(businessArguments).length > 0) {
|
|
19610
|
+
card.append(createArgumentList(businessArguments, options.reviewSchema, options.labels));
|
|
19611
|
+
}
|
|
19612
|
+
if (action !== void 0) {
|
|
19613
|
+
const technical = document.createElement("details");
|
|
19614
|
+
technical.className = "proposal-details";
|
|
19615
|
+
const summary = document.createElement("summary");
|
|
19616
|
+
summary.textContent = options.labels.details;
|
|
19617
|
+
const properties = record3(options.reviewSchema?.properties);
|
|
19618
|
+
technical.append(summary);
|
|
19619
|
+
const actionObject = record3(action);
|
|
19620
|
+
if (actionObject) {
|
|
19621
|
+
technical.append(
|
|
19622
|
+
createArgumentList(actionObject, record3(properties?.action), options.labels)
|
|
19623
|
+
);
|
|
19624
|
+
} else {
|
|
19625
|
+
const value = document.createElement("div");
|
|
19626
|
+
appendValue(value, action, record3(properties?.action), options.labels);
|
|
19627
|
+
technical.append(value);
|
|
19628
|
+
}
|
|
19629
|
+
card.append(technical);
|
|
19630
|
+
}
|
|
19590
19631
|
}
|
|
19591
19632
|
const actions = document.createElement("div");
|
|
19592
19633
|
actions.className = "proposal-actions";
|
|
19593
19634
|
const buttons = [];
|
|
19594
19635
|
for (const [labelText, action] of [
|
|
19595
19636
|
[options.labels.accept, "accept"],
|
|
19596
|
-
[options.labels.decline, "decline"]
|
|
19597
|
-
[options.labels.cancel, "cancel"]
|
|
19637
|
+
[options.labels.decline, "decline"]
|
|
19598
19638
|
]) {
|
|
19599
19639
|
const button2 = document.createElement("button");
|
|
19600
19640
|
button2.type = "button";
|
|
19641
|
+
button2.className = `proposal-${action}`;
|
|
19601
19642
|
button2.textContent = labelText;
|
|
19602
19643
|
buttons.push(button2);
|
|
19603
19644
|
button2.addEventListener("click", () => {
|
|
@@ -19611,27 +19652,98 @@ function createInteractionCard(options) {
|
|
|
19611
19652
|
card.append(actions);
|
|
19612
19653
|
return card;
|
|
19613
19654
|
}
|
|
19614
|
-
function
|
|
19615
|
-
const
|
|
19616
|
-
|
|
19655
|
+
function createResultCard(result, label, redactedLabel) {
|
|
19656
|
+
const card = document.createElement("section");
|
|
19657
|
+
card.className = "tool-result";
|
|
19658
|
+
const heading = document.createElement("strong");
|
|
19659
|
+
heading.textContent = label;
|
|
19660
|
+
card.append(heading);
|
|
19661
|
+
const body = document.createElement("div");
|
|
19662
|
+
const labels = {
|
|
19663
|
+
heading: label,
|
|
19664
|
+
accept: "",
|
|
19665
|
+
decline: "",
|
|
19666
|
+
details: "",
|
|
19667
|
+
redacted: redactedLabel
|
|
19668
|
+
};
|
|
19669
|
+
appendValue(body, result, void 0, labels);
|
|
19670
|
+
card.append(body);
|
|
19671
|
+
return card;
|
|
19672
|
+
}
|
|
19673
|
+
function createArgumentList(arguments_, schema, labels) {
|
|
19674
|
+
const list = document.createElement("dl");
|
|
19675
|
+
list.className = "proposal-arguments";
|
|
19676
|
+
const properties = record3(schema?.properties);
|
|
19617
19677
|
for (const [name, value] of Object.entries(arguments_)) {
|
|
19678
|
+
const propertySchema = record3(properties?.[name]);
|
|
19618
19679
|
const term = document.createElement("dt");
|
|
19619
|
-
term.textContent = humanizeArgumentName(name);
|
|
19680
|
+
term.textContent = string4(propertySchema?.title) ?? humanizeArgumentName(name);
|
|
19681
|
+
const help = string4(propertySchema?.description);
|
|
19682
|
+
if (help) {
|
|
19683
|
+
const description2 = document.createElement("small");
|
|
19684
|
+
description2.textContent = help;
|
|
19685
|
+
term.append(description2);
|
|
19686
|
+
}
|
|
19620
19687
|
const description = document.createElement("dd");
|
|
19621
|
-
description
|
|
19622
|
-
|
|
19688
|
+
appendValue(description, value, propertySchema, labels);
|
|
19689
|
+
list.append(term, description);
|
|
19690
|
+
}
|
|
19691
|
+
return list;
|
|
19692
|
+
}
|
|
19693
|
+
function appendValue(parent, value, schema, labels) {
|
|
19694
|
+
if (value === "[REDACTED]") {
|
|
19695
|
+
const hidden = document.createElement("span");
|
|
19696
|
+
hidden.className = "proposal-redacted";
|
|
19697
|
+
hidden.textContent = labels.redacted;
|
|
19698
|
+
parent.append(hidden);
|
|
19699
|
+
return;
|
|
19700
|
+
}
|
|
19701
|
+
if (Array.isArray(value)) {
|
|
19702
|
+
const list = document.createElement("ul");
|
|
19703
|
+
const itemSchema = record3(schema?.items);
|
|
19704
|
+
for (const item of value) {
|
|
19705
|
+
const entry = document.createElement("li");
|
|
19706
|
+
appendValue(entry, item, itemSchema, labels);
|
|
19707
|
+
list.append(entry);
|
|
19708
|
+
}
|
|
19709
|
+
parent.append(list);
|
|
19710
|
+
return;
|
|
19711
|
+
}
|
|
19712
|
+
const objectValue = record3(value);
|
|
19713
|
+
if (objectValue) {
|
|
19714
|
+
parent.append(createArgumentList(objectValue, schema, labels));
|
|
19715
|
+
return;
|
|
19716
|
+
}
|
|
19717
|
+
parent.textContent = formatScalar(value, schema);
|
|
19718
|
+
}
|
|
19719
|
+
function formatScalar(value, schema) {
|
|
19720
|
+
if (value === null || value === void 0 || value === "") return "Not provided";
|
|
19721
|
+
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
19722
|
+
if (typeof value === "number") return new Intl.NumberFormat().format(value);
|
|
19723
|
+
if (typeof value !== "string") return String(value);
|
|
19724
|
+
if (schema?.format === "date") {
|
|
19725
|
+
const date5 = /* @__PURE__ */ new Date(`${value}T00:00:00`);
|
|
19726
|
+
if (!Number.isNaN(date5.valueOf()))
|
|
19727
|
+
return new Intl.DateTimeFormat(void 0, { dateStyle: "medium" }).format(date5);
|
|
19728
|
+
}
|
|
19729
|
+
if (schema?.format === "date-time") {
|
|
19730
|
+
const date5 = new Date(value);
|
|
19731
|
+
if (!Number.isNaN(date5.valueOf()))
|
|
19732
|
+
return new Intl.DateTimeFormat(void 0, { dateStyle: "medium", timeStyle: "short" }).format(
|
|
19733
|
+
date5
|
|
19734
|
+
);
|
|
19623
19735
|
}
|
|
19624
|
-
return
|
|
19736
|
+
return value;
|
|
19625
19737
|
}
|
|
19626
19738
|
function humanizeArgumentName(value) {
|
|
19627
19739
|
const words = value.replaceAll(/([a-z0-9])([A-Z])/g, "$1 $2").replaceAll(/[_-]+/g, " ");
|
|
19628
19740
|
return words ? `${words[0]?.toUpperCase() ?? ""}${words.slice(1)}` : value;
|
|
19629
19741
|
}
|
|
19630
|
-
function
|
|
19631
|
-
|
|
19632
|
-
|
|
19633
|
-
|
|
19634
|
-
return
|
|
19742
|
+
function record3(value) {
|
|
19743
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
19744
|
+
}
|
|
19745
|
+
function string4(value) {
|
|
19746
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
19635
19747
|
}
|
|
19636
19748
|
|
|
19637
19749
|
// ../../node_modules/.pnpm/dompurify@3.4.11/node_modules/dompurify/dist/purify.es.mjs
|
|
@@ -22367,8 +22479,11 @@ var AssistantElementEventController = class {
|
|
|
22367
22479
|
if (!this.#streamKind) return;
|
|
22368
22480
|
this.#appendToolProposal(
|
|
22369
22481
|
String(data.id ?? ""),
|
|
22370
|
-
String(data.tool ??
|
|
22371
|
-
isRecord4(data.arguments) ? data.arguments : void 0
|
|
22482
|
+
String(data.tool ?? "action"),
|
|
22483
|
+
isRecord4(data.arguments) ? data.arguments : void 0,
|
|
22484
|
+
typeof data.title === "string" ? data.title : void 0,
|
|
22485
|
+
"description" in data && typeof data.description === "string" ? data.description : void 0,
|
|
22486
|
+
"reviewSchema" in data && isRecord4(data.reviewSchema) ? data.reviewSchema : void 0
|
|
22372
22487
|
);
|
|
22373
22488
|
return;
|
|
22374
22489
|
}
|
|
@@ -22406,7 +22521,13 @@ var AssistantElementEventController = class {
|
|
|
22406
22521
|
}
|
|
22407
22522
|
#finishInteraction(id, action) {
|
|
22408
22523
|
if (this.#completedTool && !this.#assistantBody) {
|
|
22409
|
-
this.#host.
|
|
22524
|
+
const messages = this.#host.messages();
|
|
22525
|
+
if (messages) {
|
|
22526
|
+
const labels = this.#host.labels();
|
|
22527
|
+
messages.append(
|
|
22528
|
+
createResultCard(this.#completedTool.result, labels.completed, labels.redacted)
|
|
22529
|
+
);
|
|
22530
|
+
}
|
|
22410
22531
|
}
|
|
22411
22532
|
this.#proposalCards.get(id)?.remove();
|
|
22412
22533
|
this.#proposalCards.delete(id);
|
|
@@ -22421,18 +22542,23 @@ var AssistantElementEventController = class {
|
|
|
22421
22542
|
this.#clearStream();
|
|
22422
22543
|
this.#completedTool = void 0;
|
|
22423
22544
|
}
|
|
22424
|
-
#appendToolProposal(id, tool, arguments_) {
|
|
22545
|
+
#appendToolProposal(id, tool, arguments_, title, description, reviewSchema) {
|
|
22425
22546
|
const messages = this.#host.messages();
|
|
22426
22547
|
if (!messages || !id) return;
|
|
22427
22548
|
this.#proposalCards.get(id)?.remove();
|
|
22428
22549
|
const labels = this.#host.labels();
|
|
22429
22550
|
const card = createInteractionCard({
|
|
22430
22551
|
tool,
|
|
22552
|
+
...title ? { title } : {},
|
|
22553
|
+
...description ? { description } : {},
|
|
22431
22554
|
...arguments_ ? { arguments: arguments_ } : {},
|
|
22555
|
+
...reviewSchema ? { reviewSchema } : {},
|
|
22432
22556
|
labels: {
|
|
22557
|
+
heading: labels.confirmationHeading,
|
|
22433
22558
|
accept: labels.confirm,
|
|
22434
|
-
decline:
|
|
22435
|
-
|
|
22559
|
+
decline: labels.decline,
|
|
22560
|
+
details: labels.additionalDetails,
|
|
22561
|
+
redacted: labels.redacted
|
|
22436
22562
|
},
|
|
22437
22563
|
respond: (action) => this.#host.respond(id, { action })
|
|
22438
22564
|
});
|
|
@@ -22440,7 +22566,9 @@ var AssistantElementEventController = class {
|
|
|
22440
22566
|
this.#proposalCards.set(id, card);
|
|
22441
22567
|
this.#revealLatestMessage(messages);
|
|
22442
22568
|
this.#host.element.dispatchEvent(
|
|
22443
|
-
new CustomEvent("assistant-tool-proposed", {
|
|
22569
|
+
new CustomEvent("assistant-tool-proposed", {
|
|
22570
|
+
detail: { id, tool, title, description, arguments: arguments_, reviewSchema }
|
|
22571
|
+
})
|
|
22444
22572
|
);
|
|
22445
22573
|
}
|
|
22446
22574
|
#appendInputRequest(id, message, requestedSchema) {
|
|
@@ -22491,7 +22619,14 @@ var AssistantElementEventController = class {
|
|
|
22491
22619
|
}
|
|
22492
22620
|
#revealLatestMessage(messages) {
|
|
22493
22621
|
this.#host.element.setAttribute("has-messages", "");
|
|
22494
|
-
messages.scrollTop
|
|
22622
|
+
const distance = messages.scrollHeight - messages.scrollTop - messages.clientHeight;
|
|
22623
|
+
const control = this.#host.element.shadowRoot?.querySelector(".new-messages");
|
|
22624
|
+
if (distance <= 160) {
|
|
22625
|
+
messages.scrollTop = messages.scrollHeight;
|
|
22626
|
+
if (control) control.hidden = true;
|
|
22627
|
+
} else if (control) {
|
|
22628
|
+
control.hidden = false;
|
|
22629
|
+
}
|
|
22495
22630
|
}
|
|
22496
22631
|
};
|
|
22497
22632
|
function isRecord4(value) {
|
|
@@ -22526,17 +22661,18 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
|
|
|
22526
22661
|
:host([data-mode="floating"][data-position="bottom-left"]) { right: auto; left: 20px; }
|
|
22527
22662
|
button { font: inherit; }
|
|
22528
22663
|
button, textarea, input, select { -webkit-tap-highlight-color: transparent; }
|
|
22529
|
-
.launcher { display: grid; place-items: center; width: 48px; height: 48px; border: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: 999px; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background:
|
|
22664
|
+
.launcher { display: grid; place-items: center; width: 48px; height: 48px; border: 1px solid var(--ns-assistant-launcher-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: 999px; color: var(--ns-assistant-launcher-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-launcher, var(--ns-assistant-panel, var(--ns-assistant-default-panel))); box-shadow: 0 8px 28px rgba(0,0,0,.14); cursor: pointer; transition: transform .24s cubic-bezier(.25,1,.5,1), box-shadow .2s ease; }
|
|
22530
22665
|
.launcher:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 8px 26px rgba(0,0,0,.16); }
|
|
22531
22666
|
.launcher img { width: 28px; height: 28px; border-radius: 50%; object-fit: contain; }
|
|
22532
|
-
.panel { display: none; flex-direction: column; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 40px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 40px)); overflow: hidden; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background:
|
|
22667
|
+
.panel { display: none; flex-direction: column; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 40px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 40px)); overflow: hidden; color: var(--ns-assistant-panel-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border: 1px solid var(--ns-assistant-panel-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); transform-origin: bottom right; animation: halo-panel-in .28s cubic-bezier(.23,1,.32,1) both; }
|
|
22533
22668
|
:host([open]) .panel { display: flex; }
|
|
22669
|
+
.panel { position: relative; }
|
|
22534
22670
|
:host([open]) .launcher { display: none; }
|
|
22535
|
-
header { display: flex; flex: 0 0 auto; gap: 10px; align-items: center; min-height: 64px; padding:
|
|
22671
|
+
header { display: flex; flex: 0 0 auto; gap: 10px; align-items: center; min-height: 64px; padding: 12px 18px; color: var(--ns-assistant-header-text, inherit); background: var(--ns-assistant-header, transparent); border-bottom: 1px solid var(--ns-assistant-header-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); }
|
|
22536
22672
|
header strong { flex: 1; font-size: 16px; font-weight: 600; letter-spacing: -.01em; }
|
|
22537
22673
|
.brand-logo { display: block; max-width: 120px; max-height: 28px; object-fit: contain; }
|
|
22538
22674
|
.close, .send { display: grid; place-items: center; border: 0; border-radius: 999px; cursor: pointer; }
|
|
22539
|
-
.close { width:
|
|
22675
|
+
.close { width: 44px; height: 44px; padding: 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; font-size: 24px; font-weight: 300; line-height: 1; transition: background .15s ease, color .15s ease; }
|
|
22540
22676
|
.close:hover { color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); }
|
|
22541
22677
|
.welcome { flex: 0 0 auto; padding: 30px 22px 18px; }
|
|
22542
22678
|
.welcome h2 { margin: 0; font-size: 1.42em; line-height: 1.25; letter-spacing: -.025em; }
|
|
@@ -22544,16 +22680,24 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
|
|
|
22544
22680
|
:host([has-messages]) .welcome, :host([has-messages]) .suggested-prompts { display: none; }
|
|
22545
22681
|
.suggested-prompts { display: flex; flex: 0 0 auto; flex-wrap: wrap; gap: 8px; padding: 0 20px 16px; }
|
|
22546
22682
|
.suggested-prompts:empty { display: none; }
|
|
22547
|
-
.suggested-prompts button { padding:
|
|
22683
|
+
.suggested-prompts button { min-height: 44px; padding: 9px 14px; color: var(--ns-assistant-suggestion-text, var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text))); background: var(--ns-assistant-suggestion, transparent); border: 1px solid var(--ns-assistant-suggestion-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: 12px; cursor: pointer; transition: background .2s ease, color .2s ease, transform .2s ease; }
|
|
22548
22684
|
.suggested-prompts button:hover { color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); transform: translateY(-1px); }
|
|
22549
|
-
.messages { flex: 1 1 auto; min-height: 0; padding: 18px 20px; overflow-y: auto; overscroll-behavior: contain; scroll-behavior: smooth; }
|
|
22685
|
+
.messages { flex: 1 1 auto; min-height: 0; padding: 18px 20px; overflow-y: auto; background: var(--ns-assistant-canvas, transparent); overscroll-behavior: contain; scroll-behavior: smooth; }
|
|
22550
22686
|
.messages::-webkit-scrollbar { width: 6px; }
|
|
22551
22687
|
.messages::-webkit-scrollbar-thumb { background: var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: 999px; }
|
|
22552
22688
|
.message { width: fit-content; max-width: 88%; margin: 0 0 14px; padding: 0; border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: transparent; white-space: pre-wrap; animation: halo-message-in .2s ease both; }
|
|
22553
22689
|
.message > span, .message > .markdown { overflow-wrap: anywhere; }
|
|
22554
22690
|
.message .avatar { float: left; width: 24px; height: 24px; margin-right: 9px; border-radius: 50%; object-fit: cover; }
|
|
22555
22691
|
.message time { display: block; margin-top: 4px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .75em; line-height: 1.2; }
|
|
22556
|
-
.message
|
|
22692
|
+
.message-copy { min-width: 44px; min-height: 32px; margin-top: 6px; padding: 4px 8px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); background: transparent; border: 0; border-radius: 8px; cursor: pointer; font-size: .78em; opacity: 0; transition: opacity .15s ease, background .15s ease; }
|
|
22693
|
+
.message:hover .message-copy, .message:focus-within .message-copy { opacity: 1; }
|
|
22694
|
+
.conversation-status { margin: 4px auto 14px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .82em; text-align: center; }
|
|
22695
|
+
.conversation-error { display: flex; gap: 12px; align-items: center; justify-content: space-between; margin: 8px 0 16px; padding: 12px 14px; color: var(--ns-assistant-danger, var(--ns-assistant-default-danger)); border: 1px solid color-mix(in srgb, var(--ns-assistant-danger, var(--ns-assistant-default-danger)) 28%, transparent); border-radius: 12px; background: color-mix(in srgb, var(--ns-assistant-danger, var(--ns-assistant-default-danger)) 7%, transparent); }
|
|
22696
|
+
.conversation-error p { margin: 0; }
|
|
22697
|
+
.conversation-error button { min-height: 44px; padding: 8px 12px; color: var(--ns-assistant-secondary-button-text, inherit); background: var(--ns-assistant-secondary-button, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); border: 1px solid var(--ns-assistant-secondary-button-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: 10px; cursor: pointer; font-weight: 600; }
|
|
22698
|
+
.new-messages { position: absolute; left: 50%; bottom: 82px; z-index: 1; min-height: 36px; padding: 7px 12px; color: var(--ns-assistant-secondary-button-text, inherit); background: var(--ns-assistant-secondary-button, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); border: 1px solid var(--ns-assistant-secondary-button-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: 999px; box-shadow: 0 4px 18px rgba(0,0,0,.12); transform: translateX(-50%); cursor: pointer; }
|
|
22699
|
+
.message.assistant { color: var(--ns-assistant-assistant-message-text, inherit); background: var(--ns-assistant-assistant-message, transparent); border: 1px solid var(--ns-assistant-assistant-message-border, transparent); }
|
|
22700
|
+
.message.user { display: grid; justify-items: start; gap: 3px; margin-left: auto; padding: 10px 16px 8px; color: var(--ns-assistant-user-message-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-user-message, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); border: 1px solid var(--ns-assistant-user-message-border, transparent); font-size: .94em; }
|
|
22557
22701
|
.message.user time { margin-top: 0; }
|
|
22558
22702
|
.markdown { white-space: normal; }
|
|
22559
22703
|
.markdown p { margin: 0 0 8px; }
|
|
@@ -22562,8 +22706,8 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
|
|
|
22562
22706
|
.markdown em, .markdown i { font-style: italic; }
|
|
22563
22707
|
.markdown a { color: var(--ns-assistant-link, var(--ns-assistant-default-link)); text-decoration: underline; text-underline-offset: 2px; }
|
|
22564
22708
|
.markdown a:hover { opacity: .8; }
|
|
22565
|
-
.markdown code { padding: 2px 6px; border-radius: 5px; background: var(--ns-assistant-code, var(--ns-assistant-default-code)); font-family: var(--ns-assistant-mono-font-family, var(--ns-assistant-default-mono-font-family)); font-size: .87em; }
|
|
22566
|
-
.markdown pre { margin: 10px 0; padding: 12px 14px; overflow-x: auto; border: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: 10px; background: var(--ns-assistant-code, var(--ns-assistant-default-code)); white-space: pre; }
|
|
22709
|
+
.markdown code { padding: 2px 6px; color: var(--ns-assistant-code-text, inherit); border: 1px solid var(--ns-assistant-code-border, transparent); border-radius: 5px; background: var(--ns-assistant-code, var(--ns-assistant-default-code)); font-family: var(--ns-assistant-mono-font-family, var(--ns-assistant-default-mono-font-family)); font-size: .87em; }
|
|
22710
|
+
.markdown pre { margin: 10px 0; padding: 12px 14px; overflow-x: auto; color: var(--ns-assistant-code-text, inherit); border: 1px solid var(--ns-assistant-code-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: 10px; background: var(--ns-assistant-code, var(--ns-assistant-default-code)); white-space: pre; }
|
|
22567
22711
|
.markdown pre code { padding: 0; background: transparent; font-size: .86em; }
|
|
22568
22712
|
.markdown ul, .markdown ol { margin: 8px 0; padding-left: 22px; }
|
|
22569
22713
|
.markdown li { margin: 3px 0; }
|
|
@@ -22572,15 +22716,25 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
|
|
|
22572
22716
|
.markdown h1:first-child, .markdown h2:first-child, .markdown h3:first-child { margin-top: 0; }
|
|
22573
22717
|
.markdown h1 { font-size: 1.3em; } .markdown h2 { font-size: 1.18em; } .markdown h3 { font-size: 1.08em; }
|
|
22574
22718
|
.message.thinking > span { display: inline-block; color: transparent; background: linear-gradient(90deg, var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)) 25%, var(--ns-assistant-text, var(--ns-assistant-default-text)) 50%, var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)) 75%); background-size: 300% 100%; background-clip: text; -webkit-background-clip: text; font-style: italic; font-weight: 500; animation: halo-shimmer 2s linear infinite; }
|
|
22575
|
-
.tool-proposal { display: grid; gap:
|
|
22576
|
-
.
|
|
22577
|
-
.proposal
|
|
22719
|
+
.tool-proposal { display: grid; gap: 12px; align-items: start; margin: 8px 0 16px; padding: 18px; color: var(--ns-assistant-confirmation-text, inherit); border: 1px solid var(--ns-assistant-confirmation-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-card-radius, 14px); background: var(--ns-assistant-confirmation, var(--ns-assistant-input, var(--ns-assistant-default-input))); animation: halo-message-in .2s ease both; }
|
|
22720
|
+
.proposal-eyebrow { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .75em; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
|
|
22721
|
+
.tool-proposal h3 { margin: -4px 0 0; font-size: 1.08em; line-height: 1.3; letter-spacing: -.01em; }
|
|
22722
|
+
.proposal-description { margin: -4px 0 0; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }
|
|
22723
|
+
.proposal-arguments { display: grid; grid-template-columns: minmax(100px, .7fr) minmax(0, 1.3fr); gap: 8px 14px; margin: 0; padding: 12px 0; border-block: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); font-size: .9em; }
|
|
22724
|
+
.proposal-arguments .proposal-arguments { grid-column: 1 / -1; padding: 4px 0 0; border: 0; }
|
|
22578
22725
|
.proposal-arguments dt { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }
|
|
22726
|
+
.proposal-arguments dt small { display: block; margin-top: 2px; font-size: .85em; line-height: 1.35; }
|
|
22579
22727
|
.proposal-arguments dd { margin: 0; overflow-wrap: anywhere; }
|
|
22728
|
+
.proposal-details { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .86em; }
|
|
22729
|
+
.proposal-details summary { min-height: 36px; padding: 8px 0; cursor: pointer; font-weight: 600; }
|
|
22730
|
+
.proposal-details .proposal-arguments { margin-top: 4px; }
|
|
22580
22731
|
.proposal-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: end; }
|
|
22581
|
-
.tool-proposal button { padding:
|
|
22582
|
-
.tool-proposal
|
|
22732
|
+
.tool-proposal button { min-height: 44px; padding: 9px 14px; border: 1px solid var(--ns-assistant-secondary-button-border, transparent); border-radius: var(--ns-assistant-button-radius, 12px); color: var(--ns-assistant-secondary-button-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-secondary-button, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); cursor: pointer; font-weight: 600; }
|
|
22733
|
+
.tool-proposal .proposal-accept { color: var(--ns-assistant-primary-button-text, var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text))); background: var(--ns-assistant-primary-button, var(--ns-assistant-accent, var(--ns-assistant-default-accent))); border-color: var(--ns-assistant-primary-button-border, transparent); }
|
|
22583
22734
|
.tool-proposal button:disabled { opacity: .55; cursor: not-allowed; }
|
|
22735
|
+
.tool-proposal button { min-height: 45px; }
|
|
22736
|
+
.tool-result { display: grid; gap: 10px; margin: 8px 0 16px; padding: 16px; border: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: var(--ns-assistant-card-radius, 14px); background: var(--ns-assistant-assistant-message, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); }
|
|
22737
|
+
.tool-result > strong { color: var(--ns-assistant-success, var(--ns-assistant-default-success)); }
|
|
22584
22738
|
.input-request form { display: grid; gap: 10px; align-items: stretch; min-height: 0; margin: 0; padding: 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; }
|
|
22585
22739
|
.input-request form:focus-within { box-shadow: none; }
|
|
22586
22740
|
.input-request label { display: grid; gap: 4px; color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); font-size: .9em; }
|
|
@@ -22589,20 +22743,21 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
|
|
|
22589
22743
|
.input-request input[type="checkbox"] { width: auto; justify-self: start; accent-color: var(--ns-assistant-accent, var(--ns-assistant-default-accent)); }
|
|
22590
22744
|
.input-request input:focus-visible, .input-request select:focus-visible { border-color: var(--ns-assistant-focus, var(--ns-assistant-default-focus)); box-shadow: 0 0 0 2px var(--ns-assistant-focus, var(--ns-assistant-default-focus)); }
|
|
22591
22745
|
.input-request .proposal-actions { margin-top: 2px; }
|
|
22592
|
-
.noodle-app-card { position: relative; display: grid; gap: 8px; width: 100%; margin: 4px 0 16px; overflow: hidden; border: 1px solid var(--ns-assistant-divider, var(--ns-assistant-default-divider)); border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-elevated, var(--ns-assistant-default-elevated)); }
|
|
22746
|
+
.noodle-app-card { position: relative; display: grid; gap: 8px; width: 100%; margin: 4px 0 16px; overflow: hidden; color: var(--ns-assistant-app-text, inherit); border: 1px solid var(--ns-assistant-app-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-card-radius, var(--ns-assistant-default-card-radius)); background: var(--ns-assistant-app, var(--ns-assistant-elevated, var(--ns-assistant-default-elevated))); }
|
|
22593
22747
|
.noodle-app-title { padding: 10px 12px 0; font-size: .86em; font-weight: 650; }
|
|
22594
22748
|
.noodle-app-frame { display: block; width: 100%; min-height: 120px; border: 0; background: transparent; }
|
|
22595
22749
|
.noodle-app-card[data-fullscreen] { position: fixed; inset: 0; z-index: 2; margin: 0; border-radius: 0; background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); }
|
|
22596
22750
|
.noodle-app-card[data-fullscreen] .noodle-app-frame { height: 100% !important; }
|
|
22597
|
-
form { display: flex; flex: 0 0 auto; gap: 8px; align-items: center; min-height:
|
|
22751
|
+
form { display: flex; flex: 0 0 auto; gap: 8px; align-items: center; min-height: 56px; margin: 8px 16px 16px; padding: 6px 6px 6px 16px; color: var(--ns-assistant-composer-text, inherit); border: 1px solid var(--ns-assistant-composer-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-input-radius, 14px); background: var(--ns-assistant-composer, var(--ns-assistant-input, var(--ns-assistant-default-input))); box-shadow: 0 1px 2px rgba(0,0,0,.04); transition: border-color .15s ease, box-shadow .15s ease; }
|
|
22598
22752
|
form:focus-within { box-shadow: inset 0 0 0 1px var(--ns-assistant-focus, var(--ns-assistant-default-focus)), 0 0 0 2px var(--ns-assistant-focus, var(--ns-assistant-default-focus)); }
|
|
22599
22753
|
textarea { flex: 1; min-height: 24px; max-height: 120px; resize: none; padding: 0; color: var(--ns-assistant-text, var(--ns-assistant-default-text)); background: transparent; border: 0; border-radius: 0; outline: 0; box-shadow: none; appearance: none; -webkit-appearance: none; font: inherit; font-size: 16px; line-height: 24px; }
|
|
22600
22754
|
textarea::placeholder { color: var(--ns-assistant-muted-text, var(--ns-assistant-default-muted-text)); }
|
|
22601
22755
|
textarea:focus, textarea:focus-visible { outline: none; box-shadow: none; }
|
|
22602
22756
|
button:focus-visible { outline: 3px solid var(--ns-assistant-focus, var(--ns-assistant-default-focus)); outline-offset: 2px; }
|
|
22603
|
-
.send { position: relative; display: block; width:
|
|
22604
|
-
.send::before { content: ''; position: absolute; top: 50%; left: 50%; width:
|
|
22757
|
+
.send { position: relative; display: block; width: 44px; height: 44px; flex: 0 0 44px; padding: 0; overflow: hidden; color: transparent; background: var(--ns-assistant-primary-button, var(--ns-assistant-accent, var(--ns-assistant-default-accent))); font-size: 0; line-height: 0; transition: transform .15s ease, background .15s ease; }
|
|
22758
|
+
.send::before { content: ''; position: absolute; top: 50%; left: 50%; width: 17px; height: 17px; background: var(--ns-assistant-primary-button-text, var(--ns-assistant-accent-text, var(--ns-assistant-default-accent-text))); transform: translate(-50%, -50%); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 19V5M5 12l7-7 7 7' fill='none' stroke='black' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 19V5M5 12l7-7 7 7' fill='none' stroke='black' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat; }
|
|
22605
22759
|
.send:hover { transform: scale(1.05); background: var(--ns-assistant-hover, var(--ns-assistant-default-hover)); }
|
|
22760
|
+
:host([busy]) .send::before { width: 13px; height: 13px; border-radius: 3px; -webkit-mask: none; mask: none; }
|
|
22606
22761
|
.send:disabled, textarea:disabled { opacity: .55; cursor: not-allowed; }
|
|
22607
22762
|
.legal { display: flex; gap: 12px; justify-content: center; padding: 0 12px 9px; font-size: .75em; }
|
|
22608
22763
|
.legal:empty { display: none; }
|
|
@@ -22615,9 +22770,107 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
|
|
|
22615
22770
|
@media (max-width: 640px) { :host([mobile-fullscreen][open]) { inset: 0; } :host([mobile-fullscreen][open]) .panel { width: 100vw; min-height: 100vh; max-height: 100vh; border: 0; border-radius: 0; } }
|
|
22616
22771
|
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; } .messages { scroll-behavior: auto; } }
|
|
22617
22772
|
@media (forced-colors: active) { .message.thinking > span { color: CanvasText; background: none; } }
|
|
22773
|
+
@media (hover: none) { .message-copy { opacity: 1; } }
|
|
22618
22774
|
@media (max-width: 560px) { :host([data-mode="floating"]) { inset: auto 12px 12px; } :host([open]) .panel { width: calc(100vw - 24px); max-height: calc(100vh - 24px); } }
|
|
22619
22775
|
</style>`;
|
|
22620
22776
|
|
|
22777
|
+
// src/host-appearance.ts
|
|
22778
|
+
var ROLE_VARIABLES = {
|
|
22779
|
+
canvas: "--ns-assistant-canvas",
|
|
22780
|
+
text: "--ns-assistant-text",
|
|
22781
|
+
mutedText: "--ns-assistant-muted-text",
|
|
22782
|
+
link: "--ns-assistant-link",
|
|
22783
|
+
focus: "--ns-assistant-focus",
|
|
22784
|
+
success: "--ns-assistant-success",
|
|
22785
|
+
warning: "--ns-assistant-warning",
|
|
22786
|
+
danger: "--ns-assistant-danger"
|
|
22787
|
+
};
|
|
22788
|
+
var SURFACE_VARIABLES = {
|
|
22789
|
+
panel: "--ns-assistant-panel",
|
|
22790
|
+
header: "--ns-assistant-header",
|
|
22791
|
+
assistantMessage: "--ns-assistant-assistant-message",
|
|
22792
|
+
userMessage: "--ns-assistant-user-message",
|
|
22793
|
+
composer: "--ns-assistant-composer",
|
|
22794
|
+
suggestion: "--ns-assistant-suggestion",
|
|
22795
|
+
confirmation: "--ns-assistant-confirmation",
|
|
22796
|
+
primaryButton: "--ns-assistant-primary-button",
|
|
22797
|
+
secondaryButton: "--ns-assistant-secondary-button",
|
|
22798
|
+
launcher: "--ns-assistant-launcher",
|
|
22799
|
+
code: "--ns-assistant-code",
|
|
22800
|
+
app: "--ns-assistant-app"
|
|
22801
|
+
};
|
|
22802
|
+
var ASSISTANT_APPEARANCE_VARIABLES = [
|
|
22803
|
+
...Object.values(ROLE_VARIABLES),
|
|
22804
|
+
...Object.values(SURFACE_VARIABLES).flatMap((name) => [name, `${name}-text`, `${name}-border`])
|
|
22805
|
+
];
|
|
22806
|
+
function applyHostAppearance(style, appearance, theme, previous = /* @__PURE__ */ new Map()) {
|
|
22807
|
+
for (const [variable, original] of previous) {
|
|
22808
|
+
if (original.value) style.setProperty(variable, original.value, original.priority);
|
|
22809
|
+
else style.removeProperty(variable);
|
|
22810
|
+
}
|
|
22811
|
+
previous.clear();
|
|
22812
|
+
const selected = appearance?.[theme];
|
|
22813
|
+
if (!selected) return [];
|
|
22814
|
+
for (const [role, variable] of Object.entries(ROLE_VARIABLES)) {
|
|
22815
|
+
const value = selected[role];
|
|
22816
|
+
if (typeof value === "string") setManagedProperty(style, previous, variable, value);
|
|
22817
|
+
}
|
|
22818
|
+
for (const [role, variable] of Object.entries(SURFACE_VARIABLES)) {
|
|
22819
|
+
const value = selected[role];
|
|
22820
|
+
if (!value || typeof value !== "object") continue;
|
|
22821
|
+
if (value.surface) setManagedProperty(style, previous, variable, value.surface);
|
|
22822
|
+
if (value.text) setManagedProperty(style, previous, `${variable}-text`, value.text);
|
|
22823
|
+
if (value.border) setManagedProperty(style, previous, `${variable}-border`, value.border);
|
|
22824
|
+
}
|
|
22825
|
+
return contrastWarnings(selected, theme);
|
|
22826
|
+
}
|
|
22827
|
+
function setManagedProperty(style, previous, variable, value) {
|
|
22828
|
+
previous.set(variable, {
|
|
22829
|
+
value: style.getPropertyValue(variable),
|
|
22830
|
+
priority: style.getPropertyPriority(variable)
|
|
22831
|
+
});
|
|
22832
|
+
style.setProperty(variable, value);
|
|
22833
|
+
}
|
|
22834
|
+
function contrastWarnings(theme, mode) {
|
|
22835
|
+
const warnings = [];
|
|
22836
|
+
const pairs = [
|
|
22837
|
+
["panel", theme.panel?.text ?? theme.text, theme.panel?.surface ?? theme.canvas],
|
|
22838
|
+
["userMessage", theme.userMessage?.text ?? theme.text, theme.userMessage?.surface],
|
|
22839
|
+
["composer", theme.composer?.text ?? theme.text, theme.composer?.surface],
|
|
22840
|
+
["confirmation", theme.confirmation?.text ?? theme.text, theme.confirmation?.surface],
|
|
22841
|
+
["primaryButton", theme.primaryButton?.text, theme.primaryButton?.surface]
|
|
22842
|
+
];
|
|
22843
|
+
for (const [role, foreground, background] of pairs) {
|
|
22844
|
+
if (!foreground || !background) continue;
|
|
22845
|
+
const ratio = contrastRatio2(foreground, background);
|
|
22846
|
+
if (ratio >= 4.5) continue;
|
|
22847
|
+
warnings.push({
|
|
22848
|
+
code: "low_contrast",
|
|
22849
|
+
theme: mode,
|
|
22850
|
+
role,
|
|
22851
|
+
foreground,
|
|
22852
|
+
background,
|
|
22853
|
+
contrastRatio: Math.round(ratio * 100) / 100,
|
|
22854
|
+
recommendedRatio: 4.5
|
|
22855
|
+
});
|
|
22856
|
+
}
|
|
22857
|
+
return warnings;
|
|
22858
|
+
}
|
|
22859
|
+
function contrastRatio2(first, second) {
|
|
22860
|
+
const lighter = Math.max(luminance(first), luminance(second));
|
|
22861
|
+
const darker = Math.min(luminance(first), luminance(second));
|
|
22862
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
22863
|
+
}
|
|
22864
|
+
function luminance(color) {
|
|
22865
|
+
const match = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color);
|
|
22866
|
+
if (!match) return 1;
|
|
22867
|
+
const values = match.slice(1).map((value) => {
|
|
22868
|
+
const channel = Number.parseInt(value, 16) / 255;
|
|
22869
|
+
return channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4;
|
|
22870
|
+
});
|
|
22871
|
+
return 0.2126 * (values[0] ?? 0) + 0.7152 * (values[1] ?? 0) + 0.0722 * (values[2] ?? 0);
|
|
22872
|
+
}
|
|
22873
|
+
|
|
22621
22874
|
// src/presentation.ts
|
|
22622
22875
|
function syncAssistantPresentation(host, root, appearance, mode, sessionState) {
|
|
22623
22876
|
const presentation = appearance.presentation;
|
|
@@ -22790,6 +23043,35 @@ function replaceFallback(root, slotName, nodes) {
|
|
|
22790
23043
|
slot?.replaceChildren(...nodes);
|
|
22791
23044
|
}
|
|
22792
23045
|
|
|
23046
|
+
// src/element-theme.ts
|
|
23047
|
+
function applyAssistantElementTheme(input) {
|
|
23048
|
+
const { host, root, appearance, mode } = input;
|
|
23049
|
+
host.setAttribute("data-theme", mode);
|
|
23050
|
+
for (const [name, value] of Object.entries(appearance.theme[mode])) {
|
|
23051
|
+
host.style.setProperty(`--ns-assistant-default-${camelToKebab(name)}`, tokenValue(name, value));
|
|
23052
|
+
}
|
|
23053
|
+
const warnings = applyHostAppearance(host.style, input.hostAppearance, mode, input.styleSnapshot);
|
|
23054
|
+
host.style.setProperty("--ns-assistant-default-panel-width", `${appearance.layout.panelWidth}px`);
|
|
23055
|
+
host.style.setProperty(
|
|
23056
|
+
"--ns-assistant-default-min-height",
|
|
23057
|
+
`${appearance.layout.panelMinHeight}px`
|
|
23058
|
+
);
|
|
23059
|
+
host.style.setProperty(
|
|
23060
|
+
"--ns-assistant-default-max-height",
|
|
23061
|
+
`${appearance.layout.panelMaxHeight}px`
|
|
23062
|
+
);
|
|
23063
|
+
host.style.setProperty("--ns-assistant-default-z-index", String(appearance.layout.zIndex));
|
|
23064
|
+
host.style.setProperty("--ns-assistant-default-edge-offset", `${appearance.layout.edgeOffset}px`);
|
|
23065
|
+
const logo = root?.querySelector(".brand-logo");
|
|
23066
|
+
const logoUrl = appearance.brand.logo[mode];
|
|
23067
|
+
if (logo) {
|
|
23068
|
+
logo.hidden = !logoUrl;
|
|
23069
|
+
if (logoUrl) logo.src = logoUrl;
|
|
23070
|
+
}
|
|
23071
|
+
if (root) syncAssistantPresentation(host, root, appearance, mode, input.sessionState);
|
|
23072
|
+
return warnings;
|
|
23073
|
+
}
|
|
23074
|
+
|
|
22793
23075
|
// src/presentation-styles.ts
|
|
22794
23076
|
var presentationStyles = `<style>
|
|
22795
23077
|
:host([data-mode="floating"]) {
|
|
@@ -22995,7 +23277,18 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
22995
23277
|
#pendingUserEcho;
|
|
22996
23278
|
#sessionState = "idle";
|
|
22997
23279
|
#startOpenApplied = false;
|
|
23280
|
+
#hostAppearance;
|
|
23281
|
+
#appearanceWarningKeys = /* @__PURE__ */ new Set();
|
|
23282
|
+
#appearanceStyleSnapshot = /* @__PURE__ */ new Map();
|
|
22998
23283
|
sessionEndpoint = "";
|
|
23284
|
+
get appearance() {
|
|
23285
|
+
return this.#hostAppearance;
|
|
23286
|
+
}
|
|
23287
|
+
set appearance(value) {
|
|
23288
|
+
this.#hostAppearance = value;
|
|
23289
|
+
this.#appearanceWarningKeys.clear();
|
|
23290
|
+
if (this.isConnected) this.#applyTheme();
|
|
23291
|
+
}
|
|
22999
23292
|
#events = new AssistantElementEventController({
|
|
23000
23293
|
element: this,
|
|
23001
23294
|
messages: () => this.#messages,
|
|
@@ -23011,10 +23304,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
23011
23304
|
this.#syncAppearance();
|
|
23012
23305
|
this.#applyStartOpenPolicy();
|
|
23013
23306
|
},
|
|
23014
|
-
labels: () =>
|
|
23015
|
-
confirm: this.#appearance.labels.confirm,
|
|
23016
|
-
cancel: this.#appearance.labels.cancel
|
|
23017
|
-
}),
|
|
23307
|
+
labels: () => this.#appearance.labels,
|
|
23018
23308
|
respond: (id, response) => this.respond(id, response),
|
|
23019
23309
|
dispatchError: (detail) => this.#dispatchError(detail),
|
|
23020
23310
|
renderView: (detail) => {
|
|
@@ -23075,6 +23365,15 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
23075
23365
|
focusComposer() {
|
|
23076
23366
|
this.shadowRoot?.querySelector("textarea")?.focus();
|
|
23077
23367
|
}
|
|
23368
|
+
/** Stop the active stream without discarding the current composer draft or session. */
|
|
23369
|
+
stop() {
|
|
23370
|
+
if (!this.hasAttribute("busy")) return;
|
|
23371
|
+
this.#conversationGeneration += 1;
|
|
23372
|
+
this.#client?.abort();
|
|
23373
|
+
this.#setBusy(false);
|
|
23374
|
+
this.#appendStatus(this.#appearance.labels.stopped);
|
|
23375
|
+
this.dispatchEvent(new CustomEvent("assistant-stopped"));
|
|
23376
|
+
}
|
|
23078
23377
|
resetSession() {
|
|
23079
23378
|
this.#conversationGeneration += 1;
|
|
23080
23379
|
this.#client?.abort();
|
|
@@ -23089,6 +23388,20 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
23089
23388
|
this.#setBusy(false);
|
|
23090
23389
|
this.#setSessionState("idle");
|
|
23091
23390
|
}
|
|
23391
|
+
/** Re-establish the session without replaying a message or interaction decision. */
|
|
23392
|
+
reconnect() {
|
|
23393
|
+
this.#conversationGeneration += 1;
|
|
23394
|
+
this.#client?.abort();
|
|
23395
|
+
this.#unsubscribeClient?.();
|
|
23396
|
+
this.#client = void 0;
|
|
23397
|
+
this.#clientEndpoint = "";
|
|
23398
|
+
this.#unsubscribeClient = void 0;
|
|
23399
|
+
this.#sessionBootstrap = void 0;
|
|
23400
|
+
this.#setBusy(false);
|
|
23401
|
+
this.#setSessionState("loading");
|
|
23402
|
+
this.#primeSession();
|
|
23403
|
+
this.dispatchEvent(new CustomEvent("assistant-reconnecting"));
|
|
23404
|
+
}
|
|
23092
23405
|
updateContext(context) {
|
|
23093
23406
|
this.#context = { ...context };
|
|
23094
23407
|
if (this.#client) {
|
|
@@ -23136,6 +23449,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
23136
23449
|
await this.#ensureClient().sendMessage(message);
|
|
23137
23450
|
} catch (error51) {
|
|
23138
23451
|
if (generation !== this.#conversationGeneration) return;
|
|
23452
|
+
if (error51 instanceof AssistantClientError && error51.detail.code === "request_aborted") return;
|
|
23139
23453
|
this.#dispatchClientError(error51, "turn_failed");
|
|
23140
23454
|
throw error51;
|
|
23141
23455
|
} finally {
|
|
@@ -23215,26 +23529,31 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
23215
23529
|
#handleClientEvent(event) {
|
|
23216
23530
|
this.dispatchEvent(new CustomEvent("assistant-event", { detail: event }));
|
|
23217
23531
|
this.#events.handle(event);
|
|
23218
|
-
if (event.event === "session_started")
|
|
23532
|
+
if (event.event === "session_started") {
|
|
23533
|
+
this.#setSessionState("ready");
|
|
23534
|
+
this.#messages?.querySelector(".conversation-error")?.remove();
|
|
23535
|
+
}
|
|
23219
23536
|
if (event.event === "session_expired" || event.event === "session_reset") {
|
|
23220
23537
|
this.#setSessionState("idle");
|
|
23221
23538
|
}
|
|
23222
23539
|
if (event.event === "tool_proposed" || event.event === "interaction_proposed" || event.event === "input_requested") {
|
|
23223
23540
|
this.#removeThinking();
|
|
23224
23541
|
this.setAttribute("has-messages", "");
|
|
23225
|
-
this.#scrollToBottom();
|
|
23226
23542
|
}
|
|
23227
23543
|
if (event.event === "content" || event.event === "message_completed" || event.event === "interaction_completed" || event.event === "error") {
|
|
23228
23544
|
this.#removeThinking();
|
|
23229
|
-
this.#scrollToBottom();
|
|
23230
23545
|
}
|
|
23231
23546
|
}
|
|
23232
23547
|
#setBusy(busy) {
|
|
23233
23548
|
this.toggleAttribute("busy", busy);
|
|
23234
23549
|
const textarea = this.shadowRoot?.querySelector("textarea");
|
|
23235
23550
|
const send = this.shadowRoot?.querySelector(".send");
|
|
23236
|
-
if (textarea) textarea.disabled =
|
|
23237
|
-
if (send)
|
|
23551
|
+
if (textarea) textarea.disabled = false;
|
|
23552
|
+
if (send) {
|
|
23553
|
+
send.dataset.action = busy ? "stop" : "send";
|
|
23554
|
+
send.textContent = busy ? this.#appearance.labels.stop : this.#appearance.labels.send;
|
|
23555
|
+
send.setAttribute("aria-label", send.textContent);
|
|
23556
|
+
}
|
|
23238
23557
|
if (!busy) {
|
|
23239
23558
|
this.#removeThinking();
|
|
23240
23559
|
return;
|
|
@@ -23272,6 +23591,16 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
23272
23591
|
body.textContent = text2;
|
|
23273
23592
|
}
|
|
23274
23593
|
message.append(body);
|
|
23594
|
+
if (role === "assistant" && text2) {
|
|
23595
|
+
const copy = document.createElement("button");
|
|
23596
|
+
copy.type = "button";
|
|
23597
|
+
copy.className = "message-copy";
|
|
23598
|
+
copy.textContent = this.#appearance.labels.copy;
|
|
23599
|
+
copy.addEventListener("click", () => {
|
|
23600
|
+
void navigator.clipboard?.writeText(text2);
|
|
23601
|
+
});
|
|
23602
|
+
message.append(copy);
|
|
23603
|
+
}
|
|
23275
23604
|
if (this.#appearance.behavior.showTimestamps) {
|
|
23276
23605
|
const timestamp = document.createElement("time");
|
|
23277
23606
|
timestamp.dateTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -23283,12 +23612,31 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
23283
23612
|
}
|
|
23284
23613
|
this.#messages.append(message);
|
|
23285
23614
|
this.setAttribute("has-messages", "");
|
|
23286
|
-
this.#
|
|
23615
|
+
this.#revealLatest();
|
|
23287
23616
|
return body;
|
|
23288
23617
|
}
|
|
23618
|
+
#appendStatus(text2) {
|
|
23619
|
+
if (!this.#messages) return;
|
|
23620
|
+
const status = document.createElement("p");
|
|
23621
|
+
status.className = "conversation-status";
|
|
23622
|
+
status.setAttribute("role", "status");
|
|
23623
|
+
status.textContent = text2;
|
|
23624
|
+
this.#messages.append(status);
|
|
23625
|
+
}
|
|
23289
23626
|
#scrollToBottom() {
|
|
23290
23627
|
if (this.#messages) this.#messages.scrollTop = this.#messages.scrollHeight;
|
|
23291
23628
|
}
|
|
23629
|
+
#revealLatest() {
|
|
23630
|
+
if (!this.#messages) return;
|
|
23631
|
+
const distance = this.#messages.scrollHeight - this.#messages.scrollTop - this.#messages.clientHeight;
|
|
23632
|
+
const control = this.shadowRoot?.querySelector(".new-messages");
|
|
23633
|
+
if (distance <= 160) {
|
|
23634
|
+
this.#scrollToBottom();
|
|
23635
|
+
if (control) control.hidden = true;
|
|
23636
|
+
} else if (control) {
|
|
23637
|
+
control.hidden = false;
|
|
23638
|
+
}
|
|
23639
|
+
}
|
|
23292
23640
|
#dispatchError(detail) {
|
|
23293
23641
|
this.dispatchEvent(new CustomEvent("assistant-error", { detail }));
|
|
23294
23642
|
}
|
|
@@ -23296,9 +23644,27 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
23296
23644
|
if (error51 instanceof AssistantClientError && error51.detail.code === "session_failed") {
|
|
23297
23645
|
this.#setSessionState("error");
|
|
23298
23646
|
}
|
|
23299
|
-
|
|
23300
|
-
|
|
23647
|
+
const detail = error51 instanceof AssistantClientError ? error51.detail : { code: fallbackCode, retryable: false };
|
|
23648
|
+
this.#appendRecoveryError(
|
|
23649
|
+
detail.code === "session_expired" ? this.#appearance.labels.sessionExpired : this.#appearance.labels.unavailable
|
|
23301
23650
|
);
|
|
23651
|
+
this.#dispatchError(detail);
|
|
23652
|
+
}
|
|
23653
|
+
#appendRecoveryError(message) {
|
|
23654
|
+
if (!this.#messages) return;
|
|
23655
|
+
this.#messages.querySelector(".conversation-error")?.remove();
|
|
23656
|
+
const error51 = document.createElement("section");
|
|
23657
|
+
error51.className = "conversation-error";
|
|
23658
|
+
error51.setAttribute("role", "alert");
|
|
23659
|
+
const text2 = document.createElement("p");
|
|
23660
|
+
text2.textContent = message;
|
|
23661
|
+
const retry = document.createElement("button");
|
|
23662
|
+
retry.type = "button";
|
|
23663
|
+
retry.textContent = this.#appearance.labels.reconnect;
|
|
23664
|
+
retry.addEventListener("click", () => this.reconnect());
|
|
23665
|
+
error51.append(text2, retry);
|
|
23666
|
+
this.#messages.append(error51);
|
|
23667
|
+
this.#revealLatest();
|
|
23302
23668
|
}
|
|
23303
23669
|
#resolvedMode() {
|
|
23304
23670
|
const configured = this.getAttribute("theme") ?? this.#appearance.theme.defaultMode;
|
|
@@ -23306,43 +23672,24 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
23306
23672
|
}
|
|
23307
23673
|
#applyTheme() {
|
|
23308
23674
|
const mode = this.#resolvedMode();
|
|
23309
|
-
|
|
23310
|
-
|
|
23311
|
-
|
|
23312
|
-
this
|
|
23313
|
-
|
|
23314
|
-
|
|
23675
|
+
for (const warning of applyAssistantElementTheme({
|
|
23676
|
+
host: this,
|
|
23677
|
+
root: this.shadowRoot,
|
|
23678
|
+
appearance: this.#appearance,
|
|
23679
|
+
hostAppearance: this.#hostAppearance,
|
|
23680
|
+
mode,
|
|
23681
|
+
sessionState: this.#sessionState,
|
|
23682
|
+
styleSnapshot: this.#appearanceStyleSnapshot
|
|
23683
|
+
})) {
|
|
23684
|
+
const key = `${warning.theme}:${warning.role}:${warning.foreground}:${warning.background}`;
|
|
23685
|
+
if (this.#appearanceWarningKeys.has(key)) continue;
|
|
23686
|
+
this.#appearanceWarningKeys.add(key);
|
|
23687
|
+
this.dispatchEvent(
|
|
23688
|
+
new CustomEvent("assistant-appearance-warning", {
|
|
23689
|
+
detail: warning
|
|
23690
|
+
})
|
|
23315
23691
|
);
|
|
23316
23692
|
}
|
|
23317
|
-
this.style.setProperty(
|
|
23318
|
-
"--ns-assistant-default-panel-width",
|
|
23319
|
-
`${this.#appearance.layout.panelWidth}px`
|
|
23320
|
-
);
|
|
23321
|
-
this.style.setProperty(
|
|
23322
|
-
"--ns-assistant-default-min-height",
|
|
23323
|
-
`${this.#appearance.layout.panelMinHeight}px`
|
|
23324
|
-
);
|
|
23325
|
-
this.style.setProperty(
|
|
23326
|
-
"--ns-assistant-default-max-height",
|
|
23327
|
-
`${this.#appearance.layout.panelMaxHeight}px`
|
|
23328
|
-
);
|
|
23329
|
-
this.style.setProperty(
|
|
23330
|
-
"--ns-assistant-default-z-index",
|
|
23331
|
-
String(this.#appearance.layout.zIndex)
|
|
23332
|
-
);
|
|
23333
|
-
this.style.setProperty(
|
|
23334
|
-
"--ns-assistant-default-edge-offset",
|
|
23335
|
-
`${this.#appearance.layout.edgeOffset}px`
|
|
23336
|
-
);
|
|
23337
|
-
const logo = this.shadowRoot?.querySelector(".brand-logo");
|
|
23338
|
-
const logoUrl = this.#appearance.brand.logo[mode];
|
|
23339
|
-
if (logo) {
|
|
23340
|
-
logo.hidden = !logoUrl;
|
|
23341
|
-
if (logoUrl) logo.src = logoUrl;
|
|
23342
|
-
}
|
|
23343
|
-
if (this.shadowRoot) {
|
|
23344
|
-
syncAssistantPresentation(this, this.shadowRoot, this.#appearance, mode, this.#sessionState);
|
|
23345
|
-
}
|
|
23346
23693
|
}
|
|
23347
23694
|
#setSessionState(state) {
|
|
23348
23695
|
this.#sessionState = state;
|
|
@@ -23422,6 +23769,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
23422
23769
|
<div class="welcome"><slot name="empty-state"></slot></div>
|
|
23423
23770
|
<div class="suggested-prompts"></div>
|
|
23424
23771
|
<div class="messages" aria-live="polite"></div>
|
|
23772
|
+
<button class="new-messages" type="button" hidden></button>
|
|
23425
23773
|
<form><slot name="composer-leading"></slot><textarea rows="1"></textarea><button class="send" type="submit"></button><slot name="composer-trailing"></slot></form>
|
|
23426
23774
|
<nav class="legal" aria-label="Legal"></nav>
|
|
23427
23775
|
<slot name="conversation-footer"></slot>
|
|
@@ -23464,6 +23812,10 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
23464
23812
|
const form = queryRequired(this.shadowRoot, "form");
|
|
23465
23813
|
form.addEventListener("submit", (event) => {
|
|
23466
23814
|
event.preventDefault();
|
|
23815
|
+
if (this.hasAttribute("busy")) {
|
|
23816
|
+
this.stop();
|
|
23817
|
+
return;
|
|
23818
|
+
}
|
|
23467
23819
|
const value = textarea.value;
|
|
23468
23820
|
textarea.value = "";
|
|
23469
23821
|
textarea.style.height = "auto";
|
|
@@ -23478,6 +23830,17 @@ var NoodleAssistantElement = class extends HTMLElementBase {
|
|
|
23478
23830
|
event.preventDefault();
|
|
23479
23831
|
form.requestSubmit();
|
|
23480
23832
|
});
|
|
23833
|
+
const newMessages = queryRequired(this.shadowRoot, ".new-messages");
|
|
23834
|
+
newMessages.textContent = appearance.labels.newMessages;
|
|
23835
|
+
newMessages.addEventListener("click", () => {
|
|
23836
|
+
this.#scrollToBottom();
|
|
23837
|
+
newMessages.hidden = true;
|
|
23838
|
+
});
|
|
23839
|
+
this.#messages?.addEventListener("scroll", () => {
|
|
23840
|
+
if (this.#messages && this.#messages.scrollHeight - this.#messages.scrollTop - this.#messages.clientHeight < 48) {
|
|
23841
|
+
newMessages.hidden = true;
|
|
23842
|
+
}
|
|
23843
|
+
});
|
|
23481
23844
|
this.#applyTheme();
|
|
23482
23845
|
}
|
|
23483
23846
|
#appendLegalLinks(legal) {
|