@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/dist/index.js CHANGED
@@ -1,39 +1,1008 @@
1
- "use strict";
1
+ "use client";
2
2
  var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
23
- DistriProvider: () => DistriProvider,
24
- useAgents: () => useAgents,
25
- useChat: () => useChat,
26
- useDistri: () => useDistri,
27
- useDistriClient: () => useDistriClient,
28
- useThreads: () => useThreads
29
- });
30
- module.exports = __toCommonJS(src_exports);
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
- var import_react = require("react");
34
- var import_core = require("@distri/core");
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] = (0, import_react.useState)(null);
48
- const [error, setError] = (0, import_react.useState)(null);
49
- const [isLoading, setIsLoading] = (0, import_react.useState)(true);
50
- (0, import_react.useEffect)(() => {
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 import_core.DistriClient(config);
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.baseUrl, config.apiVersion, config.debug]);
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__ */ (0, import_jsx_runtime.jsx)(DistriContext.Provider, { value: contextValue, children });
1050
+ return /* @__PURE__ */ jsx2(ThemeProvider, { defaultTheme, children: /* @__PURE__ */ jsx2(DistriContext.Provider, { value: contextValue, children }) });
82
1051
  }
83
1052
  function useDistri() {
84
- const context = (0, import_react.useContext)(DistriContext);
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
- function useDistriClient() {
91
- const { client, error, isLoading } = useDistri();
92
- if (isLoading) {
93
- throw new Error("Distri client is still loading");
94
- }
95
- if (error) {
96
- throw new Error(`Distri client initialization failed: ${error.message}`);
97
- }
98
- if (!client) {
99
- throw new Error("Distri client is not initialized");
100
- }
101
- return client;
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
- var import_react2 = require("react");
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] = (0, import_react2.useState)([]);
109
- const [loading, setLoading] = (0, import_react2.useState)(true);
110
- const [error, setError] = (0, import_react2.useState)(null);
111
- const fetchAgents = (0, import_react2.useCallback)(async () => {
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 = (0, import_react2.useCallback)(async (agentId) => {
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
- (0, import_react2.useEffect)(() => {
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
- var import_react3 = require("react");
175
- var import_core2 = require("@distri/core");
176
- function useChat({ agentId, contextId }) {
177
- const { client, error: clientError, isLoading: clientLoading } = useDistri();
178
- const [loading, setLoading] = (0, import_react3.useState)(false);
179
- const [error, setError] = (0, import_react3.useState)(null);
180
- const [messages, setMessages] = (0, import_react3.useState)([]);
181
- const [isStreaming, setIsStreaming] = (0, import_react3.useState)(false);
182
- const abortControllerRef = (0, import_react3.useRef)(null);
183
- const fetchMessages = (0, import_react3.useCallback)(async () => {
184
- if (!client || !contextId) {
185
- setMessages([]);
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
- try {
189
- setLoading(true);
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
- }, [client, contextId]);
201
- (0, import_react3.useEffect)(() => {
202
- if (!clientLoading && !clientError && contextId) {
203
- fetchMessages();
204
- } else {
205
- setMessages([]);
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
- }, [clientLoading, clientError, contextId, fetchMessages]);
208
- const sendMessage = (0, import_react3.useCallback)(async (input) => {
209
- if (!client) {
210
- setError(new Error("Client not available"));
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
- try {
214
- setLoading(true);
215
- setError(null);
216
- let params;
217
- if (typeof input === "string") {
218
- let userMessage = import_core2.DistriClient.initMessage(input, "user", contextId);
219
- params = import_core2.DistriClient.initMessageParams(userMessage);
220
- } else {
221
- params = input;
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
- } catch (err) {
250
- console.error(err);
251
- setError(err instanceof Error ? err : new Error("Failed to send message"));
252
- } finally {
253
- setLoading(false);
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
- }, [client, agentId]);
256
- const sendMessageStream = (0, import_react3.useCallback)(async (input) => {
257
- if (!client) {
258
- setError(new Error("Client not available"));
259
- return;
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
- try {
262
- setLoading(true);
263
- setError(null);
264
- setIsStreaming(true);
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
- abortControllerRef.current = new AbortController();
269
- let params;
270
- if (typeof input === "string") {
271
- let userMessage = import_core2.DistriClient.initMessage(input, "user", contextId);
272
- params = import_core2.DistriClient.initMessageParams(userMessage);
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
- params = input;
1609
+ return [...prev, event];
275
1610
  }
276
- setMessages((prev) => [...prev, params.message]);
277
- setIsStreaming(true);
278
- const stream = await client.sendMessageStream(agentId, params);
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
- let message = void 0;
285
- if (event.kind === "message") {
286
- message = event;
287
- }
288
- if (!message)
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
- console.log("error", err);
312
- setError(err instanceof Error ? err : new Error("Failed to stream message"));
1706
+ const error2 = err instanceof Error ? err : new Error("Failed to send message");
1707
+ setError(error2);
1708
+ onError?.(error2);
313
1709
  } finally {
314
- setLoading(false);
1710
+ setIsLoading(false);
315
1711
  setIsStreaming(false);
1712
+ abortControllerRef.current = null;
316
1713
  }
317
- }, [client, agentId]);
318
- const clearMessages = (0, import_react3.useCallback)(() => {
319
- setMessages([]);
320
- }, []);
321
- (0, import_react3.useEffect)(() => {
322
- return () => {
323
- if (abortControllerRef.current) {
324
- abortControllerRef.current.abort();
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 abort = (0, import_react3.useCallback)(() => {
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
- refreshMessages: fetchMessages,
342
- abort
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
- var import_react4 = require("react");
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] = (0, import_react4.useState)([]);
351
- const [loading, setLoading] = (0, import_react4.useState)(true);
352
- const [error, setError] = (0, import_react4.useState)(null);
353
- const fetchThreads = (0, import_react4.useCallback)(async () => {
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 = (0, import_react4.useCallback)(async (threadId) => {
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 = (0, import_react4.useCallback)(async (threadId) => {
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 = (0, import_react4.useCallback)(async (threadId, localId) => {
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
- (0, import_react4.useEffect)(() => {
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
- // Annotate the CommonJS export names for ESM import in node:
456
- 0 && (module.exports = {
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
- useDistriClient,
462
- useThreads
463
- });
464
- //# sourceMappingURL=index.js.map
4601
+ useSidebar,
4602
+ useTheme,
4603
+ useThreads,
4604
+ useToolCallState
4605
+ };