@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
@@ -76,6 +76,8 @@ function reducer(state, action) {
76
76
  return { ...state, streamPhase: action.phase };
77
77
  case "STREAM_CONTENT":
78
78
  return { ...state, streamingContent: state.streamingContent + action.content };
79
+ case "STREAM_CONTENT_RESET":
80
+ return { ...state, streamingContent: "" };
79
81
  case "STREAM_AGENT":
80
82
  return { ...state, streamingAgent: action.agent };
81
83
  case "SEND_SUCCESS":
@@ -121,6 +123,7 @@ function useAgentChat(config) {
121
123
  configRef.current = config;
122
124
  const lastUserMessageRef = (0, import_react.useRef)(null);
123
125
  const lastUserAttachmentsRef = (0, import_react.useRef)(void 0);
126
+ const abortControllerRef = (0, import_react.useRef)(null);
124
127
  const sendMessage = (0, import_react.useCallback)(
125
128
  async (content, attachments) => {
126
129
  const { apiUrl, streamPath = "/chat/stream", headers: headersOrFn, timeout = 3e4, bodyExtra } = configRef.current;
@@ -136,7 +139,15 @@ function useAgentChat(config) {
136
139
  };
137
140
  dispatch({ type: "SEND_START", message: userMessage });
138
141
  const controller = new AbortController();
142
+ abortControllerRef.current = controller;
139
143
  const timeoutId = setTimeout(() => controller.abort(), timeout);
144
+ const ctx = {
145
+ accumulatedContent: "",
146
+ agentResponse: null,
147
+ capturedAgent: null,
148
+ capturedConversationId: null,
149
+ hadStreamError: false
150
+ };
140
151
  try {
141
152
  const url = `${apiUrl}${streamPath}`;
142
153
  const mergedHeaders = {
@@ -157,13 +168,6 @@ function useAgentChat(config) {
157
168
  }));
158
169
  }
159
170
  const body = JSON.stringify(requestBody);
160
- const ctx = {
161
- accumulatedContent: "",
162
- agentResponse: null,
163
- capturedAgent: null,
164
- capturedConversationId: null,
165
- hadStreamError: false
166
- };
167
171
  const handleEvent = (event) => {
168
172
  switch (event.type) {
169
173
  case "agent":
@@ -177,6 +181,10 @@ function useAgentChat(config) {
177
181
  ctx.accumulatedContent += event.content;
178
182
  dispatch({ type: "STREAM_CONTENT", content: event.content });
179
183
  break;
184
+ case "delta_reset":
185
+ ctx.accumulatedContent = "";
186
+ dispatch({ type: "STREAM_CONTENT_RESET" });
187
+ break;
180
188
  case "done":
181
189
  ctx.agentResponse = event.response;
182
190
  ctx.capturedConversationId = event.conversation_id ?? null;
@@ -260,10 +268,26 @@ function useAgentChat(config) {
260
268
  } catch (err) {
261
269
  clearTimeout(timeoutId);
262
270
  if (err.name === "AbortError") {
263
- dispatch({
264
- type: "SEND_ERROR",
265
- error: { code: "TIMEOUT", message: "Request timed out", retryable: true }
266
- });
271
+ if (ctx.accumulatedContent) {
272
+ const partialMessage = {
273
+ id: generateMessageId(),
274
+ role: "assistant",
275
+ content: ctx.accumulatedContent,
276
+ agent: ctx.capturedAgent ?? void 0,
277
+ timestamp: /* @__PURE__ */ new Date()
278
+ };
279
+ dispatch({
280
+ type: "SEND_SUCCESS",
281
+ message: partialMessage,
282
+ streamingContent: ctx.accumulatedContent,
283
+ conversationId: ctx.capturedConversationId
284
+ });
285
+ } else {
286
+ dispatch({
287
+ type: "SEND_ERROR",
288
+ error: { code: "ABORTED", message: "Request stopped", retryable: true }
289
+ });
290
+ }
267
291
  } else {
268
292
  dispatch({
269
293
  type: "SEND_ERROR",
@@ -274,6 +298,8 @@ function useAgentChat(config) {
274
298
  }
275
299
  });
276
300
  }
301
+ } finally {
302
+ abortControllerRef.current = null;
277
303
  }
278
304
  },
279
305
  [state.conversationId]
@@ -301,6 +327,9 @@ function useAgentChat(config) {
301
327
  await sendMessage(lastUserMessageRef.current, lastUserAttachmentsRef.current);
302
328
  }
303
329
  }, [sendMessage]);
330
+ const stop = (0, import_react.useCallback)(() => {
331
+ abortControllerRef.current?.abort();
332
+ }, []);
304
333
  const reset = (0, import_react.useCallback)(() => {
305
334
  dispatch({ type: "RESET" });
306
335
  lastUserMessageRef.current = null;
@@ -312,6 +341,7 @@ function useAgentChat(config) {
312
341
  loadConversation,
313
342
  submitFeedback,
314
343
  retry,
344
+ stop,
315
345
  reset
316
346
  };
317
347
  return { state, actions };
@@ -331,6 +361,7 @@ var import_core2 = require("@surf-kit/core");
331
361
  var import_react2 = __toESM(require("react"), 1);
332
362
  var import_react_markdown = __toESM(require("react-markdown"), 1);
333
363
  var import_rehype_sanitize = __toESM(require("rehype-sanitize"), 1);
364
+ var import_remark_gfm = __toESM(require("remark-gfm"), 1);
334
365
  var import_tailwind_merge = require("tailwind-merge");
335
366
  var import_jsx_runtime = require("react/jsx-runtime");
336
367
  function normalizeMarkdownLists(content) {
@@ -355,6 +386,10 @@ function ResponseMessage({ content, className }) {
355
386
  "[&_pre]:bg-surface-raised [&_pre]:border [&_pre]:border-border [&_pre]:rounded-xl [&_pre]:p-4 [&_pre]:overflow-x-auto",
356
387
  "[&_hr]:my-3 [&_hr]:border-border",
357
388
  "[&_blockquote]:border-l-2 [&_blockquote]:border-border-strong [&_blockquote]:pl-4 [&_blockquote]:text-text-secondary",
389
+ "[&_table]:w-full [&_table]:text-sm [&_table]:border-collapse [&_table]:my-2",
390
+ "[&_thead]:border-b [&_thead]:border-border",
391
+ "[&_th]:text-left [&_th]:px-2 [&_th]:py-1.5 [&_th]:font-semibold",
392
+ "[&_td]:px-2 [&_td]:py-1.5 [&_td]:border-t [&_td]:border-border/50",
358
393
  "[&_a]:text-accent [&_a]:underline-offset-2 [&_a]:hover:text-accent/80",
359
394
  className
360
395
  ),
@@ -362,6 +397,7 @@ function ResponseMessage({ content, className }) {
362
397
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
363
398
  import_react_markdown.default,
364
399
  {
400
+ remarkPlugins: [import_remark_gfm.default],
365
401
  rehypePlugins: [import_rehype_sanitize.default],
366
402
  components: {
367
403
  script: () => null,
@@ -387,7 +423,11 @@ function ResponseMessage({ content, className }) {
387
423
  h2: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-sm font-bold mt-3 mb-1", children }),
388
424
  h3: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "text-sm font-semibold mt-2 mb-1", children }),
389
425
  hr: () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("hr", { className: "my-3 border-border" }),
390
- code: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children })
426
+ code: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children }),
427
+ table: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "overflow-x-auto my-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("table", { className: "w-full text-sm border-collapse", children }) }),
428
+ thead: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { className: "border-b border-border", children }),
429
+ th: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: "text-left px-2 py-1.5 font-semibold", children }),
430
+ td: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "px-2 py-1.5 border-t border-border/50", children })
391
431
  },
