@ai-ecoverse/slicc-spectrum 1.73.1 → 1.74.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/slicc-ui.js CHANGED
@@ -10646,7 +10646,7 @@ function watchTitles(model, update) {
10646
10646
  const seen = /* @__PURE__ */ new Map();
10647
10647
  const check3 = (id) => {
10648
10648
  const agent = model.agent.list().find((candidate) => candidate.id === id);
10649
- if (agent?.kind !== "cone") return;
10649
+ if (!agent) return;
10650
10650
  const title = agentTitle(model, agent);
10651
10651
  if (seen.get(id) === title) return;
10652
10652
  seen.set(id, title);
@@ -11406,11 +11406,25 @@ async function createCone(model, trigger2) {
11406
11406
  if (created) port.select(created.id);
11407
11407
  return created;
11408
11408
  }
11409
+ var statusOrder = ["working", "thinking", "waiting", "error", "idle"];
11410
+ function scoopSummary(scoops) {
11411
+ if (scoops.length === 0) return "";
11412
+ const counts = statusOrder.map((status2) => [status2, scoops.filter((scoop) => scoop.status === status2).length]).filter(([, count]) => count > 0).map(([status2, count]) => `${count} ${statusLabel[status2].toLowerCase()}`);
11413
+ return `${scoops.length} scoop${scoops.length === 1 ? "" : "s"}: ${counts.join(", ")}`;
11414
+ }
11415
+ function unreadCount(unread) {
11416
+ return unread > 9 ? "9+" : String(unread);
11417
+ }
11409
11418
  function fillShown(fill2) {
11410
11419
  return fill2 >= 0.5;
11411
11420
  }
11412
11421
  var SliccAgents = class extends ModelElement {
11413
11422
  static properties = { ...ModelElement.properties, errors: { state: true } };
11423
+ #expanded = null;
11424
+ #pointer = false;
11425
+ #modality = (event2) => {
11426
+ this.#pointer = event2.type === "pointerdown";
11427
+ };
11414
11428
  constructor() {
11415
11429
  super();
11416
11430
  this.errors = {};
@@ -11419,16 +11433,22 @@ var SliccAgents = class extends ModelElement {
11419
11433
  shared,
11420
11434
  i`
11421
11435
  :host {
11422
- display: block;
11436
+ display: flex;
11437
+ flex-direction: column;
11423
11438
  height: 100%;
11424
- overflow-y: auto;
11439
+ overflow: hidden;
11425
11440
  background: var(--swc-background-layer-1-color);
11426
11441
  color: var(--swc-neutral-content-color-default);
11427
11442
  font-size: var(--swc-font-size-100);
11428
11443
  }
11444
+ .list {
11445
+ flex: 1;
11446
+ min-block-size: 0;
11447
+ overflow-y: auto;
11448
+ }
11429
11449
  .actions {
11430
11450
  display: flex;
11431
- padding: var(--swc-spacing-75) var(--swc-spacing-100) 0;
11451
+ padding: var(--swc-spacing-75) var(--swc-spacing-100);
11432
11452
  }
11433
11453
  ul {
11434
11454
  list-style: none;
@@ -11436,31 +11456,67 @@ var SliccAgents = class extends ModelElement {
11436
11456
  padding: var(--swc-spacing-75) 0;
11437
11457
  }
11438
11458
  li {
11459
+ --row-background: var(--swc-background-layer-1-color);
11460
+ --row-head: 1lh;
11461
+ --row-description: calc(2 * 1.4 * var(--swc-font-size-75));
11462
+ position: relative;
11439
11463
  display: grid;
11440
- grid-template-columns: minmax(0, 1fr) auto auto auto;
11441
- grid-template-areas: 'name unread fill drop' 'title unread fill drop' 'status unread fill drop' 'error error error error';
11464
+ grid-template-columns: minmax(0, 1fr) auto;
11465
+ grid-template-areas: 'head fill' 'description description' 'ribbon ribbon' 'error error';
11466
+ grid-template-rows: var(--row-head) var(--row-description) var(--swc-spacing-100);
11442
11467
  align-items: center;
11443
11468
  column-gap: var(--swc-spacing-100);
11444
11469
  padding: var(--swc-spacing-75) var(--swc-spacing-200);
11470
+ background: var(--row-background);
11445
11471
  cursor: pointer;
11446
11472
  }
11447
11473
  li.scoop {
11448
- grid-template-areas: 'name unread fill drop' 'status unread fill drop' 'error error error error';
11449
11474
  padding-inline-start: calc(var(--swc-spacing-200) + var(--swc-spacing-300));
11450
11475
  }
11451
11476
  li:hover {
11452
- background: var(--swc-gray-100);
11477
+ --row-background: var(--swc-gray-100);
11453
11478
  }
11454
11479
  li[aria-selected='true'] {
11455
- background: var(--swc-gray-200);
11456
- box-shadow: inset var(--swc-spacing-50) 0 0 var(--swc-accent-visual-color);
11480
+ --row-background: var(--swc-gray-200);
11457
11481
  }
11458
11482
  li:focus-visible {
11459
11483
  outline: var(--swc-focus-indicator-thickness) solid var(--swc-focus-indicator-color);
11460
11484
  outline-offset: calc(-1 * var(--swc-focus-indicator-thickness));
11461
11485
  }
11486
+ .head {
11487
+ grid-area: head;
11488
+ display: flex;
11489
+ align-items: center;
11490
+ gap: var(--swc-spacing-75);
11491
+ min-inline-size: 0;
11492
+ }
11493
+ .head > * {
11494
+ flex: none;
11495
+ }
11496
+ .marker {
11497
+ flex: none;
11498
+ display: inline-flex;
11499
+ align-items: center;
11500
+ justify-content: center;
11501
+ inline-size: var(--swc-spacing-200);
11502
+ block-size: var(--swc-spacing-200);
11503
+ border-radius: var(--swc-corner-radius-full);
11504
+ font-size: var(--swc-font-size-25);
11505
+ font-variant-numeric: tabular-nums;
11506
+ line-height: 1;
11507
+ }
11508
+ .marker.unread {
11509
+ box-sizing: border-box;
11510
+ inline-size: auto;
11511
+ min-inline-size: var(--swc-spacing-200);
11512
+ padding-inline: var(--swc-spacing-50);
11513
+ background: var(--swc-accent-background-color-default);
11514
+ color: var(--swc-white);
11515
+ font-weight: var(--swc-bold-font-weight);
11516
+ }
11462
11517
  .name {
11463
- grid-area: name;
11518
+ flex: 0 1 auto;
11519
+ min-inline-size: 0;
11464
11520
  overflow: hidden;
11465
11521
  text-overflow: ellipsis;
11466
11522
  white-space: nowrap;
@@ -11469,29 +11525,58 @@ var SliccAgents = class extends ModelElement {
11469
11525
  font-weight: var(--swc-bold-font-weight);
11470
11526
  }
11471
11527
  .title {
11472
- grid-area: title;
11528
+ grid-area: description;
11529
+ display: -webkit-box;
11530
+ -webkit-box-orient: vertical;
11531
+ -webkit-line-clamp: 2;
11473
11532
  overflow: hidden;
11474
- text-overflow: ellipsis;
11475
- white-space: nowrap;
11533
+ overflow-wrap: anywhere;
11534
+ line-height: 1.4;
11476
11535
  font-size: var(--swc-font-size-75);
11477
11536
  color: var(--swc-neutral-subdued-content-color-default);
11478
11537
  }
11479
- .unread {
11480
- --swc-badge-height: var(--swc-spacing-300);
11481
- --swc-badge-padding-block: var(--swc-spacing-50);
11482
- --swc-badge-padding-inline: var(--swc-spacing-75);
11483
- --swc-badge-corner-radius: var(--swc-spacing-100);
11484
- --swc-badge-line-height: 1;
11485
- grid-area: unread;
11486
- align-self: center;
11538
+ .state {
11539
+ color: var(--swc-neutral-content-color-default);
11540
+ }
11541
+ .ribbon {
11542
+ grid-area: ribbon;
11543
+ display: flex;
11544
+ align-items: center;
11545
+ gap: var(--swc-spacing-50);
11546
+ overflow: hidden;
11547
+ }
11548
+ .status,
11549
+ .segment {
11550
+ background: var(--swc-neutral-visual-color);
11551
+ }
11552
+ .status[data-status='thinking'],
11553
+ .status[data-status='working'],
11554
+ .segment[data-status='thinking'],
11555
+ .segment[data-status='working'] {
11556
+ background: var(--swc-informative-visual-color);
11557
+ }
11558
+ .status[data-status='waiting'],
11559
+ .segment[data-status='waiting'] {
11560
+ background: var(--swc-notice-visual-color);
11561
+ }
11562
+ .status[data-status='error'],
11563
+ .segment[data-status='error'] {
11564
+ background: var(--swc-negative-visual-color);
11565
+ }
11566
+ .segment {
11567
+ flex: none;
11568
+ inline-size: var(--swc-spacing-200);
11569
+ block-size: var(--swc-spacing-50);
11570
+ border-radius: var(--swc-corner-radius-full);
11487
11571
  }
11488
11572
  .fill {
11489
11573
  grid-area: fill;
11574
+ position: relative;
11575
+ z-index: 1;
11576
+ align-self: start;
11490
11577
  font-size: var(--swc-font-size-75);
11491
11578
  font-variant-numeric: tabular-nums;
11492
11579
  color: var(--swc-neutral-subdued-content-color-default);
11493
- min-width: 4ch;
11494
- text-align: end;
11495
11580
  }
11496
11581
  .fill[data-variant='notice'] {
11497
11582
  color: var(--swc-notice-color-1000);
@@ -11501,18 +11586,20 @@ var SliccAgents = class extends ModelElement {
11501
11586
  color: var(--swc-negative-color-1000);
11502
11587
  font-weight: var(--swc-bold-font-weight);
11503
11588
  }
11504
- swc-status-light {
11505
- grid-area: status;
11506
- justify-self: start;
11507
- }
11508
- .drop {
11509
- grid-area: drop;
11510
- margin-block: calc(-1 * var(--swc-spacing-100));
11511
- visibility: hidden;
11589
+ .drop-cell {
11590
+ position: absolute;
11591
+ inset-block: 0;
11592
+ inset-inline-end: 0;
11593
+ display: flex;
11594
+ align-items: center;
11595
+ padding-inline: var(--swc-spacing-100);
11596
+ background: var(--row-background);
11597
+ opacity: 0;
11512
11598
  }
11513
- li:hover .drop,
11514
- li:focus-within .drop {
11515
- visibility: visible;
11599
+ li:hover .drop-cell,
11600
+ li:focus-visible .drop-cell,
11601
+ .drop-cell[data-shown] {
11602
+ opacity: 1;
11516
11603
  }
11517
11604
  .error {
11518
11605
  grid-area: error;
@@ -11529,23 +11616,46 @@ var SliccAgents = class extends ModelElement {
11529
11616
  white-space: nowrap;
11530
11617
  }
11531
11618
  @media (hover: none), (pointer: coarse) {
11532
- .drop {
11533
- visibility: visible;
11619
+ .drop-cell {
11620
+ opacity: 1;
11534
11621
  }
11535
11622
  }
11536
11623
  `
11537
11624
  ];
11538
11625
  subscribe(model) {
11626
+ const focused2 = this.#focused(model);
11627
+ this.#expanded = focused2?.kind === "scoop" ? focused2.parentId : null;
11539
11628
  return [
11540
11629
  model.agent.on("agents", () => this.requestUpdate()),
11541
- model.agent.on("active", () => this.requestUpdate()),
11630
+ model.agent.on("active", () => {
11631
+ const next = this.#focused(model);
11632
+ if (next) this.#expanded = next.kind === "cone" ? next.id : next.parentId;
11633
+ this.requestUpdate();
11634
+ }),
11542
11635
  watchTitles(model, () => this.requestUpdate()),
11543
- ...model.follow ? [model.follow.on("follow", () => this.requestUpdate())] : []
11636
+ ...model.follow ? [model.follow.on("follow", () => this.requestUpdate())] : [],
11637
+ this.#watchPointer()
11544
11638
  ];
11545
11639
  }
11640
+ #watchPointer() {
11641
+ const types = ["pointerdown", "keydown"];
11642
+ for (const type of types) globalThis.addEventListener(type, this.#modality, true);
11643
+ return () => {
11644
+ for (const type of types) globalThis.removeEventListener(type, this.#modality, true);
11645
+ };
11646
+ }
11647
+ #focused(model) {
11648
+ return model.agent.list().find((agent) => agent.id === model.agent.active());
11649
+ }
11546
11650
  #select(id) {
11547
11651
  this.model?.agent.select(id);
11548
11652
  }
11653
+ #pick(agent) {
11654
+ const open = agent.kind === "cone" && this.#expanded !== agent.id;
11655
+ this.#select(agent.id);
11656
+ if (agent.kind === "cone") this.#expanded = open ? agent.id : null;
11657
+ this.requestUpdate();
11658
+ }
11549
11659
  focus() {
11550
11660
  this.focusOn('li[tabindex="0"]');
11551
11661
  }
@@ -11564,21 +11674,44 @@ var SliccAgents = class extends ModelElement {
11564
11674
  if (event2.key in moves) {
11565
11675
  event2.preventDefault();
11566
11676
  items[Math.max(0, Math.min(items.length - 1, moves[event2.key]))]?.focus();
11567
- } else if (event2.key === "Enter" || event2.key === " ") {
11677
+ return;
11678
+ }
11679
+ const agent = this.model?.agent.list().find((item2) => item2.id === items[index]?.dataset.id);
11680
+ if (!agent) return;
11681
+ if (event2.key === "Enter" || event2.key === " ") {
11568
11682
  event2.preventDefault();
11569
- const id = items[index]?.dataset.id;
11570
- if (id) this.#select(id);
11683
+ this.#pick(agent);
11684
+ } else if (event2.key === "ArrowRight" && this.#scoops(agent).length > 0) {
11685
+ event2.preventDefault();
11686
+ if (this.#expanded === agent.id) items[index + 1].focus();
11687
+ else this.#pick(agent);
11688
+ } else if (event2.key === "ArrowLeft" && agent.kind === "scoop") {
11689
+ event2.preventDefault();
11690
+ items.find((item2) => item2.dataset.id === agent.parentId)?.focus();
11691
+ } else if (event2.key === "ArrowLeft" && this.#expanded === agent.id) {
11692
+ event2.preventDefault();
11693
+ this.#pick(agent);
11571
11694
  } else if (event2.key === "Delete") {
11572
- const agent = this.model?.agent.list().find((item2) => item2.id === items[index]?.dataset.id);
11573
- if (agent && this.#droppable(agent)) {
11695
+ if (this.#droppable(agent)) {
11574
11696
  event2.preventDefault();
11575
11697
  void this.#drop(agent, items[index]);
11576
- } else if (agent && this.#deletable(agent)) {
11698
+ } else if (this.#deletable(agent)) {
11577
11699
  event2.preventDefault();
11578
11700
  void this.#deleteCone(agent, items[index]);
11579
11701
  }
11580
11702
  }
11581
11703
  }
11704
+ #scoops(agent) {
11705
+ if (agent.kind !== "cone") return [];
11706
+ return this.model.agent.list().filter((other) => other.parentId === agent.id);
11707
+ }
11708
+ #focusin(event2) {
11709
+ const cell = event2.target.closest(".drop-cell");
11710
+ cell?.toggleAttribute("data-shown", !this.#pointer);
11711
+ }
11712
+ #focusout(event2) {
11713
+ event2.target.closest(".drop-cell")?.removeAttribute("data-shown");
11714
+ }
11582
11715
  #droppable(agent) {
11583
11716
  return agent.kind === "scoop" && Boolean(this.model?.agent.drop) && !watchOnly(this.model);
11584
11717
  }
