@surf-kit/agent 0.3.0 → 0.4.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.
Files changed (43) hide show
  1. package/dist/chat/index.cjs +131 -41
  2. package/dist/chat/index.cjs.map +1 -1
  3. package/dist/chat/index.d.cts +3 -2
  4. package/dist/chat/index.d.ts +3 -2
  5. package/dist/chat/index.js +132 -42
  6. package/dist/chat/index.js.map +1 -1
  7. package/dist/{chat-CGamM7Mz.d.cts → chat-BRY3xGg_.d.cts} +1 -1
  8. package/dist/{chat-BIIDOGrD.d.ts → chat-CcKc6OAR.d.ts} +1 -1
  9. package/dist/{hooks-CTeEqnBQ.d.ts → hooks-BLeiVk-x.d.ts} +3 -2
  10. package/dist/{hooks-B1NYoLLs.d.cts → hooks-CSGGLd7j.d.cts} +3 -2
  11. package/dist/hooks.cjs +41 -11
  12. package/dist/hooks.cjs.map +1 -1
  13. package/dist/hooks.d.cts +3 -3
  14. package/dist/hooks.d.ts +3 -3
  15. package/dist/hooks.js +41 -11
  16. package/dist/hooks.js.map +1 -1
  17. package/dist/index.cjs +131 -41
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +3 -3
  20. package/dist/index.d.ts +3 -3
  21. package/dist/index.js +136 -46
  22. package/dist/index.js.map +1 -1
  23. package/dist/layouts/index.cjs +131 -41
  24. package/dist/layouts/index.cjs.map +1 -1
  25. package/dist/layouts/index.d.cts +1 -1
  26. package/dist/layouts/index.d.ts +1 -1
  27. package/dist/layouts/index.js +134 -44
  28. package/dist/layouts/index.js.map +1 -1
  29. package/dist/response/index.cjs +34 -3
  30. package/dist/response/index.cjs.map +1 -1
  31. package/dist/response/index.d.cts +1 -1
  32. package/dist/response/index.d.ts +1 -1
  33. package/dist/response/index.js +35 -4
  34. package/dist/response/index.js.map +1 -1
  35. package/dist/streaming/index.cjs +14 -3
  36. package/dist/streaming/index.cjs.map +1 -1
  37. package/dist/streaming/index.d.cts +2 -2
  38. package/dist/streaming/index.d.ts +2 -2
  39. package/dist/streaming/index.js +14 -3
  40. package/dist/streaming/index.js.map +1 -1
  41. package/dist/{streaming-x7umFHoP.d.cts → streaming-BHPXnwwo.d.cts} +3 -1
  42. package/dist/{streaming-Bx-ff2tt.d.ts → streaming-C6mbU7My.d.ts} +3 -1
  43. package/package.json +5 -4
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { a as ChatMessage, A as Attachment, b as ConversationSummary } from '../chat-BIIDOGrD.js';
2
+ import { a as ChatMessage, A as Attachment, b as ConversationSummary } from '../chat-CcKc6OAR.js';
3
3
  import React from 'react';
4
4
  import '../agent-BNSmiexZ.js';
5
5
 