392
432
  children: normalizeMarkdownLists(content)
393
433
  }
@@ -397,6 +437,8 @@ function ResponseMessage({ content, className }) {
397
437
  }
398
438
 
399
439
  // src/response/StructuredResponse/StructuredResponse.tsx
440
+ var import_react_markdown2 = __toESM(require("react-markdown"), 1);
441
+ var import_rehype_sanitize2 = __toESM(require("rehype-sanitize"), 1);
400
442
  var import_jsx_runtime2 = require("react/jsx-runtime");
401
443
  function tryParse(value) {
402
444
  if (value === void 0 || value === null) return null;
@@ -409,6 +451,25 @@ function tryParse(value) {
409
451
  }
410
452
  return value;
411
453
  }
454
+ function InlineMarkdown({ text }) {
455
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
456
+ import_react_markdown2.default,
457
+ {
458
+ rehypePlugins: [import_rehype_sanitize2.default],
459
+ components: {
460
+ // Unwrap block-level <p> so content stays inline within its parent
461
+ p: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children }),
462
+ strong: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { className: "font-semibold", children }),
463
+ em: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("em", { className: "italic", children }),
464
+ code: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children }),
465
+ // Prevent block elements that would break layout
466
+ script: () => null,
467
+ iframe: () => null
468
+ },
469
+ children: text
470
+ }
471
+ );
472
+ }
412
473
  function renderSteps(data) {
413
474
  const steps = tryParse(data.steps);
414
475
  if (!steps || !Array.isArray(steps)) return null;
@@ -421,7 +482,7 @@ function renderSteps(data) {
421
482
  children: i + 1
422
483
  }
423
484
  ),
