@surf-kit/agent 0.3.0 → 0.4.1

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