@@ -47,11 +47,12 @@ declare function MessageBubble({ message, showAgent, showSources, showConfidence
47
47
 
48
48
  type MessageComposerProps = {
49
49
  onSend: (content: string, attachments?: Attachment[]) => void;
50
+ onStop?: () => void;
50
51
  isLoading?: boolean;
51
52
  placeholder?: string;
52
53
  className?: string;
53
54
  };
54
- declare function MessageComposer({ onSend, isLoading, placeholder, className, }: MessageComposerProps): react_jsx_runtime.JSX.Element;
55
+ declare function MessageComposer({ onSend, onStop, isLoading, placeholder, className, }: MessageComposerProps): react_jsx_runtime.JSX.Element;
55
56
 
56
57
  type WelcomeScreenProps = {
57
58
  title?: string;
@@ -34,6 +34,8 @@ function reducer(state, action) {
34
34
  return { ...state, streamPhase: action.phase };
35
35
  case "STREAM_CONTENT":
36
36
  return { ...state, streamingContent: state.streamingContent + action.content };
37
+ case "STREAM_CONTENT_RESET":
38
+ return { ...state, streamingContent: "" };
37
39
  case "STREAM_AGENT":
38
40
  return { ...state, streamingAgent: action.agent };
39
41
  case "SEND_SUCCESS":
@@ -79,6 +81,7 @@ function useAgentChat(config) {
79
81
  configRef.current = config;
80
82
  const lastUserMessageRef = useRef(null);
81
83
  const lastUserAttachmentsRef = useRef(void 0);
84
+ const abortControllerRef = useRef(null);
82
85
  const sendMessage = useCallback(
83
86
  async (content, attachments) => {
84
87
  const { apiUrl, streamPath = "/chat/stream", headers: headersOrFn, timeout = 3e4, bodyExtra } = configRef.current;
@@ -94,7 +97,15 @@ function useAgentChat(config) {
94
97
  };
95
98
  dispatch({ type: "SEND_START", message: userMessage });
96
99
  const controller = new AbortController();
100
+ abortControllerRef.current = controller;
97
101
  const timeoutId = setTimeout(() => controller.abort(), timeout);
102
+ const ctx = {
103
+ accumulatedContent: "",
104
+ agentResponse: null,
105
+ capturedAgent: null,
106
+ capturedConversationId: null,
107
+ hadStreamError: false
108
+ };
98
109
  try {
99
110
  const url = `${apiUrl}${streamPath}`;
100
111
  const mergedHeaders = {
@@ -115,13 +126,6 @@ function useAgentChat(config) {
115
126
  }));
116
127
  }
117
128
  const body = JSON.stringify(requestBody);
118
- const ctx = {
119
- accumulatedContent: "",
120
- agentResponse: null,
121
- capturedAgent: null,
122
- capturedConversationId: null,
123
- hadStreamError: false
124
- };
125
129
  const handleEvent = (event) => {
126
130
  switch (event.type) {
127
131
  case "agent":
@@ -135,6 +139,10 @@ function useAgentChat(config) {
135
139
  ctx.accumulatedContent += event.content;
136
140
  dispatch({ type: "STREAM_CONTENT", content: event.content });
137
141
  break;
142
+ case "delta_reset":
143
+ ctx.accumulatedContent = "";
144
+ dispatch({ type: "STREAM_CONTENT_RESET" });
145
+ break;
138
146
  case "done":
139
147
  ctx.agentResponse = event.response;
140
148
  ctx.capturedConversationId = event.conversation_id ?? null;
@@ -218,10 +226,26 @@ function useAgentChat(config) {
218
226
  } catch (err) {
219
227
  clearTimeout(timeoutId);
220
228
  if (err.name === "AbortError") {
221
- dispatch({
222
- type: "SEND_ERROR",
223
- error: { code: "TIMEOUT", message: "Request timed out", retryable: true }
224
- });
229
+ if (ctx.accumulatedContent) {
230
+ const partialMessage = {
231
+ id: generateMessageId(),
232
+ role: "assistant",
233
+ content: ctx.accumulatedContent,
234
+ agent: ctx.capturedAgent ?? void 0,
235
+ timestamp: /* @__PURE__ */ new Date()
236
+ };
237
+ dispatch({
238
+ type: "SEND_SUCCESS",
239
+ message: partialMessage,
240
+ streamingContent: ctx.accumulatedContent,
241
+ conversationId: ctx.capturedConversationId
242
+ });
243
+ } else {
244
+ dispatch({
245
+ type: "SEND_ERROR",
246
+ error: { code: "ABORTED", message: "Request stopped", retryable: true }
247
+ });
248
+ }
225
249
  } else {
226
250
  dispatch({
227
251
  type: "SEND_ERROR",
@@ -232,6 +256,8 @@ function useAgentChat(config) {
232
256
  }
233
257
  });
234
258
  }
259
+ } finally {
260
+ abortControllerRef.current = null;
235
261
  }
236
262
  },
237
263
  [state.conversationId]
@@ -259,6 +285,9 @@ function useAgentChat(config) {
259
285
  await sendMessage(lastUserMessageRef.current, lastUserAttachmentsRef.current);
260
286
  }
261
287
  }, [sendMessage]);
288
+ const stop = useCallback(() => {
289
+ abortControllerRef.current?.abort();
290
+ }, []);
262
291
  const reset = useCallback(() => {
263
292
  dispatch({ type: "RESET" });
264
293
  lastUserMessageRef.current = null;
@@ -270,6 +299,7 @@ function useAgentChat(config) {
270
299
  loadConversation,
271
300
  submitFeedback,
272
301
  retry,
302
+ stop,
273
303
  reset
274
304
  };
275
305
  return { state, actions };
@@ -289,6 +319,7 @@ import { Badge as Badge2 } from "@surf-kit/core";
289
319
  import React from "react";
290
320
  import ReactMarkdown from "react-markdown";
291
321
  import rehypeSanitize from "rehype-sanitize";
322
+ import remarkGfm from "remark-gfm";
292
323
  import { twMerge } from "tailwind-merge";
293
324
  import { jsx } from "react/jsx-runtime";
294
325
  function normalizeMarkdownLists(content) {
@@ -313,6 +344,10 @@ function ResponseMessage({ content, className }) {
313
344
  "[&_pre]:bg-surface-raised [&_pre]:border [&_pre]:border-border [&_pre]:rounded-xl [&_pre]:p-4 [&_pre]:overflow-x-auto",
314
345
  "[&_hr]:my-3 [&_hr]:border-border",
315
346
  "[&_blockquote]:border-l-2 [&_blockquote]:border-border-strong [&_blockquote]:pl-4 [&_blockquote]:text-text-secondary",
347
+ "[&_table]:w-full [&_table]:text-sm [&_table]:border-collapse [&_table]:my-2",
348
+ "[&_thead]:border-b [&_thead]:border-border",
349
+ "[&_th]:text-left [&_th]:px-2 [&_th]:py-1.5 [&_th]:font-semibold",
350
+ "[&_td]:px-2 [&_td]:py-1.5 [&_td]:border-t [&_td]:border-border/50",
316
351
  "[&_a]:text-accent [&_a]:underline-offset-2 [&_a]:hover:text-accent/80",
317
352
  className
318
353
  ),
@@ -320,6 +355,7 @@ function ResponseMessage({ content, className }) {
320
355
  children: /* @__PURE__ */ jsx(
321
356
  ReactMarkdown,
322
357
  {
358
+ remarkPlugins: [remarkGfm],
323
359
  rehypePlugins: [rehypeSanitize],
324
360
  components: {
325
361
  script: () => null,
@@ -345,7 +381,11 @@ function ResponseMessage({ content, className }) {
345
381
  h2: ({ children }) => /* @__PURE__ */ jsx("h2", { className: "text-sm font-bold mt-3 mb-1", children }),
346
382
  h3: ({ children }) => /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold mt-2 mb-1", children }),
347
383
  hr: () => /* @__PURE__ */ jsx("hr", { className: "my-3 border-border" }),
348
- code: ({ children }) => /* @__PURE__ */ jsx("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children })
384
+ code: ({ children }) => /* @__PURE__ */ jsx("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children }),
385
+ table: ({ children }) => /* @__PURE__ */ jsx("div", { className: "overflow-x-auto my-2", children: /* @__PURE__ */ jsx("table", { className: "w-full text-sm border-collapse", children }) }),
386
+ thead: ({ children }) => /* @__PURE__ */ jsx("thead", { className: "border-b border-border", children }),
387
+ th: ({ children }) => /* @__PURE__ */ jsx("th", { className: "text-left px-2 py-1.5 font-semibold", children }),
388
+ td: ({ children }) => /* @__PURE__ */ jsx("td", { className: "px-2 py-1.5 border-t border-border/50", children })
349
389
  },
350
390
  children: normalizeMarkdownLists(content)
351
391
  }
@@ -355,7 +395,9 @@ function ResponseMessage({ content, className }) {
355
395
  }
356
396
 
357
397
  // src/response/StructuredResponse/StructuredResponse.tsx
358
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
398
+ import ReactMarkdown2 from "react-markdown";
399
+ import rehypeSanitize2 from "rehype-sanitize";
400
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
359
401
  function tryParse(value) {
360
402
  if (value === void 0 || value === null) return null;
361
403
  if (typeof value === "string") {
@@ -367,6 +409,25 @@ function tryParse(value) {
367
409
  }
368
410
  return value;
369
411
  }
412
+ function InlineMarkdown({ text }) {
413
+ return /* @__PURE__ */ jsx2(
414
+ ReactMarkdown2,
415
+ {
416
+ rehypePlugins: [rehypeSanitize2],
417
+ components: {
418
+ // Unwrap block-level <p> so content stays inline within its parent
419
+ p: ({ children }) => /* @__PURE__ */ jsx2(Fragment, { children }),
420
+ strong: ({ children }) => /* @__PURE__ */ jsx2("strong", { className: "font-semibold", children }),
421
+ em: ({ children }) => /* @__PURE__ */ jsx2("em", { className: "italic", children }),
422
+ code: ({ children }) => /* @__PURE__ */ jsx2("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children }),
423
+ // Prevent block elements that would break layout
424
+ script: () => null,
425
+ iframe: () => null
426
+ },
427
+ children: text
428
+ }
429
+ );
430
+ }
370
431
  function renderSteps(data) {
371
432
  const steps = tryParse(data.steps);
372
433
  if (!steps || !Array.isArray(steps)) return null;
@@ -379,7 +440,7 @@ function renderSteps(data) {
379
440
  children: i + 1
380
441
  }
381
442
  ),
382
- /* @__PURE__ */ jsx2("span", { className: "text-sm text-text-primary leading-relaxed", children: step })
443
+ /* @__PURE__ */ jsx2("span", { className: "text-sm text-text-primary leading-relaxed", children: /* @__PURE__ */ jsx2(InlineMarkdown, { text: step }) })
383
444
  ] }, i)) });
384
445
  }
385
446
  function renderTable(data) {
@@ -445,7 +506,7 @@ function renderList(data) {
445
506
  title && /* @__PURE__ */ jsx2("p", { className: "text-xs font-semibold uppercase tracking-wider text-text-secondary mb-1", children: title }),
446
507
  /* @__PURE__ */ jsx2("ul", { className: "flex flex-col gap-1.5", children: items.map((item, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2.5", children: [
447
508
  /* @__PURE__ */ jsx2("span", { className: "mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-accent", "aria-hidden": "true" }),
448
- /* @__PURE__ */ jsx2("span", { className: "text-sm text-text-primary leading-relaxed", children: item })
509
+ /* @__PURE__ */ jsx2("span", { className: "text-sm text-text-primary leading-relaxed", children: /* @__PURE__ */ jsx2(InlineMarkdown, { text: item }) })
449
510
  ] }, i)) })
450
511
  ] });
451
512
  }
@@ -884,24 +945,46 @@ function MessageBubble({
884
945
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
885
946
  function MessageThread({ messages, streamingSlot, showAgent, showSources, showConfidence, showVerification, hideLastAssistant, userBubbleClassName, className }) {
886
947
  const scrollRef = useRef2(null);
887
- const isNearBottom = useRef2(true);
888
- const isProgrammaticScroll = useRef2(false);
948
+ const shouldAutoScroll = useRef2(true);
889
949
  const hasStreaming = !!streamingSlot;
890
950
  const scrollToBottom = useCallback2(() => {
891
951
  const el = scrollRef.current;
892
- if (el && isNearBottom.current) {
893
- isProgrammaticScroll.current = true;
952
+ if (el && shouldAutoScroll.current) {
894
953
  el.scrollTop = el.scrollHeight;
895
954
  }
896
955
  }, []);
956
+ useEffect(() => {
957
+ const el = scrollRef.current;
958
+ if (!el) return;
959
+ const onWheel = (e) => {
960
+ if (e.deltaY < 0) {
961
+ shouldAutoScroll.current = false;
962
+ }
963
+ };
964
+ const onPointerDown = () => {
965
+ el.dataset.userPointer = "1";
966
+ };
967
+ const onPointerUp = () => {
968
+ delete el.dataset.userPointer;
969
+ };
970
+ el.addEventListener("wheel", onWheel, { passive: true });
971
+ el.addEventListener("pointerdown", onPointerDown);
972
+ window.addEventListener("pointerup", onPointerUp);
973
+ return () => {
974
+ el.removeEventListener("wheel", onWheel);
975
+ el.removeEventListener("pointerdown", onPointerDown);
976
+ window.removeEventListener("pointerup", onPointerUp);
977
+ };
978
+ }, []);
897
979
  const handleScroll = useCallback2(() => {
898
- if (isProgrammaticScroll.current) {
899
- isProgrammaticScroll.current = false;
900
- return;
901
- }
902
980
  const el = scrollRef.current;
903
981
  if (!el) return;
904
- isNearBottom.current = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
982
+ const nearBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
983
+ if (nearBottom) {
984
+ shouldAutoScroll.current = true;
985
+ } else if (el.dataset.userPointer) {
986
+ shouldAutoScroll.current = false;
987
+ }
905
988
  }, []);
906
989
  useEffect(scrollToBottom, [messages.length, scrollToBottom]);
907
990
  useEffect(() => {
@@ -914,6 +997,11 @@ function MessageThread({ messages, streamingSlot, showAgent, showSources, showCo
914
997
  raf = requestAnimationFrame(tick);
915
998
  return () => cancelAnimationFrame(raf);
916
999
  }, [hasStreaming, scrollToBottom]);
1000
+ useEffect(() => {
1001
+ if (!hasStreaming) {
1002
+ shouldAutoScroll.current = true;
1003
+ }
1004
+ }, [hasStreaming]);
917
1005
  return /* @__PURE__ */ jsxs6(
918
1006
  "div",
919
1007
  {
@@ -1045,6 +1133,7 @@ function AttachmentPreview({
1045
1133
  }
1046
1134
  function MessageComposer({
1047
1135
  onSend,
1136
+ onStop,
1048
1137
  isLoading = false,
1049
1138
  placeholder = "Type a message...",
1050
1139
  className
@@ -1254,16 +1343,16 @@ function MessageComposer({
1254
1343
  "button",
1255
1344
  {
1256
1345
  type: "button",
1257
- onClick: handleSend,
1258
- disabled: !canSend,
1259
- "aria-label": "Send message",
1346
+ onClick: isLoading && onStop ? onStop : handleSend,
1347
+ disabled: !canSend && !isLoading,
1348
+ "aria-label": isLoading ? "Stop generating" : "Send message",
1260
1349
  className: twMerge6(
1261
1350
  "absolute bottom-3 right-3",
1262
1351
  "inline-flex items-center justify-center",
1263
1352
  "w-9 h-9 rounded-full",
1264
1353
  "transition-all duration-200",
1265
1354
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
1266
- canSend ? "bg-accent text-white hover:bg-accent-hover active:scale-90 shadow-md shadow-accent/25" : isLoading ? "bg-text-muted/20 text-text-secondary hover:bg-text-muted/30" : "bg-transparent text-text-muted/40 cursor-default"
1355
+ canSend ? "bg-accent text-white hover:bg-accent-hover active:scale-90 shadow-md shadow-accent/25" : isLoading ? "bg-text-muted/20 text-text-secondary hover:bg-text-muted/30 cursor-pointer" : "bg-transparent text-text-muted/40 cursor-default"
1267
1356
  ),
1268
1357
  children: isLoading ? /* @__PURE__ */ jsx9(StopIcon, {}) : /* @__PURE__ */ jsx9(ArrowUpIcon, {})
1269
1358
  }
@@ -1419,9 +1508,10 @@ var phaseLabels = {
1419
1508
  verifying: "Verifying..."
1420
1509
  };
1421
1510
  var CURSOR_STYLES = `
1422
- .sk-streaming-cursor > :not(ul,ol,blockquote):last-child::after,
1511
+ .sk-streaming-cursor > :not(ul,ol,blockquote,div:has(table)):last-child::after,
1423
1512
  .sk-streaming-cursor > :is(ul,ol):last-child > li:last-child::after,
1424
- .sk-streaming-cursor > blockquote:last-child > p:last-child::after {
1513
+ .sk-streaming-cursor > blockquote:last-child > p:last-child::after,
1514
+ .sk-streaming-cursor > div:has(table):last-child table tbody tr:last-child td:last-child::after {
1425
1515
  content: "";
1426
1516
  display: inline-block;
1427
1517
  width: 2px;
@@ -1555,7 +1645,7 @@ function AgentChat({
1555
1645
  onQuestionSelect: handleQuestionSelect
1556
1646
  }
1557
1647
  ),
1558
- /* @__PURE__ */ jsx12(MessageComposer, { onSend: handleSend, isLoading: state.isLoading })
1648
+ /* @__PURE__ */ jsx12(MessageComposer, { onSend: handleSend, onStop: actions.stop, isLoading: state.isLoading })
1559
1649
  ]
1560
1650
  }
1561
1651
  );
@@ -1576,14 +1666,14 @@ function ConversationList({
1576
1666
  "nav",
1577
1667
  {
1578
1668
  "aria-label": "Conversation list",
1579
- className: twMerge10("flex flex-col h-full bg-canvas", className),
1669
+ className: twMerge10("flex flex-col flex-1 min-h-0", className),
1580
1670
  children: [
1581
- onNew && /* @__PURE__ */ jsx13("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ jsx13(
1671
+ onNew && /* @__PURE__ */ jsx13("div", { className: "px-5 pt-1 pb-3 border-b border-border", children: /* @__PURE__ */ jsx13(
1582
1672
  "button",
1583
1673
  {
1584
1674
  type: "button",
1585
1675
  onClick: onNew,
1586
- className: "w-full px-4 py-2.5 rounded-xl text-sm font-semibold bg-accent text-white hover:bg-accent-hover transition-all duration-200",
1676
+ className: "w-full px-4 py-2 rounded-lg text-sm font-medium border border-border text-text-secondary hover:text-text-primary hover:bg-surface hover:border-border-strong transition-colors duration-150",
1587
1677
  children: "New conversation"
1588
1678
  }
1589
1679
  ) }),
@@ -1594,9 +1684,9 @@ function ConversationList({
1594
1684
  "li",
1595
1685
  {
1596
1686
  className: twMerge10(
1597
- "flex items-start border-b border-border transition-colors duration-200",
1598
- "hover:bg-surface",
1599
- isActive && "bg-surface-raised border-l-2 border-l-accent"
1687
+ "flex items-start transition-colors duration-150",
1688
+ "hover:bg-surface-raised",
1689
+ isActive ? "bg-accent-subtlest border-l-[3px] border-l-accent" : "border-l-[3px] border-l-transparent"
1600
1690
  ),
1601
1691
  children: [
1602
1692
  /* @__PURE__ */ jsxs11(
@@ -1605,10 +1695,10 @@ function ConversationList({
1605
1695
  type: "button",
1606
1696
  onClick: () => onSelect(conversation.id),
1607
1697
  "aria-current": isActive ? "true" : void 0,
1608
- className: "flex-1 min-w-0 text-left px-4 py-3",
1698
+ className: "flex-1 min-w-0 text-left px-5 py-2.5",
1609
1699
  children: [
1610
- /* @__PURE__ */ jsx13("div", { className: "text-sm font-medium text-brand-cream truncate", children: conversation.title }),
1611
- /* @__PURE__ */ jsx13("div", { className: "text-xs text-brand-cream/40 truncate mt-0.5 leading-relaxed", children: conversation.lastMessage })
1700
+ /* @__PURE__ */ jsx13("div", { className: "text-sm font-medium text-text-primary truncate", children: conversation.title }),
1701
+ /* @__PURE__ */ jsx13("div", { className: "text-xs text-text-muted truncate mt-0.5 leading-relaxed", children: conversation.lastMessage })
1612
1702
  ]
1613
1703
  }
1614
1704
  ),
@@ -1618,7 +1708,7 @@ function ConversationList({
1618
1708
  type: "button",
1619
1709
  onClick: () => onDelete(conversation.id),
1620
1710
  "aria-label": `Delete ${conversation.title}`,
1621
- className: "shrink-0 p-1.5 m-2 rounded-lg text-brand-cream/25 hover:text-brand-watermelon hover:bg-brand-watermelon/10 transition-colors duration-200",
1711
+ className: "shrink-0 p-1.5 m-2 rounded-lg text-text-muted hover:text-status-error hover:bg-status-error/10 transition-colors duration-150",
1622
1712
  children: /* @__PURE__ */ jsxs11(
1623
1713
  "svg",
1624
1714
  {
@@ -1645,7 +1735,7 @@ function ConversationList({
1645
1735
  conversation.id
1646
1736
  );
1647
1737
  }),
1648
- conversations.length === 0 && /* @__PURE__ */ jsx13("li", { className: "px-4 py-8 text-center", children: /* @__PURE__ */ jsx13("span", { className: "text-sm text-brand-cream/30 font-body", children: "No conversations yet" }) })
1738
+ conversations.length === 0 && /* @__PURE__ */ jsx13("li", { className: "px-5 py-12 text-center", children: /* @__PURE__ */ jsx13("span", { className: "text-sm text-text-muted font-body", children: "No conversations yet" }) })
1649
1739
  ] })
1650
1740
  ]
1651
1741
  }