@artooi/ag-ui-web-component 0.7.0 → 0.8.1

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.
@@ -77,12 +77,17 @@ export declare const DEFAULT_ATTACHMENT_MAX_BYTES: number;
77
77
  * How much detail a tool-call card shows. Set via the `data-tool-display`
78
78
  * attribute on `<ag-ui-chat>`; defaults to `full` (back-compatible).
79
79
  *
80
+ * - `inline` — the lightest mode: a single status row (icon + summary) with no
81
+ * surrounding card chrome, the result tucked behind its own toggle. Reads as
82
+ * one line of the answer rather than a boxed card — pairs with the answer
83
+ * well (page mode).
80
84
  * - `minimal` — just the tool name + status pill. No args, no result body.
81
85
  * - `compact` — name + status, with args *and* result tucked behind a single
82
86
  * collapsed "Details" toggle. The light default for dense UIs.
83
87
  * - `full` — args shown inline, result behind its own toggle (the original).
84
88
  */
85
89
  export declare const TOOL_DISPLAY: {
90
+ readonly INLINE: "inline";
86
91
  readonly MINIMAL: "minimal";
87
92
  readonly COMPACT: "compact";
88
93
  readonly FULL: "full";
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAGA,wEAAwE;AACxE,eAAO,MAAM,WAAW,eAAe,CAAC;AAExC;;;;GAIG;AACH,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C;;;;;GAKG;AACH,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,qCAAqC;AACrC,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC;;;;;GAKG;AACH,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C,yEAAyE;AACzE,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;CAKnB,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;CAIpB,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,QAAmB,CAAC;AAE7D;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY;;;;CAIf,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAGA,wEAAwE;AACxE,eAAO,MAAM,WAAW,eAAe,CAAC;AAExC;;;;GAIG;AACH,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C;;;;;GAKG;AACH,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAE3C,qCAAqC;AACrC,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC;;;;;GAKG;AACH,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C,yEAAyE;AACzE,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;CAKnB,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;CAIpB,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,QAAmB,CAAC;AAE7D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY;;;;;CAKf,CAAC"}
@@ -184,6 +184,10 @@ export declare class AgUiChat extends HTMLElement {
184
184
  * Assistant content is rendered as sanitised markdown/HTML; user content
185
185
  * stays literal text (no need to parse what the user typed, and it avoids
186
186
  * rendering user-authored markup).
187
+ *
188
+ * Assistant bubbles land in the current answer group (WELL-1), opening one if
189
+ * needed; a user bubble closes the prior group and sits directly in the list
190
+ * (the well wraps the *assistant* turn, the user message precedes it).
187
191
  */
188
192
  appendMessage(role: MessageRole, content: string): HTMLDivElement;
189
193
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ag_ui_chat.d.ts","sourceRoot":"","sources":["../../src/core/ag_ui_chat.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ag_ui_chat.d.ts","sourceRoot":"","sources":["../../src/core/ag_ui_chat.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@ var ATTACHMENT_STATUS = {
24
24
  };
25
25
  var DEFAULT_ATTACHMENT_MAX_BYTES = 10 * 1024 * 1024;
26
26
  var TOOL_DISPLAY = {
27
+ INLINE: "inline",
27
28
  MINIMAL: "minimal",
28
29
  COMPACT: "compact",
29
30
  FULL: "full"
@@ -3488,6 +3489,17 @@ var STYLES = `
3488
3489
  --ag-ui-danger: #b91c1c;
3489
3490
  --ag-ui-muted: #6b7280;
3490
3491
 
3492
+ /* Tool-call status icon glyphs (override to re-theme) + spinner speed.
3493
+ The pending state is the animated ring; the settled states use these. */
3494
+ --ag-ui-tool-icon-done: "\u2713";
3495
+ --ag-ui-tool-icon-error: "\u2715";
3496
+ --ag-ui-tool-icon-declined: "\u2298";
3497
+ --ag-ui-tool-spin-duration: 0.7s;
3498
+
3499
+ /* Answer well (opt-in via data-answer-well) \u2014 boxes a whole assistant turn. */
3500
+ --ag-ui-well-bg: transparent;
3501
+ --ag-ui-well-border: var(--ag-ui-border);
3502
+
3491
3503
  /* Surface \u2014 set --ag-ui-shadow: none for a flush, embedded panel. */
3492
3504
  --ag-ui-shadow: 0 12px 32px rgba(20, 20, 50, 0.18);
3493
3505
  --ag-ui-font: inherit;
@@ -3510,6 +3522,8 @@ var STYLES = `
3510
3522
  --ag-ui-inset: auto 24px 24px auto;
3511
3523
  --ag-ui-max-width: calc(100vw - 48px);
3512
3524
  --ag-ui-max-height: calc(100vh - 48px);
3525
+ /* Reading-column width for placement="page" (full-bleed, centred content). */
3526
+ --ag-ui-content-max-width: 820px;
3513
3527
 
3514
3528
  position: var(--ag-ui-position);
3515
3529
  inset: var(--ag-ui-inset);
@@ -3597,6 +3611,48 @@ var STYLES = `
3597
3611
  --ag-ui-radius: 0;
3598
3612
  }
3599
3613
 
3614
+ /* Page (PAGE-1): full-bleed background with a centred reading column. Unlike
3615
+ "full" (edge-to-edge, left-aligned messages) the content sits in a column
3616
+ capped at --ag-ui-content-max-width. The column is produced by symmetric auto
3617
+ padding on the scroll area + composer (no per-row wrapper), so user pills
3618
+ still right-align and the assistant well spans the column. */
3619
+ :host([placement="page"]) {
3620
+ --ag-ui-inset: 0;
3621
+ --ag-ui-width: 100vw;
3622
+ --ag-ui-height: 100vh;
3623
+ --ag-ui-max-width: 100vw;
3624
+ --ag-ui-max-height: 100vh;
3625
+ --ag-ui-radius: 0;
3626
+ }
3627
+
3628
+ :host([placement="page"]) .messages {
3629
+ padding-inline: max(var(--ag-ui-pad), calc((100% - var(--ag-ui-content-max-width)) / 2));
3630
+ }
3631
+
3632
+ :host([placement="page"]) .input-row {
3633
+ padding-inline: max(12px, calc((100% - var(--ag-ui-content-max-width)) / 2));
3634
+ }
3635
+
3636
+ /* The rows between the message list and the composer (skill chips, the
3637
+ /-command palette, the missing-placeholder hint, the upload tray) line up
3638
+ with the column too \u2014 chips are padding-based, the palette/hint/tray are
3639
+ margin-based, so each gets its own inline axis nudged by the same gutter. */
3640
+ :host([placement="page"]) .skill-chips,
3641
+ :host([placement="page"]) .attachment-tray {
3642
+ padding-inline: max(12px, calc((100% - var(--ag-ui-content-max-width)) / 2));
3643
+ }
3644
+
3645
+ :host([placement="page"]) .skill-palette,
3646
+ :host([placement="page"]) .skill-hint {
3647
+ margin-inline: max(12px, calc((100% - var(--ag-ui-content-max-width)) / 2));
3648
+ }
3649
+
3650
+ /* In the reading column the assistant well uses the full width; the user
3651
+ message stays a right-aligned pill (its default align-self + max-width). */
3652
+ :host([placement="page"]) .message--assistant {
3653
+ max-width: 100%;
3654
+ }
3655
+
3600
3656
  /* Sidebar (CUST-3): a full-height docked panel that slides open/closed and
3601
3657
  collapses to a slim icon rail (not the floating launcher). Docked right by
3602
3658
  default; data-side="left" docks it left. Overlay by default \u2014 set
@@ -3793,6 +3849,27 @@ var STYLES = `
3793
3849
  display: none;
3794
3850
  }
3795
3851
 
3852
+ /* \u2500\u2500 Answer group / well (WELL-1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
3853
+ One .answer per assistant turn wraps the streamed text, its tool cards,
3854
+ and the pending indicator so a whole answer reads (and can be boxed) as one
3855
+ unit. A flex column on the message-list gap, stretched to the list width so
3856
+ its children keep their own left/right alignment. data-answer-well opts into
3857
+ the bordered "well"; without it the layout is today's flat stack. */
3858
+ .answer {
3859
+ display: flex;
3860
+ flex-direction: column;
3861
+ gap: var(--ag-ui-space);
3862
+ align-self: stretch;
3863
+ min-width: 0;
3864
+ }
3865
+
3866
+ :host([data-answer-well]) .answer {
3867
+ padding: var(--ag-ui-pad);
3868
+ background: var(--ag-ui-well-bg);
3869
+ border: 1px solid var(--ag-ui-well-border);
3870
+ border-radius: var(--ag-ui-radius);
3871
+ }
3872
+
3796
3873
  .message {
3797
3874
  max-width: 80%;
3798
3875
  padding: var(--ag-ui-msg-pad);
@@ -3965,10 +4042,71 @@ var STYLES = `
3965
4042
  }
3966
4043
 
3967
4044
  .tool-call-name {
4045
+ flex: 1;
4046
+ min-width: 0;
3968
4047
  font-weight: 600;
3969
4048
  word-break: break-word;
3970
4049
  }
3971
4050
 
4051
+ /* Leading status icon (CARD-1). Empty in the DOM \u2014 the glyph/spinner is drawn
4052
+ here from the card's data-status, so it stays themeable. */
4053
+ .tool-call-icon {
4054
+ flex: none;
4055
+ box-sizing: border-box;
4056
+ display: inline-flex;
4057
+ align-items: center;
4058
+ justify-content: center;
4059
+ width: 14px;
4060
+ height: 14px;
4061
+ font-size: 12px;
4062
+ line-height: 1;
4063
+ }
4064
+
4065
+ /* Pending: a real spinning ring. Speed is tunable; reduced motion stops it. */
4066
+ .tool-call[data-status="pending"] .tool-call-icon {
4067
+ border: 2px solid var(--ag-ui-muted);
4068
+ border-top-color: transparent;
4069
+ border-radius: 50%;
4070
+ animation: ag-ui-tool-spin var(--ag-ui-tool-spin-duration) linear infinite;
4071
+ }
4072
+
4073
+ @keyframes ag-ui-tool-spin {
4074
+ to { transform: rotate(360deg); }
4075
+ }
4076
+
4077
+ /* Settled: a themeable glyph coloured by outcome. */
4078
+ .tool-call[data-status="done"] .tool-call-icon::before {
4079
+ content: var(--ag-ui-tool-icon-done);
4080
+ color: var(--ag-ui-success);
4081
+ }
4082
+
4083
+ .tool-call[data-status="error"] .tool-call-icon::before {
4084
+ content: var(--ag-ui-tool-icon-error);
4085
+ color: var(--ag-ui-danger);
4086
+ }
4087
+
4088
+ .tool-call[data-status="declined"] .tool-call-icon::before {
4089
+ content: var(--ag-ui-tool-icon-declined);
4090
+ color: var(--ag-ui-muted);
4091
+ }
4092
+
4093
+ @media (prefers-reduced-motion: reduce) {
4094
+ .tool-call[data-status="pending"] .tool-call-icon {
4095
+ animation: none;
4096
+ }
4097
+ }
4098
+
4099
+ /* Inline display mode (CARD-1): the lightest card \u2014 drop the box chrome so the
4100
+ status row reads as one line of the answer; the result toggle still expands
4101
+ below it. */
4102
+ .tool-call[data-display="inline"] {
4103
+ max-width: 100%;
4104
+ background: transparent;
4105
+ border: none;
4106
+ padding: 2px 0;
4107
+ gap: 2px;
4108
+ }
4109
+
3972
4110
  .tool-call-status {
3973
4111
  flex: none;
3974
4112
  padding: 1px 8px;
@@ -4740,15 +4878,19 @@ var ToolCallCard = class {
4740
4878
  const head = document.createElement("div");
4741
4879
  head.className = "tool-call-head";
4742
4880
  head.setAttribute("part", "tool-card-head");
4881
+ const icon = document.createElement("span");
4882
+ icon.className = "tool-call-icon";
4883
+ icon.setAttribute("part", "tool-card-icon");
4884
+ icon.setAttribute("aria-hidden", "true");
4743
4885
  const label = document.createElement("span");
4744
4886
  label.className = "tool-call-name";
4745
4887
  label.setAttribute("part", "tool-card-name");
4746
- label.textContent = `\u{1F527} ${summary ?? name}`;
4888
+ label.textContent = summary ?? name;
4747
4889
  this.#status = document.createElement("span");
4748
4890
  this.#status.className = "tool-call-status";
4749
4891
  this.#status.setAttribute("part", "tool-card-status");
4750
4892
  this.#status.textContent = statusLabels(strings)[TOOL_CALL_STATUS.PENDING];
4751
- head.append(label, this.#status);
4893
+ head.append(icon, label, this.#status);
4752
4894
  this.element.append(head);
4753
4895
  if (mode === TOOL_DISPLAY.FULL) {
4754
4896
  const argsEl = document.createElement("pre");
@@ -4764,8 +4906,8 @@ var ToolCallCard = class {
4764
4906
  }
4765
4907
  /**
4766
4908
  * Flip the status pill to ``status`` and, unless in `minimal` mode, append a
4767
- * collapsed body behind a click-to-expand toggle: the result alone (`full`),
4768
- * or the args + result together (`compact`).
4909
+ * collapsed body behind a click-to-expand toggle: the result alone (`full` /
4910
+ * `inline`), or the args + result together (`compact`).
4769
4911
  */
4770
4912
  settle(status, text2) {
4771
4913
  this.#settled = true;
@@ -5481,6 +5623,13 @@ var AgUiChat = class extends HTMLElement {
5481
5623
  // it; ≤1 ⇒ it arrived at once and the word reveal is appropriate.
5482
5624
  #streamDeltas = 0;
5483
5625
  #pending = null;
5626
+ // The current assistant turn's grouping container (WELL-1). One `.answer`
5627
+ // wraps everything a single answer produces — streamed text, tool cards, the
5628
+ // pending indicator — so it can be boxed as one "well" by CSS. Opened on the
5629
+ // turn's first run start, closed at settle, so it spans the whole multi-round
5630
+ // frontend-tool loop (which is several AG-UI runs), not one run. `null`
5631
+ // between turns; user bubbles never enter it.
5632
+ #currentGroup = null;
5484
5633
  #threadId = "";
5485
5634
  #initialMessages = [];
5486
5635
  // Skill catalog by source; merged backend → embed → client (later wins).
@@ -5614,7 +5763,7 @@ var AgUiChat = class extends HTMLElement {
5614
5763
  */
5615
5764
  get toolDisplay() {
5616
5765
  const attr = this.getAttribute("data-tool-display");
5617
- if (attr === TOOL_DISPLAY.MINIMAL || attr === TOOL_DISPLAY.COMPACT) {
5766
+ if (attr === TOOL_DISPLAY.INLINE || attr === TOOL_DISPLAY.MINIMAL || attr === TOOL_DISPLAY.COMPACT) {
5618
5767
  return attr;
5619
5768
  }
5620
5769
  return TOOL_DISPLAY.FULL;
@@ -5881,6 +6030,7 @@ Use the read_attachment tool with an id to read a file's contents.`
5881
6030
  #resetState() {
5882
6031
  this.#client = null;
5883
6032
  this.#streamingBubble = null;
6033
+ this.#currentGroup = null;
5884
6034
  this.#hidePending();
5885
6035
  this.#toolCards.clear();
5886
6036
  this.#serverSettled.clear();
@@ -6012,6 +6162,10 @@ Use the read_attachment tool with an id to read a file's contents.`
6012
6162
  * Assistant content is rendered as sanitised markdown/HTML; user content
6013
6163
  * stays literal text (no need to parse what the user typed, and it avoids
6014
6164
  * rendering user-authored markup).
6165
+ *
6166
+ * Assistant bubbles land in the current answer group (WELL-1), opening one if
6167
+ * needed; a user bubble closes the prior group and sits directly in the list
6168
+ * (the well wraps the *assistant* turn, the user message precedes it).
6015
6169
  */
6016
6170
  appendMessage(role, content) {
6017
6171
  const bubble = document.createElement("div");
@@ -6019,14 +6173,34 @@ Use the read_attachment tool with an id to read a file's contents.`
6019
6173
  bubble.setAttribute("part", `message message-${role}`);
6020
6174
  if (role === MESSAGE_ROLE.ASSISTANT) {
6021
6175
  bubble.innerHTML = renderMarkdown(content, { allowImages: this.allowImages });
6176
+ this.#ensureGroup().appendChild(bubble);
6022
6177
  } else {
6178
+ this.#currentGroup = null;
6023
6179
  bubble.textContent = content;
6180
+ this.#messages.appendChild(bubble);
6024
6181
  }
6025
- this.#messages.appendChild(bubble);
6026
6182
  this.#updateEmptyState();
6027
6183
  this.#messages.scrollTop = this.#messages.scrollHeight;
6028
6184
  return bubble;
6029
6185
  }
6186
+ /**
6187
+ * The open answer group, creating and appending it on first use. Everything a
6188
+ * single assistant turn renders (text, tool cards, the pending indicator)
6189
+ * goes inside it, so the opt-in `data-answer-well` styling can box the whole
6190
+ * turn. Idempotent across the turn's runs — it persists until {@link #handlers}'
6191
+ * `onSettled` nulls it.
6192
+ */
6193
+ #ensureGroup() {
6194
+ if (this.#currentGroup === null) {
6195
+ const group = document.createElement("div");
6196
+ group.className = "answer";
6197
+ group.setAttribute("part", "answer");
6198
+ this.#currentGroup = group;
6199
+ this.#messages.appendChild(group);
6200
+ this.#updateEmptyState();
6201
+ }
6202
+ return this.#currentGroup;
6203
+ }
6030
6204
  #render() {
6031
6205
  const style = document.createElement("style");
6032
6206
  style.textContent = STYLES;
@@ -6332,6 +6506,7 @@ Use the read_attachment tool with an id to read a file's contents.`
6332
6506
  return {
6333
6507
  onRunStart: () => {
6334
6508
  this.#setRunning(true);
6509
+ this.#ensureGroup();
6335
6510
  this.#showPending();
6336
6511
  },
6337
6512
  onTextDelta: (buffer) => {
@@ -6382,6 +6557,11 @@ Use the read_attachment tool with an id to read a file's contents.`
6382
6557
  card.settle(TOOL_CALL_STATUS.DONE, this.#strings.noResult);
6383
6558
  }
6384
6559
  }
6560
+ if (this.#currentGroup !== null && this.#currentGroup.childElementCount === 0) {
6561
+ this.#currentGroup.remove();
6562
+ this.#updateEmptyState();
6563
+ }
6564
+ this.#currentGroup = null;
6385
6565
  }
6386
6566
  };
6387
6567
  }