424
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm text-text-primary leading-relaxed", children: step })
485
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm text-text-primary leading-relaxed", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(InlineMarkdown, { text: step }) })
425
486
  ] }, i)) });
426
487
  }
427
488
  function renderTable(data) {
@@ -487,7 +548,7 @@ function renderList(data) {
487
548
  title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs font-semibold uppercase tracking-wider text-text-secondary mb-1", children: title }),
488
549
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { className: "flex flex-col gap-1.5", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: "flex items-start gap-2.5", children: [
489
550
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-accent", "aria-hidden": "true" }),
490
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm text-text-primary leading-relaxed", children: item })
551
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm text-text-primary leading-relaxed", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(InlineMarkdown, { text: item }) })
491
552
  ] }, i)) })
492
553
  ] });
493
554
  }
@@ -926,24 +987,46 @@ function MessageBubble({
926
987
  var import_jsx_runtime8 = require("react/jsx-runtime");
927
988
  function MessageThread({ messages, streamingSlot, showAgent, showSources, showConfidence, showVerification, hideLastAssistant, userBubbleClassName, className }) {
928
989
  const scrollRef = (0, import_react4.useRef)(null);
929
- const isNearBottom = (0, import_react4.useRef)(true);
930
- const isProgrammaticScroll = (0, import_react4.useRef)(false);
990
+ const shouldAutoScroll = (0, import_react4.useRef)(true);
931
991
  const hasStreaming = !!streamingSlot;
932
992
  const scrollToBottom = (0, import_react4.useCallback)(() => {
933
993
  const el = scrollRef.current;
934
- if (el && isNearBottom.current) {
935
- isProgrammaticScroll.current = true;
994
+ if (el && shouldAutoScroll.current) {
936
995
  el.scrollTop = el.scrollHeight;
937
996
  }
938
997
  }, []);
998
+ (0, import_react4.useEffect)(() => {
999
+ const el = scrollRef.current;
1000
+ if (!el) return;
1001
+ const onWheel = (e) => {
1002
+ if (e.deltaY < 0) {
1003
+ shouldAutoScroll.current = false;
1004
+ }
1005
+ };
1006
+ const onPointerDown = () => {
1007
+ el.dataset.userPointer = "1";
1008
+ };
1009
+ const onPointerUp = () => {
1010
+ delete el.dataset.userPointer;
1011
+ };
1012
+ el.addEventListener("wheel", onWheel, { passive: true });
1013
+ el.addEventListener("pointerdown", onPointerDown);
1014
+ window.addEventListener("pointerup", onPointerUp);
1015
+ return () => {
1016
+ el.removeEventListener("wheel", onWheel);
1017
+ el.removeEventListener("pointerdown", onPointerDown);
1018
+ window.removeEventListener("pointerup", onPointerUp);
1019
+ };
1020
+ }, []);
939
1021
  const handleScroll = (0, import_react4.useCallback)(() => {
940
- if (isProgrammaticScroll.current) {
941
- isProgrammaticScroll.current = false;
942
- return;
943
- }
944
1022
  const el = scrollRef.current;
945
1023
  if (!el) return;
946
- isNearBottom.current = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
1024
+ const nearBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
1025
+ if (nearBottom) {
1026
+ shouldAutoScroll.current = true;
1027
+ } else if (el.dataset.userPointer) {
1028
+ shouldAutoScroll.current = false;
1029
+ }
947
1030
  }, []);
948
1031
  (0, import_react4.useEffect)(scrollToBottom, [messages.length, scrollToBottom]);
949
1032
  (0, import_react4.useEffect)(() => {
@@ -956,6 +1039,11 @@ function MessageThread({ messages, streamingSlot, showAgent, showSources, showCo
956
1039
  raf = requestAnimationFrame(tick);
957
1040
  return () => cancelAnimationFrame(raf);
958
1041
  }, [hasStreaming, scrollToBottom]);
1042
+ (0, import_react4.useEffect)(() => {
1043
+ if (!hasStreaming) {
1044
+ shouldAutoScroll.current = true;
1045
+ }
1046
+ }, [hasStreaming]);
959
1047
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
960
1048
  "div",
961
1049
  {
@@ -1087,6 +1175,7 @@ function AttachmentPreview({
1087
1175
  }
1088
1176
  function MessageComposer({
1089
1177
  onSend,
1178
+ onStop,
1090
1179
  isLoading = false,
1091
1180
  placeholder = "Type a message...",
1092
1181
  className
@@ -1296,16 +1385,16 @@ function MessageComposer({
1296
1385
  "button",
1297
1386
  {
1298
1387
  type: "button",
1299
- onClick: handleSend,
1300
- disabled: !canSend,
1301
- "aria-label": "Send message",
1388
+ onClick: isLoading && onStop ? onStop : handleSend,
1389
+ disabled: !canSend && !isLoading,
1390
+ "aria-label": isLoading ? "Stop generating" : "Send message",
1302
1391
  className: (0, import_tailwind_merge6.twMerge)(
1303
1392
  "absolute bottom-3 right-3",
1304
1393
  "inline-flex items-center justify-center",
1305
1394
  "w-9 h-9 rounded-full",
1306
1395
  "transition-all duration-200",
1307
1396
  "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
1308
- 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"
1397
+ 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"
1309
1398
  ),
1310
1399
  children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StopIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ArrowUpIcon, {})
1311
1400
  }
@@ -1461,9 +1550,10 @@ var phaseLabels = {
1461
1550
  verifying: "Verifying..."
1462
1551
  };
1463
1552
  var CURSOR_STYLES = `
1464
- .sk-streaming-cursor > :not(ul,ol,blockquote):last-child::after,
1553
+ .sk-streaming-cursor > :not(ul,ol,blockquote,div:has(table)):last-child::after,
1465
1554
  .sk-streaming-cursor > :is(ul,ol):last-child > li:last-child::after,
1466
- .sk-streaming-cursor > blockquote:last-child > p:last-child::after {
1555
+ .sk-streaming-cursor > blockquote:last-child > p:last-child::after,
1556
+ .sk-streaming-cursor > div:has(table):last-child table tbody tr:last-child td:last-child::after {
1467
1557
  content: "";
1468
1558
  display: inline-block;
1469
1559
  width: 2px;
@@ -1597,7 +1687,7 @@ function AgentChat({
1597
1687
  onQuestionSelect: handleQuestionSelect
1598
1688
  }
1599
1689
  ),
1600
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MessageComposer, { onSend: handleSend, isLoading: state.isLoading })
1690
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MessageComposer, { onSend: handleSend, onStop: actions.stop, isLoading: state.isLoading })
1601
1691
  ]
1602
1692
  }
1603
1693
  );
@@ -1618,14 +1708,14 @@ function ConversationList({
1618
1708
  "nav",
1619
1709
  {
1620
1710
  "aria-label": "Conversation list",
1621
- className: (0, import_tailwind_merge10.twMerge)("flex flex-col h-full bg-canvas", className),
1711
+ className: (0, import_tailwind_merge10.twMerge)("flex flex-col flex-1 min-h-0", className),
1622
1712
  children: [
1623
- onNew && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1713
+ onNew && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "px-5 pt-1 pb-3 border-b border-border", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1624
1714
  "button",
1625
1715
  {
1626
1716
  type: "button",
1627
1717
  onClick: onNew,
1628
- 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",
1718
+ 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",
1629
1719
  children: "New conversation"
1630
1720
  }
1631
1721
  ) }),
@@ -1636,9 +1726,9 @@ function ConversationList({
1636
1726
  "li",
1637
1727
  {
1638
1728
  className: (0, import_tailwind_merge10.twMerge)(
1639
- "flex items-start border-b border-border transition-colors duration-200",
1640
- "hover:bg-surface",
1641
- isActive && "bg-surface-raised border-l-2 border-l-accent"
1729
+ "flex items-start transition-colors duration-150",
1730
+ "hover:bg-surface-raised",
1731
+ isActive ? "bg-accent-subtlest border-l-[3px] border-l-accent" : "border-l-[3px] border-l-transparent"
1642
1732
  ),
1643
1733
  children: [
1644
1734
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
@@ -1647,10 +1737,10 @@ function ConversationList({
1647
1737
  type: "button",
1648
1738
  onClick: () => onSelect(conversation.id),
1649
1739
  "aria-current": isActive ? "true" : void 0,
1650
- className: "flex-1 min-w-0 text-left px-4 py-3",
1740
+ className: "flex-1 min-w-0 text-left px-5 py-2.5",
1651
1741
  children: [
1652
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-sm font-medium text-brand-cream truncate", children: conversation.title }),
1653
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-xs text-brand-cream/40 truncate mt-0.5 leading-relaxed", children: conversation.lastMessage })
1742
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-sm font-medium text-text-primary truncate", children: conversation.title }),
1743
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-xs text-text-muted truncate mt-0.5 leading-relaxed", children: conversation.lastMessage })
1654
1744
  ]
1655
1745
  }
1656
1746
  ),
@@ -1660,7 +1750,7 @@ function ConversationList({
1660
1750
  type: "button",
1661
1751
  onClick: () => onDelete(conversation.id),
1662
1752
  "aria-label": `Delete ${conversation.title}`,
1663
- 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",
1753
+ 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",
1664
1754
  children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1665
1755
  "svg",
1666
1756
  {
@@ -1687,7 +1777,7 @@ function ConversationList({
1687
1777
  conversation.id
1688
1778
  );
1689
1779
  }),
1690
- conversations.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("li", { className: "px-4 py-8 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-sm text-brand-cream/30 font-body", children: "No conversations yet" }) })
1780
+ conversations.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("li", { className: "px-5 py-12 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-sm text-text-muted font-body", children: "No conversations yet" }) })
1691
1781
  ] })
1692
1782
  ]
1693
1783
  }