@m6d/cortex-react 1.0.0 → 1.0.1

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.
Files changed (2) hide show
  1. package/dist/index.js +3659 -0
  2. package/package.json +4 -3
package/dist/index.js CHANGED
@@ -1,3 +1,3662 @@
1
+ // src/components/CortexChatWidget.tsx
2
+ import { useCallback, useEffect as useEffect6, useMemo as useMemo3, useRef as useRef8, useState as useState9, useSyncExternalStore } from "react";
3
+
4
+ // ../../internal/client/src/api-client.ts
5
+ function resolveTransportHeaders(transport) {
6
+ return Promise.resolve(transport.getHeaders());
7
+ }
8
+ function resolveTransportUrl(transport, path) {
9
+ const baseUrl = transport.baseUrl;
10
+ const base = typeof baseUrl === "string" ? baseUrl : baseUrl();
11
+ return base.replace(/\/$/, "") + path;
12
+ }
13
+ function filenameFrom(disposition) {
14
+ const encoded = disposition?.match(/filename\*\s*=\s*[^']*'[^']*'([^;\r\n]+)/i)?.[1]?.trim().replace(/^"|"$/g, "");
15
+ if (encoded) {
16
+ try {
17
+ return decodeURIComponent(encoded);
18
+ } catch {}
19
+ }
20
+ return disposition?.match(/filename\s*=\s*"?([^";\r\n]+)"?/i)?.[1];
21
+ }
22
+ function createCortexApiClient(getTransport) {
23
+ function resolveHeaders() {
24
+ return resolveTransportHeaders(getTransport());
25
+ }
26
+ function resolveUrl(path) {
27
+ return resolveTransportUrl(getTransport(), path);
28
+ }
29
+ async function send(path, init) {
30
+ const headers = new Headers(await resolveHeaders());
31
+ new Headers(init?.headers).forEach(function(value, name) {
32
+ headers.set(name, value);
33
+ });
34
+ if (init?.body instanceof FormData) {
35
+ headers.delete("Content-Type");
36
+ } else if (!headers.has("Content-Type")) {
37
+ headers.set("Content-Type", "application/json");
38
+ }
39
+ const response = await fetch(resolveUrl(path), {
40
+ ...init,
41
+ headers
42
+ });
43
+ if (!response.ok) {
44
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
45
+ }
46
+ const text = await response.text();
47
+ return text ? JSON.parse(text) : undefined;
48
+ }
49
+ return {
50
+ listThreads() {
51
+ return send("/threads");
52
+ },
53
+ createThread(prompt) {
54
+ return send("/threads", {
55
+ method: "POST",
56
+ body: JSON.stringify({ prompt })
57
+ });
58
+ },
59
+ deleteThread(threadId) {
60
+ return send(`/threads/${threadId}`, { method: "DELETE" });
61
+ },
62
+ listMessages(threadId) {
63
+ return send(`/threads/${threadId}/messages`);
64
+ },
65
+ listLlmRequests(messageId) {
66
+ return send(`/messages/${messageId}/llm-requests`);
67
+ },
68
+ abortStream(threadId) {
69
+ return send(`/chat/${threadId}/abort`, { method: "POST" });
70
+ },
71
+ async uploadAttachment(threadId, file) {
72
+ const body = new FormData;
73
+ body.append("file", file);
74
+ return await send(`/threads/${threadId}/files`, {
75
+ method: "POST",
76
+ body
77
+ });
78
+ },
79
+ deleteAttachment(id) {
80
+ return send(`/files/${id}`, { method: "DELETE" });
81
+ },
82
+ async downloadAttachment(id) {
83
+ const response = await fetch(resolveUrl(`/files/${id}`), {
84
+ headers: await resolveHeaders()
85
+ });
86
+ if (!response.ok) {
87
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
88
+ }
89
+ return {
90
+ blob: await response.blob(),
91
+ name: filenameFrom(response.headers.get("Content-Disposition")) ?? id
92
+ };
93
+ },
94
+ resolveHeaders,
95
+ resolveUrl
96
+ };
97
+ }
98
+ // ../../internal/client/src/utils/pending-tool-calls.ts
99
+ var SETTLED_STATES = new Set(["complete", "error"]);
100
+ function isSettledToolState(state) {
101
+ return SETTLED_STATES.has(state);
102
+ }
103
+ function unansweredToolCalls(messages) {
104
+ const parts = newestAssistantMessage(messages)?.parts ?? [];
105
+ return parts.filter((part) => part.type === "tool-call" && !isSettledToolState(part.state));
106
+ }
107
+ function newestAssistantMessage(messages) {
108
+ for (let index = messages.length - 1;index >= 0; index -= 1) {
109
+ const message = messages[index];
110
+ if (message?.role === "assistant")
111
+ return message;
112
+ }
113
+ return;
114
+ }
115
+
116
+ // ../../internal/client/src/tool-call-view.ts
117
+ var STATE_MODIFIERS = {
118
+ complete: "success",
119
+ error: "error",
120
+ "approval-requested": "approval",
121
+ "approval-responded": "approval",
122
+ "awaiting-input": "pending",
123
+ "input-streaming": "pending",
124
+ "input-complete": "pending"
125
+ };
126
+ var BADGE_LABEL_KEYS = {
127
+ "awaiting-input": "translate_calling",
128
+ "input-streaming": "translate_calling",
129
+ "input-complete": "translate_input_ready",
130
+ "approval-requested": "translate_needs_approval",
131
+ "approval-responded": "translate_responded",
132
+ complete: "translate_completed",
133
+ error: "translate_error"
134
+ };
135
+ function toolCallBadge(part) {
136
+ const { state, approval } = part;
137
+ return {
138
+ modifier: STATE_MODIFIERS[state],
139
+ labelKey: state === "approval-responded" && approval?.approved ? "translate_approved" : BADGE_LABEL_KEYS[state],
140
+ pulse: state === "awaiting-input" || state === "input-streaming" ? "default" : state === "approval-requested" ? "violet" : undefined
141
+ };
142
+ }
143
+ function toolCallOutputText(part) {
144
+ const output = part.output;
145
+ if (output === undefined || output === null)
146
+ return "";
147
+ if (typeof output === "string")
148
+ return output;
149
+ return JSON.stringify(output, null, 2);
150
+ }
151
+ var CODE_FIELDS = {
152
+ code: "javascript",
153
+ query: "cypher"
154
+ };
155
+ function splitToolCallInput(input) {
156
+ const record = input && typeof input === "object" ? input : null;
157
+ const codeSnippets = record ? Object.entries(CODE_FIELDS).flatMap(([key, lang]) => {
158
+ const value = record[key];
159
+ return typeof value === "string" ? [{ key, lang, value: value.replace(/\\n/g, `
160
+ `) }] : [];
161
+ }) : [];
162
+ let remainingInput = input;
163
+ if (record) {
164
+ const rest = Object.fromEntries(Object.entries(record).filter(([key]) => !Object.hasOwn(CODE_FIELDS, key)));
165
+ remainingInput = Object.keys(rest).length > 0 ? rest : null;
166
+ }
167
+ return {
168
+ codeSnippets,
169
+ remainingInput,
170
+ remainingInputText: remainingInput ? JSON.stringify(remainingInput, null, 2) : ""
171
+ };
172
+ }
173
+ var STATUS_COUNT = 10;
174
+ var ANIM_STATES = {
175
+ "awaiting-input": "starting",
176
+ "input-streaming": "starting",
177
+ "input-complete": "processing",
178
+ "approval-requested": "processing",
179
+ "approval-responded": "processing",
180
+ complete: "complete",
181
+ error: "error"
182
+ };
183
+ function stableIndex(id) {
184
+ let hash = 0;
185
+ for (let i = 0;i < id.length; i++) {
186
+ hash = hash * 31 + id.charCodeAt(i) | 0;
187
+ }
188
+ return Math.abs(hash) % STATUS_COUNT;
189
+ }
190
+ function toolCallAnimation(part) {
191
+ const state = ANIM_STATES[part.state] ?? "processing";
192
+ const family = part.name === "readAttachment" ? "attachment" : "tool";
193
+ const variant = family === "tool" ? `_${stableIndex(part.id)}` : "";
194
+ return {
195
+ state,
196
+ active: state === "starting" || state === "processing",
197
+ titleKey: state === "error" ? "translate_tool_error" : `translate_${family}_${state === "complete" ? "done" : "status"}${variant}`
198
+ };
199
+ }
200
+ function activityLabelKeys(activity) {
201
+ return Array.from({ length: STATUS_COUNT }, (_, index) => `translate_${activity}_${index}`);
202
+ }
203
+ var SELF_DESCRIBING_TOOLS = ["queryGraph", "executeCode"];
204
+ function isHiddenInAnimatedMode(part, isLast, isStreaming) {
205
+ if (part.type === "thinking")
206
+ return !(isStreaming && isLast);
207
+ if (part.type !== "tool-call")
208
+ return false;
209
+ return SELF_DESCRIBING_TOOLS.includes(part.name) && isSettledToolState(part.state);
210
+ }
211
+ // ../../internal/client/src/chat-connection.ts
212
+ import { EventType } from "@tanstack/ai";
213
+ import { fetchServerSentEvents } from "@tanstack/ai-client";
214
+ function toUiMessage(message) {
215
+ return { id: message.id, role: message.role, parts: message.parts };
216
+ }
217
+ function newestUnsent(messages) {
218
+ for (let index = messages.length - 1;index >= 0; index -= 1) {
219
+ const message = messages[index];
220
+ const answersToolCall = "parts" in message && message.parts.some((part) => part.type === "tool-result");
221
+ if (message.role === "user" || answersToolCall)
222
+ return messages.slice(index, index + 1);
223
+ }
224
+ return messages.slice(-1);
225
+ }
226
+ function metadataByMessageId(rows) {
227
+ return new Map(rows.flatMap((row) => row.metadata ? [[row.id, row.metadata]] : []));
228
+ }
229
+ function createCortexConnection(options) {
230
+ const { api, thread } = options;
231
+ const requestOptions = async () => ({ headers: await api.resolveHeaders() });
232
+ const turn = fetchServerSentEvents(() => api.resolveUrl("/chat"), requestOptions);
233
+ const connect = function(messages, data, abortSignal, runContext) {
234
+ return turn.connect(newestUnsent(messages), data, abortSignal, runContext);
235
+ };
236
+ const join = fetchServerSentEvents(() => api.resolveUrl(`/chat/${thread.id}/stream`), requestOptions);
237
+ let replayBase = [];
238
+ return {
239
+ connect,
240
+ async* joinRun(runId, abortSignal) {
241
+ yield {
242
+ type: EventType.MESSAGES_SNAPSHOT,
243
+ timestamp: Date.now(),
244
+ messages: replayBase
245
+ };
246
+ yield* join.joinRun(runId, abortSignal);
247
+ },
248
+ hydrate: async () => {
249
+ const hydration = await hydrateThread(options);
250
+ replayBase = hydration.messages;
251
+ return hydration;
252
+ }
253
+ };
254
+ }
255
+ async function hydrateThread(options) {
256
+ const { api, thread, mode } = options;
257
+ const activeRun = thread.isRunning ? { runId: thread.id } : null;
258
+ if (mode === "skip")
259
+ return { messages: [], activeRun, interrupts: null };
260
+ if (mode === "load")
261
+ options.setLoadingMessages?.(true);
262
+ try {
263
+ const rows = await api.listMessages(thread.id);
264
+ const messages = rows.map(toUiMessage);
265
+ options.onHydrated?.(rows, messages);
266
+ return { messages, activeRun, interrupts: null };
267
+ } finally {
268
+ options.setLoadingMessages?.(false);
269
+ }
270
+ }
271
+ async function settleTurn(options) {
272
+ try {
273
+ const rows = await options.api.listMessages(options.threadId);
274
+ if (options.isStale?.())
275
+ return;
276
+ options.absorbMetadata(metadataByMessageId(rows));
277
+ if (options.isStreaming())
278
+ return;
279
+ options.setMessages(rows.map(toUiMessage));
280
+ } catch {}
281
+ }
282
+ // ../../internal/contracts/wire.ts
283
+ var ATTACHMENT_MIME_TYPES = [
284
+ "image/png",
285
+ "image/jpeg",
286
+ "image/webp",
287
+ "application/pdf"
288
+ ];
289
+ var ATTACHMENT_MAX_BYTES = 10 * 1024 * 1024;
290
+ var MAX_ATTACHMENTS_PER_MESSAGE = 5;
291
+ function checkAttachmentPolicy(contentType, sizeBytes) {
292
+ if (!ATTACHMENT_MIME_TYPES.some((type) => type === contentType))
293
+ return "type";
294
+ if (sizeBytes > ATTACHMENT_MAX_BYTES)
295
+ return "size";
296
+ return "ok";
297
+ }
298
+
299
+ // ../../internal/client/src/attachment-queue.ts
300
+ function createAttachmentQueue(options) {
301
+ const { api } = options;
302
+ const listeners = new Set;
303
+ const cancelled = new Set;
304
+ let items = [];
305
+ let consumed = [];
306
+ function getState() {
307
+ return items;
308
+ }
309
+ function subscribe(listener) {
310
+ listeners.add(listener);
311
+ return () => {
312
+ listeners.delete(listener);
313
+ };
314
+ }
315
+ function setItems(next) {
316
+ items = next;
317
+ for (const listener of listeners)
318
+ listener();
319
+ }
320
+ function patch(localId, changes) {
321
+ setItems(items.map((item) => item.localId === localId ? { ...item, ...changes } : item));
322
+ }
323
+ function fail(localId) {
324
+ if (cancelled.delete(localId))
325
+ return;
326
+ patch(localId, { status: "error" });
327
+ }
328
+ function accept(files) {
329
+ const accepted = [];
330
+ for (const file of files) {
331
+ const rejected = checkAttachmentPolicy(file.type, file.size) !== "ok" || items.filter((item) => item.status !== "error").length >= MAX_ATTACHMENTS_PER_MESSAGE;
332
+ const localId = crypto.randomUUID();
333
+ setItems([
334
+ ...items,
335
+ { localId, filename: file.name, status: rejected ? "error" : "uploading" }
336
+ ]);
337
+ if (!rejected)
338
+ accepted.push({ localId, file });
339
+ }
340
+ if (!accepted.length)
341
+ return;
342
+ options.ensureThread().then((threadId) => {
343
+ for (const { localId, file } of accepted) {
344
+ if (cancelled.delete(localId))
345
+ continue;
346
+ patch(localId, { threadId });
347
+ api.uploadAttachment(threadId, file).then((attachment) => {
348
+ if (cancelled.delete(localId)) {
349
+ api.deleteAttachment(attachment.id).catch(() => {});
350
+ return;
351
+ }
352
+ patch(localId, {
353
+ status: "ready",
354
+ attachmentId: attachment.id,
355
+ summary: attachment
356
+ });
357
+ }, () => fail(localId));
358
+ }
359
+ }, () => {
360
+ for (const { localId } of accepted) {
361
+ fail(localId);
362
+ }
363
+ });
364
+ }
365
+ function remove(localId) {
366
+ const item = items.find((current) => current.localId === localId);
367
+ if (!item)
368
+ return;
369
+ if (item.status === "uploading") {
370
+ cancelled.add(localId);
371
+ setItems(items.filter((current) => current.localId !== localId));
372
+ return;
373
+ }
374
+ if (item.attachmentId) {
375
+ patch(localId, { status: "deleting" });
376
+ api.deleteAttachment(item.attachmentId).then(() => setItems(items.filter((current) => current.localId !== localId)), () => patch(localId, { status: "error" }));
377
+ return;
378
+ }
379
+ setItems(items.filter((current) => current.localId !== localId));
380
+ }
381
+ function clear(threadId) {
382
+ const retained = [];
383
+ for (const item of items) {
384
+ if (item.threadId !== undefined && item.threadId !== threadId) {
385
+ retained.push(item);
386
+ continue;
387
+ }
388
+ if (item.status === "uploading") {
389
+ cancelled.add(item.localId);
390
+ } else if (item.status === "ready" && item.threadId === threadId && item.attachmentId) {
391
+ api.deleteAttachment(item.attachmentId).catch(() => {});
392
+ }
393
+ }
394
+ setItems(retained);
395
+ }
396
+ function consumeReady() {
397
+ const attachments = items.flatMap((item) => item.status === "ready" && item.summary ? [{ ...item, status: "ready", summary: item.summary }] : []);
398
+ setItems(items.filter((item) => item.status !== "ready"));
399
+ consumed = attachments;
400
+ return attachments;
401
+ }
402
+ function restoreConsumed(threadId) {
403
+ const attachments = consumed;
404
+ consumed = [];
405
+ if (attachments.some((attachment) => attachment.threadId !== threadId))
406
+ return;
407
+ setItems([
408
+ ...attachments.map((attachment) => ({ ...attachment, status: "error" })),
409
+ ...items
410
+ ]);
411
+ }
412
+ function discardConsumed() {
413
+ consumed = [];
414
+ }
415
+ return {
416
+ getState,
417
+ subscribe,
418
+ accept,
419
+ remove,
420
+ clear,
421
+ consumeReady,
422
+ restoreConsumed,
423
+ discardConsumed
424
+ };
425
+ }
426
+ function attachmentQueueFlags(items) {
427
+ return {
428
+ uploading: items.some((item) => item.status === "uploading"),
429
+ busy: items.some((item) => item.status === "uploading" || item.status === "deleting"),
430
+ hasReady: items.some((item) => item.status === "ready")
431
+ };
432
+ }
433
+ // ../../internal/client/src/websocket.ts
434
+ function wsBackoffDelay(attempt) {
435
+ return Math.min(1000 * 2 ** (attempt - 1), 30000);
436
+ }
437
+ var STABLE_CONNECTION_MS = 1e4;
438
+ function createCortexSocket(options) {
439
+ let ws;
440
+ let reconnectTimer;
441
+ let attempt = 0;
442
+ let closed = false;
443
+ function connect() {
444
+ const wsUrlOption = typeof options.wsUrl === "function" ? options.wsUrl() : options.wsUrl;
445
+ const wsUrl = resolveWsUrl(wsUrlOption, options.transport.baseUrl);
446
+ resolveTransportHeaders(options.transport).then((headers) => {
447
+ if (closed)
448
+ return;
449
+ ws = new WebSocket(appendTokenToUrl(wsUrl, headers));
450
+ ws.addEventListener("open", () => {
451
+ const opened = ws;
452
+ setTimeout(() => {
453
+ if (ws === opened && !closed)
454
+ attempt = 0;
455
+ }, STABLE_CONNECTION_MS);
456
+ options.onOpen?.();
457
+ });
458
+ ws.addEventListener("message", (event) => {
459
+ const raw = event.data;
460
+ if (typeof raw !== "string")
461
+ return;
462
+ let parsed;
463
+ try {
464
+ parsed = JSON.parse(raw);
465
+ } catch {
466
+ return;
467
+ }
468
+ options.onEvent(parsed);
469
+ });
470
+ ws.addEventListener("close", scheduleReconnect);
471
+ }).catch(scheduleReconnect);
472
+ }
473
+ function scheduleReconnect() {
474
+ if (closed || reconnectTimer)
475
+ return;
476
+ attempt += 1;
477
+ reconnectTimer = setTimeout(() => {
478
+ reconnectTimer = undefined;
479
+ connect();
480
+ }, wsBackoffDelay(attempt));
481
+ }
482
+ connect();
483
+ return {
484
+ close() {
485
+ closed = true;
486
+ clearTimeout(reconnectTimer);
487
+ ws?.close();
488
+ }
489
+ };
490
+ }
491
+ function resolveWsUrl(wsUrl, baseUrl) {
492
+ const resolvedUrl = wsUrl ?? deriveWsUrl(baseUrl);
493
+ if (!wsUrl)
494
+ return resolvedUrl;
495
+ const agentId = extractAgentId(baseUrl);
496
+ if (!agentId)
497
+ return resolvedUrl;
498
+ return appendAgentIdToUrl(resolvedUrl, agentId);
499
+ }
500
+ function deriveWsUrl(baseUrl) {
501
+ const url = typeof baseUrl === "string" ? baseUrl : baseUrl();
502
+ const parsed = new URL(url, window.location.origin);
503
+ parsed.protocol = parsed.protocol === "https:" ? "wss:" : "ws:";
504
+ parsed.pathname = parsed.pathname.replace(/\/$/, "") + "/ws";
505
+ return parsed.toString();
506
+ }
507
+ function extractAgentId(baseUrl) {
508
+ const url = typeof baseUrl === "string" ? baseUrl : baseUrl();
509
+ const parsed = new URL(url, window.location.origin);
510
+ const segments = parsed.pathname.split("/").filter(Boolean);
511
+ const agentsIndex = segments.lastIndexOf("agents");
512
+ if (agentsIndex === -1)
513
+ return;
514
+ return segments[agentsIndex + 1];
515
+ }
516
+ function appendAgentIdToUrl(wsUrl, agentId) {
517
+ const parsed = new URL(wsUrl, window.location.origin);
518
+ if (parsed.searchParams.has("agentId") || hasAgentIdInPath(parsed))
519
+ return parsed.toString();
520
+ parsed.searchParams.set("agentId", agentId);
521
+ return parsed.toString();
522
+ }
523
+ function hasAgentIdInPath(url) {
524
+ const segments = url.pathname.split("/").filter(Boolean);
525
+ const agentsIndex = segments.lastIndexOf("agents");
526
+ return agentsIndex !== -1 && Boolean(segments[agentsIndex + 1]);
527
+ }
528
+ function appendTokenToUrl(wsUrl, headers) {
529
+ const authHeader = headers["Authorization"] ?? headers["authorization"];
530
+ if (!authHeader?.startsWith("Bearer "))
531
+ return wsUrl;
532
+ const parsed = new URL(wsUrl, window.location.origin);
533
+ if (parsed.searchParams.has("token"))
534
+ return parsed.toString();
535
+ parsed.searchParams.set("token", authHeader.slice(7));
536
+ return parsed.toString();
537
+ }
538
+ // ../../internal/client/src/threads.ts
539
+ function sortThreads(threads) {
540
+ return [...threads].sort((left, right) => {
541
+ const updatedAtDelta = Date.parse(right.updatedAt) - Date.parse(left.updatedAt);
542
+ if (updatedAtDelta !== 0)
543
+ return updatedAtDelta;
544
+ return Date.parse(right.createdAt) - Date.parse(left.createdAt);
545
+ });
546
+ }
547
+ function upsertThread(threads, thread) {
548
+ const nextThreads = [...threads];
549
+ const existingIndex = nextThreads.findIndex((currentThread) => currentThread.id === thread.id);
550
+ if (existingIndex === -1) {
551
+ nextThreads.push(thread);
552
+ } else {
553
+ nextThreads[existingIndex] = { ...nextThreads[existingIndex], ...thread };
554
+ }
555
+ return sortThreads(nextThreads);
556
+ }
557
+ function removeThread(threads, threadId) {
558
+ return threads.filter((thread) => thread.id !== threadId);
559
+ }
560
+ function applyWsEvent(threads, event) {
561
+ switch (event.type) {
562
+ case "thread:deleted":
563
+ return removeThread(threads, event.payload.threadId);
564
+ case "thread:created":
565
+ case "thread:title-updated":
566
+ case "thread:run-started":
567
+ case "thread:run-finished":
568
+ case "thread:messages-updated":
569
+ return upsertThread(threads, event.payload.thread);
570
+ default:
571
+ return threads;
572
+ }
573
+ }
574
+ // ../../internal/client/src/markdown.ts
575
+ import { marked } from "marked";
576
+ import DOMPurify from "dompurify";
577
+ function renderMarkdown(value) {
578
+ if (!value) {
579
+ return "";
580
+ }
581
+ let html = marked.parse(value, { async: false });
582
+ html = html.replace(/<table>/g, '<div style="overflow-x:auto"><table style="width:auto">').replace(/<\/table>/g, "</table></div>").replace(/<(t[hd])([\s>])/g, '<$1 style="padding:0.5rem 1rem"$2');
583
+ return DOMPurify.sanitize(html);
584
+ }
585
+ // ../../internal/client/src/highlight.ts
586
+ import hljs from "highlight.js/lib/core";
587
+ import javascript from "highlight.js/lib/languages/javascript";
588
+ import json from "highlight.js/lib/languages/json";
589
+ import sql from "highlight.js/lib/languages/sql";
590
+ var registered = false;
591
+ function ensureLanguages() {
592
+ if (registered)
593
+ return;
594
+ registered = true;
595
+ hljs.registerLanguage("javascript", javascript);
596
+ hljs.registerLanguage("json", json);
597
+ hljs.registerLanguage("cypher", sql);
598
+ }
599
+ function highlightCode(code, lang) {
600
+ if (!code)
601
+ return "";
602
+ ensureLanguages();
603
+ return hljs.getLanguage(lang) ? hljs.highlight(code, { language: lang }).value : escapeHtml(code);
604
+ }
605
+ function escapeHtml(str) {
606
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
607
+ }
608
+ // ../../internal/client/src/i18n/ar.json
609
+ var ar_default = {
610
+ translate_new: "جديد",
611
+ translate_threads: "المحادثات",
612
+ translate_n_conversations: "{{count}} محادثات",
613
+ translate_one_conversation: "محادثة واحدة",
614
+ translate_no_threads_yet: "لا توجد محادثات بعد",
615
+ translate_start_a_new_conversation: "ابدأ محادثة جديدة",
616
+ translate_untitled: "بدون عنوان",
617
+ translate_new_chat: "محادثة جديدة",
618
+ translate_normal: "عادي",
619
+ translate_debug: "تصحيح",
620
+ translate_type_a_message: "اكتب رسالة...",
621
+ translate_thinking: "جارٍ معالجة الطلب...",
622
+ translate_reasoned: "تم الاستنتاج",
623
+ translate_knowledge_graph_query: "استعلام الرسم البياني المعرفي",
624
+ translate_javascript_code_execution: "تنفيذ كود جافاسكريبت",
625
+ translate_completed: "مكتمل",
626
+ translate_attach_files: "إرفاق ملفات",
627
+ translate_drop_files_here: "أفلت ملفاتك هنا...",
628
+ translate_remove_attachment: "إزالة المرفق",
629
+ translate_attachment_rejected: "لا يمكن إرفاق هذا الملف",
630
+ translate_attachment_caption: "من فضلك اطّلع على الملفات المرفقة.",
631
+ translate_download: "تنزيل",
632
+ translate_tool_status_0: "جارٍ جلب البيانات…",
633
+ translate_tool_status_1: "جارٍ تحليل المعلومات…",
634
+ translate_tool_status_2: "جارٍ معالجة الطلب…",
635
+ translate_tool_status_3: "جارٍ تجميع النتائج…",
636
+ translate_tool_status_4: "جارٍ تحضير الرد…",
637
+ translate_tool_status_5: "جارٍ البحث…",
638
+ translate_tool_status_6: "جارٍ فحص السجلات…",
639
+ translate_tool_status_7: "جارٍ مراجعة التفاصيل…",
640
+ translate_tool_status_8: "جارٍ إجراء الحسابات…",
641
+ translate_tool_status_9: "جارٍ سحب المعلومات…",
642
+ translate_tool_done_0: "تم جلب البيانات بنجاح",
643
+ translate_tool_done_1: "تم التحليل بنجاح",
644
+ translate_tool_done_2: "تمت معالجة الطلب بنجاح",
645
+ translate_tool_done_3: "تم تجميع النتائج بنجاح",
646
+ translate_tool_done_4: "تم تحضير الرد بنجاح",
647
+ translate_tool_done_5: "تم البحث بنجاح",
648
+ translate_tool_done_6: "تم فحص السجلات بنجاح",
649
+ translate_tool_done_7: "تمت المراجعة بنجاح",
650
+ translate_tool_done_8: "تمت الحسابات بنجاح",
651
+ translate_tool_done_9: "تم استرجاع المعلومات بنجاح",
652
+ translate_tool_error: "حدث خطأ",
653
+ translate_attachment_status: "جارٍ قراءة الملف المرفق…",
654
+ translate_attachment_done: "تمت قراءة الملف المرفق",
655
+ translate_graph_0: "جارٍ استكشاف الروابط...",
656
+ translate_graph_1: "جارٍ رسم الخريطة...",
657
+ translate_graph_2: "جارٍ اكتشاف العلاقات...",
658
+ translate_graph_3: "جارٍ تتبع الروابط...",
659
+ translate_graph_4: "جارٍ التنقل في المعرفة...",
660
+ translate_graph_5: "جارٍ كشف الرؤى...",
661
+ translate_graph_6: "جارٍ ربط النقاط...",
662
+ translate_graph_7: "جارٍ تتبع المسار...",
663
+ translate_graph_8: "جارٍ تجميع الأجزاء...",
664
+ translate_graph_9: "جارٍ بناء الصورة...",
665
+ translate_code_0: "جارٍ حساب الأرقام...",
666
+ translate_code_1: "جارٍ معالجة البيانات...",
667
+ translate_code_2: "جارٍ تنفيذ طلبك...",
668
+ translate_code_3: "جارٍ تحليل الأرقام...",
669
+ translate_code_4: "جارٍ تجميع كل شيء...",
670
+ translate_code_5: "جارٍ تحليل النتائج...",
671
+ translate_code_6: "جارٍ العمل خلف الكواليس...",
672
+ translate_code_7: "جارٍ ترتيب التفاصيل...",
673
+ translate_code_8: "جارٍ تحضير إجابتك...",
674
+ translate_code_9: "أوشك على الانتهاء...",
675
+ translate_reasoning_0: "جارٍ التفكير...",
676
+ translate_reasoning_1: "جارٍ دراسة الخيارات...",
677
+ translate_reasoning_2: "جارٍ تقييم الاحتمالات...",
678
+ translate_reasoning_3: "جارٍ التأمل في هذا...",
679
+ translate_reasoning_4: "جارٍ إيجاد الحل...",
680
+ translate_reasoning_5: "جارٍ ترتيب الأفكار...",
681
+ translate_reasoning_6: "جارٍ التمعن في الأمر...",
682
+ translate_reasoning_7: "جارٍ إيجاد أفضل طريقة...",
683
+ translate_reasoning_8: "جارٍ تنظيم أفكاري...",
684
+ translate_reasoning_9: "أوشك على الانتهاء...",
685
+ translate_running: "قيد التنفيذ",
686
+ translate_aborted: "تم الإلغاء",
687
+ translate_input: "المدخلات",
688
+ translate_output: "المخرجات",
689
+ translate_calling: "جارٍ الاستدعاء",
690
+ translate_input_ready: "المدخلات جاهزة",
691
+ translate_needs_approval: "بحاجة إلى موافقة",
692
+ translate_approved: "تمت الموافقة",
693
+ translate_responded: "تم الرد",
694
+ translate_error: "خطأ",
695
+ translate_approval_requested: "طلب موافقة",
696
+ translate_approval_response: "رد الموافقة",
697
+ translate_waiting_for_approval: "في انتظار الموافقة لتنفيذ هذه الأداة.",
698
+ translate_tool_approved: "تمت الموافقة.",
699
+ translate_tool_response_received: "تم استلام الرد.",
700
+ translate_tokens: "رمز",
701
+ translate_fresh: "جديد",
702
+ translate_cache_read: "قراءة من الذاكرة",
703
+ translate_cache_write: "كتابة في الذاكرة",
704
+ translate_n_percent_cached: "{{percent}}٪ مخزّن مؤقتًا",
705
+ translate_text: "نص",
706
+ translate_reasoning: "الاستنتاج",
707
+ translate_read: "قراءة",
708
+ translate_write: "كتابة",
709
+ translate_total: "الإجمالي",
710
+ translate_request: "الطلب",
711
+ translate_response: "الرد",
712
+ translate_step_n: "الخطوة {{number}}",
713
+ translate_inspect_llm_requests: "فحص طلبات النموذج",
714
+ translate_loading: "جارٍ التحميل…",
715
+ translate_no_llm_requests: "لا توجد طلبات نموذج مسجّلة لهذه الرسالة.",
716
+ translate_unhandled_type: "نوع غير مدعوم:"
717
+ };
718
+ // ../../internal/client/src/i18n/en.json
719
+ var en_default = {
720
+ translate_new: "New",
721
+ translate_threads: "Threads",
722
+ translate_n_conversations: "{{count}} conversations",
723
+ translate_one_conversation: "1 conversation",
724
+ translate_no_threads_yet: "No threads yet",
725
+ translate_start_a_new_conversation: "Start a new conversation",
726
+ translate_untitled: "Untitled",
727
+ translate_new_chat: "New Chat",
728
+ translate_normal: "Normal",
729
+ translate_debug: "Debug",
730
+ translate_type_a_message: "Type a message...",
731
+ translate_thinking: "Thinking things through...",
732
+ translate_reasoned: "Reasoned",
733
+ translate_knowledge_graph_query: "Knowledge Graph Query",
734
+ translate_javascript_code_execution: "JavaScript Code Execution",
735
+ translate_completed: "Completed",
736
+ translate_attach_files: "Attach files",
737
+ translate_drop_files_here: "Drop your files here...",
738
+ translate_remove_attachment: "Remove attachment",
739
+ translate_attachment_rejected: "This file cannot be attached",
740
+ translate_attachment_caption: "Please take a look at the attached files.",
741
+ translate_download: "Download",
742
+ translate_tool_status_0: "Fetching data...",
743
+ translate_tool_status_1: "Analyzing information...",
744
+ translate_tool_status_2: "Processing request...",
745
+ translate_tool_status_3: "Gathering results...",
746
+ translate_tool_status_4: "Preparing response...",
747
+ translate_tool_status_5: "Looking things up...",
748
+ translate_tool_status_6: "Checking records...",
749
+ translate_tool_status_7: "Reviewing details...",
750
+ translate_tool_status_8: "Running calculations...",
751
+ translate_tool_status_9: "Pulling information...",
752
+ translate_tool_done_0: "Data fetched successfully",
753
+ translate_tool_done_1: "Analysis completed successfully",
754
+ translate_tool_done_2: "Request processed successfully",
755
+ translate_tool_done_3: "Results gathered successfully",
756
+ translate_tool_done_4: "Response prepared successfully",
757
+ translate_tool_done_5: "Lookup completed successfully",
758
+ translate_tool_done_6: "Records checked successfully",
759
+ translate_tool_done_7: "Review completed successfully",
760
+ translate_tool_done_8: "Calculations completed successfully",
761
+ translate_tool_done_9: "Information retrieved successfully",
762
+ translate_tool_error: "Something went wrong",
763
+ translate_attachment_status: "Reading the attached file...",
764
+ translate_attachment_done: "Finished reading the file",
765
+ translate_graph_0: "Exploring connections...",
766
+ translate_graph_1: "Mapping out the links...",
767
+ translate_graph_2: "Discovering relationships...",
768
+ translate_graph_3: "Tracing the connections...",
769
+ translate_graph_4: "Navigating the knowledge...",
770
+ translate_graph_5: "Uncovering insights...",
771
+ translate_graph_6: "Connecting the dots...",
772
+ translate_graph_7: "Following the trail...",
773
+ translate_graph_8: "Piecing things together...",
774
+ translate_graph_9: "Building the picture...",
775
+ translate_code_0: "Running the numbers...",
776
+ translate_code_1: "Working through the data...",
777
+ translate_code_2: "Processing your request...",
778
+ translate_code_3: "Crunching the figures...",
779
+ translate_code_4: "Putting it all together...",
780
+ translate_code_5: "Analyzing the results...",
781
+ translate_code_6: "Working behind the scenes...",
782
+ translate_code_7: "Sorting through the details...",
783
+ translate_code_8: "Preparing your answer...",
784
+ translate_code_9: "Almost ready...",
785
+ translate_reasoning_0: "Thinking it through...",
786
+ translate_reasoning_1: "Considering the options...",
787
+ translate_reasoning_2: "Weighing the possibilities...",
788
+ translate_reasoning_3: "Reflecting on this...",
789
+ translate_reasoning_4: "Working it out...",
790
+ translate_reasoning_5: "Putting thoughts together...",
791
+ translate_reasoning_6: "Mulling it over...",
792
+ translate_reasoning_7: "Finding the best approach...",
793
+ translate_reasoning_8: "Organizing my thoughts...",
794
+ translate_reasoning_9: "Almost there...",
795
+ translate_running: "Running",
796
+ translate_aborted: "Aborted",
797
+ translate_input: "Input",
798
+ translate_output: "Output",
799
+ translate_calling: "Calling",
800
+ translate_input_ready: "Input ready",
801
+ translate_needs_approval: "Needs approval",
802
+ translate_approved: "Approved",
803
+ translate_responded: "Responded",
804
+ translate_error: "Error",
805
+ translate_approval_requested: "Approval requested",
806
+ translate_approval_response: "Approval response",
807
+ translate_waiting_for_approval: "Waiting for approval to execute this tool.",
808
+ translate_tool_approved: "Approved.",
809
+ translate_tool_response_received: "Response received.",
810
+ translate_tokens: "tokens",
811
+ translate_fresh: "Fresh",
812
+ translate_cache_read: "Cache read",
813
+ translate_cache_write: "Cache write",
814
+ translate_n_percent_cached: "{{percent}}% cached",
815
+ translate_text: "Text",
816
+ translate_reasoning: "Reasoning",
817
+ translate_read: "Read",
818
+ translate_write: "Write",
819
+ translate_total: "Total",
820
+ translate_request: "Request",
821
+ translate_response: "Response",
822
+ translate_step_n: "Step {{number}}",
823
+ translate_inspect_llm_requests: "Inspect LLM requests",
824
+ translate_loading: "loading…",
825
+ translate_no_llm_requests: "No LLM requests recorded for this message.",
826
+ translate_unhandled_type: "Unhandled type:"
827
+ };
828
+
829
+ // ../../internal/client/src/i18n.ts
830
+ var translations = { en: en_default, ar: ar_default };
831
+ function translate(locale, key, params) {
832
+ const table = translations[locale] ?? translations["en"];
833
+ const value = table?.[key] ?? translations["en"]?.[key] ?? key;
834
+ if (!params)
835
+ return value;
836
+ return value.replace(/\{\{\s*(\w+)\s*\}\}/g, (match, name) => (name in params) ? String(params[name]) : match);
837
+ }
838
+ // ../../internal/client/src/utils/deep-parse-json.ts
839
+ function deepParseJson(value) {
840
+ if (typeof value === "string") {
841
+ const trimmed = value.trim();
842
+ const looksLikeJson = trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]");
843
+ if (!looksLikeJson)
844
+ return value;
845
+ try {
846
+ return deepParseJson(JSON.parse(trimmed));
847
+ } catch {
848
+ return value;
849
+ }
850
+ }
851
+ if (Array.isArray(value)) {
852
+ return value.map((item) => deepParseJson(item));
853
+ }
854
+ if (value !== null && typeof value === "object") {
855
+ const result = {};
856
+ for (const [key, val] of Object.entries(value)) {
857
+ result[key] = deepParseJson(val);
858
+ }
859
+ return result;
860
+ }
861
+ return value;
862
+ }
863
+ // ../../internal/client/src/utils/describe-json-value.ts
864
+ function describeJsonValue(value, path) {
865
+ if (Array.isArray(value)) {
866
+ const items = value;
867
+ return {
868
+ kind: "container",
869
+ open: "[",
870
+ close: "]",
871
+ summary: count(items.length, "item", "items"),
872
+ entries: items.map((item, index) => ({
873
+ key: null,
874
+ value: item,
875
+ path: `${path}[${index}]`
876
+ }))
877
+ };
878
+ }
879
+ if (value !== null && typeof value === "object") {
880
+ const entries = Object.entries(value);
881
+ return {
882
+ kind: "container",
883
+ open: "{",
884
+ close: "}",
885
+ summary: count(entries.length, "property", "properties"),
886
+ entries: entries.map(([key, entryValue]) => ({
887
+ key,
888
+ value: entryValue,
889
+ path: `${path}.${key}`
890
+ }))
891
+ };
892
+ }
893
+ return {
894
+ kind: "primitive",
895
+ text: formatPrimitive(value),
896
+ className: primitiveClass(value)
897
+ };
898
+ }
899
+ function count(total, singular, plural) {
900
+ return `${total} ${total === 1 ? singular : plural}`;
901
+ }
902
+ function formatPrimitive(value) {
903
+ if (value === null || value === undefined)
904
+ return "null";
905
+ if (typeof value === "string")
906
+ return JSON.stringify(value);
907
+ if (typeof value === "number" || typeof value === "boolean")
908
+ return String(value);
909
+ return JSON.stringify(value) ?? "null";
910
+ }
911
+ function primitiveClass(value) {
912
+ if (value === null || value === undefined)
913
+ return "jt-null";
914
+ if (typeof value === "string")
915
+ return "jt-string";
916
+ if (typeof value === "number")
917
+ return "jt-number";
918
+ if (typeof value === "boolean")
919
+ return "jt-boolean";
920
+ return "";
921
+ }
922
+ // ../../internal/client/src/utils/json-text.ts
923
+ function parseJsonText(value) {
924
+ if (!value)
925
+ return null;
926
+ try {
927
+ return JSON.parse(value);
928
+ } catch {
929
+ return value;
930
+ }
931
+ }
932
+ function prettyJsonText(value) {
933
+ if (!value)
934
+ return "";
935
+ try {
936
+ return JSON.stringify(JSON.parse(value), null, 2);
937
+ } catch {
938
+ return value;
939
+ }
940
+ }
941
+ // ../../internal/client/src/utils/relative-time.ts
942
+ var UNITS = [
943
+ ["year", 31536000000],
944
+ ["month", 2592000000],
945
+ ["week", 604800000],
946
+ ["day", 86400000],
947
+ ["hour", 3600000],
948
+ ["minute", 60000],
949
+ ["second", 1000]
950
+ ];
951
+ function relativeTimeLabel(iso, locale, now = Date.now()) {
952
+ const at = Date.parse(iso);
953
+ if (Number.isNaN(at))
954
+ return "";
955
+ const elapsed = at - now;
956
+ const [unit, ms] = UNITS.find(([, size]) => Math.abs(elapsed) >= size) ?? UNITS[UNITS.length - 1];
957
+ return new Intl.RelativeTimeFormat(locale, { numeric: "auto" }).format(Math.round(elapsed / ms), unit);
958
+ }
959
+ // ../../internal/client/src/utils/save-blob.ts
960
+ function saveBlob(blob, name) {
961
+ const url = URL.createObjectURL(blob);
962
+ const link = document.createElement("a");
963
+ link.href = url;
964
+ link.download = name;
965
+ link.click();
966
+ URL.revokeObjectURL(url);
967
+ }
968
+ // ../../internal/client/src/utils/stream-text-smoother.ts
969
+ class StreamTextSmoother {
970
+ onUpdate;
971
+ fullText = "";
972
+ displayedLength = 0;
973
+ animationFrameId = null;
974
+ isDone = false;
975
+ static DRAIN_FRACTION = 0.03;
976
+ static MIN_CHARS_PER_FRAME = 1;
977
+ static DONE_DRAIN_FRACTION = 0.1;
978
+ constructor(onUpdate) {
979
+ this.onUpdate = onUpdate;
980
+ }
981
+ seed(displayedText) {
982
+ this.fullText = displayedText;
983
+ this.displayedLength = displayedText.length;
984
+ this.onUpdate(displayedText);
985
+ }
986
+ update(newFullText, done) {
987
+ this.fullText = newFullText;
988
+ this.isDone = done;
989
+ this.displayedLength = Math.min(this.displayedLength, this.fullText.length);
990
+ if (done && this.displayedLength >= this.fullText.length) {
991
+ this.onUpdate(this.fullText);
992
+ this.stopAnimation();
993
+ return;
994
+ }
995
+ if (!this.animationFrameId) {
996
+ this.scheduleFrame();
997
+ }
998
+ }
999
+ destroy() {
1000
+ this.stopAnimation();
1001
+ }
1002
+ scheduleFrame() {
1003
+ this.animationFrameId = requestAnimationFrame(() => this.tick());
1004
+ }
1005
+ tick() {
1006
+ const bufferSize = this.fullText.length - this.displayedLength;
1007
+ if (bufferSize <= 0) {
1008
+ this.animationFrameId = null;
1009
+ return;
1010
+ }
1011
+ const fraction = this.isDone ? StreamTextSmoother.DONE_DRAIN_FRACTION : StreamTextSmoother.DRAIN_FRACTION;
1012
+ const charsToRelease = Math.max(StreamTextSmoother.MIN_CHARS_PER_FRAME, Math.ceil(bufferSize * fraction));
1013
+ this.displayedLength = Math.min(this.fullText.length, this.displayedLength + charsToRelease);
1014
+ this.onUpdate(this.fullText.substring(0, this.displayedLength));
1015
+ if (this.displayedLength < this.fullText.length) {
1016
+ this.scheduleFrame();
1017
+ } else {
1018
+ this.animationFrameId = null;
1019
+ }
1020
+ }
1021
+ stopAnimation() {
1022
+ if (this.animationFrameId) {
1023
+ cancelAnimationFrame(this.animationFrameId);
1024
+ this.animationFrameId = null;
1025
+ }
1026
+ }
1027
+ }
1028
+ // ../../internal/client/src/utils/token-usage.ts
1029
+ function cachePercent(usage) {
1030
+ if (usage.input.total <= 0)
1031
+ return null;
1032
+ return Math.round(usage.input.cacheRead / usage.input.total * 100);
1033
+ }
1034
+ // src/chat-session.tsx
1035
+ import { useEffect, useLayoutEffect, useMemo, useRef } from "react";
1036
+ import { useChat } from "@tanstack/ai-react";
1037
+ function ChatSession(props) {
1038
+ const { thread, api, patchUi } = props;
1039
+ const alive = useRef(true);
1040
+ const ownsRun = useRef(false);
1041
+ const serverAnswered = useRef(false);
1042
+ const wasAborted = useRef(false);
1043
+ const wasWorking = useRef(false);
1044
+ const dispatchedToolCalls = useRef(new Set);
1045
+ const refreshing = useRef(Promise.resolve());
1046
+ const connection = useMemo(() => createCortexConnection({
1047
+ api,
1048
+ thread: { id: thread.id, isRunning: thread.isRunning },
1049
+ mode: props.mode,
1050
+ onHydrated: (rows, messages) => {
1051
+ if (!alive.current)
1052
+ return;
1053
+ patchUi({
1054
+ messageMetadata: metadataByMessageId(rows),
1055
+ hasPendingToolCalls: unansweredToolCalls(messages).length > 0
1056
+ });
1057
+ },
1058
+ setLoadingMessages: (loading) => {
1059
+ if (alive.current)
1060
+ patchUi({ isLoadingMessages: loading });
1061
+ }
1062
+ }), []);
1063
+ const chat = useChat({
1064
+ threadId: thread.id,
1065
+ persistence: true,
1066
+ connection,
1067
+ onChunk: () => {
1068
+ if (!alive.current)
1069
+ return;
1070
+ serverAnswered.current = true;
1071
+ },
1072
+ onError: () => {
1073
+ if (!alive.current)
1074
+ return;
1075
+ patchUi({ hasPendingToolCalls: false });
1076
+ if (serverAnswered.current)
1077
+ props.onTurnFinished();
1078
+ else
1079
+ props.onSendFailed();
1080
+ }
1081
+ });
1082
+ const chatRef = useRef(chat);
1083
+ chatRef.current = chat;
1084
+ const isLoadingRef = useRef(chat.isLoading);
1085
+ isLoadingRef.current = chat.isLoading;
1086
+ function syncPendingToolCalls() {
1087
+ const pending = unansweredToolCalls(chatRef.current.messages);
1088
+ patchUi({ hasPendingToolCalls: pending.length > 0 });
1089
+ return pending;
1090
+ }
1091
+ async function resolveToolCall(call, onToolCall) {
1092
+ const result = onToolCall({ toolCallId: call.id, toolName: call.name, input: call.input }, { threadId: thread.id });
1093
+ if (result === null || result === undefined)
1094
+ return;
1095
+ const output = await Promise.resolve(result);
1096
+ if (output === null || output === undefined)
1097
+ return;
1098
+ if (!alive.current)
1099
+ return;
1100
+ await chatRef.current.addToolResult({ toolCallId: call.id, tool: call.name, output });
1101
+ syncPendingToolCalls();
1102
+ }
1103
+ function dispatchPendingToolCalls() {
1104
+ const pending = syncPendingToolCalls();
1105
+ const onToolCall = props.configRef.current.hooks?.onToolCall;
1106
+ if (!onToolCall)
1107
+ return pending.length > 0;
1108
+ for (const call of pending) {
1109
+ if (call.state !== "input-complete")
1110
+ continue;
1111
+ if (dispatchedToolCalls.current.has(call.id))
1112
+ continue;
1113
+ dispatchedToolCalls.current.add(call.id);
1114
+ resolveToolCall(call, onToolCall);
1115
+ }
1116
+ return pending.length > 0;
1117
+ }
1118
+ async function readBackMessages(threadId) {
1119
+ if (!alive.current || threadId !== thread.id)
1120
+ return;
1121
+ await settleTurn({
1122
+ api,
1123
+ threadId,
1124
+ isStale: () => !alive.current,
1125
+ isStreaming: () => isLoadingRef.current,
1126
+ absorbMetadata: (metadata) => patchUi({ messageMetadata: metadata }),
1127
+ setMessages: (messages) => {
1128
+ chatRef.current.setMessages(messages);
1129
+ patchUi({ hasPendingToolCalls: unansweredToolCalls(messages).length > 0 });
1130
+ }
1131
+ });
1132
+ }
1133
+ function refreshMessages(threadId) {
1134
+ refreshing.current = refreshing.current.then(() => readBackMessages(threadId));
1135
+ return refreshing.current;
1136
+ }
1137
+ async function settleSession() {
1138
+ if (wasAborted.current) {
1139
+ wasAborted.current = false;
1140
+ return;
1141
+ }
1142
+ if (ownsRun.current && dispatchPendingToolCalls())
1143
+ return;
1144
+ await refreshMessages(thread.id);
1145
+ }
1146
+ async function performSend(prompt, attachments) {
1147
+ props.setRunning(thread.id, true);
1148
+ ownsRun.current = true;
1149
+ serverAnswered.current = false;
1150
+ const message = {
1151
+ id: crypto.randomUUID(),
1152
+ role: "user",
1153
+ parts: [{ type: "text", content: prompt }]
1154
+ };
1155
+ if (attachments.length) {
1156
+ patchUi((previous) => ({
1157
+ messageMetadata: new Map(previous.messageMetadata).set(message.id, { attachments })
1158
+ }));
1159
+ }
1160
+ await chatRef.current.append(message);
1161
+ }
1162
+ async function abort() {
1163
+ if (!isLoadingRef.current)
1164
+ return;
1165
+ const { aborted } = await api.abortStream(thread.id).catch(() => ({ aborted: false }));
1166
+ if (!alive.current)
1167
+ return;
1168
+ if (aborted) {
1169
+ wasAborted.current = true;
1170
+ props.setRunning(thread.id, false);
1171
+ }
1172
+ chatRef.current.stop();
1173
+ patchUi({ hasPendingToolCalls: false });
1174
+ }
1175
+ function addToolResult(toolCallId, toolName, output) {
1176
+ chatRef.current.addToolResult({ toolCallId, tool: toolName, output }).then(() => syncPendingToolCalls());
1177
+ }
1178
+ function reattach(freshThread) {
1179
+ if (isLoadingRef.current)
1180
+ return;
1181
+ if (freshThread.isRunning) {
1182
+ props.remount(freshThread);
1183
+ return;
1184
+ }
1185
+ refreshMessages(freshThread.id);
1186
+ }
1187
+ useEffect(() => {
1188
+ alive.current = true;
1189
+ return () => {
1190
+ alive.current = false;
1191
+ };
1192
+ }, []);
1193
+ const handleRef = useRef(undefined);
1194
+ handleRef.current = {
1195
+ threadId: thread.id,
1196
+ send: performSend,
1197
+ abort,
1198
+ addToolResult,
1199
+ reattach,
1200
+ refreshMessages: (threadId) => {
1201
+ refreshMessages(threadId);
1202
+ }
1203
+ };
1204
+ useLayoutEffect(() => {
1205
+ props.sessionRef.current = handleRef.current;
1206
+ });
1207
+ useLayoutEffect(() => {
1208
+ return () => {
1209
+ if (props.sessionRef.current === handleRef.current) {
1210
+ props.sessionRef.current = undefined;
1211
+ }
1212
+ };
1213
+ }, []);
1214
+ useEffect(() => {
1215
+ if (!props.pendingSendRef.current.length)
1216
+ return;
1217
+ const timer = setTimeout(() => {
1218
+ const pending = props.pendingSendRef.current;
1219
+ props.pendingSendRef.current = [];
1220
+ (async () => {
1221
+ for (const { prompt, attachments } of pending) {
1222
+ await performSend(prompt, attachments);
1223
+ }
1224
+ })();
1225
+ });
1226
+ return () => clearTimeout(timer);
1227
+ }, []);
1228
+ useEffect(() => {
1229
+ patchUi({ messages: chat.messages });
1230
+ }, [chat.messages]);
1231
+ useEffect(() => {
1232
+ patchUi({ isAgentWorking: chat.isLoading });
1233
+ if (chat.isLoading) {
1234
+ wasWorking.current = true;
1235
+ return;
1236
+ }
1237
+ if (!wasWorking.current)
1238
+ return;
1239
+ wasWorking.current = false;
1240
+ props.onTurnFinished();
1241
+ settleSession();
1242
+ }, [chat.isLoading]);
1243
+ return null;
1244
+ }
1245
+
1246
+ // src/context.ts
1247
+ import { createContext, useContext } from "react";
1248
+ var CortexContext = createContext(undefined);
1249
+ function useCortex() {
1250
+ const value = useContext(CortexContext);
1251
+ if (!value)
1252
+ throw new Error("useCortex must be used inside <CortexChatWidget>");
1253
+ return value;
1254
+ }
1255
+
1256
+ // src/cx.ts
1257
+ function cx(...parts) {
1258
+ return parts.filter(Boolean).join(" ");
1259
+ }
1260
+
1261
+ // src/components/ChatComposer.tsx
1262
+ import { forwardRef, useEffect as useEffect2, useImperativeHandle, useRef as useRef2, useState } from "react";
1263
+
1264
+ // src/components/AttachmentQueue.tsx
1265
+ import { jsxDEV } from "react/jsx-dev-runtime";
1266
+ function AttachmentQueue() {
1267
+ const { queue, t } = useCortex();
1268
+ if (!queue.items.length)
1269
+ return null;
1270
+ return /* @__PURE__ */ jsxDEV("div", {
1271
+ className: "cortex-attachment-queue",
1272
+ children: queue.items.map((item) => /* @__PURE__ */ jsxDEV("div", {
1273
+ className: cx("cortex-attachment-chip", item.status === "error" && "cortex-attachment-chip--error"),
1274
+ title: item.status === "error" ? t("translate_attachment_rejected") : "",
1275
+ children: [
1276
+ item.status === "uploading" || item.status === "deleting" ? /* @__PURE__ */ jsxDEV("svg", {
1277
+ className: "cortex-attachment-chip__spinner",
1278
+ viewBox: "0 0 16 16",
1279
+ fill: "none",
1280
+ children: [
1281
+ /* @__PURE__ */ jsxDEV("circle", {
1282
+ cx: "8",
1283
+ cy: "8",
1284
+ r: "6",
1285
+ stroke: "currentColor",
1286
+ strokeWidth: "2",
1287
+ className: "cortex-attachment-chip__spinner-track"
1288
+ }, undefined, false, undefined, this),
1289
+ /* @__PURE__ */ jsxDEV("path", {
1290
+ d: "M14 8a6 6 0 0 0-6-6",
1291
+ stroke: "currentColor",
1292
+ strokeWidth: "2",
1293
+ strokeLinecap: "round"
1294
+ }, undefined, false, undefined, this)
1295
+ ]
1296
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV("svg", {
1297
+ viewBox: "0 0 16 16",
1298
+ className: "cortex-attachment-chip__icon",
1299
+ fill: "none",
1300
+ children: [
1301
+ /* @__PURE__ */ jsxDEV("path", {
1302
+ d: "M4 1.5h5.172a2 2 0 0 1 1.414.586l2.328 2.328a2 2 0 0 1 .586 1.414V12.5a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-9a2 2 0 0 1 2-2Z",
1303
+ stroke: "currentColor",
1304
+ strokeWidth: "1.25"
1305
+ }, undefined, false, undefined, this),
1306
+ /* @__PURE__ */ jsxDEV("path", {
1307
+ d: "M9.5 1.5v2a2 2 0 0 0 2 2h2",
1308
+ stroke: "currentColor",
1309
+ strokeWidth: "1.25",
1310
+ strokeLinecap: "round"
1311
+ }, undefined, false, undefined, this)
1312
+ ]
1313
+ }, undefined, true, undefined, this),
1314
+ /* @__PURE__ */ jsxDEV("span", {
1315
+ className: "cortex-attachment-chip__name",
1316
+ children: item.filename
1317
+ }, undefined, false, undefined, this),
1318
+ /* @__PURE__ */ jsxDEV("button", {
1319
+ type: "button",
1320
+ onClick: () => queue.remove(item.localId),
1321
+ className: "cortex-attachment-chip__remove",
1322
+ disabled: item.status === "deleting",
1323
+ "aria-label": t("translate_remove_attachment"),
1324
+ children: /* @__PURE__ */ jsxDEV("svg", {
1325
+ viewBox: "0 0 16 16",
1326
+ fill: "none",
1327
+ children: /* @__PURE__ */ jsxDEV("path", {
1328
+ d: "M4.5 4.5l7 7m0-7l-7 7",
1329
+ stroke: "currentColor",
1330
+ strokeWidth: "1.5",
1331
+ strokeLinecap: "round"
1332
+ }, undefined, false, undefined, this)
1333
+ }, undefined, false, undefined, this)
1334
+ }, undefined, false, undefined, this)
1335
+ ]
1336
+ }, item.localId, true, undefined, this))
1337
+ }, undefined, false, undefined, this);
1338
+ }
1339
+
1340
+ // src/components/ChatComposer.tsx
1341
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
1342
+ var ACCEPTED_TYPES = ATTACHMENT_MIME_TYPES.join(",");
1343
+ var ChatComposer = forwardRef(function ChatComposer2(_props, ref) {
1344
+ const { t, queue, isAgentWorking, send, abort } = useCortex();
1345
+ const [text, setText] = useState("");
1346
+ const [dragging, setDragging] = useState(false);
1347
+ const messageInput = useRef2(null);
1348
+ const fileInput = useRef2(null);
1349
+ useImperativeHandle(ref, () => ({
1350
+ focusInput: () => messageInput.current?.focus()
1351
+ }));
1352
+ const wasWorking = useRef2(isAgentWorking);
1353
+ useEffect2(() => {
1354
+ if (wasWorking.current && !isAgentWorking)
1355
+ messageInput.current?.focus();
1356
+ wasWorking.current = isAgentWorking;
1357
+ }, [isAgentWorking]);
1358
+ const canSend = !queue.busy && (Boolean(text.trim()) || queue.hasReady);
1359
+ function onSend() {
1360
+ if (isAgentWorking || !canSend) {
1361
+ return;
1362
+ }
1363
+ const captionKey = "translate_attachment_caption";
1364
+ const translated = t(captionKey);
1365
+ const caption = translated !== captionKey ? translated : "Please take a look at the attached files.";
1366
+ const prompt = text.trim() || caption;
1367
+ const attachments = queue.consumeReady();
1368
+ setText("");
1369
+ send(prompt, attachments.map((attachment) => attachment.summary));
1370
+ }
1371
+ function onKeydown(event) {
1372
+ if (event.key === "Enter" && !event.shiftKey) {
1373
+ event.preventDefault();
1374
+ onSend();
1375
+ }
1376
+ }
1377
+ function onDragOver(event) {
1378
+ event.preventDefault();
1379
+ setDragging(true);
1380
+ }
1381
+ function onDragLeave(event) {
1382
+ const area = event.currentTarget;
1383
+ if (!area.contains(event.relatedTarget)) {
1384
+ setDragging(false);
1385
+ }
1386
+ }
1387
+ function onDrop(event) {
1388
+ event.preventDefault();
1389
+ setDragging(false);
1390
+ queue.accept([...event.dataTransfer.files]);
1391
+ }
1392
+ function onPaste(event) {
1393
+ const files = event.clipboardData.files;
1394
+ if (!files.length)
1395
+ return;
1396
+ event.preventDefault();
1397
+ queue.accept([...files]);
1398
+ }
1399
+ return /* @__PURE__ */ jsxDEV2("div", {
1400
+ className: "cortex-widget__input-area",
1401
+ onDragOver,
1402
+ onDragLeave,
1403
+ onDrop,
1404
+ children: [
1405
+ /* @__PURE__ */ jsxDEV2(AttachmentQueue, {}, undefined, false, undefined, this),
1406
+ /* @__PURE__ */ jsxDEV2("div", {
1407
+ className: cx("cortex-widget__input-box", isAgentWorking && "cortex-widget__input-box--disabled", !isAgentWorking && "cortex-widget__input-box--enabled", dragging && "cortex-widget__input-box--dragging"),
1408
+ children: [
1409
+ /* @__PURE__ */ jsxDEV2("textarea", {
1410
+ ref: messageInput,
1411
+ onKeyDown: onKeydown,
1412
+ onPaste,
1413
+ value: text,
1414
+ onChange: (event) => setText(event.target.value),
1415
+ placeholder: dragging ? t("translate_drop_files_here") : isAgentWorking ? "" : t("translate_type_a_message"),
1416
+ disabled: isAgentWorking,
1417
+ rows: 1,
1418
+ className: cx("cortex-widget__textarea", isAgentWorking && "cortex-widget__textarea--disabled")
1419
+ }, undefined, false, undefined, this),
1420
+ isAgentWorking ? /* @__PURE__ */ jsxDEV2("button", {
1421
+ onClick: () => void abort(),
1422
+ className: "cortex-stop-btn",
1423
+ children: [
1424
+ /* @__PURE__ */ jsxDEV2("span", {
1425
+ className: "cortex-stop-btn__ring"
1426
+ }, undefined, false, undefined, this),
1427
+ /* @__PURE__ */ jsxDEV2("svg", {
1428
+ width: "12",
1429
+ height: "12",
1430
+ viewBox: "0 0 12 12",
1431
+ fill: "none",
1432
+ className: "cortex-stop-btn__icon",
1433
+ children: /* @__PURE__ */ jsxDEV2("rect", {
1434
+ x: "1",
1435
+ y: "1",
1436
+ width: "10",
1437
+ height: "10",
1438
+ rx: "2.5",
1439
+ fill: "currentColor"
1440
+ }, undefined, false, undefined, this)
1441
+ }, undefined, false, undefined, this)
1442
+ ]
1443
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV2("div", {
1444
+ className: "cortex-widget__input-actions",
1445
+ children: [
1446
+ /* @__PURE__ */ jsxDEV2("button", {
1447
+ type: "button",
1448
+ onClick: () => fileInput.current?.click(),
1449
+ className: "cortex-widget__attach-btn",
1450
+ "aria-label": t("translate_attach_files"),
1451
+ children: /* @__PURE__ */ jsxDEV2("svg", {
1452
+ width: "16",
1453
+ height: "16",
1454
+ viewBox: "0 0 16 16",
1455
+ fill: "none",
1456
+ children: /* @__PURE__ */ jsxDEV2("path", {
1457
+ d: "M10.5 5.5 6.2 9.8a1.4 1.4 0 0 0 2 2l4.6-4.6a2.8 2.8 0 0 0-4-4L4.2 7.8a4.2 4.2 0 0 0 6 6l4-4",
1458
+ stroke: "currentColor",
1459
+ strokeWidth: "1.3",
1460
+ strokeLinecap: "round",
1461
+ strokeLinejoin: "round"
1462
+ }, undefined, false, undefined, this)
1463
+ }, undefined, false, undefined, this)
1464
+ }, undefined, false, undefined, this),
1465
+ /* @__PURE__ */ jsxDEV2("input", {
1466
+ ref: fileInput,
1467
+ type: "file",
1468
+ multiple: true,
1469
+ accept: ACCEPTED_TYPES,
1470
+ onChange: (event) => {
1471
+ queue.accept([...event.target.files ?? []]);
1472
+ event.target.value = "";
1473
+ },
1474
+ className: "cortex-widget__file-input"
1475
+ }, undefined, false, undefined, this),
1476
+ /* @__PURE__ */ jsxDEV2("button", {
1477
+ onClick: onSend,
1478
+ className: cx("cortex-widget__send-btn", !canSend && "cortex-widget__send-btn--empty", canSend && "cortex-widget__send-btn--ready"),
1479
+ disabled: !canSend,
1480
+ children: /* @__PURE__ */ jsxDEV2("svg", {
1481
+ width: "14",
1482
+ height: "14",
1483
+ viewBox: "0 0 16 16",
1484
+ fill: "none",
1485
+ className: "cortex-widget__send-icon",
1486
+ children: /* @__PURE__ */ jsxDEV2("path", {
1487
+ d: "M3 8h10M9 4l4 4-4 4",
1488
+ stroke: "currentColor",
1489
+ strokeWidth: "1.5",
1490
+ strokeLinecap: "round",
1491
+ strokeLinejoin: "round"
1492
+ }, undefined, false, undefined, this)
1493
+ }, undefined, false, undefined, this)
1494
+ }, undefined, false, undefined, this)
1495
+ ]
1496
+ }, undefined, true, undefined, this)
1497
+ ]
1498
+ }, undefined, true, undefined, this)
1499
+ ]
1500
+ }, undefined, true, undefined, this);
1501
+ });
1502
+
1503
+ // src/components/MessageList.tsx
1504
+ import { useEffect as useEffect5, useRef as useRef7, useState as useState8 } from "react";
1505
+
1506
+ // src/components/MessageAbortedFlag.tsx
1507
+ import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
1508
+ function MessageAbortedFlag() {
1509
+ const { t } = useCortex();
1510
+ return /* @__PURE__ */ jsxDEV3("div", {
1511
+ className: "cortex-aborted-flag",
1512
+ children: [
1513
+ /* @__PURE__ */ jsxDEV3("span", {
1514
+ className: "cortex-aborted-flag__line"
1515
+ }, undefined, false, undefined, this),
1516
+ /* @__PURE__ */ jsxDEV3("span", {
1517
+ className: "cortex-aborted-flag__label",
1518
+ children: [
1519
+ /* @__PURE__ */ jsxDEV3("svg", {
1520
+ className: "cortex-aborted-flag__icon",
1521
+ width: "12",
1522
+ height: "12",
1523
+ viewBox: "0 0 12 12",
1524
+ fill: "none",
1525
+ children: /* @__PURE__ */ jsxDEV3("path", {
1526
+ d: "M6 1.5v5M6 8.75v.5",
1527
+ stroke: "currentColor",
1528
+ strokeWidth: "1.4",
1529
+ strokeLinecap: "round"
1530
+ }, undefined, false, undefined, this)
1531
+ }, undefined, false, undefined, this),
1532
+ t("translate_aborted")
1533
+ ]
1534
+ }, undefined, true, undefined, this),
1535
+ /* @__PURE__ */ jsxDEV3("span", {
1536
+ className: "cortex-aborted-flag__line"
1537
+ }, undefined, false, undefined, this)
1538
+ ]
1539
+ }, undefined, true, undefined, this);
1540
+ }
1541
+
1542
+ // src/components/MessageAttachments.tsx
1543
+ import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
1544
+ function MessageAttachments(props) {
1545
+ const { api, t } = useCortex();
1546
+ async function download(id) {
1547
+ const { blob, name } = await api.downloadAttachment(id);
1548
+ saveBlob(blob, name);
1549
+ }
1550
+ return /* @__PURE__ */ jsxDEV4("div", {
1551
+ className: "cortex-message-attachments",
1552
+ children: props.attachments.map((attachment) => /* @__PURE__ */ jsxDEV4("button", {
1553
+ type: "button",
1554
+ onClick: () => void download(attachment.id),
1555
+ className: "cortex-message-attachment",
1556
+ "aria-label": `${t("translate_download")}: ${attachment.filename}`,
1557
+ children: [
1558
+ /* @__PURE__ */ jsxDEV4("svg", {
1559
+ viewBox: "0 0 16 16",
1560
+ className: "cortex-message-attachment__icon",
1561
+ fill: "none",
1562
+ children: [
1563
+ /* @__PURE__ */ jsxDEV4("path", {
1564
+ d: "M4 1.5h5.172a2 2 0 0 1 1.414.586l2.328 2.328a2 2 0 0 1 .586 1.414V12.5a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-9a2 2 0 0 1 2-2Z",
1565
+ stroke: "currentColor",
1566
+ strokeWidth: "1.25"
1567
+ }, undefined, false, undefined, this),
1568
+ /* @__PURE__ */ jsxDEV4("path", {
1569
+ d: "M9.5 1.5v2a2 2 0 0 0 2 2h2",
1570
+ stroke: "currentColor",
1571
+ strokeWidth: "1.25",
1572
+ strokeLinecap: "round"
1573
+ }, undefined, false, undefined, this)
1574
+ ]
1575
+ }, undefined, true, undefined, this),
1576
+ /* @__PURE__ */ jsxDEV4("span", {
1577
+ className: "cortex-message-attachment__name",
1578
+ children: attachment.filename
1579
+ }, undefined, false, undefined, this),
1580
+ /* @__PURE__ */ jsxDEV4("svg", {
1581
+ viewBox: "0 0 16 16",
1582
+ className: "cortex-message-attachment__dl-icon",
1583
+ fill: "none",
1584
+ children: /* @__PURE__ */ jsxDEV4("path", {
1585
+ d: "M8 3v7m0 0L5.5 7.5M8 10l2.5-2.5M3 13h10",
1586
+ stroke: "currentColor",
1587
+ strokeWidth: "1.5",
1588
+ strokeLinecap: "round",
1589
+ strokeLinejoin: "round"
1590
+ }, undefined, false, undefined, this)
1591
+ }, undefined, false, undefined, this)
1592
+ ]
1593
+ }, attachment.id, true, undefined, this))
1594
+ }, undefined, false, undefined, this);
1595
+ }
1596
+
1597
+ // src/components/MessageLlmInspector.tsx
1598
+ import { useRef as useRef4, useState as useState4 } from "react";
1599
+
1600
+ // src/components/CopyButton.tsx
1601
+ import { useRef as useRef3, useState as useState2 } from "react";
1602
+ import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
1603
+ function CopyButton({ value, className }) {
1604
+ const [copied, setCopied] = useState2(false);
1605
+ const resetTimer = useRef3(null);
1606
+ async function copy(event) {
1607
+ event.stopPropagation();
1608
+ event.preventDefault();
1609
+ try {
1610
+ await navigator.clipboard.writeText(value);
1611
+ setCopied(true);
1612
+ if (resetTimer.current)
1613
+ clearTimeout(resetTimer.current);
1614
+ resetTimer.current = setTimeout(() => setCopied(false), 1500);
1615
+ } catch {}
1616
+ }
1617
+ return /* @__PURE__ */ jsxDEV5("span", {
1618
+ className: cx("cortex-copy-btn", className),
1619
+ children: /* @__PURE__ */ jsxDEV5("button", {
1620
+ className: cx("cortex-copy-btn__button", copied && "cortex-copy-btn__button--copied"),
1621
+ onClick: (event) => void copy(event),
1622
+ "aria-label": copied ? "Copied" : "Copy to clipboard",
1623
+ type: "button",
1624
+ children: copied ? /* @__PURE__ */ jsxDEV5("svg", {
1625
+ className: "cortex-copy-btn__icon cortex-copy-btn__icon--check",
1626
+ width: "13",
1627
+ height: "13",
1628
+ viewBox: "0 0 24 24",
1629
+ fill: "none",
1630
+ children: /* @__PURE__ */ jsxDEV5("path", {
1631
+ d: "M5 13l4 4L19 7",
1632
+ stroke: "currentColor",
1633
+ strokeWidth: "2.5",
1634
+ strokeLinecap: "round",
1635
+ strokeLinejoin: "round"
1636
+ }, undefined, false, undefined, this)
1637
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV5("svg", {
1638
+ className: "cortex-copy-btn__icon",
1639
+ width: "13",
1640
+ height: "13",
1641
+ viewBox: "0 0 24 24",
1642
+ fill: "none",
1643
+ children: [
1644
+ /* @__PURE__ */ jsxDEV5("rect", {
1645
+ x: "9",
1646
+ y: "9",
1647
+ width: "12",
1648
+ height: "12",
1649
+ rx: "2",
1650
+ stroke: "currentColor",
1651
+ strokeWidth: "2"
1652
+ }, undefined, false, undefined, this),
1653
+ /* @__PURE__ */ jsxDEV5("path", {
1654
+ d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1",
1655
+ stroke: "currentColor",
1656
+ strokeWidth: "2",
1657
+ strokeLinecap: "round"
1658
+ }, undefined, false, undefined, this)
1659
+ ]
1660
+ }, undefined, true, undefined, this)
1661
+ }, undefined, false, undefined, this)
1662
+ }, undefined, false, undefined, this);
1663
+ }
1664
+
1665
+ // src/components/JsonTree.tsx
1666
+ import { useMemo as useMemo2, useState as useState3 } from "react";
1667
+ import { jsxDEV as jsxDEV6, Fragment } from "react/jsx-dev-runtime";
1668
+ function JsonTree({ data, expandDepth = 1, className }) {
1669
+ const parsedData = useMemo2(() => deepParseJson(data), [data]);
1670
+ const [userToggled, setUserToggled] = useState3({});
1671
+ function isCollapsed(path, depth) {
1672
+ return userToggled[path] ?? depth >= expandDepth;
1673
+ }
1674
+ function toggle(path, depth) {
1675
+ setUserToggled((current) => ({ ...current, [path]: !isCollapsed(path, depth) }));
1676
+ }
1677
+ return /* @__PURE__ */ jsxDEV6("div", {
1678
+ className: cx("cortex-json-tree", className),
1679
+ children: /* @__PURE__ */ jsxDEV6(JsonValue, {
1680
+ value: parsedData,
1681
+ path: "$",
1682
+ depth: 0,
1683
+ isCollapsed,
1684
+ toggle
1685
+ }, undefined, false, undefined, this)
1686
+ }, undefined, false, undefined, this);
1687
+ }
1688
+ function JsonValue({ value, path, depth, isCollapsed, toggle }) {
1689
+ const node = describeJsonValue(value, path);
1690
+ if (node.kind === "primitive")
1691
+ return /* @__PURE__ */ jsxDEV6("span", {
1692
+ className: node.className,
1693
+ children: node.text
1694
+ }, undefined, false, undefined, this);
1695
+ if (node.entries.length === 0) {
1696
+ return /* @__PURE__ */ jsxDEV6("span", {
1697
+ className: "jt-bracket",
1698
+ children: [
1699
+ node.open,
1700
+ node.close
1701
+ ]
1702
+ }, undefined, true, undefined, this);
1703
+ }
1704
+ const collapsed = isCollapsed(path, depth);
1705
+ function onToggle(event) {
1706
+ toggle(path, depth);
1707
+ event.stopPropagation();
1708
+ }
1709
+ return /* @__PURE__ */ jsxDEV6(Fragment, {
1710
+ children: [
1711
+ /* @__PURE__ */ jsxDEV6("span", {
1712
+ className: "jt-toggle",
1713
+ onClick: onToggle,
1714
+ role: "button",
1715
+ children: [
1716
+ /* @__PURE__ */ jsxDEV6("span", {
1717
+ className: cx("jt-arrow", collapsed && "jt-arrow--collapsed"),
1718
+ children: "▾"
1719
+ }, undefined, false, undefined, this),
1720
+ /* @__PURE__ */ jsxDEV6("span", {
1721
+ className: "jt-bracket",
1722
+ children: node.open
1723
+ }, undefined, false, undefined, this)
1724
+ ]
1725
+ }, undefined, true, undefined, this),
1726
+ collapsed ? /* @__PURE__ */ jsxDEV6(Fragment, {
1727
+ children: [
1728
+ /* @__PURE__ */ jsxDEV6("span", {
1729
+ className: "jt-collapsed-hint",
1730
+ onClick: onToggle,
1731
+ role: "button",
1732
+ children: node.summary
1733
+ }, undefined, false, undefined, this),
1734
+ /* @__PURE__ */ jsxDEV6("span", {
1735
+ className: "jt-bracket",
1736
+ children: node.close
1737
+ }, undefined, false, undefined, this)
1738
+ ]
1739
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV6(Fragment, {
1740
+ children: [
1741
+ /* @__PURE__ */ jsxDEV6("div", {
1742
+ className: "jt-indent",
1743
+ children: node.entries.map((entry, index) => /* @__PURE__ */ jsxDEV6("div", {
1744
+ className: "jt-line",
1745
+ children: [
1746
+ entry.key !== null && /* @__PURE__ */ jsxDEV6(Fragment, {
1747
+ children: [
1748
+ /* @__PURE__ */ jsxDEV6("span", {
1749
+ className: "jt-key",
1750
+ children: `"${entry.key}"`
1751
+ }, undefined, false, undefined, this),
1752
+ /* @__PURE__ */ jsxDEV6("span", {
1753
+ className: "jt-colon",
1754
+ children: ": "
1755
+ }, undefined, false, undefined, this)
1756
+ ]
1757
+ }, undefined, true, undefined, this),
1758
+ /* @__PURE__ */ jsxDEV6(JsonValue, {
1759
+ value: entry.value,
1760
+ path: entry.path,
1761
+ depth: depth + 1,
1762
+ isCollapsed,
1763
+ toggle
1764
+ }, undefined, false, undefined, this),
1765
+ index < node.entries.length - 1 && /* @__PURE__ */ jsxDEV6("span", {
1766
+ className: "jt-comma",
1767
+ children: ","
1768
+ }, undefined, false, undefined, this)
1769
+ ]
1770
+ }, entry.path, true, undefined, this))
1771
+ }, undefined, false, undefined, this),
1772
+ /* @__PURE__ */ jsxDEV6("span", {
1773
+ className: "jt-bracket",
1774
+ children: node.close
1775
+ }, undefined, false, undefined, this)
1776
+ ]
1777
+ }, undefined, true, undefined, this)
1778
+ ]
1779
+ }, undefined, true, undefined, this);
1780
+ }
1781
+
1782
+ // src/format.ts
1783
+ function num(value) {
1784
+ return value.toLocaleString("en-US");
1785
+ }
1786
+
1787
+ // src/components/LlmUsageBreakdown.tsx
1788
+ import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
1789
+ function LlmUsageBreakdown({ usage }) {
1790
+ const { t } = useCortex();
1791
+ return /* @__PURE__ */ jsxDEV7("div", {
1792
+ className: "cortex-llm-inspector__usage-rows",
1793
+ children: [
1794
+ /* @__PURE__ */ jsxDEV7("div", {
1795
+ className: "cortex-llm-inspector__usage-row",
1796
+ children: [
1797
+ /* @__PURE__ */ jsxDEV7("span", {
1798
+ className: "cortex-llm-inspector__usage-lbl",
1799
+ children: t("translate_input")
1800
+ }, undefined, false, undefined, this),
1801
+ /* @__PURE__ */ jsxDEV7("span", {
1802
+ className: "cortex-llm-inspector__usage-val",
1803
+ children: num(usage.input.total)
1804
+ }, undefined, false, undefined, this),
1805
+ /* @__PURE__ */ jsxDEV7("span", {
1806
+ className: "cortex-llm-inspector__usage-detail",
1807
+ children: [
1808
+ t("translate_fresh"),
1809
+ " ",
1810
+ num(usage.input.noCache),
1811
+ " · ",
1812
+ t("translate_read"),
1813
+ " ",
1814
+ num(usage.input.cacheRead),
1815
+ " · ",
1816
+ t("translate_write"),
1817
+ " ",
1818
+ num(usage.input.cacheWrite)
1819
+ ]
1820
+ }, undefined, true, undefined, this)
1821
+ ]
1822
+ }, undefined, true, undefined, this),
1823
+ /* @__PURE__ */ jsxDEV7("div", {
1824
+ className: "cortex-llm-inspector__usage-row",
1825
+ children: [
1826
+ /* @__PURE__ */ jsxDEV7("span", {
1827
+ className: "cortex-llm-inspector__usage-lbl",
1828
+ children: t("translate_output")
1829
+ }, undefined, false, undefined, this),
1830
+ /* @__PURE__ */ jsxDEV7("span", {
1831
+ className: "cortex-llm-inspector__usage-val",
1832
+ children: num(usage.output.total)
1833
+ }, undefined, false, undefined, this),
1834
+ /* @__PURE__ */ jsxDEV7("span", {
1835
+ className: "cortex-llm-inspector__usage-detail",
1836
+ children: [
1837
+ t("translate_text"),
1838
+ " ",
1839
+ num(usage.output.text),
1840
+ " · ",
1841
+ t("translate_reasoning"),
1842
+ " ",
1843
+ num(usage.output.reasoning)
1844
+ ]
1845
+ }, undefined, true, undefined, this)
1846
+ ]
1847
+ }, undefined, true, undefined, this),
1848
+ /* @__PURE__ */ jsxDEV7("div", {
1849
+ className: "cortex-llm-inspector__usage-row cortex-llm-inspector__usage-row--total",
1850
+ children: [
1851
+ /* @__PURE__ */ jsxDEV7("span", {
1852
+ className: "cortex-llm-inspector__usage-lbl",
1853
+ children: t("translate_total")
1854
+ }, undefined, false, undefined, this),
1855
+ /* @__PURE__ */ jsxDEV7("span", {
1856
+ className: "cortex-llm-inspector__usage-val",
1857
+ children: num(usage.total)
1858
+ }, undefined, false, undefined, this)
1859
+ ]
1860
+ }, undefined, true, undefined, this)
1861
+ ]
1862
+ }, undefined, true, undefined, this);
1863
+ }
1864
+
1865
+ // src/components/LlmUsageChips.tsx
1866
+ import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
1867
+ function LlmUsageChips({ usage }) {
1868
+ const percent = cachePercent(usage);
1869
+ return /* @__PURE__ */ jsxDEV8("span", {
1870
+ children: /* @__PURE__ */ jsxDEV8("span", {
1871
+ className: "cortex-llm-inspector__step-metrics",
1872
+ children: [
1873
+ /* @__PURE__ */ jsxDEV8("span", {
1874
+ className: "cortex-llm-inspector__metric",
1875
+ children: [
1876
+ /* @__PURE__ */ jsxDEV8("span", {
1877
+ className: "cortex-llm-inspector__dot cortex-llm-inspector__dot--input"
1878
+ }, undefined, false, undefined, this),
1879
+ num(usage.input.total)
1880
+ ]
1881
+ }, undefined, true, undefined, this),
1882
+ /* @__PURE__ */ jsxDEV8("span", {
1883
+ className: "cortex-llm-inspector__metric",
1884
+ children: [
1885
+ /* @__PURE__ */ jsxDEV8("span", {
1886
+ className: "cortex-llm-inspector__dot cortex-llm-inspector__dot--output"
1887
+ }, undefined, false, undefined, this),
1888
+ num(usage.output.total)
1889
+ ]
1890
+ }, undefined, true, undefined, this),
1891
+ percent !== null ? /* @__PURE__ */ jsxDEV8("span", {
1892
+ className: "cortex-llm-inspector__cache-pct",
1893
+ children: [
1894
+ percent,
1895
+ "%"
1896
+ ]
1897
+ }, undefined, true, undefined, this) : null
1898
+ ]
1899
+ }, undefined, true, undefined, this)
1900
+ }, undefined, false, undefined, this);
1901
+ }
1902
+
1903
+ // src/components/MessageLlmInspector.tsx
1904
+ import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
1905
+ function MessageLlmInspector({ messageId }) {
1906
+ const { t, api } = useCortex();
1907
+ const [open, setOpen] = useState4(false);
1908
+ const [loading, setLoading] = useState4(false);
1909
+ const [requests, setRequests] = useState4([]);
1910
+ const [expandedStep, setExpandedStep] = useState4(null);
1911
+ const [activeTab, setActiveTab] = useState4({});
1912
+ const loaded = useRef4(false);
1913
+ async function toggle() {
1914
+ if (!loaded.current) {
1915
+ setLoading(true);
1916
+ try {
1917
+ setRequests(await api.listLlmRequests(messageId));
1918
+ } finally {
1919
+ setLoading(false);
1920
+ loaded.current = true;
1921
+ }
1922
+ }
1923
+ setOpen((v) => !v);
1924
+ }
1925
+ function toggleStep(id) {
1926
+ setExpandedStep((current) => current === id ? null : id);
1927
+ }
1928
+ function getTab(id) {
1929
+ return activeTab[id] ?? "prompt";
1930
+ }
1931
+ function setTab(id, tab) {
1932
+ setActiveTab((current) => ({ ...current, [id]: tab }));
1933
+ }
1934
+ return /* @__PURE__ */ jsxDEV9("div", {
1935
+ className: cx("cortex-llm-inspector", open && "cortex-llm-inspector--open"),
1936
+ children: [
1937
+ /* @__PURE__ */ jsxDEV9("button", {
1938
+ className: "cortex-llm-inspector__trigger",
1939
+ onClick: () => void toggle(),
1940
+ children: [
1941
+ /* @__PURE__ */ jsxDEV9("svg", {
1942
+ className: "cortex-llm-inspector__icon",
1943
+ width: "14",
1944
+ height: "14",
1945
+ viewBox: "0 0 16 16",
1946
+ fill: "none",
1947
+ children: /* @__PURE__ */ jsxDEV9("path", {
1948
+ d: "M6 2a4 4 0 1 0 0 8 4 4 0 0 0 0-8ZM0 6a6 6 0 1 1 10.89 3.477l4.817 4.816a1 1 0 0 1-1.414 1.414l-4.816-4.816A6 6 0 0 1 0 6Z",
1949
+ fill: "currentColor"
1950
+ }, undefined, false, undefined, this)
1951
+ }, undefined, false, undefined, this),
1952
+ /* @__PURE__ */ jsxDEV9("span", {
1953
+ children: t("translate_inspect_llm_requests")
1954
+ }, undefined, false, undefined, this),
1955
+ loading ? /* @__PURE__ */ jsxDEV9("span", {
1956
+ className: "cortex-llm-inspector__loading",
1957
+ children: t("translate_loading")
1958
+ }, undefined, false, undefined, this) : requests.length > 0 ? /* @__PURE__ */ jsxDEV9("span", {
1959
+ className: "cortex-llm-inspector__badge",
1960
+ children: requests.length
1961
+ }, undefined, false, undefined, this) : null,
1962
+ /* @__PURE__ */ jsxDEV9("svg", {
1963
+ className: "cortex-llm-inspector__chevron",
1964
+ width: "12",
1965
+ height: "12",
1966
+ viewBox: "0 0 12 12",
1967
+ fill: "none",
1968
+ children: /* @__PURE__ */ jsxDEV9("path", {
1969
+ d: "M3 4.5L6 7.5L9 4.5",
1970
+ stroke: "currentColor",
1971
+ strokeWidth: "1.25",
1972
+ strokeLinecap: "round",
1973
+ strokeLinejoin: "round"
1974
+ }, undefined, false, undefined, this)
1975
+ }, undefined, false, undefined, this)
1976
+ ]
1977
+ }, undefined, true, undefined, this),
1978
+ /* @__PURE__ */ jsxDEV9("div", {
1979
+ className: "cortex-llm-inspector__panel-wrapper",
1980
+ children: /* @__PURE__ */ jsxDEV9("div", {
1981
+ className: "cortex-llm-inspector__panel-inner",
1982
+ children: /* @__PURE__ */ jsxDEV9("div", {
1983
+ className: "cortex-llm-inspector__panel",
1984
+ children: [
1985
+ requests.length === 0 && !loading ? /* @__PURE__ */ jsxDEV9("div", {
1986
+ className: "cortex-llm-inspector__empty",
1987
+ children: t("translate_no_llm_requests")
1988
+ }, undefined, false, undefined, this) : null,
1989
+ requests.map((req, idx) => /* @__PURE__ */ jsxDEV9("div", {
1990
+ className: cx("cortex-llm-inspector__step", expandedStep === req.id && "cortex-llm-inspector__step--expanded"),
1991
+ children: [
1992
+ /* @__PURE__ */ jsxDEV9("button", {
1993
+ className: "cortex-llm-inspector__step-header",
1994
+ onClick: () => toggleStep(req.id),
1995
+ children: [
1996
+ /* @__PURE__ */ jsxDEV9("span", {
1997
+ className: "cortex-llm-inspector__step-label",
1998
+ children: t("translate_step_n", { number: idx + 1 })
1999
+ }, undefined, false, undefined, this),
2000
+ req.tokenUsage ? /* @__PURE__ */ jsxDEV9(LlmUsageChips, {
2001
+ usage: req.tokenUsage
2002
+ }, undefined, false, undefined, this) : null,
2003
+ /* @__PURE__ */ jsxDEV9("svg", {
2004
+ className: "cortex-llm-inspector__step-chevron",
2005
+ width: "10",
2006
+ height: "10",
2007
+ viewBox: "0 0 12 12",
2008
+ fill: "none",
2009
+ children: /* @__PURE__ */ jsxDEV9("path", {
2010
+ d: "M3 4.5L6 7.5L9 4.5",
2011
+ stroke: "currentColor",
2012
+ strokeWidth: "1.25",
2013
+ strokeLinecap: "round",
2014
+ strokeLinejoin: "round"
2015
+ }, undefined, false, undefined, this)
2016
+ }, undefined, false, undefined, this)
2017
+ ]
2018
+ }, undefined, true, undefined, this),
2019
+ /* @__PURE__ */ jsxDEV9("div", {
2020
+ className: "cortex-llm-inspector__step-body-wrapper",
2021
+ children: /* @__PURE__ */ jsxDEV9("div", {
2022
+ className: "cortex-llm-inspector__step-body-inner",
2023
+ children: /* @__PURE__ */ jsxDEV9("div", {
2024
+ className: "cortex-llm-inspector__step-body",
2025
+ children: [
2026
+ req.tokenUsage ? /* @__PURE__ */ jsxDEV9(LlmUsageBreakdown, {
2027
+ usage: req.tokenUsage
2028
+ }, undefined, false, undefined, this) : null,
2029
+ /* @__PURE__ */ jsxDEV9("div", {
2030
+ className: "cortex-llm-inspector__tabs",
2031
+ children: [
2032
+ /* @__PURE__ */ jsxDEV9("button", {
2033
+ className: cx("cortex-llm-inspector__tab", getTab(req.id) === "prompt" && "cortex-llm-inspector__tab--active"),
2034
+ onClick: () => setTab(req.id, "prompt"),
2035
+ children: t("translate_request")
2036
+ }, undefined, false, undefined, this),
2037
+ /* @__PURE__ */ jsxDEV9("button", {
2038
+ className: cx("cortex-llm-inspector__tab", getTab(req.id) === "response" && "cortex-llm-inspector__tab--active"),
2039
+ onClick: () => setTab(req.id, "response"),
2040
+ children: t("translate_response")
2041
+ }, undefined, false, undefined, this)
2042
+ ]
2043
+ }, undefined, true, undefined, this),
2044
+ /* @__PURE__ */ jsxDEV9("div", {
2045
+ className: "cortex-llm-inspector__json-pane",
2046
+ children: [
2047
+ /* @__PURE__ */ jsxDEV9(CopyButton, {
2048
+ className: "cortex-llm-inspector__json-copy",
2049
+ value: getTab(req.id) === "prompt" ? prettyJsonText(req.prompt) : prettyJsonText(req.output)
2050
+ }, undefined, false, undefined, this),
2051
+ getTab(req.id) === "prompt" ? /* @__PURE__ */ jsxDEV9(JsonTree, {
2052
+ data: parseJsonText(req.prompt),
2053
+ expandDepth: 2
2054
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV9(JsonTree, {
2055
+ data: parseJsonText(req.output),
2056
+ expandDepth: 2
2057
+ }, undefined, false, undefined, this)
2058
+ ]
2059
+ }, undefined, true, undefined, this)
2060
+ ]
2061
+ }, undefined, true, undefined, this)
2062
+ }, undefined, false, undefined, this)
2063
+ }, undefined, false, undefined, this)
2064
+ ]
2065
+ }, req.id, true, undefined, this))
2066
+ ]
2067
+ }, undefined, true, undefined, this)
2068
+ }, undefined, false, undefined, this)
2069
+ }, undefined, false, undefined, this)
2070
+ ]
2071
+ }, undefined, true, undefined, this);
2072
+ }
2073
+
2074
+ // src/components/SubtleActivity.tsx
2075
+ import { useEffect as useEffect3, useRef as useRef5, useState as useState5 } from "react";
2076
+ import { jsxDEV as jsxDEV10 } from "react/jsx-dev-runtime";
2077
+ function SubtleActivity({ labels, className }) {
2078
+ const { t } = useCortex();
2079
+ const [currentIndex, setCurrentIndex] = useState5(0);
2080
+ const [labelState, setLabelState] = useState5("idle");
2081
+ const labelCount = useRef5(labels.length);
2082
+ labelCount.current = labels.length;
2083
+ useEffect3(() => {
2084
+ let timeout;
2085
+ let frame;
2086
+ function scheduleNextTransition() {
2087
+ timeout = setTimeout(() => {
2088
+ setLabelState("exiting");
2089
+ timeout = setTimeout(() => {
2090
+ setCurrentIndex((i) => (i + 1) % labelCount.current);
2091
+ setLabelState("enter-start");
2092
+ frame = requestAnimationFrame(() => {
2093
+ setLabelState("entering");
2094
+ timeout = setTimeout(() => {
2095
+ setLabelState("idle");
2096
+ scheduleNextTransition();
2097
+ }, 300);
2098
+ });
2099
+ }, 300);
2100
+ }, 2000);
2101
+ }
2102
+ scheduleNextTransition();
2103
+ return () => {
2104
+ if (timeout)
2105
+ clearTimeout(timeout);
2106
+ if (frame)
2107
+ cancelAnimationFrame(frame);
2108
+ };
2109
+ }, []);
2110
+ return /* @__PURE__ */ jsxDEV10("div", {
2111
+ className: cx("cortex-subtle-activity", className),
2112
+ children: [
2113
+ /* @__PURE__ */ jsxDEV10("div", {
2114
+ className: "cortex-subtle-activity__dots",
2115
+ children: [
2116
+ /* @__PURE__ */ jsxDEV10("span", {
2117
+ className: "cortex-subtle-activity__dot"
2118
+ }, undefined, false, undefined, this),
2119
+ /* @__PURE__ */ jsxDEV10("span", {
2120
+ className: "cortex-subtle-activity__dot cortex-subtle-activity__dot--d1"
2121
+ }, undefined, false, undefined, this),
2122
+ /* @__PURE__ */ jsxDEV10("span", {
2123
+ className: "cortex-subtle-activity__dot cortex-subtle-activity__dot--d2"
2124
+ }, undefined, false, undefined, this)
2125
+ ]
2126
+ }, undefined, true, undefined, this),
2127
+ /* @__PURE__ */ jsxDEV10("div", {
2128
+ className: "cortex-subtle-activity__label-mask",
2129
+ children: /* @__PURE__ */ jsxDEV10("span", {
2130
+ className: cx("cortex-subtle-activity__label", `cortex-subtle-activity__label--${labelState}`),
2131
+ children: t(labels[currentIndex])
2132
+ }, undefined, false, undefined, this)
2133
+ }, undefined, false, undefined, this)
2134
+ ]
2135
+ }, undefined, true, undefined, this);
2136
+ }
2137
+
2138
+ // src/components/MessageReasoningAnimated.tsx
2139
+ import { jsxDEV as jsxDEV11 } from "react/jsx-dev-runtime";
2140
+ var LABELS = activityLabelKeys("reasoning");
2141
+ function MessageReasoningAnimated() {
2142
+ return /* @__PURE__ */ jsxDEV11("div", {
2143
+ className: "cortex-reasoning-animated",
2144
+ children: /* @__PURE__ */ jsxDEV11(SubtleActivity, {
2145
+ labels: LABELS
2146
+ }, undefined, false, undefined, this)
2147
+ }, undefined, false, undefined, this);
2148
+ }
2149
+
2150
+ // src/components/MessageReasoningPart.tsx
2151
+ import { jsxDEV as jsxDEV12 } from "react/jsx-dev-runtime";
2152
+ function MessageReasoningPart(props) {
2153
+ const { reasoningPart, streaming = false } = props;
2154
+ const { t } = useCortex();
2155
+ return /* @__PURE__ */ jsxDEV12("details", {
2156
+ className: "cortex-reasoning-details",
2157
+ children: [
2158
+ /* @__PURE__ */ jsxDEV12("summary", {
2159
+ className: "cortex-reasoning-details__summary",
2160
+ children: [
2161
+ /* @__PURE__ */ jsxDEV12("div", {
2162
+ className: "cortex-reasoning-details__header",
2163
+ children: [
2164
+ /* @__PURE__ */ jsxDEV12("span", {
2165
+ className: "cortex-reasoning-details__icon",
2166
+ children: /* @__PURE__ */ jsxDEV12("svg", {
2167
+ width: "14",
2168
+ height: "14",
2169
+ viewBox: "0 0 20 20",
2170
+ fill: "none",
2171
+ "aria-hidden": "true",
2172
+ children: [
2173
+ /* @__PURE__ */ jsxDEV12("path", {
2174
+ d: "M10 2C6.686 2 4 4.686 4 8c0 1.655.672 3.154 1.757 4.243.362.363.576.858.576 1.371V14.5a1 1 0 0 0 1 1h5.334a1 1 0 0 0 1-1v-.886c0-.513.214-1.008.576-1.371A5.978 5.978 0 0 0 16 8c0-3.314-2.686-6-6-6Z",
2175
+ stroke: "currentColor",
2176
+ strokeWidth: "1.4",
2177
+ strokeLinecap: "round",
2178
+ strokeLinejoin: "round"
2179
+ }, undefined, false, undefined, this),
2180
+ /* @__PURE__ */ jsxDEV12("path", {
2181
+ d: "M7.5 17.5h5M8.5 8a2 2 0 0 1 2-2",
2182
+ stroke: "currentColor",
2183
+ strokeWidth: "1.4",
2184
+ strokeLinecap: "round",
2185
+ strokeLinejoin: "round"
2186
+ }, undefined, false, undefined, this)
2187
+ ]
2188
+ }, undefined, true, undefined, this)
2189
+ }, undefined, false, undefined, this),
2190
+ /* @__PURE__ */ jsxDEV12("div", {
2191
+ className: "cortex-reasoning-details__title-group",
2192
+ children: /* @__PURE__ */ jsxDEV12("div", {
2193
+ className: "cortex-reasoning-details__title-row",
2194
+ children: [
2195
+ /* @__PURE__ */ jsxDEV12("div", {
2196
+ className: "cortex-reasoning-details__title",
2197
+ children: t("translate_reasoning")
2198
+ }, undefined, false, undefined, this),
2199
+ /* @__PURE__ */ jsxDEV12("span", {
2200
+ className: cx("cortex-reasoning-details__badge", streaming ? "cortex-reasoning-details__badge--streaming" : "cortex-reasoning-details__badge--done"),
2201
+ children: streaming ? "Streaming" : "Done"
2202
+ }, undefined, false, undefined, this)
2203
+ ]
2204
+ }, undefined, true, undefined, this)
2205
+ }, undefined, false, undefined, this)
2206
+ ]
2207
+ }, undefined, true, undefined, this),
2208
+ /* @__PURE__ */ jsxDEV12("span", {
2209
+ className: "cortex-reasoning-details__chevron",
2210
+ "aria-hidden": "true",
2211
+ children: /* @__PURE__ */ jsxDEV12("svg", {
2212
+ width: "14",
2213
+ height: "14",
2214
+ viewBox: "0 0 20 20",
2215
+ fill: "none",
2216
+ children: /* @__PURE__ */ jsxDEV12("path", {
2217
+ d: "m5.75 8.25 4.25 4.25 4.25-4.25",
2218
+ stroke: "currentColor",
2219
+ strokeWidth: "1.5",
2220
+ strokeLinecap: "round",
2221
+ strokeLinejoin: "round"
2222
+ }, undefined, false, undefined, this)
2223
+ }, undefined, false, undefined, this)
2224
+ }, undefined, false, undefined, this)
2225
+ ]
2226
+ }, undefined, true, undefined, this),
2227
+ /* @__PURE__ */ jsxDEV12("div", {
2228
+ className: "cortex-reasoning-details__body",
2229
+ children: /* @__PURE__ */ jsxDEV12("div", {
2230
+ className: "cortex-reasoning-details__content",
2231
+ children: /* @__PURE__ */ jsxDEV12("pre", {
2232
+ className: "cortex-reasoning-details__pre",
2233
+ children: reasoningPart.content.trim() ? reasoningPart.content : "No reasoning provided."
2234
+ }, undefined, false, undefined, this)
2235
+ }, undefined, false, undefined, this)
2236
+ }, undefined, false, undefined, this)
2237
+ ]
2238
+ }, undefined, true, undefined, this);
2239
+ }
2240
+
2241
+ // src/components/MessageTextPart.tsx
2242
+ import { useEffect as useEffect4, useRef as useRef6, useState as useState6 } from "react";
2243
+ import { jsxDEV as jsxDEV13 } from "react/jsx-dev-runtime";
2244
+ function MessageTextPart(props) {
2245
+ const { role, textPart, streaming = false } = props;
2246
+ const initialText = role === "assistant" && streaming ? "" : textPart.content;
2247
+ const [displayedText, setDisplayedText] = useState6(initialText);
2248
+ const displayedTextRef = useRef6(initialText);
2249
+ const smootherRef = useRef6(null);
2250
+ const isFirstRenderRef = useRef6(true);
2251
+ useEffect4(() => {
2252
+ function setText(text) {
2253
+ displayedTextRef.current = text;
2254
+ setDisplayedText(text);
2255
+ }
2256
+ if (role !== "assistant" || !streaming) {
2257
+ smootherRef.current?.destroy();
2258
+ smootherRef.current = null;
2259
+ setText(textPart.content);
2260
+ isFirstRenderRef.current = false;
2261
+ return;
2262
+ }
2263
+ if (!smootherRef.current) {
2264
+ smootherRef.current = new StreamTextSmoother(setText);
2265
+ smootherRef.current.seed(displayedTextRef.current);
2266
+ }
2267
+ if (isFirstRenderRef.current) {
2268
+ isFirstRenderRef.current = false;
2269
+ smootherRef.current.seed(textPart.content);
2270
+ return;
2271
+ }
2272
+ smootherRef.current.update(textPart.content, false);
2273
+ }, [role, streaming, textPart]);
2274
+ useEffect4(() => () => {
2275
+ smootherRef.current?.destroy();
2276
+ smootherRef.current = null;
2277
+ }, []);
2278
+ return /* @__PURE__ */ jsxDEV13("div", {
2279
+ className: cx("cortex-text-part", role === "assistant" && "cortex-text-part--assistant", role === "user" && "cortex-text-part--user"),
2280
+ children: /* @__PURE__ */ jsxDEV13("div", {
2281
+ className: cx("cortex-text-bubble", role === "assistant" && "cortex-text-bubble--assistant", role === "user" && "cortex-text-bubble--user"),
2282
+ dangerouslySetInnerHTML: { __html: renderMarkdown(displayedText) }
2283
+ }, undefined, false, undefined, this)
2284
+ }, undefined, false, undefined, this);
2285
+ }
2286
+
2287
+ // src/components/MessageToolCallOutcome.tsx
2288
+ import { jsxDEV as jsxDEV14 } from "react/jsx-dev-runtime";
2289
+ function MessageToolCallOutcome({ toolCallPart }) {
2290
+ const { t } = useCortex();
2291
+ const { state, approval } = toolCallPart;
2292
+ const output = toolCallPart.output;
2293
+ const outputText = toolCallOutputText(toolCallPart);
2294
+ function section() {
2295
+ if (state === "complete") {
2296
+ return /* @__PURE__ */ jsxDEV14("div", {
2297
+ className: "dbg-tool__section dbg-tool__section--success",
2298
+ children: [
2299
+ /* @__PURE__ */ jsxDEV14("div", {
2300
+ className: "dbg-tool__section-bar",
2301
+ children: [
2302
+ /* @__PURE__ */ jsxDEV14("span", {
2303
+ className: "dbg-tool__section-label dbg-tool__section-label--success",
2304
+ children: t("translate_output")
2305
+ }, undefined, false, undefined, this),
2306
+ /* @__PURE__ */ jsxDEV14("span", {
2307
+ className: "dbg-tool__section-lang",
2308
+ children: "json"
2309
+ }, undefined, false, undefined, this),
2310
+ /* @__PURE__ */ jsxDEV14(CopyButton, {
2311
+ value: outputText
2312
+ }, undefined, false, undefined, this)
2313
+ ]
2314
+ }, undefined, true, undefined, this),
2315
+ /* @__PURE__ */ jsxDEV14("div", {
2316
+ dir: "ltr",
2317
+ className: "dbg-tool__tree",
2318
+ children: /* @__PURE__ */ jsxDEV14(JsonTree, {
2319
+ data: output,
2320
+ expandDepth: 2
2321
+ }, undefined, false, undefined, this)
2322
+ }, undefined, false, undefined, this)
2323
+ ]
2324
+ }, undefined, true, undefined, this);
2325
+ }
2326
+ if (state === "error") {
2327
+ return /* @__PURE__ */ jsxDEV14("div", {
2328
+ className: "dbg-tool__section dbg-tool__section--error",
2329
+ children: [
2330
+ /* @__PURE__ */ jsxDEV14("div", {
2331
+ className: "dbg-tool__section-bar",
2332
+ children: [
2333
+ /* @__PURE__ */ jsxDEV14("span", {
2334
+ className: "dbg-tool__section-label dbg-tool__section-label--error",
2335
+ children: t("translate_error")
2336
+ }, undefined, false, undefined, this),
2337
+ /* @__PURE__ */ jsxDEV14(CopyButton, {
2338
+ value: outputText
2339
+ }, undefined, false, undefined, this)
2340
+ ]
2341
+ }, undefined, true, undefined, this),
2342
+ /* @__PURE__ */ jsxDEV14("pre", {
2343
+ dir: "ltr",
2344
+ className: "dbg-tool__error-pre",
2345
+ children: outputText
2346
+ }, undefined, false, undefined, this)
2347
+ ]
2348
+ }, undefined, true, undefined, this);
2349
+ }
2350
+ if (state === "approval-requested") {
2351
+ return /* @__PURE__ */ jsxDEV14("div", {
2352
+ className: "dbg-tool__section dbg-tool__section--approval",
2353
+ children: [
2354
+ /* @__PURE__ */ jsxDEV14("div", {
2355
+ className: "dbg-tool__section-bar",
2356
+ children: [
2357
+ /* @__PURE__ */ jsxDEV14("span", {
2358
+ className: "dbg-tool__section-label dbg-tool__section-label--approval",
2359
+ children: t("translate_approval_requested")
2360
+ }, undefined, false, undefined, this),
2361
+ /* @__PURE__ */ jsxDEV14("span", {
2362
+ className: "dbg-tool__section-lang",
2363
+ children: approval?.id
2364
+ }, undefined, false, undefined, this)
2365
+ ]
2366
+ }, undefined, true, undefined, this),
2367
+ /* @__PURE__ */ jsxDEV14("div", {
2368
+ className: "dbg-tool__message dbg-tool__message--approval",
2369
+ children: t("translate_waiting_for_approval")
2370
+ }, undefined, false, undefined, this)
2371
+ ]
2372
+ }, undefined, true, undefined, this);
2373
+ }
2374
+ if (state === "approval-responded") {
2375
+ return /* @__PURE__ */ jsxDEV14("div", {
2376
+ className: "dbg-tool__section dbg-tool__section--approval",
2377
+ children: [
2378
+ /* @__PURE__ */ jsxDEV14("div", {
2379
+ className: "dbg-tool__section-bar",
2380
+ children: [
2381
+ /* @__PURE__ */ jsxDEV14("span", {
2382
+ className: "dbg-tool__section-label dbg-tool__section-label--approval",
2383
+ children: t("translate_approval_response")
2384
+ }, undefined, false, undefined, this),
2385
+ /* @__PURE__ */ jsxDEV14("span", {
2386
+ className: "dbg-tool__section-lang",
2387
+ children: approval?.id
2388
+ }, undefined, false, undefined, this)
2389
+ ]
2390
+ }, undefined, true, undefined, this),
2391
+ /* @__PURE__ */ jsxDEV14("div", {
2392
+ className: "dbg-tool__message dbg-tool__message--approval",
2393
+ children: t(approval?.approved ? "translate_tool_approved" : "translate_tool_response_received")
2394
+ }, undefined, false, undefined, this)
2395
+ ]
2396
+ }, undefined, true, undefined, this);
2397
+ }
2398
+ return null;
2399
+ }
2400
+ return /* @__PURE__ */ jsxDEV14("div", {
2401
+ children: section()
2402
+ }, undefined, false, undefined, this);
2403
+ }
2404
+
2405
+ // src/components/MessageToolCallStatus.tsx
2406
+ import { jsxDEV as jsxDEV15 } from "react/jsx-dev-runtime";
2407
+ function MessageToolCallStatus({ toolCallPart }) {
2408
+ const { t } = useCortex();
2409
+ const badge = toolCallBadge(toolCallPart);
2410
+ return /* @__PURE__ */ jsxDEV15("span", {
2411
+ children: /* @__PURE__ */ jsxDEV15("span", {
2412
+ className: cx("dbg-tool__state", badge.modifier && `dbg-tool__state--${badge.modifier}`),
2413
+ children: [
2414
+ badge.pulse && /* @__PURE__ */ jsxDEV15("span", {
2415
+ className: cx("dbg-tool__pulse", badge.pulse === "violet" && "dbg-tool__pulse--violet")
2416
+ }, undefined, false, undefined, this),
2417
+ t(badge.labelKey)
2418
+ ]
2419
+ }, undefined, true, undefined, this)
2420
+ }, undefined, false, undefined, this);
2421
+ }
2422
+
2423
+ // src/components/MessageToolCallPart.tsx
2424
+ import { jsxDEV as jsxDEV16 } from "react/jsx-dev-runtime";
2425
+ function MessageToolCallPart({ toolCallPart }) {
2426
+ const { t } = useCortex();
2427
+ const { codeSnippets, remainingInput, remainingInputText } = splitToolCallInput(toolCallPart.input);
2428
+ return /* @__PURE__ */ jsxDEV16("details", {
2429
+ className: "dbg-tool",
2430
+ "data-state": toolCallPart.state,
2431
+ children: [
2432
+ /* @__PURE__ */ jsxDEV16("summary", {
2433
+ className: "dbg-tool__summary",
2434
+ children: /* @__PURE__ */ jsxDEV16("div", {
2435
+ className: "dbg-tool__header",
2436
+ children: [
2437
+ /* @__PURE__ */ jsxDEV16("div", {
2438
+ className: "dbg-tool__meta",
2439
+ children: [
2440
+ /* @__PURE__ */ jsxDEV16("div", {
2441
+ className: "dbg-tool__title-row",
2442
+ children: /* @__PURE__ */ jsxDEV16("span", {
2443
+ className: "dbg-tool__name",
2444
+ title: toolCallPart.name,
2445
+ children: toolCallPart.name
2446
+ }, undefined, false, undefined, this)
2447
+ }, undefined, false, undefined, this),
2448
+ /* @__PURE__ */ jsxDEV16("div", {
2449
+ className: "dbg-tool__id-row",
2450
+ children: /* @__PURE__ */ jsxDEV16("span", {
2451
+ className: "dbg-tool__id",
2452
+ children: toolCallPart.id
2453
+ }, undefined, false, undefined, this)
2454
+ }, undefined, false, undefined, this)
2455
+ ]
2456
+ }, undefined, true, undefined, this),
2457
+ /* @__PURE__ */ jsxDEV16("div", {
2458
+ className: "dbg-tool__actions",
2459
+ children: [
2460
+ /* @__PURE__ */ jsxDEV16(MessageToolCallStatus, {
2461
+ toolCallPart
2462
+ }, undefined, false, undefined, this),
2463
+ /* @__PURE__ */ jsxDEV16("svg", {
2464
+ className: "dbg-tool__chevron",
2465
+ width: "14",
2466
+ height: "14",
2467
+ viewBox: "0 0 20 20",
2468
+ fill: "none",
2469
+ children: /* @__PURE__ */ jsxDEV16("path", {
2470
+ d: "m5.75 8.25 4.25 4.25 4.25-4.25",
2471
+ stroke: "currentColor",
2472
+ strokeWidth: "1.5",
2473
+ strokeLinecap: "round",
2474
+ strokeLinejoin: "round"
2475
+ }, undefined, false, undefined, this)
2476
+ }, undefined, false, undefined, this)
2477
+ ]
2478
+ }, undefined, true, undefined, this)
2479
+ ]
2480
+ }, undefined, true, undefined, this)
2481
+ }, undefined, false, undefined, this),
2482
+ /* @__PURE__ */ jsxDEV16("div", {
2483
+ className: "dbg-tool__body",
2484
+ children: [
2485
+ codeSnippets.map((snippet) => /* @__PURE__ */ jsxDEV16("div", {
2486
+ className: "dbg-tool__section",
2487
+ children: [
2488
+ /* @__PURE__ */ jsxDEV16("div", {
2489
+ className: "dbg-tool__section-bar",
2490
+ children: [
2491
+ /* @__PURE__ */ jsxDEV16("span", {
2492
+ className: "dbg-tool__section-label",
2493
+ children: snippet.key
2494
+ }, undefined, false, undefined, this),
2495
+ /* @__PURE__ */ jsxDEV16("span", {
2496
+ className: "dbg-tool__section-lang",
2497
+ children: snippet.lang
2498
+ }, undefined, false, undefined, this),
2499
+ /* @__PURE__ */ jsxDEV16(CopyButton, {
2500
+ value: snippet.value
2501
+ }, undefined, false, undefined, this)
2502
+ ]
2503
+ }, undefined, true, undefined, this),
2504
+ /* @__PURE__ */ jsxDEV16("pre", {
2505
+ dir: "ltr",
2506
+ className: "dbg-tool__pre",
2507
+ children: /* @__PURE__ */ jsxDEV16("code", {
2508
+ className: "hljs",
2509
+ dangerouslySetInnerHTML: { __html: highlightCode(snippet.value, snippet.lang) }
2510
+ }, undefined, false, undefined, this)
2511
+ }, undefined, false, undefined, this)
2512
+ ]
2513
+ }, snippet.key, true, undefined, this)),
2514
+ !!remainingInput && /* @__PURE__ */ jsxDEV16("div", {
2515
+ className: "dbg-tool__section",
2516
+ children: [
2517
+ /* @__PURE__ */ jsxDEV16("div", {
2518
+ className: "dbg-tool__section-bar",
2519
+ children: [
2520
+ /* @__PURE__ */ jsxDEV16("span", {
2521
+ className: "dbg-tool__section-label",
2522
+ children: t("translate_input")
2523
+ }, undefined, false, undefined, this),
2524
+ /* @__PURE__ */ jsxDEV16("span", {
2525
+ className: "dbg-tool__section-lang",
2526
+ children: "json"
2527
+ }, undefined, false, undefined, this),
2528
+ /* @__PURE__ */ jsxDEV16(CopyButton, {
2529
+ value: remainingInputText
2530
+ }, undefined, false, undefined, this)
2531
+ ]
2532
+ }, undefined, true, undefined, this),
2533
+ /* @__PURE__ */ jsxDEV16("div", {
2534
+ dir: "ltr",
2535
+ className: "dbg-tool__tree",
2536
+ children: /* @__PURE__ */ jsxDEV16(JsonTree, {
2537
+ data: remainingInput,
2538
+ expandDepth: 2
2539
+ }, undefined, false, undefined, this)
2540
+ }, undefined, false, undefined, this)
2541
+ ]
2542
+ }, undefined, true, undefined, this),
2543
+ /* @__PURE__ */ jsxDEV16(MessageToolCallOutcome, {
2544
+ toolCallPart
2545
+ }, undefined, false, undefined, this)
2546
+ ]
2547
+ }, undefined, true, undefined, this)
2548
+ ]
2549
+ }, undefined, true, undefined, this);
2550
+ }
2551
+
2552
+ // src/components/MessageToolCallAnimated.tsx
2553
+ import { jsxDEV as jsxDEV17 } from "react/jsx-dev-runtime";
2554
+ function MessageToolCallAnimated({ message, toolCallPart }) {
2555
+ const { config, t, addToolResult } = useCortex();
2556
+ const Custom = config.toolComponents?.[toolCallPart.name];
2557
+ if (Custom) {
2558
+ return /* @__PURE__ */ jsxDEV17("div", {
2559
+ className: "cortex-tool-call-animated",
2560
+ children: /* @__PURE__ */ jsxDEV17(Custom, {
2561
+ toolCallPart,
2562
+ message,
2563
+ setOutput: (output) => addToolResult(toolCallPart.id, toolCallPart.name, output)
2564
+ }, undefined, false, undefined, this)
2565
+ }, undefined, false, undefined, this);
2566
+ }
2567
+ const { state, active, titleKey } = toolCallAnimation(toolCallPart);
2568
+ return /* @__PURE__ */ jsxDEV17("div", {
2569
+ className: "cortex-tool-call-animated",
2570
+ children: /* @__PURE__ */ jsxDEV17("div", {
2571
+ className: "cortex-tool-pill",
2572
+ children: [
2573
+ /* @__PURE__ */ jsxDEV17("span", {
2574
+ className: "cortex-tool-pill__icon",
2575
+ children: [
2576
+ /* @__PURE__ */ jsxDEV17("span", {
2577
+ className: cx("cortex-tool-pill__spinner", active && "cortex-tool-pill__spinner--visible")
2578
+ }, undefined, false, undefined, this),
2579
+ /* @__PURE__ */ jsxDEV17("svg", {
2580
+ className: cx("cortex-tool-pill__svg", "cortex-tool-pill__svg--check", state === "complete" && "cortex-tool-pill__svg--visible"),
2581
+ viewBox: "0 0 20 20",
2582
+ fill: "none",
2583
+ children: /* @__PURE__ */ jsxDEV17("path", {
2584
+ d: "M5.5 10.5 L8.5 13.5 L14.5 7",
2585
+ stroke: "currentColor",
2586
+ strokeWidth: "2",
2587
+ strokeLinecap: "round",
2588
+ strokeLinejoin: "round"
2589
+ }, undefined, false, undefined, this)
2590
+ }, undefined, false, undefined, this),
2591
+ /* @__PURE__ */ jsxDEV17("svg", {
2592
+ className: cx("cortex-tool-pill__svg", "cortex-tool-pill__svg--error", state === "error" && "cortex-tool-pill__svg--visible"),
2593
+ viewBox: "0 0 20 20",
2594
+ fill: "none",
2595
+ children: /* @__PURE__ */ jsxDEV17("path", {
2596
+ d: "M6.5 6.5 L13.5 13.5 M13.5 6.5 L6.5 13.5",
2597
+ stroke: "currentColor",
2598
+ strokeWidth: "2",
2599
+ strokeLinecap: "round"
2600
+ }, undefined, false, undefined, this)
2601
+ }, undefined, false, undefined, this)
2602
+ ]
2603
+ }, undefined, true, undefined, this),
2604
+ /* @__PURE__ */ jsxDEV17("span", {
2605
+ className: cx("cortex-tool-pill__title", state === "error" && "cortex-tool-pill__title--error"),
2606
+ children: t(titleKey)
2607
+ }, undefined, false, undefined, this)
2608
+ ]
2609
+ }, undefined, true, undefined, this)
2610
+ }, undefined, false, undefined, this);
2611
+ }
2612
+
2613
+ // src/components/ToolExecuteCodeAnimated.tsx
2614
+ import { jsxDEV as jsxDEV18 } from "react/jsx-dev-runtime";
2615
+ var LABELS2 = activityLabelKeys("code");
2616
+ function ToolExecuteCodeAnimated() {
2617
+ return /* @__PURE__ */ jsxDEV18(SubtleActivity, {
2618
+ labels: LABELS2
2619
+ }, undefined, false, undefined, this);
2620
+ }
2621
+
2622
+ // src/components/ToolQueryGraphAnimated.tsx
2623
+ import { jsxDEV as jsxDEV19 } from "react/jsx-dev-runtime";
2624
+ var LABELS3 = activityLabelKeys("graph");
2625
+ function ToolQueryGraphAnimated() {
2626
+ return /* @__PURE__ */ jsxDEV19(SubtleActivity, {
2627
+ labels: LABELS3
2628
+ }, undefined, false, undefined, this);
2629
+ }
2630
+
2631
+ // src/components/ToolAnimation.tsx
2632
+ import { jsxDEV as jsxDEV20 } from "react/jsx-dev-runtime";
2633
+ function ToolAnimation({ message, toolCallPart }) {
2634
+ if (toolCallPart.name === "queryGraph")
2635
+ return /* @__PURE__ */ jsxDEV20(ToolQueryGraphAnimated, {}, undefined, false, undefined, this);
2636
+ if (toolCallPart.name === "executeCode")
2637
+ return /* @__PURE__ */ jsxDEV20(ToolExecuteCodeAnimated, {}, undefined, false, undefined, this);
2638
+ return /* @__PURE__ */ jsxDEV20(MessageToolCallAnimated, {
2639
+ toolCallPart,
2640
+ message
2641
+ }, undefined, false, undefined, this);
2642
+ }
2643
+
2644
+ // src/components/MessagePart.tsx
2645
+ import { jsxDEV as jsxDEV21 } from "react/jsx-dev-runtime";
2646
+ function MessagePart(props) {
2647
+ const { message, part, debugMode = false, animate = false, streaming = false } = props;
2648
+ const { t } = useCortex();
2649
+ function renderPart() {
2650
+ switch (part.type) {
2651
+ case "text":
2652
+ return /* @__PURE__ */ jsxDEV21(MessageTextPart, {
2653
+ textPart: part,
2654
+ role: message.role,
2655
+ streaming
2656
+ }, undefined, false, undefined, this);
2657
+ case "thinking":
2658
+ return debugMode ? /* @__PURE__ */ jsxDEV21(MessageReasoningPart, {
2659
+ reasoningPart: part,
2660
+ streaming
2661
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV21(MessageReasoningAnimated, {}, undefined, false, undefined, this);
2662
+ case "tool-call":
2663
+ return debugMode ? /* @__PURE__ */ jsxDEV21(MessageToolCallPart, {
2664
+ toolCallPart: part
2665
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV21(ToolAnimation, {
2666
+ toolCallPart: part,
2667
+ message
2668
+ }, undefined, false, undefined, this);
2669
+ default:
2670
+ return /* @__PURE__ */ jsxDEV21("p", {
2671
+ className: "cortex-unhandled-type",
2672
+ children: [
2673
+ t("translate_unhandled_type"),
2674
+ " ",
2675
+ part.type
2676
+ ]
2677
+ }, undefined, true, undefined, this);
2678
+ }
2679
+ }
2680
+ return /* @__PURE__ */ jsxDEV21("div", {
2681
+ className: cx("cortex-message-part", animate && "cortex-message-part--animated"),
2682
+ children: renderPart()
2683
+ }, undefined, false, undefined, this);
2684
+ }
2685
+
2686
+ // src/components/MessageTokenUsage.tsx
2687
+ import { useState as useState7 } from "react";
2688
+ import { jsxDEV as jsxDEV22 } from "react/jsx-dev-runtime";
2689
+ function MessageTokenUsage({ usage, modelId }) {
2690
+ const { t } = useCortex();
2691
+ const [expanded, setExpanded] = useState7(false);
2692
+ const cacheRatio = cachePercent(usage) ?? 0;
2693
+ return /* @__PURE__ */ jsxDEV22("div", {
2694
+ className: cx("cortex-token-usage", expanded && "cortex-token-usage--expanded"),
2695
+ children: [
2696
+ /* @__PURE__ */ jsxDEV22("button", {
2697
+ className: "cortex-token-usage__summary",
2698
+ onClick: () => setExpanded((v) => !v),
2699
+ children: [
2700
+ /* @__PURE__ */ jsxDEV22("span", {
2701
+ className: "cortex-token-usage__total",
2702
+ children: [
2703
+ /* @__PURE__ */ jsxDEV22("span", {
2704
+ className: "cortex-token-usage__total-number",
2705
+ children: num(usage.total)
2706
+ }, undefined, false, undefined, this),
2707
+ /* @__PURE__ */ jsxDEV22("span", {
2708
+ className: "cortex-token-usage__total-label",
2709
+ children: t("translate_tokens")
2710
+ }, undefined, false, undefined, this)
2711
+ ]
2712
+ }, undefined, true, undefined, this),
2713
+ modelId ? /* @__PURE__ */ jsxDEV22("span", {
2714
+ className: "cortex-token-usage__model",
2715
+ children: modelId
2716
+ }, undefined, false, undefined, this) : null,
2717
+ /* @__PURE__ */ jsxDEV22("span", {
2718
+ className: "cortex-token-usage__pills",
2719
+ children: [
2720
+ /* @__PURE__ */ jsxDEV22("span", {
2721
+ className: "cortex-token-usage__pill",
2722
+ children: [
2723
+ /* @__PURE__ */ jsxDEV22("span", {
2724
+ className: "cortex-token-usage__dot cortex-token-usage__dot--input"
2725
+ }, undefined, false, undefined, this),
2726
+ num(usage.input.total)
2727
+ ]
2728
+ }, undefined, true, undefined, this),
2729
+ /* @__PURE__ */ jsxDEV22("span", {
2730
+ className: "cortex-token-usage__pill",
2731
+ children: [
2732
+ /* @__PURE__ */ jsxDEV22("span", {
2733
+ className: "cortex-token-usage__dot cortex-token-usage__dot--output"
2734
+ }, undefined, false, undefined, this),
2735
+ num(usage.output.total)
2736
+ ]
2737
+ }, undefined, true, undefined, this)
2738
+ ]
2739
+ }, undefined, true, undefined, this),
2740
+ cacheRatio > 0 ? /* @__PURE__ */ jsxDEV22("span", {
2741
+ className: "cortex-token-usage__cache-badge",
2742
+ children: [
2743
+ cacheRatio,
2744
+ "%"
2745
+ ]
2746
+ }, undefined, true, undefined, this) : null,
2747
+ /* @__PURE__ */ jsxDEV22("svg", {
2748
+ className: "cortex-token-usage__chevron",
2749
+ width: "12",
2750
+ height: "12",
2751
+ viewBox: "0 0 12 12",
2752
+ fill: "none",
2753
+ children: /* @__PURE__ */ jsxDEV22("path", {
2754
+ d: "M3 4.5L6 7.5L9 4.5",
2755
+ stroke: "currentColor",
2756
+ strokeWidth: "1.25",
2757
+ strokeLinecap: "round",
2758
+ strokeLinejoin: "round"
2759
+ }, undefined, false, undefined, this)
2760
+ }, undefined, false, undefined, this)
2761
+ ]
2762
+ }, undefined, true, undefined, this),
2763
+ /* @__PURE__ */ jsxDEV22("div", {
2764
+ className: "cortex-token-usage__details",
2765
+ children: /* @__PURE__ */ jsxDEV22("div", {
2766
+ className: "cortex-token-usage__details-inner",
2767
+ children: /* @__PURE__ */ jsxDEV22("div", {
2768
+ className: "cortex-token-usage__columns",
2769
+ children: [
2770
+ /* @__PURE__ */ jsxDEV22("div", {
2771
+ className: "cortex-token-usage__col",
2772
+ children: [
2773
+ /* @__PURE__ */ jsxDEV22("div", {
2774
+ className: "cortex-token-usage__col-header",
2775
+ children: [
2776
+ /* @__PURE__ */ jsxDEV22("span", {
2777
+ className: "cortex-token-usage__dot cortex-token-usage__dot--input"
2778
+ }, undefined, false, undefined, this),
2779
+ /* @__PURE__ */ jsxDEV22("span", {
2780
+ className: "cortex-token-usage__col-label",
2781
+ children: t("translate_input")
2782
+ }, undefined, false, undefined, this),
2783
+ /* @__PURE__ */ jsxDEV22("span", {
2784
+ className: "cortex-token-usage__col-total",
2785
+ children: num(usage.input.total)
2786
+ }, undefined, false, undefined, this)
2787
+ ]
2788
+ }, undefined, true, undefined, this),
2789
+ /* @__PURE__ */ jsxDEV22("div", {
2790
+ className: "cortex-token-usage__rows",
2791
+ children: [
2792
+ usage.input.noCache ? /* @__PURE__ */ jsxDEV22("div", {
2793
+ className: "cortex-token-usage__row",
2794
+ children: [
2795
+ /* @__PURE__ */ jsxDEV22("span", {
2796
+ className: "cortex-token-usage__row-label",
2797
+ children: t("translate_fresh")
2798
+ }, undefined, false, undefined, this),
2799
+ /* @__PURE__ */ jsxDEV22("span", {
2800
+ className: "cortex-token-usage__row-value",
2801
+ children: num(usage.input.noCache)
2802
+ }, undefined, false, undefined, this)
2803
+ ]
2804
+ }, undefined, true, undefined, this) : null,
2805
+ usage.input.cacheRead ? /* @__PURE__ */ jsxDEV22("div", {
2806
+ className: "cortex-token-usage__row",
2807
+ children: [
2808
+ /* @__PURE__ */ jsxDEV22("span", {
2809
+ className: "cortex-token-usage__row-label",
2810
+ children: t("translate_cache_read")
2811
+ }, undefined, false, undefined, this),
2812
+ /* @__PURE__ */ jsxDEV22("span", {
2813
+ className: "cortex-token-usage__row-value",
2814
+ children: num(usage.input.cacheRead)
2815
+ }, undefined, false, undefined, this)
2816
+ ]
2817
+ }, undefined, true, undefined, this) : null,
2818
+ usage.input.cacheWrite ? /* @__PURE__ */ jsxDEV22("div", {
2819
+ className: "cortex-token-usage__row",
2820
+ children: [
2821
+ /* @__PURE__ */ jsxDEV22("span", {
2822
+ className: "cortex-token-usage__row-label",
2823
+ children: t("translate_cache_write")
2824
+ }, undefined, false, undefined, this),
2825
+ /* @__PURE__ */ jsxDEV22("span", {
2826
+ className: "cortex-token-usage__row-value",
2827
+ children: num(usage.input.cacheWrite)
2828
+ }, undefined, false, undefined, this)
2829
+ ]
2830
+ }, undefined, true, undefined, this) : null
2831
+ ]
2832
+ }, undefined, true, undefined, this),
2833
+ cacheRatio > 0 ? /* @__PURE__ */ jsxDEV22("div", {
2834
+ className: "cortex-token-usage__cache-bar-row",
2835
+ children: [
2836
+ /* @__PURE__ */ jsxDEV22("div", {
2837
+ className: "cortex-token-usage__cache-bar",
2838
+ children: /* @__PURE__ */ jsxDEV22("div", {
2839
+ className: "cortex-token-usage__cache-fill",
2840
+ style: { width: `${cacheRatio}%` }
2841
+ }, undefined, false, undefined, this)
2842
+ }, undefined, false, undefined, this),
2843
+ /* @__PURE__ */ jsxDEV22("span", {
2844
+ className: "cortex-token-usage__cache-label",
2845
+ children: t("translate_n_percent_cached", { percent: cacheRatio })
2846
+ }, undefined, false, undefined, this)
2847
+ ]
2848
+ }, undefined, true, undefined, this) : null
2849
+ ]
2850
+ }, undefined, true, undefined, this),
2851
+ /* @__PURE__ */ jsxDEV22("div", {
2852
+ className: "cortex-token-usage__col",
2853
+ children: [
2854
+ /* @__PURE__ */ jsxDEV22("div", {
2855
+ className: "cortex-token-usage__col-header",
2856
+ children: [
2857
+ /* @__PURE__ */ jsxDEV22("span", {
2858
+ className: "cortex-token-usage__dot cortex-token-usage__dot--output"
2859
+ }, undefined, false, undefined, this),
2860
+ /* @__PURE__ */ jsxDEV22("span", {
2861
+ className: "cortex-token-usage__col-label",
2862
+ children: t("translate_output")
2863
+ }, undefined, false, undefined, this),
2864
+ /* @__PURE__ */ jsxDEV22("span", {
2865
+ className: "cortex-token-usage__col-total",
2866
+ children: num(usage.output.total)
2867
+ }, undefined, false, undefined, this)
2868
+ ]
2869
+ }, undefined, true, undefined, this),
2870
+ /* @__PURE__ */ jsxDEV22("div", {
2871
+ className: "cortex-token-usage__rows",
2872
+ children: [
2873
+ usage.output.text ? /* @__PURE__ */ jsxDEV22("div", {
2874
+ className: "cortex-token-usage__row",
2875
+ children: [
2876
+ /* @__PURE__ */ jsxDEV22("span", {
2877
+ className: "cortex-token-usage__row-label",
2878
+ children: t("translate_text")
2879
+ }, undefined, false, undefined, this),
2880
+ /* @__PURE__ */ jsxDEV22("span", {
2881
+ className: "cortex-token-usage__row-value",
2882
+ children: num(usage.output.text)
2883
+ }, undefined, false, undefined, this)
2884
+ ]
2885
+ }, undefined, true, undefined, this) : null,
2886
+ usage.output.reasoning ? /* @__PURE__ */ jsxDEV22("div", {
2887
+ className: "cortex-token-usage__row",
2888
+ children: [
2889
+ /* @__PURE__ */ jsxDEV22("span", {
2890
+ className: "cortex-token-usage__row-label",
2891
+ children: t("translate_reasoning")
2892
+ }, undefined, false, undefined, this),
2893
+ /* @__PURE__ */ jsxDEV22("span", {
2894
+ className: "cortex-token-usage__row-value",
2895
+ children: num(usage.output.reasoning)
2896
+ }, undefined, false, undefined, this)
2897
+ ]
2898
+ }, undefined, true, undefined, this) : null
2899
+ ]
2900
+ }, undefined, true, undefined, this)
2901
+ ]
2902
+ }, undefined, true, undefined, this)
2903
+ ]
2904
+ }, undefined, true, undefined, this)
2905
+ }, undefined, false, undefined, this)
2906
+ }, undefined, false, undefined, this)
2907
+ ]
2908
+ }, undefined, true, undefined, this);
2909
+ }
2910
+
2911
+ // src/components/Message.tsx
2912
+ import { jsxDEV as jsxDEV23 } from "react/jsx-dev-runtime";
2913
+ function Message(props) {
2914
+ const { message, debugMode = false, animate = false } = props;
2915
+ const { messages, isAgentWorking, messageMetadata } = useCortex();
2916
+ const isStreaming = isAgentWorking && newestAssistantMessage(messages)?.id === message.id;
2917
+ const isAssistant = message.role === "assistant";
2918
+ const parts = message.parts;
2919
+ const visibleParts = parts.filter((part, index) => {
2920
+ if (part.type === "tool-result")
2921
+ return false;
2922
+ return debugMode || !isHiddenInAnimatedMode(part, index === parts.length - 1, isStreaming);
2923
+ });
2924
+ const streamingPartIndex = isStreaming ? visibleParts.length - 1 : -1;
2925
+ const metadata = messageMetadata.get(message.id);
2926
+ const isAborted = Boolean(metadata?.isAborted);
2927
+ const tokenUsage = metadata?.tokenUsage;
2928
+ const attachments = message.role === "user" ? metadata?.attachments ?? [] : [];
2929
+ const showsDebugZone = debugMode && !isStreaming && (Boolean(tokenUsage) || isAssistant);
2930
+ return /* @__PURE__ */ jsxDEV23("div", {
2931
+ className: "cortex-message",
2932
+ children: visibleParts.length > 0 && /* @__PURE__ */ jsxDEV23("div", {
2933
+ className: "cortex-message-parts",
2934
+ children: [
2935
+ visibleParts.map((part, index) => /* @__PURE__ */ jsxDEV23(MessagePart, {
2936
+ part,
2937
+ message,
2938
+ debugMode,
2939
+ animate,
2940
+ streaming: index === streamingPartIndex
2941
+ }, index, false, undefined, this)),
2942
+ attachments.length > 0 && /* @__PURE__ */ jsxDEV23(MessageAttachments, {
2943
+ attachments
2944
+ }, undefined, false, undefined, this),
2945
+ isAborted && /* @__PURE__ */ jsxDEV23(MessageAbortedFlag, {}, undefined, false, undefined, this),
2946
+ showsDebugZone && /* @__PURE__ */ jsxDEV23("div", {
2947
+ className: "cortex-message-debug-zone",
2948
+ children: [
2949
+ tokenUsage && /* @__PURE__ */ jsxDEV23(MessageTokenUsage, {
2950
+ usage: tokenUsage,
2951
+ modelId: metadata?.modelId
2952
+ }, undefined, false, undefined, this),
2953
+ isAssistant && /* @__PURE__ */ jsxDEV23(MessageLlmInspector, {
2954
+ messageId: message.id
2955
+ }, undefined, false, undefined, this)
2956
+ ]
2957
+ }, undefined, true, undefined, this)
2958
+ ]
2959
+ }, undefined, true, undefined, this)
2960
+ }, undefined, false, undefined, this);
2961
+ }
2962
+
2963
+ // src/components/MessageList.tsx
2964
+ import { jsxDEV as jsxDEV24 } from "react/jsx-dev-runtime";
2965
+ function MessageList(props) {
2966
+ const { messages, selectedThread } = useCortex();
2967
+ const containerRef = useRef7(null);
2968
+ const shouldScrollToBottom = useRef7(true);
2969
+ const isNearBottom = useRef7(true);
2970
+ const scrollToBottomQueued = useRef7(false);
2971
+ const [animateNewParts, setAnimateNewParts] = useState8(false);
2972
+ function scrollToBottom() {
2973
+ const el = containerRef.current;
2974
+ if (el)
2975
+ el.scrollTop = el.scrollHeight;
2976
+ }
2977
+ function scheduleScrollToBottom() {
2978
+ if (scrollToBottomQueued.current)
2979
+ return;
2980
+ scrollToBottomQueued.current = true;
2981
+ queueMicrotask(() => {
2982
+ scrollToBottomQueued.current = false;
2983
+ scrollToBottom();
2984
+ shouldScrollToBottom.current = false;
2985
+ });
2986
+ }
2987
+ useEffect5(() => {
2988
+ const el = containerRef.current;
2989
+ scheduleScrollToBottom();
2990
+ setAnimateNewParts(true);
2991
+ if (!el || typeof MutationObserver === "undefined")
2992
+ return;
2993
+ const observer = new MutationObserver(() => {
2994
+ if (!shouldScrollToBottom.current && !isNearBottom.current)
2995
+ return;
2996
+ scheduleScrollToBottom();
2997
+ });
2998
+ observer.observe(el, { childList: true, subtree: true, characterData: true });
2999
+ return () => observer.disconnect();
3000
+ }, []);
3001
+ const threadId = selectedThread?.id;
3002
+ useEffect5(() => {
3003
+ setAnimateNewParts(false);
3004
+ shouldScrollToBottom.current = true;
3005
+ queueMicrotask(() => setAnimateNewParts(true));
3006
+ }, [threadId]);
3007
+ const lastMessage = messages[messages.length - 1];
3008
+ const lastUserMessageId = lastMessage?.role === "user" ? lastMessage.id : undefined;
3009
+ useEffect5(() => {
3010
+ if (lastUserMessageId)
3011
+ shouldScrollToBottom.current = true;
3012
+ }, [lastUserMessageId]);
3013
+ useEffect5(() => {
3014
+ if (!shouldScrollToBottom.current && !isNearBottom.current)
3015
+ return;
3016
+ scheduleScrollToBottom();
3017
+ }, [messages]);
3018
+ function onScroll() {
3019
+ const el = containerRef.current;
3020
+ if (!el)
3021
+ return;
3022
+ isNearBottom.current = el.scrollHeight - el.scrollTop - el.clientHeight < 100;
3023
+ }
3024
+ return /* @__PURE__ */ jsxDEV24("div", {
3025
+ className: props.className,
3026
+ children: /* @__PURE__ */ jsxDEV24("div", {
3027
+ ref: containerRef,
3028
+ className: "cortex-message-list",
3029
+ onScroll,
3030
+ children: messages.map((message) => /* @__PURE__ */ jsxDEV24(Message, {
3031
+ message,
3032
+ debugMode: props.debugMode,
3033
+ animate: animateNewParts
3034
+ }, message.id, false, undefined, this))
3035
+ }, undefined, false, undefined, this)
3036
+ }, undefined, false, undefined, this);
3037
+ }
3038
+
3039
+ // src/components/ThreadList.tsx
3040
+ import { jsxDEV as jsxDEV25, Fragment as Fragment2 } from "react/jsx-dev-runtime";
3041
+ var BUBBLE_PATH = "M13.5 7.6c0 2.4-2.5 4.4-5.5 4.4-.6 0-1.2-.08-1.7-.23L3 13l.8-2.3C3 9.8 2.5 8.7 2.5 7.6 2.5 5.2 5 3.2 8 3.2s5.5 2 5.5 4.4Z";
3042
+ function ThreadList(props) {
3043
+ const { config, t, threads, selectedThread, deleteThread } = useCortex();
3044
+ const locale = config.locale ?? "en";
3045
+ return /* @__PURE__ */ jsxDEV25("div", {
3046
+ className: props.className,
3047
+ children: [
3048
+ /* @__PURE__ */ jsxDEV25("div", {
3049
+ className: "cortex-widget__threads-header",
3050
+ children: [
3051
+ /* @__PURE__ */ jsxDEV25("div", {
3052
+ children: [
3053
+ /* @__PURE__ */ jsxDEV25("h2", {
3054
+ className: "cortex-widget__threads-title",
3055
+ children: t("translate_threads")
3056
+ }, undefined, false, undefined, this),
3057
+ /* @__PURE__ */ jsxDEV25("p", {
3058
+ className: "cortex-widget__threads-count",
3059
+ children: t(threads?.length === 1 ? "translate_one_conversation" : "translate_n_conversations", {
3060
+ count: threads?.length ?? 0
3061
+ })
3062
+ }, undefined, false, undefined, this)
3063
+ ]
3064
+ }, undefined, true, undefined, this),
3065
+ /* @__PURE__ */ jsxDEV25("button", {
3066
+ onClick: () => props.onNewChatRequested(),
3067
+ className: "cortex-widget__new-chat-btn",
3068
+ children: [
3069
+ /* @__PURE__ */ jsxDEV25("svg", {
3070
+ width: "12",
3071
+ height: "12",
3072
+ viewBox: "0 0 16 16",
3073
+ fill: "none",
3074
+ children: /* @__PURE__ */ jsxDEV25("path", {
3075
+ d: "M8 3v10M3 8h10",
3076
+ stroke: "currentColor",
3077
+ strokeWidth: "1.5",
3078
+ strokeLinecap: "round"
3079
+ }, undefined, false, undefined, this)
3080
+ }, undefined, false, undefined, this),
3081
+ t("translate_new")
3082
+ ]
3083
+ }, undefined, true, undefined, this)
3084
+ ]
3085
+ }, undefined, true, undefined, this),
3086
+ /* @__PURE__ */ jsxDEV25("div", {
3087
+ className: "cortex-widget__threads-list",
3088
+ children: threads === undefined ? [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsxDEV25("div", {
3089
+ className: "cortex-widget__thread-skeleton",
3090
+ children: [
3091
+ /* @__PURE__ */ jsxDEV25("div", {
3092
+ className: "cortex-skeleton cortex-widget__thread-skeleton-icon"
3093
+ }, undefined, false, undefined, this),
3094
+ /* @__PURE__ */ jsxDEV25("div", {
3095
+ className: "cortex-widget__thread-skeleton-lines",
3096
+ children: /* @__PURE__ */ jsxDEV25("div", {
3097
+ className: "cortex-skeleton cortex-widget__thread-skeleton-line",
3098
+ style: { width: `${40 + i * 12}%` }
3099
+ }, undefined, false, undefined, this)
3100
+ }, undefined, false, undefined, this)
3101
+ ]
3102
+ }, i, true, undefined, this)) : /* @__PURE__ */ jsxDEV25(Fragment2, {
3103
+ children: [
3104
+ threads.map((thread) => {
3105
+ const isActive = thread.id === selectedThread?.id;
3106
+ const time = relativeTimeLabel(thread.updatedAt, locale);
3107
+ return /* @__PURE__ */ jsxDEV25("button", {
3108
+ onClick: () => props.onThreadSelected(thread),
3109
+ className: cx("cortex-widget__thread-item", isActive && "cortex-widget__thread-item--active"),
3110
+ children: [
3111
+ /* @__PURE__ */ jsxDEV25("div", {
3112
+ className: cx("cortex-widget__thread-icon", isActive && "cortex-widget__thread-icon--active"),
3113
+ children: /* @__PURE__ */ jsxDEV25("svg", {
3114
+ width: "14",
3115
+ height: "14",
3116
+ viewBox: "0 0 16 16",
3117
+ fill: "none",
3118
+ children: /* @__PURE__ */ jsxDEV25("path", {
3119
+ d: BUBBLE_PATH,
3120
+ stroke: "currentColor",
3121
+ strokeWidth: "1.3",
3122
+ strokeLinecap: "round",
3123
+ strokeLinejoin: "round"
3124
+ }, undefined, false, undefined, this)
3125
+ }, undefined, false, undefined, this)
3126
+ }, undefined, false, undefined, this),
3127
+ /* @__PURE__ */ jsxDEV25("div", {
3128
+ className: "cortex-widget__thread-info",
3129
+ children: [
3130
+ /* @__PURE__ */ jsxDEV25("div", {
3131
+ className: "cortex-widget__thread-title-row",
3132
+ children: [
3133
+ /* @__PURE__ */ jsxDEV25("p", {
3134
+ className: cx("cortex-widget__thread-title", isActive && "cortex-widget__thread-title--active"),
3135
+ children: thread.title ?? t("translate_untitled")
3136
+ }, undefined, false, undefined, this),
3137
+ thread.isRunning && /* @__PURE__ */ jsxDEV25("span", {
3138
+ className: cx("cortex-widget__thread-running", isActive && "cortex-widget__thread-running--active"),
3139
+ children: [
3140
+ /* @__PURE__ */ jsxDEV25("span", {
3141
+ className: "cortex-widget__thread-running-dot"
3142
+ }, undefined, false, undefined, this),
3143
+ t("translate_running")
3144
+ ]
3145
+ }, undefined, true, undefined, this)
3146
+ ]
3147
+ }, undefined, true, undefined, this),
3148
+ time && /* @__PURE__ */ jsxDEV25("p", {
3149
+ className: "cortex-widget__thread-time",
3150
+ children: time
3151
+ }, undefined, false, undefined, this)
3152
+ ]
3153
+ }, undefined, true, undefined, this),
3154
+ /* @__PURE__ */ jsxDEV25("span", {
3155
+ role: "button",
3156
+ tabIndex: 0,
3157
+ onClick: (event) => {
3158
+ event.stopPropagation();
3159
+ deleteThread(thread.id);
3160
+ },
3161
+ onKeyDown: (event) => {
3162
+ if (event.key !== "Enter" && event.key !== " ")
3163
+ return;
3164
+ event.preventDefault();
3165
+ event.stopPropagation();
3166
+ deleteThread(thread.id);
3167
+ },
3168
+ className: cx("cortex-widget__thread-delete", isActive && "cortex-widget__thread-delete--active"),
3169
+ children: /* @__PURE__ */ jsxDEV25("svg", {
3170
+ width: "12",
3171
+ height: "12",
3172
+ viewBox: "0 0 16 16",
3173
+ fill: "none",
3174
+ children: /* @__PURE__ */ jsxDEV25("path", {
3175
+ d: "M4 4l8 8M12 4l-8 8",
3176
+ stroke: "currentColor",
3177
+ strokeWidth: "1.3",
3178
+ strokeLinecap: "round"
3179
+ }, undefined, false, undefined, this)
3180
+ }, undefined, false, undefined, this)
3181
+ }, undefined, false, undefined, this),
3182
+ /* @__PURE__ */ jsxDEV25("svg", {
3183
+ className: cx("cortex-widget__thread-arrow", isActive && "cortex-widget__thread-arrow--active"),
3184
+ width: "10",
3185
+ height: "10",
3186
+ viewBox: "0 0 16 16",
3187
+ fill: "none",
3188
+ children: /* @__PURE__ */ jsxDEV25("path", {
3189
+ d: "M6 4l4 4-4 4",
3190
+ stroke: "currentColor",
3191
+ strokeWidth: "1.5",
3192
+ strokeLinecap: "round",
3193
+ strokeLinejoin: "round"
3194
+ }, undefined, false, undefined, this)
3195
+ }, undefined, false, undefined, this)
3196
+ ]
3197
+ }, thread.id, true, undefined, this);
3198
+ }),
3199
+ !threads.length && /* @__PURE__ */ jsxDEV25("div", {
3200
+ className: "cortex-widget__threads-empty",
3201
+ children: [
3202
+ /* @__PURE__ */ jsxDEV25("div", {
3203
+ className: "cortex-widget__threads-empty-icon",
3204
+ children: /* @__PURE__ */ jsxDEV25("svg", {
3205
+ width: "18",
3206
+ height: "18",
3207
+ viewBox: "0 0 16 16",
3208
+ fill: "none",
3209
+ className: "cortex-widget__threads-empty-svg",
3210
+ children: /* @__PURE__ */ jsxDEV25("path", {
3211
+ d: BUBBLE_PATH,
3212
+ stroke: "currentColor",
3213
+ strokeWidth: "1.3",
3214
+ strokeLinecap: "round",
3215
+ strokeLinejoin: "round"
3216
+ }, undefined, false, undefined, this)
3217
+ }, undefined, false, undefined, this)
3218
+ }, undefined, false, undefined, this),
3219
+ /* @__PURE__ */ jsxDEV25("p", {
3220
+ className: "cortex-widget__threads-empty-title",
3221
+ children: t("translate_no_threads_yet")
3222
+ }, undefined, false, undefined, this),
3223
+ /* @__PURE__ */ jsxDEV25("p", {
3224
+ className: "cortex-widget__threads-empty-subtitle",
3225
+ children: t("translate_start_a_new_conversation")
3226
+ }, undefined, false, undefined, this),
3227
+ /* @__PURE__ */ jsxDEV25("button", {
3228
+ onClick: () => props.onNewChatRequested(),
3229
+ className: "cortex-widget__new-chat-btn cortex-widget__new-chat-btn--empty-state",
3230
+ children: t("translate_new_chat")
3231
+ }, undefined, false, undefined, this)
3232
+ ]
3233
+ }, undefined, true, undefined, this)
3234
+ ]
3235
+ }, undefined, true, undefined, this)
3236
+ }, undefined, false, undefined, this)
3237
+ ]
3238
+ }, undefined, true, undefined, this);
3239
+ }
3240
+
3241
+ // src/components/CortexChatWidget.tsx
3242
+ import { jsxDEV as jsxDEV26 } from "react/jsx-dev-runtime";
3243
+ var initialSessionUi = {
3244
+ messages: [],
3245
+ isAgentWorking: false,
3246
+ isLoadingMessages: false,
3247
+ hasPendingToolCalls: false,
3248
+ messageMetadata: new Map
3249
+ };
3250
+ function CortexChatWidget({
3251
+ config,
3252
+ className
3253
+ }) {
3254
+ const configRef = useRef8(config);
3255
+ configRef.current = config;
3256
+ const [threads, setThreads] = useState9();
3257
+ const [session, setSession] = useState9();
3258
+ const [sessionUi, setSessionUi] = useState9(initialSessionUi);
3259
+ const [debugMode, setDebugMode] = useState9(false);
3260
+ const [screen, setScreen] = useState9("threads");
3261
+ const [sidebarOpen, setSidebarOpen] = useState9(false);
3262
+ const sessionRef = useRef8(undefined);
3263
+ const pendingSendRef = useRef8([]);
3264
+ const pendingThreadCreation = useRef8(undefined);
3265
+ const composerRef = useRef8(null);
3266
+ const api = useMemo3(() => createCortexApiClient(() => configRef.current.transport), []);
3267
+ const selectedThread = useMemo3(() => {
3268
+ const snapshot = session?.thread;
3269
+ if (!snapshot)
3270
+ return;
3271
+ return threads?.find((thread) => thread.id === snapshot.id) ?? snapshot;
3272
+ }, [threads, session]);
3273
+ const selectedThreadRef = useRef8(selectedThread);
3274
+ selectedThreadRef.current = selectedThread;
3275
+ const sessionUiRef = useRef8(sessionUi);
3276
+ sessionUiRef.current = sessionUi;
3277
+ const patchUi = useCallback((patch) => {
3278
+ setSessionUi((previous) => ({
3279
+ ...previous,
3280
+ ...typeof patch === "function" ? patch(previous) : patch
3281
+ }));
3282
+ }, []);
3283
+ const setRunning = useCallback((threadId, isRunning) => {
3284
+ setThreads((current) => {
3285
+ const thread = current?.find((candidate) => candidate.id === threadId);
3286
+ return thread ? upsertThread(current ?? [], { ...thread, isRunning }) : current;
3287
+ });
3288
+ }, []);
3289
+ const selectThread = useCallback((thread, options) => {
3290
+ if (selectedThreadRef.current?.id === thread.id && sessionRef.current)
3291
+ return;
3292
+ const previous = selectedThreadRef.current;
3293
+ selectedThreadRef.current = thread;
3294
+ setSessionUi(initialSessionUi);
3295
+ setSession({ thread, mode: options?.skipLoadingMessages ? "skip" : "load", epoch: 0 });
3296
+ if (previous && previous.id !== thread.id) {
3297
+ configRef.current.hooks?.onThreadDeselected?.(previous);
3298
+ }
3299
+ configRef.current.hooks?.onThreadSelected?.(thread);
3300
+ }, []);
3301
+ const deselectThread = useCallback(() => {
3302
+ const previous = selectedThreadRef.current;
3303
+ if (!previous && !sessionRef.current)
3304
+ return;
3305
+ selectedThreadRef.current = undefined;
3306
+ setSession(undefined);
3307
+ setSessionUi(initialSessionUi);
3308
+ if (previous) {
3309
+ configRef.current.hooks?.onThreadDeselected?.(previous);
3310
+ }
3311
+ }, []);
3312
+ const remountSession = useCallback((thread) => {
3313
+ patchUi({ hasPendingToolCalls: false, messageMetadata: new Map });
3314
+ setSession((current) => ({ thread, mode: "reload", epoch: (current?.epoch ?? 0) + 1 }));
3315
+ }, [patchUi]);
3316
+ const ensureThread = useCallback((prompt) => {
3317
+ const selected = selectedThreadRef.current;
3318
+ if (selected)
3319
+ return Promise.resolve(selected.id);
3320
+ pendingThreadCreation.current ??= api.createThread(prompt).then((thread) => {
3321
+ pendingThreadCreation.current = undefined;
3322
+ setThreads((current) => upsertThread(current ?? [], thread));
3323
+ selectThread(thread, { skipLoadingMessages: true });
3324
+ return thread.id;
3325
+ }, (error) => {
3326
+ pendingThreadCreation.current = undefined;
3327
+ throw error;
3328
+ });
3329
+ return pendingThreadCreation.current;
3330
+ }, [api, selectThread]);
3331
+ const queueStore = useMemo3(() => createAttachmentQueue({ api, ensureThread: () => ensureThread() }), [api, ensureThread]);
3332
+ const queueItems = useSyncExternalStore(queueStore.subscribe, queueStore.getState, queueStore.getState);
3333
+ const send = useCallback(async (prompt, attachments = []) => {
3334
+ if (sessionUiRef.current.isAgentWorking || sessionUiRef.current.hasPendingToolCalls)
3335
+ return;
3336
+ const handle = sessionRef.current;
3337
+ if (handle) {
3338
+ await handle.send(prompt, attachments);
3339
+ return;
3340
+ }
3341
+ pendingSendRef.current.push({ prompt, attachments });
3342
+ try {
3343
+ await ensureThread(prompt);
3344
+ } catch (error) {
3345
+ pendingSendRef.current = [];
3346
+ throw error;
3347
+ }
3348
+ }, [ensureThread]);
3349
+ const abort = useCallback(async () => {
3350
+ await sessionRef.current?.abort();
3351
+ }, []);
3352
+ const addToolResult = useCallback((toolCallId, toolName, output) => {
3353
+ sessionRef.current?.addToolResult(toolCallId, toolName, output);
3354
+ }, []);
3355
+ const deleteThread = useCallback(async (threadId) => {
3356
+ if (selectedThreadRef.current?.id === threadId)
3357
+ deselectThread();
3358
+ await api.deleteThread(threadId);
3359
+ setThreads((current) => current ? removeThread(current, threadId) : current);
3360
+ }, [api, deselectThread]);
3361
+ const onTurnFinished = useCallback(() => {
3362
+ queueStore.discardConsumed();
3363
+ setTimeout(() => composerRef.current?.focusInput());
3364
+ }, [queueStore]);
3365
+ const onSendFailed = useCallback(() => {
3366
+ queueStore.restoreConsumed(selectedThreadRef.current?.id);
3367
+ }, [queueStore]);
3368
+ const reloadThreads = useCallback(async () => {
3369
+ const listed = sortThreads(await api.listThreads());
3370
+ setThreads(listed);
3371
+ return listed;
3372
+ }, [api]);
3373
+ const handleWsEvent = useCallback((event) => {
3374
+ setThreads((current) => {
3375
+ const next = applyWsEvent(current ?? [], event);
3376
+ return current || next.length ? next : current;
3377
+ });
3378
+ const selectedId = selectedThreadRef.current?.id;
3379
+ switch (event.type) {
3380
+ case "thread:deleted":
3381
+ if (selectedId === event.payload.threadId)
3382
+ deselectThread();
3383
+ break;
3384
+ case "thread:run-started":
3385
+ if (selectedId === event.payload.thread.id) {
3386
+ sessionRef.current?.reattach(event.payload.thread);
3387
+ }
3388
+ break;
3389
+ case "thread:messages-updated":
3390
+ sessionRef.current?.refreshMessages(event.payload.threadId);
3391
+ break;
3392
+ }
3393
+ }, [deselectThread]);
3394
+ useEffect6(() => {
3395
+ reloadThreads();
3396
+ let openedOnce = false;
3397
+ const socket = createCortexSocket({
3398
+ wsUrl: () => configRef.current.wsUrl,
3399
+ transport: {
3400
+ baseUrl: () => {
3401
+ const baseUrl = configRef.current.transport.baseUrl;
3402
+ return typeof baseUrl === "string" ? baseUrl : baseUrl();
3403
+ },
3404
+ getHeaders: () => configRef.current.transport.getHeaders()
3405
+ },
3406
+ onEvent: handleWsEvent,
3407
+ onOpen: () => {
3408
+ if (!openedOnce) {
3409
+ openedOnce = true;
3410
+ return;
3411
+ }
3412
+ reloadThreads().then((listed) => {
3413
+ const selected = selectedThreadRef.current;
3414
+ if (!selected)
3415
+ return;
3416
+ sessionRef.current?.reattach(listed.find((thread) => thread.id === selected.id) ?? selected);
3417
+ });
3418
+ }
3419
+ });
3420
+ return () => {
3421
+ socket.close();
3422
+ };
3423
+ }, [handleWsEvent, reloadThreads]);
3424
+ const previousThreadId = useRef8(undefined);
3425
+ const selectedThreadId = selectedThread?.id;
3426
+ useEffect6(() => {
3427
+ if (selectedThreadId === previousThreadId.current)
3428
+ return;
3429
+ queueStore.clear(previousThreadId.current);
3430
+ previousThreadId.current = selectedThreadId;
3431
+ }, [selectedThreadId, queueStore]);
3432
+ const locale = config.locale ?? "en";
3433
+ const t = useCallback((key, params) => translate(locale, key, params), [locale]);
3434
+ const viewMode = config.viewMode ?? "helper";
3435
+ const contextValue = {
3436
+ config,
3437
+ t,
3438
+ api,
3439
+ debugMode,
3440
+ threads,
3441
+ selectedThread,
3442
+ deleteThread,
3443
+ ...sessionUi,
3444
+ send,
3445
+ abort,
3446
+ addToolResult,
3447
+ queue: {
3448
+ items: queueItems,
3449
+ ...attachmentQueueFlags(queueItems),
3450
+ accept: queueStore.accept,
3451
+ remove: queueStore.remove,
3452
+ consumeReady: queueStore.consumeReady
3453
+ }
3454
+ };
3455
+ function openThread(thread) {
3456
+ selectThread(thread);
3457
+ setScreen("chat");
3458
+ setSidebarOpen(false);
3459
+ }
3460
+ function newChat() {
3461
+ deselectThread();
3462
+ setScreen("chat");
3463
+ setSidebarOpen(false);
3464
+ }
3465
+ function goBack() {
3466
+ deselectThread();
3467
+ setScreen("threads");
3468
+ }
3469
+ return /* @__PURE__ */ jsxDEV26(CortexContext.Provider, {
3470
+ value: contextValue,
3471
+ children: /* @__PURE__ */ jsxDEV26("div", {
3472
+ className: cx("cortex-widget", className),
3473
+ "data-cortex-theme": config.theme,
3474
+ children: [
3475
+ /* @__PURE__ */ jsxDEV26("div", {
3476
+ className: cx("cortex-widget__container", viewMode === "full" && "cortex-widget__container--full", sidebarOpen && "cortex-widget__container--sidebar-open"),
3477
+ onDragOver: (event) => event.preventDefault(),
3478
+ onDrop: (event) => event.preventDefault(),
3479
+ children: [
3480
+ /* @__PURE__ */ jsxDEV26(ThreadList, {
3481
+ className: cx("cortex-widget__screen", screen === "threads" && "cortex-widget__screen--active", screen !== "threads" && "cortex-widget__screen--left"),
3482
+ onThreadSelected: openThread,
3483
+ onNewChatRequested: newChat
3484
+ }, undefined, false, undefined, this),
3485
+ /* @__PURE__ */ jsxDEV26("div", {
3486
+ className: cx("cortex-widget__screen", screen === "chat" && "cortex-widget__screen--active", screen !== "chat" && "cortex-widget__screen--right"),
3487
+ children: [
3488
+ /* @__PURE__ */ jsxDEV26("div", {
3489
+ className: "cortex-widget__chat-header",
3490
+ children: [
3491
+ /* @__PURE__ */ jsxDEV26("button", {
3492
+ onClick: () => setSidebarOpen((open) => !open),
3493
+ className: "cortex-widget__sidebar-toggle-btn",
3494
+ children: /* @__PURE__ */ jsxDEV26("svg", {
3495
+ width: "16",
3496
+ height: "16",
3497
+ viewBox: "0 0 16 16",
3498
+ fill: "none",
3499
+ children: /* @__PURE__ */ jsxDEV26("path", {
3500
+ d: "M2.5 4h11M2.5 8h11M2.5 12h11",
3501
+ stroke: "currentColor",
3502
+ strokeWidth: "1.4",
3503
+ strokeLinecap: "round"
3504
+ }, undefined, false, undefined, this)
3505
+ }, undefined, false, undefined, this)
3506
+ }, undefined, false, undefined, this),
3507
+ /* @__PURE__ */ jsxDEV26("button", {
3508
+ onClick: goBack,
3509
+ className: "cortex-widget__back-btn",
3510
+ children: /* @__PURE__ */ jsxDEV26("svg", {
3511
+ width: "14",
3512
+ height: "14",
3513
+ viewBox: "0 0 16 16",
3514
+ fill: "none",
3515
+ className: "cortex-widget__back-icon",
3516
+ children: /* @__PURE__ */ jsxDEV26("path", {
3517
+ d: "M10 3L5 8l5 5",
3518
+ stroke: "currentColor",
3519
+ strokeWidth: "1.5",
3520
+ strokeLinecap: "round",
3521
+ strokeLinejoin: "round"
3522
+ }, undefined, false, undefined, this)
3523
+ }, undefined, false, undefined, this)
3524
+ }, undefined, false, undefined, this),
3525
+ /* @__PURE__ */ jsxDEV26("div", {
3526
+ className: "cortex-widget__chat-title-wrap",
3527
+ children: /* @__PURE__ */ jsxDEV26("p", {
3528
+ className: "cortex-widget__chat-title",
3529
+ children: selectedThread?.title ?? t("translate_new_chat")
3530
+ }, undefined, false, undefined, this)
3531
+ }, undefined, false, undefined, this),
3532
+ config.showDebugButton && /* @__PURE__ */ jsxDEV26("button", {
3533
+ onClick: () => setDebugMode((mode) => !mode),
3534
+ className: cx("cortex-widget__debug-btn", debugMode ? "cortex-widget__debug-btn--on" : "cortex-widget__debug-btn--off"),
3535
+ children: debugMode ? t("translate_debug") : t("translate_normal")
3536
+ }, undefined, false, undefined, this)
3537
+ ]
3538
+ }, undefined, true, undefined, this),
3539
+ sessionUi.isLoadingMessages && !sessionUi.isAgentWorking ? /* @__PURE__ */ jsxDEV26("div", {
3540
+ className: "cortex-widget__messages-skeleton",
3541
+ children: [
3542
+ /* @__PURE__ */ jsxDEV26("div", {
3543
+ className: "cortex-widget__msg-skel cortex-widget__msg-skel--user",
3544
+ children: /* @__PURE__ */ jsxDEV26("div", {
3545
+ className: "cortex-widget__msg-skel-bubble cortex-widget__msg-skel-bubble--user",
3546
+ children: [
3547
+ /* @__PURE__ */ jsxDEV26("div", {
3548
+ className: "cortex-skeleton cortex-widget__msg-skel-line",
3549
+ style: { width: "13rem" }
3550
+ }, undefined, false, undefined, this),
3551
+ /* @__PURE__ */ jsxDEV26("div", {
3552
+ className: "cortex-skeleton cortex-widget__msg-skel-line",
3553
+ style: { width: "9rem" }
3554
+ }, undefined, false, undefined, this)
3555
+ ]
3556
+ }, undefined, true, undefined, this)
3557
+ }, undefined, false, undefined, this),
3558
+ /* @__PURE__ */ jsxDEV26("div", {
3559
+ className: "cortex-widget__msg-skel cortex-widget__msg-skel--assistant",
3560
+ children: /* @__PURE__ */ jsxDEV26("div", {
3561
+ className: "cortex-widget__msg-skel-bubble cortex-widget__msg-skel-bubble--assistant",
3562
+ children: [
3563
+ /* @__PURE__ */ jsxDEV26("div", {
3564
+ className: "cortex-skeleton cortex-widget__msg-skel-line",
3565
+ style: { width: "16rem" }
3566
+ }, undefined, false, undefined, this),
3567
+ /* @__PURE__ */ jsxDEV26("div", {
3568
+ className: "cortex-skeleton cortex-widget__msg-skel-line",
3569
+ style: { width: "18rem" }
3570
+ }, undefined, false, undefined, this),
3571
+ /* @__PURE__ */ jsxDEV26("div", {
3572
+ className: "cortex-skeleton cortex-widget__msg-skel-line",
3573
+ style: { width: "12rem" }
3574
+ }, undefined, false, undefined, this)
3575
+ ]
3576
+ }, undefined, true, undefined, this)
3577
+ }, undefined, false, undefined, this),
3578
+ /* @__PURE__ */ jsxDEV26("div", {
3579
+ className: "cortex-widget__msg-skel cortex-widget__msg-skel--user",
3580
+ children: /* @__PURE__ */ jsxDEV26("div", {
3581
+ className: "cortex-widget__msg-skel-bubble cortex-widget__msg-skel-bubble--user",
3582
+ children: /* @__PURE__ */ jsxDEV26("div", {
3583
+ className: "cortex-skeleton cortex-widget__msg-skel-line",
3584
+ style: { width: "11rem" }
3585
+ }, undefined, false, undefined, this)
3586
+ }, undefined, false, undefined, this)
3587
+ }, undefined, false, undefined, this),
3588
+ /* @__PURE__ */ jsxDEV26("div", {
3589
+ className: "cortex-widget__msg-skel cortex-widget__msg-skel--assistant",
3590
+ children: /* @__PURE__ */ jsxDEV26("div", {
3591
+ className: "cortex-widget__msg-skel-bubble cortex-widget__msg-skel-bubble--assistant",
3592
+ children: [
3593
+ /* @__PURE__ */ jsxDEV26("div", {
3594
+ className: "cortex-skeleton cortex-widget__msg-skel-line",
3595
+ style: { width: "14rem" }
3596
+ }, undefined, false, undefined, this),
3597
+ /* @__PURE__ */ jsxDEV26("div", {
3598
+ className: "cortex-skeleton cortex-widget__msg-skel-line",
3599
+ style: { width: "15rem" }
3600
+ }, undefined, false, undefined, this)
3601
+ ]
3602
+ }, undefined, true, undefined, this)
3603
+ }, undefined, false, undefined, this)
3604
+ ]
3605
+ }, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV26(MessageList, {
3606
+ className: "cortex-widget__messages",
3607
+ debugMode
3608
+ }, undefined, false, undefined, this),
3609
+ sessionUi.isAgentWorking && !sessionUi.hasPendingToolCalls && /* @__PURE__ */ jsxDEV26("div", {
3610
+ className: "cortex-widget__working",
3611
+ children: [
3612
+ /* @__PURE__ */ jsxDEV26("div", {
3613
+ className: "cortex-widget__working-dots",
3614
+ children: [
3615
+ /* @__PURE__ */ jsxDEV26("span", {
3616
+ className: "cortex-working-dot"
3617
+ }, undefined, false, undefined, this),
3618
+ /* @__PURE__ */ jsxDEV26("span", {
3619
+ className: "cortex-working-dot"
3620
+ }, undefined, false, undefined, this),
3621
+ /* @__PURE__ */ jsxDEV26("span", {
3622
+ className: "cortex-working-dot"
3623
+ }, undefined, false, undefined, this)
3624
+ ]
3625
+ }, undefined, true, undefined, this),
3626
+ /* @__PURE__ */ jsxDEV26("span", {
3627
+ className: "cortex-widget__working-text",
3628
+ children: t("translate_thinking")
3629
+ }, undefined, false, undefined, this)
3630
+ ]
3631
+ }, undefined, true, undefined, this),
3632
+ !sessionUi.hasPendingToolCalls && /* @__PURE__ */ jsxDEV26(ChatComposer, {
3633
+ ref: composerRef
3634
+ }, undefined, false, undefined, this)
3635
+ ]
3636
+ }, undefined, true, undefined, this),
3637
+ /* @__PURE__ */ jsxDEV26("div", {
3638
+ className: "cortex-widget__sidebar-backdrop",
3639
+ onClick: () => setSidebarOpen(false)
3640
+ }, undefined, false, undefined, this)
3641
+ ]
3642
+ }, undefined, true, undefined, this),
3643
+ session && /* @__PURE__ */ jsxDEV26(ChatSession, {
3644
+ thread: session.thread,
3645
+ mode: session.mode,
3646
+ api,
3647
+ configRef,
3648
+ sessionRef,
3649
+ pendingSendRef,
3650
+ patchUi,
3651
+ setRunning,
3652
+ remount: remountSession,
3653
+ onTurnFinished,
3654
+ onSendFailed
3655
+ }, `${session.thread.id}:${session.epoch}`, false, undefined, this)
3656
+ ]
3657
+ }, undefined, true, undefined, this)
3658
+ }, undefined, false, undefined, this);
3659
+ }
1
3660
  export {
2
3661
  CortexChatWidget
3
3662
  };