@surf-kit/agent 0.1.1 → 0.2.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/README.md +19 -1
- package/dist/agent-BNSmiexZ.d.cts +44 -0
- package/dist/agent-BNSmiexZ.d.ts +44 -0
- package/dist/agent-identity/index.cjs +157 -0
- package/dist/agent-identity/index.cjs.map +1 -0
- package/dist/agent-identity/index.d.cts +35 -0
- package/dist/agent-identity/index.d.ts +35 -0
- package/dist/agent-identity/index.js +127 -0
- package/dist/agent-identity/index.js.map +1 -0
- package/dist/chat/index.cjs +1281 -0
- package/dist/chat/index.cjs.map +1 -0
- package/dist/chat/index.d.cts +72 -0
- package/dist/chat/index.d.ts +72 -0
- package/dist/chat/index.js +1239 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat--OifhIRe.d.ts +24 -0
- package/dist/chat-ChYl2XjV.d.cts +24 -0
- package/dist/confidence/index.cjs +253 -0
- package/dist/confidence/index.cjs.map +1 -0
- package/dist/confidence/index.d.cts +40 -0
- package/dist/confidence/index.d.ts +40 -0
- package/dist/confidence/index.js +222 -0
- package/dist/confidence/index.js.map +1 -0
- package/dist/feedback/index.cjs +186 -0
- package/dist/feedback/index.cjs.map +1 -0
- package/dist/feedback/index.d.cts +27 -0
- package/dist/feedback/index.d.ts +27 -0
- package/dist/feedback/index.js +157 -0
- package/dist/feedback/index.js.map +1 -0
- package/dist/{hooks-B8CSeOsn.d.cts → hooks-BGs8-4GK.d.ts} +4 -99
- package/dist/{hooks-B8CSeOsn.d.ts → hooks-DLfF18IU.d.cts} +4 -99
- package/dist/hooks.d.cts +4 -1
- package/dist/hooks.d.ts +4 -1
- package/dist/index-BazLnae1.d.cts +67 -0
- package/dist/index-BazLnae1.d.ts +67 -0
- package/dist/index.cjs +889 -144
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -321
- package/dist/index.d.ts +15 -321
- package/dist/index.js +879 -142
- package/dist/index.js.map +1 -1
- package/dist/layouts/index.cjs +1588 -0
- package/dist/layouts/index.cjs.map +1 -0
- package/dist/layouts/index.d.cts +46 -0
- package/dist/layouts/index.d.ts +46 -0
- package/dist/layouts/index.js +1548 -0
- package/dist/layouts/index.js.map +1 -0
- package/dist/mcp/index.cjs +522 -0
- package/dist/mcp/index.cjs.map +1 -0
- package/dist/mcp/index.d.cts +2 -0
- package/dist/mcp/index.d.ts +2 -0
- package/dist/mcp/index.js +492 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/response/index.cjs +519 -0
- package/dist/response/index.cjs.map +1 -0
- package/dist/response/index.d.cts +44 -0
- package/dist/response/index.d.ts +44 -0
- package/dist/response/index.js +478 -0
- package/dist/response/index.js.map +1 -0
- package/dist/sources/index.cjs +243 -0
- package/dist/sources/index.cjs.map +1 -0
- package/dist/sources/index.d.cts +44 -0
- package/dist/sources/index.d.ts +44 -0
- package/dist/sources/index.js +212 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/streaming/index.cjs +531 -0
- package/dist/streaming/index.cjs.map +1 -0
- package/dist/streaming/index.d.cts +81 -0
- package/dist/streaming/index.d.ts +81 -0
- package/dist/streaming/index.js +495 -0
- package/dist/streaming/index.js.map +1 -0
- package/dist/streaming-DbQxScpi.d.ts +39 -0
- package/dist/streaming-DfT22A0z.d.cts +39 -0
- package/package.json +62 -17
|
@@ -0,0 +1,1588 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/layouts/index.ts
|
|
31
|
+
var layouts_exports = {};
|
|
32
|
+
__export(layouts_exports, {
|
|
33
|
+
AgentEmbed: () => AgentEmbed,
|
|
34
|
+
AgentFullPage: () => AgentFullPage,
|
|
35
|
+
AgentPanel: () => AgentPanel,
|
|
36
|
+
AgentWidget: () => AgentWidget
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(layouts_exports);
|
|
39
|
+
|
|
40
|
+
// src/layouts/AgentFullPage/AgentFullPage.tsx
|
|
41
|
+
var import_tailwind_merge10 = require("tailwind-merge");
|
|
42
|
+
var import_react7 = require("react");
|
|
43
|
+
|
|
44
|
+
// src/chat/AgentChat/AgentChat.tsx
|
|
45
|
+
var import_tailwind_merge8 = require("tailwind-merge");
|
|
46
|
+
|
|
47
|
+
// src/hooks/useAgentChat.ts
|
|
48
|
+
var import_react = require("react");
|
|
49
|
+
var initialState = {
|
|
50
|
+
messages: [],
|
|
51
|
+
conversationId: null,
|
|
52
|
+
isLoading: false,
|
|
53
|
+
error: null,
|
|
54
|
+
inputValue: "",
|
|
55
|
+
streamPhase: "idle",
|
|
56
|
+
streamingContent: ""
|
|
57
|
+
};
|
|
58
|
+
function reducer(state, action) {
|
|
59
|
+
switch (action.type) {
|
|
60
|
+
case "SET_INPUT":
|
|
61
|
+
return { ...state, inputValue: action.value };
|
|
62
|
+
case "SEND_START":
|
|
63
|
+
return {
|
|
64
|
+
...state,
|
|
65
|
+
messages: [...state.messages, action.message],
|
|
66
|
+
isLoading: true,
|
|
67
|
+
error: null,
|
|
68
|
+
inputValue: "",
|
|
69
|
+
streamPhase: "thinking",
|
|
70
|
+
streamingContent: ""
|
|
71
|
+
};
|
|
72
|
+
case "STREAM_PHASE":
|
|
73
|
+
return { ...state, streamPhase: action.phase };
|
|
74
|
+
case "STREAM_CONTENT":
|
|
75
|
+
return { ...state, streamingContent: state.streamingContent + action.content };
|
|
76
|
+
case "SEND_SUCCESS":
|
|
77
|
+
return {
|
|
78
|
+
...state,
|
|
79
|
+
messages: [...state.messages, action.message],
|
|
80
|
+
conversationId: action.conversationId ?? state.conversationId,
|
|
81
|
+
isLoading: false,
|
|
82
|
+
streamPhase: "idle",
|
|
83
|
+
streamingContent: ""
|
|
84
|
+
};
|
|
85
|
+
case "SEND_ERROR":
|
|
86
|
+
return {
|
|
87
|
+
...state,
|
|
88
|
+
isLoading: false,
|
|
89
|
+
error: action.error,
|
|
90
|
+
streamPhase: "idle",
|
|
91
|
+
streamingContent: ""
|
|
92
|
+
};
|
|
93
|
+
case "LOAD_CONVERSATION":
|
|
94
|
+
return {
|
|
95
|
+
...state,
|
|
96
|
+
conversationId: action.conversationId,
|
|
97
|
+
messages: action.messages,
|
|
98
|
+
error: null
|
|
99
|
+
};
|
|
100
|
+
case "RESET":
|
|
101
|
+
return { ...initialState };
|
|
102
|
+
case "CLEAR_ERROR":
|
|
103
|
+
return { ...state, error: null };
|
|
104
|
+
default:
|
|
105
|
+
return state;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
var msgIdCounter = 0;
|
|
109
|
+
function generateMessageId() {
|
|
110
|
+
return `msg-${Date.now()}-${++msgIdCounter}`;
|
|
111
|
+
}
|
|
112
|
+
function useAgentChat(config) {
|
|
113
|
+
const [state, dispatch] = (0, import_react.useReducer)(reducer, initialState);
|
|
114
|
+
const configRef = (0, import_react.useRef)(config);
|
|
115
|
+
configRef.current = config;
|
|
116
|
+
const lastUserMessageRef = (0, import_react.useRef)(null);
|
|
117
|
+
const sendMessage = (0, import_react.useCallback)(
|
|
118
|
+
async (content) => {
|
|
119
|
+
const { apiUrl, streamPath = "/chat/stream", headers = {}, timeout = 3e4 } = configRef.current;
|
|
120
|
+
lastUserMessageRef.current = content;
|
|
121
|
+
const userMessage = {
|
|
122
|
+
id: generateMessageId(),
|
|
123
|
+
role: "user",
|
|
124
|
+
content,
|
|
125
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
126
|
+
};
|
|
127
|
+
dispatch({ type: "SEND_START", message: userMessage });
|
|
128
|
+
const controller = new AbortController();
|
|
129
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
130
|
+
try {
|
|
131
|
+
const response = await fetch(`${apiUrl}${streamPath}`, {
|
|
132
|
+
method: "POST",
|
|
133
|
+
headers: {
|
|
134
|
+
"Content-Type": "application/json",
|
|
135
|
+
Accept: "text/event-stream",
|
|
136
|
+
...headers
|
|
137
|
+
},
|
|
138
|
+
body: JSON.stringify({
|
|
139
|
+
message: content,
|
|
140
|
+
conversation_id: state.conversationId
|
|
141
|
+
}),
|
|
142
|
+
signal: controller.signal
|
|
143
|
+
});
|
|
144
|
+
clearTimeout(timeoutId);
|
|
145
|
+
if (!response.ok) {
|
|
146
|
+
dispatch({
|
|
147
|
+
type: "SEND_ERROR",
|
|
148
|
+
error: {
|
|
149
|
+
code: "API_ERROR",
|
|
150
|
+
message: `HTTP ${response.status}: ${response.statusText}`,
|
|
151
|
+
retryable: response.status >= 500
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const reader = response.body?.getReader();
|
|
157
|
+
if (!reader) {
|
|
158
|
+
dispatch({
|
|
159
|
+
type: "SEND_ERROR",
|
|
160
|
+
error: { code: "STREAM_ERROR", message: "No response body", retryable: true }
|
|
161
|
+
});
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const decoder = new TextDecoder();
|
|
165
|
+
let buffer = "";
|
|
166
|
+
let accumulatedContent = "";
|
|
167
|
+
let agentResponse = null;
|
|
168
|
+
let capturedAgent = null;
|
|
169
|
+
let capturedConversationId = null;
|
|
170
|
+
while (true) {
|
|
171
|
+
const { done, value } = await reader.read();
|
|
172
|
+
if (done) break;
|
|
173
|
+
buffer += decoder.decode(value, { stream: true });
|
|
174
|
+
const lines = buffer.split("\n");
|
|
175
|
+
buffer = lines.pop() ?? "";
|
|
176
|
+
for (const line of lines) {
|
|
177
|
+
if (!line.startsWith("data: ")) continue;
|
|
178
|
+
const data = line.slice(6).trim();
|
|
179
|
+
if (data === "[DONE]") continue;
|
|
180
|
+
try {
|
|
181
|
+
const event = JSON.parse(data);
|
|
182
|
+
switch (event.type) {
|
|
183
|
+
case "agent":
|
|
184
|
+
capturedAgent = event.agent;
|
|
185
|
+
break;
|
|
186
|
+
case "phase":
|
|
187
|
+
dispatch({ type: "STREAM_PHASE", phase: event.phase });
|
|
188
|
+
break;
|
|
189
|
+
case "delta":
|
|
190
|
+
accumulatedContent += event.content;
|
|
191
|
+
dispatch({ type: "STREAM_CONTENT", content: event.content });
|
|
192
|
+
break;
|
|
193
|
+
case "done":
|
|
194
|
+
agentResponse = event.response;
|
|
195
|
+
capturedConversationId = event.conversation_id ?? null;
|
|
196
|
+
break;
|
|
197
|
+
case "error":
|
|
198
|
+
dispatch({ type: "SEND_ERROR", error: event.error });
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
} catch {
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const assistantMessage = {
|
|
206
|
+
id: generateMessageId(),
|
|
207
|
+
role: "assistant",
|
|
208
|
+
content: agentResponse?.message ?? accumulatedContent,
|
|
209
|
+
response: agentResponse ?? void 0,
|
|
210
|
+
agent: capturedAgent ?? void 0,
|
|
211
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
212
|
+
};
|
|
213
|
+
dispatch({
|
|
214
|
+
type: "SEND_SUCCESS",
|
|
215
|
+
message: assistantMessage,
|
|
216
|
+
streamingContent: accumulatedContent,
|
|
217
|
+
conversationId: capturedConversationId
|
|
218
|
+
});
|
|
219
|
+
} catch (err) {
|
|
220
|
+
clearTimeout(timeoutId);
|
|
221
|
+
if (err.name === "AbortError") {
|
|
222
|
+
dispatch({
|
|
223
|
+
type: "SEND_ERROR",
|
|
224
|
+
error: { code: "TIMEOUT", message: "Request timed out", retryable: true }
|
|
225
|
+
});
|
|
226
|
+
} else {
|
|
227
|
+
dispatch({
|
|
228
|
+
type: "SEND_ERROR",
|
|
229
|
+
error: {
|
|
230
|
+
code: "NETWORK_ERROR",
|
|
231
|
+
message: err.message ?? "Network error",
|
|
232
|
+
retryable: true
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
[state.conversationId]
|
|
239
|
+
);
|
|
240
|
+
const setInputValue = (0, import_react.useCallback)((value) => {
|
|
241
|
+
dispatch({ type: "SET_INPUT", value });
|
|
242
|
+
}, []);
|
|
243
|
+
const loadConversation = (0, import_react.useCallback)((conversationId, messages) => {
|
|
244
|
+
dispatch({ type: "LOAD_CONVERSATION", conversationId, messages });
|
|
245
|
+
}, []);
|
|
246
|
+
const submitFeedback = (0, import_react.useCallback)(
|
|
247
|
+
async (messageId, rating, comment) => {
|
|
248
|
+
const { apiUrl, feedbackPath = "/feedback", headers = {} } = configRef.current;
|
|
249
|
+
await fetch(`${apiUrl}${feedbackPath}`, {
|
|
250
|
+
method: "POST",
|
|
251
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
252
|
+
body: JSON.stringify({ messageId, rating, comment })
|
|
253
|
+
});
|
|
254
|
+
},
|
|
255
|
+
[]
|
|
256
|
+
);
|
|
257
|
+
const retry = (0, import_react.useCallback)(async () => {
|
|
258
|
+
if (lastUserMessageRef.current) {
|
|
259
|
+
await sendMessage(lastUserMessageRef.current);
|
|
260
|
+
}
|
|
261
|
+
}, [sendMessage]);
|
|
262
|
+
const reset = (0, import_react.useCallback)(() => {
|
|
263
|
+
dispatch({ type: "RESET" });
|
|
264
|
+
lastUserMessageRef.current = null;
|
|
265
|
+
}, []);
|
|
266
|
+
const actions = {
|
|
267
|
+
sendMessage,
|
|
268
|
+
setInputValue,
|
|
269
|
+
loadConversation,
|
|
270
|
+
submitFeedback,
|
|
271
|
+
retry,
|
|
272
|
+
reset
|
|
273
|
+
};
|
|
274
|
+
return { state, actions };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// src/chat/MessageThread/MessageThread.tsx
|
|
278
|
+
var import_tailwind_merge5 = require("tailwind-merge");
|
|
279
|
+
var import_react3 = require("react");
|
|
280
|
+
|
|
281
|
+
// src/chat/MessageBubble/MessageBubble.tsx
|
|
282
|
+
var import_tailwind_merge4 = require("tailwind-merge");
|
|
283
|
+
|
|
284
|
+
// src/response/AgentResponse/AgentResponse.tsx
|
|
285
|
+
var import_core2 = require("@surf-kit/core");
|
|
286
|
+
|
|
287
|
+
// src/response/ResponseMessage/ResponseMessage.tsx
|
|
288
|
+
var import_react_markdown = __toESM(require("react-markdown"), 1);
|
|
289
|
+
var import_rehype_sanitize = __toESM(require("rehype-sanitize"), 1);
|
|
290
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
291
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
292
|
+
function normalizeMarkdownLists(content) {
|
|
293
|
+
return content.replace(/:\s+-\s+/g, ":\n\n- ");
|
|
294
|
+
}
|
|
295
|
+
function ResponseMessage({ content, className }) {
|
|
296
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
297
|
+
"div",
|
|
298
|
+
{
|
|
299
|
+
className: (0, import_tailwind_merge.twMerge)(
|
|
300
|
+
"text-sm leading-relaxed text-text-primary",
|
|
301
|
+
"[&_p]:my-2",
|
|
302
|
+
"[&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-6",
|
|
303
|
+
"[&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-6",
|
|
304
|
+
"[&_li]:my-1",
|
|
305
|
+
"[&_strong]:text-text-primary [&_strong]:font-semibold",
|
|
306
|
+
"[&_em]:text-text-secondary",
|
|
307
|
+
"[&_h1]:text-lg [&_h1]:font-semibold [&_h1]:text-text-primary [&_h1]:mt-4 [&_h1]:mb-2",
|
|
308
|
+
"[&_h2]:text-base [&_h2]:font-semibold [&_h2]:text-text-primary [&_h2]:mt-3 [&_h2]:mb-1.5",
|
|
309
|
+
"[&_h3]:text-sm [&_h3]:font-semibold [&_h3]:text-accent [&_h3]:mt-2 [&_h3]:mb-1",
|
|
310
|
+
"[&_code]:bg-surface-raised [&_code]:text-accent [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-xs [&_code]:font-mono",
|
|
311
|
+
"[&_pre]:bg-surface-raised [&_pre]:border [&_pre]:border-border [&_pre]:rounded-xl [&_pre]:p-4 [&_pre]:overflow-x-auto",
|
|
312
|
+
"[&_blockquote]:border-l-2 [&_blockquote]:border-border-strong [&_blockquote]:pl-4 [&_blockquote]:text-text-secondary",
|
|
313
|
+
"[&_a]:text-accent [&_a]:underline-offset-2 [&_a]:hover:text-accent/80",
|
|
314
|
+
className
|
|
315
|
+
),
|
|
316
|
+
"data-testid": "response-message",
|
|
317
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
318
|
+
import_react_markdown.default,
|
|
319
|
+
{
|
|
320
|
+
rehypePlugins: [import_rehype_sanitize.default],
|
|
321
|
+
components: {
|
|
322
|
+
script: () => null,
|
|
323
|
+
iframe: () => null,
|
|
324
|
+
p: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "my-2", children }),
|
|
325
|
+
ul: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "my-2 list-disc pl-6", children }),
|
|
326
|
+
ol: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { className: "my-2 list-decimal pl-6", children }),
|
|
327
|
+
li: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: "my-1", children }),
|
|
328
|
+
strong: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { className: "font-semibold", children }),
|
|
329
|
+
h1: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "text-base font-bold mt-4 mb-2", children }),
|
|
330
|
+
h2: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "text-sm font-bold mt-3 mb-1", children }),
|
|
331
|
+
h3: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: "text-sm font-semibold mt-2 mb-1", children }),
|
|
332
|
+
code: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: "bg-surface-sunken rounded px-1 py-0.5 text-xs font-mono", children })
|
|
333
|
+
},
|
|
334
|
+
children: normalizeMarkdownLists(content)
|
|
335
|
+
}
|
|
336
|
+
)
|
|
337
|
+
}
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// src/response/StructuredResponse/StructuredResponse.tsx
|
|
342
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
343
|
+
function tryParse(value) {
|
|
344
|
+
if (value === void 0 || value === null) return null;
|
|
345
|
+
if (typeof value === "string") {
|
|
346
|
+
try {
|
|
347
|
+
return JSON.parse(value);
|
|
348
|
+
} catch {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return value;
|
|
353
|
+
}
|
|
354
|
+
function renderSteps(data) {
|
|
355
|
+
const steps = tryParse(data.steps);
|
|
356
|
+
if (!steps || !Array.isArray(steps)) return null;
|
|
357
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ol", { className: "flex flex-col gap-2", "data-testid": "structured-steps", children: steps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: "flex items-start gap-3", children: [
|
|
358
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
359
|
+
"span",
|
|
360
|
+
{
|
|
361
|
+
className: "mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-accent text-[11px] font-semibold text-white",
|
|
362
|
+
"aria-hidden": "true",
|
|
363
|
+
children: i + 1
|
|
364
|
+
}
|
|
365
|
+
),
|
|
366
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm text-text-primary leading-relaxed", children: step })
|
|
367
|
+
] }, i)) });
|
|
368
|
+
}
|
|
369
|
+
function renderTable(data) {
|
|
370
|
+
const columns = tryParse(data.columns);
|
|
371
|
+
const rawRows = tryParse(data.rows);
|
|
372
|
+
if (columns && rawRows && Array.isArray(columns) && Array.isArray(rawRows)) {
|
|
373
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "overflow-x-auto rounded-lg border border-border", "data-testid": "structured-table", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { role: "table", className: "w-full border-collapse text-sm", children: [
|
|
374
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { className: "bg-surface-raised", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
375
|
+
"th",
|
|
376
|
+
{
|
|
377
|
+
className: "text-left px-4 py-2.5 font-semibold text-text-primary border-b border-border",
|
|
378
|
+
children: col
|
|
379
|
+
},
|
|
380
|
+
col
|
|
381
|
+
)) }) }),
|
|
382
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: rawRows.map((row, i) => {
|
|
383
|
+
const cells = Array.isArray(row) ? row : columns.map((col) => row[col]);
|
|
384
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { className: "even:bg-surface-raised/40", children: cells.map((cell, j) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: "px-4 py-2 text-text-secondary border-b border-border", children: String(cell ?? "") }, j)) }, i);
|
|
385
|
+
}) })
|
|
386
|
+
] }) });
|
|
387
|
+
}
|
|
388
|
+
const entries = Object.entries(data);
|
|
389
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "overflow-x-auto rounded-lg border border-border", "data-testid": "structured-table", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("table", { role: "table", className: "w-full border-collapse text-sm", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: entries.map(([key, value]) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { className: "even:bg-surface-raised/40", children: [
|
|
390
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: "px-4 py-2 text-text-primary font-medium border-b border-border w-1/3", children: key }),
|
|
391
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: "px-4 py-2 text-text-secondary border-b border-border", children: typeof value === "object" ? JSON.stringify(value) : String(value ?? "") })
|
|
392
|
+
] }, key)) }) }) });
|
|
393
|
+
}
|
|
394
|
+
function renderCard(data) {
|
|
395
|
+
const title = typeof data.title === "string" ? data.title : null;
|
|
396
|
+
const body = typeof data.body === "string" ? data.body : null;
|
|
397
|
+
const link = typeof data.link === "string" ? data.link : null;
|
|
398
|
+
const linkLabel = typeof data.link_label === "string" ? data.link_label : "Learn more";
|
|
399
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
400
|
+
"div",
|
|
401
|
+
{
|
|
402
|
+
className: "rounded-xl border border-border bg-surface-raised p-4 flex flex-col gap-2",
|
|
403
|
+
"data-testid": "structured-card",
|
|
404
|
+
children: [
|
|
405
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-sm font-semibold text-text-primary", children: title }),
|
|
406
|
+
body && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-sm text-text-secondary leading-relaxed", children: body }),
|
|
407
|
+
link && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
408
|
+
"a",
|
|
409
|
+
{
|
|
410
|
+
href: link,
|
|
411
|
+
target: "_blank",
|
|
412
|
+
rel: "noopener noreferrer",
|
|
413
|
+
className: "mt-1 inline-flex items-center gap-1 text-xs font-medium text-accent hover:text-accent/80 underline-offset-2 hover:underline transition-colors",
|
|
414
|
+
children: [
|
|
415
|
+
linkLabel,
|
|
416
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) })
|
|
417
|
+
]
|
|
418
|
+
}
|
|
419
|
+
)
|
|
420
|
+
]
|
|
421
|
+
}
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
function renderList(data) {
|
|
425
|
+
const items = tryParse(data.items);
|
|
426
|
+
const title = typeof data.title === "string" ? data.title : null;
|
|
427
|
+
if (!items || !Array.isArray(items)) return null;
|
|
428
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col gap-1.5", "data-testid": "structured-list", children: [
|
|
429
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs font-semibold uppercase tracking-wider text-text-secondary mb-1", children: title }),
|
|
430
|
+
/* @__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: [
|
|
431
|
+
/* @__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" }),
|
|
432
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-sm text-text-primary leading-relaxed", children: item })
|
|
433
|
+
] }, i)) })
|
|
434
|
+
] });
|
|
435
|
+
}
|
|
436
|
+
function renderWarning(data) {
|
|
437
|
+
const severity = typeof data.severity === "string" ? data.severity : "medium";
|
|
438
|
+
const action = typeof data.action === "string" ? data.action : null;
|
|
439
|
+
const details = typeof data.details === "string" ? data.details : null;
|
|
440
|
+
const isHigh = severity === "high";
|
|
441
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
442
|
+
"div",
|
|
443
|
+
{
|
|
444
|
+
role: "alert",
|
|
445
|
+
className: `rounded-xl border p-4 flex gap-3 ${isHigh ? "border-red-200 bg-red-50 dark:border-red-900/50 dark:bg-red-950/30" : "border-amber-200 bg-amber-50 dark:border-amber-900/50 dark:bg-amber-950/30"}`,
|
|
446
|
+
"data-testid": "structured-warning",
|
|
447
|
+
children: [
|
|
448
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
449
|
+
"svg",
|
|
450
|
+
{
|
|
451
|
+
className: `mt-0.5 h-5 w-5 shrink-0 ${isHigh ? "text-red-500" : "text-amber-500"}`,
|
|
452
|
+
fill: "none",
|
|
453
|
+
viewBox: "0 0 24 24",
|
|
454
|
+
stroke: "currentColor",
|
|
455
|
+
strokeWidth: 2,
|
|
456
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" })
|
|
457
|
+
}
|
|
458
|
+
),
|
|
459
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex flex-col gap-1", children: [
|
|
460
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: `text-sm font-semibold ${isHigh ? "text-red-700 dark:text-red-300" : "text-amber-700 dark:text-amber-300"}`, children: action }),
|
|
461
|
+
details && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: `text-sm ${isHigh ? "text-red-600 dark:text-red-400" : "text-amber-600 dark:text-amber-400"}`, children: details })
|
|
462
|
+
] })
|
|
463
|
+
]
|
|
464
|
+
}
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
function StructuredResponse({ uiHint, data, className }) {
|
|
468
|
+
if (!data) return null;
|
|
469
|
+
let content;
|
|
470
|
+
switch (uiHint) {
|
|
471
|
+
case "steps":
|
|
472
|
+
content = renderSteps(data);
|
|
473
|
+
break;
|
|
474
|
+
case "table":
|
|
475
|
+
content = renderTable(data);
|
|
476
|
+
break;
|
|
477
|
+
case "card":
|
|
478
|
+
content = renderCard(data);
|
|
479
|
+
break;
|
|
480
|
+
case "list":
|
|
481
|
+
content = renderList(data);
|
|
482
|
+
break;
|
|
483
|
+
case "warning":
|
|
484
|
+
content = renderWarning(data);
|
|
485
|
+
break;
|
|
486
|
+
case "text":
|
|
487
|
+
content = typeof data.text === "string" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { "data-testid": "structured-text", children: data.text }) : null;
|
|
488
|
+
break;
|
|
489
|
+
default:
|
|
490
|
+
content = null;
|
|
491
|
+
}
|
|
492
|
+
if (!content) return null;
|
|
493
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className, "data-testid": "structured-response", children: content });
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// src/sources/SourceList/SourceList.tsx
|
|
497
|
+
var import_react2 = require("react");
|
|
498
|
+
|
|
499
|
+
// src/sources/SourceCard/SourceCard.tsx
|
|
500
|
+
var import_core = require("@surf-kit/core");
|
|
501
|
+
var import_tailwind_merge2 = require("tailwind-merge");
|
|
502
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
503
|
+
function getConfidenceIntent(confidence) {
|
|
504
|
+
if (confidence >= 0.8) return "success";
|
|
505
|
+
if (confidence >= 0.5) return "warning";
|
|
506
|
+
return "error";
|
|
507
|
+
}
|
|
508
|
+
function getConfidenceLabel(confidence) {
|
|
509
|
+
if (confidence >= 0.8) return "High";
|
|
510
|
+
if (confidence >= 0.5) return "Medium";
|
|
511
|
+
return "Low";
|
|
512
|
+
}
|
|
513
|
+
function SourceCard({ source, variant = "compact", onNavigate, className }) {
|
|
514
|
+
const handleClick = () => {
|
|
515
|
+
if (onNavigate) {
|
|
516
|
+
onNavigate(source);
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
const isCompact = variant === "compact";
|
|
520
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
521
|
+
"div",
|
|
522
|
+
{
|
|
523
|
+
className: (0, import_tailwind_merge2.twMerge)(
|
|
524
|
+
"rounded-xl border transition-all duration-200",
|
|
525
|
+
"bg-surface border-border",
|
|
526
|
+
onNavigate && "cursor-pointer hover:border-border-strong",
|
|
527
|
+
className
|
|
528
|
+
),
|
|
529
|
+
"data-document-id": source.document_id,
|
|
530
|
+
"data-testid": "source-card",
|
|
531
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
532
|
+
"div",
|
|
533
|
+
{
|
|
534
|
+
className: isCompact ? "px-4 py-3" : "px-6 py-4",
|
|
535
|
+
onClick: handleClick,
|
|
536
|
+
role: onNavigate ? "button" : void 0,
|
|
537
|
+
tabIndex: onNavigate ? 0 : void 0,
|
|
538
|
+
onKeyDown: onNavigate ? (e) => {
|
|
539
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
540
|
+
e.preventDefault();
|
|
541
|
+
handleClick();
|
|
542
|
+
}
|
|
543
|
+
} : void 0,
|
|
544
|
+
children: [
|
|
545
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-start justify-between gap-2", children: [
|
|
546
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
547
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-sm font-medium text-text-primary truncate", children: source.title }),
|
|
548
|
+
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 })
|
|
549
|
+
] }),
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
551
|
+
import_core.Badge,
|
|
552
|
+
{
|
|
553
|
+
intent: getConfidenceIntent(source.confidence),
|
|
554
|
+
size: "sm",
|
|
555
|
+
children: getConfidenceLabel(source.confidence)
|
|
556
|
+
}
|
|
557
|
+
)
|
|
558
|
+
] }),
|
|
559
|
+
!isCompact && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-xs text-text-secondary mt-2 line-clamp-3 leading-relaxed", children: source.snippet })
|
|
560
|
+
]
|
|
561
|
+
}
|
|
562
|
+
)
|
|
563
|
+
}
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// src/sources/SourceList/SourceList.tsx
|
|
568
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
569
|
+
function SourceList({
|
|
570
|
+
sources,
|
|
571
|
+
variant = "compact",
|
|
572
|
+
collapsible = false,
|
|
573
|
+
defaultExpanded = true,
|
|
574
|
+
onNavigate,
|
|
575
|
+
className
|
|
576
|
+
}) {
|
|
577
|
+
const [isExpanded, setIsExpanded] = (0, import_react2.useState)(defaultExpanded);
|
|
578
|
+
if (sources.length === 0) return null;
|
|
579
|
+
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)(
|
|
580
|
+
SourceCard,
|
|
581
|
+
{
|
|
582
|
+
source,
|
|
583
|
+
variant,
|
|
584
|
+
onNavigate
|
|
585
|
+
},
|
|
586
|
+
source.document_id
|
|
587
|
+
)) });
|
|
588
|
+
if (!collapsible) {
|
|
589
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, "data-testid": "source-list", children: content });
|
|
590
|
+
}
|
|
591
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className, "data-testid": "source-list", children: [
|
|
592
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
593
|
+
"button",
|
|
594
|
+
{
|
|
595
|
+
type: "button",
|
|
596
|
+
onClick: () => setIsExpanded((prev) => !prev),
|
|
597
|
+
"aria-expanded": isExpanded,
|
|
598
|
+
className: "flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wider text-text-secondary hover:text-accent mb-2 transition-colors duration-200",
|
|
599
|
+
children: [
|
|
600
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
601
|
+
"svg",
|
|
602
|
+
{
|
|
603
|
+
className: `w-4 h-4 transition-transform ${isExpanded ? "rotate-180" : ""}`,
|
|
604
|
+
fill: "none",
|
|
605
|
+
viewBox: "0 0 24 24",
|
|
606
|
+
stroke: "currentColor",
|
|
607
|
+
strokeWidth: 2,
|
|
608
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" })
|
|
609
|
+
}
|
|
610
|
+
),
|
|
611
|
+
"Sources (",
|
|
612
|
+
sources.length,
|
|
613
|
+
")"
|
|
614
|
+
]
|
|
615
|
+
}
|
|
616
|
+
),
|
|
617
|
+
isExpanded && content
|
|
618
|
+
] });
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// src/response/FollowUpChips/FollowUpChips.tsx
|
|
622
|
+
var import_tailwind_merge3 = require("tailwind-merge");
|
|
623
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
624
|
+
function FollowUpChips({ suggestions, onSelect, className }) {
|
|
625
|
+
if (suggestions.length === 0) return null;
|
|
626
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
627
|
+
"div",
|
|
628
|
+
{
|
|
629
|
+
className: (0, import_tailwind_merge3.twMerge)("flex flex-wrap gap-2 py-1", className),
|
|
630
|
+
role: "group",
|
|
631
|
+
"aria-label": "Follow-up suggestions",
|
|
632
|
+
"data-testid": "follow-up-chips",
|
|
633
|
+
children: suggestions.map((suggestion) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
634
|
+
"button",
|
|
635
|
+
{
|
|
636
|
+
type: "button",
|
|
637
|
+
onClick: () => onSelect(suggestion),
|
|
638
|
+
className: (0, import_tailwind_merge3.twMerge)(
|
|
639
|
+
"px-4 py-1.5 rounded-full text-sm whitespace-nowrap",
|
|
640
|
+
"border border-border bg-transparent text-text-secondary",
|
|
641
|
+
"hover:bg-accent/10 hover:border-interactive hover:text-text-primary",
|
|
642
|
+
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
|
|
643
|
+
"transition-all duration-200"
|
|
644
|
+
),
|
|
645
|
+
children: suggestion
|
|
646
|
+
},
|
|
647
|
+
suggestion
|
|
648
|
+
))
|
|
649
|
+
}
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// src/response/AgentResponse/AgentResponse.tsx
|
|
654
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
655
|
+
function getConfidenceIntent2(overall) {
|
|
656
|
+
if (overall === "high") return "success";
|
|
657
|
+
if (overall === "medium") return "warning";
|
|
658
|
+
return "error";
|
|
659
|
+
}
|
|
660
|
+
function getVerificationIntent(status) {
|
|
661
|
+
if (status === "passed") return "success";
|
|
662
|
+
if (status === "flagged") return "warning";
|
|
663
|
+
return "error";
|
|
664
|
+
}
|
|
665
|
+
function getVerificationLabel(status) {
|
|
666
|
+
if (status === "passed") return "Verified";
|
|
667
|
+
if (status === "flagged") return "Flagged";
|
|
668
|
+
return "Failed";
|
|
669
|
+
}
|
|
670
|
+
function AgentResponse({
|
|
671
|
+
response,
|
|
672
|
+
showSources = true,
|
|
673
|
+
showConfidence = false,
|
|
674
|
+
showVerification = false,
|
|
675
|
+
onFollowUp,
|
|
676
|
+
onNavigateSource,
|
|
677
|
+
className
|
|
678
|
+
}) {
|
|
679
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `flex flex-col gap-4 ${className ?? ""}`, "data-testid": "agent-response", children: [
|
|
680
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ResponseMessage, { content: response.message }),
|
|
681
|
+
response.ui_hint !== "text" && response.structured_data && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
682
|
+
StructuredResponse,
|
|
683
|
+
{
|
|
684
|
+
uiHint: response.ui_hint,
|
|
685
|
+
data: response.structured_data
|
|
686
|
+
}
|
|
687
|
+
),
|
|
688
|
+
(showConfidence || showVerification) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-2 mt-1", "data-testid": "response-meta", children: [
|
|
689
|
+
showConfidence && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
690
|
+
import_core2.Badge,
|
|
691
|
+
{
|
|
692
|
+
intent: getConfidenceIntent2(response.confidence.overall),
|
|
693
|
+
size: "sm",
|
|
694
|
+
children: [
|
|
695
|
+
response.confidence.overall,
|
|
696
|
+
" confidence"
|
|
697
|
+
]
|
|
698
|
+
}
|
|
699
|
+
),
|
|
700
|
+
showVerification && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
701
|
+
import_core2.Badge,
|
|
702
|
+
{
|
|
703
|
+
intent: getVerificationIntent(response.verification.status),
|
|
704
|
+
size: "sm",
|
|
705
|
+
children: [
|
|
706
|
+
getVerificationLabel(response.verification.status),
|
|
707
|
+
" (",
|
|
708
|
+
response.verification.claims_verified,
|
|
709
|
+
"/",
|
|
710
|
+
response.verification.claims_checked,
|
|
711
|
+
")"
|
|
712
|
+
]
|
|
713
|
+
}
|
|
714
|
+
)
|
|
715
|
+
] }),
|
|
716
|
+
showSources && response.sources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
717
|
+
SourceList,
|
|
718
|
+
{
|
|
719
|
+
sources: response.sources,
|
|
720
|
+
variant: "compact",
|
|
721
|
+
collapsible: true,
|
|
722
|
+
defaultExpanded: false,
|
|
723
|
+
onNavigate: onNavigateSource
|
|
724
|
+
}
|
|
725
|
+
),
|
|
726
|
+
response.follow_up_suggestions.length > 0 && onFollowUp && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
727
|
+
FollowUpChips,
|
|
728
|
+
{
|
|
729
|
+
suggestions: response.follow_up_suggestions,
|
|
730
|
+
onSelect: onFollowUp
|
|
731
|
+
}
|
|
732
|
+
)
|
|
733
|
+
] });
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// src/chat/MessageBubble/MessageBubble.tsx
|
|
737
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
738
|
+
function MessageBubble({
|
|
739
|
+
message,
|
|
740
|
+
showAgent,
|
|
741
|
+
showSources = true,
|
|
742
|
+
showConfidence = true,
|
|
743
|
+
showVerification = true,
|
|
744
|
+
animated = true,
|
|
745
|
+
className
|
|
746
|
+
}) {
|
|
747
|
+
const isUser = message.role === "user";
|
|
748
|
+
if (isUser) {
|
|
749
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
750
|
+
"div",
|
|
751
|
+
{
|
|
752
|
+
"data-message-id": message.id,
|
|
753
|
+
className: (0, import_tailwind_merge4.twMerge)("flex w-full justify-end", className),
|
|
754
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
755
|
+
"div",
|
|
756
|
+
{
|
|
757
|
+
className: (0, import_tailwind_merge4.twMerge)(
|
|
758
|
+
"max-w-[70%] rounded-[18px] rounded-br-[4px] px-4 py-2.5 bg-accent text-brand-cream break-words whitespace-pre-wrap text-sm leading-relaxed",
|
|
759
|
+
animated && "motion-safe:animate-slideFromRight"
|
|
760
|
+
),
|
|
761
|
+
children: message.content
|
|
762
|
+
}
|
|
763
|
+
)
|
|
764
|
+
}
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
768
|
+
"div",
|
|
769
|
+
{
|
|
770
|
+
"data-message-id": message.id,
|
|
771
|
+
className: (0, import_tailwind_merge4.twMerge)("flex w-full flex-col items-start gap-1.5", className),
|
|
772
|
+
children: [
|
|
773
|
+
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("_", " ") }),
|
|
774
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
775
|
+
"div",
|
|
776
|
+
{
|
|
777
|
+
className: (0, import_tailwind_merge4.twMerge)(
|
|
778
|
+
"max-w-[88%] rounded-[18px] rounded-tl-[4px] px-4 py-3 bg-surface border border-border",
|
|
779
|
+
animated && "motion-safe:animate-springFromLeft"
|
|
780
|
+
),
|
|
781
|
+
children: message.response ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
782
|
+
AgentResponse,
|
|
783
|
+
{
|
|
784
|
+
response: message.response,
|
|
785
|
+
showSources,
|
|
786
|
+
showConfidence,
|
|
787
|
+
showVerification
|
|
788
|
+
}
|
|
789
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ResponseMessage, { content: message.content })
|
|
790
|
+
}
|
|
791
|
+
)
|
|
792
|
+
]
|
|
793
|
+
}
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// src/chat/MessageThread/MessageThread.tsx
|
|
798
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
799
|
+
function MessageThread({ messages, streamingSlot, showSources, showConfidence, showVerification, className }) {
|
|
800
|
+
const bottomRef = (0, import_react3.useRef)(null);
|
|
801
|
+
(0, import_react3.useEffect)(() => {
|
|
802
|
+
bottomRef.current?.scrollIntoView?.({ behavior: "smooth" });
|
|
803
|
+
}, [messages.length, streamingSlot]);
|
|
804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
805
|
+
"div",
|
|
806
|
+
{
|
|
807
|
+
role: "log",
|
|
808
|
+
"aria-live": "polite",
|
|
809
|
+
"aria-label": "Message thread",
|
|
810
|
+
className: (0, import_tailwind_merge5.twMerge)(
|
|
811
|
+
"flex flex-col gap-4 overflow-y-auto flex-1 px-4 py-6",
|
|
812
|
+
className
|
|
813
|
+
),
|
|
814
|
+
children: [
|
|
815
|
+
messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
816
|
+
MessageBubble,
|
|
817
|
+
{
|
|
818
|
+
message,
|
|
819
|
+
showSources,
|
|
820
|
+
showConfidence,
|
|
821
|
+
showVerification
|
|
822
|
+
},
|
|
823
|
+
message.id
|
|
824
|
+
)),
|
|
825
|
+
streamingSlot,
|
|
826
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { ref: bottomRef })
|
|
827
|
+
]
|
|
828
|
+
}
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// src/chat/MessageComposer/MessageComposer.tsx
|
|
833
|
+
var import_tailwind_merge6 = require("tailwind-merge");
|
|
834
|
+
var import_react4 = require("react");
|
|
835
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
836
|
+
function MessageComposer({
|
|
837
|
+
onSend,
|
|
838
|
+
isLoading = false,
|
|
839
|
+
placeholder = "Type a message...",
|
|
840
|
+
className
|
|
841
|
+
}) {
|
|
842
|
+
const [value, setValue] = (0, import_react4.useState)("");
|
|
843
|
+
const textareaRef = (0, import_react4.useRef)(null);
|
|
844
|
+
const canSend = value.trim().length > 0 && !isLoading;
|
|
845
|
+
const resetHeight = (0, import_react4.useCallback)(() => {
|
|
846
|
+
const el = textareaRef.current;
|
|
847
|
+
if (el) {
|
|
848
|
+
el.style.height = "auto";
|
|
849
|
+
el.style.overflowY = "hidden";
|
|
850
|
+
}
|
|
851
|
+
}, []);
|
|
852
|
+
const handleSend = (0, import_react4.useCallback)(() => {
|
|
853
|
+
if (!canSend) return;
|
|
854
|
+
onSend(value.trim());
|
|
855
|
+
setValue("");
|
|
856
|
+
resetHeight();
|
|
857
|
+
textareaRef.current?.focus();
|
|
858
|
+
}, [canSend, onSend, value, resetHeight]);
|
|
859
|
+
const handleKeyDown = (0, import_react4.useCallback)(
|
|
860
|
+
(e) => {
|
|
861
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
862
|
+
e.preventDefault();
|
|
863
|
+
handleSend();
|
|
864
|
+
}
|
|
865
|
+
},
|
|
866
|
+
[handleSend]
|
|
867
|
+
);
|
|
868
|
+
const handleChange = (0, import_react4.useCallback)(
|
|
869
|
+
(e) => {
|
|
870
|
+
setValue(e.target.value);
|
|
871
|
+
const el = e.target;
|
|
872
|
+
el.style.height = "auto";
|
|
873
|
+
const capped = Math.min(el.scrollHeight, 128);
|
|
874
|
+
el.style.height = `${capped}px`;
|
|
875
|
+
el.style.overflowY = el.scrollHeight > 128 ? "auto" : "hidden";
|
|
876
|
+
},
|
|
877
|
+
[]
|
|
878
|
+
);
|
|
879
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
880
|
+
"div",
|
|
881
|
+
{
|
|
882
|
+
className: (0, import_tailwind_merge6.twMerge)(
|
|
883
|
+
"flex items-end gap-3 shrink-0 border-t border-border px-4 py-3",
|
|
884
|
+
className
|
|
885
|
+
),
|
|
886
|
+
children: [
|
|
887
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
888
|
+
"textarea",
|
|
889
|
+
{
|
|
890
|
+
ref: textareaRef,
|
|
891
|
+
value,
|
|
892
|
+
onChange: handleChange,
|
|
893
|
+
onKeyDown: handleKeyDown,
|
|
894
|
+
placeholder,
|
|
895
|
+
rows: 1,
|
|
896
|
+
disabled: isLoading,
|
|
897
|
+
className: (0, import_tailwind_merge6.twMerge)(
|
|
898
|
+
"flex-1 resize-none rounded-xl border border-border bg-surface/80",
|
|
899
|
+
"px-4 py-2.5 text-sm text-text-primary placeholder:text-text-muted",
|
|
900
|
+
"focus:border-transparent focus:ring-2 focus:ring-accent/40 focus:outline-none",
|
|
901
|
+
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
902
|
+
"overflow-hidden",
|
|
903
|
+
"transition-all duration-200"
|
|
904
|
+
),
|
|
905
|
+
style: { colorScheme: "dark" },
|
|
906
|
+
"aria-label": "Message input"
|
|
907
|
+
}
|
|
908
|
+
),
|
|
909
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
910
|
+
"button",
|
|
911
|
+
{
|
|
912
|
+
type: "button",
|
|
913
|
+
onClick: handleSend,
|
|
914
|
+
disabled: !value.trim() || isLoading,
|
|
915
|
+
"aria-label": "Send message",
|
|
916
|
+
className: (0, import_tailwind_merge6.twMerge)(
|
|
917
|
+
"inline-flex items-center justify-center rounded-xl px-5 py-2.5",
|
|
918
|
+
"text-sm font-semibold text-white shrink-0",
|
|
919
|
+
"transition-all duration-200",
|
|
920
|
+
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
|
|
921
|
+
value.trim() && !isLoading ? "bg-accent hover:bg-accent-hover hover:scale-[1.02] hover:shadow-glow-cyan active:scale-[0.98]" : "bg-accent/30 text-text-muted cursor-not-allowed"
|
|
922
|
+
),
|
|
923
|
+
children: "Send"
|
|
924
|
+
}
|
|
925
|
+
)
|
|
926
|
+
]
|
|
927
|
+
}
|
|
928
|
+
);
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// src/chat/WelcomeScreen/WelcomeScreen.tsx
|
|
932
|
+
var import_tailwind_merge7 = require("tailwind-merge");
|
|
933
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
934
|
+
function WelcomeScreen({
|
|
935
|
+
title = "Welcome",
|
|
936
|
+
message = "How can I help you today?",
|
|
937
|
+
icon,
|
|
938
|
+
suggestedQuestions = [],
|
|
939
|
+
onQuestionSelect,
|
|
940
|
+
className
|
|
941
|
+
}) {
|
|
942
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
943
|
+
"div",
|
|
944
|
+
{
|
|
945
|
+
className: (0, import_tailwind_merge7.twMerge)(
|
|
946
|
+
"flex flex-1 flex-col items-center justify-center gap-8 p-8 text-center motion-safe:animate-fadeUp",
|
|
947
|
+
className
|
|
948
|
+
),
|
|
949
|
+
children: [
|
|
950
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
951
|
+
"div",
|
|
952
|
+
{
|
|
953
|
+
className: "w-14 h-14 rounded-2xl bg-accent/10 border border-border flex items-center justify-center pulse-glow",
|
|
954
|
+
"aria-hidden": "true",
|
|
955
|
+
children: icon ?? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-2xl", children: "\u2726" })
|
|
956
|
+
}
|
|
957
|
+
),
|
|
958
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
959
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { className: "text-3xl font-bold text-text-primary", children: title }),
|
|
960
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-text-secondary text-base leading-relaxed max-w-md", children: message })
|
|
961
|
+
] }),
|
|
962
|
+
suggestedQuestions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
963
|
+
"div",
|
|
964
|
+
{
|
|
965
|
+
className: "flex flex-wrap justify-center gap-2 max-w-md",
|
|
966
|
+
role: "group",
|
|
967
|
+
"aria-label": "Suggested questions",
|
|
968
|
+
children: suggestedQuestions.map((question) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
969
|
+
"button",
|
|
970
|
+
{
|
|
971
|
+
type: "button",
|
|
972
|
+
onClick: () => onQuestionSelect?.(question),
|
|
973
|
+
className: (0, import_tailwind_merge7.twMerge)(
|
|
974
|
+
"px-4 py-2 rounded-full text-sm",
|
|
975
|
+
"border border-border bg-transparent text-text-secondary",
|
|
976
|
+
"hover:bg-accent/10 hover:border-interactive hover:text-text-primary",
|
|
977
|
+
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent",
|
|
978
|
+
"transition-colors duration-200"
|
|
979
|
+
),
|
|
980
|
+
children: question
|
|
981
|
+
},
|
|
982
|
+
question
|
|
983
|
+
))
|
|
984
|
+
}
|
|
985
|
+
)
|
|
986
|
+
]
|
|
987
|
+
}
|
|
988
|
+
);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
// src/streaming/StreamingMessage/StreamingMessage.tsx
|
|
992
|
+
var import_react6 = require("react");
|
|
993
|
+
var import_core3 = require("@surf-kit/core");
|
|
994
|
+
|
|
995
|
+
// src/hooks/useCharacterDrain.ts
|
|
996
|
+
var import_react5 = require("react");
|
|
997
|
+
function useCharacterDrain(target, msPerChar = 15) {
|
|
998
|
+
const [displayed, setDisplayed] = (0, import_react5.useState)("");
|
|
999
|
+
const indexRef = (0, import_react5.useRef)(0);
|
|
1000
|
+
const lastTimeRef = (0, import_react5.useRef)(0);
|
|
1001
|
+
const rafRef = (0, import_react5.useRef)(null);
|
|
1002
|
+
const drainTargetRef = (0, import_react5.useRef)("");
|
|
1003
|
+
const msPerCharRef = (0, import_react5.useRef)(msPerChar);
|
|
1004
|
+
msPerCharRef.current = msPerChar;
|
|
1005
|
+
if (target !== "") {
|
|
1006
|
+
drainTargetRef.current = target;
|
|
1007
|
+
}
|
|
1008
|
+
const drainTarget = drainTargetRef.current;
|
|
1009
|
+
const isDraining = displayed.length < drainTarget.length;
|
|
1010
|
+
const tickRef = (0, import_react5.useRef)(() => {
|
|
1011
|
+
});
|
|
1012
|
+
tickRef.current = (now) => {
|
|
1013
|
+
const currentTarget = drainTargetRef.current;
|
|
1014
|
+
if (currentTarget === "") {
|
|
1015
|
+
rafRef.current = null;
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
if (lastTimeRef.current === 0) lastTimeRef.current = now;
|
|
1019
|
+
const elapsed = now - lastTimeRef.current;
|
|
1020
|
+
const charsToAdvance = Math.floor(elapsed / msPerCharRef.current);
|
|
1021
|
+
if (charsToAdvance > 0 && indexRef.current < currentTarget.length) {
|
|
1022
|
+
const nextIndex = Math.min(indexRef.current + charsToAdvance, currentTarget.length);
|
|
1023
|
+
indexRef.current = nextIndex;
|
|
1024
|
+
lastTimeRef.current = now;
|
|
1025
|
+
setDisplayed(currentTarget.slice(0, nextIndex));
|
|
1026
|
+
}
|
|
1027
|
+
if (indexRef.current < currentTarget.length) {
|
|
1028
|
+
rafRef.current = requestAnimationFrame((t) => tickRef.current(t));
|
|
1029
|
+
} else {
|
|
1030
|
+
rafRef.current = null;
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
(0, import_react5.useEffect)(() => {
|
|
1034
|
+
if (drainTargetRef.current !== "" && indexRef.current < drainTargetRef.current.length && rafRef.current === null) {
|
|
1035
|
+
rafRef.current = requestAnimationFrame((t) => tickRef.current(t));
|
|
1036
|
+
}
|
|
1037
|
+
}, [drainTarget]);
|
|
1038
|
+
(0, import_react5.useEffect)(() => {
|
|
1039
|
+
if (target === "" && !isDraining && displayed !== "") {
|
|
1040
|
+
indexRef.current = 0;
|
|
1041
|
+
lastTimeRef.current = 0;
|
|
1042
|
+
drainTargetRef.current = "";
|
|
1043
|
+
setDisplayed("");
|
|
1044
|
+
}
|
|
1045
|
+
}, [target, isDraining, displayed]);
|
|
1046
|
+
(0, import_react5.useEffect)(() => {
|
|
1047
|
+
return () => {
|
|
1048
|
+
if (rafRef.current !== null) {
|
|
1049
|
+
cancelAnimationFrame(rafRef.current);
|
|
1050
|
+
rafRef.current = null;
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
}, []);
|
|
1054
|
+
return { displayed, isDraining };
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
// src/streaming/StreamingMessage/StreamingMessage.tsx
|
|
1058
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1059
|
+
var phaseLabels = {
|
|
1060
|
+
idle: "",
|
|
1061
|
+
waiting: "Waiting...",
|
|
1062
|
+
thinking: "Thinking...",
|
|
1063
|
+
retrieving: "Searching...",
|
|
1064
|
+
generating: "Writing...",
|
|
1065
|
+
verifying: "Verifying..."
|
|
1066
|
+
};
|
|
1067
|
+
function StreamingMessage({
|
|
1068
|
+
stream,
|
|
1069
|
+
onComplete,
|
|
1070
|
+
showPhases = true,
|
|
1071
|
+
className
|
|
1072
|
+
}) {
|
|
1073
|
+
const onCompleteRef = (0, import_react6.useRef)(onComplete);
|
|
1074
|
+
onCompleteRef.current = onComplete;
|
|
1075
|
+
const wasActiveRef = (0, import_react6.useRef)(stream.active);
|
|
1076
|
+
(0, import_react6.useEffect)(() => {
|
|
1077
|
+
if (wasActiveRef.current && !stream.active) {
|
|
1078
|
+
onCompleteRef.current?.();
|
|
1079
|
+
}
|
|
1080
|
+
wasActiveRef.current = stream.active;
|
|
1081
|
+
}, [stream.active]);
|
|
1082
|
+
const phaseLabel = phaseLabels[stream.phase];
|
|
1083
|
+
const { displayed: displayedContent } = useCharacterDrain(stream.content);
|
|
1084
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className, "data-testid": "streaming-message", children: [
|
|
1085
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { "aria-live": "assertive", className: "sr-only", children: [
|
|
1086
|
+
stream.active && stream.phase !== "idle" && "Response started",
|
|
1087
|
+
!stream.active && stream.content && "Response complete"
|
|
1088
|
+
] }),
|
|
1089
|
+
/* @__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: [
|
|
1090
|
+
showPhases && stream.active && stream.phase !== "idle" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1091
|
+
"div",
|
|
1092
|
+
{
|
|
1093
|
+
className: "flex items-center gap-2 mb-2 text-sm text-text-secondary",
|
|
1094
|
+
"data-testid": "phase-indicator",
|
|
1095
|
+
children: [
|
|
1096
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_core3.Spinner, { size: "sm" }) }),
|
|
1097
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: phaseLabel })
|
|
1098
|
+
]
|
|
1099
|
+
}
|
|
1100
|
+
),
|
|
1101
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "text-sm leading-relaxed text-text-primary whitespace-pre-wrap", children: [
|
|
1102
|
+
displayedContent,
|
|
1103
|
+
stream.active && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1104
|
+
"span",
|
|
1105
|
+
{
|
|
1106
|
+
className: "inline-block w-0.5 h-4 bg-accent align-text-bottom animate-pulse ml-0.5",
|
|
1107
|
+
"aria-hidden": "true",
|
|
1108
|
+
"data-testid": "streaming-cursor"
|
|
1109
|
+
}
|
|
1110
|
+
)
|
|
1111
|
+
] })
|
|
1112
|
+
] })
|
|
1113
|
+
] });
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// src/chat/AgentChat/AgentChat.tsx
|
|
1117
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1118
|
+
function AgentChat({
|
|
1119
|
+
endpoint,
|
|
1120
|
+
title = "Chat",
|
|
1121
|
+
welcomeTitle,
|
|
1122
|
+
welcomeMessage = "How can I help you today?",
|
|
1123
|
+
suggestedQuestions = [],
|
|
1124
|
+
showHeader = true,
|
|
1125
|
+
showWelcomeTitle = true,
|
|
1126
|
+
showSources,
|
|
1127
|
+
showConfidence,
|
|
1128
|
+
showVerification,
|
|
1129
|
+
className
|
|
1130
|
+
}) {
|
|
1131
|
+
const { state, actions } = useAgentChat({ apiUrl: endpoint });
|
|
1132
|
+
const hasMessages = state.messages.length > 0;
|
|
1133
|
+
const handleSend = (content) => {
|
|
1134
|
+
void actions.sendMessage(content);
|
|
1135
|
+
};
|
|
1136
|
+
const handleQuestionSelect = (question) => {
|
|
1137
|
+
void actions.sendMessage(question);
|
|
1138
|
+
};
|
|
1139
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
1140
|
+
"div",
|
|
1141
|
+
{
|
|
1142
|
+
className: (0, import_tailwind_merge8.twMerge)(
|
|
1143
|
+
"flex flex-col h-full bg-canvas border border-border rounded-xl overflow-hidden",
|
|
1144
|
+
className
|
|
1145
|
+
),
|
|
1146
|
+
children: [
|
|
1147
|
+
showHeader && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex items-center justify-between border-b border-border px-4 py-3 bg-surface-raised shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h1", { className: "text-base font-semibold text-text-primary", children: title }) }),
|
|
1148
|
+
hasMessages ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1149
|
+
MessageThread,
|
|
1150
|
+
{
|
|
1151
|
+
messages: state.messages,
|
|
1152
|
+
streamingSlot: state.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1153
|
+
StreamingMessage,
|
|
1154
|
+
{
|
|
1155
|
+
stream: {
|
|
1156
|
+
active: state.isLoading,
|
|
1157
|
+
phase: state.streamPhase,
|
|
1158
|
+
content: state.streamingContent,
|
|
1159
|
+
sources: [],
|
|
1160
|
+
agent: null,
|
|
1161
|
+
agentLabel: null
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
) : void 0,
|
|
1165
|
+
showSources,
|
|
1166
|
+
showConfidence,
|
|
1167
|
+
showVerification
|
|
1168
|
+
}
|
|
1169
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1170
|
+
WelcomeScreen,
|
|
1171
|
+
{
|
|
1172
|
+
title: showWelcomeTitle ? welcomeTitle ?? title : "",
|
|
1173
|
+
message: welcomeMessage,
|
|
1174
|
+
suggestedQuestions,
|
|
1175
|
+
onQuestionSelect: handleQuestionSelect
|
|
1176
|
+
}
|
|
1177
|
+
),
|
|
1178
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MessageComposer, { onSend: handleSend, isLoading: state.isLoading })
|
|
1179
|
+
]
|
|
1180
|
+
}
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// src/chat/ConversationList/ConversationList.tsx
|
|
1185
|
+
var import_tailwind_merge9 = require("tailwind-merge");
|
|
1186
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1187
|
+
function ConversationList({
|
|
1188
|
+
conversations,
|
|
1189
|
+
activeId,
|
|
1190
|
+
onSelect,
|
|
1191
|
+
onDelete,
|
|
1192
|
+
onNew,
|
|
1193
|
+
className
|
|
1194
|
+
}) {
|
|
1195
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1196
|
+
"nav",
|
|
1197
|
+
{
|
|
1198
|
+
"aria-label": "Conversation list",
|
|
1199
|
+
className: (0, import_tailwind_merge9.twMerge)("flex flex-col h-full bg-canvas", className),
|
|
1200
|
+
children: [
|
|
1201
|
+
onNew && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "p-3 border-b border-border", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1202
|
+
"button",
|
|
1203
|
+
{
|
|
1204
|
+
type: "button",
|
|
1205
|
+
onClick: onNew,
|
|
1206
|
+
className: "w-full px-4 py-2.5 rounded-xl text-sm font-semibold bg-accent text-white hover:bg-accent-hover transition-all duration-200",
|
|
1207
|
+
children: "New conversation"
|
|
1208
|
+
}
|
|
1209
|
+
) }),
|
|
1210
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("ul", { role: "list", className: "flex-1 overflow-y-auto", children: [
|
|
1211
|
+
conversations.map((conversation) => {
|
|
1212
|
+
const isActive = conversation.id === activeId;
|
|
1213
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1214
|
+
"li",
|
|
1215
|
+
{
|
|
1216
|
+
className: (0, import_tailwind_merge9.twMerge)(
|
|
1217
|
+
"flex items-start border-b border-border transition-colors duration-200",
|
|
1218
|
+
"hover:bg-surface",
|
|
1219
|
+
isActive && "bg-surface-raised border-l-2 border-l-accent"
|
|
1220
|
+
),
|
|
1221
|
+
children: [
|
|
1222
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1223
|
+
"button",
|
|
1224
|
+
{
|
|
1225
|
+
type: "button",
|
|
1226
|
+
onClick: () => onSelect(conversation.id),
|
|
1227
|
+
"aria-current": isActive ? "true" : void 0,
|
|
1228
|
+
className: "flex-1 min-w-0 text-left px-4 py-3",
|
|
1229
|
+
children: [
|
|
1230
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-sm font-medium text-brand-cream truncate", children: conversation.title }),
|
|
1231
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "text-xs text-brand-cream/40 truncate mt-0.5 leading-relaxed", children: conversation.lastMessage })
|
|
1232
|
+
]
|
|
1233
|
+
}
|
|
1234
|
+
),
|
|
1235
|
+
onDelete && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1236
|
+
"button",
|
|
1237
|
+
{
|
|
1238
|
+
type: "button",
|
|
1239
|
+
onClick: () => onDelete(conversation.id),
|
|
1240
|
+
"aria-label": `Delete ${conversation.title}`,
|
|
1241
|
+
className: "shrink-0 p-1.5 m-2 rounded-lg text-brand-cream/25 hover:text-brand-watermelon hover:bg-brand-watermelon/10 transition-colors duration-200",
|
|
1242
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1243
|
+
"svg",
|
|
1244
|
+
{
|
|
1245
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1246
|
+
width: "14",
|
|
1247
|
+
height: "14",
|
|
1248
|
+
viewBox: "0 0 24 24",
|
|
1249
|
+
fill: "none",
|
|
1250
|
+
stroke: "currentColor",
|
|
1251
|
+
strokeWidth: "2",
|
|
1252
|
+
strokeLinecap: "round",
|
|
1253
|
+
strokeLinejoin: "round",
|
|
1254
|
+
"aria-hidden": "true",
|
|
1255
|
+
children: [
|
|
1256
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("polyline", { points: "3 6 5 6 21 6" }),
|
|
1257
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
|
|
1258
|
+
]
|
|
1259
|
+
}
|
|
1260
|
+
)
|
|
1261
|
+
}
|
|
1262
|
+
)
|
|
1263
|
+
]
|
|
1264
|
+
},
|
|
1265
|
+
conversation.id
|
|
1266
|
+
);
|
|
1267
|
+
}),
|
|
1268
|
+
conversations.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("li", { className: "px-4 py-8 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-sm text-brand-cream/30 font-body", children: "No conversations yet" }) })
|
|
1269
|
+
] })
|
|
1270
|
+
]
|
|
1271
|
+
}
|
|
1272
|
+
);
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
// src/layouts/AgentFullPage/AgentFullPage.tsx
|
|
1276
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1277
|
+
function AgentFullPage({
|
|
1278
|
+
endpoint,
|
|
1279
|
+
title = "Chat",
|
|
1280
|
+
showConversationList = false,
|
|
1281
|
+
conversations = [],
|
|
1282
|
+
activeConversationId,
|
|
1283
|
+
onConversationSelect,
|
|
1284
|
+
onConversationDelete,
|
|
1285
|
+
onNewConversation,
|
|
1286
|
+
className
|
|
1287
|
+
}) {
|
|
1288
|
+
const [sidebarOpen, setSidebarOpen] = (0, import_react7.useState)(false);
|
|
1289
|
+
const handleSelect = (0, import_react7.useCallback)(
|
|
1290
|
+
(id) => {
|
|
1291
|
+
onConversationSelect?.(id);
|
|
1292
|
+
setSidebarOpen(false);
|
|
1293
|
+
},
|
|
1294
|
+
[onConversationSelect]
|
|
1295
|
+
);
|
|
1296
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1297
|
+
"div",
|
|
1298
|
+
{
|
|
1299
|
+
className: (0, import_tailwind_merge10.twMerge)("flex h-screen w-full overflow-hidden bg-brand-dark", className),
|
|
1300
|
+
"data-testid": "agent-full-page",
|
|
1301
|
+
children: [
|
|
1302
|
+
showConversationList && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
|
|
1303
|
+
sidebarOpen && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1304
|
+
"div",
|
|
1305
|
+
{
|
|
1306
|
+
className: "fixed inset-0 bg-brand-dark/80 backdrop-blur-sm z-30 md:hidden",
|
|
1307
|
+
onClick: () => setSidebarOpen(false),
|
|
1308
|
+
"data-testid": "sidebar-overlay"
|
|
1309
|
+
}
|
|
1310
|
+
),
|
|
1311
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1312
|
+
"aside",
|
|
1313
|
+
{
|
|
1314
|
+
className: (0, import_tailwind_merge10.twMerge)(
|
|
1315
|
+
"bg-brand-dark border-r border-brand-gold/15 w-72 shrink-0 flex-col z-40",
|
|
1316
|
+
// Desktop: always visible
|
|
1317
|
+
"hidden md:flex",
|
|
1318
|
+
// Mobile: overlay when open
|
|
1319
|
+
sidebarOpen && "fixed inset-y-0 left-0 flex md:relative"
|
|
1320
|
+
),
|
|
1321
|
+
"aria-label": "Conversations sidebar",
|
|
1322
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1323
|
+
ConversationList,
|
|
1324
|
+
{
|
|
1325
|
+
conversations,
|
|
1326
|
+
activeId: activeConversationId,
|
|
1327
|
+
onSelect: handleSelect,
|
|
1328
|
+
onDelete: onConversationDelete,
|
|
1329
|
+
onNew: onNewConversation
|
|
1330
|
+
}
|
|
1331
|
+
)
|
|
1332
|
+
}
|
|
1333
|
+
)
|
|
1334
|
+
] }),
|
|
1335
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex-1 flex flex-col min-w-0 bg-brand-dark", children: [
|
|
1336
|
+
showConversationList && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "md:hidden flex items-center border-b border-brand-gold/15 px-3 py-2 bg-brand-dark-panel/60 backdrop-blur-sm", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1337
|
+
"button",
|
|
1338
|
+
{
|
|
1339
|
+
type: "button",
|
|
1340
|
+
onClick: () => setSidebarOpen(true),
|
|
1341
|
+
"aria-label": "Open conversations sidebar",
|
|
1342
|
+
className: "p-2 rounded-xl text-brand-cream/60 hover:text-brand-cream hover:bg-brand-dark-panel transition-colors duration-200",
|
|
1343
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1344
|
+
"svg",
|
|
1345
|
+
{
|
|
1346
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1347
|
+
width: "20",
|
|
1348
|
+
height: "20",
|
|
1349
|
+
viewBox: "0 0 24 24",
|
|
1350
|
+
fill: "none",
|
|
1351
|
+
stroke: "currentColor",
|
|
1352
|
+
strokeWidth: "2",
|
|
1353
|
+
strokeLinecap: "round",
|
|
1354
|
+
strokeLinejoin: "round",
|
|
1355
|
+
"aria-hidden": "true",
|
|
1356
|
+
children: [
|
|
1357
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("line", { x1: "3", y1: "12", x2: "21", y2: "12" }),
|
|
1358
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("line", { x1: "3", y1: "6", x2: "21", y2: "6" }),
|
|
1359
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("line", { x1: "3", y1: "18", x2: "21", y2: "18" })
|
|
1360
|
+
]
|
|
1361
|
+
}
|
|
1362
|
+
)
|
|
1363
|
+
}
|
|
1364
|
+
) }),
|
|
1365
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1366
|
+
AgentChat,
|
|
1367
|
+
{
|
|
1368
|
+
endpoint,
|
|
1369
|
+
title,
|
|
1370
|
+
className: "flex-1 rounded-none border-0"
|
|
1371
|
+
}
|
|
1372
|
+
)
|
|
1373
|
+
] })
|
|
1374
|
+
]
|
|
1375
|
+
}
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
// src/layouts/AgentPanel/AgentPanel.tsx
|
|
1380
|
+
var import_tailwind_merge11 = require("tailwind-merge");
|
|
1381
|
+
var import_react8 = require("react");
|
|
1382
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1383
|
+
function AgentPanel({
|
|
1384
|
+
endpoint,
|
|
1385
|
+
isOpen,
|
|
1386
|
+
onClose,
|
|
1387
|
+
side = "right",
|
|
1388
|
+
width = 400,
|
|
1389
|
+
title = "Chat",
|
|
1390
|
+
className
|
|
1391
|
+
}) {
|
|
1392
|
+
const panelRef = (0, import_react8.useRef)(null);
|
|
1393
|
+
(0, import_react8.useEffect)(() => {
|
|
1394
|
+
if (!isOpen) return;
|
|
1395
|
+
const handleKeyDown = (e) => {
|
|
1396
|
+
if (e.key === "Escape") onClose();
|
|
1397
|
+
};
|
|
1398
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
1399
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
1400
|
+
}, [isOpen, onClose]);
|
|
1401
|
+
const widthStyle = typeof width === "number" ? `${width}px` : width;
|
|
1402
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1403
|
+
"div",
|
|
1404
|
+
{
|
|
1405
|
+
className: (0, import_tailwind_merge11.twMerge)("fixed inset-0 z-50", !isOpen && "pointer-events-none"),
|
|
1406
|
+
"aria-hidden": !isOpen,
|
|
1407
|
+
children: [
|
|
1408
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1409
|
+
"div",
|
|
1410
|
+
{
|
|
1411
|
+
className: (0, import_tailwind_merge11.twMerge)(
|
|
1412
|
+
"fixed inset-0 transition-opacity duration-300",
|
|
1413
|
+
isOpen ? "opacity-100 bg-brand-dark/70 backdrop-blur-sm pointer-events-auto" : "opacity-0 pointer-events-none"
|
|
1414
|
+
),
|
|
1415
|
+
onClick: isOpen ? onClose : void 0,
|
|
1416
|
+
"data-testid": "panel-backdrop"
|
|
1417
|
+
}
|
|
1418
|
+
),
|
|
1419
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1420
|
+
"div",
|
|
1421
|
+
{
|
|
1422
|
+
ref: panelRef,
|
|
1423
|
+
role: "dialog",
|
|
1424
|
+
"aria-label": title,
|
|
1425
|
+
"aria-modal": isOpen ? "true" : void 0,
|
|
1426
|
+
style: { width: widthStyle, maxWidth: "100vw" },
|
|
1427
|
+
className: (0, import_tailwind_merge11.twMerge)(
|
|
1428
|
+
"fixed top-0 h-full flex flex-col z-50 bg-brand-dark shadow-card",
|
|
1429
|
+
"transition-transform duration-300 ease-in-out",
|
|
1430
|
+
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"}`,
|
|
1431
|
+
className
|
|
1432
|
+
),
|
|
1433
|
+
children: [
|
|
1434
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between border-b border-brand-gold/15 px-5 py-3.5 bg-brand-dark-panel/60 backdrop-blur-sm shrink-0", children: [
|
|
1435
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { className: "text-base font-display font-semibold text-brand-cream", children: title }),
|
|
1436
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1437
|
+
"button",
|
|
1438
|
+
{
|
|
1439
|
+
type: "button",
|
|
1440
|
+
onClick: onClose,
|
|
1441
|
+
"aria-label": "Close panel",
|
|
1442
|
+
className: "rounded-xl p-2 text-brand-cream/40 hover:text-brand-cream/80 hover:bg-brand-cream/5 transition-colors duration-200",
|
|
1443
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
1444
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
1445
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
1446
|
+
] })
|
|
1447
|
+
}
|
|
1448
|
+
)
|
|
1449
|
+
] }),
|
|
1450
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1451
|
+
AgentChat,
|
|
1452
|
+
{
|
|
1453
|
+
endpoint,
|
|
1454
|
+
title,
|
|
1455
|
+
showHeader: false,
|
|
1456
|
+
showWelcomeTitle: false,
|
|
1457
|
+
className: "flex-1 rounded-none border-0"
|
|
1458
|
+
}
|
|
1459
|
+
)
|
|
1460
|
+
]
|
|
1461
|
+
}
|
|
1462
|
+
)
|
|
1463
|
+
]
|
|
1464
|
+
}
|
|
1465
|
+
);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
// src/layouts/AgentWidget/AgentWidget.tsx
|
|
1469
|
+
var import_tailwind_merge12 = require("tailwind-merge");
|
|
1470
|
+
var import_react9 = require("react");
|
|
1471
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1472
|
+
function AgentWidget({
|
|
1473
|
+
endpoint,
|
|
1474
|
+
position = "bottom-right",
|
|
1475
|
+
triggerLabel = "Chat",
|
|
1476
|
+
title = "Chat",
|
|
1477
|
+
className
|
|
1478
|
+
}) {
|
|
1479
|
+
const [isOpen, setIsOpen] = (0, import_react9.useState)(false);
|
|
1480
|
+
const toggle = (0, import_react9.useCallback)(() => {
|
|
1481
|
+
setIsOpen((prev) => !prev);
|
|
1482
|
+
}, []);
|
|
1483
|
+
const positionClasses = position === "bottom-left" ? "left-4 bottom-4" : "right-4 bottom-4";
|
|
1484
|
+
const popoverPositionClasses = position === "bottom-left" ? "left-4 bottom-20" : "right-4 bottom-20";
|
|
1485
|
+
const popoverOrigin = position === "bottom-left" ? "origin-bottom-left" : "origin-bottom-right";
|
|
1486
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className, children: [
|
|
1487
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
1488
|
+
"div",
|
|
1489
|
+
{
|
|
1490
|
+
role: "dialog",
|
|
1491
|
+
"aria-label": title,
|
|
1492
|
+
"aria-hidden": !isOpen,
|
|
1493
|
+
className: (0, import_tailwind_merge12.twMerge)(
|
|
1494
|
+
"fixed z-50 flex flex-col",
|
|
1495
|
+
"w-[min(400px,calc(100vw-2rem))] h-[min(600px,calc(100vh-6rem))]",
|
|
1496
|
+
"rounded-2xl overflow-hidden border border-brand-gold/15",
|
|
1497
|
+
"bg-brand-dark/95 backdrop-blur-[12px] shadow-card",
|
|
1498
|
+
popoverPositionClasses,
|
|
1499
|
+
popoverOrigin,
|
|
1500
|
+
"transition-all duration-200 ease-out",
|
|
1501
|
+
isOpen ? "opacity-100 scale-100 pointer-events-auto translate-y-0" : "opacity-0 scale-95 pointer-events-none translate-y-2"
|
|
1502
|
+
),
|
|
1503
|
+
children: [
|
|
1504
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center justify-between px-4 py-2.5 bg-brand-dark-panel/80 border-b border-brand-gold/15 shrink-0", children: [
|
|
1505
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h2", { className: "text-sm font-display font-semibold text-brand-cream", children: title }),
|
|
1506
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1507
|
+
"button",
|
|
1508
|
+
{
|
|
1509
|
+
type: "button",
|
|
1510
|
+
onClick: () => setIsOpen(false),
|
|
1511
|
+
"aria-label": "Minimize chat",
|
|
1512
|
+
className: "rounded-lg p-1.5 text-brand-cream/40 hover:text-brand-cream/70 transition-colors duration-200",
|
|
1513
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
1514
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
1515
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
1516
|
+
] })
|
|
1517
|
+
}
|
|
1518
|
+
)
|
|
1519
|
+
] }),
|
|
1520
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1521
|
+
AgentChat,
|
|
1522
|
+
{
|
|
1523
|
+
endpoint,
|
|
1524
|
+
title,
|
|
1525
|
+
showHeader: false,
|
|
1526
|
+
showWelcomeTitle: false,
|
|
1527
|
+
className: "flex-1 rounded-none border-0 min-h-0"
|
|
1528
|
+
}
|
|
1529
|
+
)
|
|
1530
|
+
]
|
|
1531
|
+
}
|
|
1532
|
+
),
|
|
1533
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1534
|
+
"button",
|
|
1535
|
+
{
|
|
1536
|
+
type: "button",
|
|
1537
|
+
onClick: toggle,
|
|
1538
|
+
"aria-label": isOpen ? "Close chat" : triggerLabel,
|
|
1539
|
+
"aria-expanded": isOpen,
|
|
1540
|
+
className: (0, import_tailwind_merge12.twMerge)(
|
|
1541
|
+
"fixed z-50 flex items-center justify-center w-14 h-14 rounded-full",
|
|
1542
|
+
"bg-brand-blue text-brand-cream shadow-glow-cyan",
|
|
1543
|
+
"hover:bg-brand-cyan hover:shadow-glow-cyan hover:scale-105",
|
|
1544
|
+
"active:scale-95",
|
|
1545
|
+
"transition-all duration-200",
|
|
1546
|
+
positionClasses
|
|
1547
|
+
),
|
|
1548
|
+
children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
1549
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
1550
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
1551
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) })
|
|
1552
|
+
}
|
|
1553
|
+
)
|
|
1554
|
+
] });
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
// src/layouts/AgentEmbed/AgentEmbed.tsx
|
|
1558
|
+
var import_tailwind_merge13 = require("tailwind-merge");
|
|
1559
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1560
|
+
function AgentEmbed({
|
|
1561
|
+
endpoint,
|
|
1562
|
+
title = "Chat",
|
|
1563
|
+
className
|
|
1564
|
+
}) {
|
|
1565
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1566
|
+
"div",
|
|
1567
|
+
{
|
|
1568
|
+
className: (0, import_tailwind_merge13.twMerge)("w-full h-full min-h-0", className),
|
|
1569
|
+
"data-testid": "agent-embed",
|
|
1570
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1571
|
+
AgentChat,
|
|
1572
|
+
{
|
|
1573
|
+
endpoint,
|
|
1574
|
+
title,
|
|
1575
|
+
className: "h-full rounded-none border-0"
|
|
1576
|
+
}
|
|
1577
|
+
)
|
|
1578
|
+
}
|
|
1579
|
+
);
|
|
1580
|
+
}
|
|
1581
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1582
|
+
0 && (module.exports = {
|
|
1583
|
+
AgentEmbed,
|
|
1584
|
+
AgentFullPage,
|
|
1585
|
+
AgentPanel,
|
|
1586
|
+
AgentWidget
|
|
1587
|
+
});
|
|
1588
|
+
//# sourceMappingURL=index.cjs.map
|