@distri/react 0.1.8 → 0.2.2
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 +186 -0
- package/dist/globals.css +2358 -0
- package/dist/globals.d.cts +2 -0
- package/dist/globals.d.ts +2 -0
- package/dist/index.cjs +4724 -0
- package/dist/index.d.cts +850 -0
- package/dist/index.d.ts +811 -17
- package/dist/index.js +4358 -217
- package/package.json +42 -32
- package/dist/index.d.mts +0 -56
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -434
- package/dist/index.mjs.map +0 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,4724 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
10
|
+
var __export = (target, all) => {
|
|
11
|
+
for (var name in all)
|
|
12
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
+
};
|
|
14
|
+
var __copyProps = (to, from, except, desc) => {
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
+
for (let key of __getOwnPropNames(from))
|
|
17
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
23
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
24
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
25
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
26
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
27
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
28
|
+
mod
|
|
29
|
+
));
|
|
30
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
31
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
32
|
+
|
|
33
|
+
// src/index.ts
|
|
34
|
+
var index_exports = {};
|
|
35
|
+
__export(index_exports, {
|
|
36
|
+
AgentSelect: () => AgentSelect,
|
|
37
|
+
ApprovalToolCall: () => ApprovalToolCall,
|
|
38
|
+
AssistantMessage: () => AssistantMessage,
|
|
39
|
+
AssistantWithToolCalls: () => AssistantWithToolCalls,
|
|
40
|
+
Badge: () => Badge,
|
|
41
|
+
Button: () => Button,
|
|
42
|
+
Card: () => Card,
|
|
43
|
+
CardContent: () => CardContent,
|
|
44
|
+
CardDescription: () => CardDescription,
|
|
45
|
+
CardFooter: () => CardFooter,
|
|
46
|
+
CardHeader: () => CardHeader,
|
|
47
|
+
CardTitle: () => CardTitle,
|
|
48
|
+
ChatInput: () => ChatInput,
|
|
49
|
+
DebugMessage: () => DebugMessage,
|
|
50
|
+
Dialog: () => DialogRoot,
|
|
51
|
+
DialogContent: () => DialogContent,
|
|
52
|
+
DialogHeader: () => DialogHeader,
|
|
53
|
+
DialogTitle: () => DialogTitle,
|
|
54
|
+
DialogTrigger: () => DialogTrigger,
|
|
55
|
+
DistriProvider: () => DistriProvider,
|
|
56
|
+
EmbeddableChat: () => EmbeddableChat,
|
|
57
|
+
FullChat: () => FullChat_default,
|
|
58
|
+
Input: () => Input,
|
|
59
|
+
PlanMessage: () => PlanMessage,
|
|
60
|
+
Select: () => Select,
|
|
61
|
+
SelectContent: () => SelectContent,
|
|
62
|
+
SelectGroup: () => SelectGroup,
|
|
63
|
+
SelectItem: () => SelectItem,
|
|
64
|
+
SelectLabel: () => SelectLabel,
|
|
65
|
+
SelectScrollDownButton: () => SelectScrollDownButton,
|
|
66
|
+
SelectScrollUpButton: () => SelectScrollUpButton,
|
|
67
|
+
SelectSeparator: () => SelectSeparator,
|
|
68
|
+
SelectTrigger: () => SelectTrigger,
|
|
69
|
+
SelectValue: () => SelectValue,
|
|
70
|
+
Separator: () => Separator2,
|
|
71
|
+
Sheet: () => Sheet,
|
|
72
|
+
SheetContent: () => SheetContent,
|
|
73
|
+
SheetDescription: () => SheetDescription,
|
|
74
|
+
SheetFooter: () => SheetFooter,
|
|
75
|
+
SheetHeader: () => SheetHeader,
|
|
76
|
+
SheetTitle: () => SheetTitle,
|
|
77
|
+
Sidebar: () => Sidebar,
|
|
78
|
+
SidebarContent: () => SidebarContent,
|
|
79
|
+
SidebarFooter: () => SidebarFooter,
|
|
80
|
+
SidebarGroup: () => SidebarGroup,
|
|
81
|
+
SidebarGroupAction: () => SidebarGroupAction,
|
|
82
|
+
SidebarGroupContent: () => SidebarGroupContent,
|
|
83
|
+
SidebarGroupLabel: () => SidebarGroupLabel,
|
|
84
|
+
SidebarHeader: () => SidebarHeader,
|
|
85
|
+
SidebarInset: () => SidebarInset,
|
|
86
|
+
SidebarMenu: () => SidebarMenu,
|
|
87
|
+
SidebarMenuAction: () => SidebarMenuAction,
|
|
88
|
+
SidebarMenuBadge: () => SidebarMenuBadge,
|
|
89
|
+
SidebarMenuButton: () => SidebarMenuButton,
|
|
90
|
+
SidebarMenuItem: () => SidebarMenuItem,
|
|
91
|
+
SidebarMenuSkeleton: () => SidebarMenuSkeleton,
|
|
92
|
+
SidebarMenuSub: () => SidebarMenuSub,
|
|
93
|
+
SidebarMenuSubButton: () => SidebarMenuSubButton,
|
|
94
|
+
SidebarMenuSubItem: () => SidebarMenuSubItem,
|
|
95
|
+
SidebarProvider: () => SidebarProvider,
|
|
96
|
+
SidebarRail: () => SidebarRail,
|
|
97
|
+
SidebarSeparator: () => SidebarSeparator,
|
|
98
|
+
SidebarTrigger: () => SidebarTrigger,
|
|
99
|
+
Skeleton: () => Skeleton,
|
|
100
|
+
Textarea: () => Textarea,
|
|
101
|
+
ThemeProvider: () => ThemeProvider,
|
|
102
|
+
ThemeToggle: () => ThemeToggle,
|
|
103
|
+
ToastToolCall: () => ToastToolCall,
|
|
104
|
+
Tooltip: () => Tooltip,
|
|
105
|
+
TooltipContent: () => TooltipContent,
|
|
106
|
+
TooltipProvider: () => TooltipProvider,
|
|
107
|
+
TooltipTrigger: () => TooltipTrigger,
|
|
108
|
+
UserMessage: () => UserMessage,
|
|
109
|
+
cn: () => cn,
|
|
110
|
+
extractTextFromMessage: () => extractTextFromMessage,
|
|
111
|
+
registerTools: () => registerTools,
|
|
112
|
+
shouldDisplayMessage: () => shouldDisplayMessage,
|
|
113
|
+
useAgent: () => useAgent,
|
|
114
|
+
useAgents: () => useAgents,
|
|
115
|
+
useChat: () => useChat,
|
|
116
|
+
useDistri: () => useDistri,
|
|
117
|
+
useSidebar: () => useSidebar,
|
|
118
|
+
useTheme: () => useTheme,
|
|
119
|
+
useThreads: () => useThreads,
|
|
120
|
+
useToolCallState: () => useToolCallState
|
|
121
|
+
});
|
|
122
|
+
module.exports = __toCommonJS(index_exports);
|
|
123
|
+
|
|
124
|
+
// src/DistriProvider.tsx
|
|
125
|
+
var import_react2 = require("react");
|
|
126
|
+
|
|
127
|
+
// ../../node_modules/.pnpm/@a2a-js+sdk@https+++codeload.github.com+v3g42+a2a-js+tar.gz+51444c9/node_modules/@a2a-js/sdk/dist/chunk-CUGIRVQB.js
|
|
128
|
+
var A2AClient = class {
|
|
129
|
+
/**
|
|
130
|
+
* Constructs an A2AClient instance.
|
|
131
|
+
* It initiates fetching the agent card from the provided agent baseUrl.
|
|
132
|
+
* The Agent Card is expected at `${agentBaseUrl}/.well-known/agent.json`.
|
|
133
|
+
* The `url` field from the Agent Card will be used as the RPC service endpoint.
|
|
134
|
+
* @param agentBaseUrl The base URL of the A2A agent (e.g., https://agent.example.com).
|
|
135
|
+
*/
|
|
136
|
+
constructor(agentBaseUrl, fetchFn) {
|
|
137
|
+
__publicField(this, "agentBaseUrl");
|
|
138
|
+
__publicField(this, "agentCardPromise");
|
|
139
|
+
__publicField(this, "requestIdCounter", 1);
|
|
140
|
+
__publicField(this, "serviceEndpointUrl");
|
|
141
|
+
// To be populated from AgentCard after fetching
|
|
142
|
+
__publicField(this, "fetchFn");
|
|
143
|
+
this.agentBaseUrl = agentBaseUrl.replace(/\/$/, "");
|
|
144
|
+
this.fetchFn = fetchFn || globalThis.fetch;
|
|
145
|
+
this.agentCardPromise = this._fetchAndCacheAgentCard();
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Fetches the Agent Card from the agent's well-known URI and caches its service endpoint URL.
|
|
149
|
+
* This method is called by the constructor.
|
|
150
|
+
* @returns A Promise that resolves to the AgentCard.
|
|
151
|
+
*/
|
|
152
|
+
async _fetchAndCacheAgentCard() {
|
|
153
|
+
const agentCardUrl = `${this.agentBaseUrl}/.well-known/agent.json`;
|
|
154
|
+
try {
|
|
155
|
+
const response = await this.fetchFn(agentCardUrl, {
|
|
156
|
+
headers: { "Accept": "application/json" }
|
|
157
|
+
});
|
|
158
|
+
if (!response.ok) {
|
|
159
|
+
throw new Error(`Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}`);
|
|
160
|
+
}
|
|
161
|
+
const agentCard = await response.json();
|
|
162
|
+
if (!agentCard.url) {
|
|
163
|
+
throw new Error("Fetched Agent Card does not contain a valid 'url' for the service endpoint.");
|
|
164
|
+
}
|
|
165
|
+
this.serviceEndpointUrl = agentCard.url;
|
|
166
|
+
return agentCard;
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error("Error fetching or parsing Agent Card:");
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Retrieves the Agent Card.
|
|
174
|
+
* If an `agentBaseUrl` is provided, it fetches the card from that specific URL.
|
|
175
|
+
* Otherwise, it returns the card fetched and cached during client construction.
|
|
176
|
+
* @param agentBaseUrl Optional. The base URL of the agent to fetch the card from.
|
|
177
|
+
* If provided, this will fetch a new card, not use the cached one from the constructor's URL.
|
|
178
|
+
* @returns A Promise that resolves to the AgentCard.
|
|
179
|
+
*/
|
|
180
|
+
async getAgentCard(agentBaseUrl) {
|
|
181
|
+
if (agentBaseUrl) {
|
|
182
|
+
const specificAgentBaseUrl = agentBaseUrl.replace(/\/$/, "");
|
|
183
|
+
const agentCardUrl = `${specificAgentBaseUrl}/.well-known/agent.json`;
|
|
184
|
+
const response = await this.fetchFn(agentCardUrl, {
|
|
185
|
+
headers: { "Accept": "application/json" }
|
|
186
|
+
});
|
|
187
|
+
if (!response.ok) {
|
|
188
|
+
throw new Error(`Failed to fetch Agent Card from ${agentCardUrl}: ${response.status} ${response.statusText}`);
|
|
189
|
+
}
|
|
190
|
+
return await response.json();
|
|
191
|
+
}
|
|
192
|
+
return this.agentCardPromise;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Gets the RPC service endpoint URL. Ensures the agent card has been fetched first.
|
|
196
|
+
* @returns A Promise that resolves to the service endpoint URL string.
|
|
197
|
+
*/
|
|
198
|
+
async _getServiceEndpoint() {
|
|
199
|
+
if (this.serviceEndpointUrl) {
|
|
200
|
+
return this.serviceEndpointUrl;
|
|
201
|
+
}
|
|
202
|
+
await this.agentCardPromise;
|
|
203
|
+
if (!this.serviceEndpointUrl) {
|
|
204
|
+
throw new Error("Agent Card URL for RPC endpoint is not available. Fetching might have failed.");
|
|
205
|
+
}
|
|
206
|
+
return this.serviceEndpointUrl;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Helper method to make a generic JSON-RPC POST request.
|
|
210
|
+
* @param method The RPC method name.
|
|
211
|
+
* @param params The parameters for the RPC method.
|
|
212
|
+
* @returns A Promise that resolves to the RPC response.
|
|
213
|
+
*/
|
|
214
|
+
async _postRpcRequest(method, params) {
|
|
215
|
+
const endpoint = await this._getServiceEndpoint();
|
|
216
|
+
const requestId = this.requestIdCounter++;
|
|
217
|
+
const rpcRequest = {
|
|
218
|
+
jsonrpc: "2.0",
|
|
219
|
+
method,
|
|
220
|
+
params,
|
|
221
|
+
// Cast because TParams structure varies per method
|
|
222
|
+
id: requestId
|
|
223
|
+
};
|
|
224
|
+
const httpResponse = await this.fetchFn(endpoint, {
|
|
225
|
+
method: "POST",
|
|
226
|
+
headers: {
|
|
227
|
+
"Content-Type": "application/json",
|
|
228
|
+
"Accept": "application/json"
|
|
229
|
+
// Expect JSON response for non-streaming requests
|
|
230
|
+
},
|
|
231
|
+
body: JSON.stringify(rpcRequest)
|
|
232
|
+
});
|
|
233
|
+
if (!httpResponse.ok) {
|
|
234
|
+
let errorBodyText = "(empty or non-JSON response)";
|
|
235
|
+
try {
|
|
236
|
+
errorBodyText = await httpResponse.text();
|
|
237
|
+
const errorJson = JSON.parse(errorBodyText);
|
|
238
|
+
if (!errorJson.jsonrpc && errorJson.error) {
|
|
239
|
+
throw new Error(`RPC error for ${method}: ${errorJson.error.message} (Code: ${errorJson.error.code}, HTTP Status: ${httpResponse.status}) Data: ${JSON.stringify(errorJson.error.data)}`);
|
|
240
|
+
} else if (!errorJson.jsonrpc) {
|
|
241
|
+
throw new Error(`HTTP error for ${method}! Status: ${httpResponse.status} ${httpResponse.statusText}. Response: ${errorBodyText}`);
|
|
242
|
+
}
|
|
243
|
+
} catch (e) {
|
|
244
|
+
if (e.message.startsWith("RPC error for") || e.message.startsWith("HTTP error for")) throw e;
|
|
245
|
+
throw new Error(`HTTP error for ${method}! Status: ${httpResponse.status} ${httpResponse.statusText}. Response: ${errorBodyText}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const rpcResponse = await httpResponse.json();
|
|
249
|
+
if (rpcResponse.id !== requestId) {
|
|
250
|
+
console.error(`CRITICAL: RPC response ID mismatch for method ${method}. Expected ${requestId}, got ${rpcResponse.id}. This may lead to incorrect response handling.`);
|
|
251
|
+
}
|
|
252
|
+
return rpcResponse;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Sends a message to the agent.
|
|
256
|
+
* The behavior (blocking/non-blocking) and push notification configuration
|
|
257
|
+
* are specified within the `params.configuration` object.
|
|
258
|
+
* Optionally, `params.message.contextId` or `params.message.taskId` can be provided.
|
|
259
|
+
* @param params The parameters for sending the message, including the message content and configuration.
|
|
260
|
+
* @returns A Promise resolving to SendMessageResponse, which can be a Message, Task, or an error.
|
|
261
|
+
*/
|
|
262
|
+
async sendMessage(params) {
|
|
263
|
+
return this._postRpcRequest("message/send", params);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Sends a message to the agent and streams back responses using Server-Sent Events (SSE).
|
|
267
|
+
* Push notification configuration can be specified in `params.configuration`.
|
|
268
|
+
* Optionally, `params.message.contextId` or `params.message.taskId` can be provided.
|
|
269
|
+
* Requires the agent to support streaming (`capabilities.streaming: true` in AgentCard).
|
|
270
|
+
* @param params The parameters for sending the message.
|
|
271
|
+
* @returns An AsyncGenerator yielding A2AStreamEventData (Message, Task, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent).
|
|
272
|
+
* The generator throws an error if streaming is not supported or if an HTTP/SSE error occurs.
|
|
273
|
+
*/
|
|
274
|
+
async *sendMessageStream(params) {
|
|
275
|
+
const agentCard = await this.agentCardPromise;
|
|
276
|
+
if (!agentCard.capabilities?.streaming) {
|
|
277
|
+
throw new Error("Agent does not support streaming (AgentCard.capabilities.streaming is not true).");
|
|
278
|
+
}
|
|
279
|
+
const endpoint = await this._getServiceEndpoint();
|
|
280
|
+
const clientRequestId = this.requestIdCounter++;
|
|
281
|
+
const rpcRequest = {
|
|
282
|
+
// This is the initial JSON-RPC request to establish the stream
|
|
283
|
+
jsonrpc: "2.0",
|
|
284
|
+
method: "message/stream",
|
|
285
|
+
params,
|
|
286
|
+
id: clientRequestId
|
|
287
|
+
};
|
|
288
|
+
const response = await this.fetchFn(endpoint, {
|
|
289
|
+
method: "POST",
|
|
290
|
+
headers: {
|
|
291
|
+
"Content-Type": "application/json",
|
|
292
|
+
"Accept": "text/event-stream"
|
|
293
|
+
// Crucial for SSE
|
|
294
|
+
},
|
|
295
|
+
body: JSON.stringify(rpcRequest)
|
|
296
|
+
});
|
|
297
|
+
if (!response.ok) {
|
|
298
|
+
let errorBody = "";
|
|
299
|
+
try {
|
|
300
|
+
errorBody = await response.text();
|
|
301
|
+
const errorJson = JSON.parse(errorBody);
|
|
302
|
+
if (errorJson.error) {
|
|
303
|
+
throw new Error(`HTTP error establishing stream for message/stream: ${response.status} ${response.statusText}. RPC Error: ${errorJson.error.message} (Code: ${errorJson.error.code})`);
|
|
304
|
+
}
|
|
305
|
+
} catch (e) {
|
|
306
|
+
if (e.message.startsWith("HTTP error establishing stream")) throw e;
|
|
307
|
+
throw new Error(`HTTP error establishing stream for message/stream: ${response.status} ${response.statusText}. Response: ${errorBody || "(empty)"}`);
|
|
308
|
+
}
|
|
309
|
+
throw new Error(`HTTP error establishing stream for message/stream: ${response.status} ${response.statusText}`);
|
|
310
|
+
}
|
|
311
|
+
if (!response.headers.get("Content-Type")?.startsWith("text/event-stream")) {
|
|
312
|
+
throw new Error("Invalid response Content-Type for SSE stream. Expected 'text/event-stream'.");
|
|
313
|
+
}
|
|
314
|
+
yield* this._parseA2ASseStream(response, clientRequestId);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Sets or updates the push notification configuration for a given task.
|
|
318
|
+
* Requires the agent to support push notifications (`capabilities.pushNotifications: true` in AgentCard).
|
|
319
|
+
* @param params Parameters containing the taskId and the TaskPushNotificationConfig.
|
|
320
|
+
* @returns A Promise resolving to SetTaskPushNotificationConfigResponse.
|
|
321
|
+
*/
|
|
322
|
+
async setTaskPushNotificationConfig(params) {
|
|
323
|
+
const agentCard = await this.agentCardPromise;
|
|
324
|
+
if (!agentCard.capabilities?.pushNotifications) {
|
|
325
|
+
throw new Error("Agent does not support push notifications (AgentCard.capabilities.pushNotifications is not true).");
|
|
326
|
+
}
|
|
327
|
+
return this._postRpcRequest(
|
|
328
|
+
"tasks/pushNotificationConfig/set",
|
|
329
|
+
params
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Gets the push notification configuration for a given task.
|
|
334
|
+
* @param params Parameters containing the taskId.
|
|
335
|
+
* @returns A Promise resolving to GetTaskPushNotificationConfigResponse.
|
|
336
|
+
*/
|
|
337
|
+
async getTaskPushNotificationConfig(params) {
|
|
338
|
+
return this._postRpcRequest(
|
|
339
|
+
"tasks/pushNotificationConfig/get",
|
|
340
|
+
params
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Retrieves a task by its ID.
|
|
345
|
+
* @param params Parameters containing the taskId and optional historyLength.
|
|
346
|
+
* @returns A Promise resolving to GetTaskResponse, which contains the Task object or an error.
|
|
347
|
+
*/
|
|
348
|
+
async getTask(params) {
|
|
349
|
+
return this._postRpcRequest("tasks/get", params);
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Cancels a task by its ID.
|
|
353
|
+
* @param params Parameters containing the taskId.
|
|
354
|
+
* @returns A Promise resolving to CancelTaskResponse, which contains the updated Task object or an error.
|
|
355
|
+
*/
|
|
356
|
+
async cancelTask(params) {
|
|
357
|
+
return this._postRpcRequest("tasks/cancel", params);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Resubscribes to a task's event stream using Server-Sent Events (SSE).
|
|
361
|
+
* This is used if a previous SSE connection for an active task was broken.
|
|
362
|
+
* Requires the agent to support streaming (`capabilities.streaming: true` in AgentCard).
|
|
363
|
+
* @param params Parameters containing the taskId.
|
|
364
|
+
* @returns An AsyncGenerator yielding A2AStreamEventData (Message, Task, TaskStatusUpdateEvent, or TaskArtifactUpdateEvent).
|
|
365
|
+
*/
|
|
366
|
+
async *resubscribeTask(params) {
|
|
367
|
+
const agentCard = await this.agentCardPromise;
|
|
368
|
+
if (!agentCard.capabilities?.streaming) {
|
|
369
|
+
throw new Error("Agent does not support streaming (required for tasks/resubscribe).");
|
|
370
|
+
}
|
|
371
|
+
const endpoint = await this._getServiceEndpoint();
|
|
372
|
+
const clientRequestId = this.requestIdCounter++;
|
|
373
|
+
const rpcRequest = {
|
|
374
|
+
// Initial JSON-RPC request to establish the stream
|
|
375
|
+
jsonrpc: "2.0",
|
|
376
|
+
method: "tasks/resubscribe",
|
|
377
|
+
params,
|
|
378
|
+
id: clientRequestId
|
|
379
|
+
};
|
|
380
|
+
const response = await this.fetchFn(endpoint, {
|
|
381
|
+
method: "POST",
|
|
382
|
+
headers: {
|
|
383
|
+
"Content-Type": "application/json",
|
|
384
|
+
"Accept": "text/event-stream"
|
|
385
|
+
},
|
|
386
|
+
body: JSON.stringify(rpcRequest)
|
|
387
|
+
});
|
|
388
|
+
if (!response.ok) {
|
|
389
|
+
let errorBody = "";
|
|
390
|
+
try {
|
|
391
|
+
errorBody = await response.text();
|
|
392
|
+
const errorJson = JSON.parse(errorBody);
|
|
393
|
+
if (errorJson.error) {
|
|
394
|
+
throw new Error(`HTTP error establishing stream for tasks/resubscribe: ${response.status} ${response.statusText}. RPC Error: ${errorJson.error.message} (Code: ${errorJson.error.code})`);
|
|
395
|
+
}
|
|
396
|
+
} catch (e) {
|
|
397
|
+
if (e.message.startsWith("HTTP error establishing stream")) throw e;
|
|
398
|
+
throw new Error(`HTTP error establishing stream for tasks/resubscribe: ${response.status} ${response.statusText}. Response: ${errorBody || "(empty)"}`);
|
|
399
|
+
}
|
|
400
|
+
throw new Error(`HTTP error establishing stream for tasks/resubscribe: ${response.status} ${response.statusText}`);
|
|
401
|
+
}
|
|
402
|
+
if (!response.headers.get("Content-Type")?.startsWith("text/event-stream")) {
|
|
403
|
+
throw new Error("Invalid response Content-Type for SSE stream on resubscribe. Expected 'text/event-stream'.");
|
|
404
|
+
}
|
|
405
|
+
yield* this._parseA2ASseStream(response, clientRequestId);
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Parses an HTTP response body as an A2A Server-Sent Event stream.
|
|
409
|
+
* Each 'data' field of an SSE event is expected to be a JSON-RPC 2.0 Response object,
|
|
410
|
+
* specifically a SendStreamingMessageResponse (or similar structure for resubscribe).
|
|
411
|
+
* @param response The HTTP Response object whose body is the SSE stream.
|
|
412
|
+
* @param originalRequestId The ID of the client's JSON-RPC request that initiated this stream.
|
|
413
|
+
* Used to validate the `id` in the streamed JSON-RPC responses.
|
|
414
|
+
* @returns An AsyncGenerator yielding the `result` field of each valid JSON-RPC success response from the stream.
|
|
415
|
+
*/
|
|
416
|
+
async *_parseA2ASseStream(response, originalRequestId) {
|
|
417
|
+
if (!response.body) {
|
|
418
|
+
throw new Error("SSE response body is undefined. Cannot read stream.");
|
|
419
|
+
}
|
|
420
|
+
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
|
|
421
|
+
let buffer = "";
|
|
422
|
+
let eventDataBuffer = "";
|
|
423
|
+
try {
|
|
424
|
+
while (true) {
|
|
425
|
+
const { done, value } = await reader.read();
|
|
426
|
+
if (done) {
|
|
427
|
+
if (eventDataBuffer.trim()) {
|
|
428
|
+
const result = this._processSseEventData(eventDataBuffer, originalRequestId);
|
|
429
|
+
yield result;
|
|
430
|
+
}
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
buffer += value;
|
|
434
|
+
let lineEndIndex;
|
|
435
|
+
while ((lineEndIndex = buffer.indexOf("\n")) >= 0) {
|
|
436
|
+
const line = buffer.substring(0, lineEndIndex).trim();
|
|
437
|
+
buffer = buffer.substring(lineEndIndex + 1);
|
|
438
|
+
if (line === "") {
|
|
439
|
+
if (eventDataBuffer) {
|
|
440
|
+
const result = this._processSseEventData(eventDataBuffer, originalRequestId);
|
|
441
|
+
yield result;
|
|
442
|
+
eventDataBuffer = "";
|
|
443
|
+
}
|
|
444
|
+
} else if (line.startsWith("data:")) {
|
|
445
|
+
eventDataBuffer += line.substring(5).trimStart() + "\n";
|
|
446
|
+
} else if (line.startsWith(":")) {
|
|
447
|
+
} else if (line.includes(":")) {
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
} catch (error) {
|
|
452
|
+
console.error("Error reading or parsing SSE stream:", error.message);
|
|
453
|
+
throw error;
|
|
454
|
+
} finally {
|
|
455
|
+
reader.releaseLock();
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Processes a single SSE event's data string, expecting it to be a JSON-RPC response.
|
|
460
|
+
* @param jsonData The string content from one or more 'data:' lines of an SSE event.
|
|
461
|
+
* @param originalRequestId The ID of the client's request that initiated the stream.
|
|
462
|
+
* @returns The `result` field of the parsed JSON-RPC success response.
|
|
463
|
+
* @throws Error if data is not valid JSON, not a valid JSON-RPC response, an error response, or ID mismatch.
|
|
464
|
+
*/
|
|
465
|
+
_processSseEventData(jsonData, originalRequestId) {
|
|
466
|
+
if (!jsonData.trim()) {
|
|
467
|
+
throw new Error("Attempted to process empty SSE event data.");
|
|
468
|
+
}
|
|
469
|
+
try {
|
|
470
|
+
const sseJsonRpcResponse = JSON.parse(jsonData.replace(/\n$/, ""));
|
|
471
|
+
const a2aStreamResponse = sseJsonRpcResponse;
|
|
472
|
+
if (a2aStreamResponse.id !== originalRequestId) {
|
|
473
|
+
console.warn(`SSE Event's JSON-RPC response ID mismatch. Client request ID: ${originalRequestId}, event response ID: ${a2aStreamResponse.id}.`);
|
|
474
|
+
}
|
|
475
|
+
if (this.isErrorResponse(a2aStreamResponse)) {
|
|
476
|
+
const err = a2aStreamResponse.error;
|
|
477
|
+
throw new Error(`SSE event contained an error: ${err.message} (Code: ${err.code}) Data: ${JSON.stringify(err.data)}`);
|
|
478
|
+
}
|
|
479
|
+
if (!("result" in a2aStreamResponse) || typeof a2aStreamResponse.result === "undefined") {
|
|
480
|
+
throw new Error(`SSE event JSON-RPC response is missing 'result' field. Data: ${jsonData}`);
|
|
481
|
+
}
|
|
482
|
+
const successResponse = a2aStreamResponse;
|
|
483
|
+
return successResponse.result;
|
|
484
|
+
} catch (e) {
|
|
485
|
+
if (e.message.startsWith("SSE event contained an error") || e.message.startsWith("SSE event JSON-RPC response is missing 'result' field")) {
|
|
486
|
+
throw e;
|
|
487
|
+
}
|
|
488
|
+
console.error("Failed to parse SSE event data string or unexpected JSON-RPC structure:", jsonData, e);
|
|
489
|
+
throw new Error(`Failed to parse SSE event data: "${jsonData.substring(0, 100)}...". Original error: ${e.message}`);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
isErrorResponse(response) {
|
|
493
|
+
return "error" in response;
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// ../core/src/types.ts
|
|
498
|
+
var DistriError = class extends Error {
|
|
499
|
+
constructor(message, code, details) {
|
|
500
|
+
super(message);
|
|
501
|
+
this.code = code;
|
|
502
|
+
this.details = details;
|
|
503
|
+
this.name = "DistriError";
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
var A2AProtocolError = class extends DistriError {
|
|
507
|
+
constructor(message, details) {
|
|
508
|
+
super(message, "A2A_PROTOCOL_ERROR", details);
|
|
509
|
+
this.name = "A2AProtocolError";
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
var ApiError = class extends DistriError {
|
|
513
|
+
constructor(message, statusCode, details) {
|
|
514
|
+
super(message, "API_ERROR", details);
|
|
515
|
+
this.statusCode = statusCode;
|
|
516
|
+
this.name = "ApiError";
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
function isDistriMessage(event) {
|
|
520
|
+
return "id" in event && "role" in event && "parts" in event;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// ../core/src/encoder.ts
|
|
524
|
+
function convertA2AMessageToDistri(a2aMessage) {
|
|
525
|
+
const role = a2aMessage.role === "agent" ? "assistant" : "user";
|
|
526
|
+
return {
|
|
527
|
+
id: a2aMessage.messageId,
|
|
528
|
+
role,
|
|
529
|
+
parts: a2aMessage.parts.map(convertA2APartToDistri),
|
|
530
|
+
created_at: a2aMessage.createdAt
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
function decodeA2AStreamEvent(event) {
|
|
534
|
+
if (event.kind === "message") {
|
|
535
|
+
return convertA2AMessageToDistri(event);
|
|
536
|
+
} else if (event.kind === "status-update") {
|
|
537
|
+
return event;
|
|
538
|
+
} else if (event.kind === "artifact-update") {
|
|
539
|
+
return event;
|
|
540
|
+
}
|
|
541
|
+
return event;
|
|
542
|
+
}
|
|
543
|
+
function convertA2APartToDistri(a2aPart) {
|
|
544
|
+
switch (a2aPart.kind) {
|
|
545
|
+
case "text":
|
|
546
|
+
return { type: "text", text: a2aPart.text };
|
|
547
|
+
case "file":
|
|
548
|
+
if ("uri" in a2aPart.file) {
|
|
549
|
+
return { type: "image_url", image: { mime_type: a2aPart.file.mimeType, url: a2aPart.file.uri } };
|
|
550
|
+
} else {
|
|
551
|
+
return { type: "image_bytes", image: { mime_type: a2aPart.file.mimeType, data: a2aPart.file.bytes } };
|
|
552
|
+
}
|
|
553
|
+
case "data":
|
|
554
|
+
switch (a2aPart.data.part_type) {
|
|
555
|
+
case "tool_call":
|
|
556
|
+
return { type: "tool_call", tool_call: a2aPart.data };
|
|
557
|
+
case "tool_result":
|
|
558
|
+
return { type: "tool_result", tool_result: a2aPart.data };
|
|
559
|
+
case "code_observation":
|
|
560
|
+
return { type: "code_observation", thought: a2aPart.data.thought, code: a2aPart.data.code };
|
|
561
|
+
case "plan":
|
|
562
|
+
return { type: "plan", plan: a2aPart.data.plan };
|
|
563
|
+
default:
|
|
564
|
+
return { type: "data", data: a2aPart.data };
|
|
565
|
+
}
|
|
566
|
+
default:
|
|
567
|
+
return { type: "text", text: JSON.stringify(a2aPart) };
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
function convertDistriMessageToA2A(distriMessage, context) {
|
|
571
|
+
let role;
|
|
572
|
+
switch (distriMessage.role) {
|
|
573
|
+
case "assistant":
|
|
574
|
+
role = "agent";
|
|
575
|
+
break;
|
|
576
|
+
case "user":
|
|
577
|
+
role = "user";
|
|
578
|
+
break;
|
|
579
|
+
case "system":
|
|
580
|
+
case "tool":
|
|
581
|
+
role = "user";
|
|
582
|
+
break;
|
|
583
|
+
default:
|
|
584
|
+
role = "user";
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
messageId: distriMessage.id,
|
|
588
|
+
role,
|
|
589
|
+
parts: distriMessage.parts.map(convertDistriPartToA2A),
|
|
590
|
+
kind: "message",
|
|
591
|
+
contextId: context.thread_id,
|
|
592
|
+
taskId: context.run_id
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
function convertDistriPartToA2A(distriPart) {
|
|
596
|
+
switch (distriPart.type) {
|
|
597
|
+
case "text":
|
|
598
|
+
return { kind: "text", text: distriPart.text };
|
|
599
|
+
case "image_url":
|
|
600
|
+
return { kind: "file", file: { mimeType: distriPart.image.mime_type, uri: distriPart.image.url } };
|
|
601
|
+
case "image_bytes":
|
|
602
|
+
return { kind: "file", file: { mimeType: distriPart.image.mime_type, bytes: distriPart.image.data } };
|
|
603
|
+
case "tool_call":
|
|
604
|
+
return { kind: "data", data: { part_type: "tool_call", tool_call: distriPart.tool_call } };
|
|
605
|
+
case "tool_result":
|
|
606
|
+
let val = {
|
|
607
|
+
kind: "data",
|
|
608
|
+
data: {
|
|
609
|
+
tool_call_id: distriPart.tool_result.tool_call_id,
|
|
610
|
+
result: distriPart.tool_result.result,
|
|
611
|
+
part_type: "tool_result"
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
console.log("<> val", val);
|
|
615
|
+
return val;
|
|
616
|
+
case "code_observation":
|
|
617
|
+
return { kind: "data", data: { ...distriPart, part_type: "code_observation" } };
|
|
618
|
+
case "plan":
|
|
619
|
+
return { kind: "data", data: { ...distriPart, part_type: "plan" } };
|
|
620
|
+
case "data":
|
|
621
|
+
return { kind: "data", ...distriPart.data };
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// ../core/src/distri-client.ts
|
|
626
|
+
var DistriClient = class {
|
|
627
|
+
constructor(config) {
|
|
628
|
+
this.agentClients = /* @__PURE__ */ new Map();
|
|
629
|
+
this.config = {
|
|
630
|
+
baseUrl: config.baseUrl.replace(/\/$/, ""),
|
|
631
|
+
apiVersion: config.apiVersion || "v1",
|
|
632
|
+
timeout: config.timeout || 3e4,
|
|
633
|
+
retryAttempts: config.retryAttempts || 3,
|
|
634
|
+
retryDelay: config.retryDelay || 1e3,
|
|
635
|
+
debug: config.debug || false,
|
|
636
|
+
headers: config.headers || {},
|
|
637
|
+
interceptor: config.interceptor || ((init) => Promise.resolve(init))
|
|
638
|
+
};
|
|
639
|
+
this.debug("DistriClient initialized with config:", this.config);
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Get all available agents from the Distri server
|
|
643
|
+
*/
|
|
644
|
+
async getAgents() {
|
|
645
|
+
try {
|
|
646
|
+
const response = await this.fetch(`/agents`, {
|
|
647
|
+
headers: {
|
|
648
|
+
...this.config.headers
|
|
649
|
+
}
|
|
650
|
+
});
|
|
651
|
+
if (!response.ok) {
|
|
652
|
+
throw new ApiError(`Failed to fetch agents: ${response.statusText}`, response.status);
|
|
653
|
+
}
|
|
654
|
+
const agents = await response.json();
|
|
655
|
+
agents.forEach((agent) => {
|
|
656
|
+
if (!agent.id) {
|
|
657
|
+
agent.id = agent.name;
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
return agents;
|
|
661
|
+
} catch (error) {
|
|
662
|
+
if (error instanceof ApiError) throw error;
|
|
663
|
+
throw new DistriError("Failed to fetch agents", "FETCH_ERROR", error);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Get specific agent by ID
|
|
668
|
+
*/
|
|
669
|
+
async getAgent(agentId) {
|
|
670
|
+
try {
|
|
671
|
+
const response = await this.fetch(`/agents/${agentId}`, {
|
|
672
|
+
headers: {
|
|
673
|
+
...this.config.headers
|
|
674
|
+
}
|
|
675
|
+
});
|
|
676
|
+
if (!response.ok) {
|
|
677
|
+
if (response.status === 404) {
|
|
678
|
+
throw new ApiError(`Agent not found: ${agentId}`, 404);
|
|
679
|
+
}
|
|
680
|
+
throw new ApiError(`Failed to fetch agent: ${response.statusText}`, response.status);
|
|
681
|
+
}
|
|
682
|
+
const agent = await response.json();
|
|
683
|
+
if (!agent.id) {
|
|
684
|
+
agent.id = agentId;
|
|
685
|
+
}
|
|
686
|
+
return agent;
|
|
687
|
+
} catch (error) {
|
|
688
|
+
if (error instanceof ApiError) throw error;
|
|
689
|
+
throw new DistriError(`Failed to fetch agent ${agentId}`, "FETCH_ERROR", error);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Get or create A2AClient for an agent
|
|
694
|
+
*/
|
|
695
|
+
getA2AClient(agentId) {
|
|
696
|
+
if (!this.agentClients.has(agentId)) {
|
|
697
|
+
const fetchFn = this.fetchAbsolute.bind(this);
|
|
698
|
+
const agentUrl = `${this.config.baseUrl}/agents/${agentId}`;
|
|
699
|
+
const client = new A2AClient(agentUrl, fetchFn);
|
|
700
|
+
this.agentClients.set(agentId, client);
|
|
701
|
+
this.debug(`Created A2AClient for agent ${agentId} at ${agentUrl}`);
|
|
702
|
+
}
|
|
703
|
+
return this.agentClients.get(agentId);
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Send a message to an agent
|
|
707
|
+
*/
|
|
708
|
+
async sendMessage(agentId, params) {
|
|
709
|
+
try {
|
|
710
|
+
const client = this.getA2AClient(agentId);
|
|
711
|
+
const response = await client.sendMessage(params);
|
|
712
|
+
if ("error" in response && response.error) {
|
|
713
|
+
throw new A2AProtocolError(response.error.message, response.error);
|
|
714
|
+
}
|
|
715
|
+
if ("result" in response) {
|
|
716
|
+
const result = response.result;
|
|
717
|
+
this.debug(`Message sent to ${agentId}, got ${result.kind}:`, result);
|
|
718
|
+
return result;
|
|
719
|
+
}
|
|
720
|
+
throw new DistriError("Invalid response format", "INVALID_RESPONSE");
|
|
721
|
+
} catch (error) {
|
|
722
|
+
if (error instanceof A2AProtocolError || error instanceof DistriError) throw error;
|
|
723
|
+
throw new DistriError(`Failed to send message to agent ${agentId}`, "SEND_MESSAGE_ERROR", error);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Send a streaming message to an agent
|
|
728
|
+
*/
|
|
729
|
+
async *sendMessageStream(agentId, params) {
|
|
730
|
+
try {
|
|
731
|
+
const client = this.getA2AClient(agentId);
|
|
732
|
+
yield* await client.sendMessageStream(params);
|
|
733
|
+
} catch (error) {
|
|
734
|
+
throw new DistriError(`Failed to stream message to agent ${agentId}`, "STREAM_MESSAGE_ERROR", error);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Get task details
|
|
739
|
+
*/
|
|
740
|
+
async getTask(agentId, taskId) {
|
|
741
|
+
try {
|
|
742
|
+
const client = this.getA2AClient(agentId);
|
|
743
|
+
const response = await client.getTask({ id: taskId });
|
|
744
|
+
if ("error" in response && response.error) {
|
|
745
|
+
throw new A2AProtocolError(response.error.message, response.error);
|
|
746
|
+
}
|
|
747
|
+
if ("result" in response) {
|
|
748
|
+
const result = response.result;
|
|
749
|
+
this.debug(`Got task ${taskId} from ${agentId}:`, result);
|
|
750
|
+
return result;
|
|
751
|
+
}
|
|
752
|
+
throw new DistriError("Invalid response format", "INVALID_RESPONSE");
|
|
753
|
+
} catch (error) {
|
|
754
|
+
if (error instanceof A2AProtocolError || error instanceof DistriError) throw error;
|
|
755
|
+
throw new DistriError(`Failed to get task ${taskId} from agent ${agentId}`, "GET_TASK_ERROR", error);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* Cancel a task
|
|
760
|
+
*/
|
|
761
|
+
async cancelTask(agentId, taskId) {
|
|
762
|
+
try {
|
|
763
|
+
const client = this.getA2AClient(agentId);
|
|
764
|
+
await client.cancelTask({ id: taskId });
|
|
765
|
+
this.debug(`Cancelled task ${taskId} on agent ${agentId}`);
|
|
766
|
+
} catch (error) {
|
|
767
|
+
throw new DistriError(`Failed to cancel task ${taskId} on agent ${agentId}`, "CANCEL_TASK_ERROR", error);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Get threads from Distri server
|
|
772
|
+
*/
|
|
773
|
+
async getThreads() {
|
|
774
|
+
try {
|
|
775
|
+
const response = await this.fetch(`/threads`);
|
|
776
|
+
if (!response.ok) {
|
|
777
|
+
throw new ApiError(`Failed to fetch threads: ${response.statusText}`, response.status);
|
|
778
|
+
}
|
|
779
|
+
return await response.json();
|
|
780
|
+
} catch (error) {
|
|
781
|
+
if (error instanceof ApiError) throw error;
|
|
782
|
+
throw new DistriError("Failed to fetch threads", "FETCH_ERROR", error);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
async getThread(threadId) {
|
|
786
|
+
try {
|
|
787
|
+
const response = await this.fetch(`/threads/${threadId}`);
|
|
788
|
+
if (!response.ok) {
|
|
789
|
+
throw new ApiError(`Failed to fetch thread: ${response.statusText}`, response.status);
|
|
790
|
+
}
|
|
791
|
+
return await response.json();
|
|
792
|
+
} catch (error) {
|
|
793
|
+
if (error instanceof ApiError) throw error;
|
|
794
|
+
throw new DistriError(`Failed to fetch thread ${threadId}`, "FETCH_ERROR", error);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Get thread messages
|
|
799
|
+
*/
|
|
800
|
+
async getThreadMessages(threadId) {
|
|
801
|
+
try {
|
|
802
|
+
const response = await this.fetch(`/threads/${threadId}/messages`);
|
|
803
|
+
if (!response.ok) {
|
|
804
|
+
if (response.status === 404) {
|
|
805
|
+
return [];
|
|
806
|
+
}
|
|
807
|
+
throw new ApiError(`Failed to fetch thread messages: ${response.statusText}`, response.status);
|
|
808
|
+
}
|
|
809
|
+
return await response.json();
|
|
810
|
+
} catch (error) {
|
|
811
|
+
if (error instanceof ApiError) throw error;
|
|
812
|
+
throw new DistriError(`Failed to fetch messages for thread ${threadId}`, "FETCH_ERROR", error);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Get messages from a thread as DistriMessage format
|
|
817
|
+
*/
|
|
818
|
+
async getThreadMessagesAsDistri(threadId) {
|
|
819
|
+
const messages = await this.getThreadMessages(threadId);
|
|
820
|
+
return messages.map(convertA2AMessageToDistri);
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Send a DistriMessage to a thread
|
|
824
|
+
*/
|
|
825
|
+
async sendDistriMessage(threadId, message, context) {
|
|
826
|
+
const a2aMessage = convertDistriMessageToA2A(message, context);
|
|
827
|
+
const params = {
|
|
828
|
+
message: a2aMessage,
|
|
829
|
+
metadata: context.metadata
|
|
830
|
+
};
|
|
831
|
+
await this.sendMessage(threadId, params);
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Get the base URL for making direct requests
|
|
835
|
+
*/
|
|
836
|
+
get baseUrl() {
|
|
837
|
+
return this.config.baseUrl;
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Enhanced fetch with retry logic
|
|
841
|
+
*/
|
|
842
|
+
async fetchAbsolute(url, initialInit) {
|
|
843
|
+
const init = await this.config.interceptor(initialInit);
|
|
844
|
+
let lastError;
|
|
845
|
+
for (let attempt = 0; attempt <= this.config.retryAttempts; attempt++) {
|
|
846
|
+
try {
|
|
847
|
+
const controller = new AbortController();
|
|
848
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
849
|
+
const response = await fetch(url, {
|
|
850
|
+
...init,
|
|
851
|
+
signal: controller.signal,
|
|
852
|
+
headers: {
|
|
853
|
+
...this.config.headers,
|
|
854
|
+
...init?.headers
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
clearTimeout(timeoutId);
|
|
858
|
+
return response;
|
|
859
|
+
} catch (error) {
|
|
860
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
861
|
+
if (attempt < this.config.retryAttempts) {
|
|
862
|
+
this.debug(`Request failed (attempt ${attempt + 1}), retrying in ${this.config.retryDelay}ms...`);
|
|
863
|
+
await this.delay(this.config.retryDelay);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
throw lastError;
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Enhanced fetch with retry logic
|
|
871
|
+
*/
|
|
872
|
+
async fetch(input, initialInit) {
|
|
873
|
+
const url = `${this.config.baseUrl}${input}`;
|
|
874
|
+
return this.fetchAbsolute(url, initialInit);
|
|
875
|
+
}
|
|
876
|
+
/**
|
|
877
|
+
* Delay utility
|
|
878
|
+
*/
|
|
879
|
+
delay(ms) {
|
|
880
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* Debug logging
|
|
884
|
+
*/
|
|
885
|
+
debug(...args) {
|
|
886
|
+
if (this.config.debug) {
|
|
887
|
+
console.log("[DistriClient]", ...args);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Helper method to create A2A messages
|
|
892
|
+
*/
|
|
893
|
+
static initMessage(parts, role = "user", message) {
|
|
894
|
+
return {
|
|
895
|
+
messageId: message.messageId || uuidv4(),
|
|
896
|
+
taskId: message.taskId || uuidv4(),
|
|
897
|
+
contextId: message.contextId,
|
|
898
|
+
role,
|
|
899
|
+
parts: Array.isArray(parts) ? parts : [{ kind: "text", text: parts.trim() }],
|
|
900
|
+
...message,
|
|
901
|
+
kind: "message"
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Create a DistriMessage instance
|
|
906
|
+
*/
|
|
907
|
+
static initDistriMessage(role, parts, id, created_at) {
|
|
908
|
+
return {
|
|
909
|
+
id: id || uuidv4(),
|
|
910
|
+
role,
|
|
911
|
+
parts,
|
|
912
|
+
created_at
|
|
913
|
+
};
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Helper method to create message send parameters
|
|
917
|
+
*/
|
|
918
|
+
static initMessageParams(message, configuration, metadata) {
|
|
919
|
+
return {
|
|
920
|
+
message,
|
|
921
|
+
configuration: {
|
|
922
|
+
acceptedOutputModes: ["text/plain"],
|
|
923
|
+
blocking: false,
|
|
924
|
+
// Default to non-blocking for streaming
|
|
925
|
+
...configuration
|
|
926
|
+
},
|
|
927
|
+
metadata
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* Create MessageSendParams from a DistriMessage using InvokeContext
|
|
932
|
+
*/
|
|
933
|
+
static initDistriMessageParams(message, context) {
|
|
934
|
+
const a2aMessage = convertDistriMessageToA2A(message, context);
|
|
935
|
+
return {
|
|
936
|
+
message: a2aMessage,
|
|
937
|
+
metadata: context.metadata
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
function uuidv4() {
|
|
942
|
+
if (typeof crypto?.randomUUID === "function") {
|
|
943
|
+
return crypto.randomUUID();
|
|
944
|
+
}
|
|
945
|
+
const array = new Uint8Array(16);
|
|
946
|
+
crypto.getRandomValues(array);
|
|
947
|
+
array[6] = array[6] & 15 | 64;
|
|
948
|
+
array[8] = array[8] & 63 | 128;
|
|
949
|
+
return [...array].map(
|
|
950
|
+
(b, i) => ([4, 6, 8, 10].includes(i) ? "-" : "") + b.toString(16).padStart(2, "0")
|
|
951
|
+
).join("");
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
// ../core/src/agent.ts
|
|
955
|
+
var Agent = class _Agent {
|
|
956
|
+
constructor(agentDefinition, client) {
|
|
957
|
+
this.tools = /* @__PURE__ */ new Map();
|
|
958
|
+
this.agentDefinition = agentDefinition;
|
|
959
|
+
this.client = client;
|
|
960
|
+
}
|
|
961
|
+
/**
|
|
962
|
+
* Add a tool to the agent (AG-UI style)
|
|
963
|
+
*/
|
|
964
|
+
registerTool(tool) {
|
|
965
|
+
this.tools.set(tool.name, tool);
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* Add multiple tools at once
|
|
969
|
+
*/
|
|
970
|
+
registerTools(tools) {
|
|
971
|
+
tools.forEach((tool) => this.registerTool(tool));
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Remove a tool
|
|
975
|
+
*/
|
|
976
|
+
unregisterTool(toolName) {
|
|
977
|
+
this.tools.delete(toolName);
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* Get all registered tools
|
|
981
|
+
*/
|
|
982
|
+
getTools() {
|
|
983
|
+
return Array.from(this.tools.values());
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Check if a tool is registered
|
|
987
|
+
*/
|
|
988
|
+
hasTool(toolName) {
|
|
989
|
+
return this.tools.has(toolName);
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Get agent information
|
|
993
|
+
*/
|
|
994
|
+
get id() {
|
|
995
|
+
return this.agentDefinition.id;
|
|
996
|
+
}
|
|
997
|
+
get name() {
|
|
998
|
+
return this.agentDefinition.name;
|
|
999
|
+
}
|
|
1000
|
+
get description() {
|
|
1001
|
+
return this.agentDefinition.description;
|
|
1002
|
+
}
|
|
1003
|
+
get iconUrl() {
|
|
1004
|
+
return this.agentDefinition.icon_url;
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Fetch messages for a thread (public method for useChat)
|
|
1008
|
+
*/
|
|
1009
|
+
async getThreadMessages(threadId) {
|
|
1010
|
+
return this.client.getThreadMessages(threadId);
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Direct (non-streaming) invoke
|
|
1014
|
+
*/
|
|
1015
|
+
async invoke(params) {
|
|
1016
|
+
const enhancedParams = this.enhanceParamsWithTools(params);
|
|
1017
|
+
console.log("enhancedParams", enhancedParams);
|
|
1018
|
+
return await this.client.sendMessage(this.agentDefinition.id, enhancedParams);
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* Streaming invoke
|
|
1022
|
+
*/
|
|
1023
|
+
async invokeStream(params) {
|
|
1024
|
+
const enhancedParams = this.enhanceParamsWithTools(params);
|
|
1025
|
+
console.log("enhancedParams", enhancedParams);
|
|
1026
|
+
const a2aStream = this.client.sendMessageStream(this.agentDefinition.id, enhancedParams);
|
|
1027
|
+
return async function* () {
|
|
1028
|
+
for await (const event of a2aStream) {
|
|
1029
|
+
if (event.kind === "message") {
|
|
1030
|
+
yield convertA2AMessageToDistri(event);
|
|
1031
|
+
} else if (event.kind === "status-update") {
|
|
1032
|
+
yield event;
|
|
1033
|
+
} else if (event.kind === "artifact-update") {
|
|
1034
|
+
yield event;
|
|
1035
|
+
} else {
|
|
1036
|
+
yield event;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}();
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Enhance message params with tool definitions
|
|
1043
|
+
*/
|
|
1044
|
+
enhanceParamsWithTools(params) {
|
|
1045
|
+
const tools = this.getTools();
|
|
1046
|
+
return {
|
|
1047
|
+
...params,
|
|
1048
|
+
metadata: {
|
|
1049
|
+
...params.metadata,
|
|
1050
|
+
tools: tools.map((tool) => ({
|
|
1051
|
+
name: tool.name,
|
|
1052
|
+
description: tool.description,
|
|
1053
|
+
input_schema: tool.input_schema
|
|
1054
|
+
}))
|
|
1055
|
+
}
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Create an agent instance from an agent ID
|
|
1060
|
+
*/
|
|
1061
|
+
static async create(agentId, client) {
|
|
1062
|
+
const agentDefinition = await client.getAgent(agentId);
|
|
1063
|
+
return new _Agent(agentDefinition, client);
|
|
1064
|
+
}
|
|
1065
|
+
/**
|
|
1066
|
+
* List all available agents
|
|
1067
|
+
*/
|
|
1068
|
+
static async list(client) {
|
|
1069
|
+
const agentDefinitions = await client.getAgents();
|
|
1070
|
+
return agentDefinitions.map((def) => new _Agent(def, client));
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
|
|
1074
|
+
// src/components/ThemeProvider.tsx
|
|
1075
|
+
var import_react = require("react");
|
|
1076
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1077
|
+
var initialState = {
|
|
1078
|
+
theme: "system",
|
|
1079
|
+
setTheme: () => null
|
|
1080
|
+
};
|
|
1081
|
+
var ThemeProviderContext = (0, import_react.createContext)(initialState);
|
|
1082
|
+
function ThemeProvider({
|
|
1083
|
+
children,
|
|
1084
|
+
defaultTheme = "system",
|
|
1085
|
+
storageKey = "distri-theme",
|
|
1086
|
+
...props
|
|
1087
|
+
}) {
|
|
1088
|
+
const [theme, setTheme] = (0, import_react.useState)(() => {
|
|
1089
|
+
const stored = localStorage.getItem(storageKey);
|
|
1090
|
+
if (stored) {
|
|
1091
|
+
return stored;
|
|
1092
|
+
}
|
|
1093
|
+
return defaultTheme === "system" ? "dark" : defaultTheme;
|
|
1094
|
+
});
|
|
1095
|
+
(0, import_react.useEffect)(() => {
|
|
1096
|
+
const root = window.document.documentElement;
|
|
1097
|
+
root.classList.remove("light", "dark", "chatgpt");
|
|
1098
|
+
if (theme === "system") {
|
|
1099
|
+
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
1100
|
+
root.classList.add(systemTheme);
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
root.classList.add(theme);
|
|
1104
|
+
}, [theme]);
|
|
1105
|
+
const value = {
|
|
1106
|
+
theme,
|
|
1107
|
+
setTheme: (theme2) => {
|
|
1108
|
+
localStorage.setItem(storageKey, theme2);
|
|
1109
|
+
setTheme(theme2);
|
|
1110
|
+
}
|
|
1111
|
+
};
|
|
1112
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeProviderContext.Provider, { ...props, value, children });
|
|
1113
|
+
}
|
|
1114
|
+
var useTheme = () => {
|
|
1115
|
+
const context = (0, import_react.useContext)(ThemeProviderContext);
|
|
1116
|
+
if (context === void 0)
|
|
1117
|
+
throw new Error("useTheme must be used within a ThemeProvider");
|
|
1118
|
+
return context;
|
|
1119
|
+
};
|
|
1120
|
+
|
|
1121
|
+
// src/DistriProvider.tsx
|
|
1122
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1123
|
+
var DistriContext = (0, import_react2.createContext)({
|
|
1124
|
+
client: null,
|
|
1125
|
+
error: null,
|
|
1126
|
+
isLoading: true
|
|
1127
|
+
});
|
|
1128
|
+
var debug = (config, ...args) => {
|
|
1129
|
+
if (config.debug) {
|
|
1130
|
+
console.log("[DistriProvider]", ...args);
|
|
1131
|
+
}
|
|
1132
|
+
};
|
|
1133
|
+
function DistriProvider({ config, children, defaultTheme = "dark" }) {
|
|
1134
|
+
const [client, setClient] = (0, import_react2.useState)(null);
|
|
1135
|
+
const [error, setError] = (0, import_react2.useState)(null);
|
|
1136
|
+
const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
|
|
1137
|
+
(0, import_react2.useEffect)(() => {
|
|
1138
|
+
let currentClient = null;
|
|
1139
|
+
try {
|
|
1140
|
+
debug(config, "[DistriProvider] Initializing client with config:", config);
|
|
1141
|
+
currentClient = new DistriClient(config);
|
|
1142
|
+
setClient(currentClient);
|
|
1143
|
+
setError(null);
|
|
1144
|
+
setIsLoading(false);
|
|
1145
|
+
debug(config, "[DistriProvider] Client initialized successfully");
|
|
1146
|
+
} catch (err) {
|
|
1147
|
+
debug(config, "[DistriProvider] Failed to initialize client:", err);
|
|
1148
|
+
const error2 = err instanceof Error ? err : new Error("Failed to initialize client");
|
|
1149
|
+
setError(error2);
|
|
1150
|
+
setClient(null);
|
|
1151
|
+
setIsLoading(false);
|
|
1152
|
+
}
|
|
1153
|
+
}, [config]);
|
|
1154
|
+
const contextValue = {
|
|
1155
|
+
client,
|
|
1156
|
+
error,
|
|
1157
|
+
isLoading
|
|
1158
|
+
};
|
|
1159
|
+
if (error) {
|
|
1160
|
+
console.error(config, "[DistriProvider] Rendering error state:", error.message);
|
|
1161
|
+
}
|
|
1162
|
+
if (isLoading) {
|
|
1163
|
+
debug(config, "[DistriProvider] Rendering loading state");
|
|
1164
|
+
}
|
|
1165
|
+
if (client) {
|
|
1166
|
+
debug(config, "[DistriProvider] Rendering with client available");
|
|
1167
|
+
}
|
|
1168
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ThemeProvider, { defaultTheme, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DistriContext.Provider, { value: contextValue, children }) });
|
|
1169
|
+
}
|
|
1170
|
+
function useDistri() {
|
|
1171
|
+
const context = (0, import_react2.useContext)(DistriContext);
|
|
1172
|
+
if (!context) {
|
|
1173
|
+
throw new Error("useDistri must be used within a DistriProvider");
|
|
1174
|
+
}
|
|
1175
|
+
return context;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// src/useAgent.ts
|
|
1179
|
+
var import_react3 = __toESM(require("react"), 1);
|
|
1180
|
+
function useAgent({
|
|
1181
|
+
agentId,
|
|
1182
|
+
autoCreateAgent = true
|
|
1183
|
+
}) {
|
|
1184
|
+
const { client, error: clientError, isLoading: clientLoading } = useDistri();
|
|
1185
|
+
const [agent, setAgent] = (0, import_react3.useState)(null);
|
|
1186
|
+
const [loading, setLoading] = (0, import_react3.useState)(false);
|
|
1187
|
+
const [error, setError] = (0, import_react3.useState)(null);
|
|
1188
|
+
const agentRef = (0, import_react3.useRef)(null);
|
|
1189
|
+
const currentAgentIdRef = (0, import_react3.useRef)(null);
|
|
1190
|
+
const initializeAgent = (0, import_react3.useCallback)(async () => {
|
|
1191
|
+
if (!client || !agentId) return;
|
|
1192
|
+
if (currentAgentIdRef.current === agentId && agentRef.current) {
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
try {
|
|
1196
|
+
setLoading(true);
|
|
1197
|
+
setError(null);
|
|
1198
|
+
if (currentAgentIdRef.current !== agentId) {
|
|
1199
|
+
agentRef.current = null;
|
|
1200
|
+
setAgent(null);
|
|
1201
|
+
}
|
|
1202
|
+
const newAgent = await Agent.create(agentId, client);
|
|
1203
|
+
agentRef.current = newAgent;
|
|
1204
|
+
currentAgentIdRef.current = agentId;
|
|
1205
|
+
setAgent(newAgent);
|
|
1206
|
+
} catch (err) {
|
|
1207
|
+
setError(err instanceof Error ? err : new Error("Failed to create agent"));
|
|
1208
|
+
} finally {
|
|
1209
|
+
setLoading(false);
|
|
1210
|
+
}
|
|
1211
|
+
}, [client, agentId]);
|
|
1212
|
+
import_react3.default.useEffect(() => {
|
|
1213
|
+
if (!clientLoading && !clientError && autoCreateAgent && client) {
|
|
1214
|
+
initializeAgent();
|
|
1215
|
+
}
|
|
1216
|
+
}, [clientLoading, clientError, autoCreateAgent, client, agentId, initializeAgent]);
|
|
1217
|
+
import_react3.default.useEffect(() => {
|
|
1218
|
+
if (currentAgentIdRef.current !== agentId) {
|
|
1219
|
+
agentRef.current = null;
|
|
1220
|
+
setAgent(null);
|
|
1221
|
+
currentAgentIdRef.current = null;
|
|
1222
|
+
}
|
|
1223
|
+
}, [agentId]);
|
|
1224
|
+
return {
|
|
1225
|
+
// Agent information
|
|
1226
|
+
agent,
|
|
1227
|
+
// State management
|
|
1228
|
+
loading: loading || clientLoading,
|
|
1229
|
+
error: error || clientError
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// src/useAgents.ts
|
|
1234
|
+
var import_react4 = require("react");
|
|
1235
|
+
function useAgents() {
|
|
1236
|
+
const { client, error: clientError, isLoading: clientLoading } = useDistri();
|
|
1237
|
+
const [agents, setAgents] = (0, import_react4.useState)([]);
|
|
1238
|
+
const [loading, setLoading] = (0, import_react4.useState)(true);
|
|
1239
|
+
const [error, setError] = (0, import_react4.useState)(null);
|
|
1240
|
+
const fetchAgents = (0, import_react4.useCallback)(async () => {
|
|
1241
|
+
if (!client) {
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
try {
|
|
1245
|
+
setLoading(true);
|
|
1246
|
+
setError(null);
|
|
1247
|
+
const fetchedAgents = await client.getAgents();
|
|
1248
|
+
setAgents(fetchedAgents);
|
|
1249
|
+
} catch (err) {
|
|
1250
|
+
console.error("[useAgents] Failed to fetch agents:", err);
|
|
1251
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch agents"));
|
|
1252
|
+
} finally {
|
|
1253
|
+
setLoading(false);
|
|
1254
|
+
}
|
|
1255
|
+
}, [client]);
|
|
1256
|
+
const getAgent = (0, import_react4.useCallback)(async (agentId) => {
|
|
1257
|
+
if (!client) {
|
|
1258
|
+
throw new Error("Client not available");
|
|
1259
|
+
}
|
|
1260
|
+
try {
|
|
1261
|
+
const agent = await client.getAgent(agentId);
|
|
1262
|
+
setAgents((prev) => prev.map((a) => a.id === agentId ? agent : a));
|
|
1263
|
+
return agent;
|
|
1264
|
+
} catch (err) {
|
|
1265
|
+
const error2 = err instanceof Error ? err : new Error("Failed to get agent");
|
|
1266
|
+
setError(error2);
|
|
1267
|
+
throw error2;
|
|
1268
|
+
}
|
|
1269
|
+
}, [client]);
|
|
1270
|
+
(0, import_react4.useEffect)(() => {
|
|
1271
|
+
if (clientLoading) {
|
|
1272
|
+
setLoading(true);
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
if (clientError) {
|
|
1276
|
+
console.error("[useAgents] Client error:", clientError);
|
|
1277
|
+
setError(clientError);
|
|
1278
|
+
setLoading(false);
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
if (client) {
|
|
1282
|
+
fetchAgents();
|
|
1283
|
+
} else {
|
|
1284
|
+
console.log("[useAgents] No client available");
|
|
1285
|
+
setLoading(false);
|
|
1286
|
+
}
|
|
1287
|
+
}, [clientLoading, clientError, client, fetchAgents]);
|
|
1288
|
+
return {
|
|
1289
|
+
agents,
|
|
1290
|
+
loading: loading || clientLoading,
|
|
1291
|
+
error: error || clientError,
|
|
1292
|
+
refetch: fetchAgents,
|
|
1293
|
+
getAgent
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// src/useChat.ts
|
|
1298
|
+
var import_react9 = require("react");
|
|
1299
|
+
|
|
1300
|
+
// src/hooks/registerTools.tsx
|
|
1301
|
+
var import_react7 = require("react");
|
|
1302
|
+
|
|
1303
|
+
// src/components/toolcalls/ApprovalToolCall.tsx
|
|
1304
|
+
var import_react5 = require("react");
|
|
1305
|
+
|
|
1306
|
+
// src/components/ui/button.tsx
|
|
1307
|
+
var React3 = __toESM(require("react"), 1);
|
|
1308
|
+
|
|
1309
|
+
// src/lib/utils.ts
|
|
1310
|
+
var import_clsx = require("clsx");
|
|
1311
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
1312
|
+
function cn(...inputs) {
|
|
1313
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// src/components/ui/button.tsx
|
|
1317
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1318
|
+
var buttonVariants = {
|
|
1319
|
+
variant: {
|
|
1320
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
1321
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
1322
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
1323
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
1324
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
1325
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
1326
|
+
},
|
|
1327
|
+
size: {
|
|
1328
|
+
default: "h-10 px-4 py-2",
|
|
1329
|
+
sm: "h-9 rounded-md px-3",
|
|
1330
|
+
lg: "h-11 rounded-md px-8",
|
|
1331
|
+
icon: "h-10 w-10"
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1334
|
+
var Button = React3.forwardRef(
|
|
1335
|
+
({ className, variant = "default", size = "default", ...props }, ref) => {
|
|
1336
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1337
|
+
"button",
|
|
1338
|
+
{
|
|
1339
|
+
className: cn(
|
|
1340
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
1341
|
+
buttonVariants.variant[variant],
|
|
1342
|
+
buttonVariants.size[size],
|
|
1343
|
+
className
|
|
1344
|
+
),
|
|
1345
|
+
ref,
|
|
1346
|
+
...props
|
|
1347
|
+
}
|
|
1348
|
+
);
|
|
1349
|
+
}
|
|
1350
|
+
);
|
|
1351
|
+
Button.displayName = "Button";
|
|
1352
|
+
|
|
1353
|
+
// src/components/toolcalls/ApprovalToolCall.tsx
|
|
1354
|
+
var import_lucide_react = require("lucide-react");
|
|
1355
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1356
|
+
var ApprovalToolCall = ({
|
|
1357
|
+
toolCall,
|
|
1358
|
+
completeTool
|
|
1359
|
+
}) => {
|
|
1360
|
+
const [isProcessing, setIsProcessing] = (0, import_react5.useState)(false);
|
|
1361
|
+
const input = typeof toolCall.input === "string" ? JSON.parse(toolCall.input) : toolCall.input;
|
|
1362
|
+
const reason = input.reason || "Approval required";
|
|
1363
|
+
const toolCallsToApprove = input.tool_calls || [];
|
|
1364
|
+
const handleResponse = async (approved) => {
|
|
1365
|
+
if (isProcessing || status === "completed") return;
|
|
1366
|
+
setIsProcessing(true);
|
|
1367
|
+
const result = {
|
|
1368
|
+
tool_call_id: toolCall.tool_call_id,
|
|
1369
|
+
result: `${toolCall.tool_name} ${approved ? "approved" : "denied"} by user`,
|
|
1370
|
+
success: true,
|
|
1371
|
+
error: void 0
|
|
1372
|
+
};
|
|
1373
|
+
completeTool(result);
|
|
1374
|
+
};
|
|
1375
|
+
if (status === "completed") {
|
|
1376
|
+
const result = input.result || {};
|
|
1377
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "border rounded-lg p-4 bg-muted/50", children: [
|
|
1378
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
1379
|
+
result.approved ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.CheckCircle, { className: "h-4 w-4 text-green-600" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.XCircle, { className: "h-4 w-4 text-red-600" }),
|
|
1380
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "font-medium", children: [
|
|
1381
|
+
"Approval ",
|
|
1382
|
+
result.approved ? "Granted" : "Denied"
|
|
1383
|
+
] })
|
|
1384
|
+
] }),
|
|
1385
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-sm text-muted-foreground", children: reason })
|
|
1386
|
+
] });
|
|
1387
|
+
}
|
|
1388
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "border rounded-lg p-4 bg-background", children: [
|
|
1389
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2 mb-3", children: [
|
|
1390
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react.AlertTriangle, { className: "h-4 w-4 text-amber-500" }),
|
|
1391
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "font-medium", children: "Approval Required" })
|
|
1392
|
+
] }),
|
|
1393
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-sm mb-4", children: reason }),
|
|
1394
|
+
toolCallsToApprove.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mb-4", children: [
|
|
1395
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "text-xs text-muted-foreground mb-2", children: "Tool calls requiring approval:" }),
|
|
1396
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "space-y-1", children: toolCallsToApprove.map((tc, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "text-xs bg-muted p-2 rounded", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "font-mono", children: tc.tool_name }) }, index)) })
|
|
1397
|
+
] }),
|
|
1398
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex gap-2", children: [
|
|
1399
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1400
|
+
Button,
|
|
1401
|
+
{
|
|
1402
|
+
size: "sm",
|
|
1403
|
+
variant: "destructive",
|
|
1404
|
+
onClick: () => handleResponse(false),
|
|
1405
|
+
disabled: isProcessing,
|
|
1406
|
+
children: "Deny"
|
|
1407
|
+
}
|
|
1408
|
+
),
|
|
1409
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1410
|
+
Button,
|
|
1411
|
+
{
|
|
1412
|
+
size: "sm",
|
|
1413
|
+
onClick: () => handleResponse(true),
|
|
1414
|
+
disabled: isProcessing,
|
|
1415
|
+
children: "Approve"
|
|
1416
|
+
}
|
|
1417
|
+
)
|
|
1418
|
+
] })
|
|
1419
|
+
] });
|
|
1420
|
+
};
|
|
1421
|
+
|
|
1422
|
+
// src/components/toolcalls/ToastToolCall.tsx
|
|
1423
|
+
var import_react6 = require("react");
|
|
1424
|
+
var import_sonner = require("sonner");
|
|
1425
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1426
|
+
var ToastToolCall = ({
|
|
1427
|
+
toolCall,
|
|
1428
|
+
completeTool
|
|
1429
|
+
}) => {
|
|
1430
|
+
const input = typeof toolCall.input === "string" ? JSON.parse(toolCall.input) : toolCall.input;
|
|
1431
|
+
const message = input.message || "Toast message";
|
|
1432
|
+
const type = input.type || "info";
|
|
1433
|
+
let method;
|
|
1434
|
+
switch (type) {
|
|
1435
|
+
case "success":
|
|
1436
|
+
method = import_sonner.toast.success;
|
|
1437
|
+
break;
|
|
1438
|
+
case "error":
|
|
1439
|
+
method = import_sonner.toast.error;
|
|
1440
|
+
break;
|
|
1441
|
+
case "warning":
|
|
1442
|
+
method = import_sonner.toast.warning;
|
|
1443
|
+
break;
|
|
1444
|
+
default:
|
|
1445
|
+
method = import_sonner.toast.info;
|
|
1446
|
+
}
|
|
1447
|
+
;
|
|
1448
|
+
let duration = 500;
|
|
1449
|
+
(0, import_react6.useEffect)(() => {
|
|
1450
|
+
method(message, {
|
|
1451
|
+
duration: duration * 2,
|
|
1452
|
+
position: "top-right",
|
|
1453
|
+
className: "bg-background text-foreground border border-border",
|
|
1454
|
+
style: {
|
|
1455
|
+
backgroundColor: "var(--background)",
|
|
1456
|
+
color: "var(--foreground)",
|
|
1457
|
+
border: "1px solid var(--border)"
|
|
1458
|
+
}
|
|
1459
|
+
});
|
|
1460
|
+
setTimeout(() => {
|
|
1461
|
+
const result = {
|
|
1462
|
+
tool_call_id: toolCall.tool_call_id,
|
|
1463
|
+
result: "Toast displayed successfully",
|
|
1464
|
+
success: true,
|
|
1465
|
+
error: void 0
|
|
1466
|
+
};
|
|
1467
|
+
completeTool(result);
|
|
1468
|
+
}, duration);
|
|
1469
|
+
}, [message, type, completeTool]);
|
|
1470
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, {});
|
|
1471
|
+
};
|
|
1472
|
+
|
|
1473
|
+
// src/hooks/registerTools.tsx
|
|
1474
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1475
|
+
function registerTools({ agent, tools }) {
|
|
1476
|
+
const lastAgentIdRef = (0, import_react7.useRef)(null);
|
|
1477
|
+
(0, import_react7.useEffect)(() => {
|
|
1478
|
+
if (!agent || !tools || tools.length === 0) {
|
|
1479
|
+
return;
|
|
1480
|
+
}
|
|
1481
|
+
if (lastAgentIdRef.current === agent.id) {
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
[...defaultTools, ...tools].forEach((tool) => {
|
|
1485
|
+
agent.registerTool(tool);
|
|
1486
|
+
console.log(`\u2713 Registered tool: ${tool.name}`);
|
|
1487
|
+
});
|
|
1488
|
+
lastAgentIdRef.current = agent.id;
|
|
1489
|
+
console.log(`Successfully registered ${tools.length} tools with agent`);
|
|
1490
|
+
}, [agent?.id, tools]);
|
|
1491
|
+
}
|
|
1492
|
+
var defaultTools = [
|
|
1493
|
+
{
|
|
1494
|
+
name: "toast",
|
|
1495
|
+
type: "ui",
|
|
1496
|
+
description: "Show a toast message",
|
|
1497
|
+
input_schema: {
|
|
1498
|
+
type: "object",
|
|
1499
|
+
properties: {
|
|
1500
|
+
message: { type: "string" },
|
|
1501
|
+
type: { type: "string", enum: ["success", "error", "warning", "info"] }
|
|
1502
|
+
}
|
|
1503
|
+
},
|
|
1504
|
+
component: (props) => {
|
|
1505
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToastToolCall, { ...props });
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
// {
|
|
1509
|
+
// name: 'approval_request',
|
|
1510
|
+
// type: 'ui',
|
|
1511
|
+
// description: 'Request approval from the user',
|
|
1512
|
+
// parameters: {
|
|
1513
|
+
// type: 'object',
|
|
1514
|
+
// properties: {
|
|
1515
|
+
// message: { type: 'string' }
|
|
1516
|
+
// }
|
|
1517
|
+
// },
|
|
1518
|
+
// component: (props: UiToolProps) => { return (<ApprovalToolCall {...props} />) },
|
|
1519
|
+
// }
|
|
1520
|
+
];
|
|
1521
|
+
|
|
1522
|
+
// src/hooks/useToolCallState.ts
|
|
1523
|
+
var import_react8 = require("react");
|
|
1524
|
+
function useToolCallState(options) {
|
|
1525
|
+
const [toolCallStates, setToolCallStates] = (0, import_react8.useState)(/* @__PURE__ */ new Map());
|
|
1526
|
+
const { onAllToolsCompleted, agent } = options;
|
|
1527
|
+
const executeTool = async (tool, toolCall) => {
|
|
1528
|
+
if (!tool) {
|
|
1529
|
+
console.error(`Tool ${toolCall.tool_name} not found`);
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
let component;
|
|
1533
|
+
if (tool.type === "ui") {
|
|
1534
|
+
component = tool.component({
|
|
1535
|
+
toolCall,
|
|
1536
|
+
toolCallState: toolCallStates.get(toolCall.tool_call_id),
|
|
1537
|
+
completeTool: (result) => {
|
|
1538
|
+
updateToolCallStatus(toolCall.tool_call_id, {
|
|
1539
|
+
status: "completed",
|
|
1540
|
+
result,
|
|
1541
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
1542
|
+
});
|
|
1543
|
+
}
|
|
1544
|
+
});
|
|
1545
|
+
updateToolCallStatus(toolCall.tool_call_id, {
|
|
1546
|
+
tool_name: toolCall.tool_name,
|
|
1547
|
+
input: toolCall.input,
|
|
1548
|
+
component,
|
|
1549
|
+
status: "running",
|
|
1550
|
+
startedAt: /* @__PURE__ */ new Date()
|
|
1551
|
+
});
|
|
1552
|
+
} else {
|
|
1553
|
+
try {
|
|
1554
|
+
const result = await tool.handler(toolCall.input);
|
|
1555
|
+
console.log("result", result);
|
|
1556
|
+
updateToolCallStatus(toolCall.tool_call_id, {
|
|
1557
|
+
status: "completed",
|
|
1558
|
+
result: JSON.stringify(result),
|
|
1559
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
1560
|
+
});
|
|
1561
|
+
} catch (error) {
|
|
1562
|
+
updateToolCallStatus(toolCall.tool_call_id, {
|
|
1563
|
+
status: "error",
|
|
1564
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1565
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
const initToolCall = (0, import_react8.useCallback)((toolCall) => {
|
|
1571
|
+
const tool = agent?.getTools().find((t) => t.name === toolCall.tool_name);
|
|
1572
|
+
setToolCallStates((prev) => {
|
|
1573
|
+
const newStates = new Map(prev);
|
|
1574
|
+
const state = {
|
|
1575
|
+
tool_call_id: toolCall.tool_call_id,
|
|
1576
|
+
tool_name: toolCall.tool_name,
|
|
1577
|
+
input: toolCall.input,
|
|
1578
|
+
status: "pending",
|
|
1579
|
+
startedAt: /* @__PURE__ */ new Date()
|
|
1580
|
+
};
|
|
1581
|
+
newStates.set(toolCall.tool_call_id, state);
|
|
1582
|
+
return newStates;
|
|
1583
|
+
});
|
|
1584
|
+
if (tool) {
|
|
1585
|
+
executeTool(tool, toolCall);
|
|
1586
|
+
} else {
|
|
1587
|
+
console.log(agent?.getTools());
|
|
1588
|
+
}
|
|
1589
|
+
}, []);
|
|
1590
|
+
const updateToolCallStatus = (0, import_react8.useCallback)((toolCallId, updates) => {
|
|
1591
|
+
setToolCallStates((prev) => {
|
|
1592
|
+
const newStates = new Map(prev);
|
|
1593
|
+
const currentState = newStates.get(toolCallId);
|
|
1594
|
+
if (currentState) {
|
|
1595
|
+
newStates.set(toolCallId, {
|
|
1596
|
+
...currentState,
|
|
1597
|
+
...updates
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1600
|
+
if (Array.from(newStates.values()).filter((state) => state.status === "pending" || state.status === "running").length === 0 && onAllToolsCompleted) {
|
|
1601
|
+
onAllToolsCompleted(Array.from(newStates.values()).map((state) => ({
|
|
1602
|
+
tool_call_id: state.tool_call_id,
|
|
1603
|
+
result: state.result,
|
|
1604
|
+
success: state.status === "completed",
|
|
1605
|
+
error: state.error
|
|
1606
|
+
})));
|
|
1607
|
+
}
|
|
1608
|
+
return newStates;
|
|
1609
|
+
});
|
|
1610
|
+
}, []);
|
|
1611
|
+
const getToolCallState = (0, import_react8.useCallback)((toolCallId) => {
|
|
1612
|
+
return toolCallStates.get(toolCallId);
|
|
1613
|
+
}, [toolCallStates]);
|
|
1614
|
+
const hasPendingToolCalls = (0, import_react8.useCallback)(() => {
|
|
1615
|
+
return Array.from(toolCallStates.values()).some(
|
|
1616
|
+
(state) => state.status === "pending" || state.status === "running"
|
|
1617
|
+
);
|
|
1618
|
+
}, [toolCallStates]);
|
|
1619
|
+
const getPendingToolCalls = (0, import_react8.useCallback)(() => {
|
|
1620
|
+
const pendingIds = Array.from(toolCallStates.entries()).filter(([_, state]) => state.status === "pending" || state.status === "running").map(([id, _]) => id);
|
|
1621
|
+
return Array.from(toolCallStates.values()).filter((state) => pendingIds.includes(state.tool_call_id));
|
|
1622
|
+
}, [toolCallStates]);
|
|
1623
|
+
const clearAll = (0, import_react8.useCallback)(() => {
|
|
1624
|
+
setToolCallStates(/* @__PURE__ */ new Map());
|
|
1625
|
+
}, []);
|
|
1626
|
+
const clearToolResults = (0, import_react8.useCallback)(() => {
|
|
1627
|
+
toolCallStates.forEach((state) => {
|
|
1628
|
+
state.result = void 0;
|
|
1629
|
+
state.error = void 0;
|
|
1630
|
+
});
|
|
1631
|
+
}, []);
|
|
1632
|
+
return {
|
|
1633
|
+
toolCallStates,
|
|
1634
|
+
initToolCall,
|
|
1635
|
+
updateToolCallStatus,
|
|
1636
|
+
getToolCallState,
|
|
1637
|
+
hasPendingToolCalls,
|
|
1638
|
+
getPendingToolCalls,
|
|
1639
|
+
clearAll,
|
|
1640
|
+
clearToolResults
|
|
1641
|
+
};
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
// src/useChat.ts
|
|
1645
|
+
function useChat({
|
|
1646
|
+
threadId,
|
|
1647
|
+
onMessage,
|
|
1648
|
+
onError,
|
|
1649
|
+
metadata,
|
|
1650
|
+
onMessagesUpdate,
|
|
1651
|
+
agent,
|
|
1652
|
+
tools
|
|
1653
|
+
}) {
|
|
1654
|
+
const [messages, setMessages] = (0, import_react9.useState)([]);
|
|
1655
|
+
const [isLoading, setIsLoading] = (0, import_react9.useState)(false);
|
|
1656
|
+
const [isStreaming, setIsStreaming] = (0, import_react9.useState)(false);
|
|
1657
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
1658
|
+
const abortControllerRef = (0, import_react9.useRef)(null);
|
|
1659
|
+
const createInvokeContext = (0, import_react9.useCallback)(() => ({
|
|
1660
|
+
thread_id: threadId,
|
|
1661
|
+
run_id: void 0,
|
|
1662
|
+
metadata
|
|
1663
|
+
}), [threadId, metadata]);
|
|
1664
|
+
registerTools({ agent, tools });
|
|
1665
|
+
const toolStateHandler = useToolCallState({
|
|
1666
|
+
agent,
|
|
1667
|
+
onAllToolsCompleted: (toolResults) => {
|
|
1668
|
+
sendToolResultsToAgent(toolResults);
|
|
1669
|
+
}
|
|
1670
|
+
});
|
|
1671
|
+
(0, import_react9.useEffect)(() => {
|
|
1672
|
+
return () => {
|
|
1673
|
+
if (abortControllerRef.current) {
|
|
1674
|
+
abortControllerRef.current.abort();
|
|
1675
|
+
}
|
|
1676
|
+
};
|
|
1677
|
+
}, []);
|
|
1678
|
+
const agentIdRef = (0, import_react9.useRef)(void 0);
|
|
1679
|
+
(0, import_react9.useEffect)(() => {
|
|
1680
|
+
if (agent?.id !== agentIdRef.current) {
|
|
1681
|
+
setMessages([]);
|
|
1682
|
+
toolStateHandler.clearAll();
|
|
1683
|
+
setError(null);
|
|
1684
|
+
agentIdRef.current = agent?.id;
|
|
1685
|
+
}
|
|
1686
|
+
}, [agent?.id, toolStateHandler]);
|
|
1687
|
+
const clearMessages = (0, import_react9.useCallback)(() => {
|
|
1688
|
+
setMessages([]);
|
|
1689
|
+
toolStateHandler.clearAll();
|
|
1690
|
+
}, [toolStateHandler]);
|
|
1691
|
+
const fetchMessages = (0, import_react9.useCallback)(async () => {
|
|
1692
|
+
if (!agent) return;
|
|
1693
|
+
try {
|
|
1694
|
+
const a2aMessages = await agent.getThreadMessages(threadId);
|
|
1695
|
+
const distriMessages = a2aMessages.map(decodeA2AStreamEvent);
|
|
1696
|
+
setMessages(distriMessages);
|
|
1697
|
+
onMessagesUpdate?.();
|
|
1698
|
+
} catch (err) {
|
|
1699
|
+
const error2 = err instanceof Error ? err : new Error("Failed to fetch messages");
|
|
1700
|
+
setError(error2);
|
|
1701
|
+
onError?.(error2);
|
|
1702
|
+
}
|
|
1703
|
+
}, [threadId, agent?.id, onError, onMessagesUpdate]);
|
|
1704
|
+
(0, import_react9.useEffect)(() => {
|
|
1705
|
+
if (threadId) {
|
|
1706
|
+
fetchMessages();
|
|
1707
|
+
}
|
|
1708
|
+
}, [threadId, agent?.id]);
|
|
1709
|
+
const handleStreamEvent = (0, import_react9.useCallback)((event) => {
|
|
1710
|
+
setMessages((prev) => {
|
|
1711
|
+
if (isDistriMessage(event)) {
|
|
1712
|
+
const distriMessage = event;
|
|
1713
|
+
const existingMessageIndex = prev.findIndex((msg) => isDistriMessage(msg) && msg.id && msg.id === distriMessage.id);
|
|
1714
|
+
if (existingMessageIndex >= 0) {
|
|
1715
|
+
const updatedMessages = [...prev];
|
|
1716
|
+
const existingMessage = updatedMessages[existingMessageIndex];
|
|
1717
|
+
const mergedParts = [...existingMessage.parts, ...distriMessage.parts];
|
|
1718
|
+
updatedMessages[existingMessageIndex] = {
|
|
1719
|
+
...existingMessage,
|
|
1720
|
+
parts: mergedParts
|
|
1721
|
+
};
|
|
1722
|
+
return updatedMessages;
|
|
1723
|
+
} else {
|
|
1724
|
+
return [...prev, distriMessage];
|
|
1725
|
+
}
|
|
1726
|
+
} else {
|
|
1727
|
+
return [...prev, event];
|
|
1728
|
+
}
|
|
1729
|
+
});
|
|
1730
|
+
if (isDistriMessage(event)) {
|
|
1731
|
+
const distriMessage = event;
|
|
1732
|
+
const toolCallParts = distriMessage.parts.filter((part) => part.type === "tool_call");
|
|
1733
|
+
if (toolCallParts.length > 0) {
|
|
1734
|
+
const newToolCalls = toolCallParts.map((part) => part.tool_call);
|
|
1735
|
+
newToolCalls.forEach((toolCall) => {
|
|
1736
|
+
toolStateHandler.initToolCall(toolCall);
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
const toolResultParts = distriMessage.parts.filter((part) => part.type === "tool_result");
|
|
1740
|
+
if (toolResultParts.length > 0) {
|
|
1741
|
+
const newToolResults = toolResultParts.map((part) => part.tool_result);
|
|
1742
|
+
newToolResults.forEach((toolResult) => {
|
|
1743
|
+
toolStateHandler.updateToolCallStatus(
|
|
1744
|
+
toolResult.tool_call_id,
|
|
1745
|
+
{
|
|
1746
|
+
status: toolResult.success ? "completed" : "error",
|
|
1747
|
+
result: toolResult.result,
|
|
1748
|
+
error: toolResult.error,
|
|
1749
|
+
completedAt: /* @__PURE__ */ new Date()
|
|
1750
|
+
}
|
|
1751
|
+
);
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
onMessage?.(event);
|
|
1756
|
+
}, [onMessage, agent]);
|
|
1757
|
+
const sendMessage = (0, import_react9.useCallback)(async (content) => {
|
|
1758
|
+
if (!agent) return;
|
|
1759
|
+
setIsLoading(true);
|
|
1760
|
+
setIsStreaming(true);
|
|
1761
|
+
setError(null);
|
|
1762
|
+
if (abortControllerRef.current) {
|
|
1763
|
+
abortControllerRef.current.abort();
|
|
1764
|
+
}
|
|
1765
|
+
abortControllerRef.current = new AbortController();
|
|
1766
|
+
try {
|
|
1767
|
+
const parts = typeof content === "string" ? [{ type: "text", text: content }] : content;
|
|
1768
|
+
const distriMessage = DistriClient.initDistriMessage("user", parts);
|
|
1769
|
+
const context = createInvokeContext();
|
|
1770
|
+
const a2aMessage = convertDistriMessageToA2A(distriMessage, context);
|
|
1771
|
+
setMessages((prev) => [...prev, distriMessage]);
|
|
1772
|
+
const stream = await agent.invokeStream({
|
|
1773
|
+
message: a2aMessage,
|
|
1774
|
+
metadata: context.metadata
|
|
1775
|
+
});
|
|
1776
|
+
for await (const event of stream) {
|
|
1777
|
+
if (abortControllerRef.current?.signal.aborted) {
|
|
1778
|
+
break;
|
|
1779
|
+
}
|
|
1780
|
+
handleStreamEvent(event);
|
|
1781
|
+
}
|
|
1782
|
+
} catch (err) {
|
|
1783
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1786
|
+
const error2 = err instanceof Error ? err : new Error("Failed to send message");
|
|
1787
|
+
setError(error2);
|
|
1788
|
+
onError?.(error2);
|
|
1789
|
+
} finally {
|
|
1790
|
+
setIsLoading(false);
|
|
1791
|
+
setIsStreaming(false);
|
|
1792
|
+
abortControllerRef.current = null;
|
|
1793
|
+
}
|
|
1794
|
+
}, [agent, createInvokeContext, handleStreamEvent, onError]);
|
|
1795
|
+
const sendMessageStream = (0, import_react9.useCallback)(async (content, role = "user") => {
|
|
1796
|
+
if (!agent) return;
|
|
1797
|
+
setIsLoading(true);
|
|
1798
|
+
setIsStreaming(true);
|
|
1799
|
+
setError(null);
|
|
1800
|
+
if (abortControllerRef.current) {
|
|
1801
|
+
abortControllerRef.current.abort();
|
|
1802
|
+
}
|
|
1803
|
+
abortControllerRef.current = new AbortController();
|
|
1804
|
+
try {
|
|
1805
|
+
const parts = typeof content === "string" ? [{ type: "text", text: content }] : content;
|
|
1806
|
+
const distriMessage = DistriClient.initDistriMessage(role, parts);
|
|
1807
|
+
const context = createInvokeContext();
|
|
1808
|
+
const a2aMessage = convertDistriMessageToA2A(distriMessage, context);
|
|
1809
|
+
setMessages((prev) => [...prev, distriMessage]);
|
|
1810
|
+
const stream = await agent.invokeStream({
|
|
1811
|
+
message: a2aMessage,
|
|
1812
|
+
metadata: context.metadata
|
|
1813
|
+
});
|
|
1814
|
+
for await (const event of stream) {
|
|
1815
|
+
if (abortControllerRef.current?.signal.aborted) {
|
|
1816
|
+
break;
|
|
1817
|
+
}
|
|
1818
|
+
handleStreamEvent(event);
|
|
1819
|
+
}
|
|
1820
|
+
} catch (err) {
|
|
1821
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
const error2 = err instanceof Error ? err : new Error("Failed to send message");
|
|
1825
|
+
setError(error2);
|
|
1826
|
+
onError?.(error2);
|
|
1827
|
+
} finally {
|
|
1828
|
+
setIsLoading(false);
|
|
1829
|
+
setIsStreaming(false);
|
|
1830
|
+
abortControllerRef.current = null;
|
|
1831
|
+
}
|
|
1832
|
+
}, [agent, createInvokeContext, handleStreamEvent, onError, threadId]);
|
|
1833
|
+
const sendToolResultsToAgent = (0, import_react9.useCallback)(async (toolResults) => {
|
|
1834
|
+
if (agent && toolResults.length > 0) {
|
|
1835
|
+
console.log("Sending tool results via streaming:", toolResults);
|
|
1836
|
+
try {
|
|
1837
|
+
const toolResultParts = toolResults.map((result) => ({
|
|
1838
|
+
type: "tool_result",
|
|
1839
|
+
tool_result: result
|
|
1840
|
+
}));
|
|
1841
|
+
await sendMessageStream(toolResultParts, "tool");
|
|
1842
|
+
toolStateHandler.clearToolResults();
|
|
1843
|
+
} catch (err) {
|
|
1844
|
+
console.error("Failed to send tool results:", err);
|
|
1845
|
+
setError(err instanceof Error ? err : new Error("Failed to send tool results"));
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
}, [sendMessageStream, toolStateHandler]);
|
|
1849
|
+
const stopStreaming = (0, import_react9.useCallback)(() => {
|
|
1850
|
+
if (abortControllerRef.current) {
|
|
1851
|
+
abortControllerRef.current.abort();
|
|
1852
|
+
}
|
|
1853
|
+
}, []);
|
|
1854
|
+
return {
|
|
1855
|
+
messages,
|
|
1856
|
+
isStreaming,
|
|
1857
|
+
sendMessage,
|
|
1858
|
+
sendMessageStream,
|
|
1859
|
+
isLoading,
|
|
1860
|
+
error,
|
|
1861
|
+
clearMessages,
|
|
1862
|
+
agent: agent || void 0,
|
|
1863
|
+
toolCallStates: toolStateHandler.toolCallStates,
|
|
1864
|
+
hasPendingToolCalls: toolStateHandler.hasPendingToolCalls,
|
|
1865
|
+
stopStreaming
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
// src/useThreads.ts
|
|
1870
|
+
var import_react10 = require("react");
|
|
1871
|
+
function useThreads() {
|
|
1872
|
+
const { client, error: clientError, isLoading: clientLoading } = useDistri();
|
|
1873
|
+
const [threads, setThreads] = (0, import_react10.useState)([]);
|
|
1874
|
+
const [loading, setLoading] = (0, import_react10.useState)(true);
|
|
1875
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
1876
|
+
const fetchThreads = (0, import_react10.useCallback)(async () => {
|
|
1877
|
+
if (!client) {
|
|
1878
|
+
return;
|
|
1879
|
+
}
|
|
1880
|
+
try {
|
|
1881
|
+
setLoading(true);
|
|
1882
|
+
setError(null);
|
|
1883
|
+
const fetchedThreads = await client.getThreads();
|
|
1884
|
+
setThreads(fetchedThreads);
|
|
1885
|
+
} catch (err) {
|
|
1886
|
+
console.error("[useThreads] Failed to fetch threads:", err);
|
|
1887
|
+
setError(err instanceof Error ? err : new Error("Failed to fetch threads"));
|
|
1888
|
+
} finally {
|
|
1889
|
+
setLoading(false);
|
|
1890
|
+
}
|
|
1891
|
+
}, [client]);
|
|
1892
|
+
const fetchThread = (0, import_react10.useCallback)(async (threadId) => {
|
|
1893
|
+
if (!client) {
|
|
1894
|
+
throw new Error("Client not available");
|
|
1895
|
+
}
|
|
1896
|
+
try {
|
|
1897
|
+
const response = await client.getThread(threadId);
|
|
1898
|
+
return response;
|
|
1899
|
+
} catch (err) {
|
|
1900
|
+
console.error("[useThreads] Failed to fetch thread:", err);
|
|
1901
|
+
throw err;
|
|
1902
|
+
}
|
|
1903
|
+
}, [client]);
|
|
1904
|
+
const deleteThread = (0, import_react10.useCallback)(async (threadId) => {
|
|
1905
|
+
if (!client) {
|
|
1906
|
+
throw new Error("Client not available");
|
|
1907
|
+
}
|
|
1908
|
+
try {
|
|
1909
|
+
const response = await fetch(`${client.baseUrl}/api/v1/threads/${threadId}`, {
|
|
1910
|
+
method: "DELETE"
|
|
1911
|
+
});
|
|
1912
|
+
if (!response.ok) {
|
|
1913
|
+
throw new Error("Failed to delete thread");
|
|
1914
|
+
}
|
|
1915
|
+
setThreads((prev) => prev.filter((thread) => thread.id !== threadId));
|
|
1916
|
+
} catch (err) {
|
|
1917
|
+
setThreads((prev) => prev.filter((thread) => thread.id !== threadId));
|
|
1918
|
+
console.warn("Failed to delete thread from server, but removed locally:", err);
|
|
1919
|
+
}
|
|
1920
|
+
}, [client]);
|
|
1921
|
+
const updateThread = (0, import_react10.useCallback)(async (threadId, localId) => {
|
|
1922
|
+
if (!client) {
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
try {
|
|
1926
|
+
const response = await fetch(`${client.baseUrl}/api/v1/threads/${threadId}`);
|
|
1927
|
+
if (response.ok) {
|
|
1928
|
+
const updatedThread = await response.json();
|
|
1929
|
+
setThreads((prev) => {
|
|
1930
|
+
if (localId && prev.some((thread) => thread.id === localId)) {
|
|
1931
|
+
return [
|
|
1932
|
+
updatedThread,
|
|
1933
|
+
...prev.filter((thread) => thread.id !== localId && thread.id !== threadId)
|
|
1934
|
+
];
|
|
1935
|
+
}
|
|
1936
|
+
return prev.map(
|
|
1937
|
+
(thread) => thread.id === threadId ? updatedThread : thread
|
|
1938
|
+
);
|
|
1939
|
+
});
|
|
1940
|
+
}
|
|
1941
|
+
} catch (err) {
|
|
1942
|
+
console.warn("Failed to update thread:", err);
|
|
1943
|
+
}
|
|
1944
|
+
}, [client]);
|
|
1945
|
+
(0, import_react10.useEffect)(() => {
|
|
1946
|
+
if (clientLoading) {
|
|
1947
|
+
setLoading(true);
|
|
1948
|
+
return;
|
|
1949
|
+
}
|
|
1950
|
+
if (clientError) {
|
|
1951
|
+
setError(clientError);
|
|
1952
|
+
setLoading(false);
|
|
1953
|
+
return;
|
|
1954
|
+
}
|
|
1955
|
+
if (client) {
|
|
1956
|
+
fetchThreads();
|
|
1957
|
+
} else {
|
|
1958
|
+
setLoading(false);
|
|
1959
|
+
}
|
|
1960
|
+
}, [clientLoading, clientError, client, fetchThreads]);
|
|
1961
|
+
(0, import_react10.useEffect)(() => {
|
|
1962
|
+
if (!client) return;
|
|
1963
|
+
const interval = setInterval(() => {
|
|
1964
|
+
fetchThreads();
|
|
1965
|
+
}, 3e4);
|
|
1966
|
+
return () => clearInterval(interval);
|
|
1967
|
+
}, [client, fetchThreads]);
|
|
1968
|
+
return {
|
|
1969
|
+
threads,
|
|
1970
|
+
loading: loading || clientLoading,
|
|
1971
|
+
error: error || clientError,
|
|
1972
|
+
refetch: fetchThreads,
|
|
1973
|
+
deleteThread,
|
|
1974
|
+
fetchThread,
|
|
1975
|
+
updateThread
|
|
1976
|
+
};
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
// src/components/FullChat.tsx
|
|
1980
|
+
var import_react18 = require("react");
|
|
1981
|
+
|
|
1982
|
+
// src/components/EmbeddableChat.tsx
|
|
1983
|
+
var import_react15 = require("react");
|
|
1984
|
+
var import_lucide_react7 = require("lucide-react");
|
|
1985
|
+
|
|
1986
|
+
// src/components/Components.tsx
|
|
1987
|
+
var import_react13 = __toESM(require("react"), 1);
|
|
1988
|
+
var import_lucide_react3 = require("lucide-react");
|
|
1989
|
+
|
|
1990
|
+
// src/components/MessageRenderer.tsx
|
|
1991
|
+
var import_react12 = __toESM(require("react"), 1);
|
|
1992
|
+
var import_react_markdown = __toESM(require("react-markdown"), 1);
|
|
1993
|
+
var import_react_syntax_highlighter = require("react-syntax-highlighter");
|
|
1994
|
+
var import_prism = require("react-syntax-highlighter/dist/esm/styles/prism");
|
|
1995
|
+
var import_lucide_react2 = require("lucide-react");
|
|
1996
|
+
|
|
1997
|
+
// src/components/ChatContext.tsx
|
|
1998
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
1999
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2000
|
+
var defaultConfig = {
|
|
2001
|
+
theme: "auto",
|
|
2002
|
+
showDebug: false,
|
|
2003
|
+
autoScroll: true,
|
|
2004
|
+
showTimestamps: true,
|
|
2005
|
+
enableMarkdown: true,
|
|
2006
|
+
enableCodeHighlighting: true
|
|
2007
|
+
};
|
|
2008
|
+
var ChatContext = (0, import_react11.createContext)(null);
|
|
2009
|
+
var useChatConfig = () => {
|
|
2010
|
+
const context = (0, import_react11.useContext)(ChatContext);
|
|
2011
|
+
if (!context) {
|
|
2012
|
+
return {
|
|
2013
|
+
config: defaultConfig,
|
|
2014
|
+
updateConfig: () => {
|
|
2015
|
+
}
|
|
2016
|
+
};
|
|
2017
|
+
}
|
|
2018
|
+
return context;
|
|
2019
|
+
};
|
|
2020
|
+
|
|
2021
|
+
// src/components/MessageRenderer.tsx
|
|
2022
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2023
|
+
var CodeBlock = ({ language, children, inline = false }) => {
|
|
2024
|
+
const [copied, setCopied] = import_react12.default.useState(false);
|
|
2025
|
+
const handleCopy = async () => {
|
|
2026
|
+
try {
|
|
2027
|
+
await navigator.clipboard.writeText(children);
|
|
2028
|
+
setCopied(true);
|
|
2029
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
2030
|
+
} catch (err) {
|
|
2031
|
+
console.error("Failed to copy text: ", err);
|
|
2032
|
+
}
|
|
2033
|
+
};
|
|
2034
|
+
const normalizeLanguage = (lang) => {
|
|
2035
|
+
if (!lang) return "text";
|
|
2036
|
+
const langMap = {
|
|
2037
|
+
"js": "javascript",
|
|
2038
|
+
"ts": "typescript",
|
|
2039
|
+
"jsx": "javascript",
|
|
2040
|
+
"tsx": "typescript",
|
|
2041
|
+
"py": "python",
|
|
2042
|
+
"rb": "ruby",
|
|
2043
|
+
"sh": "bash",
|
|
2044
|
+
"shell": "bash",
|
|
2045
|
+
"yml": "yaml",
|
|
2046
|
+
"md": "markdown",
|
|
2047
|
+
"json5": "json",
|
|
2048
|
+
"dockerfile": "docker",
|
|
2049
|
+
"rs": "rust",
|
|
2050
|
+
"go": "go",
|
|
2051
|
+
"php": "php",
|
|
2052
|
+
"cpp": "cpp",
|
|
2053
|
+
"cxx": "cpp",
|
|
2054
|
+
"cc": "cpp",
|
|
2055
|
+
"c++": "cpp",
|
|
2056
|
+
"cs": "csharp",
|
|
2057
|
+
"kt": "kotlin",
|
|
2058
|
+
"swift": "swift",
|
|
2059
|
+
"scala": "scala",
|
|
2060
|
+
"clj": "clojure",
|
|
2061
|
+
"cljs": "clojure",
|
|
2062
|
+
"r": "r",
|
|
2063
|
+
"matlab": "matlab",
|
|
2064
|
+
"sql": "sql",
|
|
2065
|
+
"psql": "sql",
|
|
2066
|
+
"mysql": "sql",
|
|
2067
|
+
"sqlite": "sql"
|
|
2068
|
+
};
|
|
2069
|
+
const normalized = lang.toLowerCase();
|
|
2070
|
+
return langMap[normalized] || normalized;
|
|
2071
|
+
};
|
|
2072
|
+
const normalizedLanguage = normalizeLanguage(language);
|
|
2073
|
+
if (inline) {
|
|
2074
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("code", { className: "px-1.5 py-0.5 rounded text-sm font-mono bg-muted text-foreground", children });
|
|
2075
|
+
}
|
|
2076
|
+
const lineCount = children.split("\n").length;
|
|
2077
|
+
const shouldShowLineNumbers = lineCount > 4;
|
|
2078
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "relative group", children: [
|
|
2079
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2080
|
+
"button",
|
|
2081
|
+
{
|
|
2082
|
+
onClick: handleCopy,
|
|
2083
|
+
className: "p-2 rounded-md bg-muted hover:bg-muted/80",
|
|
2084
|
+
title: "Copy code",
|
|
2085
|
+
children: copied ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Check, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Copy, { className: "h-4 w-4" })
|
|
2086
|
+
}
|
|
2087
|
+
) }),
|
|
2088
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "relative", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2089
|
+
import_react_syntax_highlighter.Prism,
|
|
2090
|
+
{
|
|
2091
|
+
style: import_prism.oneLight,
|
|
2092
|
+
language: normalizedLanguage,
|
|
2093
|
+
PreTag: "div",
|
|
2094
|
+
showLineNumbers: shouldShowLineNumbers,
|
|
2095
|
+
wrapLines: true,
|
|
2096
|
+
wrapLongLines: true,
|
|
2097
|
+
lineNumberStyle: {
|
|
2098
|
+
minWidth: "2.5em",
|
|
2099
|
+
paddingRight: "1em",
|
|
2100
|
+
color: "#9CA3AF",
|
|
2101
|
+
fontSize: "0.75rem",
|
|
2102
|
+
userSelect: "none"
|
|
2103
|
+
},
|
|
2104
|
+
customStyle: {
|
|
2105
|
+
margin: 0,
|
|
2106
|
+
padding: "0.75rem",
|
|
2107
|
+
background: "hsl(var(--muted))",
|
|
2108
|
+
fontSize: "0.875rem",
|
|
2109
|
+
lineHeight: "1.5",
|
|
2110
|
+
fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace',
|
|
2111
|
+
overflowX: "auto",
|
|
2112
|
+
maxWidth: "100%"
|
|
2113
|
+
},
|
|
2114
|
+
codeTagProps: {
|
|
2115
|
+
style: {
|
|
2116
|
+
fontSize: "0.875rem",
|
|
2117
|
+
fontFamily: "inherit"
|
|
2118
|
+
}
|
|
2119
|
+
},
|
|
2120
|
+
children: children.replace(/\n$/, "")
|
|
2121
|
+
}
|
|
2122
|
+
) })
|
|
2123
|
+
] });
|
|
2124
|
+
};
|
|
2125
|
+
var CodeObservationComponent = ({ thought, code }) => {
|
|
2126
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "border rounded-lg p-4 my-4 border-border bg-muted/50", children: [
|
|
2127
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2 mb-3", children: [
|
|
2128
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Brain, { className: "h-4 w-4 text-blue-500" }),
|
|
2129
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm font-medium text-blue-600", children: "Code Observation" })
|
|
2130
|
+
] }),
|
|
2131
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "mb-3", children: [
|
|
2132
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "text-sm text-muted-foreground mb-2", children: "Thought:" }),
|
|
2133
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "text-sm text-foreground", children: thought })
|
|
2134
|
+
] }),
|
|
2135
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
2136
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "text-sm text-muted-foreground mb-2", children: "Code:" }),
|
|
2137
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CodeBlock, { language: "javascript", children: code })
|
|
2138
|
+
] })
|
|
2139
|
+
] });
|
|
2140
|
+
};
|
|
2141
|
+
var ToolCallComponent = ({ toolCall }) => {
|
|
2142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "border rounded-lg p-4 my-4 border-border bg-muted/50", children: [
|
|
2143
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2 mb-3", children: [
|
|
2144
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Wrench, { className: "h-4 w-4 text-green-500" }),
|
|
2145
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm font-medium text-green-600", children: "Tool Call" })
|
|
2146
|
+
] }),
|
|
2147
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
|
|
2148
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
2149
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm text-muted-foreground", children: "Tool:" }),
|
|
2150
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "ml-2 text-sm font-mono text-foreground", children: toolCall.tool_name })
|
|
2151
|
+
] }),
|
|
2152
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
2153
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm text-muted-foreground", children: "Input:" }),
|
|
2154
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "mt-1", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CodeBlock, { language: "json", children: JSON.stringify(toolCall.input, null, 2) }) })
|
|
2155
|
+
] })
|
|
2156
|
+
] })
|
|
2157
|
+
] });
|
|
2158
|
+
};
|
|
2159
|
+
var ToolResultComponent = ({ toolResult }) => {
|
|
2160
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "border rounded-lg p-4 my-4 border-border bg-muted/50", children: [
|
|
2161
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2 mb-3", children: [
|
|
2162
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.FileText, { className: "h-4 w-4 text-purple-500" }),
|
|
2163
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm font-medium text-purple-600", children: "Tool Result" }),
|
|
2164
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: `text-xs px-2 py-1 rounded ${toolResult.success ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800"}`, children: toolResult.success ? "Success" : "Error" })
|
|
2165
|
+
] }),
|
|
2166
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "space-y-2", children: [
|
|
2167
|
+
toolResult.error && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
2168
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm text-destructive", children: "Error:" }),
|
|
2169
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "mt-1 text-sm text-destructive", children: toolResult.error })
|
|
2170
|
+
] }),
|
|
2171
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
|
|
2172
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm text-muted-foreground", children: "Result:" }),
|
|
2173
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "mt-1", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CodeBlock, { language: "json", children: JSON.stringify(toolResult.result, null, 2) }) })
|
|
2174
|
+
] })
|
|
2175
|
+
] })
|
|
2176
|
+
] });
|
|
2177
|
+
};
|
|
2178
|
+
var PlanComponent = ({ plan }) => {
|
|
2179
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "border rounded-lg p-4 my-4 border-border bg-muted/50", children: [
|
|
2180
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2 mb-3", children: [
|
|
2181
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react2.Brain, { className: "h-4 w-4 text-orange-500" }),
|
|
2182
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "text-sm font-medium text-orange-600", children: "Plan" })
|
|
2183
|
+
] }),
|
|
2184
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "text-sm text-foreground", children: plan })
|
|
2185
|
+
] });
|
|
2186
|
+
};
|
|
2187
|
+
var PartRenderer = ({ part }) => {
|
|
2188
|
+
switch (part.type) {
|
|
2189
|
+
case "text":
|
|
2190
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "whitespace-pre-wrap break-words text-foreground", children: part.text });
|
|
2191
|
+
case "code_observation":
|
|
2192
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CodeObservationComponent, { thought: part.thought, code: part.code });
|
|
2193
|
+
case "tool_call":
|
|
2194
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolCallComponent, { toolCall: part.tool_call });
|
|
2195
|
+
case "tool_result":
|
|
2196
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ToolResultComponent, { toolResult: part.tool_result });
|
|
2197
|
+
case "plan":
|
|
2198
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PlanComponent, { plan: part.plan });
|
|
2199
|
+
case "image_url":
|
|
2200
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "my-4", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2201
|
+
"img",
|
|
2202
|
+
{
|
|
2203
|
+
src: part.image.url,
|
|
2204
|
+
alt: part.image.name || "Image",
|
|
2205
|
+
className: "max-w-full rounded-lg"
|
|
2206
|
+
}
|
|
2207
|
+
) });
|
|
2208
|
+
case "image_bytes":
|
|
2209
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "my-4", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2210
|
+
"img",
|
|
2211
|
+
{
|
|
2212
|
+
src: `data:${part.image.mime_type};base64,${part.image.data}`,
|
|
2213
|
+
alt: part.image.name || "Image",
|
|
2214
|
+
className: "max-w-full rounded-lg"
|
|
2215
|
+
}
|
|
2216
|
+
) });
|
|
2217
|
+
case "data":
|
|
2218
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "my-4", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CodeBlock, { language: "json", children: JSON.stringify(part.data, null, 2) }) });
|
|
2219
|
+
default:
|
|
2220
|
+
return null;
|
|
2221
|
+
}
|
|
2222
|
+
};
|
|
2223
|
+
var MessageRenderer = ({
|
|
2224
|
+
content,
|
|
2225
|
+
message,
|
|
2226
|
+
className = "",
|
|
2227
|
+
metadata: _metadata
|
|
2228
|
+
}) => {
|
|
2229
|
+
let config;
|
|
2230
|
+
try {
|
|
2231
|
+
const chatConfig = useChatConfig();
|
|
2232
|
+
config = chatConfig.config;
|
|
2233
|
+
} catch {
|
|
2234
|
+
config = {
|
|
2235
|
+
enableMarkdown: true,
|
|
2236
|
+
enableCodeHighlighting: true,
|
|
2237
|
+
theme: "chatgpt"
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2240
|
+
if (message && isDistriMessage(message)) {
|
|
2241
|
+
const hasToolCalls = message.parts.some((part) => part.type === "tool_call");
|
|
2242
|
+
const filteredParts = hasToolCalls ? message.parts.filter((part) => part.type !== "tool_result") : message.parts;
|
|
2243
|
+
const groupedParts = [];
|
|
2244
|
+
let currentTextGroup = [];
|
|
2245
|
+
for (const part of filteredParts) {
|
|
2246
|
+
if (part.type === "text") {
|
|
2247
|
+
currentTextGroup.push(part);
|
|
2248
|
+
} else {
|
|
2249
|
+
if (currentTextGroup.length > 0) {
|
|
2250
|
+
groupedParts.push([...currentTextGroup]);
|
|
2251
|
+
currentTextGroup = [];
|
|
2252
|
+
}
|
|
2253
|
+
groupedParts.push([part]);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
if (currentTextGroup.length > 0) {
|
|
2257
|
+
groupedParts.push(currentTextGroup);
|
|
2258
|
+
}
|
|
2259
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `space-y-2 ${className}`, children: groupedParts.map((group, groupIndex) => {
|
|
2260
|
+
if (group.length > 1 && group.every((part) => part.type === "text")) {
|
|
2261
|
+
const concatenatedText = group.map((part) => part.type === "text" ? part.text : "").join("");
|
|
2262
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "whitespace-pre-wrap break-words text-foreground", children: concatenatedText }, groupIndex);
|
|
2263
|
+
} else {
|
|
2264
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PartRenderer, { part: group[0] }, groupIndex);
|
|
2265
|
+
}
|
|
2266
|
+
}) });
|
|
2267
|
+
}
|
|
2268
|
+
if (!content) return null;
|
|
2269
|
+
const hasMarkdownSyntax = (0, import_react12.useMemo)(() => {
|
|
2270
|
+
if (!config.enableMarkdown) return false;
|
|
2271
|
+
const markdownPatterns = [
|
|
2272
|
+
/^#{1, 6}\s+/m,
|
|
2273
|
+
// Headers
|
|
2274
|
+
/\*\*.*?\*\*/g,
|
|
2275
|
+
// Bold
|
|
2276
|
+
/\*.*?\*/g,
|
|
2277
|
+
// Italic
|
|
2278
|
+
/`.*?`/g,
|
|
2279
|
+
// Inline code
|
|
2280
|
+
/```[\s\S]*?```/g,
|
|
2281
|
+
// Code blocks
|
|
2282
|
+
/^\s*[-*+]\s+/m,
|
|
2283
|
+
// Lists
|
|
2284
|
+
/^\s*\d+\.\s+/m,
|
|
2285
|
+
// Numbered lists
|
|
2286
|
+
/^\s*>\s+/m,
|
|
2287
|
+
// Blockquotes
|
|
2288
|
+
/\[.*?\]\(.*?\)/g,
|
|
2289
|
+
// Links
|
|
2290
|
+
/!\[.*?\]\(.*?\)/g,
|
|
2291
|
+
// Images
|
|
2292
|
+
/^\|.*\|/m
|
|
2293
|
+
// Tables
|
|
2294
|
+
];
|
|
2295
|
+
return markdownPatterns.some((pattern) => pattern.test(content));
|
|
2296
|
+
}, [content, config.enableMarkdown]);
|
|
2297
|
+
const looksLikeCode = (0, import_react12.useMemo)(() => {
|
|
2298
|
+
if (!config.enableCodeHighlighting) return false;
|
|
2299
|
+
if (hasMarkdownSyntax) return false;
|
|
2300
|
+
const lines = content.split("\n");
|
|
2301
|
+
const totalLines = lines.length;
|
|
2302
|
+
if (totalLines === 1 && content.length < 50) {
|
|
2303
|
+
return false;
|
|
2304
|
+
}
|
|
2305
|
+
const explicitCodePatterns = [
|
|
2306
|
+
/^#!\//,
|
|
2307
|
+
// Shebang
|
|
2308
|
+
/^\s*(function|const|let|var)\s+\w+\s*[=\(]/,
|
|
2309
|
+
// JS/TS function/variable declarations
|
|
2310
|
+
/^\s*(class|interface)\s+\w+/,
|
|
2311
|
+
// Class/interface declarations
|
|
2312
|
+
/^\s*(import|export)\s+/,
|
|
2313
|
+
// Import/export statements
|
|
2314
|
+
/^\s*(def|class)\s+\w+/,
|
|
2315
|
+
// Python def/class
|
|
2316
|
+
/^\s*(public|private|protected)\s+(class|interface|static)/,
|
|
2317
|
+
// Java/C# declarations
|
|
2318
|
+
/^\s*<\?php/,
|
|
2319
|
+
// PHP opening tag
|
|
2320
|
+
/^\s*<html|<head|<body|<div /,
|
|
2321
|
+
// HTML tags
|
|
2322
|
+
/^\s*\{[\s]*"[\w"]+"\s*:/,
|
|
2323
|
+
// JSON objects (key-value pairs)
|
|
2324
|
+
/^\s*SELECT\s+.*\s+FROM\s+/i,
|
|
2325
|
+
// SQL SELECT statements
|
|
2326
|
+
/^\s*\/\*[\s\S]*\*\//,
|
|
2327
|
+
// Block comments
|
|
2328
|
+
/^[ \t]*\/\/\s*\w+/,
|
|
2329
|
+
// Line comments (with actual content)
|
|
2330
|
+
/;\s*$/
|
|
2331
|
+
// Lines ending with semicolons
|
|
2332
|
+
];
|
|
2333
|
+
const hasExplicitCode = explicitCodePatterns.some((pattern) => pattern.test(content));
|
|
2334
|
+
if (!hasExplicitCode) return false;
|
|
2335
|
+
const structuralPatterns = [
|
|
2336
|
+
/[{ }[\]()]/g,
|
|
2337
|
+
// Brackets and braces
|
|
2338
|
+
/^\s{2,}/m,
|
|
2339
|
+
// Indentation
|
|
2340
|
+
/=>/g,
|
|
2341
|
+
// Arrow functions
|
|
2342
|
+
/[;:]/g
|
|
2343
|
+
// Semicolons or colons
|
|
2344
|
+
];
|
|
2345
|
+
const structureCount = structuralPatterns.reduce((count, pattern) => {
|
|
2346
|
+
const matches = content.match(pattern);
|
|
2347
|
+
return count + (matches ? matches.length : 0);
|
|
2348
|
+
}, 0);
|
|
2349
|
+
return structureCount >= 3;
|
|
2350
|
+
}, [content, hasMarkdownSyntax, config.enableCodeHighlighting]);
|
|
2351
|
+
const detectLanguage = (0, import_react12.useMemo)(() => {
|
|
2352
|
+
if (/\b(function|const|let|var|=>|console\.log)\b/.test(content)) return "javascript";
|
|
2353
|
+
if (/\b(interface|type|as\s+\w+)\b/.test(content)) return "typescript";
|
|
2354
|
+
if (/\b(def|import|from|print|if\s+\w+:)\b/.test(content)) return "python";
|
|
2355
|
+
if (/\b(public\s+class|static\s+void|System\.out)\b/.test(content)) return "java";
|
|
2356
|
+
if (/\b(fn|let\s+mut|impl|match)\b/.test(content)) return "rust";
|
|
2357
|
+
if (/\b(func|package|import|fmt\.)\b/.test(content)) return "go";
|
|
2358
|
+
if (/SELECT.*FROM|INSERT.*INTO|UPDATE.*SET/i.test(content)) return "sql";
|
|
2359
|
+
if (/<[^>]+>.*<\/[^>]+>/.test(content)) return "html";
|
|
2360
|
+
if (/\{[^}]*:[^}]*\}/.test(content)) return "json";
|
|
2361
|
+
if (/^#!\/bin\/(bash|sh)/.test(content)) return "bash";
|
|
2362
|
+
if (/\$\w+|echo\s+/.test(content)) return "bash";
|
|
2363
|
+
return "text";
|
|
2364
|
+
}, [content]);
|
|
2365
|
+
if (looksLikeCode) {
|
|
2366
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2367
|
+
CodeBlock,
|
|
2368
|
+
{
|
|
2369
|
+
language: detectLanguage,
|
|
2370
|
+
children: content
|
|
2371
|
+
}
|
|
2372
|
+
);
|
|
2373
|
+
}
|
|
2374
|
+
if (!hasMarkdownSyntax) {
|
|
2375
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `whitespace-pre-wrap break-words text-foreground ${className}`, children: content });
|
|
2376
|
+
}
|
|
2377
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: `prose prose-sm max-w-none prose-foreground ${className} break-words`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2378
|
+
import_react_markdown.default,
|
|
2379
|
+
{
|
|
2380
|
+
components: {
|
|
2381
|
+
code({ className: className2, children }) {
|
|
2382
|
+
const match = /language-(\w+)/.exec(className2 || "");
|
|
2383
|
+
const language = match ? match[1] : "";
|
|
2384
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2385
|
+
CodeBlock,
|
|
2386
|
+
{
|
|
2387
|
+
language,
|
|
2388
|
+
inline: true,
|
|
2389
|
+
children: String(children).replace(/\n$/, "")
|
|
2390
|
+
}
|
|
2391
|
+
);
|
|
2392
|
+
},
|
|
2393
|
+
// Enhanced blockquote styling
|
|
2394
|
+
blockquote({ children }) {
|
|
2395
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("blockquote", { className: "border-l-4 pl-4 py-2 italic my-4 rounded-r border-primary text-primary bg-primary/10", children });
|
|
2396
|
+
},
|
|
2397
|
+
// Enhanced table styling with overflow handling
|
|
2398
|
+
table({ children }) {
|
|
2399
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "overflow-x-auto my-4", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("table", { className: "min-w-full border-collapse rounded-lg overflow-hidden border-border", children }) });
|
|
2400
|
+
},
|
|
2401
|
+
th({ children }) {
|
|
2402
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { className: "border px-4 py-2 font-semibold text-left border-border bg-muted", children });
|
|
2403
|
+
},
|
|
2404
|
+
td({ children }) {
|
|
2405
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { className: "border px-4 py-2 border-border", children });
|
|
2406
|
+
}
|
|
2407
|
+
},
|
|
2408
|
+
children: content
|
|
2409
|
+
}
|
|
2410
|
+
) });
|
|
2411
|
+
};
|
|
2412
|
+
var MessageRenderer_default = MessageRenderer;
|
|
2413
|
+
|
|
2414
|
+
// src/components/Components.tsx
|
|
2415
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
2416
|
+
var MessageContainer = ({ children, align = "left", className = "", backgroundColor }) => {
|
|
2417
|
+
const justifyClass = align === "right" ? "justify-end" : align === "center" ? "justify-center" : "justify-start";
|
|
2418
|
+
const getBgClass = (color) => {
|
|
2419
|
+
switch (color) {
|
|
2420
|
+
case "#343541":
|
|
2421
|
+
return "bg-background";
|
|
2422
|
+
case "#444654":
|
|
2423
|
+
return "bg-muted";
|
|
2424
|
+
case "#40414f":
|
|
2425
|
+
return "bg-background";
|
|
2426
|
+
default:
|
|
2427
|
+
return "";
|
|
2428
|
+
}
|
|
2429
|
+
};
|
|
2430
|
+
const bgClass = backgroundColor ? getBgClass(backgroundColor) : "";
|
|
2431
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `flex ${justifyClass} w-full ${bgClass} ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-full max-w-4xl mx-auto", children }) });
|
|
2432
|
+
};
|
|
2433
|
+
var UserMessage = ({
|
|
2434
|
+
content,
|
|
2435
|
+
message,
|
|
2436
|
+
timestamp,
|
|
2437
|
+
className = "",
|
|
2438
|
+
avatar
|
|
2439
|
+
}) => {
|
|
2440
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MessageContainer, { align: "center", className, backgroundColor: "#343541", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-start gap-4 py-3 px-2", children: [
|
|
2441
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "distri-avatar distri-avatar-user", children: avatar || /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.User, { className: "h-4 w-4" }) }),
|
|
2442
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
2443
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-sm font-medium text-foreground mb-2", children: "You" }),
|
|
2444
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "prose prose-sm max-w-none text-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2445
|
+
MessageRenderer_default,
|
|
2446
|
+
{
|
|
2447
|
+
content,
|
|
2448
|
+
message,
|
|
2449
|
+
className: "text-foreground"
|
|
2450
|
+
}
|
|
2451
|
+
) }),
|
|
2452
|
+
timestamp && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs text-muted-foreground mt-2", children: timestamp.toLocaleTimeString() })
|
|
2453
|
+
] })
|
|
2454
|
+
] }) });
|
|
2455
|
+
};
|
|
2456
|
+
var AssistantMessage = ({
|
|
2457
|
+
content,
|
|
2458
|
+
message,
|
|
2459
|
+
timestamp,
|
|
2460
|
+
isStreaming = false,
|
|
2461
|
+
metadata: _metadata,
|
|
2462
|
+
className = "",
|
|
2463
|
+
avatar,
|
|
2464
|
+
name = "Assistant"
|
|
2465
|
+
}) => {
|
|
2466
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MessageContainer, { align: "center", className, backgroundColor: "#444654", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-start gap-4 py-3 px-2", children: [
|
|
2467
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "distri-avatar distri-avatar-assistant", children: avatar || /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Bot, { className: "h-4 w-4" }) }),
|
|
2468
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
2469
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "text-sm font-medium text-foreground mb-2 flex items-center gap-2", children: [
|
|
2470
|
+
name,
|
|
2471
|
+
isStreaming && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
2472
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-1 h-1 bg-muted-foreground rounded-full animate-pulse" }),
|
|
2473
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-1 h-1 bg-muted-foreground rounded-full animate-pulse delay-75" }),
|
|
2474
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-1 h-1 bg-muted-foreground rounded-full animate-pulse delay-150" })
|
|
2475
|
+
] })
|
|
2476
|
+
] }),
|
|
2477
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "prose prose-sm max-w-none text-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2478
|
+
MessageRenderer_default,
|
|
2479
|
+
{
|
|
2480
|
+
content,
|
|
2481
|
+
message,
|
|
2482
|
+
className: "text-foreground"
|
|
2483
|
+
}
|
|
2484
|
+
) }),
|
|
2485
|
+
timestamp && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs text-muted-foreground mt-2", children: timestamp.toLocaleTimeString() })
|
|
2486
|
+
] })
|
|
2487
|
+
] }) });
|
|
2488
|
+
};
|
|
2489
|
+
var AssistantWithToolCalls = ({
|
|
2490
|
+
content,
|
|
2491
|
+
message,
|
|
2492
|
+
toolCallStates,
|
|
2493
|
+
timestamp,
|
|
2494
|
+
isStreaming = false,
|
|
2495
|
+
className = "",
|
|
2496
|
+
avatar,
|
|
2497
|
+
name = "Assistant"
|
|
2498
|
+
}) => {
|
|
2499
|
+
const [expandedTools, setExpandedTools] = (0, import_react13.useState)(/* @__PURE__ */ new Set());
|
|
2500
|
+
const toggleToolExpansion = (toolCallId) => {
|
|
2501
|
+
setExpandedTools((prev) => {
|
|
2502
|
+
const newSet = new Set(prev);
|
|
2503
|
+
if (newSet.has(toolCallId)) {
|
|
2504
|
+
newSet.delete(toolCallId);
|
|
2505
|
+
} else {
|
|
2506
|
+
newSet.add(toolCallId);
|
|
2507
|
+
}
|
|
2508
|
+
return newSet;
|
|
2509
|
+
});
|
|
2510
|
+
};
|
|
2511
|
+
import_react13.default.useEffect(() => {
|
|
2512
|
+
const newExpanded = new Set(expandedTools);
|
|
2513
|
+
toolCallStates.forEach((toolCallState) => {
|
|
2514
|
+
if (toolCallState.status === "running" || toolCallState.status === "error" || toolCallState.status === "user_action_required") {
|
|
2515
|
+
newExpanded.add(toolCallState.tool_call_id);
|
|
2516
|
+
}
|
|
2517
|
+
});
|
|
2518
|
+
setExpandedTools(newExpanded);
|
|
2519
|
+
}, [toolCallStates]);
|
|
2520
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MessageContainer, { align: "center", className, backgroundColor: "#444654", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-start gap-4 py-3 px-2", children: [
|
|
2521
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "distri-avatar distri-avatar-assistant", children: avatar || /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Bot, { className: "h-4 w-4" }) }),
|
|
2522
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
2523
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "text-sm font-medium text-foreground mb-2 flex items-center gap-2", children: [
|
|
2524
|
+
name,
|
|
2525
|
+
isStreaming && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
2526
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-1 h-1 bg-muted-foreground rounded-full animate-pulse" }),
|
|
2527
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-1 h-1 bg-muted-foreground rounded-full animate-pulse delay-75" }),
|
|
2528
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "w-1 h-1 bg-muted-foreground rounded-full animate-pulse delay-150" })
|
|
2529
|
+
] })
|
|
2530
|
+
] }),
|
|
2531
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "prose prose-sm max-w-none text-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2532
|
+
MessageRenderer_default,
|
|
2533
|
+
{
|
|
2534
|
+
content,
|
|
2535
|
+
message,
|
|
2536
|
+
className: "text-foreground"
|
|
2537
|
+
}
|
|
2538
|
+
) }),
|
|
2539
|
+
toolCallStates.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "mt-4 space-y-3", children: [
|
|
2540
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-sm font-medium text-foreground", children: "Tool Calls" }),
|
|
2541
|
+
toolCallStates.map((toolCallState, index) => {
|
|
2542
|
+
const isExpanded = expandedTools.has(toolCallState.tool_call_id);
|
|
2543
|
+
const hasResult = toolCallState?.result !== void 0;
|
|
2544
|
+
const hasError = toolCallState?.error !== void 0;
|
|
2545
|
+
const canCollapse = hasResult || hasError || toolCallState?.status === "completed" || toolCallState?.status === "error";
|
|
2546
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "border rounded-lg bg-background overflow-hidden", children: [
|
|
2547
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "p-3 border-b border-border", children: [
|
|
2548
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
2549
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2550
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2551
|
+
"button",
|
|
2552
|
+
{
|
|
2553
|
+
onClick: () => toggleToolExpansion(toolCallState.tool_call_id),
|
|
2554
|
+
className: "p-1 hover:bg-muted rounded transition-colors",
|
|
2555
|
+
disabled: !canCollapse,
|
|
2556
|
+
children: canCollapse ? isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.ChevronDown, { className: "h-3 w-3 text-muted-foreground" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.ChevronRight, { className: "h-3 w-3 text-muted-foreground" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "h-3 w-3" })
|
|
2557
|
+
}
|
|
2558
|
+
),
|
|
2559
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Wrench, { className: "h-4 w-4 text-green-500" }),
|
|
2560
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-sm font-medium text-foreground", children: toolCallState?.tool_name })
|
|
2561
|
+
] }),
|
|
2562
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
2563
|
+
toolCallState?.status === "pending" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1 text-xs text-yellow-600", children: [
|
|
2564
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Clock, { className: "h-3 w-3" }),
|
|
2565
|
+
"Pending"
|
|
2566
|
+
] }),
|
|
2567
|
+
toolCallState?.status === "running" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1 text-xs text-blue-600", children: [
|
|
2568
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Loader2, { className: "h-3 w-3 animate-spin" }),
|
|
2569
|
+
"Running"
|
|
2570
|
+
] }),
|
|
2571
|
+
toolCallState?.status === "completed" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1 text-xs text-green-600", children: [
|
|
2572
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.CheckCircle, { className: "h-3 w-3" }),
|
|
2573
|
+
"Completed"
|
|
2574
|
+
] }),
|
|
2575
|
+
toolCallState?.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1 text-xs text-red-600", children: [
|
|
2576
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.XCircle, { className: "h-3 w-3" }),
|
|
2577
|
+
"Failed"
|
|
2578
|
+
] }),
|
|
2579
|
+
toolCallState?.status === "user_action_required" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-center gap-1 text-xs text-orange-600", children: [
|
|
2580
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Wrench, { className: "h-3 w-3" }),
|
|
2581
|
+
"User Action Required"
|
|
2582
|
+
] })
|
|
2583
|
+
] })
|
|
2584
|
+
] }),
|
|
2585
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "mt-2", children: [
|
|
2586
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs text-muted-foreground mb-1", children: "Input:" }),
|
|
2587
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs font-mono bg-muted p-2 rounded border", children: JSON.stringify(toolCallState?.input, null, 2) })
|
|
2588
|
+
] }),
|
|
2589
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "mt-3", children: !!toolCallState?.component && toolCallState.component })
|
|
2590
|
+
] }),
|
|
2591
|
+
canCollapse && isExpanded && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "p-3 bg-muted/30", children: [
|
|
2592
|
+
hasError && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "mb-3", children: [
|
|
2593
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs text-red-600 font-medium mb-1", children: "Error:" }),
|
|
2594
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs text-red-600 bg-red-50 p-2 rounded border border-red-200", children: toolCallState?.error })
|
|
2595
|
+
] }),
|
|
2596
|
+
hasResult && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
|
|
2597
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs text-muted-foreground font-medium mb-1", children: "Result:" }),
|
|
2598
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs font-mono bg-background p-2 rounded border", children: JSON.stringify(toolCallState?.result, null, 2) })
|
|
2599
|
+
] })
|
|
2600
|
+
] })
|
|
2601
|
+
] }, index);
|
|
2602
|
+
})
|
|
2603
|
+
] }),
|
|
2604
|
+
timestamp && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs text-muted-foreground mt-2", children: timestamp.toLocaleTimeString() })
|
|
2605
|
+
] })
|
|
2606
|
+
] }) });
|
|
2607
|
+
};
|
|
2608
|
+
var PlanMessage = ({
|
|
2609
|
+
message,
|
|
2610
|
+
plan,
|
|
2611
|
+
timestamp,
|
|
2612
|
+
className = "",
|
|
2613
|
+
avatar
|
|
2614
|
+
}) => {
|
|
2615
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MessageContainer, { align: "center", className, backgroundColor: "#40414f", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-start gap-4 py-3 px-2", children: [
|
|
2616
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "distri-avatar distri-avatar-plan", children: avatar || /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react3.Brain, { className: "h-4 w-4" }) }),
|
|
2617
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex-1 min-w-0", children: [
|
|
2618
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-sm font-medium text-foreground mb-2", children: "Plan" }),
|
|
2619
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "prose prose-sm max-w-none text-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2620
|
+
MessageRenderer_default,
|
|
2621
|
+
{
|
|
2622
|
+
content: plan,
|
|
2623
|
+
message,
|
|
2624
|
+
className: "text-foreground"
|
|
2625
|
+
}
|
|
2626
|
+
) }),
|
|
2627
|
+
timestamp && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs text-muted-foreground mt-2", children: timestamp.toLocaleTimeString() })
|
|
2628
|
+
] })
|
|
2629
|
+
] }) });
|
|
2630
|
+
};
|
|
2631
|
+
var DebugMessage = ({
|
|
2632
|
+
message,
|
|
2633
|
+
className = "",
|
|
2634
|
+
timestamp
|
|
2635
|
+
}) => {
|
|
2636
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MessageContainer, { align: "center", className, backgroundColor: "#343541", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex items-start gap-4 py-3 px-2", children: [
|
|
2637
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "prose prose-sm max-w-none text-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2638
|
+
MessageRenderer_default,
|
|
2639
|
+
{
|
|
2640
|
+
content: JSON.stringify(message),
|
|
2641
|
+
className: "text-foreground"
|
|
2642
|
+
}
|
|
2643
|
+
) }),
|
|
2644
|
+
timestamp && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs text-muted-foreground mt-2", children: timestamp.toLocaleTimeString() })
|
|
2645
|
+
] }) });
|
|
2646
|
+
};
|
|
2647
|
+
|
|
2648
|
+
// src/utils/messageUtils.ts
|
|
2649
|
+
var extractTextFromMessage = (message) => {
|
|
2650
|
+
if (isDistriMessage(message)) {
|
|
2651
|
+
if (!message?.parts || !Array.isArray(message.parts)) {
|
|
2652
|
+
return "";
|
|
2653
|
+
}
|
|
2654
|
+
const textParts = message.parts.filter((part) => part?.type === "text" && part?.text).map((part) => part.text);
|
|
2655
|
+
return textParts.join("") || "";
|
|
2656
|
+
} else {
|
|
2657
|
+
return JSON.stringify(message);
|
|
2658
|
+
}
|
|
2659
|
+
};
|
|
2660
|
+
var shouldDisplayMessage = (message, showDebugMessages = false) => {
|
|
2661
|
+
if (!message) return false;
|
|
2662
|
+
if (isDistriMessage(message)) {
|
|
2663
|
+
if (message.role === "user") {
|
|
2664
|
+
const textContent2 = extractTextFromMessage(message);
|
|
2665
|
+
return textContent2.trim().length > 0;
|
|
2666
|
+
}
|
|
2667
|
+
const textContent = extractTextFromMessage(message);
|
|
2668
|
+
if (textContent.trim()) return true;
|
|
2669
|
+
}
|
|
2670
|
+
return showDebugMessages;
|
|
2671
|
+
};
|
|
2672
|
+
|
|
2673
|
+
// src/components/AgentSelect.tsx
|
|
2674
|
+
var import_lucide_react5 = require("lucide-react");
|
|
2675
|
+
|
|
2676
|
+
// src/components/ui/select.tsx
|
|
2677
|
+
var React9 = __toESM(require("react"), 1);
|
|
2678
|
+
var SelectPrimitive = __toESM(require("@radix-ui/react-select"), 1);
|
|
2679
|
+
var import_lucide_react4 = require("lucide-react");
|
|
2680
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2681
|
+
var Select = SelectPrimitive.Root;
|
|
2682
|
+
var SelectGroup = SelectPrimitive.Group;
|
|
2683
|
+
var SelectValue = SelectPrimitive.Value;
|
|
2684
|
+
var SelectTrigger = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2685
|
+
SelectPrimitive.Trigger,
|
|
2686
|
+
{
|
|
2687
|
+
ref,
|
|
2688
|
+
className: cn(
|
|
2689
|
+
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
|
2690
|
+
className
|
|
2691
|
+
),
|
|
2692
|
+
...props,
|
|
2693
|
+
children: [
|
|
2694
|
+
children,
|
|
2695
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.ChevronDown, { className: "h-4 w-4 opacity-50" }) })
|
|
2696
|
+
]
|
|
2697
|
+
}
|
|
2698
|
+
));
|
|
2699
|
+
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
2700
|
+
var SelectScrollUpButton = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2701
|
+
SelectPrimitive.ScrollUpButton,
|
|
2702
|
+
{
|
|
2703
|
+
ref,
|
|
2704
|
+
className: cn(
|
|
2705
|
+
"flex cursor-default items-center justify-center py-1",
|
|
2706
|
+
className
|
|
2707
|
+
),
|
|
2708
|
+
...props,
|
|
2709
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.ChevronUp, { className: "h-4 w-4" })
|
|
2710
|
+
}
|
|
2711
|
+
));
|
|
2712
|
+
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
2713
|
+
var SelectScrollDownButton = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2714
|
+
SelectPrimitive.ScrollDownButton,
|
|
2715
|
+
{
|
|
2716
|
+
ref,
|
|
2717
|
+
className: cn(
|
|
2718
|
+
"flex cursor-default items-center justify-center py-1",
|
|
2719
|
+
className
|
|
2720
|
+
),
|
|
2721
|
+
...props,
|
|
2722
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.ChevronDown, { className: "h-4 w-4" })
|
|
2723
|
+
}
|
|
2724
|
+
));
|
|
2725
|
+
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
|
2726
|
+
var SelectContent = React9.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2727
|
+
SelectPrimitive.Content,
|
|
2728
|
+
{
|
|
2729
|
+
ref,
|
|
2730
|
+
className: cn(
|
|
2731
|
+
"relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",
|
|
2732
|
+
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
2733
|
+
className
|
|
2734
|
+
),
|
|
2735
|
+
position,
|
|
2736
|
+
...props,
|
|
2737
|
+
children: [
|
|
2738
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectScrollUpButton, {}),
|
|
2739
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2740
|
+
SelectPrimitive.Viewport,
|
|
2741
|
+
{
|
|
2742
|
+
className: cn(
|
|
2743
|
+
"p-1",
|
|
2744
|
+
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
|
2745
|
+
),
|
|
2746
|
+
children
|
|
2747
|
+
}
|
|
2748
|
+
),
|
|
2749
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectScrollDownButton, {})
|
|
2750
|
+
]
|
|
2751
|
+
}
|
|
2752
|
+
) }));
|
|
2753
|
+
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
2754
|
+
var SelectLabel = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2755
|
+
SelectPrimitive.Label,
|
|
2756
|
+
{
|
|
2757
|
+
ref,
|
|
2758
|
+
className: cn("px-2 py-1.5 text-sm font-semibold", className),
|
|
2759
|
+
...props
|
|
2760
|
+
}
|
|
2761
|
+
));
|
|
2762
|
+
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
2763
|
+
var SelectItem = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
2764
|
+
SelectPrimitive.Item,
|
|
2765
|
+
{
|
|
2766
|
+
ref,
|
|
2767
|
+
className: cn(
|
|
2768
|
+
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
2769
|
+
className
|
|
2770
|
+
),
|
|
2771
|
+
...props,
|
|
2772
|
+
children: [
|
|
2773
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Check, { className: "h-4 w-4" }) }) }),
|
|
2774
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SelectPrimitive.ItemText, { children })
|
|
2775
|
+
]
|
|
2776
|
+
}
|
|
2777
|
+
));
|
|
2778
|
+
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
2779
|
+
var SelectSeparator = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2780
|
+
SelectPrimitive.Separator,
|
|
2781
|
+
{
|
|
2782
|
+
ref,
|
|
2783
|
+
className: cn("-mx-1 my-1 h-px bg-muted", className),
|
|
2784
|
+
...props
|
|
2785
|
+
}
|
|
2786
|
+
));
|
|
2787
|
+
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
2788
|
+
|
|
2789
|
+
// src/components/AgentSelect.tsx
|
|
2790
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2791
|
+
var AgentSelect = ({
|
|
2792
|
+
agents,
|
|
2793
|
+
selectedAgentId,
|
|
2794
|
+
onAgentSelect,
|
|
2795
|
+
className = "",
|
|
2796
|
+
placeholder = "Select an agent...",
|
|
2797
|
+
disabled = false
|
|
2798
|
+
}) => {
|
|
2799
|
+
const selectedAgent = agents.find((agent) => agent.id === selectedAgentId);
|
|
2800
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Select, { value: selectedAgentId, onValueChange: onAgentSelect, disabled, children: [
|
|
2801
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SelectTrigger, { className: `w-full ${className} ${disabled ? "opacity-50 cursor-not-allowed" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center space-x-2", children: [
|
|
2802
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react5.Bot, { className: "h-4 w-4" }),
|
|
2803
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SelectValue, { placeholder, children: selectedAgent?.name || placeholder })
|
|
2804
|
+
] }) }),
|
|
2805
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SelectContent, { children: agents.map((agent) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SelectItem, { value: agent.id, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center space-x-2", children: [
|
|
2806
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react5.Bot, { className: "h-4 w-4" }),
|
|
2807
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col", children: [
|
|
2808
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "font-medium", children: agent.name }),
|
|
2809
|
+
agent.description && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-xs text-muted-foreground", children: agent.description })
|
|
2810
|
+
] })
|
|
2811
|
+
] }) }, agent.id)) })
|
|
2812
|
+
] });
|
|
2813
|
+
};
|
|
2814
|
+
|
|
2815
|
+
// src/components/ui/sonner.tsx
|
|
2816
|
+
var import_next_themes = require("next-themes");
|
|
2817
|
+
var import_sonner2 = require("sonner");
|
|
2818
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2819
|
+
var Toaster = ({ ...props }) => {
|
|
2820
|
+
const { theme = "system" } = (0, import_next_themes.useTheme)();
|
|
2821
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
2822
|
+
import_sonner2.Toaster,
|
|
2823
|
+
{
|
|
2824
|
+
theme,
|
|
2825
|
+
className: "toaster group",
|
|
2826
|
+
toastOptions: {
|
|
2827
|
+
classNames: {
|
|
2828
|
+
toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
|
|
2829
|
+
description: "group-[.toast]:text-muted-foreground",
|
|
2830
|
+
actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
|
|
2831
|
+
cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground"
|
|
2832
|
+
}
|
|
2833
|
+
},
|
|
2834
|
+
...props
|
|
2835
|
+
}
|
|
2836
|
+
);
|
|
2837
|
+
};
|
|
2838
|
+
|
|
2839
|
+
// src/components/ChatInput.tsx
|
|
2840
|
+
var import_react14 = require("react");
|
|
2841
|
+
var import_lucide_react6 = require("lucide-react");
|
|
2842
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2843
|
+
var ChatInput = ({
|
|
2844
|
+
value,
|
|
2845
|
+
onChange,
|
|
2846
|
+
onSend,
|
|
2847
|
+
onStop,
|
|
2848
|
+
placeholder = "Type your message...",
|
|
2849
|
+
disabled = false,
|
|
2850
|
+
isStreaming = false,
|
|
2851
|
+
className = ""
|
|
2852
|
+
}) => {
|
|
2853
|
+
const textareaRef = (0, import_react14.useRef)(null);
|
|
2854
|
+
(0, import_react14.useEffect)(() => {
|
|
2855
|
+
if (textareaRef.current) {
|
|
2856
|
+
textareaRef.current.style.height = "auto";
|
|
2857
|
+
textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 120)}px`;
|
|
2858
|
+
}
|
|
2859
|
+
}, [value]);
|
|
2860
|
+
const handleKeyPress = (e) => {
|
|
2861
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
2862
|
+
e.preventDefault();
|
|
2863
|
+
if (value.trim() && !disabled && !isStreaming) {
|
|
2864
|
+
onSend();
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
};
|
|
2868
|
+
const handleSend = () => {
|
|
2869
|
+
if (value.trim() && !disabled && !isStreaming) {
|
|
2870
|
+
onSend();
|
|
2871
|
+
}
|
|
2872
|
+
};
|
|
2873
|
+
const handleStop = () => {
|
|
2874
|
+
if (isStreaming && onStop) {
|
|
2875
|
+
onStop();
|
|
2876
|
+
}
|
|
2877
|
+
};
|
|
2878
|
+
const hasContent = value.trim().length > 0;
|
|
2879
|
+
const isDisabled = disabled || isStreaming;
|
|
2880
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: `relative flex min-h-14 w-full items-end ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "relative flex w-full flex-auto flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative mx-5 flex min-h-14 flex-auto rounded-lg border border-input bg-input items-start h-full", children: [
|
|
2881
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2882
|
+
"textarea",
|
|
2883
|
+
{
|
|
2884
|
+
ref: textareaRef,
|
|
2885
|
+
value,
|
|
2886
|
+
onChange: (e) => onChange(e.target.value),
|
|
2887
|
+
onKeyPress: handleKeyPress,
|
|
2888
|
+
placeholder,
|
|
2889
|
+
disabled: isDisabled,
|
|
2890
|
+
rows: 1,
|
|
2891
|
+
className: "max-h-[25dvh] flex-1 resize-none border-none outline-none bg-transparent placeholder:text-muted-foreground focus:ring-0 overflow-auto text-sm p-4 pr-20 text-foreground min-h-[52px] max-h-[120px]"
|
|
2892
|
+
}
|
|
2893
|
+
),
|
|
2894
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute right-2 bottom-0 flex items-center h-full", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2895
|
+
"button",
|
|
2896
|
+
{
|
|
2897
|
+
onClick: isStreaming ? handleStop : handleSend,
|
|
2898
|
+
disabled: !hasContent && !isStreaming,
|
|
2899
|
+
className: `h-10 w-10 rounded-md transition-colors flex items-center justify-center ${isStreaming ? "bg-destructive hover:bg-destructive/90 text-destructive-foreground" : hasContent && !disabled ? "bg-primary hover:bg-primary/90 text-primary-foreground" : "bg-muted text-muted-foreground hover:bg-muted"}`,
|
|
2900
|
+
children: isStreaming ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.Square, { className: "h-5 w-5" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react6.Send, { className: "h-5 w-5" })
|
|
2901
|
+
}
|
|
2902
|
+
) })
|
|
2903
|
+
] }) }) });
|
|
2904
|
+
};
|
|
2905
|
+
|
|
2906
|
+
// src/components/EmbeddableChat.tsx
|
|
2907
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2908
|
+
var EmbeddableChat = ({
|
|
2909
|
+
threadId = uuidv4(),
|
|
2910
|
+
agent,
|
|
2911
|
+
className = "",
|
|
2912
|
+
style = {},
|
|
2913
|
+
metadata,
|
|
2914
|
+
tools,
|
|
2915
|
+
availableAgents = [],
|
|
2916
|
+
UserMessageComponent = UserMessage,
|
|
2917
|
+
AssistantMessageComponent = AssistantMessage,
|
|
2918
|
+
AssistantWithToolCallsComponent = AssistantWithToolCalls,
|
|
2919
|
+
PlanMessageComponent = PlanMessage,
|
|
2920
|
+
theme = "dark",
|
|
2921
|
+
showDebug = false,
|
|
2922
|
+
showAgentSelector = true,
|
|
2923
|
+
placeholder = "Type your message...",
|
|
2924
|
+
disableAgentSelection = false,
|
|
2925
|
+
onAgentSelect,
|
|
2926
|
+
onResponse: _onResponse,
|
|
2927
|
+
onMessagesUpdate
|
|
2928
|
+
}) => {
|
|
2929
|
+
const [input, setInput] = (0, import_react15.useState)("");
|
|
2930
|
+
const messagesEndRef = (0, import_react15.useRef)(null);
|
|
2931
|
+
const {
|
|
2932
|
+
messages,
|
|
2933
|
+
isLoading,
|
|
2934
|
+
isStreaming,
|
|
2935
|
+
error,
|
|
2936
|
+
sendMessage: sendChatMessage,
|
|
2937
|
+
toolCallStates,
|
|
2938
|
+
stopStreaming
|
|
2939
|
+
} = useChat({
|
|
2940
|
+
threadId,
|
|
2941
|
+
agent: agent || void 0,
|
|
2942
|
+
tools,
|
|
2943
|
+
metadata,
|
|
2944
|
+
onMessagesUpdate
|
|
2945
|
+
});
|
|
2946
|
+
(0, import_react15.useEffect)(() => {
|
|
2947
|
+
if (messagesEndRef.current) {
|
|
2948
|
+
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
|
2949
|
+
}
|
|
2950
|
+
}, [messages]);
|
|
2951
|
+
const sendMessage = async () => {
|
|
2952
|
+
if (!input.trim() || isLoading) return;
|
|
2953
|
+
const messageText = input.trim();
|
|
2954
|
+
setInput("");
|
|
2955
|
+
try {
|
|
2956
|
+
await sendChatMessage(messageText);
|
|
2957
|
+
} catch (err) {
|
|
2958
|
+
console.error("Failed to send message:", err);
|
|
2959
|
+
setInput(messageText);
|
|
2960
|
+
}
|
|
2961
|
+
};
|
|
2962
|
+
const getMessageType = (message) => {
|
|
2963
|
+
if (message.parts.some((part) => part.type === "tool_call")) {
|
|
2964
|
+
return "assistant_with_tools";
|
|
2965
|
+
}
|
|
2966
|
+
if (message.parts.some((part) => part.type === "plan")) {
|
|
2967
|
+
return "plan";
|
|
2968
|
+
}
|
|
2969
|
+
return message.role;
|
|
2970
|
+
};
|
|
2971
|
+
const renderedMessages = (0, import_react15.useMemo)(() => {
|
|
2972
|
+
return messages.filter((msg) => shouldDisplayMessage(msg, showDebug)).map((message, index) => {
|
|
2973
|
+
const messageContent = extractTextFromMessage(message);
|
|
2974
|
+
const key = `message-${index}`;
|
|
2975
|
+
const timestamp = message.created_at ? new Date(message.created_at) : void 0;
|
|
2976
|
+
if (isDistriMessage(message)) {
|
|
2977
|
+
switch (getMessageType(message)) {
|
|
2978
|
+
case "user":
|
|
2979
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2980
|
+
UserMessageComponent,
|
|
2981
|
+
{
|
|
2982
|
+
message,
|
|
2983
|
+
timestamp
|
|
2984
|
+
},
|
|
2985
|
+
key
|
|
2986
|
+
);
|
|
2987
|
+
case "assistant":
|
|
2988
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2989
|
+
AssistantMessageComponent,
|
|
2990
|
+
{
|
|
2991
|
+
name: agent?.name,
|
|
2992
|
+
avatar: agent?.iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("img", { src: agent.iconUrl, alt: agent.name, className: "w-6 h-6 rounded-full" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "w-6 h-6 rounded-full bg-primary text-primary-foreground flex items-center justify-center text-xs", children: agent?.name?.charAt(0).toUpperCase() || "A" }),
|
|
2993
|
+
message,
|
|
2994
|
+
timestamp,
|
|
2995
|
+
isStreaming: isStreaming && index === messages.length - 1
|
|
2996
|
+
},
|
|
2997
|
+
key
|
|
2998
|
+
);
|
|
2999
|
+
case "assistant_with_tools":
|
|
3000
|
+
const states = (message.parts || []).filter((part) => part.tool_call).map((part) => {
|
|
3001
|
+
const toolCallState = toolCallStates.get(part.tool_call.tool_call_id);
|
|
3002
|
+
return toolCallState;
|
|
3003
|
+
}).filter(Boolean);
|
|
3004
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3005
|
+
AssistantWithToolCallsComponent,
|
|
3006
|
+
{
|
|
3007
|
+
message,
|
|
3008
|
+
toolCallStates: states,
|
|
3009
|
+
timestamp,
|
|
3010
|
+
isStreaming: isStreaming && index === messages.length - 1
|
|
3011
|
+
},
|
|
3012
|
+
key
|
|
3013
|
+
);
|
|
3014
|
+
case "plan":
|
|
3015
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3016
|
+
PlanMessageComponent,
|
|
3017
|
+
{
|
|
3018
|
+
message,
|
|
3019
|
+
plan: messageContent,
|
|
3020
|
+
timestamp
|
|
3021
|
+
},
|
|
3022
|
+
key
|
|
3023
|
+
);
|
|
3024
|
+
case "debug":
|
|
3025
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3026
|
+
DebugMessage,
|
|
3027
|
+
{
|
|
3028
|
+
message,
|
|
3029
|
+
timestamp
|
|
3030
|
+
},
|
|
3031
|
+
key
|
|
3032
|
+
);
|
|
3033
|
+
default:
|
|
3034
|
+
return null;
|
|
3035
|
+
}
|
|
3036
|
+
} else {
|
|
3037
|
+
return null;
|
|
3038
|
+
}
|
|
3039
|
+
}).filter(Boolean);
|
|
3040
|
+
}, [
|
|
3041
|
+
messages,
|
|
3042
|
+
showDebug,
|
|
3043
|
+
UserMessageComponent,
|
|
3044
|
+
AssistantMessageComponent,
|
|
3045
|
+
AssistantWithToolCallsComponent,
|
|
3046
|
+
PlanMessageComponent,
|
|
3047
|
+
toolCallStates,
|
|
3048
|
+
isStreaming
|
|
3049
|
+
]);
|
|
3050
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
3051
|
+
"div",
|
|
3052
|
+
{
|
|
3053
|
+
className: `distri-chat ${className} ${theme === "dark" ? "dark" : "light"} w-full bg-background text-foreground flex flex-col relative`,
|
|
3054
|
+
style: {
|
|
3055
|
+
...style
|
|
3056
|
+
},
|
|
3057
|
+
children: [
|
|
3058
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "pt-6 px-6 bg-background flex-shrink-0 z-10", children: showAgentSelector && availableAgents && availableAgents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "mb-6", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3059
|
+
AgentSelect,
|
|
3060
|
+
{
|
|
3061
|
+
agents: availableAgents,
|
|
3062
|
+
selectedAgentId: agent?.id,
|
|
3063
|
+
onAgentSelect: (agentId) => onAgentSelect?.(agentId),
|
|
3064
|
+
className: "w-full",
|
|
3065
|
+
disabled: disableAgentSelection || messages.length > 0
|
|
3066
|
+
}
|
|
3067
|
+
) }) }),
|
|
3068
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Toaster, {}),
|
|
3069
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex-1 relative min-h-0", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "absolute inset-0 flex flex-col", children: [
|
|
3070
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex-1 overflow-y-auto distri-scroll bg-background", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "mx-auto", style: { maxWidth: "var(--thread-content-max-width)" }, children: [
|
|
3071
|
+
messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "h-full flex items-center justify-center min-h-[400px]", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "text-center", children: [
|
|
3072
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react7.MessageSquare, { className: "h-16 w-16 text-muted-foreground mx-auto mb-4" }),
|
|
3073
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { className: "text-lg font-medium text-foreground mb-2", children: "Start a conversation" }),
|
|
3074
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-muted-foreground max-w-sm", children: placeholder || "Type your message below to begin chatting." })
|
|
3075
|
+
] }) }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "space-y-0 pt-4", children: renderedMessages }),
|
|
3076
|
+
isLoading && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "px-6 py-4 flex items-center space-x-2 bg-muted rounded-lg mt-4", children: [
|
|
3077
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-muted-foreground border-t-transparent" }),
|
|
3078
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-muted-foreground text-sm", children: "Thinking..." })
|
|
3079
|
+
] }),
|
|
3080
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "px-6 py-4 bg-destructive/20 border border-destructive/20 rounded-lg mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-center space-x-2", children: [
|
|
3081
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "h-4 w-4 rounded-full bg-destructive" }),
|
|
3082
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-destructive text-sm", children: error.message || String(error) })
|
|
3083
|
+
] }) }),
|
|
3084
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { ref: messagesEndRef })
|
|
3085
|
+
] }) }),
|
|
3086
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "absolute bottom-0 left-0 right-0 bg-background py-4", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "mx-auto", style: { maxWidth: "var(--thread-content-max-width)" }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
3087
|
+
ChatInput,
|
|
3088
|
+
{
|
|
3089
|
+
value: input,
|
|
3090
|
+
onChange: setInput,
|
|
3091
|
+
onSend: sendMessage,
|
|
3092
|
+
onStop: stopStreaming,
|
|
3093
|
+
placeholder,
|
|
3094
|
+
disabled: isLoading,
|
|
3095
|
+
isStreaming,
|
|
3096
|
+
className: "w-full"
|
|
3097
|
+
}
|
|
3098
|
+
) }) })
|
|
3099
|
+
] }) }),
|
|
3100
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Toaster, {})
|
|
3101
|
+
]
|
|
3102
|
+
}
|
|
3103
|
+
);
|
|
3104
|
+
};
|
|
3105
|
+
|
|
3106
|
+
// src/components/AgentList.tsx
|
|
3107
|
+
var import_react16 = __toESM(require("react"), 1);
|
|
3108
|
+
var import_lucide_react8 = require("lucide-react");
|
|
3109
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
3110
|
+
var AgentList = ({ agents, onRefresh, onStartChat }) => {
|
|
3111
|
+
const [refreshing, setRefreshing] = import_react16.default.useState(false);
|
|
3112
|
+
const handleRefresh = async () => {
|
|
3113
|
+
setRefreshing(true);
|
|
3114
|
+
try {
|
|
3115
|
+
await onRefresh();
|
|
3116
|
+
} finally {
|
|
3117
|
+
setRefreshing(false);
|
|
3118
|
+
}
|
|
3119
|
+
};
|
|
3120
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "", children: [
|
|
3121
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between p-6 border-b border-border", children: [
|
|
3122
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { className: "text-xl font-semibold text-foreground", children: "Available Agents" }),
|
|
3123
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3124
|
+
"button",
|
|
3125
|
+
{
|
|
3126
|
+
onClick: handleRefresh,
|
|
3127
|
+
disabled: refreshing,
|
|
3128
|
+
className: "flex items-center space-x-2 px-4 py-2 text-sm bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 disabled:opacity-50 transition-colors",
|
|
3129
|
+
children: [
|
|
3130
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react8.RefreshCw, { className: `h-4 w-4 ${refreshing ? "animate-spin" : ""}` }),
|
|
3131
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Refresh" })
|
|
3132
|
+
]
|
|
3133
|
+
}
|
|
3134
|
+
)
|
|
3135
|
+
] }),
|
|
3136
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "p-6", children: agents.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "text-center py-12", children: [
|
|
3137
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react8.Bot, { className: "h-16 w-16 text-muted-foreground mx-auto mb-4" }),
|
|
3138
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-muted-foreground text-lg", children: "No agents available" }),
|
|
3139
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground mt-2", children: "Check your server connection" })
|
|
3140
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "grid gap-6 md:grid-cols-2 lg:grid-cols-3", children: agents.map((agent) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3141
|
+
"div",
|
|
3142
|
+
{
|
|
3143
|
+
className: "bg-card border border-border rounded-xl p-6 hover:border-border/80 hover:bg-card/80 transition-all duration-200",
|
|
3144
|
+
children: [
|
|
3145
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex items-start justify-between mb-4", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center space-x-3", children: [
|
|
3146
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "w-12 h-12 bg-primary rounded-full flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react8.Bot, { className: "h-6 w-6 text-primary-foreground" }) }),
|
|
3147
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
3148
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { className: "font-semibold text-foreground text-lg", children: agent.name }),
|
|
3149
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex items-center space-x-1", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-xs text-muted-foreground capitalize", children: agent.version ? `v${agent.version}` : "Latest" }) })
|
|
3150
|
+
] })
|
|
3151
|
+
] }) }),
|
|
3152
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm text-muted-foreground mb-6 line-clamp-3", children: agent.description || "No description available" }),
|
|
3153
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
3154
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "text-xs text-muted-foreground", children: agent.version && `Version ${agent.version}` }),
|
|
3155
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "flex items-center space-x-2", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
3156
|
+
"button",
|
|
3157
|
+
{
|
|
3158
|
+
onClick: () => onStartChat(agent),
|
|
3159
|
+
className: "flex items-center space-x-1 px-3 py-2 text-xs bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors",
|
|
3160
|
+
children: [
|
|
3161
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react8.Play, { className: "h-3 w-3" }),
|
|
3162
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Chat" })
|
|
3163
|
+
]
|
|
3164
|
+
}
|
|
3165
|
+
) })
|
|
3166
|
+
] })
|
|
3167
|
+
]
|
|
3168
|
+
},
|
|
3169
|
+
agent.name
|
|
3170
|
+
)) }) })
|
|
3171
|
+
] });
|
|
3172
|
+
};
|
|
3173
|
+
var AgentList_default = AgentList;
|
|
3174
|
+
|
|
3175
|
+
// src/components/AgentsPage.tsx
|
|
3176
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
3177
|
+
var AgentsPage = ({ onStartChat }) => {
|
|
3178
|
+
const { agents, loading, refetch } = useAgents();
|
|
3179
|
+
const handleRefresh = async () => {
|
|
3180
|
+
await refetch();
|
|
3181
|
+
};
|
|
3182
|
+
const handleStartChat = (agent) => {
|
|
3183
|
+
onStartChat?.(agent);
|
|
3184
|
+
};
|
|
3185
|
+
if (loading) {
|
|
3186
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "h-full bg-background flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center space-x-2", children: [
|
|
3187
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "h-6 w-6 animate-spin rounded-full border-2 border-primary border-t-transparent" }),
|
|
3188
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-foreground", children: "Loading agents..." })
|
|
3189
|
+
] }) });
|
|
3190
|
+
}
|
|
3191
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "h-full bg-background overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "container mx-auto p-6", children: [
|
|
3192
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h1", { className: "text-3xl font-bold text-foreground mb-6", children: "Agents" }),
|
|
3193
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
3194
|
+
AgentList_default,
|
|
3195
|
+
{
|
|
3196
|
+
agents,
|
|
3197
|
+
onRefresh: handleRefresh,
|
|
3198
|
+
onStartChat: handleStartChat
|
|
3199
|
+
}
|
|
3200
|
+
)
|
|
3201
|
+
] }) });
|
|
3202
|
+
};
|
|
3203
|
+
var AgentsPage_default = AgentsPage;
|
|
3204
|
+
|
|
3205
|
+
// src/components/AppSidebar.tsx
|
|
3206
|
+
var import_react17 = require("react");
|
|
3207
|
+
var import_lucide_react12 = require("lucide-react");
|
|
3208
|
+
|
|
3209
|
+
// src/components/ui/sidebar.tsx
|
|
3210
|
+
var React16 = __toESM(require("react"), 1);
|
|
3211
|
+
var import_react_slot = require("@radix-ui/react-slot");
|
|
3212
|
+
var import_class_variance_authority2 = require("class-variance-authority");
|
|
3213
|
+
var import_lucide_react10 = require("lucide-react");
|
|
3214
|
+
|
|
3215
|
+
// src/components/ui/separator.tsx
|
|
3216
|
+
var React13 = __toESM(require("react"), 1);
|
|
3217
|
+
var SeparatorPrimitive = __toESM(require("@radix-ui/react-separator"), 1);
|
|
3218
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
3219
|
+
var Separator2 = React13.forwardRef(
|
|
3220
|
+
({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
3221
|
+
SeparatorPrimitive.Root,
|
|
3222
|
+
{
|
|
3223
|
+
ref,
|
|
3224
|
+
decorative,
|
|
3225
|
+
orientation,
|
|
3226
|
+
className: cn(
|
|
3227
|
+
"shrink-0 bg-border",
|
|
3228
|
+
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
|
3229
|
+
className
|
|
3230
|
+
),
|
|
3231
|
+
...props
|
|
3232
|
+
}
|
|
3233
|
+
)
|
|
3234
|
+
);
|
|
3235
|
+
Separator2.displayName = SeparatorPrimitive.Root.displayName;
|
|
3236
|
+
|
|
3237
|
+
// src/components/ui/sheet.tsx
|
|
3238
|
+
var React14 = __toESM(require("react"), 1);
|
|
3239
|
+
var SheetPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
|
|
3240
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
3241
|
+
var import_lucide_react9 = require("lucide-react");
|
|
3242
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
3243
|
+
var Sheet = SheetPrimitive.Root;
|
|
3244
|
+
var SheetPortal = SheetPrimitive.Portal;
|
|
3245
|
+
var SheetOverlay = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3246
|
+
SheetPrimitive.Overlay,
|
|
3247
|
+
{
|
|
3248
|
+
className: cn(
|
|
3249
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
3250
|
+
className
|
|
3251
|
+
),
|
|
3252
|
+
...props,
|
|
3253
|
+
ref
|
|
3254
|
+
}
|
|
3255
|
+
));
|
|
3256
|
+
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
|
3257
|
+
var sheetVariants = (0, import_class_variance_authority.cva)(
|
|
3258
|
+
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
|
3259
|
+
{
|
|
3260
|
+
variants: {
|
|
3261
|
+
side: {
|
|
3262
|
+
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
|
3263
|
+
bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
|
3264
|
+
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
|
3265
|
+
right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm"
|
|
3266
|
+
}
|
|
3267
|
+
},
|
|
3268
|
+
defaultVariants: {
|
|
3269
|
+
side: "right"
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
);
|
|
3273
|
+
var SheetContent = React14.forwardRef(({ side = "right", className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SheetPortal, { children: [
|
|
3274
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SheetOverlay, {}),
|
|
3275
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
3276
|
+
SheetPrimitive.Content,
|
|
3277
|
+
{
|
|
3278
|
+
ref,
|
|
3279
|
+
className: cn(sheetVariants({ side }), className),
|
|
3280
|
+
...props,
|
|
3281
|
+
children: [
|
|
3282
|
+
children,
|
|
3283
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SheetPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary", children: [
|
|
3284
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react9.X, { className: "h-4 w-4" }),
|
|
3285
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "sr-only", children: "Close" })
|
|
3286
|
+
] })
|
|
3287
|
+
]
|
|
3288
|
+
}
|
|
3289
|
+
)
|
|
3290
|
+
] }));
|
|
3291
|
+
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
|
3292
|
+
var SheetHeader = ({
|
|
3293
|
+
className,
|
|
3294
|
+
...props
|
|
3295
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3296
|
+
"div",
|
|
3297
|
+
{
|
|
3298
|
+
className: cn(
|
|
3299
|
+
"flex flex-col space-y-2 text-center sm:text-left",
|
|
3300
|
+
className
|
|
3301
|
+
),
|
|
3302
|
+
...props
|
|
3303
|
+
}
|
|
3304
|
+
);
|
|
3305
|
+
SheetHeader.displayName = "SheetHeader";
|
|
3306
|
+
var SheetFooter = ({
|
|
3307
|
+
className,
|
|
3308
|
+
...props
|
|
3309
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3310
|
+
"div",
|
|
3311
|
+
{
|
|
3312
|
+
className: cn(
|
|
3313
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
3314
|
+
className
|
|
3315
|
+
),
|
|
3316
|
+
...props
|
|
3317
|
+
}
|
|
3318
|
+
);
|
|
3319
|
+
SheetFooter.displayName = "SheetFooter";
|
|
3320
|
+
var SheetTitle = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3321
|
+
SheetPrimitive.Title,
|
|
3322
|
+
{
|
|
3323
|
+
ref,
|
|
3324
|
+
className: cn("text-lg font-semibold text-foreground", className),
|
|
3325
|
+
...props
|
|
3326
|
+
}
|
|
3327
|
+
));
|
|
3328
|
+
SheetTitle.displayName = SheetPrimitive.Title.displayName;
|
|
3329
|
+
var SheetDescription = React14.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
3330
|
+
SheetPrimitive.Description,
|
|
3331
|
+
{
|
|
3332
|
+
ref,
|
|
3333
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
3334
|
+
...props
|
|
3335
|
+
}
|
|
3336
|
+
));
|
|
3337
|
+
SheetDescription.displayName = SheetPrimitive.Description.displayName;
|
|
3338
|
+
|
|
3339
|
+
// src/components/ui/skeleton.tsx
|
|
3340
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
3341
|
+
function Skeleton({
|
|
3342
|
+
className,
|
|
3343
|
+
...props
|
|
3344
|
+
}) {
|
|
3345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3346
|
+
"div",
|
|
3347
|
+
{
|
|
3348
|
+
className: cn("animate-pulse rounded-md bg-muted", className),
|
|
3349
|
+
...props
|
|
3350
|
+
}
|
|
3351
|
+
);
|
|
3352
|
+
}
|
|
3353
|
+
|
|
3354
|
+
// src/components/ui/tooltip.tsx
|
|
3355
|
+
var React15 = __toESM(require("react"), 1);
|
|
3356
|
+
var TooltipPrimitive = __toESM(require("@radix-ui/react-tooltip"), 1);
|
|
3357
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
3358
|
+
var TooltipProvider = TooltipPrimitive.Provider;
|
|
3359
|
+
var Tooltip = TooltipPrimitive.Root;
|
|
3360
|
+
var TooltipTrigger = TooltipPrimitive.Trigger;
|
|
3361
|
+
var TooltipContent = React15.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3362
|
+
TooltipPrimitive.Content,
|
|
3363
|
+
{
|
|
3364
|
+
ref,
|
|
3365
|
+
sideOffset,
|
|
3366
|
+
className: cn(
|
|
3367
|
+
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
3368
|
+
className
|
|
3369
|
+
),
|
|
3370
|
+
...props
|
|
3371
|
+
}
|
|
3372
|
+
));
|
|
3373
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
3374
|
+
|
|
3375
|
+
// src/components/ui/sidebar.tsx
|
|
3376
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
3377
|
+
var SIDEBAR_COOKIE_NAME = "sidebar:state";
|
|
3378
|
+
var SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
|
3379
|
+
var SIDEBAR_WIDTH = "16rem";
|
|
3380
|
+
var SIDEBAR_WIDTH_MOBILE = "18rem";
|
|
3381
|
+
var SIDEBAR_WIDTH_ICON = "3rem";
|
|
3382
|
+
var SIDEBAR_KEYBOARD_SHORTCUT = "b";
|
|
3383
|
+
var SidebarContext = React16.createContext(null);
|
|
3384
|
+
function useSidebar() {
|
|
3385
|
+
const context = React16.useContext(SidebarContext);
|
|
3386
|
+
if (!context) {
|
|
3387
|
+
throw new Error("useSidebar must be used within a SidebarProvider.");
|
|
3388
|
+
}
|
|
3389
|
+
return context;
|
|
3390
|
+
}
|
|
3391
|
+
var SidebarProvider = React16.forwardRef(({ defaultOpen = true, open: openProp, onOpenChange: setOpenProp, className, style, children, ...props }, ref) => {
|
|
3392
|
+
const [_open, _setOpen] = React16.useState(defaultOpen);
|
|
3393
|
+
const open = openProp ?? _open;
|
|
3394
|
+
const setOpen = React16.useCallback(
|
|
3395
|
+
(value) => {
|
|
3396
|
+
const openState = typeof value === "function" ? value(open) : value;
|
|
3397
|
+
if (setOpenProp) {
|
|
3398
|
+
setOpenProp(openState);
|
|
3399
|
+
} else {
|
|
3400
|
+
_setOpen(openState);
|
|
3401
|
+
}
|
|
3402
|
+
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
|
|
3403
|
+
},
|
|
3404
|
+
[setOpenProp, open]
|
|
3405
|
+
);
|
|
3406
|
+
const [openMobile, setOpenMobile] = React16.useState(false);
|
|
3407
|
+
const [isMobile, setIsMobile] = React16.useState(false);
|
|
3408
|
+
React16.useEffect(() => {
|
|
3409
|
+
const checkMobile = () => {
|
|
3410
|
+
setIsMobile(window.innerWidth < 768);
|
|
3411
|
+
if (window.innerWidth < 768 && open) {
|
|
3412
|
+
setOpen(false);
|
|
3413
|
+
}
|
|
3414
|
+
};
|
|
3415
|
+
checkMobile();
|
|
3416
|
+
window.addEventListener("resize", checkMobile);
|
|
3417
|
+
return () => window.removeEventListener("resize", checkMobile);
|
|
3418
|
+
}, [setOpen, open]);
|
|
3419
|
+
React16.useEffect(() => {
|
|
3420
|
+
const savedState = localStorage.getItem(SIDEBAR_COOKIE_NAME);
|
|
3421
|
+
if (savedState !== null) {
|
|
3422
|
+
setOpen(savedState === "true");
|
|
3423
|
+
}
|
|
3424
|
+
}, [setOpen]);
|
|
3425
|
+
React16.useEffect(() => {
|
|
3426
|
+
const handleKeyDown = (event) => {
|
|
3427
|
+
if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
|
|
3428
|
+
event.preventDefault();
|
|
3429
|
+
setOpen(!open);
|
|
3430
|
+
}
|
|
3431
|
+
};
|
|
3432
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
3433
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
3434
|
+
}, [open, setOpen]);
|
|
3435
|
+
const toggleSidebar = React16.useCallback(() => {
|
|
3436
|
+
return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
|
|
3437
|
+
}, [isMobile, setOpen, setOpenMobile]);
|
|
3438
|
+
const state = open ? "expanded" : "collapsed";
|
|
3439
|
+
const contextValue = React16.useMemo(
|
|
3440
|
+
() => ({
|
|
3441
|
+
state,
|
|
3442
|
+
open,
|
|
3443
|
+
setOpen,
|
|
3444
|
+
isMobile,
|
|
3445
|
+
openMobile,
|
|
3446
|
+
setOpenMobile,
|
|
3447
|
+
toggleSidebar
|
|
3448
|
+
}),
|
|
3449
|
+
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
|
|
3450
|
+
);
|
|
3451
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipProvider, { delayDuration: 0, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3452
|
+
"div",
|
|
3453
|
+
{
|
|
3454
|
+
style: {
|
|
3455
|
+
"--sidebar-width": SIDEBAR_WIDTH,
|
|
3456
|
+
"--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
|
|
3457
|
+
...style
|
|
3458
|
+
},
|
|
3459
|
+
className: cn(
|
|
3460
|
+
"group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar",
|
|
3461
|
+
className
|
|
3462
|
+
),
|
|
3463
|
+
ref,
|
|
3464
|
+
...props,
|
|
3465
|
+
children
|
|
3466
|
+
}
|
|
3467
|
+
) }) });
|
|
3468
|
+
});
|
|
3469
|
+
SidebarProvider.displayName = "SidebarProvider";
|
|
3470
|
+
var Sidebar = React16.forwardRef(({ side = "left", variant = "sidebar", collapsible = "offcanvas", className, children, ...props }, ref) => {
|
|
3471
|
+
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
|
|
3472
|
+
if (collapsible === "none") {
|
|
3473
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3474
|
+
"div",
|
|
3475
|
+
{
|
|
3476
|
+
className: cn(
|
|
3477
|
+
"flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground",
|
|
3478
|
+
className
|
|
3479
|
+
),
|
|
3480
|
+
ref,
|
|
3481
|
+
...props,
|
|
3482
|
+
children
|
|
3483
|
+
}
|
|
3484
|
+
);
|
|
3485
|
+
}
|
|
3486
|
+
if (isMobile) {
|
|
3487
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Sheet, { open: openMobile, onOpenChange: setOpenMobile, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3488
|
+
SheetContent,
|
|
3489
|
+
{
|
|
3490
|
+
"data-sidebar": "sidebar",
|
|
3491
|
+
"data-mobile": "true",
|
|
3492
|
+
className: "w-[--sidebar-width-mobile] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden",
|
|
3493
|
+
style: {
|
|
3494
|
+
"--sidebar-width": SIDEBAR_WIDTH_MOBILE
|
|
3495
|
+
},
|
|
3496
|
+
side,
|
|
3497
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex h-full w-full flex-col", children })
|
|
3498
|
+
}
|
|
3499
|
+
) });
|
|
3500
|
+
}
|
|
3501
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3502
|
+
"div",
|
|
3503
|
+
{
|
|
3504
|
+
ref,
|
|
3505
|
+
className: "group peer hidden md:block text-sidebar-foreground",
|
|
3506
|
+
"data-state": state,
|
|
3507
|
+
"data-collapsible": state === "collapsed" ? collapsible : "",
|
|
3508
|
+
"data-variant": variant,
|
|
3509
|
+
"data-side": side,
|
|
3510
|
+
children: [
|
|
3511
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3512
|
+
"div",
|
|
3513
|
+
{
|
|
3514
|
+
className: cn(
|
|
3515
|
+
"duration-200 relative h-svh w-[--sidebar-width] bg-transparent transition-[width] ease-linear",
|
|
3516
|
+
"group-data-[collapsible=offcanvas]:w-0",
|
|
3517
|
+
"group-data-[side=right]:rotate-180",
|
|
3518
|
+
variant === "floating" || variant === "inset" ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]" : "group-data-[collapsible=icon]:w-[--sidebar-width-icon]"
|
|
3519
|
+
)
|
|
3520
|
+
}
|
|
3521
|
+
),
|
|
3522
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3523
|
+
"div",
|
|
3524
|
+
{
|
|
3525
|
+
className: cn(
|
|
3526
|
+
"duration-200 fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] ease-linear md:flex",
|
|
3527
|
+
side === "left" ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
|
3528
|
+
// Adjust the padding for floating and inset variants.
|
|
3529
|
+
variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]" : "group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l",
|
|
3530
|
+
className
|
|
3531
|
+
),
|
|
3532
|
+
...props,
|
|
3533
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3534
|
+
"div",
|
|
3535
|
+
{
|
|
3536
|
+
"data-sidebar": "sidebar",
|
|
3537
|
+
className: "flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow",
|
|
3538
|
+
children
|
|
3539
|
+
}
|
|
3540
|
+
)
|
|
3541
|
+
}
|
|
3542
|
+
)
|
|
3543
|
+
]
|
|
3544
|
+
}
|
|
3545
|
+
);
|
|
3546
|
+
});
|
|
3547
|
+
Sidebar.displayName = "Sidebar";
|
|
3548
|
+
var SidebarTrigger = React16.forwardRef(({ className, onClick, ...props }, ref) => {
|
|
3549
|
+
const { toggleSidebar } = useSidebar();
|
|
3550
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3551
|
+
Button,
|
|
3552
|
+
{
|
|
3553
|
+
ref,
|
|
3554
|
+
"data-sidebar": "trigger",
|
|
3555
|
+
variant: "ghost",
|
|
3556
|
+
size: "icon",
|
|
3557
|
+
className: cn("h-7 w-7", className),
|
|
3558
|
+
onClick: (event) => {
|
|
3559
|
+
onClick?.(event);
|
|
3560
|
+
toggleSidebar();
|
|
3561
|
+
},
|
|
3562
|
+
...props,
|
|
3563
|
+
children: [
|
|
3564
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react10.PanelLeft, {}),
|
|
3565
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "sr-only", children: "Toggle Sidebar" })
|
|
3566
|
+
]
|
|
3567
|
+
}
|
|
3568
|
+
);
|
|
3569
|
+
});
|
|
3570
|
+
SidebarTrigger.displayName = "SidebarTrigger";
|
|
3571
|
+
var SidebarRail = React16.forwardRef(({ className, ...props }, ref) => {
|
|
3572
|
+
const { toggleSidebar } = useSidebar();
|
|
3573
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3574
|
+
"button",
|
|
3575
|
+
{
|
|
3576
|
+
ref,
|
|
3577
|
+
"data-sidebar": "rail",
|
|
3578
|
+
"aria-label": "Toggle Sidebar",
|
|
3579
|
+
tabIndex: -1,
|
|
3580
|
+
onClick: toggleSidebar,
|
|
3581
|
+
title: "Toggle Sidebar",
|
|
3582
|
+
className: cn(
|
|
3583
|
+
"absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] after:-translate-x-1/2 after:bg-sidebar-border hover:after:bg-sidebar-accent-foreground group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex",
|
|
3584
|
+
"[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize",
|
|
3585
|
+
"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
|
|
3586
|
+
"group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar",
|
|
3587
|
+
"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
|
|
3588
|
+
"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
|
|
3589
|
+
className
|
|
3590
|
+
),
|
|
3591
|
+
...props
|
|
3592
|
+
}
|
|
3593
|
+
);
|
|
3594
|
+
});
|
|
3595
|
+
SidebarRail.displayName = "SidebarRail";
|
|
3596
|
+
var SidebarInset = React16.forwardRef(({ className, ...props }, ref) => {
|
|
3597
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3598
|
+
"main",
|
|
3599
|
+
{
|
|
3600
|
+
ref,
|
|
3601
|
+
className: cn(
|
|
3602
|
+
"relative flex min-h-svh flex-1 flex-col bg-background",
|
|
3603
|
+
"peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow",
|
|
3604
|
+
className
|
|
3605
|
+
),
|
|
3606
|
+
...props
|
|
3607
|
+
}
|
|
3608
|
+
);
|
|
3609
|
+
});
|
|
3610
|
+
SidebarInset.displayName = "SidebarInset";
|
|
3611
|
+
var SidebarHeader = React16.forwardRef(({ className, ...props }, ref) => {
|
|
3612
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3613
|
+
"div",
|
|
3614
|
+
{
|
|
3615
|
+
ref,
|
|
3616
|
+
"data-sidebar": "header",
|
|
3617
|
+
className: cn("flex flex-col gap-2 p-2", className),
|
|
3618
|
+
...props
|
|
3619
|
+
}
|
|
3620
|
+
);
|
|
3621
|
+
});
|
|
3622
|
+
SidebarHeader.displayName = "SidebarHeader";
|
|
3623
|
+
var SidebarFooter = React16.forwardRef(({ className, ...props }, ref) => {
|
|
3624
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3625
|
+
"div",
|
|
3626
|
+
{
|
|
3627
|
+
ref,
|
|
3628
|
+
"data-sidebar": "footer",
|
|
3629
|
+
className: cn("flex flex-col gap-2 p-2", className),
|
|
3630
|
+
...props
|
|
3631
|
+
}
|
|
3632
|
+
);
|
|
3633
|
+
});
|
|
3634
|
+
SidebarFooter.displayName = "SidebarFooter";
|
|
3635
|
+
var SidebarSeparator = React16.forwardRef(({ className, ...props }, ref) => {
|
|
3636
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3637
|
+
Separator2,
|
|
3638
|
+
{
|
|
3639
|
+
ref,
|
|
3640
|
+
"data-sidebar": "separator",
|
|
3641
|
+
className: cn("mx-2 w-auto bg-sidebar-border", className),
|
|
3642
|
+
...props
|
|
3643
|
+
}
|
|
3644
|
+
);
|
|
3645
|
+
});
|
|
3646
|
+
SidebarSeparator.displayName = "SidebarSeparator";
|
|
3647
|
+
var SidebarContent = React16.forwardRef(({ className, ...props }, ref) => {
|
|
3648
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3649
|
+
"div",
|
|
3650
|
+
{
|
|
3651
|
+
ref,
|
|
3652
|
+
"data-sidebar": "content",
|
|
3653
|
+
className: cn(
|
|
3654
|
+
"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
|
|
3655
|
+
className
|
|
3656
|
+
),
|
|
3657
|
+
...props
|
|
3658
|
+
}
|
|
3659
|
+
);
|
|
3660
|
+
});
|
|
3661
|
+
SidebarContent.displayName = "SidebarContent";
|
|
3662
|
+
var SidebarGroup = React16.forwardRef(({ className, ...props }, ref) => {
|
|
3663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3664
|
+
"div",
|
|
3665
|
+
{
|
|
3666
|
+
ref,
|
|
3667
|
+
"data-sidebar": "group",
|
|
3668
|
+
className: cn("relative flex w-full min-w-0 flex-col p-2", className),
|
|
3669
|
+
...props
|
|
3670
|
+
}
|
|
3671
|
+
);
|
|
3672
|
+
});
|
|
3673
|
+
SidebarGroup.displayName = "SidebarGroup";
|
|
3674
|
+
var SidebarGroupLabel = React16.forwardRef(({ className, asChild = false, ...props }, ref) => {
|
|
3675
|
+
const Comp = asChild ? import_react_slot.Slot : "div";
|
|
3676
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3677
|
+
Comp,
|
|
3678
|
+
{
|
|
3679
|
+
ref,
|
|
3680
|
+
"data-sidebar": "group-label",
|
|
3681
|
+
className: cn(
|
|
3682
|
+
"duration-200 flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opa] ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
|
3683
|
+
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
|
|
3684
|
+
className
|
|
3685
|
+
),
|
|
3686
|
+
...props
|
|
3687
|
+
}
|
|
3688
|
+
);
|
|
3689
|
+
});
|
|
3690
|
+
SidebarGroupLabel.displayName = "SidebarGroupLabel";
|
|
3691
|
+
var SidebarGroupAction = React16.forwardRef(({ className, asChild = false, ...props }, ref) => {
|
|
3692
|
+
const Comp = asChild ? import_react_slot.Slot : "button";
|
|
3693
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3694
|
+
Comp,
|
|
3695
|
+
{
|
|
3696
|
+
ref,
|
|
3697
|
+
"data-sidebar": "group-action",
|
|
3698
|
+
className: cn(
|
|
3699
|
+
"absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
|
3700
|
+
// Increases the hit area of the button on mobile.
|
|
3701
|
+
"after:absolute after:-inset-2 after:md:hidden",
|
|
3702
|
+
"group-data-[collapsible=icon]:hidden",
|
|
3703
|
+
className
|
|
3704
|
+
),
|
|
3705
|
+
...props
|
|
3706
|
+
}
|
|
3707
|
+
);
|
|
3708
|
+
});
|
|
3709
|
+
SidebarGroupAction.displayName = "SidebarGroupAction";
|
|
3710
|
+
var SidebarGroupContent = React16.forwardRef(({ className, ...props }, ref) => {
|
|
3711
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3712
|
+
"div",
|
|
3713
|
+
{
|
|
3714
|
+
ref,
|
|
3715
|
+
"data-sidebar": "group-content",
|
|
3716
|
+
className: cn("w-full text-sm", className),
|
|
3717
|
+
...props
|
|
3718
|
+
}
|
|
3719
|
+
);
|
|
3720
|
+
});
|
|
3721
|
+
SidebarGroupContent.displayName = "SidebarGroupContent";
|
|
3722
|
+
var SidebarMenu = React16.forwardRef(({ className, ...props }, ref) => {
|
|
3723
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3724
|
+
"ul",
|
|
3725
|
+
{
|
|
3726
|
+
ref,
|
|
3727
|
+
"data-sidebar": "menu",
|
|
3728
|
+
className: cn("flex w-full min-w-0 flex-col gap-1", className),
|
|
3729
|
+
...props
|
|
3730
|
+
}
|
|
3731
|
+
);
|
|
3732
|
+
});
|
|
3733
|
+
SidebarMenu.displayName = "SidebarMenu";
|
|
3734
|
+
var SidebarMenuItem = React16.forwardRef(({ className, ...props }, ref) => {
|
|
3735
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3736
|
+
"li",
|
|
3737
|
+
{
|
|
3738
|
+
ref,
|
|
3739
|
+
"data-sidebar": "menu-item",
|
|
3740
|
+
className: cn("group/menu-item relative", className),
|
|
3741
|
+
...props
|
|
3742
|
+
}
|
|
3743
|
+
);
|
|
3744
|
+
});
|
|
3745
|
+
SidebarMenuItem.displayName = "SidebarMenuItem";
|
|
3746
|
+
var sidebarMenuButtonVariants = (0, import_class_variance_authority2.cva)(
|
|
3747
|
+
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
|
|
3748
|
+
{
|
|
3749
|
+
variants: {
|
|
3750
|
+
variant: {
|
|
3751
|
+
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
3752
|
+
outline: "bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]"
|
|
3753
|
+
},
|
|
3754
|
+
size: {
|
|
3755
|
+
default: "h-8 text-sm",
|
|
3756
|
+
sm: "h-7 text-xs",
|
|
3757
|
+
lg: "h-12 text-sm group-data-[collapsible=icon]:!size-8"
|
|
3758
|
+
}
|
|
3759
|
+
},
|
|
3760
|
+
defaultVariants: {
|
|
3761
|
+
variant: "default",
|
|
3762
|
+
size: "default"
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3765
|
+
);
|
|
3766
|
+
var SidebarMenuButton = React16.forwardRef(({ asChild = false, isActive = false, variant = "default", size = "default", tooltip, className, ...props }, ref) => {
|
|
3767
|
+
const Comp = asChild ? import_react_slot.Slot : "button";
|
|
3768
|
+
const { isMobile, state } = useSidebar();
|
|
3769
|
+
const button = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3770
|
+
Comp,
|
|
3771
|
+
{
|
|
3772
|
+
ref,
|
|
3773
|
+
"data-sidebar": "menu-button",
|
|
3774
|
+
"data-size": size,
|
|
3775
|
+
"data-active": isActive,
|
|
3776
|
+
className: cn(sidebarMenuButtonVariants({ variant, size }), className),
|
|
3777
|
+
...props
|
|
3778
|
+
}
|
|
3779
|
+
);
|
|
3780
|
+
if (!tooltip) {
|
|
3781
|
+
return button;
|
|
3782
|
+
}
|
|
3783
|
+
if (typeof tooltip === "string") {
|
|
3784
|
+
tooltip = {
|
|
3785
|
+
children: tooltip
|
|
3786
|
+
};
|
|
3787
|
+
}
|
|
3788
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Tooltip, { children: [
|
|
3789
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TooltipTrigger, { asChild: true, children: button }),
|
|
3790
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3791
|
+
TooltipContent,
|
|
3792
|
+
{
|
|
3793
|
+
side: "right",
|
|
3794
|
+
align: "center",
|
|
3795
|
+
hidden: state !== "collapsed" || isMobile,
|
|
3796
|
+
...tooltip
|
|
3797
|
+
}
|
|
3798
|
+
)
|
|
3799
|
+
] });
|
|
3800
|
+
});
|
|
3801
|
+
SidebarMenuButton.displayName = "SidebarMenuButton";
|
|
3802
|
+
var SidebarMenuAction = React16.forwardRef(({ className, asChild = false, showOnHover = false, ...props }, ref) => {
|
|
3803
|
+
const Comp = asChild ? import_react_slot.Slot : "button";
|
|
3804
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3805
|
+
Comp,
|
|
3806
|
+
{
|
|
3807
|
+
ref,
|
|
3808
|
+
"data-sidebar": "menu-action",
|
|
3809
|
+
className: cn(
|
|
3810
|
+
"absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0",
|
|
3811
|
+
// Increases the hit area of the button on mobile.
|
|
3812
|
+
"after:absolute after:-inset-2 after:md:hidden",
|
|
3813
|
+
"peer-data-[size=sm]/menu-button:top-1",
|
|
3814
|
+
"peer-data-[size=default]/menu-button:top-1.5",
|
|
3815
|
+
"peer-data-[size=lg]/menu-button:top-2.5",
|
|
3816
|
+
"group-data-[collapsible=icon]:hidden",
|
|
3817
|
+
showOnHover && "group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0",
|
|
3818
|
+
className
|
|
3819
|
+
),
|
|
3820
|
+
...props
|
|
3821
|
+
}
|
|
3822
|
+
);
|
|
3823
|
+
});
|
|
3824
|
+
SidebarMenuAction.displayName = "SidebarMenuAction";
|
|
3825
|
+
var SidebarMenuBadge = React16.forwardRef(({ className, ...props }, ref) => {
|
|
3826
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3827
|
+
"div",
|
|
3828
|
+
{
|
|
3829
|
+
ref,
|
|
3830
|
+
"data-sidebar": "menu-badge",
|
|
3831
|
+
className: cn(
|
|
3832
|
+
"absolute right-1 flex h-5 min-w-5 items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums text-sidebar-foreground select-none pointer-events-none",
|
|
3833
|
+
"peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
|
|
3834
|
+
"peer-data-[size=sm]/menu-button:top-1",
|
|
3835
|
+
"peer-data-[size=default]/menu-button:top-1.5",
|
|
3836
|
+
"peer-data-[size=lg]/menu-button:top-2.5",
|
|
3837
|
+
"group-data-[collapsible=icon]:hidden",
|
|
3838
|
+
className
|
|
3839
|
+
),
|
|
3840
|
+
...props
|
|
3841
|
+
}
|
|
3842
|
+
);
|
|
3843
|
+
});
|
|
3844
|
+
SidebarMenuBadge.displayName = "SidebarMenuBadge";
|
|
3845
|
+
var SidebarMenuSkeleton = React16.forwardRef(({ className, showIcon = false, ...props }, ref) => {
|
|
3846
|
+
const width = React16.useMemo(() => {
|
|
3847
|
+
return `${Math.floor(Math.random() * 40) + 50}%`;
|
|
3848
|
+
}, []);
|
|
3849
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3850
|
+
"div",
|
|
3851
|
+
{
|
|
3852
|
+
ref,
|
|
3853
|
+
"data-sidebar": "menu-skeleton",
|
|
3854
|
+
className: cn("rounded-md h-8 flex gap-2 px-2 items-center", className),
|
|
3855
|
+
...props,
|
|
3856
|
+
children: [
|
|
3857
|
+
showIcon && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Skeleton, { className: "size-4 rounded-md", "data-sidebar": "menu-skeleton-icon" }),
|
|
3858
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3859
|
+
Skeleton,
|
|
3860
|
+
{
|
|
3861
|
+
className: "h-4 flex-1 max-w-[--skeleton-width]",
|
|
3862
|
+
"data-sidebar": "menu-skeleton-text",
|
|
3863
|
+
style: {
|
|
3864
|
+
"--skeleton-width": width
|
|
3865
|
+
}
|
|
3866
|
+
}
|
|
3867
|
+
)
|
|
3868
|
+
]
|
|
3869
|
+
}
|
|
3870
|
+
);
|
|
3871
|
+
});
|
|
3872
|
+
SidebarMenuSkeleton.displayName = "SidebarMenuSkeleton";
|
|
3873
|
+
var SidebarMenuSub = React16.forwardRef(({ className, ...props }, ref) => {
|
|
3874
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3875
|
+
"ul",
|
|
3876
|
+
{
|
|
3877
|
+
ref,
|
|
3878
|
+
"data-sidebar": "menu-sub",
|
|
3879
|
+
className: cn(
|
|
3880
|
+
"mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5",
|
|
3881
|
+
"group-data-[collapsible=icon]:hidden",
|
|
3882
|
+
className
|
|
3883
|
+
),
|
|
3884
|
+
...props
|
|
3885
|
+
}
|
|
3886
|
+
);
|
|
3887
|
+
});
|
|
3888
|
+
SidebarMenuSub.displayName = "SidebarMenuSub";
|
|
3889
|
+
var SidebarMenuSubItem = React16.forwardRef(({ ...props }, ref) => {
|
|
3890
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("li", { ref, ...props });
|
|
3891
|
+
});
|
|
3892
|
+
SidebarMenuSubItem.displayName = "SidebarMenuSubItem";
|
|
3893
|
+
var SidebarMenuSubButton = React16.forwardRef(({ asChild = false, size = "md", isActive, className, ...props }, ref) => {
|
|
3894
|
+
const Comp = asChild ? import_react_slot.Slot : "a";
|
|
3895
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3896
|
+
Comp,
|
|
3897
|
+
{
|
|
3898
|
+
ref,
|
|
3899
|
+
"data-sidebar": "menu-sub-button",
|
|
3900
|
+
"data-size": size,
|
|
3901
|
+
"data-active": isActive,
|
|
3902
|
+
className: cn(
|
|
3903
|
+
"flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-none ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-foreground/50",
|
|
3904
|
+
"data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
|
|
3905
|
+
size === "sm" && "text-xs",
|
|
3906
|
+
size === "md" && "text-sm",
|
|
3907
|
+
"group-data-[collapsible=icon]:hidden",
|
|
3908
|
+
className
|
|
3909
|
+
),
|
|
3910
|
+
...props
|
|
3911
|
+
}
|
|
3912
|
+
);
|
|
3913
|
+
});
|
|
3914
|
+
SidebarMenuSubButton.displayName = "SidebarMenuSubButton";
|
|
3915
|
+
|
|
3916
|
+
// src/components/ui/input.tsx
|
|
3917
|
+
var React17 = __toESM(require("react"), 1);
|
|
3918
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
3919
|
+
var Input = React17.forwardRef(
|
|
3920
|
+
({ className, type, ...props }, ref) => {
|
|
3921
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3922
|
+
"input",
|
|
3923
|
+
{
|
|
3924
|
+
type,
|
|
3925
|
+
className: cn(
|
|
3926
|
+
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
3927
|
+
className
|
|
3928
|
+
),
|
|
3929
|
+
ref,
|
|
3930
|
+
...props
|
|
3931
|
+
}
|
|
3932
|
+
);
|
|
3933
|
+
}
|
|
3934
|
+
);
|
|
3935
|
+
Input.displayName = "Input";
|
|
3936
|
+
|
|
3937
|
+
// src/components/ui/card.tsx
|
|
3938
|
+
var React18 = __toESM(require("react"), 1);
|
|
3939
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
3940
|
+
var Card = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3941
|
+
"div",
|
|
3942
|
+
{
|
|
3943
|
+
ref,
|
|
3944
|
+
className: cn(
|
|
3945
|
+
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
|
3946
|
+
className
|
|
3947
|
+
),
|
|
3948
|
+
...props
|
|
3949
|
+
}
|
|
3950
|
+
));
|
|
3951
|
+
Card.displayName = "Card";
|
|
3952
|
+
var CardHeader = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3953
|
+
"div",
|
|
3954
|
+
{
|
|
3955
|
+
ref,
|
|
3956
|
+
className: cn("flex flex-col space-y-1.5 p-6", className),
|
|
3957
|
+
...props
|
|
3958
|
+
}
|
|
3959
|
+
));
|
|
3960
|
+
CardHeader.displayName = "CardHeader";
|
|
3961
|
+
var CardTitle = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3962
|
+
"h3",
|
|
3963
|
+
{
|
|
3964
|
+
ref,
|
|
3965
|
+
className: cn(
|
|
3966
|
+
"text-2xl font-semibold leading-none tracking-tight",
|
|
3967
|
+
className
|
|
3968
|
+
),
|
|
3969
|
+
...props
|
|
3970
|
+
}
|
|
3971
|
+
));
|
|
3972
|
+
CardTitle.displayName = "CardTitle";
|
|
3973
|
+
var CardDescription = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3974
|
+
"p",
|
|
3975
|
+
{
|
|
3976
|
+
ref,
|
|
3977
|
+
className: cn("text-sm text-muted-foreground", className),
|
|
3978
|
+
...props
|
|
3979
|
+
}
|
|
3980
|
+
));
|
|
3981
|
+
CardDescription.displayName = "CardDescription";
|
|
3982
|
+
var CardContent = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { ref, className: cn("p-6 pt-0", className), ...props }));
|
|
3983
|
+
CardContent.displayName = "CardContent";
|
|
3984
|
+
var CardFooter = React18.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
3985
|
+
"div",
|
|
3986
|
+
{
|
|
3987
|
+
ref,
|
|
3988
|
+
className: cn("flex items-center p-6 pt-0", className),
|
|
3989
|
+
...props
|
|
3990
|
+
}
|
|
3991
|
+
));
|
|
3992
|
+
CardFooter.displayName = "CardFooter";
|
|
3993
|
+
|
|
3994
|
+
// src/components/ui/badge.tsx
|
|
3995
|
+
var import_class_variance_authority3 = require("class-variance-authority");
|
|
3996
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
3997
|
+
var badgeVariants = (0, import_class_variance_authority3.cva)(
|
|
3998
|
+
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
3999
|
+
{
|
|
4000
|
+
variants: {
|
|
4001
|
+
variant: {
|
|
4002
|
+
default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
|
4003
|
+
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
4004
|
+
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
4005
|
+
outline: "text-foreground"
|
|
4006
|
+
}
|
|
4007
|
+
},
|
|
4008
|
+
defaultVariants: {
|
|
4009
|
+
variant: "default"
|
|
4010
|
+
}
|
|
4011
|
+
}
|
|
4012
|
+
);
|
|
4013
|
+
function Badge({ className, variant, ...props }) {
|
|
4014
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
4015
|
+
}
|
|
4016
|
+
|
|
4017
|
+
// src/components/ui/dialog.tsx
|
|
4018
|
+
var React19 = __toESM(require("react"), 1);
|
|
4019
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
4020
|
+
var Dialog = React19.createContext({});
|
|
4021
|
+
var DialogRoot = ({ open, onOpenChange, children }) => {
|
|
4022
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Dialog.Provider, { value: { open, onOpenChange }, children });
|
|
4023
|
+
};
|
|
4024
|
+
var DialogTrigger = React19.forwardRef(({ className, children, ...props }, ref) => {
|
|
4025
|
+
const context = React19.useContext(Dialog);
|
|
4026
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
4027
|
+
"button",
|
|
4028
|
+
{
|
|
4029
|
+
ref,
|
|
4030
|
+
className: cn(className),
|
|
4031
|
+
onClick: () => context.onOpenChange?.(true),
|
|
4032
|
+
...props,
|
|
4033
|
+
children
|
|
4034
|
+
}
|
|
4035
|
+
);
|
|
4036
|
+
});
|
|
4037
|
+
DialogTrigger.displayName = "DialogTrigger";
|
|
4038
|
+
var DialogContent = React19.forwardRef(({ className, children, ...props }, ref) => {
|
|
4039
|
+
const context = React19.useContext(Dialog);
|
|
4040
|
+
if (!context.open) return null;
|
|
4041
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
4042
|
+
"div",
|
|
4043
|
+
{
|
|
4044
|
+
ref,
|
|
4045
|
+
className: cn(
|
|
4046
|
+
"relative z-50 grid w-full max-w-lg gap-4 border bg-background p-6 shadow-lg duration-200 sm:rounded-lg",
|
|
4047
|
+
className
|
|
4048
|
+
),
|
|
4049
|
+
...props,
|
|
4050
|
+
children: [
|
|
4051
|
+
children,
|
|
4052
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
4053
|
+
"button",
|
|
4054
|
+
{
|
|
4055
|
+
className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
4056
|
+
onClick: () => context.onOpenChange?.(false),
|
|
4057
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
4058
|
+
"svg",
|
|
4059
|
+
{
|
|
4060
|
+
width: "24",
|
|
4061
|
+
height: "24",
|
|
4062
|
+
viewBox: "0 0 24 24",
|
|
4063
|
+
fill: "none",
|
|
4064
|
+
stroke: "currentColor",
|
|
4065
|
+
strokeWidth: "2",
|
|
4066
|
+
strokeLinecap: "round",
|
|
4067
|
+
strokeLinejoin: "round",
|
|
4068
|
+
className: "h-4 w-4",
|
|
4069
|
+
children: [
|
|
4070
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("path", { d: "m18 6-12 12" }),
|
|
4071
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("path", { d: "m6 6 12 12" })
|
|
4072
|
+
]
|
|
4073
|
+
}
|
|
4074
|
+
)
|
|
4075
|
+
}
|
|
4076
|
+
)
|
|
4077
|
+
]
|
|
4078
|
+
}
|
|
4079
|
+
) });
|
|
4080
|
+
});
|
|
4081
|
+
DialogContent.displayName = "DialogContent";
|
|
4082
|
+
var DialogHeader = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
4083
|
+
"div",
|
|
4084
|
+
{
|
|
4085
|
+
ref,
|
|
4086
|
+
className: cn(
|
|
4087
|
+
"flex flex-col space-y-1.5 text-center sm:text-left",
|
|
4088
|
+
className
|
|
4089
|
+
),
|
|
4090
|
+
...props
|
|
4091
|
+
}
|
|
4092
|
+
));
|
|
4093
|
+
DialogHeader.displayName = "DialogHeader";
|
|
4094
|
+
var DialogTitle = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
4095
|
+
"h3",
|
|
4096
|
+
{
|
|
4097
|
+
ref,
|
|
4098
|
+
className: cn(
|
|
4099
|
+
"text-lg font-semibold leading-none tracking-tight",
|
|
4100
|
+
className
|
|
4101
|
+
),
|
|
4102
|
+
...props
|
|
4103
|
+
}
|
|
4104
|
+
));
|
|
4105
|
+
DialogTitle.displayName = "DialogTitle";
|
|
4106
|
+
|
|
4107
|
+
// src/components/ui/textarea.tsx
|
|
4108
|
+
var React20 = __toESM(require("react"), 1);
|
|
4109
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
4110
|
+
var Textarea = React20.forwardRef(
|
|
4111
|
+
({ className, ...props }, ref) => {
|
|
4112
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
4113
|
+
"textarea",
|
|
4114
|
+
{
|
|
4115
|
+
className: cn(
|
|
4116
|
+
"flex min-h-[80px] w-full rounded-md border-none bg-transparent px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0 disabled:cursor-not-allowed disabled:opacity-50 resize-none",
|
|
4117
|
+
className
|
|
4118
|
+
),
|
|
4119
|
+
ref,
|
|
4120
|
+
...props
|
|
4121
|
+
}
|
|
4122
|
+
);
|
|
4123
|
+
}
|
|
4124
|
+
);
|
|
4125
|
+
Textarea.displayName = "Textarea";
|
|
4126
|
+
|
|
4127
|
+
// src/components/ui/dropdown-menu.tsx
|
|
4128
|
+
var React21 = __toESM(require("react"), 1);
|
|
4129
|
+
var DropdownMenuPrimitive = __toESM(require("@radix-ui/react-dropdown-menu"), 1);
|
|
4130
|
+
var import_lucide_react11 = require("lucide-react");
|
|
4131
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
4132
|
+
var DropdownMenu = DropdownMenuPrimitive.Root;
|
|
4133
|
+
var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
4134
|
+
var DropdownMenuSubTrigger = React21.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
4135
|
+
DropdownMenuPrimitive.SubTrigger,
|
|
4136
|
+
{
|
|
4137
|
+
ref,
|
|
4138
|
+
className: cn(
|
|
4139
|
+
"flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
4140
|
+
inset && "pl-8",
|
|
4141
|
+
className
|
|
4142
|
+
),
|
|
4143
|
+
...props,
|
|
4144
|
+
children: [
|
|
4145
|
+
children,
|
|
4146
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.ChevronRight, { className: "ml-auto" })
|
|
4147
|
+
]
|
|
4148
|
+
}
|
|
4149
|
+
));
|
|
4150
|
+
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
|
4151
|
+
var DropdownMenuSubContent = React21.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
4152
|
+
DropdownMenuPrimitive.SubContent,
|
|
4153
|
+
{
|
|
4154
|
+
ref,
|
|
4155
|
+
className: cn(
|
|
4156
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
|
|
4157
|
+
className
|
|
4158
|
+
),
|
|
4159
|
+
...props
|
|
4160
|
+
}
|
|
4161
|
+
));
|
|
4162
|
+
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
|
4163
|
+
var DropdownMenuContent = React21.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
4164
|
+
DropdownMenuPrimitive.Content,
|
|
4165
|
+
{
|
|
4166
|
+
ref,
|
|
4167
|
+
sideOffset,
|
|
4168
|
+
className: cn(
|
|
4169
|
+
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
|
|
4170
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
|
|
4171
|
+
className
|
|
4172
|
+
),
|
|
4173
|
+
...props
|
|
4174
|
+
}
|
|
4175
|
+
) }));
|
|
4176
|
+
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
4177
|
+
var DropdownMenuItem = React21.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
4178
|
+
DropdownMenuPrimitive.Item,
|
|
4179
|
+
{
|
|
4180
|
+
ref,
|
|
4181
|
+
className: cn(
|
|
4182
|
+
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
|
|
4183
|
+
inset && "pl-8",
|
|
4184
|
+
className
|
|
4185
|
+
),
|
|
4186
|
+
...props
|
|
4187
|
+
}
|
|
4188
|
+
));
|
|
4189
|
+
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
4190
|
+
var DropdownMenuCheckboxItem = React21.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
4191
|
+
DropdownMenuPrimitive.CheckboxItem,
|
|
4192
|
+
{
|
|
4193
|
+
ref,
|
|
4194
|
+
className: cn(
|
|
4195
|
+
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
4196
|
+
className
|
|
4197
|
+
),
|
|
4198
|
+
checked,
|
|
4199
|
+
...props,
|
|
4200
|
+
children: [
|
|
4201
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.Check, { className: "h-4 w-4" }) }) }),
|
|
4202
|
+
children
|
|
4203
|
+
]
|
|
4204
|
+
}
|
|
4205
|
+
));
|
|
4206
|
+
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
|
4207
|
+
var DropdownMenuRadioItem = React21.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
4208
|
+
DropdownMenuPrimitive.RadioItem,
|
|
4209
|
+
{
|
|
4210
|
+
ref,
|
|
4211
|
+
className: cn(
|
|
4212
|
+
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
4213
|
+
className
|
|
4214
|
+
),
|
|
4215
|
+
...props,
|
|
4216
|
+
children: [
|
|
4217
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_lucide_react11.Circle, { className: "h-2 w-2 fill-current" }) }) }),
|
|
4218
|
+
children
|
|
4219
|
+
]
|
|
4220
|
+
}
|
|
4221
|
+
));
|
|
4222
|
+
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
|
4223
|
+
var DropdownMenuLabel = React21.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
4224
|
+
DropdownMenuPrimitive.Label,
|
|
4225
|
+
{
|
|
4226
|
+
ref,
|
|
4227
|
+
className: cn(
|
|
4228
|
+
"px-2 py-1.5 text-sm font-semibold",
|
|
4229
|
+
inset && "pl-8",
|
|
4230
|
+
className
|
|
4231
|
+
),
|
|
4232
|
+
...props
|
|
4233
|
+
}
|
|
4234
|
+
));
|
|
4235
|
+
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
|
4236
|
+
var DropdownMenuSeparator = React21.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
4237
|
+
DropdownMenuPrimitive.Separator,
|
|
4238
|
+
{
|
|
4239
|
+
ref,
|
|
4240
|
+
className: cn("-mx-1 my-1 h-px bg-muted", className),
|
|
4241
|
+
...props
|
|
4242
|
+
}
|
|
4243
|
+
));
|
|
4244
|
+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
|
4245
|
+
var DropdownMenuShortcut = ({
|
|
4246
|
+
className,
|
|
4247
|
+
...props
|
|
4248
|
+
}) => {
|
|
4249
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
4250
|
+
"span",
|
|
4251
|
+
{
|
|
4252
|
+
className: cn("ml-auto text-xs tracking-widest opacity-60", className),
|
|
4253
|
+
...props
|
|
4254
|
+
}
|
|
4255
|
+
);
|
|
4256
|
+
};
|
|
4257
|
+
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
|
4258
|
+
|
|
4259
|
+
// src/components/AppSidebar.tsx
|
|
4260
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
4261
|
+
var ThreadItem = ({
|
|
4262
|
+
thread,
|
|
4263
|
+
isActive,
|
|
4264
|
+
onClick,
|
|
4265
|
+
onDelete,
|
|
4266
|
+
onRename
|
|
4267
|
+
}) => {
|
|
4268
|
+
const [isEditing, setIsEditing] = (0, import_react17.useState)(false);
|
|
4269
|
+
const [editTitle, setEditTitle] = (0, import_react17.useState)(thread.title || "New Chat");
|
|
4270
|
+
const [showMenu, setShowMenu] = (0, import_react17.useState)(false);
|
|
4271
|
+
const handleRename = (0, import_react17.useCallback)(() => {
|
|
4272
|
+
if (editTitle.trim() && editTitle !== thread.title) {
|
|
4273
|
+
onRename(editTitle.trim());
|
|
4274
|
+
}
|
|
4275
|
+
setIsEditing(false);
|
|
4276
|
+
}, [editTitle, thread.title, onRename]);
|
|
4277
|
+
const handleKeyPress = (0, import_react17.useCallback)((e) => {
|
|
4278
|
+
if (e.key === "Enter") {
|
|
4279
|
+
handleRename();
|
|
4280
|
+
} else if (e.key === "Escape") {
|
|
4281
|
+
setEditTitle(thread.title || "New Chat");
|
|
4282
|
+
setIsEditing(false);
|
|
4283
|
+
}
|
|
4284
|
+
}, [handleRename, thread.title]);
|
|
4285
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(SidebarMenuItem, { className: "mb-3", children: [
|
|
4286
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarMenuButton, { asChild: true, isActive, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { onClick, children: isEditing ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
4287
|
+
Input,
|
|
4288
|
+
{
|
|
4289
|
+
value: editTitle,
|
|
4290
|
+
onChange: (e) => setEditTitle(e.target.value),
|
|
4291
|
+
onBlur: handleRename,
|
|
4292
|
+
onKeyPress: handleKeyPress,
|
|
4293
|
+
className: "flex-1 text-sm bg-transparent border-none outline-none",
|
|
4294
|
+
autoFocus: true,
|
|
4295
|
+
onClick: (e) => e.stopPropagation()
|
|
4296
|
+
}
|
|
4297
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "flex-1", children: [
|
|
4298
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-sm font-medium truncate leading-tight", children: thread.title || "New Chat" }),
|
|
4299
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-xs text-muted-foreground truncate leading-tight mt-0.5", children: thread.last_message || "No messages yet" })
|
|
4300
|
+
] }) }) }),
|
|
4301
|
+
!isEditing && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(DropdownMenu, { children: [
|
|
4302
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarMenuAction, { onClick: (e) => {
|
|
4303
|
+
e.stopPropagation();
|
|
4304
|
+
setShowMenu(!showMenu);
|
|
4305
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react12.MoreHorizontal, {}) }) }),
|
|
4306
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(DropdownMenuContent, { className: "w-[--radix-popper-anchor-width]", children: [
|
|
4307
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
4308
|
+
DropdownMenuItem,
|
|
4309
|
+
{
|
|
4310
|
+
onClick: (e) => {
|
|
4311
|
+
e.stopPropagation();
|
|
4312
|
+
setIsEditing(true);
|
|
4313
|
+
setShowMenu(false);
|
|
4314
|
+
},
|
|
4315
|
+
children: [
|
|
4316
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react12.Edit3, { className: "h-3 w-3" }),
|
|
4317
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { children: "Rename" })
|
|
4318
|
+
]
|
|
4319
|
+
}
|
|
4320
|
+
),
|
|
4321
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
4322
|
+
DropdownMenuItem,
|
|
4323
|
+
{
|
|
4324
|
+
onClick: (e) => {
|
|
4325
|
+
e.stopPropagation();
|
|
4326
|
+
onDelete();
|
|
4327
|
+
setShowMenu(false);
|
|
4328
|
+
},
|
|
4329
|
+
children: [
|
|
4330
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react12.Trash2, { className: "h-3 w-3" }),
|
|
4331
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { children: "Delete" })
|
|
4332
|
+
]
|
|
4333
|
+
}
|
|
4334
|
+
)
|
|
4335
|
+
] })
|
|
4336
|
+
] })
|
|
4337
|
+
] });
|
|
4338
|
+
};
|
|
4339
|
+
function AppSidebar({
|
|
4340
|
+
selectedThreadId,
|
|
4341
|
+
currentPage,
|
|
4342
|
+
onNewChat,
|
|
4343
|
+
onThreadSelect,
|
|
4344
|
+
onThreadDelete,
|
|
4345
|
+
onThreadRename,
|
|
4346
|
+
onLogoClick,
|
|
4347
|
+
onPageChange
|
|
4348
|
+
}) {
|
|
4349
|
+
const { threads, loading: threadsLoading, refetch } = useThreads();
|
|
4350
|
+
const { theme, setTheme } = useTheme();
|
|
4351
|
+
const { open } = useSidebar();
|
|
4352
|
+
const handleRefresh = (0, import_react17.useCallback)(() => {
|
|
4353
|
+
refetch();
|
|
4354
|
+
}, [refetch]);
|
|
4355
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(Sidebar, { collapsible: "icon", variant: "floating", children: [
|
|
4356
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarMenu, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(SidebarMenuItem, { children: [
|
|
4357
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
4358
|
+
SidebarMenuButton,
|
|
4359
|
+
{
|
|
4360
|
+
onClick: onLogoClick,
|
|
4361
|
+
children: [
|
|
4362
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react12.Bot, {}),
|
|
4363
|
+
"Distri"
|
|
4364
|
+
]
|
|
4365
|
+
}
|
|
4366
|
+
),
|
|
4367
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
4368
|
+
SidebarMenuAction,
|
|
4369
|
+
{
|
|
4370
|
+
onClick: () => setTheme(theme === "light" ? "dark" : "light"),
|
|
4371
|
+
title: "Toggle theme",
|
|
4372
|
+
className: "absolute right-0 top-0",
|
|
4373
|
+
children: [
|
|
4374
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("svg", { className: "h-4 w-4 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: [
|
|
4375
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("circle", { cx: "12", cy: "12", r: "5" }),
|
|
4376
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { d: "M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" })
|
|
4377
|
+
] }),
|
|
4378
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("svg", { className: "absolute h-4 w-4 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" }) })
|
|
4379
|
+
]
|
|
4380
|
+
}
|
|
4381
|
+
)
|
|
4382
|
+
] }) }) }),
|
|
4383
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarSeparator, {}),
|
|
4384
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(SidebarContent, { children: [
|
|
4385
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(SidebarGroup, { children: [
|
|
4386
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarGroupLabel, { children: "Actions" }),
|
|
4387
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarGroupContent, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(SidebarMenu, { children: [
|
|
4388
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarMenuItem, { className: "mb-1", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
4389
|
+
SidebarMenuButton,
|
|
4390
|
+
{
|
|
4391
|
+
isActive: currentPage === "chat",
|
|
4392
|
+
onClick: () => {
|
|
4393
|
+
onPageChange("chat");
|
|
4394
|
+
onNewChat();
|
|
4395
|
+
},
|
|
4396
|
+
children: [
|
|
4397
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react12.Edit2, { className: "h-4 w-4" }),
|
|
4398
|
+
"New Chat"
|
|
4399
|
+
]
|
|
4400
|
+
}
|
|
4401
|
+
) }),
|
|
4402
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarMenuItem, { className: "mb-1", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
4403
|
+
SidebarMenuButton,
|
|
4404
|
+
{
|
|
4405
|
+
isActive: currentPage === "agents",
|
|
4406
|
+
onClick: () => onPageChange("agents"),
|
|
4407
|
+
children: [
|
|
4408
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react12.Users, { className: "h-4 w-4" }),
|
|
4409
|
+
"Agents"
|
|
4410
|
+
]
|
|
4411
|
+
}
|
|
4412
|
+
) })
|
|
4413
|
+
] }) })
|
|
4414
|
+
] }),
|
|
4415
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(SidebarGroup, { children: [
|
|
4416
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarGroupLabel, { children: "Conversations" }),
|
|
4417
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarGroupContent, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarMenu, { children: threadsLoading ? /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(SidebarMenuItem, { children: [
|
|
4418
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react12.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
4419
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { children: "Loading threads..." })
|
|
4420
|
+
] }) : threads.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarMenuItem, { children: "No conversations yet" }) : threads.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
4421
|
+
ThreadItem,
|
|
4422
|
+
{
|
|
4423
|
+
thread,
|
|
4424
|
+
isActive: thread.id === selectedThreadId,
|
|
4425
|
+
onClick: () => onThreadSelect(thread.id),
|
|
4426
|
+
onDelete: () => onThreadDelete(thread.id),
|
|
4427
|
+
onRename: (newTitle) => onThreadRename(thread.id, newTitle)
|
|
4428
|
+
},
|
|
4429
|
+
thread.id
|
|
4430
|
+
)) }) }),
|
|
4431
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
4432
|
+
SidebarGroupAction,
|
|
4433
|
+
{
|
|
4434
|
+
onClick: handleRefresh,
|
|
4435
|
+
disabled: threadsLoading,
|
|
4436
|
+
title: "Refresh conversations",
|
|
4437
|
+
children: [
|
|
4438
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react12.RefreshCw, { className: `${threadsLoading ? "animate-spin" : ""}` }),
|
|
4439
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "sr-only", children: "Refresh conversations" })
|
|
4440
|
+
]
|
|
4441
|
+
}
|
|
4442
|
+
)
|
|
4443
|
+
] })
|
|
4444
|
+
] }),
|
|
4445
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarFooter, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarMenu, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarMenuItem, { children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
4446
|
+
SidebarMenuButton,
|
|
4447
|
+
{
|
|
4448
|
+
onClick: () => window.open("https://github.com/your-repo/distri", "_blank"),
|
|
4449
|
+
title: "GitHub",
|
|
4450
|
+
children: [
|
|
4451
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react12.Github, {}),
|
|
4452
|
+
"Distri"
|
|
4453
|
+
]
|
|
4454
|
+
}
|
|
4455
|
+
) }) }) })
|
|
4456
|
+
] });
|
|
4457
|
+
}
|
|
4458
|
+
|
|
4459
|
+
// src/components/FullChat.tsx
|
|
4460
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
4461
|
+
var FullChat = ({
|
|
4462
|
+
agentId: initialAgentId,
|
|
4463
|
+
metadata,
|
|
4464
|
+
className = "",
|
|
4465
|
+
UserMessageComponent,
|
|
4466
|
+
AssistantMessageComponent,
|
|
4467
|
+
AssistantWithToolCallsComponent,
|
|
4468
|
+
PlanMessageComponent,
|
|
4469
|
+
showDebug = false,
|
|
4470
|
+
onThreadSelect,
|
|
4471
|
+
onThreadCreate,
|
|
4472
|
+
onThreadDelete,
|
|
4473
|
+
onLogoClick,
|
|
4474
|
+
availableAgents,
|
|
4475
|
+
onAgentSelect
|
|
4476
|
+
}) => {
|
|
4477
|
+
const [selectedThreadId, setSelectedThreadId] = (0, import_react18.useState)(uuidv4());
|
|
4478
|
+
const [currentAgentId, setCurrentAgentId] = (0, import_react18.useState)(initialAgentId);
|
|
4479
|
+
const { threads, refetch: refetchThreads } = useThreads();
|
|
4480
|
+
const [currentPage, setCurrentPage] = (0, import_react18.useState)("chat");
|
|
4481
|
+
const [defaultOpen, setDefaultOpen] = (0, import_react18.useState)(true);
|
|
4482
|
+
const { agent, loading: agentLoading, error: agentError } = useAgent({ agentId: currentAgentId });
|
|
4483
|
+
const { theme } = useTheme();
|
|
4484
|
+
const currentThread = threads.find((t) => t.id === selectedThreadId);
|
|
4485
|
+
const { messages } = useChat({
|
|
4486
|
+
threadId: selectedThreadId,
|
|
4487
|
+
agent: agent || void 0
|
|
4488
|
+
});
|
|
4489
|
+
const threadHasStarted = messages.length > 0;
|
|
4490
|
+
(0, import_react18.useEffect)(() => {
|
|
4491
|
+
const savedState = localStorage.getItem("sidebar:state");
|
|
4492
|
+
if (savedState !== null) {
|
|
4493
|
+
setDefaultOpen(savedState === "true");
|
|
4494
|
+
}
|
|
4495
|
+
}, []);
|
|
4496
|
+
(0, import_react18.useEffect)(() => {
|
|
4497
|
+
if (currentThread?.agent_id && currentThread.agent_id !== currentAgentId) {
|
|
4498
|
+
setCurrentAgentId(currentThread.agent_id);
|
|
4499
|
+
onAgentSelect?.(currentThread.agent_id);
|
|
4500
|
+
}
|
|
4501
|
+
}, [currentThread?.agent_id, currentAgentId, onAgentSelect]);
|
|
4502
|
+
const handleNewChat = (0, import_react18.useCallback)(() => {
|
|
4503
|
+
const newThreadId = `thread-${Date.now()}`;
|
|
4504
|
+
setSelectedThreadId(newThreadId);
|
|
4505
|
+
onThreadCreate?.(newThreadId);
|
|
4506
|
+
}, [onThreadCreate]);
|
|
4507
|
+
const handleThreadSelect = (0, import_react18.useCallback)((threadId) => {
|
|
4508
|
+
setCurrentPage("chat");
|
|
4509
|
+
setSelectedThreadId(threadId);
|
|
4510
|
+
onThreadSelect?.(threadId);
|
|
4511
|
+
}, [onThreadSelect]);
|
|
4512
|
+
const handleThreadDelete = (0, import_react18.useCallback)((threadId) => {
|
|
4513
|
+
if (threadId === selectedThreadId) {
|
|
4514
|
+
const remainingThreads = threads.filter((t) => t.id !== threadId);
|
|
4515
|
+
if (remainingThreads.length > 0) {
|
|
4516
|
+
setSelectedThreadId(remainingThreads[0].id);
|
|
4517
|
+
} else {
|
|
4518
|
+
handleNewChat();
|
|
4519
|
+
}
|
|
4520
|
+
}
|
|
4521
|
+
onThreadDelete?.(threadId);
|
|
4522
|
+
refetchThreads();
|
|
4523
|
+
}, [selectedThreadId, threads, handleNewChat, onThreadDelete, refetchThreads]);
|
|
4524
|
+
const handleAgentSelect = (0, import_react18.useCallback)((newAgentId) => {
|
|
4525
|
+
if (!threadHasStarted) {
|
|
4526
|
+
setCurrentAgentId(newAgentId);
|
|
4527
|
+
onAgentSelect?.(newAgentId);
|
|
4528
|
+
}
|
|
4529
|
+
}, [threadHasStarted, onAgentSelect]);
|
|
4530
|
+
const handleMessagesUpdate = (0, import_react18.useCallback)(() => {
|
|
4531
|
+
refetchThreads();
|
|
4532
|
+
}, [refetchThreads]);
|
|
4533
|
+
const renderMainContent = () => {
|
|
4534
|
+
if (currentPage === "agents") {
|
|
4535
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(AgentsPage_default, { onStartChat: (agent2) => {
|
|
4536
|
+
setCurrentPage("chat");
|
|
4537
|
+
handleAgentSelect(agent2.id);
|
|
4538
|
+
} });
|
|
4539
|
+
}
|
|
4540
|
+
if (!agent) {
|
|
4541
|
+
if (agentLoading) return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { children: "Loading agent..." });
|
|
4542
|
+
if (agentError) return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
|
|
4543
|
+
"Error loading agent: ",
|
|
4544
|
+
agentError.message
|
|
4545
|
+
] });
|
|
4546
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { children: "No agent selected" });
|
|
4547
|
+
}
|
|
4548
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
4549
|
+
EmbeddableChat,
|
|
4550
|
+
{
|
|
4551
|
+
threadId: selectedThreadId,
|
|
4552
|
+
showAgentSelector: false,
|
|
4553
|
+
agent,
|
|
4554
|
+
metadata,
|
|
4555
|
+
height: "calc(100vh - 4rem)",
|
|
4556
|
+
availableAgents,
|
|
4557
|
+
UserMessageComponent,
|
|
4558
|
+
AssistantMessageComponent,
|
|
4559
|
+
AssistantWithToolCallsComponent,
|
|
4560
|
+
PlanMessageComponent,
|
|
4561
|
+
theme,
|
|
4562
|
+
showDebug,
|
|
4563
|
+
placeholder: "Type your message...",
|
|
4564
|
+
disableAgentSelection: threadHasStarted,
|
|
4565
|
+
onAgentSelect: handleAgentSelect,
|
|
4566
|
+
onMessagesUpdate: handleMessagesUpdate
|
|
4567
|
+
}
|
|
4568
|
+
);
|
|
4569
|
+
};
|
|
4570
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: `distri-chat ${className} h-full`, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
4571
|
+
SidebarProvider,
|
|
4572
|
+
{
|
|
4573
|
+
defaultOpen,
|
|
4574
|
+
style: {
|
|
4575
|
+
"--sidebar-width": "20rem",
|
|
4576
|
+
"--sidebar-width-mobile": "18rem"
|
|
4577
|
+
},
|
|
4578
|
+
children: [
|
|
4579
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
4580
|
+
AppSidebar,
|
|
4581
|
+
{
|
|
4582
|
+
selectedThreadId,
|
|
4583
|
+
currentPage,
|
|
4584
|
+
onNewChat: handleNewChat,
|
|
4585
|
+
onThreadSelect: handleThreadSelect,
|
|
4586
|
+
onThreadDelete: handleThreadDelete,
|
|
4587
|
+
onThreadRename: (threadId, newTitle) => {
|
|
4588
|
+
console.log("Rename thread", threadId, "to", newTitle);
|
|
4589
|
+
refetchThreads();
|
|
4590
|
+
},
|
|
4591
|
+
onLogoClick,
|
|
4592
|
+
onPageChange: setCurrentPage
|
|
4593
|
+
}
|
|
4594
|
+
),
|
|
4595
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(SidebarInset, { children: [
|
|
4596
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("header", { className: "flex h-16 shrink-0 items-center gap-2 px-4 border-b", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "flex items-center gap-2 flex-1", children: [
|
|
4597
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(SidebarTrigger, { className: "-ml-1" }),
|
|
4598
|
+
availableAgents && availableAgents.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "w-64", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
4599
|
+
AgentSelect,
|
|
4600
|
+
{
|
|
4601
|
+
agents: availableAgents,
|
|
4602
|
+
selectedAgentId: currentAgentId,
|
|
4603
|
+
onAgentSelect: handleAgentSelect,
|
|
4604
|
+
placeholder: "Select an agent...",
|
|
4605
|
+
disabled: threadHasStarted
|
|
4606
|
+
}
|
|
4607
|
+
) })
|
|
4608
|
+
] }) }),
|
|
4609
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("main", { className: "flex-1 overflow-hidden", children: renderMainContent() })
|
|
4610
|
+
] })
|
|
4611
|
+
]
|
|
4612
|
+
}
|
|
4613
|
+
) });
|
|
4614
|
+
};
|
|
4615
|
+
var FullChat_default = FullChat;
|
|
4616
|
+
|
|
4617
|
+
// src/components/ThemeToggle.tsx
|
|
4618
|
+
var import_react19 = __toESM(require("react"), 1);
|
|
4619
|
+
var import_lucide_react13 = require("lucide-react");
|
|
4620
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
4621
|
+
function ThemeToggle() {
|
|
4622
|
+
const { theme, setTheme } = useTheme();
|
|
4623
|
+
const dropdownRef = import_react19.default.useRef(null);
|
|
4624
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "relative", ref: dropdownRef, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
4625
|
+
"button",
|
|
4626
|
+
{
|
|
4627
|
+
onClick: () => setTheme(theme === "light" ? "dark" : "light"),
|
|
4628
|
+
className: "flex items-center justify-center w-9 h-9 rounded-md border bg-background hover:bg-sidebar-accent hover:text-sidebar-accent-foreground transition-colors",
|
|
4629
|
+
children: [
|
|
4630
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react13.Sun, { className: "h-[1.2rem] w-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" }),
|
|
4631
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_lucide_react13.Moon, { className: "absolute h-[1.2rem] w-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" }),
|
|
4632
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { className: "sr-only", children: "Toggle theme" })
|
|
4633
|
+
]
|
|
4634
|
+
}
|
|
4635
|
+
) });
|
|
4636
|
+
}
|
|
4637
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
4638
|
+
0 && (module.exports = {
|
|
4639
|
+
AgentSelect,
|
|
4640
|
+
ApprovalToolCall,
|
|
4641
|
+
AssistantMessage,
|
|
4642
|
+
AssistantWithToolCalls,
|
|
4643
|
+
Badge,
|
|
4644
|
+
Button,
|
|
4645
|
+
Card,
|
|
4646
|
+
CardContent,
|
|
4647
|
+
CardDescription,
|
|
4648
|
+
CardFooter,
|
|
4649
|
+
CardHeader,
|
|
4650
|
+
CardTitle,
|
|
4651
|
+
ChatInput,
|
|
4652
|
+
DebugMessage,
|
|
4653
|
+
Dialog,
|
|
4654
|
+
DialogContent,
|
|
4655
|
+
DialogHeader,
|
|
4656
|
+
DialogTitle,
|
|
4657
|
+
DialogTrigger,
|
|
4658
|
+
DistriProvider,
|
|
4659
|
+
EmbeddableChat,
|
|
4660
|
+
FullChat,
|
|
4661
|
+
Input,
|
|
4662
|
+
PlanMessage,
|
|
4663
|
+
Select,
|
|
4664
|
+
SelectContent,
|
|
4665
|
+
SelectGroup,
|
|
4666
|
+
SelectItem,
|
|
4667
|
+
SelectLabel,
|
|
4668
|
+
SelectScrollDownButton,
|
|
4669
|
+
SelectScrollUpButton,
|
|
4670
|
+
SelectSeparator,
|
|
4671
|
+
SelectTrigger,
|
|
4672
|
+
SelectValue,
|
|
4673
|
+
Separator,
|
|
4674
|
+
Sheet,
|
|
4675
|
+
SheetContent,
|
|
4676
|
+
SheetDescription,
|
|
4677
|
+
SheetFooter,
|
|
4678
|
+
SheetHeader,
|
|
4679
|
+
SheetTitle,
|
|
4680
|
+
Sidebar,
|
|
4681
|
+
SidebarContent,
|
|
4682
|
+
SidebarFooter,
|
|
4683
|
+
SidebarGroup,
|
|
4684
|
+
SidebarGroupAction,
|
|
4685
|
+
SidebarGroupContent,
|
|
4686
|
+
SidebarGroupLabel,
|
|
4687
|
+
SidebarHeader,
|
|
4688
|
+
SidebarInset,
|
|
4689
|
+
SidebarMenu,
|
|
4690
|
+
SidebarMenuAction,
|
|
4691
|
+
SidebarMenuBadge,
|
|
4692
|
+
SidebarMenuButton,
|
|
4693
|
+
SidebarMenuItem,
|
|
4694
|
+
SidebarMenuSkeleton,
|
|
4695
|
+
SidebarMenuSub,
|
|
4696
|
+
SidebarMenuSubButton,
|
|
4697
|
+
SidebarMenuSubItem,
|
|
4698
|
+
SidebarProvider,
|
|
4699
|
+
SidebarRail,
|
|
4700
|
+
SidebarSeparator,
|
|
4701
|
+
SidebarTrigger,
|
|
4702
|
+
Skeleton,
|
|
4703
|
+
Textarea,
|
|
4704
|
+
ThemeProvider,
|
|
4705
|
+
ThemeToggle,
|
|
4706
|
+
ToastToolCall,
|
|
4707
|
+
Tooltip,
|
|
4708
|
+
TooltipContent,
|
|
4709
|
+
TooltipProvider,
|
|
4710
|
+
TooltipTrigger,
|
|
4711
|
+
UserMessage,
|
|
4712
|
+
cn,
|
|
4713
|
+
extractTextFromMessage,
|
|
4714
|
+
registerTools,
|
|
4715
|
+
shouldDisplayMessage,
|
|
4716
|
+
useAgent,
|
|
4717
|
+
useAgents,
|
|
4718
|
+
useChat,
|
|
4719
|
+
useDistri,
|
|
4720
|
+
useSidebar,
|
|
4721
|
+
useTheme,
|
|
4722
|
+
useThreads,
|
|
4723
|
+
useToolCallState
|
|
4724
|
+
});
|