@ai-ecoverse/slicc-spectrum 1.28.0 → 1.29.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
@@ -13930,6 +13930,7 @@ e25("swc-icon-alert-triangle", o51);
13930
13930
  // src/app/updates.ts
13931
13931
  var states = {
13932
13932
  current: ["neutral", "Up to date"],
13933
+ queued: ["neutral", "Waiting"],
13933
13934
  checking: ["info", "Checking"],
13934
13935
  downloading: ["info", "Downloading"],
13935
13936
  linking: ["info", "Linking"],
@@ -13953,8 +13954,8 @@ function hint(port) {
13953
13954
  return "Preparing your agent. You can keep working; this panel closes when the agent is ready.";
13954
13955
  }
13955
13956
  function updatesStatus(items) {
13956
- const failed = items.filter((item2) => item2.state === "failed").length;
13957
- if (failed) return `${failed} failed`;
13957
+ const failed2 = items.filter((item2) => item2.state === "failed").length;
13958
+ if (failed2) return `${failed2} failed`;
13958
13959
  const busy = items.filter((item2) => running.has(item2.state)).length;
13959
13960
  if (busy) return `updating ${busy}`;
13960
13961
  if (items.some((item2) => item2.state === "ready" || item2.state === "available")) {
@@ -13970,13 +13971,13 @@ var UpdateVisibility = class {
13970
13971
  this.#boot = !ready;
13971
13972
  }
13972
13973
  change(port, layout = false) {
13973
- const failed = new Set(
13974
+ const failed2 = new Set(
13974
13975
  port.list().filter((item2) => item2.state === "failed").map((item2) => item2.id)
13975
13976
  );
13976
- const open = (this.#initial || layout) && this.#boot || [...failed].some((id) => !this.#failed.has(id));
13977
+ const open = (this.#initial || layout) && this.#boot || [...failed2].some((id) => !this.#failed.has(id));
13977
13978
  this.#initial = false;
13978
- this.#failed = failed;
13979
- if (this.#boot && port.ready() && failed.size === 0) {
13979
+ this.#failed = failed2;
13980
+ if (this.#boot && port.ready() && failed2.size === 0) {
13980
13981
  this.#boot = false;
13981
13982
  return "close";
13982
13983
  }
@@ -14193,7 +14194,8 @@ var SliccUpdates = class extends ModelElement {
14193
14194
  return b`<span>Checked <time datetime=${date.toISOString()}>${shown}</time></span>`;
14194
14195
  }
14195
14196
  #item(item2) {
14196
- const [variant, label] = states[item2.state];
14197
+ const [variant, state] = states[item2.state];
14198
+ const label = item2.state === "failed" && item2.from !== null ? "Update failed" : state;
14197
14199
  const error = this.failures.get(item2.id) ?? item2.error;
14198
14200
  return b`<swc-divider size="s"></swc-divider>
14199
14201
  <article data-id=${item2.id} data-state=${item2.state} aria-label=${item2.label}>
@@ -14251,6 +14253,30 @@ function updatesVariant(status2) {
14251
14253
  if (status2.startsWith("updating")) return "info";
14252
14254
  return "notice";
14253
14255
  }
14256
+ var overscrollLocks = /* @__PURE__ */ new WeakMap();
14257
+ function lockOverscroll(document2) {
14258
+ const lock = overscrollLocks.get(document2) ?? { count: 0, restore: () => {
14259
+ } };
14260
+ overscrollLocks.set(document2, lock);
14261
+ if (lock.count === 0) {
14262
+ const saved = [document2.documentElement, document2.body].flatMap(
14263
+ ({ style }) => ["overscroll-behavior-x", "overscroll-behavior-y"].map((name) => {
14264
+ const value = style.getPropertyValue(name);
14265
+ const priority = style.getPropertyPriority(name);
14266
+ style.setProperty(name, "none", "important");
14267
+ return () => style.setProperty(name, value, priority);
14268
+ })
14269
+ );
14270
+ lock.restore = () => {
14271
+ for (const restore of saved) restore();
14272
+ };
14273
+ }
14274
+ lock.count += 1;
14275
+ return () => {
14276
+ lock.count -= 1;
14277
+ if (lock.count === 0) lock.restore();
14278
+ };
14279
+ }
14254
14280
  var SliccApp = class extends ThemedElement {
14255
14281
  static properties = {
14256
14282
  ...ThemedElement.properties,
@@ -14268,6 +14294,7 @@ var SliccApp = class extends ThemedElement {
14268
14294
  #started = null;
14269
14295
  #saving = false;
14270
14296
  #updatesPort;
14297
+ #unlock;
14271
14298
  #updatesVisibility = null;
14272
14299
  constructor() {
14273
14300
  super();
@@ -14456,12 +14483,14 @@ var SliccApp = class extends ThemedElement {
14456
14483
  this.ownerDocument.addEventListener("keydown", this.#keydown, true);
14457
14484
  this.#fonts();
14458
14485
  installProperties(this.ownerDocument);
14486
+ this.#unlock = lockOverscroll(this.ownerDocument);
14459
14487
  this.#resize = new ResizeObserver(() => this.#measure());
14460
14488
  this.#resize.observe(this);
14461
14489
  }
14462
14490
  disconnectedCallback() {
14463
14491
  super.disconnectedCallback();
14464
14492
  this.ownerDocument.removeEventListener("keydown", this.#keydown, true);
14493
+ this.#unlock();
14465
14494
  this.#resize?.disconnect();
14466
14495
  }
14467
14496
  get fontBase() {
@@ -18807,6 +18836,10 @@ var actionLabels = {
18807
18836
  login: "Log in",
18808
18837
  "drop-turn": "Drop the last turn"
18809
18838
  };
18839
+ function actionLabel(action, handlers, messageId) {
18840
+ const count = action === "drop-turn" ? handlers.dropping(messageId) : 1;
18841
+ return count > 1 ? `Drop ${count} failed turns` : actionLabels[action];
18842
+ }
18810
18843
  function time(at) {
18811
18844
  return new Date(at).toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });
18812
18845
  }
@@ -18858,14 +18891,14 @@ function tool(call, color = "light") {
18858
18891
  </details>`;
18859
18892
  }
18860
18893
  function cluster(calls, open, color) {
18861
- const failed = calls.filter((call) => call.status === "error").length;
18894
+ const failed2 = calls.filter((call) => call.status === "error").length;
18862
18895
  const running2 = calls.some((call) => call.status === "running");
18863
18896
  return b`<details class="cluster" ?open=${open || running2}>
18864
18897
  <summary>
18865
18898
  <span class="chevron" aria-hidden="true">▸</span>
18866
18899
  <span class="title">${calls.length} steps</span>
18867
18900
  <span class="names">${[...new Set(calls.map((call) => call.name))].join(" \xB7 ")}</span>
18868
- ${failed ? b`<span class="state failed">${toolStates.error[1]}${failed} failed</span>` : A}
18901
+ ${failed2 ? b`<span class="state failed">${toolStates.error[1]}${failed2} failed</span>` : A}
18869
18902
  </summary>
18870
18903
  ${calls.map((call) => tool(call, color))}
18871
18904
  </details>`;
@@ -18987,7 +19020,7 @@ function part(entry, handlers, showThinking) {
18987
19020
  default:
18988
19021
  return b`<div class="error-card" role="alert">
18989
19022
  <div class="error-text"><span class="lead">${entry.message}</span>${entry.detail ? b`<span class="detail">${entry.detail}</span>` : A}</div>
18990
- ${entry.action ? b`<swc-button size="s" variant="secondary" fill-style="outline" data-action=${entry.action} ?disabled=${handlers.readOnly} @click=${() => handlers.action(entry.action)}>${actionLabels[entry.action]}</swc-button>` : A}
19023
+ ${entry.action ? b`<swc-button size="s" variant="secondary" fill-style="outline" data-action=${entry.action} ?disabled=${handlers.readOnly} @click=${() => handlers.action(entry.action)}>${actionLabel(entry.action, handlers, "")}</swc-button>` : A}
18991
19024
  </div>`;
18992
19025
  }
18993
19026
  }
@@ -19083,7 +19116,11 @@ function assistant(message, name, model, handlers, showThinking, suggestion = nu
19083
19116
  ${status(message)}
19084
19117
  ${parts(
19085
19118
  message.parts,
19086
- { ...handlers, action: (action) => handlers.action(action, message.id) },
19119
+ {
19120
+ ...handlers,
19121
+ action: (action) => handlers.action(action, message.id),
19122
+ dropping: () => handlers.dropping(message.id)
19123
+ },
19087
19124
  showThinking,
19088
19125
  message.status === "streaming"
19089
19126
  )}
@@ -19126,7 +19163,7 @@ function system(message, handlers) {
19126
19163
  "Error",
19127
19164
  b`<div class="error-card system-error" role="alert" data-id=${message.id}>
19128
19165
  <div class="error-text"><strong>${message.title}</strong><span>${message.text}</span></div>
19129
- ${message.action ? b`<swc-button size="s" variant="secondary" fill-style="outline" data-action=${message.action} ?disabled=${handlers.readOnly} @click=${() => handlers.action(message.action, message.id)}>${actionLabels[message.action]}</swc-button>` : A}
19166
+ ${message.action ? b`<swc-button size="s" variant="secondary" fill-style="outline" data-action=${message.action} ?disabled=${handlers.readOnly} @click=${() => handlers.action(message.action, message.id)}>${actionLabel(message.action, handlers, message.id)}</swc-button>` : A}
19130
19167
  </div>`
19131
19168
  );
19132
19169
  }
@@ -19699,6 +19736,20 @@ var navigation = /* @__PURE__ */ new Set([
19699
19736
  "PageUp",
19700
19737
  "PageDown"
19701
19738
  ]);
19739
+ var failed = (message) => message.role === "assistant" ? message.status === "error" : message.role === "system" && message.kind === "error";
19740
+ function failedTurns(messages, messageId) {
19741
+ const at = messages.findIndex((message) => message.id === messageId);
19742
+ const turns = messages.flatMap(
19743
+ (message, index) => message.role === "user" && index < at ? [index] : []
19744
+ );
19745
+ const ids = [messageId];
19746
+ for (let turn = turns.length - 1; turn > 0; turn--) {
19747
+ const error = messages.slice(turns[turn - 1], turns[turn]).find(failed);
19748
+ if (!error) break;
19749
+ ids.push(error.id);
19750
+ }
19751
+ return ids;
19752
+ }
19702
19753
  var touched = false;
19703
19754
  document.addEventListener(
19704
19755
  "pointerdown",
@@ -19791,6 +19842,7 @@ var SliccChat = class extends ThemedElement {
19791
19842
  answer: (questionId, answer) => this.model?.agent.answer(this.#id(), questionId, answer),
19792
19843
  resolve: (messageId, state) => this.model?.agent.resolveLick(this.#id(), messageId, state),
19793
19844
  action: (action, messageId) => this.#action(action, messageId),
19845
+ dropping: (messageId) => failedTurns(this.model.agent.messages(this.#id()), messageId).length,
19794
19846
  open: (path) => this.dispatchEvent(
19795
19847
  new CustomEvent("open-file", { detail: { path }, bubbles: true, composed: true })
19796
19848
  ),
@@ -19880,9 +19932,15 @@ var SliccChat = class extends ThemedElement {
19880
19932
  return this.model?.agent.list().find((agent) => agent.id === id);
19881
19933
  }
19882
19934
  async #rewind(id, messageId) {
19883
- const restored = await this.model?.agent.rewind?.(id, messageId);
19935
+ const messages = this.model?.agent.messages(id) ?? [];
19936
+ const at = messages.findIndex((message) => message.id === messageId);
19937
+ const latest = messages.findLast(
19938
+ (message, index) => index < at && message.role === "user"
19939
+ );
19940
+ const first2 = failedTurns(messages, messageId).at(-1);
19941
+ const restored = await this.model?.agent.rewind?.(id, first2);
19884
19942
  if (!restored) return;
19885
- this.renderRoot.querySelector("slicc-composer")?.restore(restored);
19943
+ this.renderRoot.querySelector("slicc-composer")?.restore(latest ? { text: latest.text, attachments: latest.attachments } : restored);
19886
19944
  }
19887
19945
  #action(action, messageId = "") {
19888
19946
  const model = this.model;
@@ -40697,7 +40755,7 @@ var File = class {
40697
40755
  if (this.editor != null) throw new Error("File.__completeEditSession: detach the editor before completing the session");
40698
40756
  const sessionAnnotationsCurrent = editSessionAnnotations?.current;
40699
40757
  let acceptedFile;
40700
- let failed = false;
40758
+ let failed2 = false;
40701
40759
  let failure2;
40702
40760
  if (editor == null) throw new Error("File.__completeEditSession: editor is required for completion");
40703
40761
  const completedFile = { ...editSessionFile };
@@ -40716,7 +40774,7 @@ var File = class {
40716
40774
  acceptedFile = completedFile;
40717
40775
  }
40718
40776
  } catch (error) {
40719
- failed = true;
40777
+ failed2 = true;
40720
40778
  failure2 = error;
40721
40779
  }
40722
40780
  if (installResult && acceptedFile != null) {
@@ -40728,7 +40786,7 @@ var File = class {
40728
40786
  this.fileRenderer.endEditSession(settledFile);
40729
40787
  if (renderedFile != null && settledFile != null && renderedFile !== settledFile && areFileTargetsEqual(renderedFile, settledFile)) this.renderedFile = settledFile;
40730
40788
  if (installResult && this.fileContainer != null) this.rerender();
40731
- if (failed) throw failure2;
40789
+ if (failed2) throw failure2;
40732
40790
  }
40733
40791
  applyDocumentChange(textDocument, newLineAnnotations) {
40734
40792
  const editSessionFile = this.editSession?.file;
@@ -46982,7 +47040,7 @@ var FileDiff = class {
46982
47040
  let acceptedDiff;
46983
47041
  let acceptedOldFile = null;
46984
47042
  let acceptedNewFile = null;
46985
- let failed = false;
47043
+ let failed2 = false;
46986
47044
  let failure2;
46987
47045
  if (editor == null) throw new Error("FileDiff.__completeEditSession: editor is required for completion");
46988
47046
  const completedDiff = cloneFileDiffMetadata(editSessionDiff);
@@ -47013,7 +47071,7 @@ var FileDiff = class {
47013
47071
  acceptedNewFile = event2.newFile;
47014
47072
  }
47015
47073
  } catch (error) {
47016
- failed = true;
47074
+ failed2 = true;
47017
47075
  failure2 = error;
47018
47076
  }
47019
47077
  if (installResult && acceptedDiff != null) {
@@ -47026,7 +47084,7 @@ var FileDiff = class {
47026
47084
  }
47027
47085
  this.editSession = void 0;
47028
47086
  if (installResult && this.fileContainer != null) this.rerender();
47029
- if (failed) throw failure2;
47087
+ if (failed2) throw failure2;
47030
47088
  }
47031
47089
  /**
47032
47090
  * Run the session-end recompute: restore recompute-shaped hunks (a