@syntrologie/adapt-chatbot 2.8.0-canary.293 → 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-YQU3O7VK.js";
5
- import "./chunk-C6K7W3LO.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-YQU3O7VK.js";
4
- import "./chunk-C6K7W3LO.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-C6K7W3LO.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-C6K7W3LO.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-YQU3O7VK.js.map
417
+ //# sourceMappingURL=chunk-3HYMFSO4.js.map
@@ -2244,7 +2244,9 @@ var stopIcon = html2`<svg width="14" height="14" viewBox="0 0 14 14" fill="none"
2244
2244
  function autoResize(e) {
2245
2245
  const el = e.target;
2246
2246
  el.style.height = "auto";
2247
- el.style.height = `${Math.min(el.scrollHeight, 150)}px`;
2247
+ const capped = Math.min(el.scrollHeight, 150);
2248
+ el.style.height = `${capped}px`;
2249
+ el.style.overflowY = capped >= 150 ? "auto" : "hidden";
2248
2250
  }
2249
2251
  function renderChatInput(props) {
2250
2252
  const canSend = props.value.trim().length > 0 && !props.isStreaming;
@@ -2284,7 +2286,18 @@ function renderChatInput(props) {
2284
2286
  `;
2285
2287
  }
2286
2288
  function fingerprint(msg) {
2287
- 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(",") ?? "";
2288
2301
  return `${msg.id}:${msg.role}:${msg.content.length}:${msg.status}:${tcIds}`;
2289
2302
  }
2290
2303
  var marked = new B({ async: false, gfm: true, breaks: true });
@@ -2344,16 +2357,50 @@ function statusIcon(status) {
2344
2357
  return toolIcon;
2345
2358
  }
2346
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
+ }
2347
2390
  function renderToolCallCard(props) {
2348
2391
  const { toolCall, toolLabel, approve, deny } = props;
2349
- const displayName = toolLabel ?? toolCall.name;
2392
+ const displayName = toolLabel ?? humanizeToolName(toolCall.name);
2350
2393
  const isActive = toolCall.status === "args-streaming" || toolCall.status === "running";
2394
+ const statusText = STATUS_TEXT[toolCall.status] ?? "";
2395
+ const argsSummary = summarizeArgs(toolCall.args);
2351
2396
  return html3`
2352
- <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}>
2353
2398
  <div data-sc-tool-header>
2354
2399
  <span data-sc-tool-icon data-sc-status=${toolCall.status}>${statusIcon(toolCall.status)}</span>
2355
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}
2356
2402
  </div>
2403
+ ${argsSummary ? html3`<div data-sc-tool-args>${argsSummary}</div>` : nothing2}
2357
2404
  ${toolCall.status === "error" && toolCall.error ? html3`<div data-sc-tool-error>${toolCall.error}</div>` : nothing2}
2358
2405
  ${toolCall.status === "pending" ? html3`<div data-sc-tool-actions>
2359
2406
  <button data-sc-approve @click=${approve} aria-label="Approve ${displayName}">Approve</button>
@@ -2407,7 +2454,7 @@ function renderMessageBubble(props) {
2407
2454
  ${!isUser ? assistantIcon : nothing3}
2408
2455
  <div data-sc-msg-content>
2409
2456
  ${renderBubbleContent(message)}
2410
- ${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}
2411
2458
  ${toolCards ?? nothing3}
2412
2459
  ${renderActionBar({
2413
2460
  messageId: message.id,
@@ -2669,7 +2716,7 @@ var STYLE_RULES = `
2669
2716
  max-height: 150px;
2670
2717
  line-height: 1.4;
2671
2718
  transition: border-color 0.2s, box-shadow 0.2s;
2672
- overflow-y: auto;
2719
+ overflow-y: hidden;
2673
2720
  }
2674
2721
 
2675
2722
  [data-sc-chat] [data-sc-chat-input] textarea:focus {
@@ -2837,7 +2884,50 @@ var STYLE_RULES = `
2837
2884
  }
2838
2885
 
2839
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;
2840
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);
2841
2931
  }
2842
2932
 
2843
2933
  [data-sc-chat] [data-sc-tool-error] {
@@ -3078,8 +3168,15 @@ var SyntroChat = class extends LitElement {
3078
3168
  }
3079
3169
  case "tool-call-result": {
3080
3170
  let foundToolName;
3081
- this._messages = this._messages.map((m2) => {
3082
- 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;
3083
3180
  const toolCalls = m2.toolCalls.map((tc) => {
3084
3181
  if (tc.id !== event.toolCallId) return tc;
3085
3182
  foundToolName = tc.name;
@@ -3102,6 +3199,18 @@ var SyntroChat = class extends LitElement {
3102
3199
  }
3103
3200
  case "error":
3104
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
+ });
3105
3214
  break;
3106
3215
  case "a2ui":
3107
3216
  break;
@@ -3148,6 +3257,16 @@ var SyntroChat = class extends LitElement {
3148
3257
  });
3149
3258
  return;
3150
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
+ }
3151
3270
  if (_retryCount < 10) {
3152
3271
  setTimeout(() => this._onToolApprove(toolCallId, payload, _retryCount + 1), 200);
3153
3272
  return;
@@ -3171,6 +3290,16 @@ var SyntroChat = class extends LitElement {
3171
3290
  });
3172
3291
  return;
3173
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
+ }
3174
3303
  if (_retryCount < 10) {
3175
3304
  setTimeout(() => this._onToolDeny(toolCallId, _retryCount + 1), 200);
3176
3305
  return;
@@ -3250,9 +3379,19 @@ var SyntroChat = class extends LitElement {
3250
3379
  this._unsubscribe?.();
3251
3380
  this._unsubscribe = null;
3252
3381
  this.transport?.disconnect();
3382
+ this._scrollContainer?.removeEventListener("scroll", this._handleScroll);
3383
+ this._scrollContainer = null;
3253
3384
  }
3254
3385
  firstUpdated() {
3255
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;
3256
3395
  this._scrollContainer = this.querySelector("[data-sc-scroll-area]");
3257
3396
  this._scrollContainer?.addEventListener("scroll", this._handleScroll);
3258
3397
  }
@@ -3289,6 +3428,7 @@ var SyntroChat = class extends LitElement {
3289
3428
  injectChatStyles(this._resolveStyleRoot());
3290
3429
  }
3291
3430
  updated() {
3431
+ this._attachScrollListener();
3292
3432
  this._injectCodeCopyButtons();
3293
3433
  }
3294
3434
  _injectCodeCopyButtons() {
@@ -3330,6 +3470,13 @@ var SyntroChat = class extends LitElement {
3330
3470
  this._messages = [...this._messages, msg];
3331
3471
  this._scrollToBottom();
3332
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
+ }
3333
3480
  _findInterruptId(toolCallId) {
3334
3481
  for (const m2 of this._messages) {
3335
3482
  const tc = m2.toolCalls?.find((t) => t.id === toolCallId);
@@ -3555,4 +3702,4 @@ export {
3555
3702
  dompurify/dist/purify.es.mjs:
3556
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 *)
3557
3704
  */
3558
- //# sourceMappingURL=chunk-C6K7W3LO.js.map
3705
+ //# sourceMappingURL=chunk-A4X7HEVE.js.map