@ai-ecoverse/slicc-spectrum 1.11.0 → 1.13.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
@@ -7781,10 +7781,10 @@ function render(entry) {
7781
7781
  return entry.ordered ? b`<ol>${items}</ol>` : b`<ul>${items}</ul>`;
7782
7782
  }
7783
7783
  case "table": {
7784
- const [head2, ...body3] = entry.rows;
7784
+ const [head2, ...body4] = entry.rows;
7785
7785
  return b`<div class="table"><table>
7786
7786
  <thead><tr>${head2.map((cell) => b`<th>${inline(cell)}</th>`)}</tr></thead>
7787
- <tbody>${body3.map((row) => b`<tr>${row.map((cell) => b`<td>${inline(cell)}</td>`)}</tr>`)}</tbody>
7787
+ <tbody>${body4.map((row) => b`<tr>${row.map((cell) => b`<td>${inline(cell)}</td>`)}</tr>`)}</tbody>
7788
7788
  </table></div>`;
7789
7789
  }
7790
7790
  case "quote":
@@ -7824,7 +7824,8 @@ var actionLabels = {
7824
7824
  retry: "Retry",
7825
7825
  settings: "Open settings",
7826
7826
  "change-model": "Change model",
7827
- login: "Log in"
7827
+ login: "Log in",
7828
+ "drop-turn": "Drop the last turn"
7828
7829
  };
