@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
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { A as AgentInfo, a as AgentResponse, C as ConfidenceBreakdown, S as Source, V as VerificationResult } from './agent-BNSmiexZ.cjs';
2
- export { C as ChatError, a as ChatMessage, b as ConversationSummary } from './chat-CGamM7Mz.cjs';
3
- export { S as StreamEvent, a as StreamState } from './streaming-x7umFHoP.cjs';
4
- export { A as AgentChatActions, a as AgentChatConfig, b as AgentChatState, c as AgentThemeResult, C as CharacterDrainResult, d as Conversation, F as FeedbackPayload, e as FeedbackState, U as UseConversationOptions, f as UseFeedbackOptions, g as UseStreamingOptions } from './hooks-B1NYoLLs.cjs';
2
+ export { C as ChatError, a as ChatMessage, b as ConversationSummary } from './chat-BRY3xGg_.cjs';
3
+ export { S as StreamEvent, a as StreamState } from './streaming-BHPXnwwo.cjs';
4
+ export { A as AgentChatActions, a as AgentChatConfig, b as AgentChatState, c as AgentThemeResult, C as CharacterDrainResult, d as Conversation, F as FeedbackPayload, e as FeedbackState, U as UseConversationOptions, f as UseFeedbackOptions, g as UseStreamingOptions } from './hooks-CSGGLd7j.cjs';
5
5
  export { M as MCPApprovalDialog, a as MCPApprovalDialogProps, b as MCPResource, c as MCPResourceView, d as MCPResourceViewProps, e as MCPServerInfo, f as MCPServerStatus, g as MCPServerStatusProps, h as MCPToolCall, i as MCPToolCallData, j as MCPToolCallProps, k as MCPToolStatus } from './index-BazLnae1.cjs';
6
6
  export { AgentChat, AgentChatProps, ConversationList, ConversationListProps, MessageBubble, MessageBubbleProps, MessageComposer, MessageComposerProps, MessageThread, MessageThreadProps, WelcomeScreen, WelcomeScreenProps } from './chat/index.cjs';
7
7
  export { AgentResponseProps, AgentResponse as AgentResponseView, ErrorResponse, ErrorResponseProps, FollowUpChips, FollowUpChipsProps, ResponseMessage, ResponseMessageProps, StructuredResponse, StructuredResponseProps } from './response/index.cjs';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { A as AgentInfo, a as AgentResponse, C as ConfidenceBreakdown, S as Source, V as VerificationResult } from './agent-BNSmiexZ.js';
2
- export { C as ChatError, a as ChatMessage, b as ConversationSummary } from './chat-BIIDOGrD.js';
3
- export { S as StreamEvent, a as StreamState } from './streaming-Bx-ff2tt.js';
4
- export { A as AgentChatActions, a as AgentChatConfig, b as AgentChatState, c as AgentThemeResult, C as CharacterDrainResult, d as Conversation, F as FeedbackPayload, e as FeedbackState, U as UseConversationOptions, f as UseFeedbackOptions, g as UseStreamingOptions } from './hooks-CTeEqnBQ.js';
2
+ export { C as ChatError, a as ChatMessage, b as ConversationSummary } from './chat-CcKc6OAR.js';
3
+ export { S as StreamEvent, a as StreamState } from './streaming-C6mbU7My.js';
4
+ export { A as AgentChatActions, a as AgentChatConfig, b as AgentChatState, c as AgentThemeResult, C as CharacterDrainResult, d as Conversation, F as FeedbackPayload, e as FeedbackState, U as UseConversationOptions, f as UseFeedbackOptions, g as UseStreamingOptions } from './hooks-BLeiVk-x.js';
5
5
  export { M as MCPApprovalDialog, a as MCPApprovalDialogProps, b as MCPResource, c as MCPResourceView, d as MCPResourceViewProps, e as MCPServerInfo, f as MCPServerStatus, g as MCPServerStatusProps, h as MCPToolCall, i as MCPToolCallData, j as MCPToolCallProps, k as MCPToolStatus } from './index-BazLnae1.js';
6
6
  export { AgentChat, AgentChatProps, ConversationList, ConversationListProps, MessageBubble, MessageBubbleProps, MessageComposer, MessageComposerProps, MessageThread, MessageThreadProps, WelcomeScreen, WelcomeScreenProps } from './chat/index.js';
7
7
  export { AgentResponseProps, AgentResponse as AgentResponseView, ErrorResponse, ErrorResponseProps, FollowUpChips, FollowUpChipsProps, ResponseMessage, ResponseMessageProps, StructuredResponse, StructuredResponseProps } from './response/index.js';