@@ -6392,7 +6572,7 @@ Use the read_attachment tool with an id to read a file's contents.`
6392
6572
  note.setAttribute("part", "stopped");
6393
6573
  note.setAttribute("role", "status");
6394
6574
  note.textContent = this.#strings.stopped;
6395
- this.#messages.appendChild(note);
6575
+ this.#ensureGroup().appendChild(note);
6396
6576
  this.#updateEmptyState();
6397
6577
  this.#messages.scrollTop = this.#messages.scrollHeight;
6398
6578
  }
@@ -6416,7 +6596,7 @@ Use the read_attachment tool with an id to read a file's contents.`
6416
6596
  pending.appendChild(dot);
6417
6597
  }
6418
6598
  this.#pending = pending;
6419
- this.#messages.appendChild(pending);
6599
+ this.#ensureGroup().appendChild(pending);
6420
6600
  this.#updateEmptyState();
6421
6601
  this.#messages.scrollTop = this.#messages.scrollHeight;
6422
6602
  }
@@ -6449,7 +6629,7 @@ Use the read_attachment tool with an id to read a file's contents.`
6449
6629
  const summary = typeof labelled === "string" ? labelled : this.toolSummaries[call.name] ?? this.#toolCatalog[call.name] ?? prettifyToolName(call.name);
6450
6630
  const card = new ToolCallCard(call.name, call.args, this.toolDisplay, summary, this.#strings);
6451
6631
  this.#toolCards.set(call.id, card);
6452
- this.#messages.appendChild(card.element);
6632
+ this.#ensureGroup().appendChild(card.element);
6453
6633
  this.#updateEmptyState();
6454
6634
  this.#messages.scrollTop = this.#messages.scrollHeight;
6455
6635
  return card;
@@ -6496,7 +6676,7 @@ function setControlValue(el, value) {
6496
6676
  }
6497
6677
 
6498
6678
  // src/version.ts
6499
- var VERSION = "0.7.0";
6679
+ var VERSION = "0.8.1";
6500
6680
  export {
6501
6681
  AgUiChat,
6502
6682
  AgUiClient,