7829
7830
  function time(at) {
7830
7831
  return new Date(at).toISOString().slice(11, 16);
@@ -7842,21 +7843,28 @@ function size(bytes) {
7842
7843
  if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
7843
7844
  return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
7844
7845
  }
7845
- function tool(call) {
7846
+ function body(call, color) {
7847
+ if (call.diff) {
7848
+ return b`<slicc-diff-view class="input" path=${call.paths[0] ?? call.title} color=${color} .oldText=${call.diff.before} .newText=${call.diff.after}></slicc-diff-view>`;
7849
+ }
7850
+ return b`<pre class="input">${call.name === "bash" ? `$ ${call.input}` : call.input}</pre>`;
7851
+ }
7852
+ function tool(call, color = "light") {
7846
7853
  const state = call.status === "running" ? b`<sp-progress-circle size="s" indeterminate label="Running"></sp-progress-circle>` : b`<span class="state">${toolStates[call.status]}</span>`;
7847
7854
  return b`<details class="tool" data-status=${call.status} data-tool=${call.name}>
7848
7855
  <summary>
7849
7856
  <span class="chevron" aria-hidden="true">▸</span>
7850
7857
  <span class="name">${call.name}</span>
7851
7858
  <span class="title">${call.title}</span>
7859
+ ${call.meta ? b`<span class="tool-meta">${call.meta}</span>` : A}
7852
7860
  ${state}
7853
7861
  </summary>
7854
- <pre class="input">${call.name === "bash" ? `$ ${call.input}` : call.input}</pre>
7862
+ ${body(call, color)}
7855
7863
  ${call.output ? b`<pre class="output">${call.output}</pre>` : A}
7856
7864
  ${call.image ? b`<img class="shot" src=${call.image} alt=${call.title} />` : A}
7857
7865
  </details>`;
7858
7866
  }
7859
- function cluster(calls, open) {
7867
+ function cluster(calls, open, color) {
7860
7868
  const failed = calls.filter((call) => call.status === "error").length;
7861
7869
  const running = calls.some((call) => call.status === "running");
7862
7870
  return b`<details class="cluster" ?open=${open || running}>
@@ -7866,7 +7874,7 @@ function cluster(calls, open) {
7866
7874
  <span class="names">${[...new Set(calls.map((call) => call.name))].join(" \xB7 ")}</span>
7867
7875
  ${failed ? b`<span class="state failed">${failed} failed</span>` : A}
7868
7876
  </summary>
7869
- ${calls.map(tool)}
7877
+ ${calls.map((call) => tool(call, color))}
7870
7878
  </details>`;
7871
7879
  }
7872
7880
  function media(items) {
@@ -7906,14 +7914,14 @@ function check(items) {
7906
7914
  }
7907
7915
  function question(item2, handlers) {
7908
7916
  const answer = (value) => handlers.answer(item2.id, value);
7909
- let body3;
7917
+ let body4;
7910
7918
  if (item2.state === "answered") {
7911
- body3 = b`<div class="answer">✓ ${item2.answer}</div>`;
7919
+ body4 = b`<div class="answer">✓ ${item2.answer}</div>`;
7912
7920
  } else if (item2.state === "inert") {
7913
- body3 = b`<div class="hint">Only the latest question can be answered here.</div>`;
7921
+ body4 = b`<div class="hint">Only the latest question can be answered here.</div>`;
7914
7922
  } else if (item2.kind === "yes-no" || item2.kind === "choice") {
7915
7923
  const options = item2.kind === "yes-no" ? ["Yes", "No"] : item2.options;
7916
- body3 = b`<div class="options">${options.map(
7924
+ body4 = b`<div class="options">${options.map(
7917
7925
  (option2) => b`<sp-button size="s" variant="secondary" treatment="outline" @click=${() => answer(option2)}>${option2}</sp-button>`
7918
7926
  )}</div>`;
7919
7927
  } else {
@@ -7922,14 +7930,14 @@ function question(item2, handlers) {
7922
7930
  const field = event.currentTarget.querySelector("input");
7923
7931
  if (field.value.trim()) answer(field.value.trim());
7924
7932
  };
7925
- body3 = b`<form class="options" @submit=${submit}>
7933
+ body4 = b`<form class="options" @submit=${submit}>
7926
7934
  <input class="input" type=${item2.kind === "email" ? "email" : item2.kind === "number" ? "number" : item2.kind === "date" ? "date" : "text"} aria-label=${item2.question} />
7927
7935
  <sp-button size="s" variant="accent" @click=${(event) => event.currentTarget.closest("form")?.requestSubmit()}>Answer</sp-button>
7928
7936
  </form>`;
7929
7937
  }
7930
7938
  return b`<div class="question" data-state=${item2.state} data-kind=${item2.kind}>
7931
7939
  <div class="q">${item2.question}</div>
7932
- ${body3}
7940
+ ${body4}
7933
7941
  </div>`;
7934
7942
  }
7935
7943
  var delegationVerbs = {
@@ -7945,7 +7953,7 @@ function part(entry, handlers, showThinking) {
7945
7953
  case "thinking":
7946
7954
  return showThinking ? b`<div class="thinking">${entry.text}</div>` : A;
7947
7955
  case "tool":
7948
- return tool(entry.tool);
7956
+ return tool(entry.tool, handlers.color);
7949
7957
  case "media":
7950
7958
  return media(entry.items);
7951
7959
  case "card":
@@ -7984,7 +7992,7 @@ function parts(entries, handlers, showThinking, streaming) {
7984
7992
  while (end < entries.length && entries[end].type === "tool") end++;
7985
7993
  if (end - i10 >= 3) {
7986
7994
  const calls = entries.slice(i10, end).map((entry) => entry.tool);
7987
- out.push(cluster(calls, streaming && end === entries.length));
7995
+ out.push(cluster(calls, streaming && end === entries.length, handlers.color));
7988
7996
  i10 = end;
7989
7997
  } else {
7990
7998
  out.push(part(entries[i10], handlers, showThinking));
@@ -8026,14 +8034,19 @@ function assistant(message, name, model, handlers, showThinking) {
8026
8034
  ${message.status === "stopped" ? b`<span class="tag">stopped</span>` : A}
8027
8035
  ${message.status === "error" ? b`<span class="tag negative">failed</span>` : A}
8028
8036
  </div>
8029
- ${parts(message.parts, handlers, showThinking, message.status === "streaming")}
8037
+ ${parts(
8038
+ message.parts,
8039
+ { ...handlers, action: (action) => handlers.action(action, message.id) },
8040
+ showThinking,
8041
+ message.status === "streaming"
8042
+ )}
8030
8043
  ${message.status === "streaming" ? b`<span class="caret" aria-hidden="true"></span>` : A}
8031
8044
  </article>`;
8032
8045
  }
8033
- function toolMessage(message) {
8046
+ function toolMessage(message, color = "light") {
8034
8047
  return b`<article class="message tool-message" data-id=${message.id}>
8035
8048
  <div class="meta"><span class="who">Tool</span><span>${time(message.createdAt)}</span></div>
8036
- ${tool(message.tool)}
8049
+ ${tool(message.tool, color)}
8037
8050
  </article>`;
8038
8051
  }
8039
8052
  function system(message, handlers) {
@@ -8049,7 +8062,7 @@ function system(message, handlers) {
8049
8062
  }
8050
8063
  return b`<div class="error-card system-error" role="alert" data-id=${message.id}>
8051
8064
  <div class="error-text"><strong>${message.title}</strong><span>${message.text}</span></div>
8052
- ${message.action ? b`<sp-button size="s" variant="secondary" treatment="outline" @click=${() => handlers.action(message.action)}>${actionLabels[message.action]}</sp-button>` : A}
8065
+ ${message.action ? b`<sp-button size="s" variant="secondary" treatment="outline" @click=${() => handlers.action(message.action, message.id)}>${actionLabels[message.action]}</sp-button>` : A}
8053
8066
  </div>`;
8054
8067
  }
8055
8068
  function lick(message, handlers) {
@@ -8326,6 +8339,17 @@ var messageCss = i`
8326
8339
  .state.failed {
8327
8340
  color: var(--spectrum-negative-visual-color);
8328
8341
  }
8342
+ .tool-meta {
8343
+ flex: none;
8344
+ color: var(--spectrum-neutral-subdued-content-color-default);
8345
+ font-size: var(--spectrum-font-size-50);
8346
+ }
8347
+ .tool > slicc-diff-view {
8348
+ display: block;
8349
+ margin: 0 8px 8px;
8350
+ max-height: 240px;
8351
+ overflow: auto;
8352
+ }
8329
8353
  .tool pre,
8330
8354
  .lick pre {
8331
8355
  margin: 0 8px 8px;
@@ -8707,7 +8731,7 @@ var SliccChat = class extends ThemedElement {
8707
8731
  model: null,
8708
8732
  answer: (questionId, answer) => this.model?.agent.answer(this.#id(), questionId, answer),
8709
8733
  resolve: (messageId, state) => this.model?.agent.resolveLick(this.#id(), messageId, state),
8710
- action: (action) => this.#action(action),
8734
+ action: (action, messageId) => this.#action(action, messageId),
8711
8735
  open: (path) => this.dispatchEvent(
8712
8736
  new CustomEvent("open-file", { detail: { path }, bubbles: true, composed: true })
8713
8737
  )
@@ -8749,10 +8773,19 @@ var SliccChat = class extends ThemedElement {
8749
8773
  const id = this.#id();
8750
8774
  return this.model?.agent.list().find((agent) => agent.id === id);
8751
8775
  }
8752
- #action(action) {
8776
+ async #rewind(id, messageId) {
8777
+ const restored = await this.model?.agent.rewind?.(id, messageId);
8778
+ if (!restored) return;
8779
+ this.renderRoot.querySelector("slicc-composer")?.restore(restored);
8780
+ }
8781
+ #action(action, messageId = "") {
8753
8782
  const model = this.model;
8754
8783
  if (!model) return;
8755
8784
  const id = this.#id();
8785
+ if (action === "drop-turn") {
8786
+ void this.#rewind(id, messageId);
8787
+ return;
8788
+ }
8756
8789
  if (action === "retry") {
8757
8790
  const last = model.agent.messages(id).filter((message) => message.role === "user").at(-1);
8758
8791
  if (last) void model.agent.send(id, { text: last.text, attachments: last.attachments });
@@ -8778,7 +8811,7 @@ var SliccChat = class extends ThemedElement {
8778
8811
  case "user":
8779
8812
  return user(message);
8780
8813
  case "tool":
8781
- return toolMessage(message);
8814
+ return toolMessage(message, this.#handlers.color);
8782
8815
  case "system":
8783
8816
  return system(message, this.#handlers);
8784
8817
  default:
@@ -9157,6 +9190,12 @@ var SliccComposer = class extends ModelElement {
9157
9190
  focus() {
9158
9191
  this.focusOn("textarea");
9159
9192
  }
9193
+ restore(message) {
9194
+ this.value = message.text;
9195
+ this.attachments = [...message.attachments ?? []];
9196
+ this.#history = -1;
9197
+ this.focus();
9198
+ }
9160
9199
  get #textarea() {
9161
9200
  return this.renderRoot.querySelector("textarea");
9162
9201
  }
@@ -19027,7 +19066,7 @@ function omission(handlers) {
19027
19066
 
19028
19067
  // node_modules/hast-util-to-html/lib/omission/closing.js
19029
19068
  var closing = omission({
19030
- body,
19069
+ body: body2,
19031
19070
  caption: headOrColgroupOrCaption,
19032
19071
  colgroup: headOrColgroupOrCaption,
19033
19072
  dd,
@@ -19055,7 +19094,7 @@ function html3(_6, index, parent) {
19055
19094
  const next = siblingAfter(parent, index);
19056
19095
  return !next || next.type !== "comment";
19057
19096
  }
19058
- function body(_6, index, parent) {
19097
+ function body2(_6, index, parent) {
19059
19098
  const next = siblingAfter(parent, index);
19060
19099
  return !next || next.type !== "comment";
19061
19100
  }
@@ -19114,7 +19153,7 @@ function cells2(_6, index, parent) {
19114
19153
 
19115
19154
  // node_modules/hast-util-to-html/lib/omission/opening.js
19116
19155
  var opening = omission({
19117
- body: body2,
19156
+ body: body3,
19118
19157
  colgroup,
19119
19158
  head,
19120
19159
  html: html4,
@@ -19135,7 +19174,7 @@ function head(node) {
19135
19174
  const child = node.children[0];
19136
19175
  return !child || child.type === "element";
19137
19176
  }
19138
- function body2(node) {
19177
+ function body3(node) {
19139
19178
  const head2 = siblingAfter(node, -1, true);
19140
19179
  return !head2 || head2.type !== "comment" && !(head2.type === "text" && whitespace(head2.value.charAt(0))) && !(head2.type === "element" && (head2.tagName === "meta" || head2.tagName === "link" || head2.tagName === "script" || head2.tagName === "style" || head2.tagName === "template"));
19141
19180
  }
@@ -22223,12 +22262,12 @@ function transform(ast, options) {
22223
22262
  }
22224
22263
  var FirstPassVisitor = {
22225
22264
  AbsenceFunction({ node, parent, replaceWith }) {
22226
- const { body: body3, kind } = node;
22265
+ const { body: body4, kind } = node;
22227
22266
  if (kind === "repeater") {
22228
22267
  const innerGroup = A4();
22229
22268
  innerGroup.body[0].body.push(
22230
22269
  // Insert own alts as `body`
22231
- K2({ negate: true, body: body3 }),
22270
+ K2({ negate: true, body: body4 }),
22232
22271
  Q2("Any")
22233
22272
  );
22234
22273
  const outerGroup = A4();
@@ -22813,8 +22852,8 @@ function getKids(node) {
22813
22852
  if (!node) {
22814
22853
  throw new Error("Node expected");
22815
22854
  }
22816
- const { body: body3 } = node;
22817
- return Array.isArray(body3) ? body3 : body3 ? [body3] : null;
22855
+ const { body: body4 } = node;
22856
+ return Array.isArray(body4) ? body4 : body4 ? [body4] : null;
22818
22857
  }
22819
22858
  function getLeadingG(els) {
22820
22859
  const firstToConsider = els.find((el) => el.kind === "search_start" || isLoneGLookaround(el, { negate: false }) || !isAlwaysZeroLength(el));
@@ -23023,8 +23062,8 @@ var generator = {
23023
23062
  /**
23024
23063
  @param {AlternativeNode} node
23025
23064
  */
23026
- Alternative({ body: body3 }, _6, gen) {
23027
- return body3.map(gen).join("");
23065
+ Alternative({ body: body4 }, _6, gen) {
23066
+ return body4.map(gen).join("");
23028
23067
  },
23029
23068
  /**
23030
23069
  @param {AssertionNode} node
@@ -23057,7 +23096,7 @@ var generator = {
23057
23096
  @param {CapturingGroupNode} node
23058
23097
  */
23059
23098
  CapturingGroup(node, state, gen) {
23060
- const { body: body3, name, number: number2 } = node;
23099
+ const { body: body4, name, number: number2 } = node;
23061
23100
  const data = { ignoreCase: state.currentFlags.ignoreCase };
23062
23101
  const origin = state.originMap.get(node);
23063
23102
  if (origin) {
@@ -23067,7 +23106,7 @@ var generator = {
23067
23106
  }
23068
23107
  }
23069
23108
  state.captureMap.set(number2, data);
23070
- return `(${name ? `?<${name}>` : ""}${body3.map(gen).join("|")})`;
23109
+ return `(${name ? `?<${name}>` : ""}${body4.map(gen).join("|")})`;
23071
23110
  },
23072
23111
  /**
23073
23112
  @param {CharacterNode} node
@@ -23093,20 +23132,20 @@ var generator = {
23093
23132
  */
23094
23133
  CharacterClass(node, state, gen) {
23095
23134
  const { kind, negate, parent } = node;
23096
- let { body: body3 } = node;
23135
+ let { body: body4 } = node;
23097
23136
  if (kind === "intersection" && !state.useFlagV) {
23098
23137
  throw new Error("Use of character class intersection requires min target ES2024");
23099
23138
  }
23100
- if (envFlags.bugFlagVLiteralHyphenIsRange && state.useFlagV && body3.some(isLiteralHyphen)) {
23101
- body3 = [m4(45), ...body3.filter((kid) => !isLiteralHyphen(kid))];
23139
+ if (envFlags.bugFlagVLiteralHyphenIsRange && state.useFlagV && body4.some(isLiteralHyphen)) {
23140
+ body4 = [m4(45), ...body4.filter((kid) => !isLiteralHyphen(kid))];
23102
23141
  }
23103
- const genClass = () => `[${negate ? "^" : ""}${body3.map(gen).join(kind === "intersection" ? "&&" : "")}]`;
23142
+ const genClass = () => `[${negate ? "^" : ""}${body4.map(gen).join(kind === "intersection" ? "&&" : "")}]`;
23104
23143
  if (!state.inCharClass) {
23105
23144
  if (
23106
23145
  // Already established `kind !== 'intersection'` if `!state.useFlagV`; don't check again
23107
23146
  (!state.useFlagV || envFlags.bugNestedClassIgnoresNegation) && !negate
23108
23147
  ) {
23109
- const negatedChildClasses = body3.filter(
23148
+ const negatedChildClasses = body4.filter(
23110
23149
  (kid) => kid.type === "CharacterClass" && kid.kind === "union" && kid.negate
23111
23150
  );
23112
23151
  if (negatedChildClasses.length) {
@@ -23114,9 +23153,9 @@ var generator = {
23114
23153
  const groupFirstAlt = group.body[0];
23115
23154
  group.parent = parent;
23116
23155
  groupFirstAlt.parent = group;
23117
- body3 = body3.filter((kid) => !negatedChildClasses.includes(kid));
23118
- node.body = body3;
23119
- if (body3.length) {
23156
+ body4 = body4.filter((kid) => !negatedChildClasses.includes(kid));
23157
+ node.body = body4;
23158
+ if (body4.length) {
23120
23159
  node.parent = groupFirstAlt;
23121
23160
  groupFirstAlt.body.push(node);
23122
23161
  } else {
@@ -23136,14 +23175,14 @@ var generator = {
23136
23175
  state.inCharClass = false;
23137
23176
  return result;
23138
23177
  }
23139
- const firstEl = body3[0];
23178
+ const firstEl = body4[0];
23140
23179
  if (
23141
23180
  // Already established that the parent is a char class via `inCharClass`; don't check again
23142
23181
  kind === "union" && !negate && firstEl && // Allows many nested classes to work with `target` ES2018 which doesn't support nesting
23143
23182
  ((!state.useFlagV || !state.verbose) && parent.kind === "union" && !(envFlags.bugFlagVLiteralHyphenIsRange && state.useFlagV) || !state.verbose && parent.kind === "intersection" && // JS doesn't allow intersection with union or ranges
23144
- body3.length === 1 && firstEl.type !== "CharacterClassRange")
23183
+ body4.length === 1 && firstEl.type !== "CharacterClassRange")
23145
23184
  ) {
23146
- return body3.map(gen).join("");
23185
+ return body4.map(gen).join("");
23147
23186
  }
23148
23187
  if (!state.useFlagV && parent.type === "CharacterClass") {
23149
23188
  throw new Error("Uses nested character class in a way that requires min target ES2024");
@@ -23215,13 +23254,13 @@ var generator = {
23215
23254
  /**
23216
23255
  @param {GroupNode} node
23217
23256
  */
23218
- Group({ atomic: atomic2, body: body3, flags, parent }, state, gen) {
23257
+ Group({ atomic: atomic2, body: body4, flags, parent }, state, gen) {
23219
23258
  const currentFlags = state.currentFlags;
23220
23259
  if (flags) {
23221
23260
  state.currentFlags = getNewCurrentFlags(currentFlags, flags);
23222
23261
  }
23223
- const contents = body3.map(gen).join("|");
23224
- const result = !state.verbose && body3.length === 1 && // Single alt
23262
+ const contents = body4.map(gen).join("|");
23263
+ const result = !state.verbose && body4.length === 1 && // Single alt
23225
23264
  parent.type !== "Quantifier" && !atomic2 && (!state.useFlagMods || !flags) ? contents : `(?${getGroupPrefix(atomic2, flags, state.useFlagMods)}${contents})`;
23226
23265
  state.currentFlags = currentFlags;
23227
23266
  return result;
@@ -23229,9 +23268,9 @@ var generator = {
23229
23268
  /**
23230
23269
  @param {LookaroundAssertionNode} node
23231
23270
  */
23232
- LookaroundAssertion({ body: body3, kind, negate }, _6, gen) {
23271
+ LookaroundAssertion({ body: body4, kind, negate }, _6, gen) {
23233
23272
  const prefix = `${kind === "lookahead" ? "" : "<"}${negate ? "!" : "="}`;
23234
- return `(?${prefix}${body3.map(gen).join("|")})`;
23273
+ return `(?${prefix}${body4.map(gen).join("|")})`;
23235
23274
  },
23236
23275
  /**
23237
23276
  @param {QuantifierNode} node
@@ -44889,8 +44928,8 @@ var TabsContainer = class extends CompositeDisposable {
44889
44928
  }
44890
44929
  };
44891
44930
  },
44892
- open: (body3) => {
44893
- popup().openPopover(body3, anchor);
44931
+ open: (body4) => {
44932
+ popup().openPopover(body4, anchor);
44894
44933
  },
44895
44934
  close: () => popup().close(),
44896
44935
  focusTrigger: () => {