@syntrologie/adapt-chatbot 2.8.0-canary.294 → 2.8.0-canary.295

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.
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  AdaptiveChatBar
3
3
  } from "./chunk-SCVTTLFJ.js";
4
- import "./chunk-IGRIDG7O.js";
5
- import "./chunk-NLQR3MGO.js";
4
+ import "./chunk-3HYMFSO4.js";
5
+ import "./chunk-A4X7HEVE.js";
6
6
  import "./chunk-UVKRO5ER.js";
7
7
  export {
8
8
  AdaptiveChatBar
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AdaptiveChatTrail
3
- } from "./chunk-IGRIDG7O.js";
4
- import "./chunk-NLQR3MGO.js";
3
+ } from "./chunk-3HYMFSO4.js";
4
+ import "./chunk-A4X7HEVE.js";
5
5
  import "./chunk-UVKRO5ER.js";
6
6
  export {
7
7
  AdaptiveChatTrail
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  ChatAssistantLitMountable,
3
3
  renderFallbackHtml
4
- } from "./chunk-FLSMUFFX.js";
5
- import "./chunk-NLQR3MGO.js";
4
+ } from "./chunk-F2INJT5F.js";
5
+ import "./chunk-A4X7HEVE.js";
6
6
  import "./chunk-VLJ3WOEX.js";
7
7
  import "./chunk-UVKRO5ER.js";
8
8
  export {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  renderMarkdown
3
- } from "./chunk-NLQR3MGO.js";
3
+ } from "./chunk-A4X7HEVE.js";
4
4
 
5
5
  // src/AdaptiveChatTrail.ts
6
6
  import { html, LitElement, nothing } from "lit";