@@ -11616,69 +11749,89 @@ var SliccAgents = class extends ModelElement {
11616
11749
  await this.updateComplete;
11617
11750
  this.focus();
11618
11751
  }
11619
- #dropButton(agent) {
11752
+ #dropButton(agent, selected) {
11620
11753
  if (!this.#droppable(agent)) return A;
11621
11754
  const id = `drop-${agent.id}`;
11622
11755
  const label = `Drop scoop ${agent.name}`;
11623
- return b`<swc-action-button
11624
- id=${id}
11625
- class="drop"
11626
- size="l"
11627
- quiet
11628
- tabindex="-1"
11629
- data-action="drop"
11630
- accessible-label=${label}
11631
- @click=${(event2) => {
11756
+ return b`<span class="drop-cell"
11757
+ ><swc-action-button
11758
+ id=${id}
11759
+ class="drop"
11760
+ size="l"
11761
+ quiet
11762
+ tabindex=${selected ? "0" : "-1"}
11763
+ data-action="drop"
11764
+ accessible-label=${label}
11765
+ @click=${(event2) => {
11632
11766
  event2.stopPropagation();
11633
11767
  void this.#drop(agent, event2.currentTarget);
11634
11768
  }}
11635
- ><swc-icon-close slot="icon"></swc-icon-close></swc-action-button
11636
- ><swc-tooltip for=${id} placement="start">${label}</swc-tooltip>`;
11769
+ ><swc-icon-close slot="icon"></swc-icon-close></swc-action-button
11770
+ ><swc-tooltip for=${id} placement="start">${label}</swc-tooltip></span
11771
+ >`;
11637
11772
  }