package/dist/index.js CHANGED
@@ -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(config2) {
79
81
  configRef.current = config2;
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(config2) {
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(config2) {
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(config2) {
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(config2) {
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(config2) {
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(config2) {
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(config2) {
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
  );
@@ -2371,14 +2461,14 @@ function ConversationList({
2371
2461
  "nav",
2372
2462
  {
2373
2463
  "aria-label": "Conversation list",
2374
- className: twMerge14("flex flex-col h-full bg-canvas", className),
2464
+ className: twMerge14("flex flex-col flex-1 min-h-0", className),
2375
2465
  children: [
2376
- onNew && /* @__PURE__ */ jsx34("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ jsx34(
2466
+ onNew && /* @__PURE__ */ jsx34("div", { className: "px-5 pt-1 pb-3 border-b border-border", children: /* @__PURE__ */ jsx34(
2377
2467
  "button",
2378
2468
  {
2379
2469
  type: "button",
2380
2470
  onClick: onNew,
2381
- 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",
2471
+ 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",
2382
2472
  children: "New conversation"
2383
2473
  }
2384
2474
  ) }),
@@ -2389,9 +2479,9 @@ function ConversationList({
2389
2479
  "li",
2390
2480
  {
2391
2481
  className: twMerge14(
2392
- "flex items-start border-b border-border transition-colors duration-200",
2393
- "hover:bg-surface",
2394
- isActive && "bg-surface-raised border-l-2 border-l-accent"
2482
+ "flex items-start transition-colors duration-150",
2483
+ "hover:bg-surface-raised",
2484
+ isActive ? "bg-accent-subtlest border-l-[3px] border-l-accent" : "border-l-[3px] border-l-transparent"
2395
2485
  ),
2396
2486
  children: [
2397
2487
  /* @__PURE__ */ jsxs31(
@@ -2400,10 +2490,10 @@ function ConversationList({
2400
2490
  type: "button",
2401
2491
  onClick: () => onSelect(conversation.id),
2402
2492
  "aria-current": isActive ? "true" : void 0,
2403
- className: "flex-1 min-w-0 text-left px-4 py-3",
2493
+ className: "flex-1 min-w-0 text-left px-5 py-2.5",
2404
2494
  children: [
2405
- /* @__PURE__ */ jsx34("div", { className: "text-sm font-medium text-brand-cream truncate", children: conversation.title }),
2406
- /* @__PURE__ */ jsx34("div", { className: "text-xs text-brand-cream/40 truncate mt-0.5 leading-relaxed", children: conversation.lastMessage })
2495
+ /* @__PURE__ */ jsx34("div", { className: "text-sm font-medium text-text-primary truncate", children: conversation.title }),
2496
+ /* @__PURE__ */ jsx34("div", { className: "text-xs text-text-muted truncate mt-0.5 leading-relaxed", children: conversation.lastMessage })
2407
2497
  ]
2408
2498
  }
2409
2499
  ),
@@ -2413,7 +2503,7 @@ function ConversationList({
2413
2503
  type: "button",
2414
2504
  onClick: () => onDelete(conversation.id),
2415
2505
  "aria-label": `Delete ${conversation.title}`,
2416
- 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",
2506
+ 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",
2417
2507
  children: /* @__PURE__ */ jsxs31(
2418
2508
  "svg",
2419
2509
  {
@@ -2440,7 +2530,7 @@ function ConversationList({
2440
2530
  conversation.id
2441
2531
  );
2442
2532
  }),
2443
- conversations.length === 0 && /* @__PURE__ */ jsx34("li", { className: "px-4 py-8 text-center", children: /* @__PURE__ */ jsx34("span", { className: "text-sm text-brand-cream/30 font-body", children: "No conversations yet" }) })
2533
+ conversations.length === 0 && /* @__PURE__ */ jsx34("li", { className: "px-5 py-12 text-center", children: /* @__PURE__ */ jsx34("span", { className: "text-sm text-text-muted font-body", children: "No conversations yet" }) })
2444
2534
  ] })
2445
2535
  ]
2446
2536
  }
@@ -2450,7 +2540,7 @@ function ConversationList({
2450
2540
  // src/layouts/AgentFullPage/AgentFullPage.tsx
2451
2541
  import { twMerge as twMerge15 } from "tailwind-merge";
2452
2542
  import { useState as useState7, useCallback as useCallback4 } from "react";
2453
- import { Fragment, jsx as jsx35, jsxs as jsxs32 } from "react/jsx-runtime";
2543
+ import { Fragment as Fragment2, jsx as jsx35, jsxs as jsxs32 } from "react/jsx-runtime";
2454
2544
  function AgentFullPage({
2455
2545
  endpoint,
2456
2546
  title = "Chat",
@@ -2476,7 +2566,7 @@ function AgentFullPage({
2476
2566
  className: twMerge15("flex h-screen w-full overflow-hidden bg-brand-dark", className),
2477
2567
  "data-testid": "agent-full-page",
2478
2568
  children: [
2479
- showConversationList && /* @__PURE__ */ jsxs32(Fragment, { children: [
2569
+ showConversationList && /* @__PURE__ */ jsxs32(Fragment2, { children: [
2480
2570
  sidebarOpen && /* @__PURE__ */ jsx35(
2481
2571
  "div",
2482
2572
  {
@@ -3334,7 +3424,7 @@ function ThumbsFeedback({
3334
3424
  // src/feedback/FeedbackDialog/FeedbackDialog.tsx
3335
3425
  import { useState as useState11 } from "react";
3336
3426
  import { Dialog, Button as Button3, TextArea } from "@surf-kit/core";
3337
- import { Fragment as Fragment2, jsx as jsx44, jsxs as jsxs40 } from "react/jsx-runtime";
3427
+ import { Fragment as Fragment3, jsx as jsx44, jsxs as jsxs40 } from "react/jsx-runtime";
3338
3428
  function FeedbackDialog({ isOpen, onClose, onSubmit, className }) {
3339
3429
  const [comment, setComment] = useState11("");
3340
3430
  const handleSubmit = () => {
@@ -3350,7 +3440,7 @@ function FeedbackDialog({ isOpen, onClose, onSubmit, className }) {
3350
3440
  title: "Share your feedback",
3351
3441
  size: "sm",
3352
3442
  className,
3353
- footer: /* @__PURE__ */ jsxs40(Fragment2, { children: [
3443
+ footer: /* @__PURE__ */ jsxs40(Fragment3, { children: [
3354
3444
  /* @__PURE__ */ jsx44(Button3, { intent: "ghost", onPress: onClose, children: "Cancel" }),
3355
3445
  /* @__PURE__ */ jsx44(Button3, { intent: "primary", onPress: handleSubmit, isDisabled: comment.trim().length === 0, children: "Submit" })
3356
3446
  ] }),