@unofficialbox/box-open-elements 0.18.0 → 0.20.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/dist/components/actions/button-group.js +6 -0
- package/dist/components/actions/button.js +6 -0
- package/dist/components/actions/icon-button.js +6 -0
- package/dist/components/actions/link-button.js +6 -0
- package/dist/components/actions/menu-item.js +6 -0
- package/dist/components/actions/menu.js +6 -0
- package/dist/components/actions/segmented-control.js +6 -0
- package/dist/components/actions/toolbar.js +6 -0
- package/dist/components/collections/card.js +6 -0
- package/dist/components/collections/carousel.js +6 -0
- package/dist/components/collections/check-list.d.ts +10 -0
- package/dist/components/collections/check-list.js +8 -0
- package/dist/components/collections/datalist-item.js +6 -0
- package/dist/components/collections/document-list.d.ts +10 -0
- package/dist/components/collections/document-list.js +8 -0
- package/dist/components/collections/draggable-list.js +6 -0
- package/dist/components/collections/fact-list.d.ts +10 -0
- package/dist/components/collections/fact-list.js +8 -0
- package/dist/components/collections/grid-view.js +6 -0
- package/dist/components/collections/pagination.js +6 -0
- package/dist/components/collections/result-blocks.d.ts +54 -0
- package/dist/components/collections/result-blocks.js +71 -0
- package/dist/components/collections/table.js +6 -0
- package/dist/components/collections/thumbnail-card.js +6 -0
- package/dist/components/collections/tree-grid.js +6 -0
- package/dist/components/collections/tree.js +6 -0
- package/dist/components/feedback/alert.js +1 -1
- package/dist/components/feedback/badge.js +1 -1
- package/dist/components/feedback/badgeable.js +6 -0
- package/dist/components/feedback/chip.js +6 -0
- package/dist/components/feedback/due-badge.js +6 -0
- package/dist/components/feedback/empty-state.js +6 -0
- package/dist/components/feedback/error-mask.js +6 -0
- package/dist/components/feedback/help-text.js +6 -0
- package/dist/components/feedback/indicator.js +1 -1
- package/dist/components/feedback/nudge.js +6 -0
- package/dist/components/feedback/path.js +6 -0
- package/dist/components/feedback/progress-bar.d.ts +9 -0
- package/dist/components/feedback/progress-bar.js +35 -3
- package/dist/components/feedback/progress-ring.js +6 -0
- package/dist/components/feedback/progress-steps.js +6 -0
- package/dist/components/feedback/skeleton.js +6 -0
- package/dist/components/feedback/spinner.js +6 -0
- package/dist/components/feedback/status-icon.d.ts +10 -0
- package/dist/components/feedback/status-icon.js +26 -0
- package/dist/components/feedback/toast.js +1 -1
- package/dist/components/files/drop-zone.js +1 -1
- package/dist/components/forms/calendar.js +6 -0
- package/dist/components/forms/category-selector.js +6 -0
- package/dist/components/forms/checkbox-group.js +6 -0
- package/dist/components/forms/checkbox.js +6 -0
- package/dist/components/forms/color-picker.js +6 -0
- package/dist/components/forms/combobox.js +6 -0
- package/dist/components/forms/date-field.js +6 -0
- package/dist/components/forms/dropdown.js +6 -0
- package/dist/components/forms/dual-listbox.js +6 -0
- package/dist/components/forms/fieldset.js +6 -0
- package/dist/components/forms/multi-select.js +6 -0
- package/dist/components/forms/number-input.js +6 -0
- package/dist/components/forms/pill-cloud.js +6 -0
- package/dist/components/forms/pill-selector-dropdown.js +6 -0
- package/dist/components/forms/radio-group.js +6 -0
- package/dist/components/forms/range-slider.js +6 -0
- package/dist/components/forms/rating.js +6 -0
- package/dist/components/forms/rich-text-input.js +6 -0
- package/dist/components/forms/search-field.js +6 -0
- package/dist/components/forms/select.js +6 -0
- package/dist/components/forms/slider.js +6 -0
- package/dist/components/forms/spin-button.js +6 -0
- package/dist/components/forms/switch.js +6 -0
- package/dist/components/forms/tag-input.js +6 -0
- package/dist/components/forms/text-area.js +6 -0
- package/dist/components/forms/text-field.js +6 -0
- package/dist/components/forms/tile-group.js +1 -1
- package/dist/components/forms/time-field.js +6 -0
- package/dist/components/identity/avatar.js +6 -0
- package/dist/components/identity/contact-datalist-item.js +6 -0
- package/dist/components/identity/persona.js +6 -0
- package/dist/components/layout/app-shell.js +6 -0
- package/dist/components/layout/divider.js +6 -0
- package/dist/components/layout/grid.js +1 -1
- package/dist/components/layout/nav-sidebar.js +6 -0
- package/dist/components/layout/section.js +6 -0
- package/dist/components/layout/sidebar-toggle-button.js +6 -0
- package/dist/components/layout/split-view.js +6 -0
- package/dist/components/navigation/accordion.js +6 -0
- package/dist/components/navigation/breadcrumb.js +6 -0
- package/dist/components/navigation/tabs.js +6 -0
- package/dist/components/output/code-block.js +1 -1
- package/dist/components/output/formatted-value.js +1 -1
- package/dist/components/overlays/command-palette.js +6 -0
- package/dist/components/overlays/context-menu.js +6 -0
- package/dist/components/overlays/guide-tooltip.js +6 -0
- package/dist/components/overlays/popover.js +6 -0
- package/dist/components/overlays/shortcuts-overlay.js +6 -0
- package/dist/components/overlays/tooltip.js +6 -0
- package/dist/components/visuals/illustration.js +6 -0
- package/dist/element-maps.d.ts +39 -19
- package/dist/entries/agent-workspace.d.ts +1 -0
- package/dist/entries/agent-workspace.js +1 -0
- package/dist/entries/call-console.d.ts +1 -0
- package/dist/entries/call-console.js +1 -0
- package/dist/entries/check-list.d.ts +1 -0
- package/dist/entries/check-list.js +1 -0
- package/dist/entries/document-list.d.ts +1 -0
- package/dist/entries/document-list.js +1 -0
- package/dist/entries/fact-list.d.ts +1 -0
- package/dist/entries/fact-list.js +1 -0
- package/dist/entries/result-blocks.d.ts +1 -0
- package/dist/entries/result-blocks.js +1 -0
- package/dist/entries/run-summary.d.ts +1 -0
- package/dist/entries/run-summary.js +1 -0
- package/dist/entries/status-icon.d.ts +1 -0
- package/dist/entries/status-icon.js +1 -0
- package/dist/foundations/motion/behaviors.d.ts +8 -0
- package/dist/foundations/motion/behaviors.js +24 -0
- package/dist/foundations/motion/index.d.ts +2 -0
- package/dist/foundations/motion/index.js +2 -0
- package/dist/foundations/motion/scroll-pin.d.ts +19 -0
- package/dist/foundations/motion/scroll-pin.js +60 -0
- package/dist/foundations/motion/tokens.d.ts +2 -0
- package/dist/foundations/motion/tokens.js +2 -0
- package/dist/foundations/profiles/registry.d.ts +3 -0
- package/dist/foundations/profiles/registry.js +3 -0
- package/dist/foundations/profiles/types.d.ts +3 -0
- package/dist/foundations/status/index.d.ts +6 -0
- package/dist/foundations/status/index.js +33 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +10 -0
- package/dist/patterns/agent-chat/agent-chat.d.ts +9 -0
- package/dist/patterns/agent-chat/agent-chat.js +141 -21
- package/dist/patterns/agent-chat/controller.d.ts +3 -1
- package/dist/patterns/agent-chat/controller.js +92 -16
- package/dist/patterns/agent-chat/index.d.ts +1 -0
- package/dist/patterns/agent-chat/index.js +1 -0
- package/dist/patterns/agent-chat/ndjson.d.ts +5 -0
- package/dist/patterns/agent-chat/ndjson.js +41 -0
- package/dist/patterns/agent-chat/types.d.ts +44 -1
- package/dist/patterns/agent-workspace/agent-workspace.d.ts +28 -0
- package/dist/patterns/agent-workspace/agent-workspace.js +215 -0
- package/dist/patterns/agent-workspace/controller.d.ts +38 -0
- package/dist/patterns/agent-workspace/controller.js +65 -0
- package/dist/patterns/agent-workspace/index.d.ts +2 -0
- package/dist/patterns/agent-workspace/index.js +2 -0
- package/dist/patterns/audit/activity-density.js +6 -0
- package/dist/patterns/audit/audit-log.js +6 -0
- package/dist/patterns/call-console/call-console.d.ts +17 -0
- package/dist/patterns/call-console/call-console.js +107 -0
- package/dist/patterns/call-console/controller.d.ts +23 -0
- package/dist/patterns/call-console/controller.js +50 -0
- package/dist/patterns/call-console/http-transport.d.ts +3 -0
- package/dist/patterns/call-console/http-transport.js +26 -0
- package/dist/patterns/call-console/index.d.ts +4 -0
- package/dist/patterns/call-console/index.js +4 -0
- package/dist/patterns/call-console/types.d.ts +32 -0
- package/dist/patterns/call-console/types.js +8 -0
- package/dist/patterns/comments/comment-thread.js +6 -0
- package/dist/patterns/content-explorer/adapters/action-menu.js +6 -0
- package/dist/patterns/content-explorer/adapters/breadcrumbs.js +6 -0
- package/dist/patterns/content-explorer/adapters/list.js +6 -0
- package/dist/patterns/content-explorer/adapters/table.js +6 -0
- package/dist/patterns/content-explorer/adapters/toolbar.js +6 -0
- package/dist/patterns/content-explorer/content-explorer.js +6 -0
- package/dist/patterns/content-picker/content-picker.js +6 -0
- package/dist/patterns/content-sidebar/content-sidebar.js +6 -0
- package/dist/patterns/content-uploader/content-uploader.js +8 -1
- package/dist/patterns/diff/compare-view.js +6 -0
- package/dist/patterns/diff/diff-viewer.js +6 -0
- package/dist/patterns/file-request/file-request-builder.js +6 -0
- package/dist/patterns/form-wizard/form-wizard.js +6 -0
- package/dist/patterns/form-wizard/wizard-summary.js +6 -0
- package/dist/patterns/governance/governance-panel.js +6 -0
- package/dist/patterns/insights/bar-chart.js +6 -0
- package/dist/patterns/insights/chart-panel.js +6 -0
- package/dist/patterns/insights/donut-chart.js +6 -0
- package/dist/patterns/insights/line-chart.js +6 -0
- package/dist/patterns/insights/metric-card.js +6 -0
- package/dist/patterns/item/bulk-action-bar.js +6 -0
- package/dist/patterns/item/item-details-panel.js +6 -0
- package/dist/patterns/item/item-form.js +6 -0
- package/dist/patterns/item/preview-header.js +6 -0
- package/dist/patterns/lineage/lineage-graph.js +6 -0
- package/dist/patterns/lineage/provenance-strip.js +6 -0
- package/dist/patterns/metadata/metadata-filter-builder.js +6 -0
- package/dist/patterns/metadata/metadata-inspector.js +6 -0
- package/dist/patterns/notifications/notification-bell.js +6 -0
- package/dist/patterns/notifications/notification-inbox.js +6 -0
- package/dist/patterns/preview/annotation-inspector.js +6 -0
- package/dist/patterns/preview/annotation-toolbar.js +6 -0
- package/dist/patterns/preview/preview-element.js +6 -0
- package/dist/patterns/run/index.d.ts +2 -0
- package/dist/patterns/run/index.js +2 -0
- package/dist/patterns/run/progress.d.ts +24 -0
- package/dist/patterns/run/progress.js +32 -0
- package/dist/patterns/run/run-summary.d.ts +21 -0
- package/dist/patterns/run/run-summary.js +82 -0
- package/dist/patterns/run/run-trace.d.ts +1 -0
- package/dist/patterns/run/run-trace.js +20 -3
- package/dist/patterns/search/filter-bar.js +6 -0
- package/dist/patterns/search/saved-view-picker.js +6 -0
- package/dist/patterns/search/search-results-header.js +6 -0
- package/dist/patterns/share/access-stats.js +6 -0
- package/dist/patterns/share/collaborator-avatars.js +6 -0
- package/dist/patterns/share/invite-collaborators-modal.js +6 -0
- package/dist/patterns/share/permission-matrix.js +6 -0
- package/dist/patterns/share/presence.js +6 -0
- package/dist/patterns/share/share-panel.js +6 -0
- package/dist/patterns/share/unified-share-modal.js +6 -0
- package/dist/patterns/signature/signature-ceremony.js +6 -0
- package/dist/patterns/task/review-queue-item.js +6 -0
- package/dist/patterns/task/task-assignment-panel.js +6 -0
- package/dist/patterns/timeline/timeline.js +6 -0
- package/dist/patterns/versions/version-graph.js +6 -0
- package/dist/patterns/versions/version-list.js +6 -0
- package/dist/patterns/work-queue/work-queue.js +6 -0
- package/dist/patterns/work-queue/workload-board.js +6 -0
- package/package.json +13 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Scroll following is changed by user intent, never by resize-induced scroll events. */
|
|
2
|
+
export class ScrollPinController {
|
|
3
|
+
viewport;
|
|
4
|
+
onChange;
|
|
5
|
+
pinned = true;
|
|
6
|
+
cleanup = [];
|
|
7
|
+
observer;
|
|
8
|
+
pointer = false;
|
|
9
|
+
lastTop = 0;
|
|
10
|
+
touchY = 0;
|
|
11
|
+
constructor(viewport, onChange = () => { }) {
|
|
12
|
+
this.viewport = viewport;
|
|
13
|
+
this.onChange = onChange;
|
|
14
|
+
}
|
|
15
|
+
connect(content = this.viewport) {
|
|
16
|
+
this.disconnect();
|
|
17
|
+
const on = (kind, fn) => {
|
|
18
|
+
this.viewport.addEventListener(kind, fn);
|
|
19
|
+
this.cleanup.push(() => this.viewport.removeEventListener(kind, fn));
|
|
20
|
+
};
|
|
21
|
+
on("wheel", e => { if (e.deltaY < 0)
|
|
22
|
+
this.unpin(); });
|
|
23
|
+
on("keydown", e => { if (["ArrowUp", "PageUp", "Home"].includes(e.key))
|
|
24
|
+
this.unpin(); });
|
|
25
|
+
on("touchstart", e => { this.touchY = e.touches[0]?.clientY ?? 0; });
|
|
26
|
+
on("touchmove", e => { const y = e.touches[0]?.clientY ?? this.touchY; if (y > this.touchY)
|
|
27
|
+
this.unpin(); this.touchY = y; });
|
|
28
|
+
on("pointerdown", () => { this.pointer = true; this.lastTop = this.viewport.scrollTop; });
|
|
29
|
+
const release = () => { this.pointer = false; };
|
|
30
|
+
this.viewport.ownerDocument.addEventListener("pointerup", release);
|
|
31
|
+
this.cleanup.push(() => this.viewport.ownerDocument.removeEventListener("pointerup", release));
|
|
32
|
+
on("scroll", () => {
|
|
33
|
+
if (this.pointer && this.viewport.scrollTop < this.lastTop)
|
|
34
|
+
this.unpin();
|
|
35
|
+
this.lastTop = this.viewport.scrollTop;
|
|
36
|
+
if (this.atBottom())
|
|
37
|
+
this.pinned = true;
|
|
38
|
+
this.notify();
|
|
39
|
+
});
|
|
40
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
41
|
+
this.observer = new ResizeObserver(() => this.contentChanged());
|
|
42
|
+
this.observer.observe(this.viewport);
|
|
43
|
+
if (content !== this.viewport)
|
|
44
|
+
this.observer.observe(content);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
atBottom() { return this.viewport.scrollHeight - this.viewport.clientHeight - this.viewport.scrollTop < 40; }
|
|
48
|
+
notify() { this.onChange(!this.pinned && !this.atBottom()); }
|
|
49
|
+
unpin() { this.pinned = false; this.notify(); }
|
|
50
|
+
contentChanged(newMessage = false) { if (newMessage)
|
|
51
|
+
this.pinned = true; if (this.pinned)
|
|
52
|
+
this.viewport.scrollTop = this.viewport.scrollHeight; this.notify(); }
|
|
53
|
+
jump() {
|
|
54
|
+
this.pinned = true;
|
|
55
|
+
const reduced = this.viewport.ownerDocument.defaultView?.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
56
|
+
this.viewport.scrollTo?.({ top: this.viewport.scrollHeight, behavior: reduced ? "instant" : "smooth" });
|
|
57
|
+
this.onChange(false);
|
|
58
|
+
}
|
|
59
|
+
disconnect() { this.cleanup.forEach(fn => fn()); this.cleanup = []; this.observer?.disconnect(); }
|
|
60
|
+
}
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* prefers-reduced-motion policy is one place to update.
|
|
7
7
|
*/
|
|
8
8
|
export declare const boeMotionDuration: {
|
|
9
|
+
readonly arrival: "var(--boe-profile-motion-arrival, 200ms)";
|
|
10
|
+
readonly panel: "var(--boe-profile-motion-panel, 320ms)";
|
|
9
11
|
/** Quick accent transitions (charts, micro-feedback) */
|
|
10
12
|
readonly fast: "var(--boe-profile-motion-fast, 120ms)";
|
|
11
13
|
/**
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* prefers-reduced-motion policy is one place to update.
|
|
7
7
|
*/
|
|
8
8
|
export const boeMotionDuration = {
|
|
9
|
+
arrival: "var(--boe-profile-motion-arrival, 200ms)",
|
|
10
|
+
panel: "var(--boe-profile-motion-panel, 320ms)",
|
|
9
11
|
/** Quick accent transitions (charts, micro-feedback) */
|
|
10
12
|
fast: "var(--boe-profile-motion-fast, 120ms)",
|
|
11
13
|
/**
|
|
@@ -52,6 +52,9 @@ export declare const DESIGN_PROFILE_VARIABLES: {
|
|
|
52
52
|
readonly primaryFocus: "--boe-profile-shadow-primary-focus";
|
|
53
53
|
};
|
|
54
54
|
readonly motion: {
|
|
55
|
+
readonly arrival: "--boe-profile-motion-arrival";
|
|
56
|
+
readonly panel: "--boe-profile-motion-panel";
|
|
57
|
+
readonly stagger: "--boe-profile-motion-stagger";
|
|
55
58
|
readonly fast: "--boe-profile-motion-fast";
|
|
56
59
|
readonly interactive: "--boe-profile-motion-interactive";
|
|
57
60
|
readonly medium: "--boe-profile-motion-medium";
|
|
@@ -51,6 +51,9 @@ export const DESIGN_PROFILE_VARIABLES = {
|
|
|
51
51
|
primaryFocus: "--boe-profile-shadow-primary-focus",
|
|
52
52
|
},
|
|
53
53
|
motion: {
|
|
54
|
+
arrival: "--boe-profile-motion-arrival",
|
|
55
|
+
panel: "--boe-profile-motion-panel",
|
|
56
|
+
stagger: "--boe-profile-motion-stagger",
|
|
54
57
|
fast: "--boe-profile-motion-fast",
|
|
55
58
|
interactive: "--boe-profile-motion-interactive",
|
|
56
59
|
medium: "--boe-profile-motion-medium",
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type StatusKind = "pending" | "active" | "done" | "warning" | "failed" | "skipped";
|
|
2
|
+
export declare const toStatusKind: (status: string) => StatusKind;
|
|
3
|
+
export declare const statusLabel: (kind: StatusKind) => string;
|
|
4
|
+
/** Decorative markup. Pair with visible words or the StatusIcon component. */
|
|
5
|
+
export declare const boeStatusGlyph: (kind: StatusKind) => string;
|
|
6
|
+
export declare const boeStatusStyles = "\n.boe-status { flex: none; vertical-align: middle; fill: none; stroke: currentColor; stroke-width: 1.5; }\n.boe-status[data-kind=\"active\"] { color: var(--boe-token-surface-surface-brand, #0061d5); animation: boe-status-spin .8s linear infinite; }\n.boe-status[data-kind=\"active\"] circle { opacity: .25; }\n.boe-status[data-kind=\"done\"] { color: var(--boe-token-text-status-text-success, #187657); }\n.boe-status[data-kind=\"warning\"] { color: var(--boe-token-text-status-text-warning, #946400); }\n.boe-status[data-kind=\"failed\"] { color: var(--boe-token-text-status-text-error, #c52a46); }\n.boe-status[data-kind=\"skipped\"] circle { stroke-dasharray: 2 2; }\n.boe-status:is([data-kind=\"done\"], [data-kind=\"warning\"], [data-kind=\"failed\"]) circle { fill: currentColor; }\n.boe-status:is([data-kind=\"done\"], [data-kind=\"warning\"], [data-kind=\"failed\"]) path { stroke: var(--boe-token-surface-surface, #fff); stroke-linecap: round; }\n.boe-status[data-kind=\"done\"] { animation: boe-pop 200ms ease-out both; }\n.boe-status[data-kind=\"done\"] path { stroke-dasharray: 20; animation: boe-status-check 200ms ease-out both; }\n";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const mappings = {
|
|
2
|
+
pending: "pending", info: "pending", active: "active", running: "active", in_progress: "active",
|
|
3
|
+
done: "done", succeeded: "done", completed: "done", pass: "done", approved: "done",
|
|
4
|
+
warning: "warning", warn: "warning", failed: "failed", fail: "failed", error: "failed",
|
|
5
|
+
skipped: "skipped", rejected: "skipped",
|
|
6
|
+
};
|
|
7
|
+
export const toStatusKind = (status) => mappings[status] ?? "pending";
|
|
8
|
+
export const statusLabel = (kind) => ({
|
|
9
|
+
pending: "Pending", active: "In progress", done: "Done", warning: "Done with a warning",
|
|
10
|
+
failed: "Failed", skipped: "Skipped",
|
|
11
|
+
})[kind];
|
|
12
|
+
/** Decorative markup. Pair with visible words or the StatusIcon component. */
|
|
13
|
+
export const boeStatusGlyph = (kind) => {
|
|
14
|
+
const state = toStatusKind(kind);
|
|
15
|
+
const path = state === "done" ? '<path d="m4 8 3 3 5-6"/>'
|
|
16
|
+
: state === "failed" ? '<path d="m5 5 6 6m0-6-6 6"/>'
|
|
17
|
+
: state === "warning" ? '<path d="M5 8h6"/>'
|
|
18
|
+
: state === "active" ? '<path d="M8 1a7 7 0 0 1 7 7"/>' : "";
|
|
19
|
+
return `<svg class="boe-status" data-kind="${state}" aria-hidden="true" viewBox="0 0 16 16" width="16" height="16"><circle cx="8" cy="8" r="7"/>${path}</svg>`;
|
|
20
|
+
};
|
|
21
|
+
export const boeStatusStyles = `
|
|
22
|
+
.boe-status { flex: none; vertical-align: middle; fill: none; stroke: currentColor; stroke-width: 1.5; }
|
|
23
|
+
.boe-status[data-kind="active"] { color: var(--boe-token-surface-surface-brand, #0061d5); animation: boe-status-spin .8s linear infinite; }
|
|
24
|
+
.boe-status[data-kind="active"] circle { opacity: .25; }
|
|
25
|
+
.boe-status[data-kind="done"] { color: var(--boe-token-text-status-text-success, #187657); }
|
|
26
|
+
.boe-status[data-kind="warning"] { color: var(--boe-token-text-status-text-warning, #946400); }
|
|
27
|
+
.boe-status[data-kind="failed"] { color: var(--boe-token-text-status-text-error, #c52a46); }
|
|
28
|
+
.boe-status[data-kind="skipped"] circle { stroke-dasharray: 2 2; }
|
|
29
|
+
.boe-status:is([data-kind="done"], [data-kind="warning"], [data-kind="failed"]) circle { fill: currentColor; }
|
|
30
|
+
.boe-status:is([data-kind="done"], [data-kind="warning"], [data-kind="failed"]) path { stroke: var(--boe-token-surface-surface, #fff); stroke-linecap: round; }
|
|
31
|
+
.boe-status[data-kind="done"] { animation: boe-pop 200ms ease-out both; }
|
|
32
|
+
.boe-status[data-kind="done"] path { stroke-dasharray: 20; animation: boe-status-check 200ms ease-out both; }
|
|
33
|
+
`;
|
package/dist/index.d.ts
CHANGED
|
@@ -134,3 +134,13 @@ export * from "./patterns/task/index.js";
|
|
|
134
134
|
export * from "./patterns/governance/index.js";
|
|
135
135
|
export * from "./patterns/insights/index.js";
|
|
136
136
|
export * from "./element-maps.js";
|
|
137
|
+
export * from "./components/feedback/status-icon.js";
|
|
138
|
+
export * from "./components/collections/fact-list.js";
|
|
139
|
+
export * from "./components/collections/check-list.js";
|
|
140
|
+
export * from "./components/collections/document-list.js";
|
|
141
|
+
export * from "./components/collections/result-blocks.js";
|
|
142
|
+
export * from "./patterns/run/run-summary.js";
|
|
143
|
+
export * from "./patterns/agent-workspace/index.js";
|
|
144
|
+
export * from "./patterns/call-console/index.js";
|
|
145
|
+
export * from "./foundations/status/index.js";
|
|
146
|
+
export * from "./patterns/run/progress.js";
|
package/dist/index.js
CHANGED
|
@@ -148,3 +148,13 @@ export * from "./patterns/task/index.js";
|
|
|
148
148
|
export * from "./patterns/governance/index.js";
|
|
149
149
|
export * from "./patterns/insights/index.js";
|
|
150
150
|
export * from "./element-maps.js";
|
|
151
|
+
export * from "./components/feedback/status-icon.js";
|
|
152
|
+
export * from "./components/collections/fact-list.js";
|
|
153
|
+
export * from "./components/collections/check-list.js";
|
|
154
|
+
export * from "./components/collections/document-list.js";
|
|
155
|
+
export * from "./components/collections/result-blocks.js";
|
|
156
|
+
export * from "./patterns/run/run-summary.js";
|
|
157
|
+
export * from "./patterns/agent-workspace/index.js";
|
|
158
|
+
export * from "./patterns/call-console/index.js";
|
|
159
|
+
export * from "./foundations/status/index.js";
|
|
160
|
+
export * from "./patterns/run/progress.js";
|
|
@@ -16,6 +16,15 @@ export declare class AgentChat extends BaseElement {
|
|
|
16
16
|
static readonly tagName: string;
|
|
17
17
|
static get observedAttributes(): string[];
|
|
18
18
|
private controller;
|
|
19
|
+
private readonly scope;
|
|
20
|
+
private composing;
|
|
21
|
+
private scrollPin?;
|
|
22
|
+
private resizeObserver?;
|
|
23
|
+
private messageCount;
|
|
24
|
+
private jumpEl;
|
|
25
|
+
focusComposer(): void;
|
|
26
|
+
proposalAnchor(messageId: string, proposalId: string): string;
|
|
27
|
+
focusProposal(messageId: string, proposalId: string): void;
|
|
19
28
|
private ownsController;
|
|
20
29
|
private pendingStart;
|
|
21
30
|
private unsubscribeFns;
|
|
@@ -3,6 +3,11 @@ import { isSafeHref } from "../internal/safe-href.js";
|
|
|
3
3
|
import { BaseElement } from "../../core/index.js";
|
|
4
4
|
import { boeMotionDuration, boeMotionEasing } from "../../foundations/motion/index.js";
|
|
5
5
|
import { boePanel, boeRadius } from "../../foundations/geometry/index.js";
|
|
6
|
+
import { ScrollPinController, boeEntranceKeyframes, boeReducedMotionPolicy } from "../../foundations/motion/index.js";
|
|
7
|
+
import { boeStatusGlyph, boeStatusStyles } from "../../foundations/status/index.js";
|
|
8
|
+
import { ResultBlocks, resultDocumentIds } from "../../components/collections/result-blocks.js";
|
|
9
|
+
import { RunSummary } from "../run/run-summary.js";
|
|
10
|
+
let chatInstance = 0;
|
|
6
11
|
const DEFAULT_TAG_NAME = "box-agent-chat";
|
|
7
12
|
const escapeHtml = (value) => value
|
|
8
13
|
.replaceAll("&", "&")
|
|
@@ -28,6 +33,12 @@ const elementStyles = `
|
|
|
28
33
|
font: inherit;
|
|
29
34
|
}
|
|
30
35
|
|
|
36
|
+
/* The host's own display would otherwise beat the UA rule for [hidden],
|
|
37
|
+
leaving the element on screen when a host hides it. */
|
|
38
|
+
:host([hidden]) {
|
|
39
|
+
display: none !important;
|
|
40
|
+
}
|
|
41
|
+
|
|
31
42
|
section[part="panel"] {
|
|
32
43
|
display: grid;
|
|
33
44
|
gap: ${boePanel.gap};
|
|
@@ -359,9 +370,22 @@ const elementStyles = `
|
|
|
359
370
|
export class AgentChat extends BaseElement {
|
|
360
371
|
static tagName = DEFAULT_TAG_NAME;
|
|
361
372
|
static get observedAttributes() {
|
|
362
|
-
return ["agent-name", "heading", "placeholder", "token"];
|
|
373
|
+
return ["agent-name", "heading", "placeholder", "token", "hidden", "hide-citations"];
|
|
363
374
|
}
|
|
364
375
|
controller = null;
|
|
376
|
+
scope = `boe-chat-${++chatInstance}`;
|
|
377
|
+
composing = false;
|
|
378
|
+
scrollPin;
|
|
379
|
+
resizeObserver;
|
|
380
|
+
messageCount = 0;
|
|
381
|
+
jumpEl;
|
|
382
|
+
focusComposer() { this.inputEl?.focus({ preventScroll: true }); }
|
|
383
|
+
proposalAnchor(messageId, proposalId) { return `${this.scope}-${encodeURIComponent(messageId)}-${encodeURIComponent(proposalId)}`; }
|
|
384
|
+
focusProposal(messageId, proposalId) {
|
|
385
|
+
const card = this.shadowRoot?.getElementById(this.proposalAnchor(messageId, proposalId));
|
|
386
|
+
card?.scrollIntoView({ block: "nearest" });
|
|
387
|
+
card?.focus({ preventScroll: true });
|
|
388
|
+
}
|
|
365
389
|
ownsController = false;
|
|
366
390
|
pendingStart = false;
|
|
367
391
|
unsubscribeFns = [];
|
|
@@ -419,6 +443,8 @@ export class AgentChat extends BaseElement {
|
|
|
419
443
|
this.adoptController(value);
|
|
420
444
|
}
|
|
421
445
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
446
|
+
if (name === "hidden" && newValue === null && this.isRendered)
|
|
447
|
+
this.focusComposer();
|
|
422
448
|
if (name === "token") {
|
|
423
449
|
this.scheduleStart();
|
|
424
450
|
}
|
|
@@ -436,10 +462,26 @@ export class AgentChat extends BaseElement {
|
|
|
436
462
|
}
|
|
437
463
|
connectedCallback() {
|
|
438
464
|
super.connectedCallback();
|
|
465
|
+
if (this.controller && !this.ownsController && this.unsubscribeFns.length === 0)
|
|
466
|
+
this.subscribeToController(this.controller);
|
|
467
|
+
this.scrollPin?.connect();
|
|
468
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
469
|
+
this.resizeObserver = new ResizeObserver(() => this.scrollPin?.contentChanged());
|
|
470
|
+
this.resizeObserver.observe(this.threadEl);
|
|
471
|
+
for (const child of Array.from(this.threadEl.children))
|
|
472
|
+
this.resizeObserver.observe(child);
|
|
473
|
+
}
|
|
439
474
|
this.scheduleStart();
|
|
440
475
|
}
|
|
441
476
|
disconnectedCallback() {
|
|
442
|
-
this.
|
|
477
|
+
this.scrollPin?.disconnect();
|
|
478
|
+
this.resizeObserver?.disconnect();
|
|
479
|
+
if (this.ownsController)
|
|
480
|
+
this.teardownController();
|
|
481
|
+
else {
|
|
482
|
+
this.unsubscribeFns.forEach(fn => fn());
|
|
483
|
+
this.unsubscribeFns = [];
|
|
484
|
+
}
|
|
443
485
|
}
|
|
444
486
|
/** Send the composer's contents (or an explicit body) as a user turn. */
|
|
445
487
|
async send(body) {
|
|
@@ -449,11 +491,13 @@ export class AgentChat extends BaseElement {
|
|
|
449
491
|
}
|
|
450
492
|
// Clear only once the controller has accepted the turn, so a refused
|
|
451
493
|
// send (no controller, or a disconnected session) never loses typing.
|
|
452
|
-
const
|
|
453
|
-
|
|
494
|
+
const accepted = this.controller?.getState().connected;
|
|
495
|
+
const sending = this.controller?.send(text);
|
|
496
|
+
if (accepted && body === undefined && this.inputEl) {
|
|
454
497
|
this.inputEl.value = "";
|
|
455
498
|
this.syncComposer();
|
|
456
499
|
}
|
|
500
|
+
await sending;
|
|
457
501
|
}
|
|
458
502
|
/** Stop the in-flight generation; the partial reply is kept. */
|
|
459
503
|
stop() {
|
|
@@ -552,6 +596,13 @@ export class AgentChat extends BaseElement {
|
|
|
552
596
|
const canResolve = Boolean(this.controller?.config.transport.resolveAction);
|
|
553
597
|
return message.proposals
|
|
554
598
|
.map(proposal => {
|
|
599
|
+
if (proposal.decision) {
|
|
600
|
+
const failed = proposal.outcome === "failed";
|
|
601
|
+
return `<div part="proposal" tabindex="-1" id="${this.proposalAnchor(message.id, proposal.id)}" data-proposal-id="${escapeHtml(proposal.id)}" data-decision="${escapeHtml(proposal.decision)}" ${failed ? 'role="alert"' : ""}>
|
|
602
|
+
<span part="decision">${boeStatusGlyph(failed ? "failed" : proposal.decision === "approved" ? "done" : "skipped")}${proposal.decision === "approved" ? failed ? "Approved · didn't complete" : "Approved" : "Rejected"} · <span part="proposal-title">${escapeHtml(proposal.title)}</span></span>
|
|
603
|
+
${proposal.note ? `<p part="proposal-note">${escapeHtml(proposal.note)}</p>` : ""}
|
|
604
|
+
${failed ? `<button part="retry" data-message-id="${escapeHtml(message.id)}">Try again</button>` : ""}</div>`;
|
|
605
|
+
}
|
|
555
606
|
const params = (proposal.params ?? [])
|
|
556
607
|
.map(param => `
|
|
557
608
|
<dt part="param-label">${escapeHtml(param.label)}</dt>
|
|
@@ -561,20 +612,22 @@ export class AgentChat extends BaseElement {
|
|
|
561
612
|
const actions = canResolve && !proposal.decision
|
|
562
613
|
? `
|
|
563
614
|
<div part="proposal-actions">
|
|
564
|
-
<button type="button" part="proposal-action" data-action="approve" data-proposal-id="${escapeHtml(proposal.id)}"
|
|
565
|
-
<button type="button" part="proposal-action" data-action="reject" data-proposal-id="${escapeHtml(proposal.id)}"
|
|
566
|
-
<button type="button" part="proposal-action" data-action="modify" data-proposal-id="${escapeHtml(proposal.id)}">Modify</button>
|
|
615
|
+
<button type="button" part="proposal-action" data-action="approve" data-proposal-id="${escapeHtml(proposal.id)}" ${proposal.resolving ? "disabled" : ""} aria-busy="${proposal.resolving === "approved"}">${proposal.resolving === "approved" ? boeStatusGlyph("active") : ""}Approve</button>
|
|
616
|
+
<button type="button" part="proposal-action" data-action="reject" data-proposal-id="${escapeHtml(proposal.id)}" ${proposal.resolving ? "disabled" : ""} aria-busy="${proposal.resolving === "rejected"}">${proposal.resolving === "rejected" ? boeStatusGlyph("active") : ""}Reject</button>
|
|
617
|
+
<button type="button" part="proposal-action" data-action="modify" data-proposal-id="${escapeHtml(proposal.id)}" ${proposal.resolving ? "disabled" : ""}>Modify</button>
|
|
567
618
|
</div>
|
|
568
619
|
`
|
|
569
620
|
: "";
|
|
570
621
|
return `
|
|
571
|
-
<div part="proposal"
|
|
622
|
+
<div part="proposal" tabindex="-1" id="${this.proposalAnchor(message.id, proposal.id)}" data-proposal-id="${escapeHtml(proposal.id)}">
|
|
623
|
+
<span>${boeStatusGlyph("pending")} Needs your approval</span>
|
|
572
624
|
<span part="proposal-title">${escapeHtml(proposal.title)}</span>
|
|
573
625
|
${proposal.summary ? `<p part="proposal-summary">${escapeHtml(proposal.summary)}</p>` : ""}
|
|
574
626
|
${params ? `<dl part="proposal-params">${params}</dl>` : ""}
|
|
575
627
|
${proposal.decision ? `<span part="decision">${proposal.decision === "approved" ? "Approved" : "Rejected"}</span>` : ""}
|
|
576
628
|
${proposal.note ? `<p part="proposal-note">${escapeHtml(proposal.note)}</p>` : ""}
|
|
577
629
|
${actions}
|
|
630
|
+
<p part="proposal-note">To change it, reply with the new values.</p>
|
|
578
631
|
</div>
|
|
579
632
|
`;
|
|
580
633
|
})
|
|
@@ -583,7 +636,8 @@ export class AgentChat extends BaseElement {
|
|
|
583
636
|
messageInnerHtml(message) {
|
|
584
637
|
const name = message.role === "user" ? "You" : (message.actor?.name ?? this.agentName);
|
|
585
638
|
const initials = message.actor?.initials ?? initialsOf(name);
|
|
586
|
-
const
|
|
639
|
+
const documentIds = resultDocumentIds(message.blocks ?? []);
|
|
640
|
+
const citations = (this.hasAttribute("hide-citations") ? [] : message.citations.filter(c => !documentIds.includes(c.id)))
|
|
587
641
|
.map(citation => this.citationHtml(message.id, citation))
|
|
588
642
|
.join("");
|
|
589
643
|
return `
|
|
@@ -591,10 +645,14 @@ export class AgentChat extends BaseElement {
|
|
|
591
645
|
<span part="avatar" aria-hidden="true">${escapeHtml(initials)}</span>
|
|
592
646
|
<span part="author">${escapeHtml(name)}</span>
|
|
593
647
|
</div>
|
|
594
|
-
|
|
648
|
+
${message.role === "agent" ? '<box-run-summary></box-run-summary>' : ""}
|
|
649
|
+
<p part="body">${escapeHtml(message.body)}${message.status === "streaming" && !message.blocks?.length ? `<span part="caret" aria-hidden="true"></span>` : ""}</p>
|
|
650
|
+
<box-result-blocks></box-result-blocks>
|
|
651
|
+
${message.completeness?.status === "incomplete" ? '<p part="incomplete" role="status">This reply may be incomplete.</p>' : ""}
|
|
595
652
|
${message.status === "error" && message.errorMessage ? `<p part="error" role="alert">${escapeHtml(message.errorMessage)}</p>` : ""}
|
|
596
653
|
${citations ? `<div part="citations">${citations}</div>` : ""}
|
|
597
654
|
${this.proposalHtml(message)}
|
|
655
|
+
${message.proposals.some(p => p.outcome === "failed") ? "" : (message.options ?? []).map((o, i) => `<button part="option" data-option="${i}">${escapeHtml(o.label)}</button>`).join("")}
|
|
598
656
|
`;
|
|
599
657
|
}
|
|
600
658
|
/**
|
|
@@ -614,7 +672,12 @@ export class AgentChat extends BaseElement {
|
|
|
614
672
|
},
|
|
615
673
|
agentName: this.agentName,
|
|
616
674
|
citations: message.citations.map(({ id, href, label }) => ({ id, href, label })),
|
|
617
|
-
|
|
675
|
+
hideCitations: this.hasAttribute("hide-citations"),
|
|
676
|
+
blocks: message.blocks,
|
|
677
|
+
completeness: message.completeness?.status,
|
|
678
|
+
options: message.options,
|
|
679
|
+
proposals: message.proposals.map(({ id, title, summary, params, decision, note, outcome, resolving }) => ({
|
|
680
|
+
outcome, resolving,
|
|
618
681
|
id,
|
|
619
682
|
title,
|
|
620
683
|
summary,
|
|
@@ -650,21 +713,38 @@ export class AgentChat extends BaseElement {
|
|
|
650
713
|
body.insertBefore(document.createTextNode(message.body), body.firstChild);
|
|
651
714
|
}
|
|
652
715
|
renderTemplate() {
|
|
716
|
+
ResultBlocks.register();
|
|
717
|
+
RunSummary.register();
|
|
653
718
|
if (!this.shadowRoot) {
|
|
654
719
|
return;
|
|
655
720
|
}
|
|
656
721
|
// The composer is part of the stable shell: a streaming reply patches
|
|
657
722
|
// only [part="thread"], so typing is never interrupted.
|
|
658
723
|
this.shadowRoot.innerHTML = `
|
|
659
|
-
<style>${elementStyles}
|
|
724
|
+
<style>${elementStyles}
|
|
725
|
+
[part="message"][data-role="agent"]{border:0;background:transparent;padding-inline:0;max-width:75ch;min-width:0}
|
|
726
|
+
[part="message"][data-role="user"]{background:var(--boe-token-surface-surface-secondary,#f4f4f4)}
|
|
727
|
+
[part="proposal"]{border:1px solid var(--boe-token-stroke-stroke,#ddd);background:var(--boe-token-surface-surface,#fff);box-shadow:var(--boe-profile-shadow-overlay,0 3px 14px #0001)}
|
|
728
|
+
[part="proposal"][data-decision]{border:0;background:transparent;box-shadow:none;padding-inline:0}
|
|
729
|
+
[part="decision"]{background:none;border-radius:0;padding:0;gap:.4rem;font:inherit}
|
|
730
|
+
[part="proposal-action"][data-action="approve"],[part="proposal-action"][aria-busy="true"]{background:var(--boe-token-surface-surface-brand,#0061d5);color:var(--boe-token-text-text-on-brand,#fff);border-color:transparent}
|
|
731
|
+
[part="proposal-action"]:disabled:not([aria-busy="true"]){opacity:.5}
|
|
732
|
+
[part="composer"]{position:relative;border:1px solid var(--boe-token-stroke-stroke,#ddd);border-radius:12px;padding:.4rem}
|
|
733
|
+
[part="input"]{border:0;resize:none;max-height:180px;padding-right:5rem;box-sizing:border-box}
|
|
734
|
+
[part="composer-actions"]{position:absolute;right:.5rem;bottom:.5rem}
|
|
735
|
+
[part="jump"]{justify-self:center;border:1px solid var(--boe-token-stroke-stroke,#ddd);border-radius:999px;padding:.4rem .8rem;background:var(--boe-token-surface-surface,#fff);color:inherit;cursor:pointer}
|
|
736
|
+
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}
|
|
737
|
+
${boeEntranceKeyframes}${boeStatusStyles}${boeReducedMotionPolicy}</style>
|
|
660
738
|
<section part="panel">
|
|
661
739
|
<div part="header">
|
|
662
740
|
<h2 part="title"></h2>
|
|
663
741
|
<span part="status" role="status" aria-live="polite"></span>
|
|
664
742
|
</div>
|
|
665
|
-
<ol part="thread" role="log" aria-live="polite" aria-relevant="additions"></ol>
|
|
743
|
+
<ol part="thread" role="log" aria-live="polite" aria-relevant="additions" tabindex="0"></ol>
|
|
744
|
+
<button part="jump" hidden>Jump to latest</button>
|
|
666
745
|
<div part="composer">
|
|
667
|
-
<
|
|
746
|
+
<label class="sr-only" id="${this.scope}-label">Message</label>
|
|
747
|
+
<textarea part="input" rows="2" aria-labelledby="${this.scope}-label"></textarea>
|
|
668
748
|
<div part="composer-actions">
|
|
669
749
|
<button type="button" part="stop" hidden>Stop</button>
|
|
670
750
|
<button type="button" part="send">Send</button>
|
|
@@ -679,6 +759,11 @@ export class AgentChat extends BaseElement {
|
|
|
679
759
|
this.statusEl = this.shadowRoot.querySelector('[part="status"]');
|
|
680
760
|
}
|
|
681
761
|
setupListeners() {
|
|
762
|
+
this.jumpEl = this.shadowRoot.querySelector('[part="jump"]');
|
|
763
|
+
this.scrollPin = new ScrollPinController(this.threadEl, show => { this.jumpEl.hidden = !show; });
|
|
764
|
+
this.jumpEl.addEventListener("click", () => this.scrollPin?.jump());
|
|
765
|
+
this.inputEl.addEventListener("compositionstart", () => { this.composing = true; });
|
|
766
|
+
this.inputEl.addEventListener("compositionend", () => { this.composing = false; });
|
|
682
767
|
this.sendEl.addEventListener("click", () => {
|
|
683
768
|
void this.send();
|
|
684
769
|
});
|
|
@@ -687,7 +772,7 @@ export class AgentChat extends BaseElement {
|
|
|
687
772
|
});
|
|
688
773
|
this.inputEl.addEventListener("keydown", event => {
|
|
689
774
|
// Enter sends, Shift+Enter makes a newline — the conversational default.
|
|
690
|
-
if (event.key === "Enter" && !event.shiftKey) {
|
|
775
|
+
if (event.key === "Enter" && !event.shiftKey && !event.isComposing && !this.composing && event.keyCode !== 229) {
|
|
691
776
|
event.preventDefault();
|
|
692
777
|
void this.send();
|
|
693
778
|
}
|
|
@@ -697,15 +782,31 @@ export class AgentChat extends BaseElement {
|
|
|
697
782
|
});
|
|
698
783
|
this.threadEl.addEventListener("click", event => {
|
|
699
784
|
const target = event.target;
|
|
785
|
+
const messageId = target.closest('[part="message"]')?.getAttribute("data-message-id") ?? "";
|
|
786
|
+
const option = target.closest("[data-option]");
|
|
787
|
+
if (option) {
|
|
788
|
+
const prompt = this.controller?.getMessage(messageId)?.options?.[Number(option.dataset.option)]?.prompt;
|
|
789
|
+
if (prompt)
|
|
790
|
+
void this.send(prompt);
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
if (target.closest('[part="retry"]')) {
|
|
794
|
+
const messages = this.controller?.getState().messages ?? [];
|
|
795
|
+
const index = messages.findIndex(m => m.id === messageId);
|
|
796
|
+
const request = messages.slice(0, index).reverse().find(m => m.role === "user");
|
|
797
|
+
if (request)
|
|
798
|
+
void this.send(request.body);
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
700
801
|
const proposalButton = target.closest('[part="proposal-action"]');
|
|
701
802
|
if (proposalButton && this.threadEl.contains(proposalButton)) {
|
|
702
803
|
const proposalId = proposalButton.getAttribute("data-proposal-id") ?? "";
|
|
703
804
|
const action = proposalButton.getAttribute("data-action") ?? "";
|
|
704
805
|
if (action === "approve") {
|
|
705
|
-
void this.controller?.resolveAction(proposalId, "approved");
|
|
806
|
+
void this.controller?.resolveAction(proposalId, "approved", undefined, messageId);
|
|
706
807
|
}
|
|
707
808
|
else if (action === "reject") {
|
|
708
|
-
void this.controller?.resolveAction(proposalId, "rejected");
|
|
809
|
+
void this.controller?.resolveAction(proposalId, "rejected", undefined, messageId);
|
|
709
810
|
}
|
|
710
811
|
else if (action === "modify") {
|
|
711
812
|
// Modifying needs the host's own editor, so this surfaces intent.
|
|
@@ -738,6 +839,9 @@ export class AgentChat extends BaseElement {
|
|
|
738
839
|
const streaming = this.controller?.getState().streaming ?? false;
|
|
739
840
|
this.inputEl.placeholder = this.placeholder;
|
|
740
841
|
this.sendEl.disabled = streaming || this.inputEl.value.trim().length === 0;
|
|
842
|
+
this.sendEl.hidden = streaming;
|
|
843
|
+
this.inputEl.style.height = "auto";
|
|
844
|
+
this.inputEl.style.height = `${Math.min(180, Math.max(56, this.inputEl.scrollHeight))}px`;
|
|
741
845
|
this.stopEl.hidden = !streaming;
|
|
742
846
|
this.statusEl.textContent = streaming ? "Agent is responding…" : "";
|
|
743
847
|
}
|
|
@@ -756,7 +860,8 @@ export class AgentChat extends BaseElement {
|
|
|
756
860
|
: null;
|
|
757
861
|
const state = this.controller?.getState() ?? null;
|
|
758
862
|
const messages = state?.messages ?? [];
|
|
759
|
-
const
|
|
863
|
+
const newMessage = messages.length > this.messageCount;
|
|
864
|
+
this.messageCount = messages.length;
|
|
760
865
|
this.shadowRoot.querySelector('[part="title"]').textContent = this.heading;
|
|
761
866
|
if (messages.length === 0) {
|
|
762
867
|
if (!this.threadEl.querySelector('[part="empty"]')) {
|
|
@@ -787,7 +892,13 @@ export class AgentChat extends BaseElement {
|
|
|
787
892
|
else {
|
|
788
893
|
node.setAttribute("data-signature", signature);
|
|
789
894
|
node.setAttribute("data-status", message.status);
|
|
895
|
+
const summary = node.querySelector("box-run-summary");
|
|
896
|
+
const results = node.querySelector("box-result-blocks");
|
|
790
897
|
node.innerHTML = this.messageInnerHtml(message);
|
|
898
|
+
if (summary)
|
|
899
|
+
node.querySelector("box-run-summary")?.replaceWith(summary);
|
|
900
|
+
if (results)
|
|
901
|
+
node.querySelector("box-result-blocks")?.replaceWith(results);
|
|
791
902
|
}
|
|
792
903
|
}
|
|
793
904
|
else {
|
|
@@ -800,8 +911,19 @@ export class AgentChat extends BaseElement {
|
|
|
800
911
|
this.threadEl.insertBefore(node, anchor);
|
|
801
912
|
}
|
|
802
913
|
previous = node;
|
|
914
|
+
this.resizeObserver?.observe(node);
|
|
915
|
+
const blocks = node.querySelector("box-result-blocks");
|
|
916
|
+
if (blocks && blocks.blocks !== message.blocks)
|
|
917
|
+
blocks.blocks = message.blocks ?? [];
|
|
918
|
+
const summary = node.querySelector("box-run-summary");
|
|
919
|
+
if (summary) {
|
|
920
|
+
summary.toggleAttribute("failed", message.status === "error");
|
|
921
|
+
summary.turn = { steps: message.trace ?? [], todos: message.todos ?? [], startedAt: message.startedAt ?? 0,
|
|
922
|
+
...(message.endedAt !== undefined ? { endedAt: message.endedAt } : {}), incomplete: message.completeness?.status === "incomplete" };
|
|
923
|
+
}
|
|
803
924
|
}
|
|
804
925
|
for (const stale of existing.values()) {
|
|
926
|
+
this.resizeObserver?.unobserve(stale);
|
|
805
927
|
stale.remove();
|
|
806
928
|
}
|
|
807
929
|
if (focusKey?.part) {
|
|
@@ -811,9 +933,7 @@ export class AgentChat extends BaseElement {
|
|
|
811
933
|
target?.focus();
|
|
812
934
|
}
|
|
813
935
|
// Follow the stream only when the reader is already at the bottom.
|
|
814
|
-
|
|
815
|
-
this.threadEl.scrollTop = this.threadEl.scrollHeight;
|
|
816
|
-
}
|
|
936
|
+
this.scrollPin?.contentChanged(newMessage);
|
|
817
937
|
this.syncComposer();
|
|
818
938
|
}
|
|
819
939
|
}
|
|
@@ -11,6 +11,8 @@ export declare class AgentChatController extends Controller<AgentChatState, Agen
|
|
|
11
11
|
readonly config: AgentChatSessionConfig;
|
|
12
12
|
private sendCounter;
|
|
13
13
|
private activeAbortController;
|
|
14
|
+
private finishActive?;
|
|
15
|
+
private readonly resolving;
|
|
14
16
|
constructor(config: AgentChatSessionConfig);
|
|
15
17
|
connect(): void;
|
|
16
18
|
disconnect(): void;
|
|
@@ -23,5 +25,5 @@ export declare class AgentChatController extends Controller<AgentChatState, Agen
|
|
|
23
25
|
*/
|
|
24
26
|
send(body: string): Promise<AgentChatMessage | null>;
|
|
25
27
|
/** Resolve a HITL proposal through the transport capability. */
|
|
26
|
-
resolveAction(proposalId: string, decision: AgentActionDecision, note?: string): Promise<AgentActionProposal | null>;
|
|
28
|
+
resolveAction(proposalId: string, decision: AgentActionDecision, note?: string, messageId?: string): Promise<AgentActionProposal | null>;
|
|
27
29
|
}
|