11638
- #deleteButton(agent) {
11773
+ #deleteButton(agent, selected) {
11639
11774
  if (!this.#deletable(agent)) return A;
11640
11775
  const id = `delete-${agent.id}`;
11641
11776
  const label = `Delete cone ${coneLabel(this.model, agent)}`;
11642
- return b`<swc-action-button
11643
- id=${id}
11644
- class="drop"
11645
- size="l"
11646
- quiet
11647
- tabindex="-1"
11648
- data-action="delete-cone"
11649
- accessible-label=${label}
11650
- @click=${(event2) => {
11777
+ return b`<span class="drop-cell"
11778
+ ><swc-action-button
11779
+ id=${id}
11780
+ class="drop"
11781
+ size="l"
11782
+ quiet
11783
+ tabindex=${selected ? "0" : "-1"}
11784
+ data-action="delete-cone"
11785
+ accessible-label=${label}
11786
+ @click=${(event2) => {
11651
11787
  event2.stopPropagation();
11652
11788
  void this.#deleteCone(agent, event2.currentTarget);
11653
11789
  }}
11654
- ><swc-icon-delete slot="icon"></swc-icon-delete></swc-action-button
11655
- ><swc-tooltip for=${id} placement="start">${label}</swc-tooltip>`;
11790
+ ><swc-icon-delete slot="icon"></swc-icon-delete></swc-action-button
11791
+ ><swc-tooltip for=${id} placement="start">${label}</swc-tooltip></span
11792
+ >`;
11793
+ }
11794
+ #ribbon(scoops) {
11795
+ if (scoops.length === 0) return A;
11796
+ return b`<span class="ribbon" aria-hidden="true">${scoops.map(
11797
+ (scoop) => b`<span class="segment" data-status=${scoop.status}></span>`
11798
+ )}</span>`;
11656
11799
  }
