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