@surf-kit/agent 0.2.2 → 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.
- package/dist/chat/index.cjs +733 -222
- package/dist/chat/index.cjs.map +1 -1
- package/dist/chat/index.d.cts +13 -7
- package/dist/chat/index.d.ts +13 -7
- package/dist/chat/index.js +715 -204
- package/dist/chat/index.js.map +1 -1
- package/dist/{chat-ChYl2XjV.d.cts → chat-BRY3xGg_.d.cts} +11 -2
- package/dist/{chat--OifhIRe.d.ts → chat-CcKc6OAR.d.ts} +11 -2
- package/dist/{hooks-BGs8-4GK.d.ts → hooks-BLeiVk-x.d.ts} +22 -5
- package/dist/{hooks-DLfF18IU.d.cts → hooks-CSGGLd7j.d.cts} +22 -5
- package/dist/hooks.cjs +160 -85
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +3 -3
- package/dist/hooks.d.ts +3 -3
- package/dist/hooks.js +160 -85
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +794 -283
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +758 -247
- package/dist/index.js.map +1 -1
- package/dist/layouts/index.cjs +754 -243
- package/dist/layouts/index.cjs.map +1 -1
- package/dist/layouts/index.d.cts +1 -1
- package/dist/layouts/index.d.ts +1 -1
- package/dist/layouts/index.js +733 -222
- package/dist/layouts/index.js.map +1 -1
- package/dist/mcp/index.cjs +1 -1
- package/dist/mcp/index.cjs.map +1 -1
- package/dist/mcp/index.js +2 -2
- package/dist/mcp/index.js.map +1 -1
- package/dist/response/index.cjs +100 -15
- package/dist/response/index.cjs.map +1 -1
- package/dist/response/index.d.cts +2 -2
- package/dist/response/index.d.ts +2 -2
- package/dist/response/index.js +99 -14
- package/dist/response/index.js.map +1 -1
- package/dist/sources/index.cjs +30 -1
- package/dist/sources/index.cjs.map +1 -1
- package/dist/sources/index.js +30 -1
- package/dist/sources/index.js.map +1 -1
- package/dist/streaming/index.cjs +213 -93
- package/dist/streaming/index.cjs.map +1 -1
- package/dist/streaming/index.d.cts +4 -3
- package/dist/streaming/index.d.ts +4 -3
- package/dist/streaming/index.js +183 -73
- package/dist/streaming/index.js.map +1 -1
- package/dist/{streaming-DfT22A0z.d.cts → streaming-BHPXnwwo.d.cts} +3 -1
- package/dist/{streaming-DbQxScpi.d.ts → streaming-C6mbU7My.d.ts} +3 -1
- package/package.json +17 -5
package/dist/index.cjs
CHANGED
|
@@ -81,7 +81,7 @@ __export(index_exports, {
|
|
|
81
81
|
module.exports = __toCommonJS(index_exports);
|
|
82
82
|
|
|
83
83
|
// src/chat/AgentChat/AgentChat.tsx
|
|
84
|
-
var
|
|
84
|
+
var import_tailwind_merge9 = require("tailwind-merge");
|
|
85
85
|
|
|
86
86
|
// src/hooks/useAgentChat.ts
|
|
87
87
|
var import_react = require("react");
|
|
@@ -92,7 +92,8 @@ var initialState = {
|
|
|
92
92
|
error: null,
|
|
93
93
|
inputValue: "",
|
|
94
94
|
streamPhase: "idle",
|
|
95
|
-
streamingContent: ""
|
|
95
|
+
streamingContent: "",
|
|
96
|
+
streamingAgent: null
|
|
96
97
|
};
|
|
97
98
|
function reducer(state, action) {
|
|
98
99
|
switch (action.type) {
|
|
@@ -106,12 +107,17 @@ function reducer(state, action) {
|
|
|
106
107
|
error: null,
|
|
107
108
|
inputValue: "",
|
|
108
109
|
streamPhase: "thinking",
|
|
109
|
-
streamingContent: ""
|
|
110
|
+
streamingContent: "",
|
|
111
|
+
streamingAgent: null
|
|
110
112
|
};
|
|
111
113
|
case "STREAM_PHASE":
|
|
112
114
|
return { ...state, streamPhase: action.phase };
|
|
113
115
|
case "STREAM_CONTENT":
|
|
114
116
|
return { ...state, streamingContent: state.streamingContent + action.content };
|
|
117
|
+
case "STREAM_CONTENT_RESET":
|
|
118
|
+
return { ...state, streamingContent: "" };
|
|
119
|
+
case "STREAM_AGENT":
|
|
120
|
+
return { ...state, streamingAgent: action.agent };
|
|
115
121
|
case "SEND_SUCCESS":
|
|
116
122
|
return {
|
|
117
123
|
...state,
|
|
@@ -127,7 +133,8 @@ function reducer(state, action) {
|
|
|
127
133
|
isLoading: false,
|
|
128
134
|
error: action.error,
|
|
129
135
|
streamPhase: "idle",
|
|
130
|
-
streamingContent: ""
|
|
136
|
+
streamingContent: "",
|
|
137
|
+
streamingAgent: null
|
|
131
138
|
};
|
|
132
139
|
case "LOAD_CONVERSATION":
|
|
133
140
|
return {
|
|
@@ -153,115 +160,172 @@ function useAgentChat(config2) {
|
|
|
153
160
|
const configRef = (0, import_react.useRef)(config2);
|
|
154
161
|
configRef.current = config2;
|
|
155
162
|
const lastUserMessageRef = (0, import_react.useRef)(null);
|
|
163
|
+
const lastUserAttachmentsRef = (0, import_react.useRef)(void 0);
|
|
164
|
+
const abortControllerRef = (0, import_react.useRef)(null);
|
|
156
165
|
const sendMessage = (0, import_react.useCallback)(
|
|
157
|
-
async (content) => {
|
|
158
|
-
const { apiUrl, streamPath = "/chat/stream", headers
|
|
166
|
+
async (content, attachments) => {
|
|
167
|
+
const { apiUrl, streamPath = "/chat/stream", headers: headersOrFn, timeout = 3e4, bodyExtra } = configRef.current;
|
|
168
|
+
const headers = typeof headersOrFn === "function" ? await headersOrFn() : headersOrFn ?? {};
|
|
159
169
|
lastUserMessageRef.current = content;
|
|
170
|
+
lastUserAttachmentsRef.current = attachments;
|
|
160
171
|
const userMessage = {
|
|
161
172
|
id: generateMessageId(),
|
|
162
173
|
role: "user",
|
|
163
174
|
content,
|
|
175
|
+
attachments,
|
|
164
176
|
timestamp: /* @__PURE__ */ new Date()
|
|
165
177
|
};
|
|
166
178
|
dispatch({ type: "SEND_START", message: userMessage });
|
|
167
179
|
const controller = new AbortController();
|
|
180
|
+
abortControllerRef.current = controller;
|
|
168
181
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
182
|
+
const ctx = {
|
|
183
|
+
accumulatedContent: "",
|
|
184
|
+
agentResponse: null,
|
|
185
|
+
capturedAgent: null,
|
|
186
|
+
capturedConversationId: null,
|
|
187
|
+
hadStreamError: false
|
|
188
|
+
};
|
|
169
189
|
try {
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
error: {
|
|
188
|
-
code: "API_ERROR",
|
|
189
|
-
message: `HTTP ${response.status}: ${response.statusText}`,
|
|
190
|
-
retryable: response.status >= 500
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
return;
|
|
190
|
+
const url = `${apiUrl}${streamPath}`;
|
|
191
|
+
const mergedHeaders = {
|
|
192
|
+
"Content-Type": "application/json",
|
|
193
|
+
Accept: "text/event-stream",
|
|
194
|
+
...headers
|
|
195
|
+
};
|
|
196
|
+
const requestBody = {
|
|
197
|
+
message: content,
|
|
198
|
+
conversation_id: state.conversationId,
|
|
199
|
+
...bodyExtra
|
|
200
|
+
};
|
|
201
|
+
if (attachments && attachments.length > 0) {
|
|
202
|
+
requestBody.attachments = attachments.map((a) => ({
|
|
203
|
+
filename: a.filename,
|
|
204
|
+
content_type: a.content_type,
|
|
205
|
+
data: a.data
|
|
206
|
+
}));
|
|
194
207
|
}
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
208
|
+
const body = JSON.stringify(requestBody);
|
|
209
|
+
const handleEvent = (event) => {
|
|
210
|
+
switch (event.type) {
|
|
211
|
+
case "agent":
|
|
212
|
+
ctx.capturedAgent = event.agent;
|
|
213
|
+
dispatch({ type: "STREAM_AGENT", agent: ctx.capturedAgent });
|
|
214
|
+
break;
|
|
215
|
+
case "phase":
|
|
216
|
+
dispatch({ type: "STREAM_PHASE", phase: event.phase });
|
|
217
|
+
break;
|
|
218
|
+
case "delta":
|
|
219
|
+
ctx.accumulatedContent += event.content;
|
|
220
|
+
dispatch({ type: "STREAM_CONTENT", content: event.content });
|
|
221
|
+
break;
|
|
222
|
+
case "delta_reset":
|
|
223
|
+
ctx.accumulatedContent = "";
|
|
224
|
+
dispatch({ type: "STREAM_CONTENT_RESET" });
|
|
225
|
+
break;
|
|
226
|
+
case "done":
|
|
227
|
+
ctx.agentResponse = event.response;
|
|
228
|
+
ctx.capturedConversationId = event.conversation_id ?? null;
|
|
229
|
+
break;
|
|
230
|
+
case "error":
|
|
231
|
+
ctx.hadStreamError = true;
|
|
232
|
+
dispatch({ type: "SEND_ERROR", error: event.error });
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
const { streamAdapter } = configRef.current;
|
|
237
|
+
if (streamAdapter) {
|
|
238
|
+
await streamAdapter(
|
|
239
|
+
url,
|
|
240
|
+
{ method: "POST", headers: mergedHeaders, body, signal: controller.signal },
|
|
241
|
+
handleEvent
|
|
242
|
+
);
|
|
243
|
+
clearTimeout(timeoutId);
|
|
244
|
+
} else {
|
|
245
|
+
const response = await fetch(url, {
|
|
246
|
+
method: "POST",
|
|
247
|
+
headers: mergedHeaders,
|
|
248
|
+
body,
|
|
249
|
+
signal: controller.signal
|
|
200
250
|
});
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
dispatch({ type: "SEND_ERROR", error: event.error });
|
|
238
|
-
return;
|
|
251
|
+
clearTimeout(timeoutId);
|
|
252
|
+
if (!response.ok) {
|
|
253
|
+
dispatch({
|
|
254
|
+
type: "SEND_ERROR",
|
|
255
|
+
error: {
|
|
256
|
+
code: "API_ERROR",
|
|
257
|
+
message: `HTTP ${response.status}: ${response.statusText}`,
|
|
258
|
+
retryable: response.status >= 500
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const reader = response.body?.getReader();
|
|
264
|
+
if (!reader) {
|
|
265
|
+
dispatch({
|
|
266
|
+
type: "SEND_ERROR",
|
|
267
|
+
error: { code: "STREAM_ERROR", message: "No response body", retryable: true }
|
|
268
|
+
});
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const decoder = new TextDecoder();
|
|
272
|
+
let buffer = "";
|
|
273
|
+
while (true) {
|
|
274
|
+
const { done, value } = await reader.read();
|
|
275
|
+
if (done) break;
|
|
276
|
+
buffer += decoder.decode(value, { stream: true });
|
|
277
|
+
const lines = buffer.split("\n");
|
|
278
|
+
buffer = lines.pop() ?? "";
|
|
279
|
+
for (const line of lines) {
|
|
280
|
+
if (!line.startsWith("data: ")) continue;
|
|
281
|
+
const data = line.slice(6).trim();
|
|
282
|
+
if (data === "[DONE]") continue;
|
|
283
|
+
try {
|
|
284
|
+
const event = JSON.parse(data);
|
|
285
|
+
handleEvent(event);
|
|
286
|
+
} catch {
|
|
239
287
|
}
|
|
240
|
-
} catch {
|
|
241
288
|
}
|
|
242
289
|
}
|
|
243
290
|
}
|
|
291
|
+
if (ctx.hadStreamError) return;
|
|
244
292
|
const assistantMessage = {
|
|
245
293
|
id: generateMessageId(),
|
|
246
294
|
role: "assistant",
|
|
247
|
-
content: agentResponse?.message ?? accumulatedContent,
|
|
248
|
-
response: agentResponse ?? void 0,
|
|
249
|
-
agent: capturedAgent ?? void 0,
|
|
295
|
+
content: ctx.agentResponse?.message ?? ctx.accumulatedContent,
|
|
296
|
+
response: ctx.agentResponse ?? void 0,
|
|
297
|
+
agent: ctx.capturedAgent ?? void 0,
|
|
250
298
|
timestamp: /* @__PURE__ */ new Date()
|
|
251
299
|
};
|
|
252
300
|
dispatch({
|
|
253
301
|
type: "SEND_SUCCESS",
|
|
254
302
|
message: assistantMessage,
|
|
255
|
-
streamingContent: accumulatedContent,
|
|
256
|
-
conversationId: capturedConversationId
|
|
303
|
+
streamingContent: ctx.accumulatedContent,
|
|
304
|
+
conversationId: ctx.capturedConversationId
|
|
257
305
|
});
|
|
258
306
|
} catch (err) {
|
|
259
307
|
clearTimeout(timeoutId);
|
|
260
308
|
if (err.name === "AbortError") {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
309
|
+
if (ctx.accumulatedContent) {
|
|
310
|
+
const partialMessage = {
|
|
311
|
+
id: generateMessageId(),
|
|
312
|
+
role: "assistant",
|
|
313
|
+
content: ctx.accumulatedContent,
|
|
314
|
+
agent: ctx.capturedAgent ?? void 0,
|
|
315
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
316
|
+
};
|
|
317
|
+
dispatch({
|
|
318
|
+
type: "SEND_SUCCESS",
|
|
319
|
+
message: partialMessage,
|
|
320
|
+
streamingContent: ctx.accumulatedContent,
|
|
321
|
+
conversationId: ctx.capturedConversationId
|
|
322
|
+
});
|
|
323
|
+
} else {
|
|
324
|
+
dispatch({
|
|
325
|
+
type: "SEND_ERROR",
|
|
326
|
+
error: { code: "ABORTED", message: "Request stopped", retryable: true }
|
|
327
|
+
});
|
|
328
|
+
}
|
|
265
329
|
} else {
|
|
266
330
|
dispatch({
|
|
267
331
|
type: "SEND_ERROR",
|
|
@@ -272,6 +336,8 @@ function useAgentChat(config2) {
|
|
|
272
336
|
}
|
|
273
337
|
});
|
|
274
338
|
}
|
|
339
|
+
} finally {
|
|
340
|
+
abortControllerRef.current = null;
|
|
275
341
|
}
|
|
276
342
|
},
|
|
277
343
|
[state.conversationId]
|
|
@@ -284,7 +350,8 @@ function useAgentChat(config2) {
|
|
|
284
350
|
}, []);
|
|
285
351
|
const submitFeedback = (0, import_react.useCallback)(
|
|
286
352
|
async (messageId, rating, comment) => {
|
|
287
|
-
const { apiUrl, feedbackPath = "/feedback", headers
|
|
353
|
+
const { apiUrl, feedbackPath = "/feedback", headers: headersOrFn } = configRef.current;
|
|
354
|
+
const headers = typeof headersOrFn === "function" ? await headersOrFn() : headersOrFn ?? {};
|
|
288
355
|
await fetch(`${apiUrl}${feedbackPath}`, {
|
|
289
356
|
method: "POST",
|
|
290
357
|
headers: { "Content-Type": "application/json", ...headers },
|
|
@@ -295,12 +362,16 @@ function useAgentChat(config2) {
|
|
|
295
362
|
);
|
|
296
363
|
const retry = (0, import_react.useCallback)(async () => {
|
|
297
364
|
if (lastUserMessageRef.current) {
|
|
298
|
-
await sendMessage(lastUserMessageRef.current);
|
|
365
|
+
await sendMessage(lastUserMessageRef.current, lastUserAttachmentsRef.current);
|
|
299
366
|
}
|
|
300
367
|
}, [sendMessage]);
|
|
368
|
+
const stop = (0, import_react.useCallback)(() => {
|
|
369
|
+
abortControllerRef.current?.abort();
|
|
370
|
+
}, []);
|
|
301
371
|
const reset = (0, import_react.useCallback)(() => {
|
|
302
372
|
dispatch({ type: "RESET" });
|
|
303
373
|
lastUserMessageRef.current = null;
|
|
374
|
+
lastUserAttachmentsRef.current = void 0;
|
|
304
375
|
}, []);
|
|
305
376
|
const actions = {
|
|
306
377
|
sendMessage,
|
|
@@ -308,6 +379,7 @@ function useAgentChat(config2) {
|
|
|
308
379
|
loadConversation,
|
|
309
380
|
submitFeedback,
|
|
310
381
|
retry,
|
|
382
|
+
stop,
|
|
311
383
|
reset
|
|
312
384
|
};
|
|
313
385
|
return { state, actions };
|
|
@@ -315,7 +387,7 @@ function useAgentChat(config2) {
|
|
|
315
387
|
|
|
316
388
|
// src/chat/MessageThread/MessageThread.tsx
|
|
317
389
|
var import_tailwind_merge5 = require("tailwind-merge");
|
|
318
|
-
var
|
|
390
|
+
var import_react4 = require("react");
|
|
319
391
|
|
|
320
392
|
// src/chat/MessageBubble/MessageBubble.tsx
|
|
321
393
|
var import_tailwind_merge4 = require("tailwind-merge");
|
|
@@ -324,8 +396,10 @@ var import_tailwind_merge4 = require("tailwind-merge");
|
|
|
324
396
|
var import_core2 = require("@surf-kit/core");
|
|
325
397
|
|
|
326
398
|
// src/response/ResponseMessage/ResponseMessage.tsx
|
|
399
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
327
400
|
var import_react_markdown = __toESM(require("react-markdown"), 1);
|
|
328
401
|
var import_rehype_sanitize = __toESM(require("rehype-sanitize"), 1);
|
|
402
|
+
var import_remark_gfm = __toESM(require("remark-gfm"), 1);
|
|
329
403
|
var import_tailwind_merge = require("tailwind-merge");
|
|
330
404
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
331
405
|
function normalizeMarkdownLists(content) {
|
|
@@ -348,7 +422,12 @@ function ResponseMessage({ content, className }) {
|
|
|
348
422
|
"[&_h3]:text-sm [&_h3]:font-semibold [&_h3]:text-accent [&_h3]:mt-2 [&_h3]:mb-1",
|
|
349
423
|
"[&_code]:bg-surface-raised [&_code]:text-accent [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-xs [&_code]:font-mono",
|
|
350
424
|
"[&_pre]:bg-surface-raised [&_pre]:border [&_pre]:border-border [&_pre]:rounded-xl [&_pre]:p-4 [&_pre]:overflow-x-auto",
|
|
425
|
+
"[&_hr]:my-3 [&_hr]:border-border",
|
|
351
426
|
"[&_blockquote]:border-l-2 [&_blockquote]:border-border-strong [&_blockquote]:pl-4 [&_blockquote]:text-text-secondary",
|
|
427
|
+
"[&_table]:w-full [&_table]:text-sm [&_table]:border-collapse [&_table]:my-2",
|
|
428
|
+
"[&_thead]:border-b [&_thead]:border-border",
|
|
429
|
+
"[&_th]:text-left [&_th]:px-2 [&_th]:py-1.5 [&_th]:font-semibold",
|
|
430
|
+
"[&_td]:px-2 [&_td]:py-1.5 [&_td]:border-t [&_td]:border-border/50",
|
|
352
431
|
"[&_a]:text-accent [&_a]:underline-offset-2 [&_a]:hover:text-accent/80",
|
|
353
432
|
className
|
|
354
433
|
),
|
|
@@ -356,6 +435,7 @@ function ResponseMessage({ content, className }) {
|
|
|
356
435
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
357
436
|
import_react_markdown.default,
|
|
358
437
|
{
|
|
438
|
+
remarkPlugins: [import_remark_gfm.default],
|
|
359
439
|
rehypePlugins: [import_rehype_sanitize.default],
|
|
360
440
|
components: {
|
|
361
441
|
script: () => null,
|
|
@@ -363,12 +443,29 @@ function ResponseMessage({ content, className }) {
|
|
|
363
443
|
p: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "my-2", children }),
|
|
364
444
|
ul: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "my-2 list-disc pl-6", children }),
|
|
365
445
|
ol: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "my-2 list-decimal pl-6", children }),
|
|
366
|
-
li: ({ children }) =>
|
|
446
|
+
li: ({ children, ...props }) => {
|
|
447
|
+
let content2 = children;
|
|
448
|
+
if (props.ordered) {
|
|
449
|
+
content2 = import_react2.default.Children.map(children, (child, i) => {
|
|
450
|
+
if (i === 0 && typeof child === "string") {
|
|
451
|
+
return child.replace(/^\d+[.)]\s*/, "");
|
|
452
|
+
}
|
|
453
|
+
return child;
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: "my-1", children: content2 });
|
|
457
|
+
},
|
|
367
458
|
strong: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { className: "font-semibold", children }),
|
|
459
|
+
em: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("em", { className: "italic text-text-secondary", children }),
|
|
368
460
|
h1: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "text-base font-bold mt-4 mb-2", children }),
|
|
369
461
|
h2: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-sm font-bold mt-3 mb-1", children }),
|
|
370
462
|
h3: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "text-sm font-semibold mt-2 mb-1", children }),
|
|
371
|
-
|
|
463
|
+
hr: () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("hr", { className: "my-3 border-border" }),
|
|
464
|
+
code: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children }),
|
|
465
|
+
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 }) }),
|
|
466
|
+
thead: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { className: "border-b border-border", children }),
|
|
467
|
+
th: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { className: "text-left px-2 py-1.5 font-semibold", children }),
|
|
468
|
+
td: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { className: "px-2 py-1.5 border-t border-border/50", children })
|
|
372
469
|
},
|
|
373
470
|
children: normalizeMarkdownLists(content)
|
|
374
471
|
}
|
|
@@ -378,6 +475,8 @@ function ResponseMessage({ content, className }) {
|
|
|
378
475
|
}
|
|
379
476
|
|
|
380
477
|
// src/response/StructuredResponse/StructuredResponse.tsx
|
|
478
|
+
var import_react_markdown2 = __toESM(require("react-markdown"), 1);
|
|
479
|
+
var import_rehype_sanitize2 = __toESM(require("rehype-sanitize"), 1);
|
|
381
480
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
382
481
|
function tryParse(value) {
|
|
383
482
|
if (value === void 0 || value === null) return null;
|
|
@@ -390,6 +489,25 @@ function tryParse(value) {
|
|
|
390
489
|
}
|
|
391
490
|
return value;
|
|
392
491
|
}
|
|
492
|
+
function InlineMarkdown({ text }) {
|
|
493
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
494
|
+
import_react_markdown2.default,
|
|
495
|
+
{
|
|
496
|
+
rehypePlugins: [import_rehype_sanitize2.default],
|
|
497
|
+
components: {
|
|
498
|
+
// Unwrap block-level <p> so content stays inline within its parent
|
|
499
|
+
p: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children }),
|
|
500
|
+
strong: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { className: "font-semibold", children }),
|
|
501
|
+
em: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("em", { className: "italic", children }),
|
|
502
|
+
code: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children }),
|
|
503
|
+
// Prevent block elements that would break layout
|
|
504
|
+
script: () => null,
|
|
505
|
+
iframe: () => null
|
|
506
|
+
},
|
|
507
|
+
children: text
|
|
508
|
+
}
|
|
509
|
+
);
|
|
510
|
+
}
|
|
393
511
|
function renderSteps(data) {
|
|
394
512
|
const steps = tryParse(data.steps);
|
|
395
513
|
if (!steps || !Array.isArray(steps)) return null;
|
|
@@ -402,7 +520,7 @@ function renderSteps(data) {
|
|
|
402
520
|
children: i + 1
|
|
403
521
|
}
|
|
404
522
|
),
|
|
405
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm text-text-primary leading-relaxed", children: step })
|
|
523
|
+
/* @__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 }) })
|
|
406
524
|
] }, i)) });
|
|
407
525
|
}
|
|
408
526
|
function renderTable(data) {
|
|
@@ -468,7 +586,7 @@ function renderList(data) {
|
|
|
468
586
|
title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs font-semibold uppercase tracking-wider text-text-secondary mb-1", children: title }),
|
|
469
587
|
/* @__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: [
|
|
470
588
|
/* @__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" }),
|
|
471
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm text-text-primary leading-relaxed", children: item })
|
|
589
|
+
/* @__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 }) })
|
|
472
590
|
] }, i)) })
|
|
473
591
|
] });
|
|
474
592
|
}
|
|
@@ -503,7 +621,14 @@ function renderWarning(data) {
|
|
|
503
621
|
}
|
|
504
622
|
);
|
|
505
623
|
}
|
|
506
|
-
function StructuredResponse({ uiHint, data, className }) {
|
|
624
|
+
function StructuredResponse({ uiHint, data: rawData, className }) {
|
|
625
|
+
const data = typeof rawData === "string" ? (() => {
|
|
626
|
+
try {
|
|
627
|
+
return JSON.parse(rawData);
|
|
628
|
+
} catch {
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
})() : rawData;
|
|
507
632
|
if (!data) return null;
|
|
508
633
|
let content;
|
|
509
634
|
switch (uiHint) {
|
|
@@ -533,7 +658,7 @@ function StructuredResponse({ uiHint, data, className }) {
|
|
|
533
658
|
}
|
|
534
659
|
|
|
535
660
|
// src/sources/SourceList/SourceList.tsx
|
|
536
|
-
var
|
|
661
|
+
var import_react3 = require("react");
|
|
537
662
|
|
|
538
663
|
// src/sources/SourceCard/SourceCard.tsx
|
|
539
664
|
var import_core = require("@surf-kit/core");
|
|
@@ -583,7 +708,36 @@ function SourceCard({ source, variant = "compact", onNavigate, className }) {
|
|
|
583
708
|
children: [
|
|
584
709
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
|
|
585
710
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
586
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
711
|
+
source.url ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
712
|
+
"a",
|
|
713
|
+
{
|
|
714
|
+
href: source.url,
|
|
715
|
+
target: "_blank",
|
|
716
|
+
rel: "noopener noreferrer",
|
|
717
|
+
className: "text-sm font-medium text-accent hover:underline truncate block",
|
|
718
|
+
onClick: (e) => e.stopPropagation(),
|
|
719
|
+
children: [
|
|
720
|
+
source.title,
|
|
721
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
722
|
+
"svg",
|
|
723
|
+
{
|
|
724
|
+
className: "inline-block ml-1 w-3 h-3 opacity-60",
|
|
725
|
+
viewBox: "0 0 24 24",
|
|
726
|
+
fill: "none",
|
|
727
|
+
stroke: "currentColor",
|
|
728
|
+
strokeWidth: "2",
|
|
729
|
+
strokeLinecap: "round",
|
|
730
|
+
strokeLinejoin: "round",
|
|
731
|
+
children: [
|
|
732
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6" }),
|
|
733
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "15 3 21 3 21 9" }),
|
|
734
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
|
|
735
|
+
]
|
|
736
|
+
}
|
|
737
|
+
)
|
|
738
|
+
]
|
|
739
|
+
}
|
|
740
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-sm font-medium text-text-primary truncate", children: source.title }),
|
|
587
741
|
source.section && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-[11px] font-semibold uppercase tracking-wider text-text-secondary truncate mt-0.5", children: source.section })
|
|
588
742
|
] }),
|
|
589
743
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -613,7 +767,7 @@ function SourceList({
|
|
|
613
767
|
onNavigate,
|
|
614
768
|
className
|
|
615
769
|
}) {
|
|
616
|
-
const [isExpanded, setIsExpanded] = (0,
|
|
770
|
+
const [isExpanded, setIsExpanded] = (0, import_react3.useState)(defaultExpanded);
|
|
617
771
|
if (sources.length === 0) return null;
|
|
618
772
|
const content = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex flex-col gap-1.5", "data-testid": "source-list-items", children: sources.map((source) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
619
773
|
SourceCard,
|
|
@@ -717,13 +871,16 @@ function AgentResponse({
|
|
|
717
871
|
}) {
|
|
718
872
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `flex flex-col gap-4 ${className ?? ""}`, "data-testid": "agent-response", children: [
|
|
719
873
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ResponseMessage, { content: response.message }),
|
|
720
|
-
response.ui_hint !== "text" && response.structured_data &&
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
874
|
+
response.ui_hint !== "text" && response.structured_data && (() => {
|
|
875
|
+
const parsed = typeof response.structured_data === "string" ? (() => {
|
|
876
|
+
try {
|
|
877
|
+
return JSON.parse(response.structured_data);
|
|
878
|
+
} catch {
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
})() : response.structured_data;
|
|
882
|
+
return parsed ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StructuredResponse, { uiHint: response.ui_hint, data: parsed }) : null;
|
|
883
|
+
})(),
|
|
727
884
|
(showConfidence || showVerification) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-2 mt-1", "data-testid": "response-meta", children: [
|
|
728
885
|
showConfidence && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
729
886
|
import_core2.Badge,
|
|
@@ -774,6 +931,31 @@ function AgentResponse({
|
|
|
774
931
|
|
|
775
932
|
// src/chat/MessageBubble/MessageBubble.tsx
|
|
776
933
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
934
|
+
function DocumentIcon() {
|
|
935
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
936
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" }),
|
|
937
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("polyline", { points: "14 2 14 8 20 8" }),
|
|
938
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "16", y1: "13", x2: "8", y2: "13" }),
|
|
939
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("line", { x1: "16", y1: "17", x2: "8", y2: "17" })
|
|
940
|
+
] });
|
|
941
|
+
}
|
|
942
|
+
function AttachmentThumbnail({ attachment }) {
|
|
943
|
+
const isImage = attachment.content_type.startsWith("image/");
|
|
944
|
+
if (isImage) {
|
|
945
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "rounded-lg overflow-hidden border border-black/10 max-w-[240px]", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
946
|
+
"img",
|
|
947
|
+
{
|
|
948
|
+
src: attachment.preview_url ?? `data:${attachment.content_type};base64,${attachment.data}`,
|
|
949
|
+
alt: attachment.filename,
|
|
950
|
+
className: "max-w-full max-h-[200px] object-contain"
|
|
951
|
+
}
|
|
952
|
+
) });
|
|
953
|
+
}
|
|
954
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2 px-3 py-2 rounded-lg border border-black/10 bg-black/5", children: [
|
|
955
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DocumentIcon, {}),
|
|
956
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-xs truncate max-w-[160px]", children: attachment.filename })
|
|
957
|
+
] });
|
|
958
|
+
}
|
|
777
959
|
function MessageBubble({
|
|
778
960
|
message,
|
|
779
961
|
showAgent,
|
|
@@ -781,23 +963,29 @@ function MessageBubble({
|
|
|
781
963
|
showConfidence = true,
|
|
782
964
|
showVerification = true,
|
|
783
965
|
animated = true,
|
|
966
|
+
userBubbleClassName,
|
|
784
967
|
className
|
|
785
968
|
}) {
|
|
786
969
|
const isUser = message.role === "user";
|
|
970
|
+
const hasAttachments = message.attachments && message.attachments.length > 0;
|
|
787
971
|
if (isUser) {
|
|
788
972
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
789
973
|
"div",
|
|
790
974
|
{
|
|
791
975
|
"data-message-id": message.id,
|
|
792
976
|
className: (0, import_tailwind_merge4.twMerge)("flex w-full justify-end", className),
|
|
793
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime7.
|
|
977
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
794
978
|
"div",
|
|
795
979
|
{
|
|
796
980
|
className: (0, import_tailwind_merge4.twMerge)(
|
|
797
|
-
"max-w-[70%] rounded-[18px] rounded-br-[4px] px-4 py-2.5 bg-
|
|
798
|
-
animated && "motion-safe:animate-slideFromRight"
|
|
981
|
+
"max-w-[70%] rounded-[18px] rounded-br-[4px] px-4 py-2.5 bg-[#e8e8e8] text-[#1a1a1a] break-words whitespace-pre-wrap text-sm leading-relaxed",
|
|
982
|
+
animated && "motion-safe:animate-slideFromRight",
|
|
983
|
+
userBubbleClassName
|
|
799
984
|
),
|
|
800
|
-
children:
|
|
985
|
+
children: [
|
|
986
|
+
hasAttachments && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex flex-wrap gap-2 mb-2", children: message.attachments.map((att, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AttachmentThumbnail, { attachment: att }, `${att.filename}-${i}`)) }),
|
|
987
|
+
message.content
|
|
988
|
+
]
|
|
801
989
|
}
|
|
802
990
|
)
|
|
803
991
|
}
|
|
@@ -809,7 +997,7 @@ function MessageBubble({
|
|
|
809
997
|
"data-message-id": message.id,
|
|
810
998
|
className: (0, import_tailwind_merge4.twMerge)("flex w-full flex-col items-start gap-1.5", className),
|
|
811
999
|
children: [
|
|
812
|
-
showAgent && message.agent && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-[11px] font-semibold uppercase tracking-[0.08em] text-text-muted px-1", children: message.agent.replace("_agent", "").replace("_", " ") }),
|
|
1000
|
+
showAgent && message.agent && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-[11px] font-display font-semibold uppercase tracking-[0.08em] text-text-muted px-1", children: message.agent.replace("_agent", "").replace("_", " ") }),
|
|
813
1001
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
814
1002
|
"div",
|
|
815
1003
|
{
|
|
@@ -835,34 +1023,97 @@ function MessageBubble({
|
|
|
835
1023
|
|
|
836
1024
|
// src/chat/MessageThread/MessageThread.tsx
|
|
837
1025
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
838
|
-
function MessageThread({ messages, streamingSlot, showSources, showConfidence, showVerification, className }) {
|
|
839
|
-
const
|
|
840
|
-
(0,
|
|
841
|
-
|
|
842
|
-
|
|
1026
|
+
function MessageThread({ messages, streamingSlot, showAgent, showSources, showConfidence, showVerification, hideLastAssistant, userBubbleClassName, className }) {
|
|
1027
|
+
const scrollRef = (0, import_react4.useRef)(null);
|
|
1028
|
+
const shouldAutoScroll = (0, import_react4.useRef)(true);
|
|
1029
|
+
const hasStreaming = !!streamingSlot;
|
|
1030
|
+
const scrollToBottom = (0, import_react4.useCallback)(() => {
|
|
1031
|
+
const el = scrollRef.current;
|
|
1032
|
+
if (el && shouldAutoScroll.current) {
|
|
1033
|
+
el.scrollTop = el.scrollHeight;
|
|
1034
|
+
}
|
|
1035
|
+
}, []);
|
|
1036
|
+
(0, import_react4.useEffect)(() => {
|
|
1037
|
+
const el = scrollRef.current;
|
|
1038
|
+
if (!el) return;
|
|
1039
|
+
const onWheel = (e) => {
|
|
1040
|
+
if (e.deltaY < 0) {
|
|
1041
|
+
shouldAutoScroll.current = false;
|
|
1042
|
+
}
|
|
1043
|
+
};
|
|
1044
|
+
const onPointerDown = () => {
|
|
1045
|
+
el.dataset.userPointer = "1";
|
|
1046
|
+
};
|
|
1047
|
+
const onPointerUp = () => {
|
|
1048
|
+
delete el.dataset.userPointer;
|
|
1049
|
+
};
|
|
1050
|
+
el.addEventListener("wheel", onWheel, { passive: true });
|
|
1051
|
+
el.addEventListener("pointerdown", onPointerDown);
|
|
1052
|
+
window.addEventListener("pointerup", onPointerUp);
|
|
1053
|
+
return () => {
|
|
1054
|
+
el.removeEventListener("wheel", onWheel);
|
|
1055
|
+
el.removeEventListener("pointerdown", onPointerDown);
|
|
1056
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
1057
|
+
};
|
|
1058
|
+
}, []);
|
|
1059
|
+
const handleScroll = (0, import_react4.useCallback)(() => {
|
|
1060
|
+
const el = scrollRef.current;
|
|
1061
|
+
if (!el) return;
|
|
1062
|
+
const nearBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 80;
|
|
1063
|
+
if (nearBottom) {
|
|
1064
|
+
shouldAutoScroll.current = true;
|
|
1065
|
+
} else if (el.dataset.userPointer) {
|
|
1066
|
+
shouldAutoScroll.current = false;
|
|
1067
|
+
}
|
|
1068
|
+
}, []);
|
|
1069
|
+
(0, import_react4.useEffect)(scrollToBottom, [messages.length, scrollToBottom]);
|
|
1070
|
+
(0, import_react4.useEffect)(() => {
|
|
1071
|
+
if (!hasStreaming) return;
|
|
1072
|
+
let raf;
|
|
1073
|
+
const tick = () => {
|
|
1074
|
+
scrollToBottom();
|
|
1075
|
+
raf = requestAnimationFrame(tick);
|
|
1076
|
+
};
|
|
1077
|
+
raf = requestAnimationFrame(tick);
|
|
1078
|
+
return () => cancelAnimationFrame(raf);
|
|
1079
|
+
}, [hasStreaming, scrollToBottom]);
|
|
1080
|
+
(0, import_react4.useEffect)(() => {
|
|
1081
|
+
if (!hasStreaming) {
|
|
1082
|
+
shouldAutoScroll.current = true;
|
|
1083
|
+
}
|
|
1084
|
+
}, [hasStreaming]);
|
|
843
1085
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
844
1086
|
"div",
|
|
845
1087
|
{
|
|
1088
|
+
ref: scrollRef,
|
|
846
1089
|
role: "log",
|
|
847
1090
|
"aria-live": "polite",
|
|
848
1091
|
"aria-label": "Message thread",
|
|
1092
|
+
onScroll: handleScroll,
|
|
849
1093
|
className: (0, import_tailwind_merge5.twMerge)(
|
|
850
1094
|
"flex flex-col gap-4 overflow-y-auto flex-1 px-4 py-6",
|
|
851
1095
|
className
|
|
852
1096
|
),
|
|
853
1097
|
children: [
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
{
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1098
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex-1 shrink-0" }),
|
|
1099
|
+
messages.map((message, i) => {
|
|
1100
|
+
if (hideLastAssistant && i === messages.length - 1 && message.role === "assistant") {
|
|
1101
|
+
return null;
|
|
1102
|
+
}
|
|
1103
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1104
|
+
MessageBubble,
|
|
1105
|
+
{
|
|
1106
|
+
message,
|
|
1107
|
+
showAgent,
|
|
1108
|
+
showSources,
|
|
1109
|
+
showConfidence,
|
|
1110
|
+
showVerification,
|
|
1111
|
+
userBubbleClassName
|
|
1112
|
+
},
|
|
1113
|
+
message.id
|
|
1114
|
+
);
|
|
1115
|
+
}),
|
|
1116
|
+
streamingSlot
|
|
866
1117
|
]
|
|
867
1118
|
}
|
|
868
1119
|
);
|
|
@@ -870,32 +1121,127 @@ function MessageThread({ messages, streamingSlot, showSources, showConfidence, s
|
|
|
870
1121
|
|
|
871
1122
|
// src/chat/MessageComposer/MessageComposer.tsx
|
|
872
1123
|
var import_tailwind_merge6 = require("tailwind-merge");
|
|
873
|
-
var
|
|
1124
|
+
var import_react5 = require("react");
|
|
874
1125
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1126
|
+
var ALLOWED_TYPES = /* @__PURE__ */ new Set([
|
|
1127
|
+
"image/png",
|
|
1128
|
+
"image/jpeg",
|
|
1129
|
+
"image/gif",
|
|
1130
|
+
"image/webp",
|
|
1131
|
+
"application/pdf"
|
|
1132
|
+
]);
|
|
1133
|
+
var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
1134
|
+
var MAX_ATTACHMENTS = 5;
|
|
1135
|
+
function ArrowUpIcon() {
|
|
1136
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1137
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M10 16V4" }),
|
|
1138
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M4 10l6-6 6 6" })
|
|
1139
|
+
] });
|
|
1140
|
+
}
|
|
1141
|
+
function StopIcon() {
|
|
1142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("rect", { x: "3", y: "3", width: "10", height: "10", rx: "2" }) });
|
|
1143
|
+
}
|
|
1144
|
+
function PaperclipIcon() {
|
|
1145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48" }) });
|
|
1146
|
+
}
|
|
1147
|
+
function XIcon({ size = 14 }) {
|
|
1148
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1149
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M18 6L6 18" }),
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M6 6l12 12" })
|
|
1151
|
+
] });
|
|
1152
|
+
}
|
|
1153
|
+
function DocumentIcon2() {
|
|
1154
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1155
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("path", { d: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" }),
|
|
1156
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "14 2 14 8 20 8" }),
|
|
1157
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "16", y1: "13", x2: "8", y2: "13" }),
|
|
1158
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "16", y1: "17", x2: "8", y2: "17" }),
|
|
1159
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("polyline", { points: "10 9 9 9 8 9" })
|
|
1160
|
+
] });
|
|
1161
|
+
}
|
|
1162
|
+
function fileToBase64(file) {
|
|
1163
|
+
return new Promise((resolve, reject) => {
|
|
1164
|
+
const reader = new FileReader();
|
|
1165
|
+
reader.onload = () => {
|
|
1166
|
+
const result = reader.result;
|
|
1167
|
+
const base64 = result.split(",")[1];
|
|
1168
|
+
resolve(base64);
|
|
1169
|
+
};
|
|
1170
|
+
reader.onerror = reject;
|
|
1171
|
+
reader.readAsDataURL(file);
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
function AttachmentPreview({
|
|
1175
|
+
attachment,
|
|
1176
|
+
onRemove
|
|
1177
|
+
}) {
|
|
1178
|
+
const isImage = attachment.content_type.startsWith("image/");
|
|
1179
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "relative group flex-shrink-0", children: [
|
|
1180
|
+
isImage ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-16 h-16 rounded-lg overflow-hidden border border-border/60 bg-surface-alt", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1181
|
+
"img",
|
|
1182
|
+
{
|
|
1183
|
+
src: attachment.preview_url ?? `data:${attachment.content_type};base64,${attachment.data}`,
|
|
1184
|
+
alt: attachment.filename,
|
|
1185
|
+
className: "w-full h-full object-cover"
|
|
1186
|
+
}
|
|
1187
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "h-16 px-3 rounded-lg border border-border/60 bg-surface-alt flex items-center gap-2", children: [
|
|
1188
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-text-muted", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DocumentIcon2, {}) }),
|
|
1189
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col min-w-0", children: [
|
|
1190
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs text-text-primary truncate max-w-[120px]", children: attachment.filename }),
|
|
1191
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-[10px] text-text-muted", children: "PDF" })
|
|
1192
|
+
] })
|
|
1193
|
+
] }),
|
|
1194
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1195
|
+
"button",
|
|
1196
|
+
{
|
|
1197
|
+
type: "button",
|
|
1198
|
+
onClick: onRemove,
|
|
1199
|
+
className: (0, import_tailwind_merge6.twMerge)(
|
|
1200
|
+
"absolute -top-1.5 -right-1.5",
|
|
1201
|
+
"w-5 h-5 rounded-full",
|
|
1202
|
+
"bg-text-muted/80 text-white",
|
|
1203
|
+
"flex items-center justify-center",
|
|
1204
|
+
"opacity-0 group-hover:opacity-100",
|
|
1205
|
+
"transition-opacity duration-150",
|
|
1206
|
+
"hover:bg-text-primary"
|
|
1207
|
+
),
|
|
1208
|
+
"aria-label": `Remove ${attachment.filename}`,
|
|
1209
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(XIcon, { size: 10 })
|
|
1210
|
+
}
|
|
1211
|
+
)
|
|
1212
|
+
] });
|
|
1213
|
+
}
|
|
875
1214
|
function MessageComposer({
|
|
876
1215
|
onSend,
|
|
1216
|
+
onStop,
|
|
877
1217
|
isLoading = false,
|
|
878
1218
|
placeholder = "Type a message...",
|
|
879
1219
|
className
|
|
880
1220
|
}) {
|
|
881
|
-
const [value, setValue] = (0,
|
|
882
|
-
const
|
|
883
|
-
const
|
|
884
|
-
const
|
|
1221
|
+
const [value, setValue] = (0, import_react5.useState)("");
|
|
1222
|
+
const [attachments, setAttachments] = (0, import_react5.useState)([]);
|
|
1223
|
+
const [dragOver, setDragOver] = (0, import_react5.useState)(false);
|
|
1224
|
+
const textareaRef = (0, import_react5.useRef)(null);
|
|
1225
|
+
const fileInputRef = (0, import_react5.useRef)(null);
|
|
1226
|
+
const canSend = (value.trim().length > 0 || attachments.length > 0) && !isLoading;
|
|
1227
|
+
const resetHeight = (0, import_react5.useCallback)(() => {
|
|
885
1228
|
const el = textareaRef.current;
|
|
886
1229
|
if (el) {
|
|
887
1230
|
el.style.height = "auto";
|
|
888
1231
|
el.style.overflowY = "hidden";
|
|
889
1232
|
}
|
|
890
1233
|
}, []);
|
|
891
|
-
const handleSend = (0,
|
|
1234
|
+
const handleSend = (0, import_react5.useCallback)(() => {
|
|
892
1235
|
if (!canSend) return;
|
|
893
|
-
|
|
1236
|
+
const message = value.trim() || (attachments.length > 0 ? "Please analyse the attached file(s)." : "");
|
|
1237
|
+
if (!message && attachments.length === 0) return;
|
|
1238
|
+
onSend(message, attachments.length > 0 ? attachments : void 0);
|
|
894
1239
|
setValue("");
|
|
1240
|
+
setAttachments([]);
|
|
895
1241
|
resetHeight();
|
|
896
1242
|
textareaRef.current?.focus();
|
|
897
|
-
}, [canSend, onSend, value, resetHeight]);
|
|
898
|
-
const handleKeyDown = (0,
|
|
1243
|
+
}, [canSend, onSend, value, attachments, resetHeight]);
|
|
1244
|
+
const handleKeyDown = (0, import_react5.useCallback)(
|
|
899
1245
|
(e) => {
|
|
900
1246
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
901
1247
|
e.preventDefault();
|
|
@@ -904,64 +1250,194 @@ function MessageComposer({
|
|
|
904
1250
|
},
|
|
905
1251
|
[handleSend]
|
|
906
1252
|
);
|
|
907
|
-
const handleChange = (0,
|
|
1253
|
+
const handleChange = (0, import_react5.useCallback)(
|
|
908
1254
|
(e) => {
|
|
909
1255
|
setValue(e.target.value);
|
|
910
1256
|
const el = e.target;
|
|
911
1257
|
el.style.height = "auto";
|
|
912
|
-
const capped = Math.min(el.scrollHeight,
|
|
1258
|
+
const capped = Math.min(el.scrollHeight, 200);
|
|
913
1259
|
el.style.height = `${capped}px`;
|
|
914
|
-
el.style.overflowY = el.scrollHeight >
|
|
1260
|
+
el.style.overflowY = el.scrollHeight > 200 ? "auto" : "hidden";
|
|
915
1261
|
},
|
|
916
1262
|
[]
|
|
917
1263
|
);
|
|
1264
|
+
const addFiles = (0, import_react5.useCallback)(async (files) => {
|
|
1265
|
+
const fileArray = Array.from(files);
|
|
1266
|
+
for (const file of fileArray) {
|
|
1267
|
+
if (attachments.length >= MAX_ATTACHMENTS) break;
|
|
1268
|
+
if (!ALLOWED_TYPES.has(file.type)) continue;
|
|
1269
|
+
if (file.size > MAX_FILE_SIZE) continue;
|
|
1270
|
+
try {
|
|
1271
|
+
const data = await fileToBase64(file);
|
|
1272
|
+
const previewUrl = file.type.startsWith("image/") ? URL.createObjectURL(file) : void 0;
|
|
1273
|
+
const attachment = {
|
|
1274
|
+
filename: file.name,
|
|
1275
|
+
content_type: file.type,
|
|
1276
|
+
data,
|
|
1277
|
+
preview_url: previewUrl
|
|
1278
|
+
};
|
|
1279
|
+
setAttachments((prev) => {
|
|
1280
|
+
if (prev.length >= MAX_ATTACHMENTS) return prev;
|
|
1281
|
+
return [...prev, attachment];
|
|
1282
|
+
});
|
|
1283
|
+
} catch {
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
}, [attachments.length]);
|
|
1287
|
+
const handleFileSelect = (0, import_react5.useCallback)(() => {
|
|
1288
|
+
fileInputRef.current?.click();
|
|
1289
|
+
}, []);
|
|
1290
|
+
const handleFileInputChange = (0, import_react5.useCallback)(
|
|
1291
|
+
(e) => {
|
|
1292
|
+
if (e.target.files) {
|
|
1293
|
+
void addFiles(e.target.files);
|
|
1294
|
+
e.target.value = "";
|
|
1295
|
+
}
|
|
1296
|
+
},
|
|
1297
|
+
[addFiles]
|
|
1298
|
+
);
|
|
1299
|
+
const removeAttachment = (0, import_react5.useCallback)((index) => {
|
|
1300
|
+
setAttachments((prev) => {
|
|
1301
|
+
const removed = prev[index];
|
|
1302
|
+
if (removed?.preview_url) URL.revokeObjectURL(removed.preview_url);
|
|
1303
|
+
return prev.filter((_, i) => i !== index);
|
|
1304
|
+
});
|
|
1305
|
+
}, []);
|
|
1306
|
+
const handlePaste = (0, import_react5.useCallback)(
|
|
1307
|
+
(e) => {
|
|
1308
|
+
const items = e.clipboardData.items;
|
|
1309
|
+
const files = [];
|
|
1310
|
+
for (const item of items) {
|
|
1311
|
+
if (item.kind === "file" && ALLOWED_TYPES.has(item.type)) {
|
|
1312
|
+
const file = item.getAsFile();
|
|
1313
|
+
if (file) files.push(file);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
if (files.length > 0) {
|
|
1317
|
+
void addFiles(files);
|
|
1318
|
+
}
|
|
1319
|
+
},
|
|
1320
|
+
[addFiles]
|
|
1321
|
+
);
|
|
1322
|
+
const handleDragOver = (0, import_react5.useCallback)((e) => {
|
|
1323
|
+
e.preventDefault();
|
|
1324
|
+
e.stopPropagation();
|
|
1325
|
+
setDragOver(true);
|
|
1326
|
+
}, []);
|
|
1327
|
+
const handleDragLeave = (0, import_react5.useCallback)((e) => {
|
|
1328
|
+
e.preventDefault();
|
|
1329
|
+
e.stopPropagation();
|
|
1330
|
+
setDragOver(false);
|
|
1331
|
+
}, []);
|
|
1332
|
+
const handleDrop = (0, import_react5.useCallback)(
|
|
1333
|
+
(e) => {
|
|
1334
|
+
e.preventDefault();
|
|
1335
|
+
e.stopPropagation();
|
|
1336
|
+
setDragOver(false);
|
|
1337
|
+
if (e.dataTransfer.files.length > 0) {
|
|
1338
|
+
void addFiles(e.dataTransfer.files);
|
|
1339
|
+
}
|
|
1340
|
+
},
|
|
1341
|
+
[addFiles]
|
|
1342
|
+
);
|
|
918
1343
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
919
1344
|
"div",
|
|
920
1345
|
{
|
|
921
1346
|
className: (0, import_tailwind_merge6.twMerge)(
|
|
922
|
-
"
|
|
1347
|
+
"relative shrink-0 rounded-3xl border bg-surface",
|
|
1348
|
+
"shadow-lg shadow-black/10",
|
|
1349
|
+
"transition-all duration-200",
|
|
1350
|
+
"focus-within:border-accent/40 focus-within:shadow-accent/5",
|
|
1351
|
+
dragOver ? "border-accent/60 bg-accent/5" : "border-border/60",
|
|
923
1352
|
className
|
|
924
1353
|
),
|
|
1354
|
+
onDragOver: handleDragOver,
|
|
1355
|
+
onDragLeave: handleDragLeave,
|
|
1356
|
+
onDrop: handleDrop,
|
|
925
1357
|
children: [
|
|
926
1358
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
927
|
-
"
|
|
1359
|
+
"input",
|
|
928
1360
|
{
|
|
929
|
-
ref:
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
className: (0, import_tailwind_merge6.twMerge)(
|
|
937
|
-
"flex-1 resize-none rounded-xl border border-border bg-surface/80",
|
|
938
|
-
"px-4 py-2.5 text-sm text-text-primary placeholder:text-text-muted",
|
|
939
|
-
"focus:border-transparent focus:ring-2 focus:ring-accent/40 focus:outline-none",
|
|
940
|
-
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
941
|
-
"overflow-hidden",
|
|
942
|
-
"transition-all duration-200"
|
|
943
|
-
),
|
|
944
|
-
style: { colorScheme: "dark" },
|
|
945
|
-
"aria-label": "Message input"
|
|
1361
|
+
ref: fileInputRef,
|
|
1362
|
+
type: "file",
|
|
1363
|
+
multiple: true,
|
|
1364
|
+
accept: "image/png,image/jpeg,image/gif,image/webp,application/pdf",
|
|
1365
|
+
onChange: handleFileInputChange,
|
|
1366
|
+
className: "hidden",
|
|
1367
|
+
"aria-hidden": "true"
|
|
946
1368
|
}
|
|
947
1369
|
),
|
|
948
|
-
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
949
|
-
|
|
1370
|
+
attachments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "flex gap-2 px-4 pt-3 pb-1 overflow-x-auto", children: attachments.map((att, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1371
|
+
AttachmentPreview,
|
|
950
1372
|
{
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1373
|
+
attachment: att,
|
|
1374
|
+
onRemove: () => removeAttachment(i)
|
|
1375
|
+
},
|
|
1376
|
+
`${att.filename}-${i}`
|
|
1377
|
+
)) }),
|
|
1378
|
+
dragOver && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "absolute inset-0 rounded-3xl flex items-center justify-center bg-accent/10 border-2 border-dashed border-accent/40 z-10 pointer-events-none", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-sm font-display font-semibold text-accent", children: "Drop files here" }) }),
|
|
1379
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-end", children: [
|
|
1380
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1381
|
+
"button",
|
|
1382
|
+
{
|
|
1383
|
+
type: "button",
|
|
1384
|
+
onClick: handleFileSelect,
|
|
1385
|
+
disabled: isLoading || attachments.length >= MAX_ATTACHMENTS,
|
|
1386
|
+
"aria-label": "Attach file",
|
|
1387
|
+
className: (0, import_tailwind_merge6.twMerge)(
|
|
1388
|
+
"flex-shrink-0 ml-2 mb-3",
|
|
1389
|
+
"inline-flex items-center justify-center",
|
|
1390
|
+
"w-9 h-9 rounded-full",
|
|
1391
|
+
"transition-all duration-200",
|
|
1392
|
+
"text-text-muted/60 hover:text-text-secondary hover:bg-text-muted/10",
|
|
1393
|
+
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
|
|
1394
|
+
"disabled:opacity-30 disabled:cursor-not-allowed disabled:hover:bg-transparent"
|
|
1395
|
+
),
|
|
1396
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PaperclipIcon, {})
|
|
1397
|
+
}
|
|
1398
|
+
),
|
|
1399
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1400
|
+
"textarea",
|
|
1401
|
+
{
|
|
1402
|
+
ref: textareaRef,
|
|
1403
|
+
value,
|
|
1404
|
+
onChange: handleChange,
|
|
1405
|
+
onKeyDown: handleKeyDown,
|
|
1406
|
+
onPaste: handlePaste,
|
|
1407
|
+
placeholder,
|
|
1408
|
+
rows: 1,
|
|
1409
|
+
disabled: isLoading,
|
|
1410
|
+
className: (0, import_tailwind_merge6.twMerge)(
|
|
1411
|
+
"flex-1 resize-none bg-transparent",
|
|
1412
|
+
"pl-2 pr-14 pt-4 pb-4 text-[15px] leading-relaxed",
|
|
1413
|
+
"text-text-primary placeholder:text-text-muted/70",
|
|
1414
|
+
"focus:outline-none",
|
|
1415
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1416
|
+
"overflow-hidden"
|
|
1417
|
+
),
|
|
1418
|
+
style: { colorScheme: "dark" },
|
|
1419
|
+
"aria-label": "Message input"
|
|
1420
|
+
}
|
|
1421
|
+
),
|
|
1422
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1423
|
+
"button",
|
|
1424
|
+
{
|
|
1425
|
+
type: "button",
|
|
1426
|
+
onClick: isLoading && onStop ? onStop : handleSend,
|
|
1427
|
+
disabled: !canSend && !isLoading,
|
|
1428
|
+
"aria-label": isLoading ? "Stop generating" : "Send message",
|
|
1429
|
+
className: (0, import_tailwind_merge6.twMerge)(
|
|
1430
|
+
"absolute bottom-3 right-3",
|
|
1431
|
+
"inline-flex items-center justify-center",
|
|
1432
|
+
"w-9 h-9 rounded-full",
|
|
1433
|
+
"transition-all duration-200",
|
|
1434
|
+
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
|
|
1435
|
+
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"
|
|
1436
|
+
),
|
|
1437
|
+
children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(StopIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ArrowUpIcon, {})
|
|
1438
|
+
}
|
|
1439
|
+
)
|
|
1440
|
+
] })
|
|
965
1441
|
]
|
|
966
1442
|
}
|
|
967
1443
|
);
|
|
@@ -974,6 +1450,7 @@ function WelcomeScreen({
|
|
|
974
1450
|
title = "Welcome",
|
|
975
1451
|
message = "How can I help you today?",
|
|
976
1452
|
icon,
|
|
1453
|
+
iconClassName,
|
|
977
1454
|
suggestedQuestions = [],
|
|
978
1455
|
onQuestionSelect,
|
|
979
1456
|
className
|
|
@@ -986,12 +1463,15 @@ function WelcomeScreen({
|
|
|
986
1463
|
className
|
|
987
1464
|
),
|
|
988
1465
|
children: [
|
|
989
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1466
|
+
icon ? iconClassName ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: iconClassName, "aria-hidden": "true", children: icon }) : icon : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
990
1467
|
"div",
|
|
991
1468
|
{
|
|
992
|
-
className:
|
|
1469
|
+
className: (0, import_tailwind_merge7.twMerge)(
|
|
1470
|
+
"w-14 h-14 rounded-2xl bg-accent/10 border border-border flex items-center justify-center pulse-glow",
|
|
1471
|
+
iconClassName
|
|
1472
|
+
),
|
|
993
1473
|
"aria-hidden": "true",
|
|
994
|
-
children:
|
|
1474
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-2xl", children: "\u2726" })
|
|
995
1475
|
}
|
|
996
1476
|
),
|
|
997
1477
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
@@ -1001,7 +1481,7 @@ function WelcomeScreen({
|
|
|
1001
1481
|
suggestedQuestions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1002
1482
|
"div",
|
|
1003
1483
|
{
|
|
1004
|
-
className: "flex flex-wrap justify-center gap-2 max-w-
|
|
1484
|
+
className: "flex flex-wrap justify-center gap-2 max-w-xl",
|
|
1005
1485
|
role: "group",
|
|
1006
1486
|
"aria-label": "Suggested questions",
|
|
1007
1487
|
children: suggestedQuestions.map((question) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
@@ -1010,7 +1490,7 @@ function WelcomeScreen({
|
|
|
1010
1490
|
type: "button",
|
|
1011
1491
|
onClick: () => onQuestionSelect?.(question),
|
|
1012
1492
|
className: (0, import_tailwind_merge7.twMerge)(
|
|
1013
|
-
"px-
|
|
1493
|
+
"px-3.5 py-1.5 rounded-full text-[12px]",
|
|
1014
1494
|
"border border-border bg-transparent text-text-secondary",
|
|
1015
1495
|
"hover:bg-accent/10 hover:border-interactive hover:text-text-primary",
|
|
1016
1496
|
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
|
|
@@ -1028,25 +1508,26 @@ function WelcomeScreen({
|
|
|
1028
1508
|
}
|
|
1029
1509
|
|
|
1030
1510
|
// src/streaming/StreamingMessage/StreamingMessage.tsx
|
|
1031
|
-
var
|
|
1511
|
+
var import_react7 = require("react");
|
|
1512
|
+
var import_tailwind_merge8 = require("tailwind-merge");
|
|
1032
1513
|
var import_core3 = require("@surf-kit/core");
|
|
1033
1514
|
|
|
1034
1515
|
// src/hooks/useCharacterDrain.ts
|
|
1035
|
-
var
|
|
1516
|
+
var import_react6 = require("react");
|
|
1036
1517
|
function useCharacterDrain(target, msPerChar = 15) {
|
|
1037
|
-
const [displayed, setDisplayed] = (0,
|
|
1038
|
-
const indexRef = (0,
|
|
1039
|
-
const lastTimeRef = (0,
|
|
1040
|
-
const rafRef = (0,
|
|
1041
|
-
const drainTargetRef = (0,
|
|
1042
|
-
const msPerCharRef = (0,
|
|
1518
|
+
const [displayed, setDisplayed] = (0, import_react6.useState)("");
|
|
1519
|
+
const indexRef = (0, import_react6.useRef)(0);
|
|
1520
|
+
const lastTimeRef = (0, import_react6.useRef)(0);
|
|
1521
|
+
const rafRef = (0, import_react6.useRef)(null);
|
|
1522
|
+
const drainTargetRef = (0, import_react6.useRef)("");
|
|
1523
|
+
const msPerCharRef = (0, import_react6.useRef)(msPerChar);
|
|
1043
1524
|
msPerCharRef.current = msPerChar;
|
|
1044
1525
|
if (target !== "") {
|
|
1045
1526
|
drainTargetRef.current = target;
|
|
1046
1527
|
}
|
|
1047
1528
|
const drainTarget = drainTargetRef.current;
|
|
1048
1529
|
const isDraining = displayed.length < drainTarget.length;
|
|
1049
|
-
const tickRef = (0,
|
|
1530
|
+
const tickRef = (0, import_react6.useRef)(() => {
|
|
1050
1531
|
});
|
|
1051
1532
|
tickRef.current = (now) => {
|
|
1052
1533
|
const currentTarget = drainTargetRef.current;
|
|
@@ -1058,7 +1539,10 @@ function useCharacterDrain(target, msPerChar = 15) {
|
|
|
1058
1539
|
const elapsed = now - lastTimeRef.current;
|
|
1059
1540
|
const charsToAdvance = Math.floor(elapsed / msPerCharRef.current);
|
|
1060
1541
|
if (charsToAdvance > 0 && indexRef.current < currentTarget.length) {
|
|
1061
|
-
|
|
1542
|
+
let nextIndex = Math.min(indexRef.current + charsToAdvance, currentTarget.length);
|
|
1543
|
+
while (nextIndex < currentTarget.length && currentTarget[nextIndex - 1].trim() === "") {
|
|
1544
|
+
nextIndex++;
|
|
1545
|
+
}
|
|
1062
1546
|
indexRef.current = nextIndex;
|
|
1063
1547
|
lastTimeRef.current = now;
|
|
1064
1548
|
setDisplayed(currentTarget.slice(0, nextIndex));
|
|
@@ -1069,12 +1553,12 @@ function useCharacterDrain(target, msPerChar = 15) {
|
|
|
1069
1553
|
rafRef.current = null;
|
|
1070
1554
|
}
|
|
1071
1555
|
};
|
|
1072
|
-
(0,
|
|
1556
|
+
(0, import_react6.useEffect)(() => {
|
|
1073
1557
|
if (drainTargetRef.current !== "" && indexRef.current < drainTargetRef.current.length && rafRef.current === null) {
|
|
1074
1558
|
rafRef.current = requestAnimationFrame((t) => tickRef.current(t));
|
|
1075
1559
|
}
|
|
1076
1560
|
}, [drainTarget]);
|
|
1077
|
-
(0,
|
|
1561
|
+
(0, import_react6.useEffect)(() => {
|
|
1078
1562
|
if (target === "" && !isDraining && displayed !== "") {
|
|
1079
1563
|
indexRef.current = 0;
|
|
1080
1564
|
lastTimeRef.current = 0;
|
|
@@ -1082,7 +1566,7 @@ function useCharacterDrain(target, msPerChar = 15) {
|
|
|
1082
1566
|
setDisplayed("");
|
|
1083
1567
|
}
|
|
1084
1568
|
}, [target, isDraining, displayed]);
|
|
1085
|
-
(0,
|
|
1569
|
+
(0, import_react6.useEffect)(() => {
|
|
1086
1570
|
return () => {
|
|
1087
1571
|
if (rafRef.current !== null) {
|
|
1088
1572
|
cancelAnimationFrame(rafRef.current);
|
|
@@ -1103,51 +1587,78 @@ var phaseLabels = {
|
|
|
1103
1587
|
generating: "Writing...",
|
|
1104
1588
|
verifying: "Verifying..."
|
|
1105
1589
|
};
|
|
1590
|
+
var CURSOR_STYLES = `
|
|
1591
|
+
.sk-streaming-cursor > :not(ul,ol,blockquote,div:has(table)):last-child::after,
|
|
1592
|
+
.sk-streaming-cursor > :is(ul,ol):last-child > li:last-child::after,
|
|
1593
|
+
.sk-streaming-cursor > blockquote:last-child > p:last-child::after,
|
|
1594
|
+
.sk-streaming-cursor > div:has(table):last-child table tbody tr:last-child td:last-child::after {
|
|
1595
|
+
content: "";
|
|
1596
|
+
display: inline-block;
|
|
1597
|
+
width: 2px;
|
|
1598
|
+
height: 1em;
|
|
1599
|
+
background: var(--color-accent, #38bdf8);
|
|
1600
|
+
animation: sk-cursor-blink 0.8s steps(1) infinite;
|
|
1601
|
+
margin-left: 2px;
|
|
1602
|
+
vertical-align: text-bottom;
|
|
1603
|
+
}
|
|
1604
|
+
@keyframes sk-cursor-blink {
|
|
1605
|
+
0%, 60% { opacity: 1; }
|
|
1606
|
+
61%, 100% { opacity: 0; }
|
|
1607
|
+
}
|
|
1608
|
+
`;
|
|
1106
1609
|
function StreamingMessage({
|
|
1107
1610
|
stream,
|
|
1108
1611
|
onComplete,
|
|
1612
|
+
onDraining,
|
|
1109
1613
|
showPhases = true,
|
|
1110
1614
|
className
|
|
1111
1615
|
}) {
|
|
1112
|
-
const onCompleteRef = (0,
|
|
1616
|
+
const onCompleteRef = (0, import_react7.useRef)(onComplete);
|
|
1113
1617
|
onCompleteRef.current = onComplete;
|
|
1114
|
-
const
|
|
1115
|
-
|
|
1618
|
+
const onDrainingRef = (0, import_react7.useRef)(onDraining);
|
|
1619
|
+
onDrainingRef.current = onDraining;
|
|
1620
|
+
const wasActiveRef = (0, import_react7.useRef)(stream.active);
|
|
1621
|
+
(0, import_react7.useEffect)(() => {
|
|
1116
1622
|
if (wasActiveRef.current && !stream.active) {
|
|
1117
1623
|
onCompleteRef.current?.();
|
|
1118
1624
|
}
|
|
1119
1625
|
wasActiveRef.current = stream.active;
|
|
1120
1626
|
}, [stream.active]);
|
|
1121
1627
|
const phaseLabel = phaseLabels[stream.phase];
|
|
1122
|
-
const { displayed:
|
|
1123
|
-
|
|
1628
|
+
const { displayed: rawDisplayed, isDraining } = useCharacterDrain(stream.content);
|
|
1629
|
+
const displayedContent = stream.active || isDraining ? rawDisplayed.trimEnd() : rawDisplayed;
|
|
1630
|
+
(0, import_react7.useEffect)(() => {
|
|
1631
|
+
onDrainingRef.current?.(isDraining);
|
|
1632
|
+
}, [isDraining]);
|
|
1633
|
+
const agentLabel = stream.agent ? stream.agent.replace("_agent", "").replace("_", " ") : null;
|
|
1634
|
+
const showPhaseIndicator = showPhases && stream.active && stream.phase !== "idle" && !displayedContent;
|
|
1635
|
+
const showCursor = (stream.active || isDraining) && !!displayedContent;
|
|
1636
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: (0, import_tailwind_merge8.twMerge)("flex w-full flex-col items-start", className), "data-testid": "streaming-message", children: [
|
|
1124
1637
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "aria-live": "assertive", className: "sr-only", children: [
|
|
1125
1638
|
stream.active && stream.phase !== "idle" && "Response started",
|
|
1126
1639
|
!stream.active && stream.content && "Response complete"
|
|
1127
1640
|
] }),
|
|
1641
|
+
showCursor && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("style", { children: CURSOR_STYLES }),
|
|
1642
|
+
agentLabel && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "text-[11px] font-display font-semibold uppercase tracking-[0.08em] text-text-muted px-1 mb-1.5", children: agentLabel }),
|
|
1128
1643
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "max-w-[88%] px-4 py-3 rounded-[18px] rounded-tl-[4px] bg-surface border border-border motion-safe:animate-springFromLeft", children: [
|
|
1129
|
-
|
|
1644
|
+
showPhaseIndicator && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1130
1645
|
"div",
|
|
1131
1646
|
{
|
|
1132
|
-
className: "flex items-center gap-2
|
|
1647
|
+
className: "flex items-center gap-2 text-sm text-text-secondary",
|
|
1133
1648
|
"data-testid": "phase-indicator",
|
|
1134
1649
|
children: [
|
|
1135
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_core3.
|
|
1650
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_core3.WaveLoader, { size: "sm", color: "#38bdf8" }) }),
|
|
1136
1651
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: phaseLabel })
|
|
1137
1652
|
]
|
|
1138
1653
|
}
|
|
1139
1654
|
),
|
|
1140
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
"data-testid": "streaming-cursor"
|
|
1148
|
-
}
|
|
1149
|
-
)
|
|
1150
|
-
] })
|
|
1655
|
+
displayedContent && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1656
|
+
ResponseMessage,
|
|
1657
|
+
{
|
|
1658
|
+
content: displayedContent,
|
|
1659
|
+
className: showCursor ? "sk-streaming-cursor" : void 0
|
|
1660
|
+
}
|
|
1661
|
+
)
|
|
1151
1662
|
] })
|
|
1152
1663
|
] });
|
|
1153
1664
|
}
|
|
@@ -1178,7 +1689,7 @@ function AgentChat({
|
|
|
1178
1689
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1179
1690
|
"div",
|
|
1180
1691
|
{
|
|
1181
|
-
className: (0,
|
|
1692
|
+
className: (0, import_tailwind_merge9.twMerge)(
|
|
1182
1693
|
"flex flex-col h-full bg-canvas border border-border rounded-xl overflow-hidden",
|
|
1183
1694
|
className
|
|
1184
1695
|
),
|
|
@@ -1214,7 +1725,7 @@ function AgentChat({
|
|
|
1214
1725
|
onQuestionSelect: handleQuestionSelect
|
|
1215
1726
|
}
|
|
1216
1727
|
),
|
|
1217
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MessageComposer, { onSend: handleSend, isLoading: state.isLoading })
|
|
1728
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MessageComposer, { onSend: handleSend, onStop: actions.stop, isLoading: state.isLoading })
|
|
1218
1729
|
]
|
|
1219
1730
|
}
|
|
1220
1731
|
);
|
|
@@ -1350,7 +1861,7 @@ function ConfidenceBadge({ confidence, className }) {
|
|
|
1350
1861
|
}
|
|
1351
1862
|
|
|
1352
1863
|
// src/confidence/ConfidenceBreakdown/ConfidenceBreakdown.tsx
|
|
1353
|
-
var
|
|
1864
|
+
var import_react8 = require("react");
|
|
1354
1865
|
|
|
1355
1866
|
// src/confidence/ConfidenceMeter/ConfidenceMeter.tsx
|
|
1356
1867
|
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
@@ -1405,7 +1916,7 @@ function ConfidenceBreakdown({
|
|
|
1405
1916
|
defaultExpanded = false,
|
|
1406
1917
|
className
|
|
1407
1918
|
}) {
|
|
1408
|
-
const [expanded, setExpanded] = (0,
|
|
1919
|
+
const [expanded, setExpanded] = (0, import_react8.useState)(defaultExpanded);
|
|
1409
1920
|
const isExpanded = expandable ? expanded : true;
|
|
1410
1921
|
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: `rounded-xl border border-border bg-surface ${className ?? ""}`, "data-testid": "confidence-breakdown", children: [
|
|
1411
1922
|
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
@@ -1485,7 +1996,7 @@ function VerificationBadge({ verification, className }) {
|
|
|
1485
1996
|
}
|
|
1486
1997
|
|
|
1487
1998
|
// src/confidence/VerificationDetail/VerificationDetail.tsx
|
|
1488
|
-
var
|
|
1999
|
+
var import_react9 = require("react");
|
|
1489
2000
|
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1490
2001
|
function VerificationDetail({
|
|
1491
2002
|
verification,
|
|
@@ -1493,7 +2004,7 @@ function VerificationDetail({
|
|
|
1493
2004
|
defaultExpanded = false,
|
|
1494
2005
|
className
|
|
1495
2006
|
}) {
|
|
1496
|
-
const [expanded, setExpanded] = (0,
|
|
2007
|
+
const [expanded, setExpanded] = (0, import_react9.useState)(defaultExpanded);
|
|
1497
2008
|
const isExpanded = expandable ? expanded : true;
|
|
1498
2009
|
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: `rounded-xl border border-border bg-surface ${className ?? ""}`, "data-testid": "verification-detail", children: [
|
|
1499
2010
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
@@ -1537,11 +2048,11 @@ function VerificationDetail({
|
|
|
1537
2048
|
}
|
|
1538
2049
|
|
|
1539
2050
|
// src/hooks/useAgentTheme.ts
|
|
1540
|
-
var
|
|
2051
|
+
var import_react10 = require("react");
|
|
1541
2052
|
var DEFAULT_ACCENT = "#6366f1";
|
|
1542
2053
|
var DEFAULT_LABEL = "Agent";
|
|
1543
2054
|
function useAgentTheme(agentId, agentThemes) {
|
|
1544
|
-
return (0,
|
|
2055
|
+
return (0, import_react10.useMemo)(() => {
|
|
1545
2056
|
if (!agentId) {
|
|
1546
2057
|
return { accent: DEFAULT_ACCENT, icon: null, label: DEFAULT_LABEL };
|
|
1547
2058
|
}
|
|
@@ -1697,7 +2208,7 @@ function ToolExecution({ tool, label, className }) {
|
|
|
1697
2208
|
role: "status",
|
|
1698
2209
|
"data-testid": "tool-execution",
|
|
1699
2210
|
children: [
|
|
1700
|
-
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_core10.
|
|
2211
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_core10.WaveLoader, { size: "sm", color: "#38bdf8" }) }),
|
|
1701
2212
|
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: displayLabel })
|
|
1702
2213
|
]
|
|
1703
2214
|
}
|
|
@@ -1717,7 +2228,7 @@ function RetrievalProgress({ sources, isActive, className }) {
|
|
|
1717
2228
|
"data-testid": "retrieval-progress",
|
|
1718
2229
|
children: [
|
|
1719
2230
|
isActive && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex items-center gap-2 text-sm text-text-secondary", children: [
|
|
1720
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_core11.
|
|
2231
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_core11.WaveLoader, { size: "sm", color: "#38bdf8" }) }),
|
|
1721
2232
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { children: "Retrieving sources..." })
|
|
1722
2233
|
] }),
|
|
1723
2234
|
sources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("ul", { className: "space-y-1", "data-testid": "source-list", children: sources.map((source, index) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
@@ -1774,7 +2285,7 @@ function VerificationProgress({
|
|
|
1774
2285
|
}
|
|
1775
2286
|
|
|
1776
2287
|
// src/streaming/TypewriterText/TypewriterText.tsx
|
|
1777
|
-
var
|
|
2288
|
+
var import_react11 = require("react");
|
|
1778
2289
|
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1779
2290
|
function TypewriterText({
|
|
1780
2291
|
text,
|
|
@@ -1784,9 +2295,9 @@ function TypewriterText({
|
|
|
1784
2295
|
className = "",
|
|
1785
2296
|
showCursor = true
|
|
1786
2297
|
}) {
|
|
1787
|
-
const [displayedText, setDisplayedText] = (0,
|
|
1788
|
-
const [isComplete, setIsComplete] = (0,
|
|
1789
|
-
(0,
|
|
2298
|
+
const [displayedText, setDisplayedText] = (0, import_react11.useState)("");
|
|
2299
|
+
const [isComplete, setIsComplete] = (0, import_react11.useState)(false);
|
|
2300
|
+
(0, import_react11.useEffect)(() => {
|
|
1790
2301
|
setDisplayedText("");
|
|
1791
2302
|
setIsComplete(false);
|
|
1792
2303
|
let index = 0;
|
|
@@ -1815,7 +2326,7 @@ function TypewriterText({
|
|
|
1815
2326
|
}
|
|
1816
2327
|
|
|
1817
2328
|
// src/streaming/TypingIndicator/TypingIndicator.tsx
|
|
1818
|
-
var
|
|
2329
|
+
var import_tailwind_merge10 = require("tailwind-merge");
|
|
1819
2330
|
var import_hooks2 = require("@surf-kit/hooks");
|
|
1820
2331
|
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1821
2332
|
var bounceKeyframes = `
|
|
@@ -1835,7 +2346,7 @@ function TypingIndicator({
|
|
|
1835
2346
|
{
|
|
1836
2347
|
role: "status",
|
|
1837
2348
|
"aria-label": label ?? "typing",
|
|
1838
|
-
className: (0,
|
|
2349
|
+
className: (0, import_tailwind_merge10.twMerge)("inline-flex items-center gap-2", className),
|
|
1839
2350
|
"data-testid": "typing-indicator",
|
|
1840
2351
|
children: [
|
|
1841
2352
|
!reducedMotion && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("style", { children: bounceKeyframes }),
|
|
@@ -1857,7 +2368,7 @@ function TypingIndicator({
|
|
|
1857
2368
|
}
|
|
1858
2369
|
|
|
1859
2370
|
// src/streaming/TextGlimmer/TextGlimmer.tsx
|
|
1860
|
-
var
|
|
2371
|
+
var import_tailwind_merge11 = require("tailwind-merge");
|
|
1861
2372
|
var import_hooks3 = require("@surf-kit/hooks");
|
|
1862
2373
|
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
1863
2374
|
var shimmerKeyframes = `
|
|
@@ -1874,7 +2385,7 @@ function TextGlimmer({ lines = 3, className }) {
|
|
|
1874
2385
|
{
|
|
1875
2386
|
role: "status",
|
|
1876
2387
|
"aria-label": "Loading",
|
|
1877
|
-
className: (0,
|
|
2388
|
+
className: (0, import_tailwind_merge11.twMerge)("flex flex-col gap-2", className),
|
|
1878
2389
|
"data-testid": "text-glimmer",
|
|
1879
2390
|
children: [
|
|
1880
2391
|
!reducedMotion && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("style", { children: shimmerKeyframes }),
|
|
@@ -1900,7 +2411,7 @@ function TextGlimmer({ lines = 3, className }) {
|
|
|
1900
2411
|
}
|
|
1901
2412
|
|
|
1902
2413
|
// src/streaming/StreamingList/StreamingList.tsx
|
|
1903
|
-
var
|
|
2414
|
+
var import_tailwind_merge12 = require("tailwind-merge");
|
|
1904
2415
|
var import_hooks4 = require("@surf-kit/hooks");
|
|
1905
2416
|
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
1906
2417
|
var fadeSlideInKeyframes = `
|
|
@@ -1918,13 +2429,13 @@ function StreamingList({
|
|
|
1918
2429
|
}) {
|
|
1919
2430
|
const reducedMotion = (0, import_hooks4.useReducedMotion)();
|
|
1920
2431
|
if (items.length === 0 && !isStreaming) {
|
|
1921
|
-
return emptyMessage ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: (0,
|
|
2432
|
+
return emptyMessage ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: (0, import_tailwind_merge12.twMerge)("text-sm text-text-secondary", className), "data-testid": "streaming-list-empty", children: emptyMessage }) : null;
|
|
1922
2433
|
}
|
|
1923
2434
|
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(
|
|
1924
2435
|
"ul",
|
|
1925
2436
|
{
|
|
1926
2437
|
"aria-live": "polite",
|
|
1927
|
-
className: (0,
|
|
2438
|
+
className: (0, import_tailwind_merge12.twMerge)("list-none p-0 m-0", className),
|
|
1928
2439
|
"data-testid": "streaming-list",
|
|
1929
2440
|
children: [
|
|
1930
2441
|
!reducedMotion && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("style", { children: fadeSlideInKeyframes }),
|
|
@@ -1944,7 +2455,7 @@ function StreamingList({
|
|
|
1944
2455
|
}
|
|
1945
2456
|
|
|
1946
2457
|
// src/streaming/StreamingStructure/StreamingStructure.tsx
|
|
1947
|
-
var
|
|
2458
|
+
var import_tailwind_merge13 = require("tailwind-merge");
|
|
1948
2459
|
var import_hooks5 = require("@surf-kit/hooks");
|
|
1949
2460
|
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
1950
2461
|
var fadeSlideInKeyframes2 = `
|
|
@@ -1993,7 +2504,7 @@ function StreamingStructure({
|
|
|
1993
2504
|
"dl",
|
|
1994
2505
|
{
|
|
1995
2506
|
"aria-live": "polite",
|
|
1996
|
-
className: (0,
|
|
2507
|
+
className: (0, import_tailwind_merge13.twMerge)("m-0", className),
|
|
1997
2508
|
"data-testid": "streaming-structure",
|
|
1998
2509
|
children: [
|
|
1999
2510
|
!reducedMotion && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("style", { children: fadeSlideInKeyframes2 }),
|
|
@@ -2016,7 +2527,7 @@ function StreamingStructure({
|
|
|
2016
2527
|
}
|
|
2017
2528
|
|
|
2018
2529
|
// src/chat/ConversationList/ConversationList.tsx
|
|
2019
|
-
var
|
|
2530
|
+
var import_tailwind_merge14 = require("tailwind-merge");
|
|
2020
2531
|
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
2021
2532
|
function ConversationList({
|
|
2022
2533
|
conversations,
|
|
@@ -2030,14 +2541,14 @@ function ConversationList({
|
|
|
2030
2541
|
"nav",
|
|
2031
2542
|
{
|
|
2032
2543
|
"aria-label": "Conversation list",
|
|
2033
|
-
className: (0,
|
|
2544
|
+
className: (0, import_tailwind_merge14.twMerge)("flex flex-col flex-1 min-h-0", className),
|
|
2034
2545
|
children: [
|
|
2035
|
-
onNew && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "
|
|
2546
|
+
onNew && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "px-5 pt-1 pb-3 border-b border-border", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
2036
2547
|
"button",
|
|
2037
2548
|
{
|
|
2038
2549
|
type: "button",
|
|
2039
2550
|
onClick: onNew,
|
|
2040
|
-
className: "w-full px-4 py-2
|
|
2551
|
+
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",
|
|
2041
2552
|
children: "New conversation"
|
|
2042
2553
|
}
|
|
2043
2554
|
) }),
|
|
@@ -2047,10 +2558,10 @@ function ConversationList({
|
|
|
2047
2558
|
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
2048
2559
|
"li",
|
|
2049
2560
|
{
|
|
2050
|
-
className: (0,
|
|
2051
|
-
"flex items-start
|
|
2052
|
-
"hover:bg-surface",
|
|
2053
|
-
isActive
|
|
2561
|
+
className: (0, import_tailwind_merge14.twMerge)(
|
|
2562
|
+
"flex items-start transition-colors duration-150",
|
|
2563
|
+
"hover:bg-surface-raised",
|
|
2564
|
+
isActive ? "bg-accent-subtlest border-l-[3px] border-l-accent" : "border-l-[3px] border-l-transparent"
|
|
2054
2565
|
),
|
|
2055
2566
|
children: [
|
|
2056
2567
|
/* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
@@ -2059,10 +2570,10 @@ function ConversationList({
|
|
|
2059
2570
|
type: "button",
|
|
2060
2571
|
onClick: () => onSelect(conversation.id),
|
|
2061
2572
|
"aria-current": isActive ? "true" : void 0,
|
|
2062
|
-
className: "flex-1 min-w-0 text-left px-
|
|
2573
|
+
className: "flex-1 min-w-0 text-left px-5 py-2.5",
|
|
2063
2574
|
children: [
|
|
2064
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "text-sm font-medium text-
|
|
2065
|
-
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "text-xs text-
|
|
2575
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "text-sm font-medium text-text-primary truncate", children: conversation.title }),
|
|
2576
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "text-xs text-text-muted truncate mt-0.5 leading-relaxed", children: conversation.lastMessage })
|
|
2066
2577
|
]
|
|
2067
2578
|
}
|
|
2068
2579
|
),
|
|
@@ -2072,7 +2583,7 @@ function ConversationList({
|
|
|
2072
2583
|
type: "button",
|
|
2073
2584
|
onClick: () => onDelete(conversation.id),
|
|
2074
2585
|
"aria-label": `Delete ${conversation.title}`,
|
|
2075
|
-
className: "shrink-0 p-1.5 m-2 rounded-lg text-
|
|
2586
|
+
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",
|
|
2076
2587
|
children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
2077
2588
|
"svg",
|
|
2078
2589
|
{
|
|
@@ -2099,7 +2610,7 @@ function ConversationList({
|
|
|
2099
2610
|
conversation.id
|
|
2100
2611
|
);
|
|
2101
2612
|
}),
|
|
2102
|
-
conversations.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("li", { className: "px-
|
|
2613
|
+
conversations.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("li", { className: "px-5 py-12 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "text-sm text-text-muted font-body", children: "No conversations yet" }) })
|
|
2103
2614
|
] })
|
|
2104
2615
|
]
|
|
2105
2616
|
}
|
|
@@ -2107,8 +2618,8 @@ function ConversationList({
|
|
|
2107
2618
|
}
|
|
2108
2619
|
|
|
2109
2620
|
// src/layouts/AgentFullPage/AgentFullPage.tsx
|
|
2110
|
-
var
|
|
2111
|
-
var
|
|
2621
|
+
var import_tailwind_merge15 = require("tailwind-merge");
|
|
2622
|
+
var import_react12 = require("react");
|
|
2112
2623
|
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
2113
2624
|
function AgentFullPage({
|
|
2114
2625
|
endpoint,
|
|
@@ -2121,8 +2632,8 @@ function AgentFullPage({
|
|
|
2121
2632
|
onNewConversation,
|
|
2122
2633
|
className
|
|
2123
2634
|
}) {
|
|
2124
|
-
const [sidebarOpen, setSidebarOpen] = (0,
|
|
2125
|
-
const handleSelect = (0,
|
|
2635
|
+
const [sidebarOpen, setSidebarOpen] = (0, import_react12.useState)(false);
|
|
2636
|
+
const handleSelect = (0, import_react12.useCallback)(
|
|
2126
2637
|
(id) => {
|
|
2127
2638
|
onConversationSelect?.(id);
|
|
2128
2639
|
setSidebarOpen(false);
|
|
@@ -2132,7 +2643,7 @@ function AgentFullPage({
|
|
|
2132
2643
|
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
2133
2644
|
"div",
|
|
2134
2645
|
{
|
|
2135
|
-
className: (0,
|
|
2646
|
+
className: (0, import_tailwind_merge15.twMerge)("flex h-screen w-full overflow-hidden bg-brand-dark", className),
|
|
2136
2647
|
"data-testid": "agent-full-page",
|
|
2137
2648
|
children: [
|
|
2138
2649
|
showConversationList && /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
|
|
@@ -2147,7 +2658,7 @@ function AgentFullPage({
|
|
|
2147
2658
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
2148
2659
|
"aside",
|
|
2149
2660
|
{
|
|
2150
|
-
className: (0,
|
|
2661
|
+
className: (0, import_tailwind_merge15.twMerge)(
|
|
2151
2662
|
"bg-brand-dark border-r border-brand-gold/15 w-72 shrink-0 flex-col z-40",
|
|
2152
2663
|
// Desktop: always visible
|
|
2153
2664
|
"hidden md:flex",
|
|
@@ -2213,8 +2724,8 @@ function AgentFullPage({
|
|
|
2213
2724
|
}
|
|
2214
2725
|
|
|
2215
2726
|
// src/layouts/AgentPanel/AgentPanel.tsx
|
|
2216
|
-
var
|
|
2217
|
-
var
|
|
2727
|
+
var import_tailwind_merge16 = require("tailwind-merge");
|
|
2728
|
+
var import_react13 = require("react");
|
|
2218
2729
|
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
2219
2730
|
function AgentPanel({
|
|
2220
2731
|
endpoint,
|
|
@@ -2225,8 +2736,8 @@ function AgentPanel({
|
|
|
2225
2736
|
title = "Chat",
|
|
2226
2737
|
className
|
|
2227
2738
|
}) {
|
|
2228
|
-
const panelRef = (0,
|
|
2229
|
-
(0,
|
|
2739
|
+
const panelRef = (0, import_react13.useRef)(null);
|
|
2740
|
+
(0, import_react13.useEffect)(() => {
|
|
2230
2741
|
if (!isOpen) return;
|
|
2231
2742
|
const handleKeyDown = (e) => {
|
|
2232
2743
|
if (e.key === "Escape") onClose();
|
|
@@ -2238,13 +2749,13 @@ function AgentPanel({
|
|
|
2238
2749
|
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
2239
2750
|
"div",
|
|
2240
2751
|
{
|
|
2241
|
-
className: (0,
|
|
2752
|
+
className: (0, import_tailwind_merge16.twMerge)("fixed inset-0 z-50", !isOpen && "pointer-events-none"),
|
|
2242
2753
|
"aria-hidden": !isOpen,
|
|
2243
2754
|
children: [
|
|
2244
2755
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
2245
2756
|
"div",
|
|
2246
2757
|
{
|
|
2247
|
-
className: (0,
|
|
2758
|
+
className: (0, import_tailwind_merge16.twMerge)(
|
|
2248
2759
|
"fixed inset-0 transition-opacity duration-300",
|
|
2249
2760
|
isOpen ? "opacity-100 bg-brand-dark/70 backdrop-blur-sm pointer-events-auto" : "opacity-0 pointer-events-none"
|
|
2250
2761
|
),
|
|
@@ -2260,7 +2771,7 @@ function AgentPanel({
|
|
|
2260
2771
|
"aria-label": title,
|
|
2261
2772
|
"aria-modal": isOpen ? "true" : void 0,
|
|
2262
2773
|
style: { width: widthStyle, maxWidth: "100vw" },
|
|
2263
|
-
className: (0,
|
|
2774
|
+
className: (0, import_tailwind_merge16.twMerge)(
|
|
2264
2775
|
"fixed top-0 h-full flex flex-col z-50 bg-brand-dark shadow-card",
|
|
2265
2776
|
"transition-transform duration-300 ease-in-out",
|
|
2266
2777
|
side === "left" ? `left-0 border-r border-brand-gold/15 ${isOpen ? "translate-x-0" : "-translate-x-full"}` : `right-0 border-l border-brand-gold/15 ${isOpen ? "translate-x-0" : "translate-x-full"}`,
|
|
@@ -2302,8 +2813,8 @@ function AgentPanel({
|
|
|
2302
2813
|
}
|
|
2303
2814
|
|
|
2304
2815
|
// src/layouts/AgentWidget/AgentWidget.tsx
|
|
2305
|
-
var
|
|
2306
|
-
var
|
|
2816
|
+
var import_tailwind_merge17 = require("tailwind-merge");
|
|
2817
|
+
var import_react14 = require("react");
|
|
2307
2818
|
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
2308
2819
|
function AgentWidget({
|
|
2309
2820
|
endpoint,
|
|
@@ -2312,8 +2823,8 @@ function AgentWidget({
|
|
|
2312
2823
|
title = "Chat",
|
|
2313
2824
|
className
|
|
2314
2825
|
}) {
|
|
2315
|
-
const [isOpen, setIsOpen] = (0,
|
|
2316
|
-
const toggle = (0,
|
|
2826
|
+
const [isOpen, setIsOpen] = (0, import_react14.useState)(false);
|
|
2827
|
+
const toggle = (0, import_react14.useCallback)(() => {
|
|
2317
2828
|
setIsOpen((prev) => !prev);
|
|
2318
2829
|
}, []);
|
|
2319
2830
|
const positionClasses = position === "bottom-left" ? "left-4 bottom-4" : "right-4 bottom-4";
|
|
@@ -2326,7 +2837,7 @@ function AgentWidget({
|
|
|
2326
2837
|
role: "dialog",
|
|
2327
2838
|
"aria-label": title,
|
|
2328
2839
|
"aria-hidden": !isOpen,
|
|
2329
|
-
className: (0,
|
|
2840
|
+
className: (0, import_tailwind_merge17.twMerge)(
|
|
2330
2841
|
"fixed z-50 flex flex-col",
|
|
2331
2842
|
"w-[min(400px,calc(100vw-2rem))] h-[min(600px,calc(100vh-6rem))]",
|
|
2332
2843
|
"rounded-2xl overflow-hidden border border-brand-gold/15",
|
|
@@ -2373,7 +2884,7 @@ function AgentWidget({
|
|
|
2373
2884
|
onClick: toggle,
|
|
2374
2885
|
"aria-label": isOpen ? "Close chat" : triggerLabel,
|
|
2375
2886
|
"aria-expanded": isOpen,
|
|
2376
|
-
className: (0,
|
|
2887
|
+
className: (0, import_tailwind_merge17.twMerge)(
|
|
2377
2888
|
"fixed z-50 flex items-center justify-center w-14 h-14 rounded-full",
|
|
2378
2889
|
"bg-brand-blue text-brand-cream shadow-glow-cyan",
|
|
2379
2890
|
"hover:bg-brand-cyan hover:shadow-glow-cyan hover:scale-105",
|
|
@@ -2391,7 +2902,7 @@ function AgentWidget({
|
|
|
2391
2902
|
}
|
|
2392
2903
|
|
|
2393
2904
|
// src/layouts/AgentEmbed/AgentEmbed.tsx
|
|
2394
|
-
var
|
|
2905
|
+
var import_tailwind_merge18 = require("tailwind-merge");
|
|
2395
2906
|
var import_jsx_runtime39 = require("react/jsx-runtime");
|
|
2396
2907
|
function AgentEmbed({
|
|
2397
2908
|
endpoint,
|
|
@@ -2401,7 +2912,7 @@ function AgentEmbed({
|
|
|
2401
2912
|
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2402
2913
|
"div",
|
|
2403
2914
|
{
|
|
2404
|
-
className: (0,
|
|
2915
|
+
className: (0, import_tailwind_merge18.twMerge)("w-full h-full min-h-0", className),
|
|
2405
2916
|
"data-testid": "agent-embed",
|
|
2406
2917
|
children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
2407
2918
|
AgentChat,
|
|
@@ -2417,7 +2928,7 @@ function AgentEmbed({
|
|
|
2417
2928
|
|
|
2418
2929
|
// src/mcp/MCPToolCall/MCPToolCall.tsx
|
|
2419
2930
|
var import_class_variance_authority = require("class-variance-authority");
|
|
2420
|
-
var
|
|
2931
|
+
var import_tailwind_merge19 = require("tailwind-merge");
|
|
2421
2932
|
var import_core12 = require("@surf-kit/core");
|
|
2422
2933
|
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
2423
2934
|
var statusBadgeIntent = {
|
|
@@ -2461,7 +2972,7 @@ function MCPToolCall({ call, isExpanded = false, onToggleExpand, className }) {
|
|
|
2461
2972
|
return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
2462
2973
|
"div",
|
|
2463
2974
|
{
|
|
2464
|
-
className: (0,
|
|
2975
|
+
className: (0, import_tailwind_merge19.twMerge)(container({ status: call.status }), className),
|
|
2465
2976
|
"data-testid": "mcp-tool-call",
|
|
2466
2977
|
children: [
|
|
2467
2978
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
|
|
@@ -2478,7 +2989,7 @@ function MCPToolCall({ call, isExpanded = false, onToggleExpand, className }) {
|
|
|
2478
2989
|
call.serverName && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "text-xs text-text-secondary truncate", children: call.serverName })
|
|
2479
2990
|
] }),
|
|
2480
2991
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
2481
|
-
call.status === "running" && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_core12.
|
|
2992
|
+
call.status === "running" && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_core12.WaveLoader, { size: "sm", color: "#38bdf8" }) }),
|
|
2482
2993
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
2483
2994
|
import_core12.Badge,
|
|
2484
2995
|
{
|
|
@@ -2552,7 +3063,7 @@ function MCPToolCall({ call, isExpanded = false, onToggleExpand, className }) {
|
|
|
2552
3063
|
}
|
|
2553
3064
|
|
|
2554
3065
|
// src/mcp/MCPResourceView/MCPResourceView.tsx
|
|
2555
|
-
var
|
|
3066
|
+
var import_tailwind_merge20 = require("tailwind-merge");
|
|
2556
3067
|
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
2557
3068
|
function isImageMime(mime) {
|
|
2558
3069
|
return !!mime && mime.startsWith("image/");
|
|
@@ -2570,7 +3081,7 @@ function MCPResourceView({ resource, className }) {
|
|
|
2570
3081
|
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
|
|
2571
3082
|
"div",
|
|
2572
3083
|
{
|
|
2573
|
-
className: (0,
|
|
3084
|
+
className: (0, import_tailwind_merge20.twMerge)("rounded-lg border border-border bg-surface p-3 text-sm", className),
|
|
2574
3085
|
"data-testid": "mcp-resource-view",
|
|
2575
3086
|
children: [
|
|
2576
3087
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "mb-2", children: [
|
|
@@ -2620,9 +3131,9 @@ function MCPResourceView({ resource, className }) {
|
|
|
2620
3131
|
}
|
|
2621
3132
|
|
|
2622
3133
|
// src/mcp/MCPServerStatus/MCPServerStatus.tsx
|
|
2623
|
-
var
|
|
3134
|
+
var import_react15 = require("react");
|
|
2624
3135
|
var import_class_variance_authority2 = require("class-variance-authority");
|
|
2625
|
-
var
|
|
3136
|
+
var import_tailwind_merge21 = require("tailwind-merge");
|
|
2626
3137
|
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
2627
3138
|
var statusDot = (0, import_class_variance_authority2.cva)("inline-block h-2 w-2 rounded-full shrink-0", {
|
|
2628
3139
|
variants: {
|
|
@@ -2644,13 +3155,13 @@ function formatLastPing(date) {
|
|
|
2644
3155
|
return date.toLocaleTimeString();
|
|
2645
3156
|
}
|
|
2646
3157
|
function MCPServerStatus({ server, className }) {
|
|
2647
|
-
const [showTools, setShowTools] = (0,
|
|
2648
|
-
const [showResources, setShowResources] = (0,
|
|
3158
|
+
const [showTools, setShowTools] = (0, import_react15.useState)(false);
|
|
3159
|
+
const [showResources, setShowResources] = (0, import_react15.useState)(false);
|
|
2649
3160
|
const lastPing = formatLastPing(server.lastPing);
|
|
2650
3161
|
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
|
|
2651
3162
|
"div",
|
|
2652
3163
|
{
|
|
2653
|
-
className: (0,
|
|
3164
|
+
className: (0, import_tailwind_merge21.twMerge)("rounded-lg border border-border bg-surface p-3 text-sm", className),
|
|
2654
3165
|
"data-testid": "mcp-server-status",
|
|
2655
3166
|
children: [
|
|
2656
3167
|
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center gap-2 mb-1", children: [
|
|
@@ -2762,9 +3273,9 @@ function MCPServerStatus({ server, className }) {
|
|
|
2762
3273
|
}
|
|
2763
3274
|
|
|
2764
3275
|
// src/mcp/MCPApprovalDialog/MCPApprovalDialog.tsx
|
|
2765
|
-
var
|
|
3276
|
+
var import_react16 = require("react");
|
|
2766
3277
|
var import_class_variance_authority3 = require("class-variance-authority");
|
|
2767
|
-
var
|
|
3278
|
+
var import_tailwind_merge22 = require("tailwind-merge");
|
|
2768
3279
|
var import_react_aria = require("react-aria");
|
|
2769
3280
|
var import_core13 = require("@surf-kit/core");
|
|
2770
3281
|
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
@@ -2800,9 +3311,9 @@ function MCPApprovalDialog({
|
|
|
2800
3311
|
isOpen,
|
|
2801
3312
|
className
|
|
2802
3313
|
}) {
|
|
2803
|
-
const ref = (0,
|
|
3314
|
+
const ref = (0, import_react16.useRef)(null);
|
|
2804
3315
|
const { dialogProps, titleProps } = (0, import_react_aria.useDialog)({ role: "alertdialog" }, ref);
|
|
2805
|
-
(0,
|
|
3316
|
+
(0, import_react16.useEffect)(() => {
|
|
2806
3317
|
if (!isOpen) return;
|
|
2807
3318
|
const handleKeyDown = (e) => {
|
|
2808
3319
|
if (e.key === "Escape") {
|
|
@@ -2824,7 +3335,7 @@ function MCPApprovalDialog({
|
|
|
2824
3335
|
{
|
|
2825
3336
|
...dialogProps,
|
|
2826
3337
|
ref,
|
|
2827
|
-
className: (0,
|
|
3338
|
+
className: (0, import_tailwind_merge22.twMerge)(riskBorder({ risk: riskLevel }), className),
|
|
2828
3339
|
"data-testid": "mcp-approval-dialog",
|
|
2829
3340
|
children: [
|
|
2830
3341
|
/* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
|
|
@@ -2902,7 +3413,7 @@ function MCPApprovalDialog({
|
|
|
2902
3413
|
}
|
|
2903
3414
|
|
|
2904
3415
|
// src/feedback/ThumbsFeedback/ThumbsFeedback.tsx
|
|
2905
|
-
var
|
|
3416
|
+
var import_react17 = require("react");
|
|
2906
3417
|
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
2907
3418
|
function ThumbsFeedback({
|
|
2908
3419
|
messageId,
|
|
@@ -2911,7 +3422,7 @@ function ThumbsFeedback({
|
|
|
2911
3422
|
onNegative,
|
|
2912
3423
|
className
|
|
2913
3424
|
}) {
|
|
2914
|
-
const [selected, setSelected] = (0,
|
|
3425
|
+
const [selected, setSelected] = (0, import_react17.useState)(state);
|
|
2915
3426
|
const handleClick = (rating) => {
|
|
2916
3427
|
setSelected(rating);
|
|
2917
3428
|
onFeedback(messageId, rating);
|
|
@@ -2991,11 +3502,11 @@ function ThumbsFeedback({
|
|
|
2991
3502
|
}
|
|
2992
3503
|
|
|
2993
3504
|
// src/feedback/FeedbackDialog/FeedbackDialog.tsx
|
|
2994
|
-
var
|
|
3505
|
+
var import_react18 = require("react");
|
|
2995
3506
|
var import_core14 = require("@surf-kit/core");
|
|
2996
3507
|
var import_jsx_runtime45 = require("react/jsx-runtime");
|
|
2997
3508
|
function FeedbackDialog({ isOpen, onClose, onSubmit, className }) {
|
|
2998
|
-
const [comment, setComment] = (0,
|
|
3509
|
+
const [comment, setComment] = (0, import_react18.useState)("");
|
|
2999
3510
|
const handleSubmit = () => {
|
|
3000
3511
|
onSubmit(comment);
|
|
3001
3512
|
setComment("");
|