11657
11800
  #row(agent, active) {
11658
11801
  const selected = agent.id === active;
11659
11802
  const error = this.errors[agent.id];
11660
11803
  const model = this.model;
11661
- const title = agent.kind === "cone" ? agentTitle(model, agent) : null;
11804
+ const title = agentTitle(model, agent);
11805
+ const scoops = this.#scoops(agent);
11806
+ const open = this.#expanded === agent.id;
11662
11807
  const unread = selected ? 0 : agent.unread;
11663
11808
  const label = `${coneLabel(model, agent)}: ${statusLabel[agent.status]}, ${percent(agent.contextFill)} context${unread ? `, ${unread} unread` : ""}${error ? `. ${error}` : ""}`;
11809
+ const summary = scoopSummary(scoops);
11664
11810
  return b`<li
11665
- role="option"
11811
+ role="treeitem"
11812
+ id=${`row-${agent.id}`}
11666
11813
  class=${agent.kind}
11667
11814
  data-id=${agent.id}
11815
+ aria-level=${agent.kind === "cone" ? "1" : "2"}
11668
11816
  aria-selected=${selected ? "true" : "false"}
11817
+ aria-expanded=${scoops.length ? String(open) : A}
11818
+ aria-controls=${open && scoops.length ? scoops.map((scoop) => `row-${scoop.id}`).join(" ") : A}
11669
11819
  aria-label=${label}
11820
+ aria-description=${summary || A}
11670
11821
  tabindex=${selected ? "0" : "-1"}
11671
11822
  aria-keyshortcuts=${this.#droppable(agent) || this.#deletable(agent) ? "Delete" : A}
11672
- title=${label}
11673
- @click=${() => this.#select(agent.id)}
11823
+ title=${summary ? `${label}. ${summary}` : label}
11824
+ @click=${() => this.#pick(agent)}
11674
11825
  >
11675
- <span class="name">${agent.name}</span>
11676
- ${title === null ? A : b`<span class="title">${title || untitled}</span>`}
11677
- ${unread ? b`<swc-badge class="unread" size="s" variant="accent">${unread}</swc-badge>` : A}
11826
+ <div class="head">
11827
+ ${unread ? b`<span class="marker unread" aria-hidden="true">${unreadCount(unread)}</span>` : b`<span class="marker status" data-status=${agent.status} aria-hidden="true"></span>`}
11828
+ <span class="name">${agent.name}</span>
11829
+ </div>
11678
11830
  ${fillShown(agent.contextFill) ? b`<span class="fill" data-variant=${meterVariant2(agent.contextFill)}>${percent(agent.contextFill)}</span>` : A}
11679
- ${statusLight(agent.status)}
11680
- ${this.#dropButton(agent)}
11681
- ${this.#deleteButton(agent)}
11831
+ <span class="title"><span class="state">${statusLabel[agent.status]}</span> · ${title || untitled}</span>
11832
+ ${this.#ribbon(scoops)}
11833
+ ${this.#dropButton(agent, selected)}
11834
+ ${this.#deleteButton(agent, selected)}
11682
11835
  ${error ? b`<span class="error">${error}</span>` : A}
11683
11836
  </li>`;