@@ -414,4 +414,4 @@ if (!customElements.get("adaptive-chat-trail")) {
414
414
  export {
415
415
  AdaptiveChatTrail
416
416
  };
417
- //# sourceMappingURL=chunk-IGRIDG7O.js.map
417
+ //# sourceMappingURL=chunk-3HYMFSO4.js.map
@@ -2286,7 +2286,18 @@ function renderChatInput(props) {
2286
2286
  `;
2287
2287
  }
2288
2288
  function fingerprint(msg) {
2289
- const tcIds = msg.toolCalls?.map((tc) => `${tc.id}:${tc.status}`).join(",") ?? "";
2289
+ const tcIds = msg.toolCalls?.map((tc) => {
2290
+ let resultKey = "-";
2291
+ if (tc.result !== void 0) {
2292
+ try {
2293
+ const json = JSON.stringify(tc.result);
2294
+ resultKey = json === void 0 ? "u" : String(json.length);
2295
+ } catch {
2296
+ resultKey = String(String(tc.result).length);
2297
+ }
2298
+ }
2299
+ return `${tc.id}:${tc.status}:${tc.interruptId ?? ""}:${resultKey}:${tc.error ?? ""}`;
2300
+ }).join(",") ?? "";
2290
2301
  return `${msg.id}:${msg.role}:${msg.content.length}:${msg.status}:${tcIds}`;
2291
2302
  }
2292
2303
  var marked = new B({ async: false, gfm: true, breaks: true });
@@ -2346,16 +2357,50 @@ function statusIcon(status) {
2346
2357
  return toolIcon;
2347
2358
  }
2348
2359
  }
2360
+ var STATUS_TEXT = {
2361
+ "args-streaming": "Running\u2026",
2362
+ running: "Running\u2026",
2363
+ pending: "Needs approval",
2364
+ done: "Done",
2365
+ error: "Failed",
2366
+ cancelled: "Cancelled"
2367
+ };
2368
+ function humanizeToolName(name) {
2369
+ const words = name.replace(/[_-]+/g, " ").trim();
2370
+ return words ? words.charAt(0).toUpperCase() + words.slice(1) : name;
2371
+ }
2372
+ var ARGS_SUMMARY_MAX = 90;
2373
+ var ARG_VALUE_MAX = 48;
2374
+ function summarizeArgs(args) {
2375
+ if (!args) return "";
2376
+ const bits = [];
2377
+ for (const [key, value] of Object.entries(args)) {
2378
+ if (value === null || value === void 0) continue;
2379
+ const t = typeof value;
2380
+ if (t !== "string" && t !== "number" && t !== "boolean") continue;
2381
+ let rendered = String(value);
2382
+ if (rendered.length > ARG_VALUE_MAX) rendered = `${rendered.slice(0, ARG_VALUE_MAX)}\u2026`;
2383
+ bits.push(`${key}: ${rendered}`);
2384
+ if (bits.join(" \xB7 ").length >= ARGS_SUMMARY_MAX) break;
2385
+ }
2386
+ let summary = bits.join(" \xB7 ");
2387
+ if (summary.length > ARGS_SUMMARY_MAX) summary = `${summary.slice(0, ARGS_SUMMARY_MAX)}\u2026`;
2388
+ return summary;
2389
+ }
2349
2390
  function renderToolCallCard(props) {
2350
2391
  const { toolCall, toolLabel, approve, deny } = props;
2351
- const displayName = toolLabel ?? toolCall.name;
2392
+ const displayName = toolLabel ?? humanizeToolName(toolCall.name);
2352
2393
  const isActive = toolCall.status === "args-streaming" || toolCall.status === "running";
2394
+ const statusText = STATUS_TEXT[toolCall.status] ?? "";
2395
+ const argsSummary = summarizeArgs(toolCall.args);
2353
2396
  return html3`
2354
- <div data-sc-tool-card ?data-sc-active=${isActive}>
2397
+ <div data-sc-tool-card ?data-sc-active=${isActive} data-sc-tool-phase=${toolCall.status}>
2355
2398
  <div data-sc-tool-header>
2356
2399
  <span data-sc-tool-icon data-sc-status=${toolCall.status}>${statusIcon(toolCall.status)}</span>
2357
2400
  <span data-sc-tool-name>${displayName}</span>
2401
+ ${statusText ? html3`<span data-sc-tool-status-text data-sc-status=${toolCall.status}>${statusText}</span>` : nothing2}
2358
2402
  </div>
2403
+ ${argsSummary ? html3`<div data-sc-tool-args>${argsSummary}</div>` : nothing2}
2359
2404
  ${toolCall.status === "error" && toolCall.error ? html3`<div data-sc-tool-error>${toolCall.error}</div>` : nothing2}
2360
2405
  ${toolCall.status === "pending" ? html3`<div data-sc-tool-actions>
2361
2406
  <button data-sc-approve @click=${approve} aria-label="Approve ${displayName}">Approve</button>
@@ -2409,7 +2454,7 @@ function renderMessageBubble(props) {
2409
2454
  ${!isUser ? assistantIcon : nothing3}
2410
2455
  <div data-sc-msg-content>
2411
2456
  ${renderBubbleContent(message)}
2412
- ${message.status === "error" ? html4`<div data-sc-msg-error>Failed to send</div>` : nothing3}
2457
+ ${message.status === "error" ? html4`<div data-sc-msg-error>${isUser ? "Failed to send" : "Response interrupted"}</div>` : nothing3}
2413
2458
  ${toolCards ?? nothing3}
2414
2459
  ${renderActionBar({
2415
2460
  messageId: message.id,
@@ -2839,7 +2884,50 @@ var STYLE_RULES = `
2839
2884
  }
2840
2885
 
2841
2886
  [data-sc-chat] [data-sc-tool-name] {
2887
+ font-weight: 600;
2888
+ }
2889
+
2890
+ [data-sc-chat] [data-sc-tool-status-text] {
2891
+ margin-left: auto;
2892
+ font-size: 0.72rem;
2842
2893
  font-weight: 500;
2894
+ letter-spacing: 0.02em;
2895
+ text-transform: uppercase;
2896
+ color: var(--sc-content-text-secondary-color, #6b6b80);
2897
+ white-space: nowrap;
2898
+ }
2899
+
2900
+ [data-sc-chat] [data-sc-tool-status-text][data-sc-status="done"] {
2901
+ color: #22c55e;
2902
+ }
2903
+
2904
+ [data-sc-chat] [data-sc-tool-status-text][data-sc-status="error"] {
2905
+ color: #ef4444;
2906
+ }
2907
+
2908
+ [data-sc-chat] [data-sc-tool-status-text][data-sc-status="running"],
2909
+ [data-sc-chat] [data-sc-tool-status-text][data-sc-status="args-streaming"] {
2910
+ color: #3b82f6;
2911
+ }
2912
+
2913
+ [data-sc-chat] [data-sc-tool-status-text][data-sc-status="cancelled"] {
2914
+ color: var(--sc-content-text-secondary-color, #6b6b80);
2915
+ text-decoration: line-through;
2916
+ }
2917
+
2918
+ [data-sc-chat] [data-sc-tool-args] {
2919
+ margin-top: 6px;
2920
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
2921
+ font-size: 0.76rem;
2922
+ color: var(--sc-content-text-secondary-color, #6b6b80);
2923
+ overflow: hidden;
2924
+ text-overflow: ellipsis;
2925
+ white-space: nowrap;
2926
+ }
2927
+
2928
+ [data-sc-chat] [data-sc-tool-card][data-sc-tool-phase="cancelled"] {
2929
+ opacity: 0.65;
2930
+ border-left-color: var(--sc-content-border-color, #e8e8ee);
2843
2931
  }
2844
2932
 
2845
2933
  [data-sc-chat] [data-sc-tool-error] {
@@ -3080,8 +3168,15 @@ var SyntroChat = class extends LitElement {
3080
3168
  }
3081
3169
  case "tool-call-result": {
3082
3170
  let foundToolName;
3083
- this._messages = this._messages.map((m2) => {
3084
- if (!m2.toolCalls) return m2;
3171
+ let lastIdx = -1;
3172
+ for (let i = this._messages.length - 1; i >= 0; i--) {
3173
+ if (this._messages[i].toolCalls?.some((tc) => tc.id === event.toolCallId)) {
3174
+ lastIdx = i;
3175
+ break;
3176
+ }
3177
+ }
3178
+ this._messages = this._messages.map((m2, idx) => {
3179
+ if (idx !== lastIdx || !m2.toolCalls) return m2;
3085
3180
  const toolCalls = m2.toolCalls.map((tc) => {
3086
3181
  if (tc.id !== event.toolCallId) return tc;
3087
3182
  foundToolName = tc.name;
@@ -3104,6 +3199,18 @@ var SyntroChat = class extends LitElement {
3104
3199
  }
3105
3200
  case "error":
3106
3201
  this._errorMessage = event.message;
3202
+ this._isStreaming = false;
3203
+ this._messages = this._messages.map((m2) => {
3204
+ const wasStreaming = m2.status === "streaming";
3205
+ const hasLiveTool = m2.toolCalls?.some(
3206
+ (tc) => tc.status === "args-streaming" || tc.status === "running"
3207
+ );
3208
+ if (!wasStreaming && !hasLiveTool) return m2;
3209
+ const toolCalls = hasLiveTool ? m2.toolCalls?.map(
3210
+ (tc) => tc.status === "args-streaming" || tc.status === "running" ? { ...tc, status: "error", error: tc.error ?? event.message } : tc
3211
+ ) : m2.toolCalls;
3212
+ return { ...m2, status: wasStreaming ? "error" : m2.status, toolCalls };
3213
+ });
3107
3214
  break;
3108
3215
  case "a2ui":
3109
3216
  break;
@@ -3150,6 +3257,16 @@ var SyntroChat = class extends LitElement {
3150
3257
  });
3151
3258
  return;
3152
3259
  }
3260
+ if (this._isPendingClientTool(toolCallId)) {
3261
+ this._markToolDone(toolCallId);
3262
+ this.transport.send({
3263
+ type: "tool-result",
3264
+ toolCallId,
3265
+ result: payload?.editedArgs ?? null,
3266
+ approved: true
3267
+ });
3268
+ return;
3269
+ }
3153
3270
  if (_retryCount < 10) {
3154
3271
  setTimeout(() => this._onToolApprove(toolCallId, payload, _retryCount + 1), 200);
3155
3272
  return;
@@ -3173,6 +3290,16 @@ var SyntroChat = class extends LitElement {
3173
3290
  });
3174
3291
  return;
3175
3292
  }
3293
+ if (this._isPendingClientTool(toolCallId)) {
3294
+ this._markToolDone(toolCallId);
3295
+ this.transport.send({
3296
+ type: "tool-result",
3297
+ toolCallId,
3298
+ result: null,
3299
+ approved: false
3300
+ });
3301
+ return;
3302
+ }
3176
3303
  if (_retryCount < 10) {
3177
3304
  setTimeout(() => this._onToolDeny(toolCallId, _retryCount + 1), 200);
3178
3305
  return;
@@ -3252,9 +3379,19 @@ var SyntroChat = class extends LitElement {
3252
3379
  this._unsubscribe?.();
3253
3380
  this._unsubscribe = null;
3254
3381
  this.transport?.disconnect();
3382
+ this._scrollContainer?.removeEventListener("scroll", this._handleScroll);
3383
+ this._scrollContainer = null;
3255
3384
  }
3256
3385
  firstUpdated() {
3257
3386
  this._ensureStylesInRoot();
3387
+ this._attachScrollListener();
3388
+ }
3389
+ /** Attach the scroll listener if not already attached. Called from both
3390
+ * firstUpdated (initial mount) and updated (re-mounts — Lit never
3391
+ * re-fires firstUpdated for the same element instance, and
3392
+ * disconnectedCallback tears the listener down). */
3393
+ _attachScrollListener() {
3394
+ if (this._scrollContainer) return;
3258
3395
  this._scrollContainer = this.querySelector("[data-sc-scroll-area]");
3259
3396
  this._scrollContainer?.addEventListener("scroll", this._handleScroll);
3260
3397
  }
@@ -3291,6 +3428,7 @@ var SyntroChat = class extends LitElement {
3291
3428
  injectChatStyles(this._resolveStyleRoot());
3292
3429
  }
3293
3430
  updated() {
3431
+ this._attachScrollListener();
3294
3432
  this._injectCodeCopyButtons();
3295
3433
  }
3296
3434
  _injectCodeCopyButtons() {
@@ -3332,6 +3470,13 @@ var SyntroChat = class extends LitElement {
3332
3470
  this._messages = [...this._messages, msg];
3333
3471
  this._scrollToBottom();
3334
3472
  }
3473
+ _isPendingClientTool(toolCallId) {
3474
+ for (const m2 of this._messages) {
3475
+ const tc = m2.toolCalls?.find((t) => t.id === toolCallId);
3476
+ if (tc) return tc.status === "pending" && !tc.interruptId;
3477
+ }
3478
+ return false;
3479
+ }
3335
3480
  _findInterruptId(toolCallId) {
3336
3481
  for (const m2 of this._messages) {
3337
3482
  const tc = m2.toolCalls?.find((t) => t.id === toolCallId);
@@ -3557,4 +3702,4 @@ export {
3557
3702
  dompurify/dist/purify.es.mjs:
3558
3703
  (*! @license DOMPurify 3.3.1 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.1/LICENSE *)
3559
3704
  */
3560
- //# sourceMappingURL=chunk-NLQR3MGO.js.map
3705
+ //# sourceMappingURL=chunk-A4X7HEVE.js.map