11684
11837
  }
@@ -11696,12 +11849,15 @@ var SliccAgents = class extends ModelElement {
11696
11849
  </div>`;
11697
11850
  }
11698
11851
  render() {
11699
- const agents = ordered(this.model?.agent.list() ?? []);
11852
+ const list5 = this.model?.agent.list() ?? [];
11700
11853
  const active = this.model?.agent.active() ?? "";
11701
11854
  const errors = Object.values(this.errors);
11702
- return b`${this.#actions()}<ul role="listbox" aria-label="Cones and scoops" @keydown=${this.#keydown}>
11703
- ${agents.map((agent) => this.#row(agent, active))}
11704
- </ul>
11855
+ const rows = ordered(list5).filter(
11856
+ (agent) => agent.kind === "cone" || agent.parentId === this.#expanded
11857
+ );
11858
+ return b`<div class="list"><ul role="tree" aria-label="Cones and scoops" @keydown=${this.#keydown} @focusin=${this.#focusin} @focusout=${this.#focusout}>
11859
+ ${rows.map((agent) => this.#row(agent, active))}
11860
+ </ul></div>${this.#actions()}
11705
11861
  <div class="sr" role="status">${errors.at(-1) ?? ""}</div>`;
11706
11862
  }
11707
11863
  };
@@ -30847,6 +31003,20 @@ function user(message, stamp = true) {
30847
31003
  </div>
30848
31004
  </swc-conversation-turn>`;
30849
31005
  }
31006
+ var toolLoaders = {
31007
+ edit: "pencil",
31008
+ read: "page",
31009
+ search: "mag",
31010
+ browser: "eye"
31011
+ };
31012
+ function statusLoader(message) {
31013
+ if (message.parts.at(-1)?.type !== "tool") return "aiLogo";
31014
+ const running2 = message.parts.findLast(
31015
+ (part2) => part2.type === "tool" && part2.tool.status === "running"
31016
+ );
31017
+ if (running2?.type !== "tool") return "aiLogo";
31018
+ return toolLoaders[toolKind(running2.tool.name).id] ?? "hourglass";
31019
+ }
30850
31020
  var people = /* @__PURE__ */ new Set(["follower", "guest"]);
30851
31021
  function byline(message, who2, stamp) {
30852
31022
  if (!who2 && !stamp) return A;
@@ -30861,7 +31031,7 @@ function status(message) {
30861
31031
  }
30862
31032
  if (message.status !== "streaming") return A;
30863
31033
  const calls = message.parts.flatMap((entry) => entry.type === "tool" ? [entry.tool] : []);
30864
- return b`<swc-response-status slot="status" status="active">
31034
+ return b`<swc-response-status slot="status" status="active" loader=${statusLoader(message)}>
30865
31035
  ${calls.map((call) => b`<swc-response-status-step status=${stepStates[call.status]}><span slot="label">${call.name} ${call.title}</span></swc-response-status-step>`)}
30866
31036
  </swc-response-status>`;
30867
31037
  }
@@ -36087,7 +36257,8 @@ var SliccChat = class extends ThemedElement {
36087
36257
  min-height: 0;
36088
36258
  overflow-y: auto;
36089
36259
  container-type: inline-size;
36090
- padding: var(--swc-spacing-400) var(--swc-spacing-300) var(--swc-spacing-500);
36260
+ padding: var(--swc-spacing-400) var(--swc-spacing-300) calc(var(--composer-height, 0px) + var(--swc-spacing-500));
36261
+ scroll-padding-block-end: calc(var(--composer-height, 0px) + var(--swc-spacing-200));
36091
36262
  font-size: var(--swc-font-size-200);
36092
36263
  }
36093
36264
  @container (min-width: 600px) {
@@ -36200,6 +36371,11 @@ var SliccChat = class extends ThemedElement {
36200
36371
  return last?.role === "user" && last.id !== this.#tail && (last.origin ?? "user") === "user";
36201
36372
  }
36202
36373
  #resize = new ResizeObserver(() => this.#pin());
36374
+ #fitted = null;
36375
+ #fit = new ResizeObserver(([entry]) => {
36376
+ this.style.setProperty("--composer-height", `${entry.target.offsetHeight}px`);
36377
+ this.#pin();
36378
+ });
36203
36379
  #log() {
36204
36380
  return this.renderRoot.querySelector(".log");
36205
36381
  }
@@ -36254,8 +36430,20 @@ var SliccChat = class extends ThemedElement {
36254
36430
  const log = this.#log();
36255
36431
  this.#resize.observe(log);
36256
36432
  this.#resize.observe(log.firstElementChild);
36433
+ this.#attach();
36257
36434
  this.#refresh(true);
36258
36435
  }
36436
+ #attach() {
36437
+ const composer = this.renderRoot.querySelector("slicc-composer");
36438
+ if (composer === this.#fitted) return;
36439
+ this.#fit.disconnect();
36440
+ this.#fitted = composer;
36441
+ if (composer) this.#fit.observe(composer);
36442
+ else this.style.setProperty("--composer-height", "0px");
36443
+ }
36444
+ updated() {
36445
+ this.#attach();
36446
+ }
36259
36447
  connectedCallback() {
36260
36448
  super.connectedCallback();
36261
36449
  globalThis.addEventListener("pointerup", this.#release, true);
@@ -36267,6 +36455,8 @@ var SliccChat = class extends ThemedElement {
36267
36455
  globalThis.removeEventListener("pointerup", this.#release, true);
36268
36456
  globalThis.removeEventListener("pointercancel", this.#release, true);
36269
36457
  this.#resize.disconnect();
36458
+ this.#fit.disconnect();
36459
+ this.#fitted = null;
36270
36460
  clearTimeout(this.#settle);
36271
36461
  }
36272
36462
  firstUpdated() {
@@ -37720,6 +37910,7 @@ var SliccComposer = class extends ThemedElement {
37720
37910
  attachments: { state: true },
37721
37911
  popup: { state: true },
37722
37912
  dictating: { state: true },
37913
+ erasing: { state: true },
37723
37914
  blocked: { state: true },
37724
37915
  sharing: { state: true },
37725
37916
  secretError: { state: true },
@@ -37733,6 +37924,7 @@ var SliccComposer = class extends ThemedElement {
37733
37924
  #next = 1;
37734
37925
  #abandon;
37735
37926
  #recognition = null;
37927
+ #erase;
37736
37928
  #keys = { capture: true, handleEvent: (event2) => this.#keydown(event2) };
37737
37929
  constructor() {
37738
37930
  super();
@@ -37740,6 +37932,7 @@ var SliccComposer = class extends ThemedElement {
37740
37932
  this.attachments = [];
37741
37933
  this.popup = null;
37742
37934
  this.dictating = false;
37935
+ this.erasing = false;
37743
37936
  this.blocked = false;
37744
37937
  this.sharing = false;
37745
37938
  this.secretError = null;
@@ -37751,11 +37944,49 @@ var SliccComposer = class extends ThemedElement {
37751
37944
  i`
37752
37945
  :host {
37753
37946
  display: block;
37754
- flex: none;
37947
+ position: absolute;
37948
+ left: 0;
37949
+ right: 0;
37950
+ bottom: 0;
37951
+ z-index: 2;
37755
37952
  padding: var(--swc-spacing-100) var(--swc-spacing-200) var(--swc-spacing-200);
37756
- background: var(--swc-background-layer-1-color);
37757
37953
  font-size: var(--swc-font-size-100);
37758
- position: relative;
37954
+ }
37955
+ :host::before {
37956
+ content: '';
37957
+ position: absolute;
37958
+ top: -72px;
37959
+ left: 0;
37960
+ right: 0;
37961
+ bottom: 0;
37962
+ z-index: -1;
37963
+ pointer-events: none;
37964
+ background: color-mix(in srgb, var(--swc-background-layer-1-color) 72%, transparent);
37965
+ backdrop-filter: blur(16px) saturate(1.4);
37966
+ -webkit-backdrop-filter: blur(16px) saturate(1.4);
37967
+ mask-image: linear-gradient(to bottom, transparent, black 72px);
37968
+ -webkit-mask-image: linear-gradient(to bottom, transparent, black 72px);
37969
+ }
37970
+ @media (prefers-reduced-transparency: reduce) {
37971
+ :host::before {
37972
+ top: 0;
37973
+ background: var(--swc-background-layer-1-color);
37974
+ backdrop-filter: none;
37975
+ -webkit-backdrop-filter: none;
37976
+ mask-image: none;
37977
+ -webkit-mask-image: none;
37978
+ }
37979
+ }
37980
+ @media (forced-colors: active) {
37981
+ :host::before {
37982
+ top: 0;
37983
+ background: Canvas;
37984
+ backdrop-filter: none;
37985
+ -webkit-backdrop-filter: none;
37986
+ mask-image: none;
37987
+ -webkit-mask-image: none;
37988
+ border-block-start: var(--swc-border-width-100) solid CanvasText;
37989
+ }
37759
37990
  }
37760
37991
  .column {
37761
37992
  max-width: 860px;
@@ -37863,28 +38094,6 @@ var SliccComposer = class extends ThemedElement {
37863
38094
  margin: var(--swc-spacing-75) auto 0;
37864
38095
  min-height: var(--swc-component-height-75);
37865
38096
  }
37866
- .hint {
37867
- display: flex;
37868
- flex: 1;
37869
- flex-wrap: wrap;
37870
- align-items: center;
37871
- min-width: 0;
37872
- max-block-size: var(--swc-component-height-75);
37873
- overflow: hidden;
37874
- font-size: var(--swc-font-size-75);
37875
- color: var(--swc-neutral-subdued-content-color-default);
37876
- }
37877
- .hint > span {
37878
- display: flex;
37879
- align-items: center;
37880
- block-size: var(--swc-component-height-75);
37881
- gap: var(--swc-spacing-50);
37882
- white-space: nowrap;
37883
- }
37884
- .hint > span + span::before {
37885
- content: '·';
37886
- padding-inline-start: var(--swc-spacing-75);
37887
- }
37888
38097
  .below swc-action-button {
37889
38098
  margin-inline-start: auto;
37890
38099
  }
@@ -37898,11 +38107,6 @@ var SliccComposer = class extends ThemedElement {
37898
38107
  --swc-action-button-content-color-down: var(--swc-gray-25);
37899
38108
  --swc-action-button-content-color-focus: var(--swc-gray-25);
37900
38109
  }
37901
- @media (pointer: coarse), (hover: none) {
37902
- .hint {
37903
- display: none;
37904
- }
37905
- }
37906
38110
  .popup {
37907
38111
  position: absolute;
37908
38112
  left: 0;
@@ -38037,6 +38241,8 @@ var SliccComposer = class extends ThemedElement {
38037
38241
  popover.triggerElement = field.shadowRoot.querySelector(
38038
38242
  ".swc-PromptField-upload"
38039
38243
  );
38244
+ const area = this.#textarea;
38245
+ area.ariaDescribedByElements = [this.renderRoot.querySelector("#keys")];
38040
38246
  });
38041
38247
  }
38042
38248
  subscribe(model) {
@@ -38361,6 +38567,7 @@ var SliccComposer = class extends ThemedElement {
38361
38567
  #keydown(event2) {
38362
38568
  const area = this.#textarea;
38363
38569
  if (event2.isComposing || !area || event2.composedPath()[0] !== area) return;
38570
+ if (event2.key === "Backspace" || event2.key === "Delete") this.#flash();
38364
38571
  const sendOnEnter = this.model?.settings.get().sendOnEnter ?? true;
38365
38572
  let handled = this.#popupKey(event2) || this.#historyKey(event2, area);
38366
38573
  if (!handled && event2.key === "Tab" && !event2.shiftKey && !this.value) {
@@ -38381,6 +38588,29 @@ var SliccComposer = class extends ThemedElement {
38381
38588
  if (handled) event2.preventDefault();
38382
38589
  if (handled || event2.key === "Enter") event2.stopPropagation();
38383
38590
  }
38591
+ #flash() {
38592
+ if (!this.value) return;
38593
+ this.erasing = true;
38594
+ clearTimeout(this.#erase);
38595
+ this.#erase = setTimeout(() => this.erasing = false, 700);
38596
+ }
38597
+ #loader(busy) {
38598
+ if (busy) return "aiLogo";
38599
+ if (this.dictating) return "microphone";
38600
+ if (this.erasing) return "brush";
38601
+ return this.value ? "pencil" : "aiLogo";
38602
+ }
38603
+ #instructions(busy) {
38604
+ const enter = this.model?.settings.get().sendOnEnter ?? true;
38605
+ const keys = enter ? [`Enter ${busy ? "steers" : "sends"}`, ...busy ? ["Ctrl+Enter queues"] : []] : [`Ctrl+Enter ${busy ? "queues" : "sends"}`];
38606
+ if (busy) keys.push("Escape stops");
38607
+ keys.push(
38608
+ `${enter ? "Shift+Enter" : "Enter"} adds a new line`,
38609
+ "/ lists commands",
38610
+ "@ mentions"
38611
+ );
38612
+ return `${keys.join(", ")}.`;
38613
+ }
38384
38614
  #input(event2) {
38385
38615
  this.value = event2.detail.value;
38386
38616
  this.#history = -1;
@@ -38570,16 +38800,17 @@ var SliccComposer = class extends ThemedElement {
38570
38800
  const speech = "SpeechRecognition" in globalThis || "webkitSpeechRecognition" in globalThis;
38571
38801
  const held = this.#held();
38572
38802
  return b`<div class="column">
38803
+ <span id="keys" class="sr" aria-hidden="true">${this.#instructions(busy)}</span>
38573
38804
  ${this.#hold()}
38574
38805
  ${this.#queue()}
38575
38806
  ${this.#popup()}
38576
38807
  <swc-prompt-field
38577
38808
  label="Message"
38809
+ loader=${this.#loader(busy)}
38578
38810
  upload-label="Add"
38579
38811
  stop-label="Stop"
38580
38812
  send-label=${busy ? "Steer" : "Send"}
38581
38813
  max-rows="10"
38582
- animate-loader
38583
38814
  ?generating=${busy && !canSend}
38584
38815
  ?disabled=${!!held}
38585
38816
  placeholder=${held ? `Reconnecting to ${held}\u2026` : suggestion ? `${suggestion} (Tab)` : `Message ${agent?.name ?? ""}`}
@@ -38612,24 +38843,16 @@ var SliccComposer = class extends ThemedElement {
38612
38843
  input.value = "";
38613
38844
  }} />
38614
38845
  </div>
38615
- <div class="below">
38616
- <div class="hint">
38617
- <span><kbd>Enter</kbd> ${busy ? "steer" : "send"}</span>
38618
- ${busy ? b`<span><kbd>Ctrl+Enter</kbd> queue</span><span><kbd>Esc</kbd> stop</span>` : A}
38619
- <span><kbd>/</kbd> commands</span>
38620
- <span><kbd>@</kbd> mention</span>
38621
- <span><kbd>Shift+Enter</kbd> new line</span>
38622
- <span><kbd>↑</kbd> history</span>
38623
- </div>
38624
- ${speech ? b`<swc-action-button
38846
+ ${speech ? b`<div class="below">
38847
+ <swc-action-button
38625
38848
  size="s"
38626
38849
  quiet
38627
38850
  class=${this.dictating ? "selected" : ""}
38628
38851
  accessible-label=${this.dictating ? "Stop dictation" : "Dictate"}
38629
38852
  data-action="dictate"
38630
38853
  @click=${() => this.dictate()}
38631
- ><swc-icon-microphone slot="icon"></swc-icon-microphone></swc-action-button>` : A}
38632
- </div>`;
38854
+ ><swc-icon-microphone slot="icon"></swc-icon-microphone></swc-action-button>
38855
+ </div>` : A}`;
38633
38856
  }
38634
38857
  };
38635
38858
 
@@ -41043,12 +41266,13 @@ var bridge = `(() => {
41043
41266
  }
41044
41267
  node.replaceWith(svg);
41045
41268
  }
41269
+ size();
41046
41270
  };
41047
41271
  const fonts = (list) => {
41048
41272
  for (const font of list) {
41049
41273
  const face = new FontFace(font.family, font.data, { weight: String(font.weight) });
41050
41274
  document.fonts.add(face);
41051
- face.load().catch(() => {});
41275
+ face.load().then(size, () => {});
41052
41276
  }
41053
41277
  };
41054
41278
  addEventListener('message', (event) => {
@@ -41064,6 +41288,7 @@ var bridge = `(() => {
41064
41288
  };
41065
41289
  document.addEventListener('DOMContentLoaded', () => {
41066
41290
  window.LucideIcons.render();
41291
+ size();
41067
41292
  new ResizeObserver(size).observe(document.body);
41068
41293
  });
41069
41294
  post({ type: 'slicc-ready' });